diff options
-rw-r--r-- | src/charon/credentials/credential_manager.c | 315 | ||||
-rw-r--r-- | src/charon/credentials/credential_manager.h | 24 | ||||
-rw-r--r-- | src/charon/sa/authenticators/rsa_authenticator.c | 21 |
3 files changed, 231 insertions, 129 deletions
diff --git a/src/charon/credentials/credential_manager.c b/src/charon/credentials/credential_manager.c index 570420d78..3583771fd 100644 --- a/src/charon/credentials/credential_manager.c +++ b/src/charon/credentials/credential_manager.c @@ -303,10 +303,9 @@ static shared_key_t *get_shared(private_credential_manager_t *this, /** * forward declaration */ -static certificate_t *get_trusted_cert(private_credential_manager_t *this, - key_type_t type, identification_t *id, - auth_info_t *auth, bool crl, bool ocsp); +static enumerator_t *create_trusted_enumerator(private_credential_manager_t *this, + key_type_t type, identification_t *id, bool crl, bool ocsp); /** * Do an OCSP request */ @@ -362,10 +361,10 @@ static bool check_ocsp_response(private_credential_manager_t *this, { certificate_t *issuer, *subject; identification_t *responder; - auth_info_t *auth; ocsp_response_wrapper_t *wrapper; + enumerator_t *enumerator; + bool verified = FALSE; - auth = auth_info_create(); wrapper = ocsp_response_wrapper_create((ocsp_response_t*)response); this->sets->remove(this->sets, this->cache, NULL); this->sets->insert_first(this->sets, wrapper); @@ -373,25 +372,20 @@ static bool check_ocsp_response(private_credential_manager_t *this, subject = &response->certificate; responder = subject->get_issuer(subject); - issuer = get_trusted_cert(this, KEY_ANY, responder, auth, FALSE, FALSE); + enumerator = create_trusted_enumerator(this, KEY_ANY, responder, FALSE, FALSE); + while (enumerator->enumerate(enumerator, &issuer, NULL)) + { + if (this->cache->issued_by(this->cache, subject, issuer)) + { + verified = TRUE; + break; + } + } + enumerator->destroy(enumerator); this->sets->remove(this->sets, wrapper, NULL); wrapper->destroy(wrapper); - auth->destroy(auth); - - if (!issuer) - { - DBG1(DBG_CFG, "OCSP response verification failed, responder cert missing"); - return FALSE; - } - if (!this->cache->issued_by(this->cache, subject, issuer)) - { - DBG1(DBG_CFG, "OCSP response verification failed"); - issuer->destroy(issuer); - return FALSE; - } - issuer->destroy(issuer); - return TRUE; + return verified; } /** @@ -411,6 +405,7 @@ static certificate_t *get_better_ocsp(private_credential_manager_t *this, /* check ocsp signature */ if (!check_ocsp_response(this, response)) { + DBG1(DBG_CFG, "OCSP response verification failed"); cand->destroy(cand); return best; } @@ -552,7 +547,9 @@ static cert_validation_t check_ocsp(private_credential_manager_t *this, */ static certificate_t* fetch_crl(private_credential_manager_t *this, char *url) { - certificate_t *crl_cert; + certificate_t *crl, *issuer; + enumerator_t *enumerator; + bool verified = FALSE; chunk_t chunk; /* TODO: unlock the manager while fetching? */ @@ -562,45 +559,36 @@ static certificate_t* fetch_crl(private_credential_manager_t *this, char *url) DBG1(DBG_CFG, "crl fetching failed"); return NULL; } - crl_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL, - BUILD_BLOB_ASN1_DER, chunk, BUILD_END); - if (!crl_cert) + crl = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL, + BUILD_BLOB_ASN1_DER, chunk, BUILD_END); + if (!crl) { DBG1(DBG_CFG, "crl fetched successfully but parsing failed"); return NULL; } /* verify the signature of the fetched crl */ + enumerator = create_trusted_enumerator(this, KEY_ANY, crl->get_issuer(crl), + FALSE, FALSE); + while (enumerator->enumerate(enumerator, &issuer, NULL)) { - identification_t *issuer = crl_cert->get_issuer(crl_cert); - auth_info_t *auth = auth_info_create(); - certificate_t *issuer_cert = get_trusted_cert(this, KEY_ANY, issuer, - auth, FALSE, FALSE); - auth->destroy(auth); - - if (!issuer_cert) - { - DBG1(DBG_CFG, "crl is untrusted: issuer certificate not found"); - crl_cert->destroy(crl_cert); - return NULL; - } - - if (this->cache->issued_by(this->cache, crl_cert, issuer_cert)) + if (this->cache->issued_by(this->cache, crl, issuer)) { DBG1(DBG_CFG, " crl correctly signed by \"%D\"", - issuer_cert->get_subject(issuer_cert)); - issuer_cert->destroy(issuer_cert); - } - else - { - DBG1(DBG_CFG, "crl not accepted from \"%D\"", - issuer_cert->get_subject(issuer_cert)); - issuer_cert->destroy(issuer_cert); - crl_cert->destroy(crl_cert); - return NULL; + issuer->get_subject(issuer)); + verified = TRUE; + break; } } - return crl_cert; + enumerator->destroy(enumerator); + + if (!verified) + { + DBG1(DBG_CFG, "crl is untrusted: issuer certificate not found"); + crl->destroy(crl); + return NULL; + } + return crl; } /** @@ -967,90 +955,197 @@ static bool verify_trust_chain(private_credential_manager_t *this, } /** - * Get a trusted certificate by verifying the trust chain + * enumerator for trusted certificates + */ +typedef struct { + /** implements enumerator_t interface */ + enumerator_t public; + /** enumerator over candidate peer certificates */ + enumerator_t *candidates; + /** reference to the credential_manager */ + private_credential_manager_t *this; + /** type of the requested key */ + key_type_t type; + /** identity the requested key belongs to */ + identification_t *id; + /** TRUE to do CRL checking */ + bool crl; + /** TRUE to do OCSP checking */ + bool ocsp; + /** currently enumerating certificate */ + certificate_t *current; + /** currently enumerating auth info */ + auth_info_t *auth; +} trusted_enumerator_t; + +/** + * Implements trusted_enumerator_t.enumerate */ -static certificate_t *get_trusted_cert(private_credential_manager_t *this, - key_type_t type, identification_t *id, - auth_info_t *auth, bool crl, bool ocsp) +static bool trusted_enumerate(trusted_enumerator_t *this, + certificate_t **cert, auth_info_t **auth) { - certificate_t *subject, *current; - enumerator_t *enumerator; + DESTROY_IF(this->current); + DESTROY_IF(this->auth); + this->auth = auth_info_create(); - /* check if we have a trusted certificate for that peer */ - subject = get_pretrusted_cert(this, type, id); - if (subject) + if (!this->candidates) { - /* if we find a trusted self signed certificate, we just accept it */ - if (this->cache->issued_by(this->cache, subject, subject)) + /* first invocation, build enumerator for next one */ + this->candidates = create_cert_enumerator(this->this, CERT_ANY, + this->type, this->id, FALSE); + /* check if we have a trusted certificate for that peer */ + this->current = get_pretrusted_cert(this->this, this->type, this->id); + if (this->current) { - DBG1(DBG_CFG, " using trusted self-signed certificate \"%D\"", - subject->get_subject(subject)); - return subject; - } - - /* if we find a trusted certificate, we accept it. However, in order - * to fulfill authorization rules, we try to build the trust chain - * anyway. - */ - if (verify_trust_chain(this, subject, auth, TRUE, crl, ocsp)) - { - DBG1(DBG_CFG, " using trusted certificate \"%D\"", - subject->get_subject(subject)); - return subject; + /* if we find a trusted self signed certificate, we just accept it. + * However, in order to fulfill authorization rules, we try to build + * the trust chain if it is not self signed */ + if (this->this->cache->issued_by(this->this->cache, + this->current, this->current) || + verify_trust_chain(this->this, this->current, this->auth, + TRUE, this->crl, this->ocsp)) + { + DBG1(DBG_CFG, " using trusted certificate \"%D\"", + this->current->get_subject(this->current)); + *cert = this->current; + if (auth) + { + *auth = this->auth; + } + return TRUE; + } + return FALSE; } - subject->destroy(subject); } - - subject = NULL; /* try to verify the trust chain for each certificate found */ - enumerator = create_cert_enumerator(this, CERT_ANY, type, id, FALSE); - while (enumerator->enumerate(enumerator, ¤t)) + while (this->candidates->enumerate(this->candidates, &this->current)) { DBG1(DBG_CFG, " using certificate \"%D\"", - current->get_subject(current)); - if (verify_trust_chain(this, current, auth, FALSE, crl, ocsp)) + this->current->get_subject(this->current)); + if (verify_trust_chain(this->this, this->current, this->auth, FALSE, + this->crl, this->ocsp)) { - subject = current->get_ref(current); - break; + *cert = this->current->get_ref(this->current); + if (auth) + { + *auth = this->auth; + } + return TRUE; } } - enumerator->destroy(enumerator); + return FALSE; +} + +/** + * Implements trusted_enumerator_t.destroy + */ +static void trusted_destroy(trusted_enumerator_t *this) +{ + DESTROY_IF(this->current); + DESTROY_IF(this->auth); + DESTROY_IF(this->candidates); + free(this); +} + +/** + * create an enumerator over trusted certificates and their trustchain + */ +static enumerator_t *create_trusted_enumerator(private_credential_manager_t *this, + key_type_t type, identification_t *id, bool crl, bool ocsp) +{ + trusted_enumerator_t *enumerator = malloc_thing(trusted_enumerator_t); - if (!subject) + enumerator->public.enumerate = (void*)trusted_enumerate; + enumerator->public.destroy = (void*)trusted_destroy; + + enumerator->candidates = NULL; + enumerator->this = this; + enumerator->type = type; + enumerator->id = id; + enumerator->crl = crl; + enumerator->ocsp = ocsp; + enumerator->current = NULL; + enumerator->auth = NULL; + + return &enumerator->public; +} + +/** + * enumerator for public keys + */ +typedef struct { + /** implements enumerator_t interface */ + enumerator_t public; + /** enumerator over candidate peer certificates */ + enumerator_t *inner; + /** reference to the credential_manager */ + private_credential_manager_t *this; + /** currently enumerating key */ + public_key_t *current; + /** credset wrapper around auth */ + auth_info_wrapper_t *wrapper; +} public_enumerator_t; + +/** + * Implements public_enumerator_t.enumerate + */ +static bool public_enumerate(public_enumerator_t *this, + public_key_t **key, auth_info_t **auth) +{ + certificate_t *cert; + + while (this->inner->enumerate(this->inner, &cert, auth)) { - DBG1(DBG_CFG, "no trusted certificate found for '%D'", id); + DESTROY_IF(this->current); + this->current = cert->get_public_key(cert); + if (this->current) + { + *key = this->current; + return TRUE; + } } - return subject; + return FALSE; } /** - * Implementation of credential_manager_t.get_public. + * Implements public_enumerator_t.destroy */ -static public_key_t *get_public(private_credential_manager_t *this, - key_type_t type, identification_t *id, - auth_info_t *auth) +static void public_destroy(public_enumerator_t *this) { - public_key_t *public = NULL; - certificate_t *cert; - auth_info_wrapper_t *wrapper; + if (this->wrapper) + { + this->this->sets->remove(this->this->sets, this->wrapper, NULL); + this->this->mutex->unlock(this->this->mutex); + this->wrapper->destroy(this->wrapper); + } + DESTROY_IF(this->current); + this->inner->destroy(this->inner); + free(this); +} + +/** + * Implementation of credential_manager_t.create_public_enumerator. + */ +static enumerator_t* create_public_enumerator(private_credential_manager_t *this, + key_type_t type, identification_t *id, auth_info_t *auth) +{ + public_enumerator_t *enumerator = malloc_thing(public_enumerator_t); - wrapper = auth_info_wrapper_create(auth); + enumerator->public.enumerate = (void*)public_enumerate; + enumerator->public.destroy = (void*)public_destroy; + enumerator->inner = create_trusted_enumerator(this, type, id, TRUE, TRUE); + enumerator->this = this; + enumerator->current = NULL; + enumerator->wrapper = NULL; this->mutex->lock(this->mutex); - this->sets->remove(this->sets, this->cache, NULL); - this->sets->insert_first(this->sets, wrapper); - this->sets->insert_first(this->sets, this->cache); - - cert = get_trusted_cert(this, type, id, auth, TRUE, TRUE); - if (cert) + if (auth) { - public = cert->get_public_key(cert); - cert->destroy(cert); + enumerator->wrapper = auth_info_wrapper_create(auth); + this->sets->remove(this->sets, this->cache, NULL); + this->sets->insert_first(this->sets, enumerator->wrapper); + this->sets->insert_first(this->sets, this->cache); } - - this->sets->remove(this->sets, wrapper, NULL); - wrapper->destroy(wrapper); - this->mutex->unlock(this->mutex); - return public; + return &enumerator->public; } /** @@ -1288,7 +1383,7 @@ credential_manager_t *credential_manager_create() this->public.get_cert = (certificate_t *(*)(credential_manager_t *this,certificate_type_t cert, key_type_t key,identification_t *, bool))get_cert; this->public.get_shared = (shared_key_t *(*)(credential_manager_t *this,shared_key_type_t type,identification_t *me, identification_t *other))get_shared; this->public.get_private = (private_key_t*(*)(credential_manager_t*, key_type_t type, identification_t *, auth_info_t*))get_private; - this->public.get_public = (public_key_t*(*)(credential_manager_t*, key_type_t type, identification_t *, auth_info_t*))get_public; + this->public.create_public_enumerator = (enumerator_t*(*)(credential_manager_t*, key_type_t type, identification_t *id, auth_info_t *aut))create_public_enumerator; this->public.flush_cache = (void(*)(credential_manager_t*, certificate_type_t type))flush_cache; this->public.add_set = (void(*)(credential_manager_t*, credential_set_t *set))add_set; this->public.remove_set = (void(*)(credential_manager_t*, credential_set_t *set))remove_set; diff --git a/src/charon/credentials/credential_manager.h b/src/charon/credentials/credential_manager.h index ca22f98a2..9f9d6136f 100644 --- a/src/charon/credentials/credential_manager.h +++ b/src/charon/credentials/credential_manager.h @@ -144,20 +144,24 @@ struct credential_manager_t { */ private_key_t* (*get_private)(credential_manager_t *this, key_type_t type, identification_t *id, auth_info_t *auth); + /** - * Get a public key to verify a signature. + * Create an enumerator over trusted public keys. * - * The get_public() method gets a trusted public key to verify a signature - * of id. The auth parameter contains additional authentication infos, - * e.g. peer and intermediate certificates. + * This method gets a an enumerator over trusted public keys to verify a + * signature created by id. The auth parameter contains additional + * authentication infos, e.g. peer and intermediate certificates. + * The resulting enumerator enumerates over public_key_t *, auth_info_t *, + * where the auth info contains gained privileges for the authorization + * process. * - * @param type type of key to get - * @param id identification the key belongs to - * @param auth auth_info helper, including certificates to verify key - * @return public_key_t, NULL if none found + * @param type type of the key to get + * @param id owner of the key, signer of the signature + * @param auth authentication infos + * @return enumerator */ - public_key_t* (*get_public)(credential_manager_t *this, key_type_t type, - identification_t *id, auth_info_t *auth); + enumerator_t* (*create_public_enumerator)(credential_manager_t *this, + key_type_t type, identification_t *id, auth_info_t *auth); /** * Flush the certificate cache. diff --git a/src/charon/sa/authenticators/rsa_authenticator.c b/src/charon/sa/authenticators/rsa_authenticator.c index 9f34d51db..fff660b3c 100644 --- a/src/charon/sa/authenticators/rsa_authenticator.c +++ b/src/charon/sa/authenticators/rsa_authenticator.c @@ -58,7 +58,8 @@ static status_t verify(private_rsa_authenticator_t *this, chunk_t ike_sa_init, chunk_t auth_data, octets; identification_t *other_id; prf_t *prf; - auth_info_t *auth; + auth_info_t *auth, *current_auth; + enumerator_t *enumerator; status_t status = FAILED; other_id = this->ike_sa->get_other_id(this->ike_sa); @@ -73,9 +74,9 @@ static status_t verify(private_rsa_authenticator_t *this, chunk_t ike_sa_init, octets = build_tbs_octets(ike_sa_init, my_nonce, other_id, prf); auth = this->ike_sa->get_other_auth(this->ike_sa); - public = charon->credentials->get_public(charon->credentials, KEY_RSA, - other_id, auth); - if (public) + enumerator = charon->credentials->create_public_enumerator( + charon->credentials, KEY_RSA, other_id, auth); + while (enumerator->enumerate(enumerator, &public, ¤t_auth)) { /* We are currently fixed to SHA1 hashes. * TODO: allow other hash algorithms and note it in "auth" */ @@ -84,13 +85,15 @@ static status_t verify(private_rsa_authenticator_t *this, chunk_t ike_sa_init, DBG1(DBG_IKE, "authentication of '%D' with %N successful", other_id, auth_method_names, AUTH_RSA); status = SUCCESS; + auth->merge(auth, current_auth); + break; + } + else + { + DBG1(DBG_IKE, "signature validation failed, looking for another key"); } - public->destroy(public); - } - else - { - DBG1(DBG_IKE, "no trusted public key found for '%D'", other_id); } + enumerator->destroy(enumerator); chunk_free(&octets); return status; } |