#include #include #include #include #include "libcreddy_common.h" #define ROLE_SEPARATOR " <- " #define INTERSECTION_SEP " & " #define SHA1_LENGTH 40 struct _creddy_attribute_t { creddy_id_t *issuer; char *role; int validity; char **subject; int num_subjects; int size_subjects; int total_len; // total length of all subject strings certificate_t *cert; // NULL until baked }; static char *_validate_principal(char *keyid); static void _append(creddy_attribute_t *attr, char *subject); char *_get_role_encoding(creddy_attribute_t *attr); // validity is measured in seconds (as of 0.2.0) int creddy_attribute_create(creddy_attribute_t **ret, creddy_id_t *issuer, char *role, int validity) { if (creddy_id_privkey(issuer) == NULL) return CREDDY_ATTRIBUTE_ISSUER_NOKEY; if (!creddy_clean_name(role)) return CREDDY_ATTRIBUTE_INVALID_ROLE; if (validity < 0) return CREDDY_ATTRIBUTE_INVALID_VALIDITY; creddy_attribute_t *attr = creddy_xmalloc(sizeof(creddy_attribute_t)); attr->issuer = creddy_id_dup(issuer); attr->role = creddy_xstrdup(role); attr->validity = validity; attr->num_subjects = 0; attr->size_subjects = 4; attr->subject = creddy_xmalloc(sizeof(char *) * attr->size_subjects); attr->total_len = 0; // NULL until baked attr->cert = NULL; *ret = attr; return CREDDY_SUCCESS; } int creddy_attribute_principal(creddy_attribute_t *attr, char *keyid) { char *copy = _validate_principal(keyid); if (copy == NULL) return 0; _append(attr, copy); return 1; } int creddy_attribute_role(creddy_attribute_t *attr, char *keyid, char *role) { if (!creddy_clean_name(role)) return 0; char *copy = _validate_principal(keyid); if (copy == NULL) return 0; int len = strlen(copy) + strlen(role) + strlen(ROLE_SEPARATOR) + 1; copy = creddy_xrealloc(copy, len); strcat(copy, "."); strcat(copy, role); _append(attr, copy); return 1; } int creddy_attribute_linking_role(creddy_attribute_t *attr, char *keyid, char *role, char *linked) { if (!creddy_clean_name(role) || !creddy_clean_name(linked)) return 0; char *copy = _validate_principal(keyid); if (copy == NULL) return 0; int len = strlen(copy) + strlen(role) + strlen(linked) + strlen(ROLE_SEPARATOR) + 2; copy = creddy_xrealloc(copy, len); strcat(copy, "."); strcat(copy, role); strcat(copy, "."); strcat(copy, linked); _append(attr, copy); return 1; } int creddy_attribute_bake(creddy_attribute_t *attr) { if (attr->num_subjects == 0) return 0; libabac_init(); char *role_encoding = _get_role_encoding(attr); // create attribute cert time_t not_before = time(NULL); time_t not_after = not_before + attr->validity; chunk_t serial = creddy_generate_serial(); certificate_t *attr_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_AC, BUILD_CERT, creddy_id_cert(attr->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(attr->issuer), BUILD_SIGNING_KEY, creddy_id_privkey(attr->issuer), BUILD_END ); if (attr_cert == NULL) return 0; attr->cert = attr_cert; free(role_encoding); free(serial.ptr); return 1; } int creddy_attribute_cert_chunk(creddy_attribute_t *attr, abac_chunk_t *chunk) { if (attr->cert == NULL) return 0; chunk_t encoding = attr->cert->get_encoding(attr->cert); chunk->ptr = encoding.ptr; chunk->len = encoding.len; return 1; } int creddy_attribute_baked(creddy_attribute_t *attr) { return attr->cert != NULL; } // returns 0 if the cert hasn't been baked int creddy_attribute_write(creddy_attribute_t *attr, FILE *out) { assert(attr != NULL); if (attr->cert == NULL) return 0; // write to file chunk_t encoding = attr->cert->get_encoding(attr->cert); fwrite(encoding.ptr, encoding.len, 1, out); free(encoding.ptr); return 1; } void creddy_attribute_free(creddy_attribute_t *attr) { int i; if (attr == NULL) return; creddy_id_free(attr->issuer); free(attr->role); DESTROY_IF(attr->cert); // free all the subjects for (i = 0; i < attr->num_subjects; ++i) free(attr->subject[i]); free(attr->subject); free(attr); } // // Helper functions below // // validate a princpal's name // makes sure it's a valid SHA1 identifier // return values: // success: malloc'd copy with all hex digits lowercase // fail: NULL static char *_validate_principal(char *keyid) { int i; char *copy = NULL; if (strlen(keyid) != SHA1_LENGTH) return NULL; copy = creddy_xstrdup(keyid); for (i = 0; i < SHA1_LENGTH; ++i) { copy[i] = tolower(copy[i]); if (!isxdigit(copy[i])) goto error; } return copy; error: free(copy); return NULL; } static void _append(creddy_attribute_t *attr, char *subject) { // expand the array if necessary if (attr->num_subjects == attr->size_subjects) { attr->size_subjects *= 2; attr->subject = creddy_xrealloc(attr->subject, attr->size_subjects * sizeof(creddy_attribute_t)); } attr->subject[attr->num_subjects++] = subject; attr->total_len += strlen(subject); } char *_get_role_encoding(creddy_attribute_t *attr) { int i, num_subjects; num_subjects = attr->num_subjects; int len = SHA1_LENGTH + 1 + strlen(attr->role) + strlen(ROLE_SEPARATOR); len += attr->total_len + num_subjects * strlen(INTERSECTION_SEP); char *encoding = creddy_xmalloc(len); sprintf(encoding, "%s.%s" ROLE_SEPARATOR, creddy_id_keyid(attr->issuer), attr->role); for (i = 0; i < num_subjects; ++i) { strcat(encoding, attr->subject[i]); if (i < num_subjects - 1) strcat(encoding, INTERSECTION_SEP); } return encoding; }