source: creddy/attribute.c @ 980a7b6

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

intersection support in creddy

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