/** ** abac_verifier.c **/ // include the GNU extension of asprintf #define _GNU_SOURCE #include #include #include #include #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; /* from abac_attribute.c */ extern char *get_cred_encoding(abac_attribute_t *ptr); 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 abac_list_t *generate_pl_clauses(abac_aspect_t *, abac_aspect_t *); extern void generate_pl_set_abac_yyfptr_encoded(char *string); extern void abac_print_aspect_string_with_condition(abac_aspect_t *role, FILE*); extern int abac_id_load_privkey_chunk(abac_id_t *ptr, chunk_t keychunk); 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; /* linked list of all the ids's hashkeyid */ abac_list_t *id_hashkeyid_list = 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"); } } void abac_print_prin_info(abac_id_credential_t *prin, FILE *fp) { if(fp == NULL) return; abac_id_t *ptr=abac_id_credential_id(prin); if(debug) fprintf(fp,"---> printing out principal info ..\n"); if(abac_id_has_privkey(ptr)) fprintf(fp," (%s,%s,y)\n",abac_id_name(ptr),abac_id_idtype_string(ptr)); else fprintf(fp," (%s,%s,n)\n",abac_id_name(ptr),abac_id_idtype_string(ptr)); } // 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 int verify_signature(certificate_t *issuer_cert, certificate_t *cert) { /** XXX for 5.0.1 if (cert->issued_by(cert, issuer_cert, NULL)) */ if (cert->issued_by(cert, issuer_cert)) if (cert->get_validity(cert, NULL, NULL, NULL)) return 1; return 0; } // verify that cert is still valid static int _verify_validity(certificate_t *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(debug)fprintf(stderr, "abac_verifier_init... init strongswan..\n"); 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(); id_hashkeyid_list = abac_list_new(); } /** * Uninitialize the system, free up any allocated memory. */ void abac_verifier_deinit(void) { if(debug)fprintf(stderr, "abac_verifier_deinit... being called..\n"); abac_id_credential_t *ptr; while ((ptr = id_creds) != NULL) { if(debug) fprintf(stderr, "abac_verifier_deinit: deleting id (%s)\n",abac_id_name(ptr->id)); 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) { fprintf(stderr, "abac_verifier_deinit: deleting attr hashkey(%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) { if(debug) fprintf(stderr, "looking to free attr_hashkeyid_list..\n"); char *cur; abac_list_foreach(attr_hashkeyid_list, cur, if(cur) free(cur); ); abac_list_free(attr_hashkeyid_list); } if(id_hashkeyid_list) { if(debug) fprintf(stderr, "looking to free id_hashkeyid_list..\n"); char *cur; abac_list_foreach(id_hashkeyid_list, cur, if(cur) { if(debug) fprintf(stderr, "hum.. id hashkey being freed.. %s\n", cur); free(cur); } ); abac_list_free(id_hashkeyid_list); } if(debug) fprintf(stderr, "now it is time to deinit strongswan lib..\n"); 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) { fprintf(stderr, "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) fprintf(stderr, "-->adding into id_creds, (%s)..cnt(%d)(%d)\n", id_cred->hashkeyid, HASH_COUNT(id_creds),(int)id_cred); assert(id_hashkeyid_list); abac_list_add(id_hashkeyid_list, abac_xstrdup(id_cred->hashkeyid)); return id_cred; } /* have to find the last cn CN=test/emailAddress=abac.isi.edu, CN=12345678 CN=client ..CN=255a03f3-ed30/emailAddress=.. */ static char* _extract_cn(char *string) { /* find the first CN= */ char *ptr=strstr(string,"CN="); if(ptr == NULL) return NULL; /* look for last CN= */ while(1) { char *tptr=ptr+3; char *p=strstr(tptr,"CN="); if(p) ptr=p; else break; } /* remove the possible additional stuff */ char *cn=abac_xstrdup(ptr); /* it would get write over */ char *nptr=strtok(cn,"/"); char *pcn=abac_xmalloc(sizeof(char) * strlen(nptr)); pcn[0]='p'; /* special case.. replace empty space with _ */ int i=strlen(nptr); while(i--) if(nptr[i]==' ') nptr[i]='_'; sscanf(nptr,"CN=%s", &pcn[1]); free(cn); return pcn; } /** * 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=NULL; int rv = asprintf(&str, "%Y", cert->get_issuer(cert)); /* add p to cn name here, if there is no useable one reuse keyid */ char *cn=_extract_cn(str); if(cn == NULL) { if(debug) fprintf(stderr, "DEBUG:did not find usable cn, reuse keyid\n"); cn=abac_xstrdup(keyid); } if(debug) { fprintf(stderr, "DEBUG:keyid %s \n", keyid); fprintf(stderr, "DEBUG:issuer '%s' \n", str); fprintf(stderr, "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) fprintf(stderr, "existing cert \n"); ret = ABAC_CERT_EXISTS; goto error; } // validate validity ret = _verify_validity(cert); if (!ret) { ret = ABAC_CERT_INVALID; goto error; } // validate sig ret = verify_signature(cert, cert); if (!ret) { /* well.. this is not a self signed cert, don't fault it anymore */ if(debug) fprintf(stderr, "This is not a self-signed cert \n"); } else { if(debug) fprintf(stderr, "This is a self-signed cert \n"); } // 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; if (keyid != NULL) free(keyid); if (cn != NULL) free(cn); 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++; ); } if(debug) fprintf(stderr, "abac_verifier_dump_cred: %d\n",cnt); return cred_list; } /* collect all the id stored so far */ abac_stack_t *abac_verifier_dump_principals() { abac_stack_t *id_list = abac_stack_new(); int cnt=0; if(id_hashkeyid_list) { char *keyid; abac_id_credential_t *id; abac_list_foreach(id_hashkeyid_list, keyid, id=abac_id_credential_lookup(keyid); abac_stack_push(id_list, id); cnt++; ); } if(debug) fprintf(stderr, "abac_verifier_dump_principals: %d\n",cnt); return id_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; } /** * Load an ID cert from a file. */ int abac_verifier_load_id_file_key_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) fprintf(stderr, "loading id file... %s\n", filename); // load the cert, with public 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) fprintf(stderr, "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) && keyfilename!=NULL && file_exist(keyfilename)) { if(debug) fprintf(stderr, "loading... %s\n", keyfilename); int keyrc=abac_id_load_privkey_file(id, keyfilename); if(debug) { if(keyrc == 1) fprintf(stderr, "..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 ABAC_CERT_SUCCESS; } int abac_verifier_load_enc_id_file_key_file(char *filename, char *keyfilename, char *pfile, 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) fprintf(stderr, "loading id file... %s\n", filename); // load the cert, with public 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) fprintf(stderr, "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) && keyfilename!=NULL && file_exist(keyfilename)) { if(debug) fprintf(stderr, "loading... %s\n", keyfilename); int keyrc=abac_id_load_enc_privkey_file(id, keyfilename, pfile); if(debug) { if(keyrc == 1) fprintf(stderr, "..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 ABAC_CERT_SUCCESS; } /** * 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_pem_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_PEM, 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); } /** * Load an ID cert from a chunk, Note, this only loads the id cert part * and so it is not suitable for creating an attribute credential with. * Only a complete id cert + privkey could create attribute credential. */ 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); } /** * Load an ID cert from a cert chunk and a privkey chunk, * this complete id cert + privkey could create attribute credential. */ int abac_verifier_load_id_privkey_chunk(chunk_t chunk, chunk_t privkey_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; int rc=_load_id(&id, cert,id_cred_ret); if(rc == ABAC_CERT_SUCCESS) { rc=abac_id_load_privkey_chunk(id, privkey_chunk); } return rc; } int abac_verifier_load_id_enc_privkey_chunk(chunk_t chunk, chunk_t privkey_chunk, char* pfile, 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; int rc=_load_id(&id, cert,id_cred_ret); if(rc == ABAC_CERT_SUCCESS) { rc=abac_id_load_enc_privkey_chunk(id, privkey_chunk, pfile); } return rc; } abac_id_t *abac_verifier_load_issuer(char *filename, char *keyfilename) { abac_id_credential_t *id_cred=NULL; int ret=abac_verifier_load_id_file_key_file(filename,keyfilename,&id_cred); if(ret !=ABAC_CERT_SUCCESS) return NULL; abac_id_t *issuer=abac_id_credential_id(id_cred); return issuer; } static int matchex(const char *subject, const char *pattern, int *so, int *eo) { int rc; // Returned code regmatch_t pmatch; regex_t re; // Compiled regexp pattern if (regcomp(&re, pattern, 0) != 0) return 0; rc = regexec(&re, subject, 1 , &pmatch, 0); regfree(&re); if (rc == REG_NOMATCH ) return 0; *so=pmatch.rm_so; *eo=pmatch.rm_eo; return 1; } static chunk_t _extract_chunk(char *data, char* startline, char* endline) { int found=0; int startos=0; int endos=0; regex_t re; regmatch_t pm; int rc; int st; int et; rc=matchex(data, startline, &st, &et); if(rc==0) return chunk_empty; startos=st; rc=matchex(data, endline, &st, &et); if(rc==0) return chunk_empty; endos=et; int len=endos - startos; if(debug) fprintf(stderr, "making a chunk of size (%d) from %d and %d\n",len, startos,endos); char *ptr=strndup(data+startos,len); chunk_t ret = { ptr, len }; return ret; } int abac_verifier_load_idkey_file(char *filename, abac_id_credential_t **id_cred_ret) { struct stat sb; int fd; int rc; fd = open(filename, O_RDONLY); if (fd == -1) { return 1; } if(stat(filename, &sb) == -1) { close(fd); return 1; } char* data = (char *)mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if(data == MAP_FAILED) { close(fd); return 1; } close(fd); chunk_t key_pem_chunk=_extract_chunk(data, "-----BEGIN RSA PRIVATE KEY-----","-----END RSA PRIVATE KEY-----"); chunk_t cert_pem_chunk=_extract_chunk(data, "-----BEGIN CERTIFICATE-----","-----END CERTIFICATE-----"); /* key=0, cert=0 */ if(key_pem_chunk.len==0 && cert_pem_chunk.len==0) { if(debug) fprintf(stderr, "abac_verifier_load_idkey_file: no key or id in idkey_file\n"); goto error; } /* key=0, cert=1 */ if(key_pem_chunk.len==0) { if(debug) fprintf(stderr, "abac_verifier_load_idkey_file: no key in idkey_file\n"); munmap(data, sb.st_size); chunk_free(&key_pem_chunk); return abac_verifier_load_id_file_key_file(filename,NULL,id_cred_ret); } /* key=1, cert=1 */ if(cert_pem_chunk.len!=0) { if(debug) { fprintf(stderr, "loading cert pem chunk %d\n", cert_pem_chunk.len); printf("(%s)\n",cert_pem_chunk.ptr); } rc=abac_verifier_load_id_pem_chunk(cert_pem_chunk, id_cred_ret); if(rc != 0) { if(debug) fprintf(stderr, "abac_verifier_load_idkey_file: fail to load the id\n"); goto error; } /* key=1, cert=0 */ } else { if(debug) fprintf(stderr, "abac_verifier_load_idkey_file: there is no id info in there\n"); goto error; } /* handle the key_pem_chunk */ if(debug) { fprintf(stderr, "loading key pem chunk %d\n", key_pem_chunk.len); printf("(%s)\n",key_pem_chunk.ptr); } abac_id_t *id=abac_id_credential_id(*id_cred_ret); rc=abac_id_load_privkey_chunk(id, key_pem_chunk); if(rc==0) { printf("abac_verifier_load_idkey_file:failed to load priv key!!!\n"); goto error; } munmap(data, sb.st_size); return 0; error: munmap(data, sb.st_size); return 1; } int abac_verifier_load_enc_idkey_file(char *filename, char *pfile, abac_id_credential_t **id_cred_ret) { struct stat sb; int fd; int rc; fd = open(filename, O_RDONLY); if (fd == -1) { return 1; } if(stat(filename, &sb) == -1) { close(fd); return 1; } char* data = (char *)mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if(data == MAP_FAILED) { close(fd); return 1; } close(fd); chunk_t key_pem_chunk=_extract_chunk(data, "-----BEGIN RSA PRIVATE KEY-----","-----END RSA PRIVATE KEY-----"); chunk_t cert_pem_chunk=_extract_chunk(data, "-----BEGIN CERTIFICATE-----","-----END CERTIFICATE-----"); /* key=0, cert=0 */ if(key_pem_chunk.len==0 && cert_pem_chunk.len==0) { if(debug) fprintf(stderr, "abac_verifier_load_idkey_file: no key or id in idkey_file\n"); goto error; } /* key=0, cert=1 */ if(key_pem_chunk.len==0) { if(debug) fprintf(stderr, "abac_verifier_load_idkey_file: no key in idkey_file\n"); munmap(data, sb.st_size); chunk_free(&key_pem_chunk); return abac_verifier_load_id_file_key_file(filename,NULL,id_cred_ret); } /* key=1, cert=1 */ if(cert_pem_chunk.len!=0) { if(debug) { fprintf(stderr, "loading cert pem chunk %d\n", cert_pem_chunk.len); printf("(%s)\n",cert_pem_chunk.ptr); } rc=abac_verifier_load_id_pem_chunk(cert_pem_chunk, id_cred_ret); if(rc != 0) { if(debug) fprintf(stderr, "abac_verifier_load_idkey_file: fail to load the id\n"); goto error; } /* key=1, cert=0 */ } else { if(debug) fprintf(stderr, "abac_verifier_load_idkey_file: there is no id info in there\n"); goto error; } /* handle the key_pem_chunk */ if(debug) { fprintf(stderr, "loading key pem chunk %d\n", key_pem_chunk.len); printf("(%s)\n",key_pem_chunk.ptr); printf("(%d)\n",strlen(key_pem_chunk.ptr)); } abac_id_t *id=abac_id_credential_id(*id_cred_ret); rc=abac_id_load_enc_privkey_chunk(id, key_pem_chunk, pfile); if(rc==0) { printf("abac_verifier_load_idkey_file:failed to load priv key!!!\n"); goto error; } munmap(data, sb.st_size); return 0; error: munmap(data, sb.st_size); return 1; } 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); if(debug) fprintf(stderr, "calling abac_id_credential_dup, increment id ref count\n"); 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); if(id_cred != NULL) return abac_id_credential_dup(id_cred); else return NULL; } void abac_id_credential_free(abac_id_credential_t *ptr) { if (ptr == NULL) return; if(debug) fprintf(stderr, "abac_id_credential_free:freeing (%s)\n", abac_id_name(ptr->id)); // this is very hacky... int last=abac_id_lastone(ptr->id); if(!last) { if(debug) fprintf(stderr, "abac_id_credential_free:not last one\n"); abac_id_free(ptr->id); } else { if(debug) fprintf(stderr, "abac_id_credential_free: deleting id (%s)\n",abac_id_name(ptr->id)); 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_string(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) fprintf(stderr, "LOOKING for %s\n", principalname); HASH_FIND_STR(id_creds, principalname, id_cred); 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=id_cred->id; 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); 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)); if(debug) fprintf(stderr, "-->adding into attr_creds 2, (%s)..cnt(%d)\n", cred->hashkeyid, HASH_COUNT(attr_creds)); 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. * attribute string is parsed via yyparse call */ static int _load_attribute_cert(certificate_t *cert, abac_credential_t **cred_ret) { 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; } ret=_verify_valid_credential_string(cert,cred_ret,encoded_attr_string); if(ret != ABAC_CERT_SUCCESS) { char *tmp=NULL; asprintf(&tmp,"_load_attribute_cert: fail to verify credential (%s)",attr_string); panic(tmp); } // free up some crap attr_cert->destroy(attr_cert); return ret; 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. * attr should be all checked out before arriving here */ int abac_verifier_load_attribute_cert_attribute(abac_attribute_t *ptr, abac_credential_t **cred_ret) { // get the attr abac_aspect_t *head=abac_attribute_head(ptr); abac_aspect_t *tail=abac_attribute_tail(ptr); // preprocess for constraint part preprocess_pl_head(head); preprocess_pl_tail(tail); /* setup the encoded attribute string */ char *encoded_attr_string=get_cred_encoding(ptr); generate_pl_set_abac_yyfptr_encoded(encoded_attr_string); /* collect up type clauses, constraint clauses and generate rule clauses */ abac_list_t *clauses=generate_pl_clauses(head,tail); if(debug) abac_print_clauses(clauses,NULL); abac_credential_t *cred = abac_xmalloc(sizeof(abac_credential_t)); cred->hashkeyid=abac_xstrdup(encoded_attr_string); cred->attr=abac_attribute_dup(ptr); 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)); if(debug) fprintf(stderr, "-->adding into attr_creds, (%s)..cnt(%d)\n", cred->hashkeyid, HASH_COUNT(attr_creds)); return ABAC_CERT_SUCCESS; } /** * 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) fprintf(stderr, "..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 = chunk_empty; int rc=cert->get_encoding(cert,CERT_ASN1_DER,&encoding); 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 = chunk_empty; // XXX MEI, not sure ?? int rc=issuer_cert->get_encoding(issuer_cert,CERT_ASN1_DER,&encoding); 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) fprintf(stderr, "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) fprintf(stderr, "DEBUG:NOT FOUND..\n"); return NULL; } abac_credential_t *rt=abac_credential_dup(attr_cred); if(debug) fprintf(stderr, "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) fprintf(stderr, "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 { if(debug) fprintf(stderr, "abac_credential_free: real free for (%d)\n",(int) cred); 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) { // this id, sha string is not in the db... if(debug) fprintf(stderr,"abac_idtype_with_sha: this id is not in the id_creds list\n"); 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); }