source: creddy/attribute.c @ 46bd849

abac0-leakabac0-meicompt_changesgec13mei-idmei-rt0-nmei_rt0mei_rt2mei_rt2_fix_1meiyap-rt1meiyap1rt2tvf-new-xml
Last change on this file since 46bd849 was 46bd849, checked in by Mike Ryan <mikeryan@…>, 14 years ago

Merge branch 'master' of abac.deterlab.net:/var/local/git/abac

  • Property mode set to 100644
File size: 7.5 KB
Line 
1#define GNU_SOURCE
2#include <credentials/keys/private_key.h>
3
4#include "creddy.h"
5
6#include <termios.h>
7
8#define ROLE_SEPARATOR " <- "
9#define INTERSECTION_SEP " & "
10#define SHA1_LENGTH 40
11/* Size of password memory allocation */
12#define PWLEN 128
13
14/* Callback configuration */
15struct cb_opts {
16    bool use_prompt;    /* Print a prompt to stderr */
17    bool use_echo;      /* If true, turn off input echo on stdin */
18    unsigned int tries; /* Number of attempts allowed */
19    char prompt[20];    /* The prompt to display if use_echo is true */
20};
21
22chunk_t passphrase_callback(void *user, int try) {
23    /* Get a password from stdin and return it as a chunk_t.  If too many tries
24     * have occurred or there is any other problem, return an empty chunk_t,
25     * which libstrongswan takes as giving up.  The chunk is alloated here
26     * (inside getline), and presumably freed by libstrongswan. User points to
27     * a cb_opts struct, which affects this routine in the obvious ways.
28     */
29    /* Configuration options */
30    struct cb_opts *opts = (struct cb_opts *) user;
31    chunk_t rv = chunk_empty;   /* Return value, starts empty */
32
33    if (try -1 < opts->tries ) {
34        struct termios t;   /* Terminal settings */
35        size_t len = 0;     /* Length of string from getline */
36        tcflag_t orig = 0;  /* Holds the original local flags (echo in here) */
37
38        if (!opts->use_echo) {
39            /* Use tc{get,set}attr to turn echo off and restore the intial
40             * echo settings */
41            if (!tcgetattr(0, &t)) { 
42                orig = t.c_lflag;
43
44                t.c_lflag &= ~ECHO;
45                if ( tcsetattr(0, TCSANOW, &t) ) { 
46                    perror("Cannot turn off echo"); 
47                    return rv;
48                }
49            }
50            else {
51                perror("Cannot turn get attributes to off echo"); 
52                return rv;
53            }
54        }
55        if (opts->use_prompt) printf("%s", opts->prompt);
56
57        /* Because rv.ptr starts as NULL, getline allocates memory.  The size
58         * of the allocation returns in rv.len and the size of the string
59         * (including newline and NUL) is in len.  */
60        if ((rv.ptr = (u_char *) malloc(rv.len = PWLEN))) {
61            if ( fgets(rv.ptr, rv.len, stdin) ) {
62                /* Readjust the chunk_t's len field to the size of the string
63                 * w/o the newline or NUL */
64                /* would prefer strnlen, but no such luck in FBSD7 or earlier*/
65                size_t len = strlen(rv.ptr);
66
67                if (rv.ptr[len-2] == '\n') rv.len = len-2;
68                else rv.len = len -1;
69            }
70            else {
71                /* Read failed.  Deallocate and clear rv */
72                free(rv.ptr);
73                rv = chunk_empty;
74            }
75        }
76        else {
77            /* Failed malloc.  Restore rv to empty and return it */
78            perror("malloc");
79            rv = chunk_empty;
80            return rv;
81        }
82
83        if (!opts->use_echo ) {
84            /* Pop echo beck to its original setting. */
85            t.c_lflag = orig;
86
87            if ( tcsetattr(0, TCSANOW, &t) ) 
88                perror("Cannot restore echo setting?"); 
89
90            if (opts->use_prompt) printf("\n");
91        }
92    }
93    else fprintf(stderr, "Too many tries (%d)", try-1);
94    return rv;
95}
96
97void attribute_main(options_t *opts) {
98    struct cb_opts c_opts = { 1, 0, 3, "Key password:" };
99    int i, role_len = 1;
100
101    if (
102        opts->issuer == NULL ||
103        opts->key == NULL ||
104        opts->role == NULL ||
105        opts->out == NULL
106    )
107        usage(opts);
108
109    if (!clean_name(opts->role)) {
110        printf("bad role name %s\n", opts->role);
111        usage(opts);
112    }
113
114    role_len += SHA1_LENGTH + 1 + strlen(opts->role);
115    role_len += strlen(ROLE_SEPARATOR);
116
117    for (i = 0; i < opts->num_subjects; ++i) {
118        subject_t *cur = &opts->subjects[i];
119
120        // if we have an ID, make sure it's SHA1 and lowercase
121        if (cur->id) {
122            int j;
123            char *subject_id = cur->id;
124
125            // hex chars (also convert to lowercase)
126            for (j = 0; subject_id[j]; ++j) {
127                subject_id[j] = tolower(subject_id[j]);
128                if (!isxdigit(subject_id[j])) {
129                    printf("Invalid subject ID %s: must be SHA1\n", subject_id);
130                    usage(opts);
131                }
132            }
133
134            // correct length
135            if (j != SHA1_LENGTH) {
136                printf("Invalid subject ID %s: must be SHA1 (wrong length)\n", subject_id);
137                usage(opts);
138            }
139        }
140
141        // otherwise we have a cert
142        else {
143            certificate_t *subject = cert_from_file(cur->cert);
144            cur->id = cert_keyid(subject);
145            DESTROY_IF(subject);
146        }
147
148        role_len += SHA1_LENGTH;
149
150        // verify the subject role name if present
151        if (cur->role) {
152            char *role = cur->role;
153            char *start[3];
154            int name_parts = 0, j;
155
156            start[name_parts++] = role;
157
158            for (j = 0; role[j] != '\0'; ++j)
159                if (role[j] == '.') {
160                    if (name_parts == 3) {
161                        printf("bad subject role name (too many dots)\n");
162                        usage(opts);
163                    }
164                    start[name_parts++] = &role[j+1];
165                    role[j] = 0;
166                }
167
168            for (j = 0; j < name_parts; ++j)
169                if (!clean_name(start[j])) {
170                    printf("bad subject role name\n");
171                    usage(opts);
172                }
173
174            for (j = 1; j < name_parts; ++j)
175                *(start[j]-1) = '.'; // replace the dot
176
177            role_len += strlen(cur->role) + 1;
178        }
179
180        role_len += sizeof(INTERSECTION_SEP) - 1;
181    }
182
183    if (opts->validity < 0) {
184        printf("Validity must be >= 1 day\n");
185        usage(opts);
186    }
187
188    chunk_t pw = chunk_empty;
189    // load signer key
190    private_key_t *key = lib->creds->create(lib->creds,
191        CRED_PRIVATE_KEY, KEY_RSA,
192        BUILD_FROM_FILE, opts->key,
193        /* Ask for password if the key's encrypted */
194        BUILD_PASSPHRASE_CALLBACK, passphrase_callback, &c_opts, 
195        BUILD_END
196    );
197    if (key == NULL)
198        errx(1, "can't open private key file %s", opts->key);
199
200    // get the keyids
201    certificate_t *issuer = cert_from_file(opts->issuer);
202    char *issuer_id = cert_keyid(issuer);
203
204    // build the role encoding
205    char *role_encoding = xmalloc(role_len);
206    role_encoding[0] = '\0';
207
208    // role
209    sprintf(role_encoding, "%s.%s" ROLE_SEPARATOR, issuer_id, opts->role);
210
211    // subject(s)
212    for (i = 0; i < opts->num_subjects; ++i) {
213        subject_t *cur = &opts->subjects[i];
214
215        strcat(role_encoding, cur->id);
216        if (cur->role) {
217            strcat(role_encoding, ".");
218            strcat(role_encoding, cur->role);
219        }
220
221        if (i < opts->num_subjects - 1)
222            strcat(role_encoding, INTERSECTION_SEP);
223    }
224
225    free(issuer_id);
226
227    // create attribute cert
228    time_t not_before = time(NULL);
229    time_t not_after = not_before + opts->validity * 3600 * 60 * 60;
230    chunk_t serial = generate_serial();
231
232    certificate_t *attr_cert = lib->creds->create(lib->creds,
233        CRED_CERTIFICATE, CERT_X509_AC,
234        BUILD_CERT, issuer,
235        BUILD_NOT_BEFORE_TIME, not_before,
236        BUILD_NOT_AFTER_TIME, not_after,
237        BUILD_SERIAL, serial,
238        BUILD_IETF_GROUP_ATTR, role_encoding,
239        BUILD_SIGNING_CERT, issuer,
240        BUILD_SIGNING_KEY, key,
241        BUILD_END
242    );
243    if (attr_cert == NULL)
244        errx(1, "Couldn't build attribute cert");
245
246    // write to file
247    chunk_t encoding = attr_cert->get_encoding(attr_cert);
248
249    FILE *out = fopen(opts->out, "w");
250    if (out == NULL)
251        err(1, "Can't open attribute cert output file %s", opts->out);
252    fwrite(encoding.ptr, encoding.len, 1, out);
253    fclose(out);
254
255    free(role_encoding);
256    free(serial.ptr);
257    DESTROY_IF(attr_cert);
258    DESTROY_IF(issuer);
259    DESTROY_IF(key);
260}
Note: See TracBrowser for help on using the repository browser.