#define GNU_SOURCE #include #include "creddy.h" #include "id.h" #include #define ROLE_SEPARATOR " <- " #define INTERSECTION_SEP " & " #define SHA1_LENGTH 40 void attribute_main(options_t *opts) { int i, ret, role_len = 1; if ( opts->issuer == NULL || opts->key == NULL || opts->role == NULL || opts->out == NULL ) usage(opts); if (!clean_name(opts->role)) { printf("bad role name %s\n", opts->role); usage(opts); } role_len += SHA1_LENGTH + 1 + strlen(opts->role); role_len += strlen(ROLE_SEPARATOR); for (i = 0; i < opts->num_subjects; ++i) { subject_t *cur = &opts->subjects[i]; // if we have an ID, make sure it's SHA1 and lowercase if (cur->id) { int j; char *subject_id = cur->id; // hex chars (also convert to lowercase) for (j = 0; subject_id[j]; ++j) { subject_id[j] = tolower(subject_id[j]); if (!isxdigit(subject_id[j])) { printf("Invalid subject ID %s: must be SHA1\n", subject_id); usage(opts); } } // correct length if (j != SHA1_LENGTH) { printf("Invalid subject ID %s: must be SHA1 (wrong length)\n", subject_id); usage(opts); } } // otherwise we have a cert else { creddy_id_t *subject = creddy_id_from_file(cur->cert); if (subject == NULL) errx(1, "Can't load subject cert from %s", cur->cert); cur->id = xstrdup(creddy_id_keyid(subject)); creddy_id_free(subject); } role_len += SHA1_LENGTH; // verify the subject role name if present if (cur->role) { char *role = cur->role; char *start[3]; int name_parts = 0, j; start[name_parts++] = role; for (j = 0; role[j] != '\0'; ++j) if (role[j] == '.') { if (name_parts == 3) { printf("bad subject role name (too many dots)\n"); usage(opts); } start[name_parts++] = &role[j+1]; role[j] = 0; } for (j = 0; j < name_parts; ++j) if (!clean_name(start[j])) { printf("bad subject role name\n"); usage(opts); } for (j = 1; j < name_parts; ++j) *(start[j]-1) = '.'; // replace the dot role_len += strlen(cur->role) + 1; } role_len += sizeof(INTERSECTION_SEP) - 1; } if (opts->validity < 0) { printf("Validity must be >= 1 day\n"); usage(opts); } // issuer creddy_id_t *issuer = creddy_id_from_file(opts->issuer); if (issuer == NULL) errx(1, "Can't load cert from %s", opts->issuer); // private key ret = creddy_id_load_privkey(issuer, opts->key); if (!ret) errx(1, "Can't load private key from %s", opts->key); // get the keyids char *issuer_id = creddy_id_keyid(issuer); // build the role encoding char *role_encoding = xmalloc(role_len); role_encoding[0] = '\0'; // role sprintf(role_encoding, "%s.%s" ROLE_SEPARATOR, issuer_id, opts->role); // subject(s) for (i = 0; i < opts->num_subjects; ++i) { subject_t *cur = &opts->subjects[i]; strcat(role_encoding, cur->id); if (cur->role) { strcat(role_encoding, "."); strcat(role_encoding, cur->role); } if (i < opts->num_subjects - 1) strcat(role_encoding, INTERSECTION_SEP); } // create attribute cert time_t not_before = time(NULL); time_t not_after = not_before + opts->validity * 3600 * 60 * 60; chunk_t serial = generate_serial(); certificate_t *attr_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_AC, BUILD_CERT, creddy_id_cert(issuer), BUILD_NOT_BEFORE_TIME, not_before, BUILD_NOT_AFTER_TIME, not_after, BUILD_SERIAL, serial, BUILD_IETF_GROUP_ATTR, role_encoding, BUILD_SIGNING_CERT, creddy_id_cert(issuer), BUILD_SIGNING_KEY, creddy_id_privkey(issuer), BUILD_END ); if (attr_cert == NULL) errx(1, "Couldn't build attribute cert"); // write to file chunk_t encoding = attr_cert->get_encoding(attr_cert); FILE *out = fopen(opts->out, "w"); if (out == NULL) err(1, "Can't open attribute cert output file %s", opts->out); fwrite(encoding.ptr, encoding.len, 1, out); fclose(out); free(role_encoding); free(serial.ptr); DESTROY_IF(attr_cert); free(encoding.ptr); creddy_id_free(issuer); }