certificate handling for XAuth responder.
authorClavister OpenSource <opensource@clavister.com>
Mon, 5 Dec 2011 13:11:48 +0000 (14:11 +0100)
committerClavister OpenSource <opensource@clavister.com>
Tue, 20 Mar 2012 16:31:11 +0000 (17:31 +0100)
src/libcharon/encoding/message.c [changed mode: 0644->0755]
src/libcharon/encoding/payloads/certreq_payload.c [changed mode: 0644->0755]
src/libcharon/encoding/payloads/certreq_payload.h [changed mode: 0644->0755]
src/libcharon/encoding/payloads/payload.c [changed mode: 0644->0755]
src/libcharon/sa/tasks/ike_cert_post.c [changed mode: 0644->0755]
src/libcharon/sa/tasks/ike_cert_pre.c [changed mode: 0644->0755]

old mode 100644 (file)
new mode 100755 (executable)
index 0a808ac..5b79ac7
@@ -438,7 +438,7 @@ static payload_rule_t id_prot_i_rules[] = {
        {CERTIFICATE_REQUEST_V1,        0,      MAX_CERTREQ_PAYLOADS,   FALSE,  FALSE},
        {NAT_D_V1,                                      0,      MAX_NAT_D_PAYLOADS,             FALSE,  FALSE},
        {ID_V1,                                         0,      1,                                              TRUE,   FALSE},
-       {CERTIFICATE_V1,                        0,      1,                                              TRUE,   FALSE},
+       {CERTIFICATE_V1,                        0,      2,                                              TRUE,   FALSE},
        {SIGNATURE_V1,                          0,      1,                                              TRUE,   FALSE},
        {HASH_V1,                                       0,      1,                                              TRUE,   FALSE},
 };
@@ -474,7 +474,7 @@ static payload_rule_t id_prot_r_rules[] = {
        {CERTIFICATE_REQUEST_V1,        0,      MAX_CERTREQ_PAYLOADS,   FALSE,  FALSE},
        {NAT_D_V1,                                      0,      MAX_NAT_D_PAYLOADS,             FALSE,  FALSE},
        {ID_V1,                                         0,      1,                                              TRUE,   FALSE},
-       {CERTIFICATE_V1,                        0,      1,                                              TRUE,   FALSE},
+       {CERTIFICATE_V1,                        0,      2,                                              TRUE,   FALSE},
        {SIGNATURE_V1,                          0,      1,                                              TRUE,   FALSE},
        {HASH_V1,                                       0,      1,                                              TRUE,   FALSE},
 };
