From a702b731cb68fad39a49484f7ed902f4fbf0b89e Mon Sep 17 00:00:00 2001 From: Andreas Steffen Date: Sat, 28 Oct 2006 20:02:26 +0000 Subject: [PATCH] support of certreq payload in IKE_AUTH messages --- src/charon/config/credentials/credential_store.h | 9 +++ .../config/credentials/local_credential_store.c | 30 ++++++++++ src/charon/encoding/payloads/certreq_payload.c | 54 +++++++++++++++++- src/charon/encoding/payloads/certreq_payload.h | 15 ++++- src/charon/sa/transactions/ike_auth.c | 65 ++++++++++++++++++---- 5 files changed, 155 insertions(+), 18 deletions(-) diff --git a/src/charon/config/credentials/credential_store.h b/src/charon/config/credentials/credential_store.h index f9c9cd4..2394a0f 100755 --- a/src/charon/config/credentials/credential_store.h +++ b/src/charon/config/credentials/credential_store.h @@ -116,6 +116,15 @@ struct credential_store_t { x509_t* (*get_ca_certificate) (credential_store_t *this, identification_t *id); /** + * @brief Returns the ca certificate of a specific keyID. + * + * @param this calling object + * @param keyid identification_t object identifiying the cacert. + * @return certificate, or NULL if not found + */ + x509_t* (*get_ca_certificate_by_keyid) (credential_store_t *this, chunk_t keyid); + + /** * @brief Returns the ca certificate of a specific subject distinguished name. * * @param this calling object diff --git a/src/charon/config/credentials/local_credential_store.c b/src/charon/config/credentials/local_credential_store.c index 63a7194..f984082 100644 --- a/src/charon/config/credentials/local_credential_store.c +++ b/src/charon/config/credentials/local_credential_store.c @@ -330,6 +330,7 @@ static x509_t* get_ca_certificate(private_local_credential_store_t *this, x509_t *current_cert; iterator_t *iterator = this->ca_certs->create_iterator(this->ca_certs, TRUE); + while (iterator->iterate(iterator, (void**)¤t_cert)) { if (id->equals(id, current_cert->get_subject(current_cert))) @@ -342,6 +343,33 @@ static x509_t* get_ca_certificate(private_local_credential_store_t *this, return found; } + +/** + * Implementation of credential_store_t.get_ca_certificate_by_keyid. + */ +static x509_t* get_ca_certificate_by_keyid(private_local_credential_store_t *this, + chunk_t keyid) +{ + x509_t *found = NULL; + x509_t *current_cert; + + iterator_t *iterator = this->ca_certs->create_iterator(this->ca_certs, TRUE); + + while (iterator->iterate(iterator, (void**)¤t_cert)) + { + rsa_public_key_t *pubkey = current_cert->get_public_key(current_cert); + + if (chunk_equals(keyid, pubkey->get_keyid(pubkey))) + { + found = current_cert; + break; + } + } + iterator->destroy(iterator); + + return found; +} + /** * Implementation of credential_store_t.get_issuer_certificate. */ @@ -352,6 +380,7 @@ static x509_t* get_issuer_certificate(private_local_credential_store_t *this, x509_t *current_cert; iterator_t *iterator = this->ca_certs->create_iterator(this->ca_certs, TRUE); + while (iterator->iterate(iterator, (void**)¤t_cert)) { if (cert->is_issuer(cert, current_cert)) @@ -1096,6 +1125,7 @@ local_credential_store_t * local_credential_store_create(bool strict) this->public.credential_store.get_trusted_public_key = (rsa_public_key_t*(*)(credential_store_t*,identification_t*))get_trusted_public_key; this->public.credential_store.get_certificate = (x509_t* (*) (credential_store_t*,identification_t*))get_certificate; this->public.credential_store.get_ca_certificate = (x509_t* (*) (credential_store_t*,identification_t*))get_ca_certificate; + this->public.credential_store.get_ca_certificate_by_keyid = (x509_t* (*) (credential_store_t*,identification_t*))get_ca_certificate_by_keyid; this->public.credential_store.get_issuer_certificate = (x509_t* (*) (credential_store_t*,const x509_t*))get_issuer_certificate; this->public.credential_store.verify = (bool (*) (credential_store_t*,x509_t*,bool*))verify; this->public.credential_store.add_end_certificate = (x509_t* (*) (credential_store_t*,x509_t*))add_end_certificate; diff --git a/src/charon/encoding/payloads/certreq_payload.c b/src/charon/encoding/payloads/certreq_payload.c index 2fce259..9108a35 100644 --- a/src/charon/encoding/payloads/certreq_payload.c +++ b/src/charon/encoding/payloads/certreq_payload.c @@ -22,6 +22,10 @@ */ #include +#include + +#include +#include #include "certreq_payload.h" @@ -262,12 +266,56 @@ certreq_payload_t *certreq_payload_create() /* * Described in header */ -certreq_payload_t *certreq_payload_create_from_x509(x509_t *cert) +certreq_payload_t *certreq_payload_create_from_cacert(identification_t *id) { + x509_t *cacert = charon->credentials->get_ca_certificate(charon->credentials, id); + rsa_public_key_t *pubkey = cacert->get_public_key(cacert); + chunk_t keyid = pubkey->get_keyid(pubkey); + certreq_payload_t *this = certreq_payload_create(); - rsa_public_key_t *pubkey = cert->get_public_key(cert); + + DBG1(DBG_IKE, "request certificate issued by '%D'", id); + DBG2(DBG_IKE, " with keyid %#B", &keyid); + + this->set_cert_encoding(this, CERT_X509_SIGNATURE); + this->set_data(this, keyid); + return this; +} + +/* + * Described in header + */ +certreq_payload_t *certreq_payload_create_from_cacerts(void) +{ + certreq_payload_t *this; + chunk_t keyids; + u_char *pos; + x509_t *cacert; + + iterator_t *iterator = charon->credentials->create_cacert_iterator(charon->credentials); + int count = iterator->get_count(iterator); + + if (count == 0) + return NULL; + + this = certreq_payload_create(); + keyids = chunk_alloc(count * HASH_SIZE_SHA1); + pos = keyids.ptr; + + while (iterator->iterate(iterator, (void**)&cacert)) + { + rsa_public_key_t *pubkey = cacert->get_public_key(cacert); + chunk_t keyid = pubkey->get_keyid(pubkey); + + DBG1(DBG_IKE, "request certificate issued by '%D'", cacert->get_subject(cacert)); + DBG2(DBG_IKE, " with keyid %#B", &keyid); + memcpy(pos, keyid.ptr, keyid.len); + pos += HASH_SIZE_SHA1; + } + iterator->destroy(iterator); this->set_cert_encoding(this, CERT_X509_SIGNATURE); - this->set_data(this, pubkey->get_keyid(pubkey)); + this->set_data(this, keyids); + free(keyids.ptr); return this; } diff --git a/src/charon/encoding/payloads/certreq_payload.h b/src/charon/encoding/payloads/certreq_payload.h index 11c7f85..db3976a 100644 --- a/src/charon/encoding/payloads/certreq_payload.h +++ b/src/charon/encoding/payloads/certreq_payload.h @@ -123,13 +123,22 @@ struct certreq_payload_t { certreq_payload_t *certreq_payload_create(void); /** - * @brief Creates a certreq_payload_t object from a X.509 CA certificate. + * @brief Creates a certreq_payload_t object from a ca certificate * - * @param cert X.509 CA certificate + * @param id subject distinguished name of CA certificate * @return certreq_payload_t object * * @ingroup payloads */ -certreq_payload_t *certreq_payload_create_from_x509(x509_t *cert); +certreq_payload_t *certreq_payload_create_from_cacert(identification_t *id); + +/** + * @brief Creates a certreq_payload_t object from all ca certificates + * + * @return certreq_payload_t object + * + * @ingroup payloads + */ +certreq_payload_t *certreq_payload_create_from_cacerts(void); #endif /* CERTREQ_PAYLOAD_H_ */ diff --git a/src/charon/sa/transactions/ike_auth.c b/src/charon/sa/transactions/ike_auth.c index 82e75fa..ca46be0 100644 --- a/src/charon/sa/transactions/ike_auth.c +++ b/src/charon/sa/transactions/ike_auth.c @@ -225,19 +225,14 @@ static status_t get_request(private_ike_auth_t *this, message_t **result) if (this->connection->get_certreq_policy(this->connection) != CERT_NEVER_SEND) { certreq_payload_t *certreq_payload; - identification_t *other_ca = this->policy->get_other_ca(this->policy); - if (other_ca->get_type(other_ca) == ID_ANY) - { + certreq_payload = (other_ca->get_type(other_ca) == ID_ANY) + ? certreq_payload_create_from_cacerts() + : certreq_payload_create_from_cacert(other_ca); - } - else + if (certreq_payload != NULL) { - x509_t *cacert = charon->credentials->get_ca_certificate(charon->credentials, other_ca); - - DBG2(DBG_IKE, "certreq with ca: '%D'", other_ca); - certreq_payload = certreq_payload_create_from_x509(cacert); request->add_payload(request, (payload_t*)certreq_payload); } } @@ -422,9 +417,46 @@ static void build_notify(notify_type_t type, message_t *message, bool flush_mess } /** + * Import certificate requests from a certreq payload + */ +static void import_certificate_request(certreq_payload_t *certreq_payload) +{ + chunk_t keyids; + cert_encoding_t encoding = certreq_payload->get_cert_encoding(certreq_payload); + + if (encoding != CERT_X509_SIGNATURE) + { + DBG1(DBG_IKE, "certreq payload %N not supported, ignored", + cert_encoding_names, encoding); + return; + } + + keyids = certreq_payload->get_data(certreq_payload); + + while (keyids.len >= HASH_SIZE_SHA1) + { + chunk_t keyid = { keyids.ptr, HASH_SIZE_SHA1}; + x509_t *cacert = charon->credentials->get_ca_certificate_by_keyid(charon->credentials, keyid); + + if (cacert) + { + DBG1(DBG_IKE, "request for certificate issued by ca '%D'", cacert->get_subject(cacert)); + DBG2(DBG_IKE, " with keyid %#B", &keyid); + } + else + { + DBG1(DBG_IKE, "request for certificate issued by unknown ca"); + DBG1(DBG_IKE, " with keyid %#B", &keyid); + } + keyids.ptr += HASH_SIZE_SHA1; + keyids.len -= HASH_SIZE_SHA1; + } +} + +/** * Import a certificate from a cert payload */ -static void import_certificate(private_ike_auth_t *this, cert_payload_t *cert_payload) +static void import_certificate(cert_payload_t *cert_payload) { bool found; x509_t *cert; @@ -527,6 +559,7 @@ static status_t get_response(private_ike_auth_t *this, message_t *request, id_payload_t *idi_request = NULL; id_payload_t *idr_request = NULL; auth_payload_t *auth_request = NULL; + certreq_payload_t *certreq_request = NULL; cert_payload_t *cert_request = NULL; sa_payload_t *sa_request = NULL; ts_payload_t *tsi_request = NULL; @@ -580,6 +613,9 @@ static status_t get_response(private_ike_auth_t *this, message_t *request, case AUTHENTICATION: auth_request = (auth_payload_t*)payload; break; + case CERTIFICATE_REQUEST: + certreq_request = (certreq_payload_t*)payload; + break; case CERTIFICATE: cert_request = (cert_payload_t*)payload; break; @@ -699,9 +735,14 @@ static status_t get_response(private_ike_auth_t *this, message_t *request, } } + if (certreq_request) + { /* process certificate request payload */ + import_certificate_request(certreq_request); + } + if (cert_request) { /* process certificate payload */ - import_certificate(this, cert_request); + import_certificate(cert_request); } { /* process auth payload */ @@ -923,7 +964,7 @@ static status_t conclude(private_ike_auth_t *this, message_t *response, if (cert_payload) { /* process cert payload */ - import_certificate(this, cert_payload); + import_certificate(cert_payload); } { /* authenticate peer */ -- 2.7.4