/** ** abac_attribute.c **/ #include #include #include #include #include "abac_internal.h" #include "abac_util.h" #include "abac_rt.h" #define SHA1_LENGTH 40 extern char* abac_encode_string(char*); extern abac_key_t *abac_id_keyptr(abac_id_t *id); extern abac_aspect_t *abac_yy_get_rule_head_aspect(); extern abac_aspect_t *abac_yy_get_rule_tail_aspect(); extern abac_list_t *abac_yy_get_rule_clauses(); extern char* abac_decode_string(char *); extern void abac_yy_free_rule_clauses(); extern int verify_signature(certificate_t *issuer_cert, certificate_t *cert); abac_attribute_t *abac_attribute_set_head(abac_attribute_t *ptr, abac_aspect_t *head); static int debug=0; struct _abac_attribute_t { abac_id_t *issuer_id; abac_aspect_t *head; abac_aspect_t *tail; int validity; certificate_t *cert; // NULL until baked certificate_t *issuer_cert; int refcount; }; /********************************************************************/ char *get_cred_encoding(abac_attribute_t *ptr) { char *encoding=NULL; /* must have a head aspect and tail aspect */ assert(ptr->head != NULL); assert(ptr->tail != NULL); char *head_string=abac_aspect_typed_string_with_condition(ptr->head); char *tail_string=abac_aspect_typed_string_with_condition(ptr->tail); asprintf(&encoding,"%s<-%s", head_string,tail_string); char* base64_encoding=abac_encode_string(encoding); if(debug) fprintf(stderr,"XXX abac_attribute_bake (%s)\n", encoding); free(encoding); free(head_string); free(tail_string); return base64_encoding; } /********************************************************************/ abac_attribute_t *abac_attribute_new(abac_id_t *issuer, certificate_t *cert, certificate_t *issuer_cert) { abac_attribute_t *ptr = abac_xmalloc(sizeof(abac_attribute_t)); ptr->issuer_id = abac_id_dup(issuer); ptr->head = NULL; ptr->tail = NULL; ptr->validity= 365 * 86400; // default ptr->cert=cert; // already baked.. ptr->issuer_cert=issuer_cert; ptr->refcount=1; return ptr; } // validity is measured in seconds (as of 0.2.0) int abac_attribute_create(abac_attribute_t **ret, abac_aspect_t *head, abac_aspect_t *tail, int validity) { abac_id_t *issuer_id=abac_aspect_get_issuer_id(head); if(debug) print_abac_key("abac_attribute_create" , abac_id_keyptr(issuer_id)); char *name=abac_aspect_aspect_name(head); if (!abac_id_has_privkey(issuer_id)) return ABAC_ATTRIBUTE_ISSUER_NOKEY; if (!abac_validate_clean_aspect_name(name)) return ABAC_ATTRIBUTE_INVALID_ROLE; if (validity < 0) return ABAC_ATTRIBUTE_INVALID_VALIDITY; abac_attribute_t *ptr = abac_xmalloc(sizeof(abac_attribute_t)); ptr->issuer_id = abac_id_dup(issuer_id); ptr->head = abac_aspect_dup(head); ptr->tail = (tail!=NULL) ? abac_aspect_dup(tail):NULL; ptr->validity=(validity==0?(365 * 86400):validity); // NULL until baked ptr->cert=NULL; ptr->issuer_cert=NULL; ptr->refcount=1; *ret = ptr; return ABAC_ATTRIBUTE_SUCCESS; } // validity is measured in seconds (as of 0.2.0) int abac_attribute_create_creddy(abac_attribute_t **ret, abac_id_t *issuer, abac_aspect_t *head_aspect, abac_aspect_t *tail_aspect, char *name, int validity) { if (!abac_id_has_privkey(issuer)) return ABAC_ATTRIBUTE_ISSUER_NOKEY; if (!abac_validate_clean_aspect_name(name)) return ABAC_ATTRIBUTE_INVALID_ROLE; if (validity < 0) return ABAC_ATTRIBUTE_INVALID_VALIDITY; abac_attribute_t *ptr = abac_xmalloc(sizeof(abac_attribute_t)); ptr->issuer_id = abac_id_dup(issuer); ptr->head=head_aspect; ptr->tail=tail_aspect; ptr->validity = validity; // NULL until baked ptr->cert = NULL; ptr->issuer_cert = NULL; *ret = ptr; return ABAC_ATTRIBUTE_SUCCESS; } int abac_attribute_bake(abac_attribute_t *ptr) { assert(ptr); char *cred_encoding = get_cred_encoding(ptr); // create attribute cert time_t not_before = time(NULL); time_t not_after = not_before + ptr->validity; chunk_t serial = abac_generate_serial(); private_key_t *private = abac_id_privkey(ptr->issuer_id); if(private==NULL) errx(1,"can not bake without a private key!!!"); certificate_t *attr_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_AC, BUILD_CERT, abac_id_cert(ptr->issuer_id), BUILD_NOT_BEFORE_TIME, not_before, BUILD_NOT_AFTER_TIME, not_after, BUILD_SERIAL, serial, BUILD_IETF_GROUP_ATTR, cred_encoding, BUILD_SIGNING_CERT, abac_id_cert(ptr->issuer_id), BUILD_SIGNING_KEY, private, BUILD_END ); DESTROY_IF(private); if (attr_cert == NULL) return 0; ptr->cert = attr_cert; // cert and issuer can be the same, in which case it is the self signing ptr->issuer_cert= attr_cert->get_ref(attr_cert); free(cred_encoding); free(serial.ptr); return 1; } abac_chunk_t abac_attribute_cert_chunk(abac_attribute_t *ptr) { assert(ptr->cert); chunk_t encoding = chunk_empty; int rc=ptr->cert->get_encoding(ptr->cert,CERT_ASN1_DER,&encoding); abac_chunk_t ret = { encoding.ptr, encoding.len }; return ret; } /* just loading it without any verifying */ certificate_t *abac_attribute_cert_from_file(char *filename) { if(!file_exist(filename)) return NULL; libabac_init(); certificate_t *cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_AC, BUILD_FROM_FILE, filename, BUILD_END ); if (cert == NULL) errx(1, "Couldn't load attribute cert %s", filename); return cert; } certificate_t *abac_attribute_cert_from_chunk(abac_chunk_t achunk) { chunk_t chunk = { .ptr = achunk.ptr, .len = achunk.len }; if(achunk.len == 0) { errx(1, "Couldn't load attribute chunk, size of 0"); } libabac_init(); certificate_t *cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_AC, BUILD_BLOB_ASN1_DER, chunk, BUILD_END ); if (cert == NULL) errx(1, "Couldn't load attribute chunk"); return cert; } /** * Load an attribute cert with a cert. * Returns true only if the certificate is valid and is issued by the proper * authority. * attribute string is parsed via yyparse call */ static abac_attribute_t *_load_attribute_from_cert(certificate_t *cert) { ietf_attributes_t *attr_cert = NULL; int ret, i; // get the attr ac_t *ac = (ac_t *)cert; attr_cert = ac->get_groups(ac); if (attr_cert == NULL) { ret = ABAC_CERT_INVALID; goto error; } char *encoded_attr_string=attr_cert->get_string(attr_cert); char *attr_string = abac_decode_string(encoded_attr_string); if(debug) fprintf(stderr, "string to be yyparse..(%d)(%s)\n",strlen(attr_string),attr_string); if (attr_string == NULL) { ret = ABAC_CERT_INVALID; goto error; } /* call into yacc parser */ abac_reset_yyfptr(attr_string); abac_yy_init(); int rc=yyparse(); if (rc) { ret = ABAC_CERT_INVALID; goto error; } abac_aspect_t *head_aspect = NULL; abac_aspect_t *tail_aspect = NULL; abac_list_t *clauses=NULL; abac_id_credential_t *id_cred; abac_id_t *issuer_id; // get the attr head_aspect = abac_yy_get_rule_head_aspect(); tail_aspect = abac_yy_get_rule_tail_aspect(); clauses = abac_yy_get_rule_clauses(); // get the issuer based on keyid char *principalname = abac_aspect_principal_principalname(head_aspect); if(debug) fprintf(stderr, "LOOKING for %s\n", principalname); id_cred = abac_id_credential_lookup(principalname); if(id_cred == NULL) { ret = ABAC_CERT_MISSING_ISSUER; if(debug) fprintf(stderr, "can not find %s in id_creds\n", principalname); goto error; } issuer_id=abac_id_credential_id(id_cred); if (issuer_id == NULL) { ret = ABAC_CERT_MISSING_ISSUER; if(debug) fprintf(stderr, "can not find %s in id_creds\n", principalname); goto error; } // make sure the issuer's signed it ret = verify_signature(abac_id_cert(issuer_id), cert); if (!ret) { abac_yy_set_error_code(ABAC_RT_CERT_BAD_SIG); ret=ABAC_CERT_BAD_SIG; goto error; } // at this point we know we have a good attribute cert baked it in abac_attribute_t *attr=abac_attribute_new(issuer_id, cert, cert->get_ref(cert)); abac_attribute_set_head(attr, head_aspect); abac_attribute_add_tail(attr, tail_aspect); // free up some stuff attr_cert->destroy(attr_cert); return attr; error: if (cert) cert->destroy(cert); errx(1, "fail to extract attribute from a cert properly\n"); } abac_attribute_t *abac_attribute_from_chunk(abac_chunk_t achunk) { certificate_t *cert=abac_attribute_cert_from_chunk(achunk); abac_attribute_t *ret=_load_attribute_from_cert(cert); return ret; } // returns 0 if the cert hasn't been baked int abac_attribute_baked(abac_attribute_t *ptr) { return ptr->cert != NULL; } int abac_attribute_write_cert(abac_attribute_t *ptr, FILE *out) { assert(ptr != NULL); if (ptr->cert == NULL) return 0; // write to file chunk_t encoding = chunk_empty; int rc=ptr->cert->get_encoding(ptr->cert,CERT_ASN1_DER,&encoding); if(rc) { fwrite(encoding.ptr, encoding.len, 1, out); free(encoding.ptr); return 1; } return 0; } abac_attribute_t *abac_attribute_dup(abac_attribute_t *ptr) { assert(ptr); ++ptr->refcount; return ptr; } void abac_attribute_free(abac_attribute_t *ptr) { int i; if (ptr == NULL) return; --ptr->refcount; if (ptr->refcount > 0) return; if(ptr->issuer_id) abac_id_free(ptr->issuer_id); if(ptr->head) abac_aspect_free(ptr->head); if(ptr->tail) abac_aspect_free(ptr->tail); if(ptr->cert) DESTROY_IF(ptr->cert); if(ptr->issuer_cert) DESTROY_IF(ptr->issuer_cert); free(ptr); } char *abac_attribute_string(abac_attribute_t *ptr) { char *head=abac_aspect_string_with_condition(ptr->head); char *tail=abac_aspect_string_with_condition(ptr->tail); if(head==NULL || tail==NULL) errx(1, "attribute string, head and tail can not be NULL"); char *tmp=NULL; asprintf(&tmp,"%s<-%s",head,tail); return tmp; } char *abac_attribute_typed_string(abac_attribute_t *ptr) { char *head=abac_aspect_typed_string_with_condition(ptr->head); char *tail=abac_aspect_typed_string_with_condition(ptr->tail); if(head==NULL || tail==NULL) errx(1, "attribute typed string, head and tail can not be NULL"); char *tmp=NULL; asprintf(&tmp,"%s<-%s",head,tail); return tmp; } /********************************************************************/ certificate_t *abac_attribute_issuer_cert(abac_attribute_t *ptr) { assert(ptr); return ptr->issuer_cert; } abac_aspect_t *abac_attribute_head(abac_attribute_t *ptr) { assert(ptr); return ptr->head; } int abac_attribute_is_role(abac_attribute_t *ptr) { assert(ptr); assert(ptr->head); return abac_aspect_is_role(ptr->head); } abac_attribute_t *abac_attribute_set_head(abac_attribute_t *ptr, abac_aspect_t *head) { assert(ptr); ptr->head=head; return ptr; } abac_aspect_t *abac_attribute_tail(abac_attribute_t *ptr) { assert(ptr); return ptr->tail; } abac_attribute_t *abac_attribute_add_tail(abac_attribute_t *ptr, abac_aspect_t *tail) { assert(ptr); assert(tail); /* type of head and tail has to match */ abac_aspect_t *head=abac_attribute_head(ptr); if(debug) { fprintf(stderr, "head->(%s)\n",abac_aspect_type_string(head)); fprintf(stderr, "tail->(%s)\n",abac_aspect_type_string(tail)); } if(abac_aspect_is_intersecting(tail)) { if(debug) { fprintf(stderr, "tail is intersection \n"); fprintf(stderr, "tail is (%s)\n", abac_aspect_string_with_condition(tail)); } if(abac_aspect_intersecting_aspect_type(tail) != abac_aspect_aspect_type(head)) errx(1, "head and intersecting tail's aspect type does not match"); } else { if(abac_aspect_aspect_type(head) != abac_aspect_aspect_type(tail)) { if(debug) fprintf(stderr, "tail is (%s)\n", abac_aspect_string_with_condition(tail)); errx(1, "head and tail's aspect type does not match"); } } if(ptr->tail == NULL) { ptr->tail=abac_aspect_dup(tail); } else { if(abac_aspect_is_intersecting(ptr->tail)) { abac_aspect_add_intersecting_aspect(ptr->tail, tail); } else { /* special case.. if there is a tail there already and it is not an intersecting tail, need to turn this into an intersecting tails */ abac_aspect_t *nptr=abac_aspect_intersection_new(ptr->tail); abac_aspect_add_intersecting_aspect(nptr, tail); ptr->tail=nptr; } } return ptr; } certificate_t *abac_attribute_cert(abac_attribute_t *ptr) { assert(ptr); return ptr->cert; } int abac_attribute_lastone(abac_attribute_t *ptr) { assert(ptr); if(ptr->refcount == 1) return 1; return 0; } abac_aspect_t **abac_attribute_tail_vectorized(abac_attribute_t *ptr) { abac_aspect_t **tails=NULL; abac_aspect_t *tail=ptr->tail; abac_list_t *list=NULL; int cnt=0; if(tail != NULL) { if(!abac_aspect_is_intersecting(tail)) { tails = abac_xmalloc(sizeof(abac_aspect_t *) * 2); tails[0] = abac_aspect_dup(tail); tails[1] = NULL; if(debug) { fprintf(stderr, "abac_attribute_tail_vectorized, only 1 tail\n"); } return tails; } else { abac_list_t *list=abac_aspect_prereqs(tail); cnt=abac_list_size(list); } } // make the array (leave space to NULL terminate it) // n.b., even if the list is empty, we still return an array that // only contains the NULL terminator tails = abac_xmalloc(sizeof(abac_aspect_t *) * (cnt + 1)); abac_aspect_t *cur; int i = 0; if(i