old mode 100644 (file)
new mode 100755 (executable)
index 69e80ad..dea1f40
@@ -64,6 +64,11 @@ struct private_certreq_payload_t {
         * The contained certreq data value.
         */
        chunk_t data;
+
+       /**
+        * Payload type for certificate request.
+        */
+       payload_type_t payload_type;
 };
 
 /**
@@ -122,6 +127,13 @@ METHOD(payload_t, verify, status_t,
        return SUCCESS;
 }
 
+METHOD(payload_t, verify_v1, status_t,
+                        private_certreq_payload_t *this)
+{
+       /*TODO: */
+       return SUCCESS;
+}
+
 METHOD(payload_t, get_encoding_rules, int,
        private_certreq_payload_t *this, encoding_rule_t **rules)
 {
@@ -138,7 +150,7 @@ METHOD(payload_t, get_header_length, int,
 METHOD(payload_t, get_type, payload_type_t,
        private_certreq_payload_t *this)
 {
-       return CERTIFICATE_REQUEST;
+       return this->payload_type;
 }
 
 METHOD(payload_t, get_next_type, payload_type_t,
@@ -159,6 +171,23 @@ METHOD(payload_t, get_length, size_t,
        return this->payload_length;
 }
 
+METHOD(certreq_payload_t, get_dn, chunk_t,
+       private_certreq_payload_t *this)
+{
+       return this->data;
+}
+
+METHOD(certreq_payload_t, set_dn, void,
+       private_certreq_payload_t *this, chunk_t dn)
+{
+       if (this->data.ptr)
+       {
+               free(this->data.ptr);
+       }
+       this->data = chunk_clone(dn);
+       this->payload_length = get_header_length(this) + this->data.len;
+}
+
 METHOD(certreq_payload_t, add_keyid, void,
        private_certreq_payload_t *this, chunk_t keyid)
 {
@@ -238,7 +267,7 @@ METHOD2(payload_t, certreq_payload_t, destroy, void,
 /*
  * Described in header
  */
-certreq_payload_t *certreq_payload_create()
+certreq_payload_t *certreq_payload_create(payload_type_t payload_type)
 {
        private_certreq_payload_t *this;
 
@@ -258,19 +287,28 @@ certreq_payload_t *certreq_payload_create()
                        .get_cert_type = _get_cert_type,
                        .add_keyid = _add_keyid,
                        .destroy = _destroy,
+                       .get_dn = _get_dn,
+                       .set_dn = _set_dn,
                },
                .next_payload = NO_PAYLOAD,
                .payload_length = get_header_length(this),
+               .payload_type = payload_type,
        );
+
+       if (payload_type == CERTIFICATE_REQUEST_V1)
+       {
+               this->public.payload_interface.verify = _verify_v1;
+       }
+
        return &this->public;
 }
 
 /*
  * Described in header
  */
-certreq_payload_t *certreq_payload_create_type(certificate_type_t type)
+certreq_payload_t *certreq_payload_create_type(payload_type_t payload_type, certificate_type_t type)
 {
-       private_certreq_payload_t *this = (private_certreq_payload_t*)certreq_payload_create();
+       private_certreq_payload_t *this = (private_certreq_payload_t*)certreq_payload_create(payload_type);
 
        switch (type)
        {
old mode 100644 (file)
new mode 100755 (executable)
index 421ad6d..d426da7
@@ -40,7 +40,7 @@ struct certreq_payload_t {
        payload_t payload_interface;
 
        /**
-        * Create an enumerator over contained keyids.
+        * Create an enumerator over contained keyids (IKEv2 only).
         *
         * @return                      enumerator over chunk_t's.
         */
@@ -54,7 +54,7 @@ struct certreq_payload_t {
        certificate_type_t (*get_cert_type)(certreq_payload_t *this);
 
        /**
-        * Add a certificates keyid to the payload.
+        * Add a certificates keyid to the payload (IKEv2 only).
         *
         * @param keyid         keyid of the trusted certifcate
         * @return
@@ -62,6 +62,21 @@ struct certreq_payload_t {
        void (*add_keyid)(certreq_payload_t *this, chunk_t keyid);
 
        /**
+        * Get certificate request data (IKEv1 only).
+        *
+         * @return certifcate request data
+        */
+       chunk_t (*get_dn)(certreq_payload_t *this);
+
+       /**
+        * Set certificate request data (IKEv1 only).
+        *
+        * @param dn            certifcate request data to set
+        * @return
+        */
+       void (*set_dn)(certreq_payload_t *this, chunk_t dn);
+
+       /**
         * Destroys an certreq_payload_t object.
         */
        void (*destroy) (certreq_payload_t *this);
@@ -72,7 +87,7 @@ struct certreq_payload_t {
  *
  * @return                             certreq payload
  */
-certreq_payload_t *certreq_payload_create(void);
+certreq_payload_t *certreq_payload_create(payload_type_t payload_type);
 
 /**
  * Creates an empty certreq_payload_t for a kind of certificates.
@@ -80,6 +95,6 @@ certreq_payload_t *certreq_payload_create(void);
  * @param type                 type of the added keyids
  * @return                             certreq payload
  */
-certreq_payload_t *certreq_payload_create_type(certificate_type_t type);
+certreq_payload_t *certreq_payload_create_type(payload_type_t payload_type, certificate_type_t type);
 
 #endif /** CERTREQ_PAYLOAD_H_ @}*/
old mode 100644 (file)
new mode 100755 (executable)
index baa8387..257d538
@@ -213,7 +213,8 @@ payload_t *payload_create(payload_type_t type)
                case CERTIFICATE_V1:
                        return (payload_t*)cert_payload_create(type);
                case CERTIFICATE_REQUEST:
-                       return (payload_t*)certreq_payload_create();
+               case CERTIFICATE_REQUEST_V1:
+                       return (payload_t*)certreq_payload_create(type);
                case TRAFFIC_SELECTOR_SUBSTRUCTURE:
                        return (payload_t*)traffic_selector_substructure_create();
                case TRAFFIC_SELECTOR_INITIATOR:
@@ -233,6 +234,7 @@ payload_t *payload_create(payload_type_t type)
                case VENDOR_ID_V1:
                        return (payload_t*)vendor_id_payload_create(type);
                case HASH_V1:
+               case SIGNATURE_V1:
                case NAT_D_V1:
                        return (payload_t*)hash_payload_create(type);
                case CONFIGURATION:
old mode 100644 (file)
new mode 100755 (executable)
index ba5d76b..358a067
@@ -21,6 +21,7 @@
 #include <encoding/payloads/cert_payload.h>
 #include <encoding/payloads/certreq_payload.h>
 #include <encoding/payloads/auth_payload.h>
+#include <encoding/payloads/sa_payload.h>
 #include <credentials/certificates/x509.h>
 
 
@@ -45,6 +46,20 @@ struct private_ike_cert_post_t {
         * Are we the initiator?
         */
        bool initiator;
+
+       /**
+        * Certificate payload type that we are handling
+        */
+       payload_type_t payload_type;
+
+       /**
+        * States of ike cert pre
+        */
+       enum {
+               CP_INIT,
+               CP_SA,
+               CP_SA_POST,
+       } state;
 };
 
 /**
@@ -62,14 +77,14 @@ static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this,
 
        if (!this->ike_sa->supports_extension(this->ike_sa, EXT_HASH_AND_URL))
        {
-               return cert_payload_create_from_cert(cert, CERTIFICATE);
+               return cert_payload_create_from_cert(cert, this->payload_type);
        }
 
        hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
        if (!hasher)
        {
                DBG1(DBG_IKE, "unable to use hash-and-url: sha1 not supported");
-               return cert_payload_create_from_cert(cert, CERTIFICATE);
+               return cert_payload_create_from_cert(cert, this->payload_type);
        }
 
        if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoded))
@@ -86,12 +101,12 @@ static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this,
        enumerator = lib->credmgr->create_cdp_enumerator(lib->credmgr, CERT_X509, id);
        if (enumerator->enumerate(enumerator, &url))
        {
-               payload = cert_payload_create_from_hash_and_url(hash, url, CERTIFICATE);
+               payload = cert_payload_create_from_hash_and_url(hash, url, this->payload_type);
                DBG1(DBG_IKE, "sending hash-and-url \"%s\"", url);
        }
        else
        {
-               payload = cert_payload_create_from_cert(cert, CERTIFICATE);
+               payload = cert_payload_create_from_cert(cert, this->payload_type);
        }
        enumerator->destroy(enumerator);
        chunk_free(&hash);
@@ -100,20 +115,73 @@ static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this,
 }
 
 /**
+ * Checks for the auth_method to see if this task should handle certificates.
+ * (IKEv1 only)
+ */
+static status_t check_auth_method(private_ike_cert_post_t *this,
+                                                                                                                                       message_t *message)
+{
+       enumerator_t *enumerator;
+       payload_t *payload;
+       status_t status = SUCCESS;
+
+       enumerator = message->create_payload_enumerator(message);
+       while (enumerator->enumerate(enumerator, &payload))
+       {
+               if (payload->get_type(payload) == SECURITY_ASSOCIATION_V1)
+               {
+                       sa_payload_t *sa_payload = (sa_payload_t*)payload;
+
+                       switch (sa_payload->get_auth_method(sa_payload))
+                       {
+                               case    AUTH_RSA:
+                               case    AUTH_XAUTH_INIT_RSA:
+                               case  AUTH_XAUTH_RESP_RSA:
+                                       DBG3(DBG_IKE, "handling certs method (%d)",
+                                                               sa_payload->get_auth_method(sa_payload));
+                                       status = NEED_MORE;
+                                       break;
+                               default:
+                                       DBG3(DBG_IKE, "not handling certs method (%d)",
+                                                               sa_payload->get_auth_method(sa_payload));
+                                       status = SUCCESS;
+                                       break;
+                       }
+
+                       this->state = CP_SA;
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       return status;
+}
+
+/**
  * add certificates to message
  */
 static void build_certs(private_ike_cert_post_t *this, message_t *message)
 {
        peer_cfg_t *peer_cfg;
-       auth_payload_t *payload;
 
-       payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION);
        peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
-       if (!peer_cfg || !payload || payload->get_auth_method(payload) == AUTH_PSK)
-       {       /* no CERT payload for EAP/PSK */
+
+       if (!peer_cfg)
+       {
                return;
        }
 
+       if (this->payload_type == CERTIFICATE)
+       {
+               auth_payload_t *payload;
+               payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION);
+
+               if (!payload || payload->get_auth_method(payload) == AUTH_PSK)
+               {       /* no CERT payload for EAP/PSK */
+                       return;
+               }
+       }
+
        switch (peer_cfg->get_cert_policy(peer_cfg))
        {
                case CERT_NEVER_SEND:
@@ -154,7 +222,7 @@ static void build_certs(private_ike_cert_post_t *this, message_t *message)
                        {
                                if (type == AUTH_RULE_IM_CERT)
                                {
-                                       payload = cert_payload_create_from_cert(cert, CERTIFICATE);
+                                       payload = cert_payload_create_from_cert(cert, this->payload_type);
                                        if (payload)
                                        {
                                                DBG1(DBG_IKE, "sending issuer cert \"%Y\"",
@@ -166,6 +234,8 @@ static void build_certs(private_ike_cert_post_t *this, message_t *message)
                        enumerator->destroy(enumerator);
                }
        }
+
+       return;
 }
 
 METHOD(task_t, build_i, status_t,
@@ -176,6 +246,14 @@ METHOD(task_t, build_i, status_t,
        return NEED_MORE;
 }
 
+METHOD(task_t, build_i_v1, status_t,
+       private_ike_cert_post_t *this, message_t *message)
+{
+       /* TODO:*/
+
+       return FAILED;
+}
+
 METHOD(task_t, process_r, status_t,
        private_ike_cert_post_t *this, message_t *message)
 {
@@ -194,6 +272,52 @@ METHOD(task_t, build_r, status_t,
        return SUCCESS;
 }
 
+METHOD(task_t, build_r_v1, status_t,
+       private_ike_cert_post_t *this, message_t *message)
+{
+       switch (message->get_exchange_type(message))
+       {
+               case ID_PROT:
+               {
+                       switch (this->state)
+                       {
+                               case CP_INIT:
+                                       this->state = CP_SA;
+                                       return check_auth_method(this, message);
+                                       break;
+
+                               case CP_SA:
+                                       this->state = CP_SA_POST;
+                                       build_certs(this, message);
+                                       break;
+
+                               case CP_SA_POST:
+                                       build_certs(this, message);
+                                       return SUCCESS;
+                       }
+                       break;
+               }
+               case AGGRESSIVE:
+               {
+                       if (check_auth_method(this, message) == NEED_MORE)
+                       {
+                               build_certs(this, message);
+                       }
+                       return SUCCESS;
+                       break;
+               }
+               default:
+                       break;
+       }
+
+       if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED)
+       {
+               return NEED_MORE;
+       }
+
+       return SUCCESS;
+}
+
 METHOD(task_t, process_i, status_t,
        private_ike_cert_post_t *this, message_t *message)
 {
@@ -241,17 +365,43 @@ ike_cert_post_t *ike_cert_post_create(ike_sa_t *ike_sa, bool initiator)
                .initiator = initiator,
        );
 
+
        if (initiator)
        {
-               this->public.task.build = _build_i;
                this->public.task.process = _process_i;
        }
        else
        {
-               this->public.task.build = _build_r;
                this->public.task.process = _process_r;
        }
 
+       if (ike_sa->get_version(ike_sa) == IKEV2)
+       {
+               this->payload_type = CERTIFICATE;
+
+               if (initiator)
+               {
+                       this->public.task.build = _build_i;
+               }
+               else
+               {
+                       this->public.task.build = _build_r;
+               }
+       }
+       else
+       {
+               this->payload_type = CERTIFICATE_V1;
+
+               if (initiator)
+               {
+                       this->public.task.build = _build_i_v1;
+               }
+               else
+               {
+                       this->public.task.build = _build_r_v1;
+               }
+       }
+
        return &this->public;
 }
 
old mode 100644 (file)
new mode 100755 (executable)
index 0de2efd..0bdbea5
@@ -19,6 +19,7 @@
 #include <daemon.h>
 #include <sa/ike_sa.h>
 #include <encoding/payloads/cert_payload.h>
+#include <encoding/payloads/sa_payload.h>
 #include <encoding/payloads/certreq_payload.h>
 #include <credentials/certificates/x509.h>
 
@@ -54,9 +55,59 @@ struct private_ike_cert_pre_t {
         * wheter this is the final authentication round
         */
        bool final;
+
+       /** states of ike cert pre */
+       enum {
+               CP_INIT,
+               CP_SA,
+               CP_SA_POST,
+               CP_REQ_SENT,
+               CP_NO_CERT,
+       } state;
+
+       /**
+        * type of certicate request to send
+        */
+       payload_type_t cert_req_payload_type;
 };
 
 /**
+ * add certificate to auth
+ */
+static bool add_certificate(auth_cfg_t *auth, chunk_t keyid, id_type_t id_type )
+{
+       identification_t *id = NULL;
+       certificate_t *cert;
+       bool status = TRUE;
+
+       id = identification_create_from_encoding(id_type, keyid);
+
+       if (!id)
+       {
+               return FALSE;
+       }
+
+       cert = lib->credmgr->get_cert(lib->credmgr,
+                                                                       CERT_X509, KEY_ANY, id, TRUE);
+       if (cert)
+       {
+               DBG1(DBG_IKE, "received cert request for \"%Y\"",
+                        cert->get_subject(cert));
+               auth->add(auth, AUTH_RULE_CA_CERT, cert);
+       }
+       else
+       {
+               DBG2(DBG_IKE, "received cert request for unknown ca "
+                                               "with keyid %Y", id);
+               status = FALSE;
+       }
+
+       id->destroy(id);
+
+       return status;
+}
+
+/**
  * read certificate requests
  */
 static void process_certreqs(private_ike_cert_pre_t *this, message_t *message)
@@ -73,6 +124,7 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message)
                switch (payload->get_type(payload))
                {
                        case CERTIFICATE_REQUEST:
+                       case CERTIFICATE_REQUEST_V1:
                        {
                                certreq_payload_t *certreq = (certreq_payload_t*)payload;
                                enumerator_t *enumerator;
@@ -87,30 +139,31 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message)
                                                 certificate_type_names, certreq->get_cert_type(certreq));
                                        break;
                                }
-                               enumerator = certreq->create_keyid_enumerator(certreq);
-                               while (enumerator->enumerate(enumerator, &keyid))
-                               {
-                                       identification_t *id;
-                                       certificate_t *cert;
 
-                                       id = identification_create_from_encoding(ID_KEY_ID, keyid);
-                                       cert = lib->credmgr->get_cert(lib->credmgr,
-                                                                                                 CERT_X509, KEY_ANY, id, TRUE);
-                                       if (cert)
+                               if (payload->get_type(payload) == CERTIFICATE_REQUEST)
+                               {
+                                       enumerator = certreq->create_keyid_enumerator(certreq);
+                                       while (enumerator->enumerate(enumerator, &keyid))
                                        {
-                                               DBG1(DBG_IKE, "received cert request for \"%Y\"",
-                                                        cert->get_subject(cert));
-                                               auth->add(auth, AUTH_RULE_CA_CERT, cert);
+                                               if (!add_certificate(auth, keyid, ID_KEY_ID))
+                                               {
+                                                       unknown++;
+                                               }
                                        }
-                                       else
+                                       enumerator->destroy(enumerator);
+                               }
+                               else
+                               {
+                                       keyid = certreq->get_dn(certreq);
+
+                                       /* In case client (iPhone) is sending empty cert requests */
+                                       if (!keyid.ptr || !keyid.len ||
+                                               !add_certificate(auth, keyid, ID_DER_ASN1_DN))
                                        {
-                                               DBG2(DBG_IKE, "received cert request for unknown ca "
-                                                                         "with keyid %Y", id);
                                                unknown++;
                                        }
-                                       id->destroy(id);
                                }
-                               enumerator->destroy(enumerator);
+
                                if (unknown)
                                {
                                        DBG1(DBG_IKE, "received %u cert requests for an unknown ca",
@@ -191,7 +244,8 @@ static void process_certs(private_ike_cert_pre_t *this, message_t *message)
        enumerator = message->create_payload_enumerator(message);
        while (enumerator->enumerate(enumerator, &payload))
        {
-               if (payload->get_type(payload) == CERTIFICATE)
+               if (payload->get_type(payload) == CERTIFICATE ||
+                               payload->get_type(payload) == CERTIFICATE_V1)
                {
                        cert_payload_t *cert_payload;
                        cert_encoding_t encoding;
@@ -291,7 +345,8 @@ static void process_certs(private_ike_cert_pre_t *this, message_t *message)
 /**
  * add the keyid of a certificate to the certificate request payload
  */
-static void add_certreq(certreq_payload_t **req, certificate_t *cert)
+static void add_certreq(private_ike_cert_pre_t *this,
+                                                                                               certreq_payload_t **req, certificate_t *cert)
 {
        switch (cert->get_type(cert))
        {
@@ -310,15 +365,30 @@ static void add_certreq(certreq_payload_t **req, certificate_t *cert)
                        {
                                break;
                        }
+
                        if (*req == NULL)
                        {
-                               *req = certreq_payload_create_type(CERT_X509);
+                               *req = certreq_payload_create_type(this->cert_req_payload_type, CERT_X509);
+                       }
+
+                       if (this->cert_req_payload_type == CERTIFICATE_REQUEST)
+                       {
+                               if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid))
+                               {
+                                       (*req)->add_keyid(*req, keyid);
+                                       DBG1(DBG_IKE, "sending cert request for \"%Y\"",
+                                                cert->get_subject(cert));
+                               }
                        }
-                       if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid))
+                       else
                        {
-                               (*req)->add_keyid(*req, keyid);
+                               identification_t *id;
+                               id = cert->get_subject(cert);
+
+                               (*req)->set_dn(*req, id->get_encoding(id));
                                DBG1(DBG_IKE, "sending cert request for \"%Y\"",
-                                        cert->get_subject(cert));
+                                                cert->get_subject(cert));
+
                        }
                        public->destroy(public);
                        break;
@@ -331,7 +401,8 @@ static void add_certreq(certreq_payload_t **req, certificate_t *cert)
 /**
  * add a auth_cfg's CA certificates to the certificate request
  */
-static void add_certreqs(certreq_payload_t **req, auth_cfg_t *auth)
+static void add_certreqs(private_ike_cert_pre_t *this,
+                                                                                                certreq_payload_t **req, auth_cfg_t *auth)
 {
        enumerator_t *enumerator;
        auth_rule_t type;
@@ -343,7 +414,37 @@ static void add_certreqs(certreq_payload_t **req, auth_cfg_t *auth)
                switch (type)
                {
                        case AUTH_RULE_CA_CERT:
-                               add_certreq(req, (certificate_t*)value);
+                               add_certreq(this, req, (certificate_t*)value);
+                               break;
+                       default:
+                               break;
+               }
+       }
+       enumerator->destroy(enumerator);
+}
+
+/**
+ * add a auth_cfg's CA certificates to the certificate request
+ */
+static void add_certreqs_v1(private_ike_cert_pre_t *this,
+                                                                                                               certreq_payload_t **req,
+                                                                                                               auth_cfg_t *auth, message_t *message)
+{
+       enumerator_t *enumerator;
+       auth_rule_t type;
+       void *value;
+
+       enumerator = auth->create_enumerator(auth);
+       while (enumerator->enumerate(enumerator, &type, &value))
+       {
+               switch (type)
+               {
+                       case AUTH_RULE_CA_CERT:
+                               add_certreq(this, req, (certificate_t*)value);
+                               if (req)
+                               {
+                                       message->add_payload(message,(payload_t*)req);
+                               }
                                break;
                        default:
                                break;
@@ -377,7 +478,7 @@ static void build_certreqs(private_ike_cert_pre_t *this, message_t *message)
                enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE);
                while (enumerator->enumerate(enumerator, &auth))
                {
-                       add_certreqs(&req, auth);
+                       add_certreqs(this, &req, auth);
                }
                enumerator->destroy(enumerator);
        }
@@ -389,7 +490,7 @@ static void build_certreqs(private_ike_cert_pre_t *this, message_t *message)
                                                                                                CERT_ANY, KEY_ANY, NULL, TRUE);
                while (enumerator->enumerate(enumerator, &cert))
                {
-                       add_certreq(&req, cert);
+                       add_certreq(this, &req, cert);
                }
                enumerator->destroy(enumerator);
        }
@@ -408,6 +509,58 @@ static void build_certreqs(private_ike_cert_pre_t *this, message_t *message)
 }
 
 /**
+ * build certificate requests
+ */
+static void build_certreqs_v1(private_ike_cert_pre_t *this, message_t *message)
+{
+       enumerator_t *enumerator;
+       ike_cfg_t *ike_cfg;
+       peer_cfg_t *peer_cfg;
+       certificate_t *cert;
+       auth_cfg_t *auth;
+       certreq_payload_t *req = NULL;
+
+       ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
+       if (!ike_cfg->send_certreq(ike_cfg))
+       {
+               return;
+       }
+
+       /* check if we require a specific CA for that peer */
+       /* Get the first authentcation config from peer config */
+       peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
+       if (peer_cfg)
+       {
+               enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE);
+               if (enumerator->enumerate(enumerator, &auth))
+               {
+                       add_certreqs_v1(this, &req, auth, message);
+                       if (req)
+                       {
+                               message->add_payload(message, (payload_t*)req);
+                       }
+               }
+               enumerator->destroy(enumerator);
+       }
+
+       if (!req)
+       {
+               /* otherwise add all trusted CA certificates */
+               enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
+                                                                                               CERT_ANY, KEY_ANY, NULL, TRUE);
+               while (enumerator->enumerate(enumerator, &cert))
+               {
+                       add_certreq(this, &req, cert);
+                       if (req)
+                       {
+                               message->add_payload(message, (payload_t*)req);
+                       }
+               }
+               enumerator->destroy(enumerator);
+       }
+}
+
+/**
  * Check if this is the final authentication round
  */
 static bool final_auth(message_t *message)
@@ -424,6 +577,55 @@ static bool final_auth(message_t *message)
        return TRUE;
 }
 
+/**
+ * Checks for the auth_method to see if this task should handle certificates.
+ * (IKEv1 only)
+ */
+static status_t check_auth_method(private_ike_cert_pre_t *this,
+                                                                                                                                       message_t *message)
+{
+       enumerator_t *enumerator;
+       payload_t *payload;
+       status_t status = SUCCESS;
+
+       enumerator = message->create_payload_enumerator(message);
+       while (enumerator->enumerate(enumerator, &payload))
+       {
+               if (payload->get_type(payload) == SECURITY_ASSOCIATION_V1)
+               {
+                       sa_payload_t *sa_payload = (sa_payload_t*)payload;
+
+                       switch (sa_payload->get_auth_method(sa_payload))
+                       {
+                               case    AUTH_RSA:
+                               case    AUTH_XAUTH_INIT_RSA:
+                               case  AUTH_XAUTH_RESP_RSA:
+                                       DBG3(DBG_IKE, "handling certs method (%d)",
+                                                               sa_payload->get_auth_method(sa_payload));
+                                       status = NEED_MORE;
+                                       break;
+                               default:
+                                       DBG3(DBG_IKE, "not handling certs method (%d)",
+                                                               sa_payload->get_auth_method(sa_payload));
+                                       status = SUCCESS;
+                                       break;
+                       }
+
+                       this->state = CP_SA;
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       if (status != NEED_MORE)
+       {
+               this->state = CP_NO_CERT;
+               this->final = TRUE;
+       }
+
+       return status;
+}
+
 METHOD(task_t, build_i, status_t,
        private_ike_cert_pre_t *this, message_t *message)
 {
@@ -476,6 +678,97 @@ METHOD(task_t, process_i, status_t,
        return NEED_MORE;
 }
 
+METHOD(task_t, process_r_v1, status_t,
+       private_ike_cert_pre_t *this, message_t *message)
+{
+       switch (message->get_exchange_type(message))
+       {
+               case ID_PROT:
+               {
+                       switch (this->state)
+                       {
+                               case CP_INIT:
+                                       check_auth_method(this, message);
+                                       break;
+                               case CP_SA:
+                                       process_certreqs(this, message);
+                                       this->state = CP_SA_POST;
+                                       break;
+                               case CP_SA_POST:
+                                       process_certreqs(this, message);
+                                       process_certs(this, message);
+                                       this->state = CP_REQ_SENT;
+                                       this->final = TRUE;
+                                       break;
+                               default:
+                                       break;
+                       }
+                       break;
+               }
+               case AGGRESSIVE:
+               {
+                       if (check_auth_method(this, message) == NEED_MORE)
+                       {
+                               process_certreqs(this, message);
+                               process_certs(this, message);
+                       }
+                       this->final = TRUE;
+                       break;
+               }
+               default:
+                       break;
+       }
+
+       return NEED_MORE;
+}
+
+METHOD(task_t, process_i_v1, status_t,
+       private_ike_cert_pre_t *this, message_t *message)
+{
+       /* TODO: */
+       return FAILED;
+}
+
+METHOD(task_t, build_r_v1, status_t,
+       private_ike_cert_pre_t *this, message_t *message)
+{
+
+       switch (message->get_exchange_type(message))
+       {
+               case ID_PROT:
+               {
+                       if (this->state == CP_SA_POST)
+                       {
+                               build_certreqs_v1(this, message);
+                       }
+                       break;
+               }
+               case AGGRESSIVE:
+               {
+                       if (this->state != CP_NO_CERT)
+                       {
+                               build_certreqs_v1(this, message);
+                       }
+               }
+               default:
+                       break;
+
+       }
+
+       if (this->final)
+       {
+               return SUCCESS;
+       }
+       return NEED_MORE;
+}
+
+METHOD(task_t, build_i_v1, status_t,
+       private_ike_cert_pre_t *this, message_t *message)
+{
+       /* TODO: */
+       return FAILED;
+}
+
 METHOD(task_t, get_type, task_type_t,
        private_ike_cert_pre_t *this)
 {
@@ -513,15 +806,35 @@ ike_cert_pre_t *ike_cert_pre_create(ike_sa_t *ike_sa, bool initiator)
                .initiator = initiator,
        );
 
-       if (initiator)
+       if (ike_sa->get_version(ike_sa) == IKEV2)
        {
-               this->public.task.build = _build_i;
-               this->public.task.process = _process_i;
+               if (initiator)
+               {
+                       this->public.task.build = _build_i;
+                       this->public.task.process = _process_i;
+               }
+               else
+               {
+                       this->public.task.build = _build_r;
+                       this->public.task.process = _process_r;
+               }
+               this->cert_req_payload_type = CERTIFICATE_REQUEST;
        }
        else
        {
-               this->public.task.build = _build_r;
-               this->public.task.process = _process_r;
+               this->state = CP_INIT;
+               if (initiator)
+               {
+                       this->public.task.build = _build_i_v1;
+                       this->public.task.process = _process_i_v1;
+               }
+               else
+               {
+                       this->public.task.build = _build_r_v1;
+                       this->public.task.process = _process_r_v1;
+               }
+               this->cert_req_payload_type = CERTIFICATE_REQUEST_V1;
+
        }
 
        return &this->public;