support of certreq payload in IKE_AUTH messages
authorAndreas Steffen <andreas.steffen@strongswan.org>
Sat, 28 Oct 2006 20:02:26 +0000 (20:02 -0000)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Sat, 28 Oct 2006 20:02:26 +0000 (20:02 -0000)
src/charon/config/credentials/credential_store.h
src/charon/config/credentials/local_credential_store.c
src/charon/encoding/payloads/certreq_payload.c
src/charon/encoding/payloads/certreq_payload.h
src/charon/sa/transactions/ike_auth.c

index f9c9cd4..2394a0f 100755 (executable)
@@ -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
index 63a7194..f984082 100644 (file)
@@ -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**)&current_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**)&current_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**)&current_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;
index 2fce259..9108a35 100644 (file)
  */
 
 #include <stddef.h>
+#include <string.h>
+
+#include <daemon.h>
+#include <crypto/hashers/hasher.h>
 
 #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;
 }
index 11c7f85..db3976a 100644 (file)
@@ -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_ */
index 82e75fa..ca46be0 100644 (file)
@@ -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 */