diff options
author | Clavister OpenSource <opensource@clavister.com> | 2011-12-05 14:11:48 +0100 |
---|---|---|
committer | Clavister OpenSource <opensource@clavister.com> | 2012-03-20 17:31:11 +0100 |
commit | 7d9269bfce9ab02e614b41c12178174aad2d42de (patch) | |
tree | 798592c3ab89525e8ecdaa25c6cc7f1881b64cd0 | |
parent | a846be311627f23e202bee65dae71d5731e53967 (diff) | |
download | strongswan-7d9269bfce9ab02e614b41c12178174aad2d42de.tar.bz2 strongswan-7d9269bfce9ab02e614b41c12178174aad2d42de.tar.xz |
certificate handling for XAuth responder.
-rwxr-xr-x[-rw-r--r--] | src/libcharon/encoding/message.c | 4 | ||||
-rwxr-xr-x[-rw-r--r--] | src/libcharon/encoding/payloads/certreq_payload.c | 46 | ||||
-rwxr-xr-x[-rw-r--r--] | src/libcharon/encoding/payloads/certreq_payload.h | 23 | ||||
-rwxr-xr-x[-rw-r--r--] | src/libcharon/encoding/payloads/payload.c | 4 | ||||
-rwxr-xr-x[-rw-r--r--] | src/libcharon/sa/tasks/ike_cert_post.c | 172 | ||||
-rwxr-xr-x[-rw-r--r--] | src/libcharon/sa/tasks/ike_cert_pre.c | 377 |
6 files changed, 572 insertions, 54 deletions
diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 0a808ac02..5b79ac733 100644..100755 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -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}, }; diff --git a/src/libcharon/encoding/payloads/certreq_payload.c b/src/libcharon/encoding/payloads/certreq_payload.c index 69e80ad7e..dea1f40bd 100644..100755 --- a/src/libcharon/encoding/payloads/certreq_payload.c +++ b/src/libcharon/encoding/payloads/certreq_payload.c @@ -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) { diff --git a/src/libcharon/encoding/payloads/certreq_payload.h b/src/libcharon/encoding/payloads/certreq_payload.h index 421ad6d58..d426da711 100644..100755 --- a/src/libcharon/encoding/payloads/certreq_payload.h +++ b/src/libcharon/encoding/payloads/certreq_payload.h @@ -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_ @}*/ diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c index baa838715..257d53858 100644..100755 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -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: diff --git a/src/libcharon/sa/tasks/ike_cert_post.c b/src/libcharon/sa/tasks/ike_cert_post.c index ba5d76baa..358a067c9 100644..100755 --- a/src/libcharon/sa/tasks/ike_cert_post.c +++ b/src/libcharon/sa/tasks/ike_cert_post.c @@ -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; } diff --git a/src/libcharon/sa/tasks/ike_cert_pre.c b/src/libcharon/sa/tasks/ike_cert_pre.c index 0de2efd38..0bdbea5e1 100644..100755 --- a/src/libcharon/sa/tasks/ike_cert_pre.c +++ b/src/libcharon/sa/tasks/ike_cert_pre.c @@ -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; |