replaced get_public() by create_public_enumerator() to try multiple public keys for signature verification

This commit is contained in:
Martin Willi
2008-03-27 19:07:23 +00:00
parent 0d30ba3343
commit d20e5c6ab5
3 changed files with 237 additions and 135 deletions
+211 -116
View File
@@ -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
*/
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)
{
certificate_t *subject, *current;
enumerator_t *enumerator;
/* check if we have a trusted certificate for that peer */
subject = get_pretrusted_cert(this, type, id);
if (subject)
{
/* if we find a trusted self signed certificate, we just accept it */
if (this->cache->issued_by(this->cache, subject, subject))
{
DBG1(DBG_CFG, " using trusted self-signed certificate \"%D\"",
subject->get_subject(subject));
return subject;
}
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;
/* 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;
}
subject->destroy(subject);
}
/**
* Implements trusted_enumerator_t.enumerate
*/
static bool trusted_enumerate(trusted_enumerator_t *this,
certificate_t **cert, auth_info_t **auth)
{
DESTROY_IF(this->current);
DESTROY_IF(this->auth);
this->auth = auth_info_create();
subject = NULL;
if (!this->candidates)
{
/* 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)
{
/* 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;
}
}
/* try to verify the trust chain for each certificate found */
enumerator = create_cert_enumerator(this, CERT_ANY, type, id, FALSE);
while (enumerator->enumerate(enumerator, &current))
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);
if (!subject)
{
DBG1(DBG_CFG, "no trusted certificate found for '%D'", id);
}
return subject;
return FALSE;
}
/**
* Implementation of credential_manager_t.get_public.
* Implements trusted_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 trusted_destroy(trusted_enumerator_t *this)
{
public_key_t *public = NULL;
certificate_t *cert;
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);
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;
wrapper = auth_info_wrapper_create(auth);
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)
while (this->inner->enumerate(this->inner, &cert, auth))
{
public = cert->get_public_key(cert);
cert->destroy(cert);
DESTROY_IF(this->current);
this->current = cert->get_public_key(cert);
if (this->current)
{
*key = this->current;
return TRUE;
}
}
return FALSE;
}
/**
* Implements public_enumerator_t.destroy
*/
static void public_destroy(public_enumerator_t *this)
{
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);
this->sets->remove(this->sets, wrapper, NULL);
wrapper->destroy(wrapper);
this->mutex->unlock(this->mutex);
return public;
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);
if (auth)
{
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);
}
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;
+14 -10
View File
@@ -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.
@@ -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, &current_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;
}