diff options
author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2009-06-23 11:35:38 +0000 |
---|---|---|
committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2009-06-23 11:35:38 +0000 |
commit | 7c52c3f35cdbdff58443b994f2f33d13b4d81f57 (patch) | |
tree | e54a27979ea72ec41702bec2984c2eadac3b8862 /src/charon/sa/tasks/ike_cert_pre.c | |
parent | 4ef45ba0404dac3773e83af995a5ec584b23d633 (diff) | |
download | vyos-strongswan-7c52c3f35cdbdff58443b994f2f33d13b4d81f57.tar.gz vyos-strongswan-7c52c3f35cdbdff58443b994f2f33d13b4d81f57.zip |
Updated to new upstream version.
Diffstat (limited to 'src/charon/sa/tasks/ike_cert_pre.c')
-rw-r--r-- | src/charon/sa/tasks/ike_cert_pre.c | 302 |
1 files changed, 170 insertions, 132 deletions
diff --git a/src/charon/sa/tasks/ike_cert_pre.c b/src/charon/sa/tasks/ike_cert_pre.c index 353b76a22..1c72f289f 100644 --- a/src/charon/sa/tasks/ike_cert_pre.c +++ b/src/charon/sa/tasks/ike_cert_pre.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 Tobias Brunner - * Copyright (C) 2006-2007 Martin Willi + * Copyright (C) 2006-2009 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -12,8 +12,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. - * - * $Id: ike_cert_pre.c 4285 2008-08-26 05:15:34Z andreas $ */ #include "ike_cert_pre.h" @@ -48,9 +46,14 @@ struct private_ike_cert_pre_t { bool initiator; /** - * Did we send a HTTP_CERT_LOOKUP_SUPPORTED Notify? + * Do we accept HTTP certificate lookup requests + */ + bool do_http_lookup; + + /** + * wheter this is the final authentication round */ - bool http_cert_lookup_supported_sent; + bool final; }; /** @@ -58,23 +61,22 @@ struct private_ike_cert_pre_t { */ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; - auth_info_t *auth; - bool ca_found = FALSE; + auth_cfg_t *auth; - auth = this->ike_sa->get_my_auth(this->ike_sa); + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { switch(payload->get_type(payload)) { case CERTIFICATE_REQUEST: { certreq_payload_t *certreq = (certreq_payload_t*)payload; - chunk_t keyid; enumerator_t *enumerator; + chunk_t keyid; this->ike_sa->set_condition(this->ike_sa, COND_CERTREQ_SEEN, TRUE); @@ -96,17 +98,14 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) CERT_X509, KEY_ANY, id, TRUE); if (cert) { - DBG1(DBG_IKE, "received cert request for \"%D\"", + DBG1(DBG_IKE, "received cert request for \"%Y\"", cert->get_subject(cert)); - auth->add_item(auth, AUTHN_CA_CERT, cert); - cert->destroy(cert); - ca_found = TRUE; + auth->add(auth, AUTH_RULE_CA_CERT, cert); } else { DBG1(DBG_IKE, "received cert request for unknown ca " - "with keyid %D", id); - auth->add_item(auth, AUTHN_CA_CERT_KEYID, id); + "with keyid %Y", id); } id->destroy(id); } @@ -129,7 +128,7 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -140,6 +139,7 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) static certificate_t *try_get_cert(cert_payload_t *cert_payload) { certificate_t *cert = NULL; + switch (cert_payload->get_cert_encoding(cert_payload)) { case ENC_X509_SIGNATURE: @@ -158,7 +158,7 @@ static certificate_t *try_get_cert(cert_payload_t *cert_payload) } id = identification_create_from_encoding(ID_CERT_DER_SHA1, hash); cert = charon->credentials->get_cert(charon->credentials, - CERT_X509, KEY_ANY, id, FALSE); + CERT_X509, KEY_ANY, id, FALSE); id->destroy(id); break; } @@ -175,78 +175,81 @@ static certificate_t *try_get_cert(cert_payload_t *cert_payload) */ static void process_certs(private_ike_cert_pre_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; - auth_info_t *auth; + auth_cfg_t *auth; bool first = TRUE; - auth = this->ike_sa->get_other_auth(this->ike_sa); + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { if (payload->get_type(payload) == CERTIFICATE) { - cert_payload_t *cert_payload = (cert_payload_t*)payload; - cert_encoding_t type = cert_payload->get_cert_encoding(cert_payload); - switch (type) + cert_payload_t *cert_payload; + cert_encoding_t encoding; + certificate_t *cert; + char *url; + + cert_payload = (cert_payload_t*)payload; + encoding = cert_payload->get_cert_encoding(cert_payload); + + switch (encoding) { - case ENC_X509_SIGNATURE: case ENC_X509_HASH_AND_URL: { - if (type == ENC_X509_HASH_AND_URL && - !this->http_cert_lookup_supported_sent) + if (!this->do_http_lookup) { DBG1(DBG_IKE, "received hash-and-url encoded cert, but" " we don't accept them, ignore"); break; } - - certificate_t *cert = try_get_cert(cert_payload); - + /* FALL */ + } + case ENC_X509_SIGNATURE: + { + cert = try_get_cert(cert_payload); if (cert) { - /* we've got a certificate from the payload or the cache */ if (first) - { /* the first certificate MUST be an end entity one */ - DBG1(DBG_IKE, "received end entity cert \"%D\"", + { /* the first is an end entity certificate */ + DBG1(DBG_IKE, "received end entity cert \"%Y\"", cert->get_subject(cert)); - auth->add_item(auth, AUTHN_SUBJECT_CERT, cert); + auth->add(auth, AUTH_HELPER_SUBJECT_CERT, cert); first = FALSE; } else { - DBG1(DBG_IKE, "received issuer cert \"%D\"", + DBG1(DBG_IKE, "received issuer cert \"%Y\"", cert->get_subject(cert)); - auth->add_item(auth, AUTHN_IM_CERT, cert); + auth->add(auth, AUTH_HELPER_IM_CERT, cert); } - cert->destroy(cert); } - else if (type == ENC_X509_HASH_AND_URL) + else if (encoding == ENC_X509_HASH_AND_URL) { - /* we received a "Hash and URL" encoded certificate that - * we haven't fetched yet, we store the URL and fetch - * it later */ - char *url = cert_payload->get_url(cert_payload); + /* we fetch the certificate not yet, but only if + * it is really needed during authentication */ + url = cert_payload->get_url(cert_payload); if (!url) { - DBG1(DBG_IKE, "received invalid hash-and-url encoded" - " cert, ignore"); + DBG1(DBG_IKE, "received invalid hash-and-url " + "encoded cert, ignore"); break; } - + url = strdup(url); if (first) - { /* the first certificate MUST be an end entity one */ + { /* first URL is for an end entity certificate */ DBG1(DBG_IKE, "received hash-and-url for end" - " entity cert \"%s\"", url); - auth->add_item(auth, AUTHN_SUBJECT_HASH_URL, url); + " entity cert \"%s\"", url); + auth->add(auth, AUTH_HELPER_SUBJECT_HASH_URL, url); first = FALSE; } else { DBG1(DBG_IKE, "received hash-and-url for issuer" " cert \"%s\"", url); - auth->add_item(auth, AUTHN_IM_HASH_URL, url); + auth->add(auth, AUTH_HELPER_IM_HASH_URL, url); } } break; @@ -264,31 +267,23 @@ static void process_certs(private_ike_cert_pre_t *this, message_t *message) case ENC_OCSP_CONTENT: default: DBG1(DBG_ENC, "certificate encoding %N not supported", - cert_encoding_names, cert_payload->get_cert_encoding(cert_payload)); + cert_encoding_names, encoding); } } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** - * add a certificate request to the message, building request payload if required. + * add the keyid of a certificate to the certificate request payload */ -static void add_certreq_payload(message_t *message, certreq_payload_t **reqp, - certificate_t *cert) +static void add_certreq(certreq_payload_t **req, certificate_t *cert) { - public_key_t *public; - certreq_payload_t *req; - - public = cert->get_public_key(cert); - if (!public) - { - return; - } switch (cert->get_type(cert)) { case CERT_X509: { + public_key_t *public; identification_t *keyid; x509_t *x509 = (x509_t*)cert; @@ -296,22 +291,49 @@ static void add_certreq_payload(message_t *message, certreq_payload_t **reqp, { /* no CA cert, skip */ break; } - if (*reqp == NULL) + public = cert->get_public_key(cert); + if (!public) { - *reqp = certreq_payload_create_type(CERT_X509); - message->add_payload(message, (payload_t*)*reqp); + break; + } + if (*req == NULL) + { + *req = certreq_payload_create_type(CERT_X509); } - req = *reqp; keyid = public->get_id(public, ID_PUBKEY_INFO_SHA1); - req->add_keyid(req, keyid->get_encoding(keyid)); - DBG1(DBG_IKE, "sending cert request for \"%D\"", + (*req)->add_keyid(*req, keyid->get_encoding(keyid)); + public->destroy(public); + DBG1(DBG_IKE, "sending cert request for \"%Y\"", cert->get_subject(cert)); break; } default: break; } - public->destroy(public); +} + +/** + * add a auth_cfg's CA certificates to the certificate request + */ +static void add_certreqs(certreq_payload_t **req, auth_cfg_t *auth) +{ + 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(req, (certificate_t*)value); + break; + default: + break; + } + } + enumerator->destroy(enumerator); } /** @@ -319,88 +341,96 @@ static void add_certreq_payload(message_t *message, certreq_payload_t **reqp, */ static void build_certreqs(private_ike_cert_pre_t *this, message_t *message) { + enumerator_t *enumerator; ike_cfg_t *ike_cfg; peer_cfg_t *peer_cfg; - enumerator_t *enumerator; certificate_t *cert; - bool restricted = FALSE; - certreq_payload_t *x509_req = NULL; + 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 */ peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); if (peer_cfg) { - void *ptr; - identification_t *id; - auth_item_t item; - auth_info_t *auth = peer_cfg->get_auth(peer_cfg); - enumerator_t *auth_enumerator = auth->create_item_enumerator(auth); - - while (auth_enumerator->enumerate(auth_enumerator, &item, &ptr)) + enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE); + while (enumerator->enumerate(enumerator, &auth)) { - switch (item) - { - case AUTHZ_CA_CERT: - cert = (certificate_t *)ptr; - add_certreq_payload(message, &x509_req, cert); - restricted = TRUE; - break; - case AUTHZ_CA_CERT_NAME: - id = (identification_t *)ptr; - enumerator = charon->credentials->create_cert_enumerator( - charon->credentials, CERT_ANY, KEY_ANY, id, TRUE); - while (enumerator->enumerate(enumerator, &cert, TRUE)) - { - add_certreq_payload(message, &x509_req, cert); - restricted = TRUE; - } - enumerator->destroy(enumerator); - break; - default: - break; - } + add_certreqs(&req, auth); } - auth_enumerator->destroy(auth_enumerator); + enumerator->destroy(enumerator); } - - if (!restricted) + + if (!req) { - /* otherwise include all trusted CA certificates */ + /* otherwise add all trusted CA certificates */ enumerator = charon->credentials->create_cert_enumerator( charon->credentials, CERT_ANY, KEY_ANY, NULL, TRUE); - while (enumerator->enumerate(enumerator, &cert, TRUE)) + while (enumerator->enumerate(enumerator, &cert)) { - add_certreq_payload(message, &x509_req, cert); + add_certreq(&req, cert); } enumerator->destroy(enumerator); } - /* if we've added at least one certreq, we notify our peer that we support - * "Hash and URL" for the requested certificates */ - if (lib->settings->get_bool(lib->settings, "charon.hash_and_url", FALSE) && - message->get_payload(message, CERTIFICATE_REQUEST)) + if (req) { - message->add_notify(message, FALSE, HTTP_CERT_LOOKUP_SUPPORTED, chunk_empty); - this->http_cert_lookup_supported_sent = TRUE; + message->add_payload(message, (payload_t*)req); + + if (lib->settings->get_bool(lib->settings, "charon.hash_and_url", FALSE)) + { + message->add_notify(message, FALSE, HTTP_CERT_LOOKUP_SUPPORTED, + chunk_empty); + this->do_http_lookup = TRUE; + } } } /** + * Check if this is the final authentication round + */ +static bool final_auth(message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + notify_payload_t *notify; + + /* we check for an AUTH payload without a ANOTHER_AUTH_FOLLOWS notify */ + if (message->get_payload(message, AUTHENTICATION) == NULL) + { + return FALSE; + } + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == NOTIFY) + { + notify = (notify_payload_t*)payload; + if (notify->get_notify_type(notify) == ANOTHER_AUTH_FOLLOWS) + { + enumerator->destroy(enumerator); + return FALSE; + } + } + } + enumerator->destroy(enumerator); + return TRUE; +} + +/** * Implementation of task_t.process for initiator */ static status_t build_i(private_ike_cert_pre_t *this, message_t *message) { - if (message->get_exchange_type(message) == IKE_SA_INIT) - { - return NEED_MORE; + if (message->get_message_id(message) == 1) + { /* initiator sends CERTREQs in first IKE_AUTH */ + build_certreqs(this, message); } - build_certreqs(this, message); return NEED_MORE; } @@ -408,13 +438,13 @@ static status_t build_i(private_ike_cert_pre_t *this, message_t *message) * Implementation of task_t.process for responder */ static status_t process_r(private_ike_cert_pre_t *this, message_t *message) -{ - if (message->get_exchange_type(message) == IKE_SA_INIT) - { - return NEED_MORE; +{ + if (message->get_exchange_type(message) != IKE_SA_INIT) + { /* handle certreqs/certs in any IKE_AUTH, just in case */ + process_certreqs(this, message); + process_certs(this, message); } - process_certreqs(this, message); - process_certs(this, message); + this->final = final_auth(message); return NEED_MORE; } @@ -426,9 +456,12 @@ static status_t build_r(private_ike_cert_pre_t *this, message_t *message) if (message->get_exchange_type(message) == IKE_SA_INIT) { build_certreqs(this, message); - return NEED_MORE; } - return SUCCESS; + if (this->final) + { + return SUCCESS; + } + return NEED_MORE; } /** @@ -439,10 +472,14 @@ static status_t process_i(private_ike_cert_pre_t *this, message_t *message) if (message->get_exchange_type(message) == IKE_SA_INIT) { process_certreqs(this, message); - return NEED_MORE; } process_certs(this, message); - return SUCCESS; + + if (final_auth(message)) + { + return SUCCESS; + } + return NEED_MORE; } /** @@ -493,7 +530,8 @@ ike_cert_pre_t *ike_cert_pre_create(ike_sa_t *ike_sa, bool initiator) this->ike_sa = ike_sa; this->initiator = initiator; - this->http_cert_lookup_supported_sent = FALSE; + this->do_http_lookup = FALSE; + this->final = FALSE; return &this->public; } |