#include #include #include #include #include #include "abac_verifier.h" #include "abac_util.h" typedef struct _abac_id_cert_t { char *keyid; certificate_t *cert; UT_hash_handle hh; } abac_id_cert_t; struct _abac_credential_t { abac_role_t *head; abac_role_t *tail; certificate_t *cert; certificate_t *issuer; int refcount; }; abac_id_cert_t *id_certs = NULL; // 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, certificate_t *cert) { // XXX make sure this checks signature if (cert->issued_by(cert, issuer)) if (cert->get_validity(cert, NULL, NULL, NULL)) return 1; return 0; } /** * Init the verifier subsystem. */ void abac_verifier_init(void) { atexit(library_deinit); // silence all debugging dbg_default_set_level(-1); 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); } /** * Uninitialize the system, free up any allocated memory. */ void abac_verifier_deinit(void) { abac_id_cert_t *id; while ((id = id_certs) != NULL) { HASH_DEL(id_certs, id); free(id->keyid); id->cert->destroy(id->cert); free(id); } } /** * Load an ID certificate. */ static int _load_id(certificate_t *cert) { abac_id_cert_t *id_cert = NULL; char *keyid = NULL; chunk_t id; int ret; x509_t *x509 = (x509_t *)cert; assert(cert != NULL); // get the key ID id = x509->get_subjectKeyIdentifier(x509); keyid = _chunk_to_string(id); // if we already have this cert 'error' with success HASH_FIND_STR(id_certs, keyid, id_cert); if (id_cert != NULL) { ret = ABAC_CERT_SUCCESS; goto error; } // validate sig ret = _verify_signature(cert, cert); if (!ret) { ret = ABAC_CERT_BAD_SIG; goto error; } // success, add the key to the map of certificates id_cert = abac_xmalloc(sizeof(abac_id_cert_t)); id_cert->keyid = keyid; id_cert->cert = cert; HASH_ADD_KEYPTR(hh, id_certs, id_cert->keyid, strlen(id_cert->keyid), id_cert); return ABAC_CERT_SUCCESS; error: if (keyid != NULL) free(keyid); return ret; } /** * Load an ID cert from a file. */ int abac_verifier_load_id_file(char *filename) { if (lib == NULL) errx(1, "looks like you didn't call libabac_init() (lib is NULL)"); // load the cert 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; return _load_id(cert); } /** * Load an ID cert from a chunk. */ int abac_verifier_load_id_chunk(chunk_t chunk) { // 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(cert); } /** * 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_role_t *head_role = NULL; abac_role_t *tail_role = NULL; abac_id_cert_t *issuer; int ret; // 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 *attr_string = attr_cert->get_string(attr_cert); if (attr_string == NULL) { ret = ABAC_CERT_INVALID; goto error; } // split into head/tail parts char head[256], tail[256]; ret = sscanf(attr_string, "%255s <- %255s", head, tail); if (ret != 2) { ret = ABAC_CERT_INVALID; goto error; } // must be a role head_role = abac_role_from_string(head); if (head_role == NULL) goto error; if (!abac_role_is_role(head_role)) { ret = ABAC_CERT_INVALID; goto error; } // make sure the tail role is valid tail_role = abac_role_from_string(tail); if (tail_role == NULL) { ret = ABAC_CERT_INVALID; goto error; } // get the issuer based on keyid char *principal = abac_role_principal(head_role); HASH_FIND_STR(id_certs, principal, issuer); if (issuer == NULL) { ret = ABAC_CERT_MISSING_ISSUER; goto error; } // make sure the issuer's signed it ret = _verify_signature(issuer->cert, cert); if (!ret) { ret = ABAC_CERT_BAD_SIG; goto error; } // at this point we know we have a good attribute cert abac_credential_t *cred = abac_xmalloc(sizeof(abac_credential_t)); cred->head = head_role; cred->tail = tail_role; cred->cert = cert; cred->issuer = issuer->cert->get_ref(issuer->cert); cred->refcount = 1; *cred_ret = cred; // free up some crap attr_cert->destroy(attr_cert); return ABAC_CERT_SUCCESS; error: if (cert != NULL) cert->destroy(cert); if (attr_cert != NULL) attr_cert->destroy(attr_cert); if (head_role != NULL) abac_role_free(head_role); if (tail_role != NULL) abac_role_free(tail_role); return ret; } /** * Load an attribute cert from a file. */ int abac_verifier_load_attribute_cert_file(char *filename, abac_credential_t **cred) { // load the cert 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 head role. */ abac_role_t *abac_credential_head(abac_credential_t *cred) { return cred->head; } /** * Return the tail role. */ abac_role_t *abac_credential_tail(abac_credential_t *cred) { return cred->tail; } /** * Return the encoding of the attribute cert. */ abac_chunk_t abac_credential_attribute_cert(abac_credential_t *cred) { chunk_t encoding = cred->cert->get_encoding(cred->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) { chunk_t encoding = cred->issuer->get_encoding(cred->issuer); abac_chunk_t ret = { encoding.ptr, encoding.len }; return ret; } /** * Increase the ref count of a credential. */ abac_credential_t *abac_credential_dup(abac_credential_t *cred) { assert(cred != NULL); ++cred->refcount; return cred; } /** * Decrease the reference count of a credential, freeing it when it reaches 0. */ void abac_credential_free(abac_credential_t *cred) { if (cred == NULL) return; --cred->refcount; if (cred->refcount > 0) return; abac_role_free(cred->head); abac_role_free(cred->tail); cred->cert->destroy(cred->cert); cred->issuer->destroy(cred->issuer); // reference counted free(cred); }