source: creddy/attribute.c @ ee5afdd

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

support subject-cert and subject-id

  • Property mode set to 100644
File size: 4.6 KB
Line 
1#include <credentials/keys/private_key.h>
2
3#include "creddy.h"
4
5#define ROLE_SEPARATOR " <- "
6#define SHA1_LENGTH 40
7
8void attribute_main(options_t *opts) {
9    char *subject_id = NULL;
10
11    if (
12        opts->issuer == NULL ||
13        opts->key == NULL ||
14        opts->role == NULL ||
15        opts->out == NULL
16    )
17        usage(opts);
18
19    // make sure we have exactly one of --subject-cert / --subject-id
20    if (opts->subject_cert == NULL && opts->subject_id == NULL)
21        usage(opts);
22    if (opts->subject_cert && opts->subject_id) {
23        printf("Need exactly one of --subject-cert / --subject-id");
24        usage(opts);
25    }
26
27    // if we have an ID, make sure it's SHA1 and lowercase
28    if (opts->subject_id) {
29        int i;
30        subject_id = opts->subject_id;
31
32        // hex chars (also convert to lowercase)
33        for (i = 0; subject_id[i]; ++i) {
34            subject_id[i] = tolower(subject_id[i]);
35            if (!isxdigit(subject_id[i])) {
36                printf("Invalid subject ID: must be SHA1\n");
37                usage(opts);
38            }
39        }
40
41        // correct length
42        if (i != SHA1_LENGTH) {
43            printf("Invalid subject ID: must be SHA1 (too long)\n");
44            usage(opts);
45        }
46    }
47
48    if (!clean_name(opts->role)) {
49        printf("bad role name\n");
50        usage(opts);
51    }
52
53    // verify the subject role name if present
54    if (opts->subject_role) {
55        char *role = opts->subject_role;
56        char *start[3];
57        int name_parts = 0, i;
58
59        start[name_parts++] = role;
60
61        for (i = 0; role[i] != '\0'; ++i)
62            if (role[i] == '.') {
63                if (name_parts == 3) {
64                    printf("bad subject role name (too many dots)\n");
65                    usage(opts);
66                }
67                start[name_parts++] = &role[i+1];
68                role[i] = 0;
69            }
70
71        for (i = 0; i < name_parts; ++i)
72            if (!clean_name(start[i])) {
73                printf("bad subject role name\n");
74                usage(opts);
75            }
76
77        for (i = 1; i < name_parts; ++i)
78            *(start[i]-1) = '.'; // replace the dot
79    }
80
81    if (opts->validity < 0) {
82        printf("Validity must be >= 1 day\n");
83        usage(opts);
84    }
85
86    // load signer key
87    private_key_t *key = lib->creds->create(lib->creds,
88        CRED_PRIVATE_KEY, KEY_RSA,
89        BUILD_FROM_FILE, opts->key,
90        BUILD_END
91    );
92    if (key == NULL)
93        errx(1, "can't open private key file %s", opts->key);
94
95    // get the keyids
96    certificate_t *issuer = cert_from_file(opts->issuer);
97    char *issuer_id = cert_keyid(issuer);
98
99    // subject keyid from cert if it wasn't passed in
100    if (opts->subject_cert) {
101        certificate_t *subject = cert_from_file(opts->subject_cert);
102        subject_id = cert_keyid(subject);
103        DESTROY_IF(subject);
104    }
105
106    // build the role encoding
107    int role_encoding_len = 1; // for nul terminator
108    role_encoding_len += strlen(issuer_id) + 1 + strlen(opts->role);
109    role_encoding_len += sizeof(ROLE_SEPARATOR) - 1;
110    role_encoding_len += strlen(subject_id);
111    if (opts->subject_role)
112        role_encoding_len += 1 + strlen(opts->subject_role);
113
114    char *role_encoding = xmalloc(role_encoding_len);
115    role_encoding[0] = '\0';
116
117    sprintf(role_encoding, "%s.%s" ROLE_SEPARATOR "%s", issuer_id, opts->role, subject_id);
118    if (opts->subject_role) {
119        strcat(role_encoding, ".");
120        strcat(role_encoding, opts->subject_role);
121    }
122
123    free(issuer_id);
124
125    // if opts->subject_id, the memory will be freed in main
126    if (opts->subject_cert)
127        free(subject_id);
128
129    // create attribute cert
130    time_t not_before = time(NULL);
131    time_t not_after = not_before + opts->validity * 3600 * 60 * 60;
132    chunk_t serial = generate_serial();
133
134    certificate_t *attr_cert = lib->creds->create(lib->creds,
135        CRED_CERTIFICATE, CERT_X509_AC,
136        BUILD_CERT, issuer,
137        BUILD_NOT_BEFORE_TIME, not_before,
138        BUILD_NOT_AFTER_TIME, not_after,
139        BUILD_SERIAL, serial,
140        BUILD_IETF_GROUP_ATTR, role_encoding,
141        BUILD_SIGNING_CERT, issuer,
142        BUILD_SIGNING_KEY, key,
143        BUILD_END
144    );
145    if (attr_cert == NULL)
146        errx(1, "Couldn't build attribute cert");
147
148    // write to file
149    chunk_t encoding = attr_cert->get_encoding(attr_cert);
150
151    FILE *out = fopen(opts->out, "w");
152    if (out == NULL)
153        err(1, "Can't open attribute cert output file %s", opts->out);
154    fwrite(encoding.ptr, encoding.len, 1, out);
155    fclose(out);
156
157    free(role_encoding);
158    free(serial.ptr);
159    DESTROY_IF(attr_cert);
160    DESTROY_IF(issuer);
161    DESTROY_IF(key);
162}
Note: See TracBrowser for help on using the repository browser.