/** ** abac_verifier.c **/ // include the GNU extension of asprintf #define _GNU_SOURCE #include #include #include #include #include #include #include "abac_internal.h" #include "abac_verifier.h" #include "abac_util.h" #include "abac_rt.h" static int debug=0; 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 char *generate_pl_type_clause(char *, int); extern void abac_print_aspect_string_with_condition(abac_aspect_t *role, FILE*); struct _abac_id_credential_t { char *hashkeyid; abac_id_t *id; char *pl_clause; UT_hash_handle hh; }; /* hash table base on sha with a p */ abac_id_credential_t *id_creds = NULL; /* can store either role or oset */ struct _abac_credential_t { char *hashkeyid; abac_attribute_t *attr; abac_list_t *pl_clauses; UT_hash_handle hh; }; /* hash table base on encoded attr rule */ abac_credential_t *attr_creds = NULL; /* linked list of all the attr's hashkeyid */ abac_list_t *attr_hashkeyid_list = NULL; /*****************************************************************************/ void abac_print_cred_info(abac_credential_t *cred, FILE *fp) { if(fp == NULL) fp=stdout; abac_attribute_t *ptr=cred->attr; abac_aspect_t *head=abac_attribute_head(ptr); abac_aspect_t *tail=abac_attribute_tail(ptr); if(debug) { fprintf(fp,"---> printing out credential info cred(%d)..\n", (int) cred); if(head) { abac_print_aspect_string_with_condition(head,fp); } if(tail) { abac_print_aspect_string_with_condition(tail,fp); } abac_list_t *clauses=cred->pl_clauses; if (clauses != NULL) { char *cur=NULL; abac_list_foreach(clauses, cur, fprintf(fp,"\n a clause(%d):\n",(int)cur); if(cur) fprintf(fp,"strlen(%d)loc(%d)(%s)\n", strlen(cur),(int)cur, cur); ); } } else { fprintf(fp," "); abac_print_aspect_string_with_condition(head,fp); fprintf(fp," <- "); abac_print_aspect_string_with_condition(tail,fp); fprintf(fp,"\n"); } } // int abac_verify_idtype_type(char *type) { int i; if (type == NULL) return 0; for (i = 1; i <= _idtypename_cnt ; i++) if(strcmp(type,_idtypename[i])==0) return i; return 0; } char *abac_idtype_string(int i) { if(i > _idtypename_cnt) { printf("bad idtypename idx %d\n", i); panic("abac_idtype_string: went out of range on idtypename"); } return (char*) _idtypename[i]; } // convert a chunk to a lowercase binary string // malloc's the string static char *_chunk_to_string(chunk_t chunk) { int i; char *ret = abac_xmalloc(chunk.len * 2 + 1); for (i = 0; i < chunk.len; ++i) sprintf(ret + 2 * i, "%02x", chunk.ptr[i]); return ret; } // verify that cert was issued by issuer // cert and issuer can be the same, in which case the self-sig is validated static int _verify_signature(certificate_t *issuer_cert, certificate_t *cert) { if (cert->issued_by(cert, issuer_cert)) if (cert->get_validity(cert, NULL, NULL, NULL)) return 1; return 0; } /** * Init the verifier subsystem. */ void abac_verifier_init(void) { // silence all debugging if (!library_init(NULL)) exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); if (!lib->plugins->load(lib->plugins, NULL, lib->settings->get_str(lib->settings, "pki.load", PLUGINS))) exit(SS_RC_INITIALIZATION_FAILED); attr_hashkeyid_list = abac_list_new(); } /** * Uninitialize the system, free up any allocated memory. */ void abac_verifier_deinit(void) { abac_id_credential_t *ptr; while ((ptr = id_creds) != NULL) { HASH_DEL(id_creds, ptr); free(ptr->hashkeyid); free(ptr->pl_clause); abac_id_free(ptr->id); free(ptr); } abac_credential_t *ptr2; while ((ptr2 = attr_creds) != NULL) { HASH_DEL(attr_creds, ptr2); if(debug) { printf("attr_creds -- %s\n",ptr2->hashkeyid); } free(ptr2->hashkeyid); abac_attribute_free(ptr2->attr); char *cur=NULL; abac_list_foreach(ptr2->pl_clauses, cur, free(cur); ); free(ptr2->pl_clauses); free(ptr2); } if(attr_hashkeyid_list) { char *cur; if(attr_hashkeyid_list) { abac_list_foreach(attr_hashkeyid_list, cur, if(cur) free(cur); ); } abac_list_free(attr_hashkeyid_list); } library_deinit(); } abac_id_credential_t *abac_verifier_add_id_credential(abac_id_t *a_id) { abac_id_credential_t *id_cred; char *cn=abac_id_cn(a_id); char *keyid=abac_id_keyid(a_id); if(debug) { printf("abac_verifier_add_id_credential, cn(%s),keyid(%s)\n", cn, keyid); } // add the abac_id to the map of id credentials id_cred = abac_xmalloc(sizeof(abac_id_credential_t)); id_cred->hashkeyid = abac_xstrdup(keyid); id_cred->id=abac_id_dup(a_id); /* special handling here */ if(USE("ABAC_CN")) { id_cred->pl_clause = generate_pl_type_clause(cn, abac_id_idtype(a_id)); } else { id_cred->pl_clause=generate_pl_type_clause(prologIt(keyid), abac_id_idtype(a_id)); } HASH_ADD_KEYPTR(hh, id_creds, id_cred->hashkeyid, strlen(id_cred->hashkeyid), id_cred); if(debug) printf("-->adding into id_creds, (%s)..cnt(%d)\n", id_cred->hashkeyid, HASH_COUNT(id_creds)); return id_cred; } /** * Load an ID */ static int _load_id(abac_id_t **a_id,certificate_t *cert, abac_id_credential_t **id_cred_ret) { abac_id_credential_t *id_cred = NULL; char *keyid = NULL; chunk_t id; int ret; x509_t *x509 = (x509_t *)cert; assert(cert != NULL); // get the key ID, add p to keyid SHA here */ id = x509->get_subjectKeyIdentifier(x509); keyid = _chunk_to_string(id); /* Mike said this is the way it is */ char *str; int rv = asprintf(&str, "%Y", cert->get_issuer(cert)); /* add p to cn name here */ char *cn=(char *)abac_xmalloc(strlen(str)+2); cn[0]='p'; int n=sscanf(str,"CN=%s", &(cn[1])); if ( n!=1 ) { ret = ABAC_CERT_BAD_CN; goto error; } if(debug) { printf ("DEBUG:keyid %s \n", keyid); printf( "DEBUG:issuer '%s' \n", str); printf ("DEBUG:cn %s \n", cn); } free(str); // if we already have this cert 'error' with success HASH_FIND_STR(id_creds, keyid, id_cred); if (id_cred != NULL) { if(debug) printf("existing cert \n"); ret = ABAC_CERT_EXISTS; goto error; } // validate sig ret = _verify_signature(cert, cert); if (!ret) { ret = ABAC_CERT_BAD_SIG; goto error; } // success, add a new abac_id if(*a_id==NULL) { *a_id=abac_id_keyid_new(keyid,cn,cert); } abac_id_credential_t *n_id_cred=abac_verifier_add_id_credential(*a_id); *id_cred_ret=n_id_cred; return ABAC_CERT_SUCCESS; error: if (keyid != NULL) free(keyid); if (cn != NULL) free(cn); return ret; } /* collect all the creds stored so far */ abac_stack_t *abac_verifier_dump_creds() { abac_stack_t *cred_list = abac_stack_new(); int cnt=0; if(attr_hashkeyid_list) { char *keyid; abac_credential_t *cred; abac_list_foreach(attr_hashkeyid_list, keyid, cred=abac_credential_lookup(keyid); abac_stack_push(cred_list, cred); cnt++; ); } return cred_list; } static void check_id_cred(abac_id_credential_t *id_cred) { if(id_cred) { printf("checking on this id_cred location %d\n", (int)id_cred); printf(" --> sha is (%s)\n", abac_id_keyid(id_cred->id)); printf(" --> cn is (%s)\n", abac_id_cn(id_cred->id)); } } /** * Load an attribute cert as string. * have minimum syntax & validity check */ static int _load_attribute_string(char* attr_string) { printf("NOT implemented yet!!!"); return ABAC_CERT_INVALID; } int _exist(char *filename) { struct stat stbuf; if(stat(filename,&stbuf) == -1) return 0; return 1; } /** * Load an ID cert from a file. */ int abac_verifier_load_id_file(char *filename, char *keyfilename, abac_id_credential_t **id_cred_ret) { abac_id_t *id=NULL; if (lib == NULL) errx(1, "looks like you didn't call libabac_init() (lib is NULL)"); if(debug) printf("loading id file... %s\n", filename); // load the cert, with pubic key certificate_t *cert = lib->creds->create( lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, filename, BUILD_X509_FLAG, X509_AA, // attribute authority, dumb BUILD_END ); if (cert == NULL) return ABAC_CERT_INVALID; int rc=_load_id(&id,cert,id_cred_ret); if(rc==ABAC_CERT_EXISTS) { if(debug) printf("abac_verifier_load_id_files: id already exists\n"); return ABAC_CERT_SUCCESS; } /* try to load the private key if it is there */ if((rc==ABAC_CERT_SUCCESS) && _exist(keyfilename)) { if(debug) printf("loading... %s\n", keyfilename); int keyrc=abac_id_load_privkey(id, keyfilename); if(debug) { if(keyrc == 1) printf("..load_id_file: load(%s) with a private key\n",filename); else printf("..load_id_file: load(%s) without a private key\n",filename); } } return rc; } /** * Load an ID cert from a abac_id_t */ int abac_verifier_load_id_id(abac_id_t *id, abac_id_credential_t **id_cred_ret) { certificate_t *cert = abac_id_cert(id); return _load_id(&id,cert,id_cred_ret); } /** * Load an ID cert from a chunk. */ int abac_verifier_load_id_chunk(chunk_t chunk, abac_id_credential_t **id_cred_ret) { abac_id_t *id=NULL; // load the cert certificate_t *cert = lib->creds->create( lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_BLOB_ASN1_DER, chunk, BUILD_X509_FLAG, X509_AA, // attribute authority, dumb BUILD_END ); if (cert == NULL) return ABAC_CERT_INVALID; return _load_id(&id, cert,id_cred_ret); } void abac_print_clauses(abac_list_t *clauses, FILE *fp) { if (clauses != NULL) { char *cur; printf("total-- %d clauses\n", abac_list_size(clauses)); abac_list_foreach(clauses, cur, if(cur) { if(fp) fprintf (fp,"a clause, %d(%s)\n", (int)cur,cur); else printf ("a clause, %d(%s)\n", (int)cur,cur); } ); } } abac_id_credential_t *abac_id_credential_dup(abac_id_credential_t *ptr) { assert(ptr != NULL); abac_id_dup(ptr->id); return ptr; } abac_id_t *abac_id_credential_id(abac_id_credential_t *ptr) { assert(ptr); return ptr->id; } abac_id_credential_t *abac_id_credential_lookup(char *pname) { abac_id_credential_t *id_cred=NULL; HASH_FIND_STR(id_creds, pname, id_cred); return id_cred; } void abac_id_credential_free(abac_id_credential_t *ptr) { if (ptr == NULL) return; // this is very hacky... int last=abac_id_lastone(ptr->id); if(!last) { abac_id_free(ptr->id); } else { free(ptr->hashkeyid); if(ptr->pl_clause) free(ptr->pl_clause); abac_id_free(ptr->id); HASH_DEL(id_creds, ptr); free(ptr); } } /****************************************************************************/ static int _verify_valid_credential(certificate_t *cert, abac_credential_t **cred_ret, char *encoded_attr_string) { 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; int ret, i; // 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) printf("LOOKING for %s\n", principalname); HASH_FIND_STR(id_creds, principalname, id_cred); if(id_cred == NULL) { ret = ABAC_CERT_MISSING_ISSUER; if(debug) printf("can not find %s in id_creds\n", principalname); goto error; } issuer_id=id_cred->id; if (issuer_id == NULL) { ret = ABAC_CERT_MISSING_ISSUER; if(debug) printf("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); 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); abac_credential_t *cred = abac_xmalloc(sizeof(abac_credential_t)); cred->hashkeyid=abac_xstrdup(encoded_attr_string); cred->attr=attr; cred->pl_clauses = clauses; *cred_ret = cred; // success, add the key to the map of certificates HASH_ADD_KEYPTR(hh, attr_creds, cred->hashkeyid, strlen(cred->hashkeyid), cred); assert(attr_hashkeyid_list); abac_list_add(attr_hashkeyid_list, abac_xstrdup(cred->hashkeyid)); return ABAC_CERT_SUCCESS; error: if (head_aspect) abac_aspect_free(head_aspect); if (tail_aspect) abac_aspect_free(tail_aspect); abac_yy_free_rule_clauses(); return ret; } /** * Load an attribute cert. * Returns true only if the certificate is valid and is issued by the proper * authority. */ static int _load_attribute_cert(certificate_t *cert, abac_credential_t **cred_ret) { ietf_attributes_t *attr_cert = NULL; abac_id_credential_t *issuer; 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) printf("string to be yyparse..(%s)\n",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; } ret=_verify_valid_credential(cert,cred_ret,encoded_attr_string); // free up some crap attr_cert->destroy(attr_cert); return ABAC_CERT_SUCCESS; error: if (cert) cert->destroy(cert); if (attr_cert) attr_cert->destroy(attr_cert); return ret; } /** * Load an attribute cert from a abac_attribute_t. */ int abac_verifier_load_attribute_cert_attribute(abac_attribute_t *attr, abac_credential_t **cred) { // load the cert certificate_t *cert = abac_attribute_cert(attr); if (cert == NULL) return ABAC_CERT_INVALID; // XXX need to skip the parsing part return _load_attribute_cert(cert, cred); } /** * Load an attribute cert from a file. */ int abac_verifier_load_attribute_cert_file(char *filename, abac_credential_t **cred) { // load the cert if(debug) printf("..loading attr file %s\n", filename); certificate_t *cert = lib->creds->create( lib->creds, CRED_CERTIFICATE, CERT_X509_AC, BUILD_FROM_FILE, filename, BUILD_END ); if (cert == NULL) return ABAC_CERT_INVALID; return _load_attribute_cert(cert, cred); } /** * Load an attribute cert from a chunk. */ int abac_verifier_load_attribute_cert_chunk(chunk_t chunk, abac_credential_t **cred) { // load the cert certificate_t *cert = lib->creds->create( lib->creds, CRED_CERTIFICATE, CERT_X509_AC, BUILD_BLOB_ASN1_DER, chunk, BUILD_END ); if (cert == NULL) return ABAC_CERT_INVALID; return _load_attribute_cert(cert, cred); } /** * Return the encoding of the attribute cert. */ abac_chunk_t abac_credential_attribute_cert(abac_credential_t *cred) { abac_attribute_t *ptr=cred->attr; certificate_t *cert=abac_attribute_cert(ptr); chunk_t encoding = cert->get_encoding(cert); abac_chunk_t ret = { encoding.ptr, encoding.len }; return ret; } /** * Return the encoding of the issuer cert. */ abac_chunk_t abac_credential_issuer_cert(abac_credential_t *cred) { certificate_t *issuer_cert=abac_attribute_issuer_cert(cred->attr); assert(issuer_cert); chunk_t encoding = issuer_cert->get_encoding(issuer_cert); abac_chunk_t ret = { encoding.ptr, encoding.len }; return ret; } /** * Return the clause of the cert */ abac_list_t *abac_credential_clauses(abac_credential_t *cred) { return cred->pl_clauses; } abac_attribute_t *abac_credential_attribute(abac_credential_t *cred) { assert(cred); return cred->attr; } /** * Increase the ref count of a credential. */ abac_credential_t *abac_credential_dup(abac_credential_t *cred) { assert(cred != NULL); abac_attribute_dup(cred->attr); return cred; } /** * lookup for a credential. */ abac_credential_t *abac_credential_lookup(char* cred_string) { if(debug) printf("abac_credential_lookup: looking for (%s)\n", cred_string); abac_credential_t *attr_cred; HASH_FIND_STR(attr_creds, cred_string, attr_cred); if (attr_cred == NULL) { if(debug) printf("DEBUG:NOT FOUND..\n"); return NULL; } abac_credential_t *rt=abac_credential_dup(attr_cred); if(debug) printf("DEBUG:FOUND.. (%d) returning, (%d)\n", (int)attr_cred, (int) rt); return rt; } /** * Decrease the reference count of a credential, freeing it when it reaches 0. */ void abac_credential_free(abac_credential_t *cred) { if(debug) printf("abac_credential_free:freeing cred(%d)clause(%d)\n", (int)cred, (int)cred->pl_clauses); if (cred == NULL) return; // this is very hacky... int last=abac_attribute_lastone(cred->attr); if(!last) { abac_attribute_free(cred->attr); } else { free(cred->hashkeyid); char *cur=NULL; abac_list_foreach(cred->pl_clauses, cur, free(cur); ); abac_attribute_free(cred->attr); HASH_DEL(attr_creds, cred); free(cred); } } char *abac_id_clause(abac_id_credential_t *id_cred) { if(id_cred) return id_cred->pl_clause; return NULL; } /* retrieve the cn that is associated with this sha_string */ char *abac_cn_with_sha(char *sha_string) { // get the issuer based on keyid abac_id_credential_t *id_cred; HASH_FIND_STR(id_creds, sha_string, id_cred); if (id_cred == NULL) { return NULL; } if(debug) check_id_cred(id_cred); return abac_id_cn(id_cred->id); } char *abac_idtype_with_sha(char* sha_string) { // get the issuer based on keyid abac_id_credential_t *id_cred; HASH_FIND_STR(id_creds, sha_string, id_cred); if (id_cred == NULL) { return NULL; } int idtype=abac_id_idtype(id_cred->id); return abac_idtype_string(idtype); } abac_aspect_t *abac_credential_head(abac_credential_t *cred) { return abac_attribute_head(cred->attr); } abac_aspect_t *abac_credential_tail(abac_credential_t *cred) { return abac_attribute_tail(cred->attr); }