diff options
Diffstat (limited to 'src/charon/sa/tasks')
-rw-r--r-- | src/charon/sa/tasks/child_create.c | 99 | ||||
-rw-r--r-- | src/charon/sa/tasks/child_delete.c | 7 | ||||
-rw-r--r-- | src/charon/sa/tasks/child_rekey.c | 18 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_auth.c | 1099 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_auth_lifetime.c | 8 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_cert_post.c | 120 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_cert_pre.c | 276 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_config.c | 30 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_init.c | 41 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_me.c | 10 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_mobike.c | 18 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_natd.c | 8 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_rekey.c | 12 |
13 files changed, 963 insertions, 783 deletions
diff --git a/src/charon/sa/tasks/child_create.c b/src/charon/sa/tasks/child_create.c index b3bb1840d..1e1624dca 100644 --- a/src/charon/sa/tasks/child_create.c +++ b/src/charon/sa/tasks/child_create.c @@ -570,7 +570,7 @@ static void handle_notify(private_child_create_t *this, notify_payload_t *notify */ static void process_payloads(private_child_create_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; sa_payload_t *sa_payload; ke_payload_t *ke_payload; @@ -579,8 +579,8 @@ static void process_payloads(private_child_create_t *this, message_t *message) /* defaults to TUNNEL mode */ this->mode = MODE_TUNNEL; - 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)) { @@ -616,7 +616,7 @@ static void process_payloads(private_child_create_t *this, message_t *message) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -643,9 +643,9 @@ static status_t build_i(private_child_create_t *this, message_t *message) } break; case IKE_AUTH: - if (!message->get_payload(message, ID_INITIATOR)) + if (message->get_message_id(message) != 1) { - /* send only in the first request, not in subsequent EAP */ + /* send only in the first request, not in subsequent rounds */ return NEED_MORE; } break; @@ -737,8 +737,6 @@ static status_t build_i(private_child_create_t *this, message_t *message) */ static status_t process_r(private_child_create_t *this, message_t *message) { - peer_cfg_t *peer_cfg; - switch (message->get_exchange_type(message)) { case IKE_SA_INIT: @@ -747,42 +745,17 @@ static status_t process_r(private_child_create_t *this, message_t *message) get_nonce(message, &this->other_nonce); break; case IKE_AUTH: - if (message->get_payload(message, ID_INITIATOR) == NULL) + if (message->get_message_id(message) != 1) { - /* wait until extensible authentication completed, if used */ + /* only handle first AUTH payload, not additional rounds */ return NEED_MORE; } default: break; } - + process_payloads(this, message); - if (this->tsi == NULL || this->tsr == NULL) - { - DBG1(DBG_IKE, "TS payload missing in message"); - return NEED_MORE; - } - - peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - if (peer_cfg) - { - host_t *me, *other; - - me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); - if (me == NULL) - { - me = this->ike_sa->get_my_host(this->ike_sa); - } - other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE); - if (other == NULL) - { - other = this->ike_sa->get_other_host(this->ike_sa); - } - - this->config = peer_cfg->select_child_cfg(peer_cfg, this->tsr, - this->tsi, me, other); - } return NEED_MORE; } @@ -810,10 +783,11 @@ static void handle_child_sa_failure(private_child_create_t *this, */ static status_t build_r(private_child_create_t *this, message_t *message) { + peer_cfg_t *peer_cfg; payload_t *payload; - iterator_t *iterator; + enumerator_t *enumerator; bool no_dh = TRUE; - + switch (message->get_exchange_type(message)) { case IKE_SA_INIT: @@ -828,9 +802,8 @@ static status_t build_r(private_child_create_t *this, message_t *message) no_dh = FALSE; break; case IKE_AUTH: - if (message->get_payload(message, EXTENSIBLE_AUTHENTICATION)) - { - /* wait until extensible authentication completed, if used */ + if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) + { /* wait until all authentication round completed */ return NEED_MORE; } default: @@ -844,6 +817,25 @@ static status_t build_r(private_child_create_t *this, message_t *message) return SUCCESS; } + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (peer_cfg && this->tsi && this->tsr) + { + host_t *me, *other; + + me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); + if (me == NULL) + { + me = this->ike_sa->get_my_host(this->ike_sa); + } + other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE); + if (other == NULL) + { + other = this->ike_sa->get_other_host(this->ike_sa); + } + this->config = peer_cfg->select_child_cfg(peer_cfg, this->tsr, + this->tsi, me, other); + } + if (this->config == NULL) { DBG1(DBG_IKE, "traffic selectors %#R=== %#R inacceptable", @@ -854,8 +846,8 @@ static status_t build_r(private_child_create_t *this, message_t *message) } /* check if ike_config_t included non-critical error notifies */ - 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) == NOTIFY) { @@ -868,7 +860,7 @@ static status_t build_r(private_child_create_t *this, message_t *message) { DBG1(DBG_IKE,"configuration payload negotation " "failed, no CHILD_SA built"); - iterator->destroy(iterator); + enumerator->destroy(enumerator); handle_child_sa_failure(this, message); return SUCCESS; } @@ -877,7 +869,7 @@ static status_t build_r(private_child_create_t *this, message_t *message) } } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa), this->config, this->reqid, @@ -938,7 +930,7 @@ static status_t build_r(private_child_create_t *this, message_t *message) */ static status_t process_i(private_child_create_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; bool no_dh = TRUE; @@ -951,9 +943,8 @@ static status_t process_i(private_child_create_t *this, message_t *message) no_dh = FALSE; break; case IKE_AUTH: - if (message->get_payload(message, EXTENSIBLE_AUTHENTICATION)) - { - /* wait until extensible authentication completed, if used */ + if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) + { /* wait until all authentication round completed */ return NEED_MORE; } default: @@ -961,8 +952,8 @@ static status_t process_i(private_child_create_t *this, message_t *message) } /* check for erronous notifies */ - 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) == NOTIFY) { @@ -982,7 +973,7 @@ static status_t process_i(private_child_create_t *this, message_t *message) { DBG1(DBG_IKE, "received %N notify, no CHILD_SA built", notify_type_names, type); - iterator->destroy(iterator); + enumerator->destroy(enumerator); handle_child_sa_failure(this, message); /* an error in CHILD_SA creation is not critical */ return SUCCESS; @@ -1000,7 +991,7 @@ static status_t process_i(private_child_create_t *this, message_t *message) bad_group, diffie_hellman_group_names, this->dh_group); this->public.task.migrate(&this->public.task, this->ike_sa); - iterator->destroy(iterator); + enumerator->destroy(enumerator); return NEED_MORE; } default: @@ -1008,7 +999,7 @@ static status_t process_i(private_child_create_t *this, message_t *message) } } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); process_payloads(this, message); diff --git a/src/charon/sa/tasks/child_delete.c b/src/charon/sa/tasks/child_delete.c index 36d260f99..26e9695f9 100644 --- a/src/charon/sa/tasks/child_delete.c +++ b/src/charon/sa/tasks/child_delete.c @@ -114,15 +114,16 @@ static void build_payloads(private_child_delete_t *this, message_t *message) */ static void process_payloads(private_child_delete_t *this, message_t *message) { - iterator_t *payloads, *spis; + enumerator_t *payloads; + iterator_t *spis; payload_t *payload; delete_payload_t *delete_payload; u_int32_t *spi; protocol_id_t protocol; child_sa_t *child_sa; - payloads = message->get_payload_iterator(message); - while (payloads->iterate(payloads, (void**)&payload)) + payloads = message->create_payload_enumerator(message); + while (payloads->enumerate(payloads, &payload)) { if (payload->get_type(payload) == DELETE) { diff --git a/src/charon/sa/tasks/child_rekey.c b/src/charon/sa/tasks/child_rekey.c index 127280efc..44a22575c 100644 --- a/src/charon/sa/tasks/child_rekey.c +++ b/src/charon/sa/tasks/child_rekey.c @@ -103,11 +103,11 @@ static status_t process_i_delete(private_child_rekey_t *this, message_t *message */ static void find_child(private_child_rekey_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { notify_payload_t *notify; u_int32_t spi; @@ -131,7 +131,7 @@ static void find_child(private_child_rekey_t *this, message_t *message) break; } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -220,12 +220,12 @@ static status_t process_i(private_child_rekey_t *this, message_t *message) protocol_id_t protocol; u_int32_t spi; child_sa_t *to_delete; - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; /* handle NO_ADDITIONAL_SAS notify */ - 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) == NOTIFY) { @@ -239,12 +239,12 @@ static status_t process_i(private_child_rekey_t *this, message_t *message) charon->processor->queue_job(charon->processor, (job_t*)rekey_ike_sa_job_create( this->ike_sa->get_id(this->ike_sa), TRUE)); - iterator->destroy(iterator); + enumerator->destroy(enumerator); return SUCCESS; } } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); if (this->child_create->task.process(&this->child_create->task, message) == NEED_MORE) { diff --git a/src/charon/sa/tasks/ike_auth.c b/src/charon/sa/tasks/ike_auth.c index ad1621714..d594e3baa 100644 --- a/src/charon/sa/tasks/ike_auth.c +++ b/src/charon/sa/tasks/ike_auth.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2007 Martin Willi + * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -21,14 +21,12 @@ #include <string.h> #include <daemon.h> -#include <crypto/diffie_hellman.h> #include <encoding/payloads/id_payload.h> #include <encoding/payloads/auth_payload.h> #include <encoding/payloads/eap_payload.h> #include <encoding/payloads/nonce_payload.h> #include <sa/authenticators/eap_authenticator.h> - typedef struct private_ike_auth_t private_ike_auth_t; /** @@ -72,220 +70,65 @@ struct private_ike_auth_t { packet_t *other_packet; /** - * EAP authenticator when using EAP + * completed authentication configs initiated by us (auth_cfg_t) */ - eap_authenticator_t *eap_auth; + linked_list_t *my_cfgs; /** - * EAP payload received and ready to process + * completed authentication configs initiated by other (auth_cfg_t) */ - eap_payload_t *eap_payload; + linked_list_t *other_cfgs;; /** - * has the peer been authenticated successfully? + * currently active authenticator, to authenticate us */ - bool peer_authenticated; -}; - -/** - * get the authentication class of a config - */ -auth_class_t get_auth_class(peer_cfg_t *config) -{ - auth_class_t *class; - auth_info_t *auth_info; - - auth_info = config->get_auth(config); - if (auth_info->get_item(auth_info, AUTHN_AUTH_CLASS, (void**)&class)) - { - return *class; - } - /* fallback to pubkey authentication */ - return AUTH_CLASS_PUBKEY; -} - -/** - * get the eap type/vendor - */ -static eap_type_t get_eap_type(peer_cfg_t *config, u_int32_t *vendor) -{ - auth_info_t *auth_info; - u_int *ptr; - - *vendor = 0; - auth_info = config->get_auth(config); - if (auth_info->get_item(auth_info, AUTHN_EAP_VENDOR, (void**)&ptr)) - { - *vendor = *ptr; - } - if (auth_info->get_item(auth_info, AUTHN_EAP_TYPE, (void**)&ptr)) - { - return *ptr; - } - return EAP_NAK; -} - -/** - * build the AUTH payload - */ -static status_t build_auth(private_ike_auth_t *this, message_t *message) -{ - authenticator_t *auth; - auth_payload_t *auth_payload; - peer_cfg_t *config; - status_t status; + authenticator_t *my_auth; - /* create own authenticator and add auth payload */ - config = this->ike_sa->get_peer_cfg(this->ike_sa); - if (!config) - { - DBG1(DBG_IKE, "unable to authenticate, no peer config found"); - return FAILED; - } - - auth = authenticator_create_from_class(this->ike_sa, get_auth_class(config)); - if (auth == NULL) - { - DBG1(DBG_IKE, "configured authentication class %N not supported", - auth_class_names, get_auth_class(config)); - return FAILED; - } - - status = auth->build(auth, this->my_packet->get_data(this->my_packet), - this->other_nonce, &auth_payload); - auth->destroy(auth); - if (status != SUCCESS) - { - DBG1(DBG_IKE, "generating authentication data failed"); - return FAILED; - } - message->add_payload(message, (payload_t*)auth_payload); - return SUCCESS; -} - -/** - * build ID payload(s) - */ -static status_t build_id(private_ike_auth_t *this, message_t *message) -{ - identification_t *me, *other; - id_payload_t *id; - peer_cfg_t *config; - - me = this->ike_sa->get_my_id(this->ike_sa); - other = this->ike_sa->get_other_id(this->ike_sa); - config = this->ike_sa->get_peer_cfg(this->ike_sa); - - if (me->contains_wildcards(me)) - { - me = config->get_my_id(config); - if (me->contains_wildcards(me)) - { - DBG1(DBG_IKE, "negotiation of own ID failed"); - return FAILED; - } - this->ike_sa->set_my_id(this->ike_sa, me->clone(me)); - } + /** + * currently active authenticator, to authenticate peer + */ + authenticator_t *other_auth; - id = id_payload_create_from_identification(this->initiator ? ID_INITIATOR : ID_RESPONDER, me); - message->add_payload(message, (payload_t*)id); + /** + * peer_cfg candidates, ordered by priority + */ + linked_list_t *candidates; - /* as initiator, include other ID if it does not contain wildcards */ - if (this->initiator && !other->contains_wildcards(other)) - { - id = id_payload_create_from_identification(ID_RESPONDER, other); - message->add_payload(message, (payload_t*)id); - } - return SUCCESS; -} - -/** - * process AUTH payload - */ -static status_t process_auth(private_ike_auth_t *this, message_t *message) -{ - auth_payload_t *auth_payload; - authenticator_t *auth; - auth_method_t auth_method; - status_t status; + /** + * selected peer config (might change when using multiple authentications) + */ + peer_cfg_t *peer_cfg; - auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); + /** + * have we planned an(other) authentication exchange? + */ + bool do_another_auth; - if (auth_payload == NULL) - { - /* AUTH payload is missing, client wants to use EAP authentication */ - return NOT_FOUND; - } + /** + * has the peer announced another authentication exchange? + */ + bool expect_another_auth; - auth_method = auth_payload->get_auth_method(auth_payload); - auth = authenticator_create_from_method(this->ike_sa, - auth_payload->get_auth_method(auth_payload)); - if (auth == NULL) - { - DBG1(DBG_IKE, "authentication method %N used by '%D' not supported", - auth_method_names, auth_method, - this->ike_sa->get_other_id(this->ike_sa)); - return NOT_SUPPORTED; - } - status = auth->verify(auth, this->other_packet->get_data(this->other_packet), - this->my_nonce, auth_payload); - auth->destroy(auth); - if (status != SUCCESS) - { - DBG0(DBG_IKE, "authentication of '%D' with %N failed", - this->ike_sa->get_other_id(this->ike_sa), - auth_method_names, auth_method); - return FAILED; - } - return SUCCESS; -} + /** + * should we send a AUTHENTICATION_FAILED notify? + */ + bool authentication_failed; +}; /** - * process ID payload(s) + * check if multiple authentication extension is enabled, configuration-wise */ -static status_t process_id(private_ike_auth_t *this, message_t *message) +static bool multiple_auth_enabled() { - identification_t *id, *req; - id_payload_t *idr, *idi; - - idi = (id_payload_t*)message->get_payload(message, ID_INITIATOR); - idr = (id_payload_t*)message->get_payload(message, ID_RESPONDER); - - if ((this->initiator && idr == NULL) || (!this->initiator && idi == NULL)) - { - DBG1(DBG_IKE, "ID payload missing in message"); - return FAILED; - } - - if (this->initiator) - { - id = idr->get_identification(idr); - req = this->ike_sa->get_other_id(this->ike_sa); - if (!id->matches(id, req)) - { - DBG0(DBG_IKE, "peer ID '%D' unacceptable, '%D' required", id, req); - id->destroy(id); - return FAILED; - } - this->ike_sa->set_other_id(this->ike_sa, id); - } - else - { - id = idi->get_identification(idi); - this->ike_sa->set_other_id(this->ike_sa, id); - if (idr) - { - id = idr->get_identification(idr); - this->ike_sa->set_my_id(this->ike_sa, id); - } - } - return SUCCESS; + return lib->settings->get_bool(lib->settings, + "charon.multiple_authentication", TRUE); } /** * collect the needed information in the IKE_SA_INIT exchange from our message */ -static status_t collect_my_init_data(private_ike_auth_t *this, message_t *message) +static status_t collect_my_init_data(private_ike_auth_t *this, + message_t *message) { nonce_payload_t *nonce; @@ -297,7 +140,7 @@ static status_t collect_my_init_data(private_ike_auth_t *this, message_t *messag } this->my_nonce = nonce->get_nonce(nonce); - /* pre-generate the message, so we can store it for us */ + /* pre-generate the message, keep a copy */ if (this->ike_sa->generate_message(this->ike_sa, message, &this->my_packet) != SUCCESS) { @@ -309,7 +152,8 @@ static status_t collect_my_init_data(private_ike_auth_t *this, message_t *messag /** * collect the needed information in the IKE_SA_INIT exchange from others message */ -static status_t collect_other_init_data(private_ike_auth_t *this, message_t *message) +static status_t collect_other_init_data(private_ike_auth_t *this, + message_t *message) { /* we collect the needed information in the IKE_SA_INIT exchange */ nonce_payload_t *nonce; @@ -322,184 +166,186 @@ static status_t collect_other_init_data(private_ike_auth_t *this, message_t *mes } this->other_nonce = nonce->get_nonce(nonce); - /* pre-generate the message, so we can store it for us */ + /* keep a copy of the received packet */ this->other_packet = message->get_packet(message); return NEED_MORE; } - /** - * Implementation of task_t.build to create AUTH payload from EAP data + * Get the next authentication configuration */ -static status_t build_auth_eap(private_ike_auth_t *this, message_t *message) +static auth_cfg_t *get_auth_cfg(private_ike_auth_t *this, bool local) { - authenticator_t *auth; - auth_payload_t *auth_payload; + enumerator_t *e1, *e2; + auth_cfg_t *c1, *c2, *next = NULL; - if (!this->initiator && !this->peer_authenticated) + /* find an available config not already done */ + e1 = this->peer_cfg->create_auth_cfg_enumerator(this->peer_cfg, local); + while (e1->enumerate(e1, &c1)) { - message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); - return FAILED; - } - - auth = (authenticator_t*)this->eap_auth; - if (auth->build(auth, this->my_packet->get_data(this->my_packet), - this->other_nonce, &auth_payload) != SUCCESS) - { - DBG1(DBG_IKE, "generating authentication data failed"); - if (!this->initiator) + bool found = FALSE; + + if (local) { - message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); + e2 = this->my_cfgs->create_enumerator(this->my_cfgs); + } + else + { + e2 = this->other_cfgs->create_enumerator(this->other_cfgs); + } + while (e2->enumerate(e2, &c2)) + { + if (c2->complies(c2, c1, FALSE)) + { + found = TRUE; + break; + } + } + e2->destroy(e2); + if (!found) + { + next = c1; + break; } - return FAILED; - } - message->add_payload(message, (payload_t*)auth_payload); - if (!this->initiator) - { - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%D]...%H[%D]", - this->ike_sa->get_name(this->ike_sa), - this->ike_sa->get_unique_id(this->ike_sa), - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa)); - return SUCCESS; } - return NEED_MORE; + e1->destroy(e1); + return next; } /** - * Implementation of task_t.process to verify AUTH payload after EAP + * Check if we have should initiate another authentication round */ -static status_t process_auth_eap(private_ike_auth_t *this, message_t *message) +static bool do_another_auth(private_ike_auth_t *this) { - auth_payload_t *auth_payload; - authenticator_t *auth; - - auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); - this->peer_authenticated = FALSE; + bool do_another = FALSE; + enumerator_t *done, *todo; + auth_cfg_t *done_cfg, *todo_cfg; - if (auth_payload) + if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MULTIPLE_AUTH)) { - auth = (authenticator_t*)this->eap_auth; - if (auth->verify(auth, this->other_packet->get_data(this->other_packet), - this->my_nonce, auth_payload) == SUCCESS) - { - this->peer_authenticated = TRUE; - } + return FALSE; } - - if (!this->peer_authenticated) + + done = this->my_cfgs->create_enumerator(this->my_cfgs); + todo = this->peer_cfg->create_auth_cfg_enumerator(this->peer_cfg, TRUE); + while (todo->enumerate(todo, &todo_cfg)) { - DBG0(DBG_IKE, "authentication of '%D' with %N failed", - this->ike_sa->get_other_id(this->ike_sa), - auth_class_names, AUTH_CLASS_EAP); - if (this->initiator) + if (!done->enumerate(done, &done_cfg)) { - return FAILED; + done_cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + } + if (!done_cfg->complies(done_cfg, todo_cfg, FALSE)) + { + do_another = TRUE; + break; } - return NEED_MORE; - } - if (this->initiator) - { - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%D]...%H[%D]", - this->ike_sa->get_name(this->ike_sa), - this->ike_sa->get_unique_id(this->ike_sa), - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa)); - return SUCCESS; } - return NEED_MORE; + done->destroy(done); + todo->destroy(todo); + return do_another; } /** - * Implementation of task_t.process for EAP exchanges + * Get peer configuration candidates from backends */ -static status_t process_eap_i(private_ike_auth_t *this, message_t *message) +static bool load_cfg_candidates(private_ike_auth_t *this) { - eap_payload_t *eap; - - eap = (eap_payload_t*)message->get_payload(message, EXTENSIBLE_AUTHENTICATION); - if (eap == NULL) - { - DBG1(DBG_IKE, "EAP payload missing"); - return FAILED; + enumerator_t *enumerator; + peer_cfg_t *peer_cfg; + host_t *me, *other; + identification_t *my_id, *other_id; + + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); + my_id = this->ike_sa->get_my_id(this->ike_sa); + other_id = this->ike_sa->get_other_id(this->ike_sa); + + enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, + me, other, my_id, other_id); + while (enumerator->enumerate(enumerator, &peer_cfg)) + { + peer_cfg->get_ref(peer_cfg); + if (this->peer_cfg == NULL) + { /* best match */ + this->peer_cfg = peer_cfg; + this->ike_sa->set_peer_cfg(this->ike_sa, peer_cfg); + } + else + { + this->candidates->insert_last(this->candidates, peer_cfg); + } } - switch (this->eap_auth->process(this->eap_auth, eap, &eap)) + enumerator->destroy(enumerator); + if (this->peer_cfg) { - case NEED_MORE: - this->eap_payload = eap; - return NEED_MORE; - case SUCCESS: - /* EAP exchange completed, now create and process AUTH */ - this->eap_payload = NULL; - this->public.task.build = (status_t(*)(task_t*,message_t*))build_auth_eap; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_auth_eap; - return NEED_MORE; - default: - this->eap_payload = NULL; - DBG0(DBG_IKE, "failed to authenticate against '%D' using EAP", - this->ike_sa->get_other_id(this->ike_sa)); - return FAILED; + DBG1(DBG_CFG, "selected peer config '%s'", + this->peer_cfg->get_name(this->peer_cfg)); + return TRUE; } + DBG1(DBG_CFG, "no matching peer config found"); + return FALSE; } /** - * Implementation of task_t.process for EAP exchanges - */ -static status_t process_eap_r(private_ike_auth_t *this, message_t *message) -{ - this->eap_payload = (eap_payload_t*)message->get_payload(message, - EXTENSIBLE_AUTHENTICATION); - return NEED_MORE; -} - -/** - * Implementation of task_t.build for EAP exchanges - */ -static status_t build_eap_i(private_ike_auth_t *this, message_t *message) -{ - message->add_payload(message, (payload_t*)this->eap_payload); - return NEED_MORE; -} - -/** - * Implementation of task_t.build for EAP exchanges + * update the current peer candidate if necessary, using candidates */ -static status_t build_eap_r(private_ike_auth_t *this, message_t *message) +static bool update_cfg_candidates(private_ike_auth_t *this, bool strict) { - status_t status = NEED_MORE; - eap_payload_t *eap; - - if (this->eap_payload == NULL) - { - DBG1(DBG_IKE, "EAP payload missing"); - return FAILED; - } - - switch (this->eap_auth->process(this->eap_auth, this->eap_payload, &eap)) + do { - case NEED_MORE: + if (this->peer_cfg) + { + bool complies = TRUE; + enumerator_t *e1, *e2, *tmp; + auth_cfg_t *c1, *c2; - break; - case SUCCESS: - /* EAP exchange completed, now create and process AUTH */ - this->public.task.build = (status_t(*)(task_t*,message_t*))build_auth_eap; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_auth_eap; - break; - default: - DBG0(DBG_IKE, "authentication of '%D' with %N failed", - this->ike_sa->get_other_id(this->ike_sa), - auth_class_names, AUTH_CLASS_EAP); - status = FAILED; - break; + e1 = this->other_cfgs->create_enumerator(this->other_cfgs); + e2 = this->peer_cfg->create_auth_cfg_enumerator(this->peer_cfg, FALSE); + + if (strict) + { /* swap lists in strict mode: all configured rounds must be + * fulfilled. If !strict, we check only the rounds done so far. */ + tmp = e1; + e1 = e2; + e2 = tmp; + } + while (e1->enumerate(e1, &c1)) + { + /* check if done authentications comply to configured ones */ + if ((!e2->enumerate(e2, &c2)) || + (!strict && !c1->complies(c1, c2, TRUE)) || + (strict && !c2->complies(c2, c1, TRUE))) + { + complies = FALSE; + break; + } + } + e1->destroy(e1); + e2->destroy(e2); + if (complies) + { + break; + } + DBG1(DBG_CFG, "selected peer config '%s' inacceptable", + this->peer_cfg->get_name(this->peer_cfg)); + this->peer_cfg->destroy(this->peer_cfg); + } + if (this->candidates->remove_first(this->candidates, + (void**)&this->peer_cfg) != SUCCESS) + { + DBG1(DBG_CFG, "no alternative config found"); + this->peer_cfg = NULL; + } + else + { + DBG1(DBG_CFG, "switching to peer config '%s'", + this->peer_cfg->get_name(this->peer_cfg)); + this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg); + } } - message->add_payload(message, (payload_t*)eap); - return status; + while (this->peer_cfg); + + return this->peer_cfg != NULL; } /** @@ -507,31 +353,103 @@ static status_t build_eap_r(private_ike_auth_t *this, message_t *message) */ static status_t build_i(private_ike_auth_t *this, message_t *message) { - peer_cfg_t *config; - + auth_cfg_t *cfg; + if (message->get_exchange_type(message) == IKE_SA_INIT) { return collect_my_init_data(this, message); } - - if (build_id(this, message) != SUCCESS) + + if (this->peer_cfg == NULL) { - return FAILED; + this->peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + this->peer_cfg->get_ref(this->peer_cfg); } - config = this->ike_sa->get_peer_cfg(this->ike_sa); - if (get_auth_class(config) == AUTH_CLASS_EAP) - { - this->eap_auth = eap_authenticator_create(this->ike_sa); + if (message->get_message_id(message) == 1 && + this->ike_sa->supports_extension(this->ike_sa, EXT_MULTIPLE_AUTH)) + { /* in the first IKE_AUTH, indicate support for multiple authentication */ + message->add_notify(message, FALSE, MULTIPLE_AUTH_SUPPORTED, chunk_empty); } - else + + if (!this->do_another_auth && !this->my_auth) + { /* we have done our rounds */ + return NEED_MORE; + } + + /* check if an authenticator is in progress */ + if (this->my_auth == NULL) { - if (build_auth(this, message) != SUCCESS) + identification_t *id; + id_payload_t *id_payload; + + /* clean up authentication config from a previous round */ + cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + cfg->purge(cfg, TRUE); + + /* add (optional) IDr */ + cfg = get_auth_cfg(this, FALSE); + if (cfg) + { + id = cfg->get(cfg, AUTH_RULE_IDENTITY); + if (id && !id->contains_wildcards(id)) + { + this->ike_sa->set_other_id(this->ike_sa, id->clone(id)); + id_payload = id_payload_create_from_identification( + ID_RESPONDER, id); + message->add_payload(message, (payload_t*)id_payload); + } + } + /* add IDi */ + cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + cfg->merge(cfg, get_auth_cfg(this, TRUE), TRUE); + id = cfg->get(cfg, AUTH_RULE_IDENTITY); + if (!id) + { + DBG1(DBG_CFG, "configuration misses IDi"); + return FAILED; + } + this->ike_sa->set_my_id(this->ike_sa, id->clone(id)); + id_payload = id_payload_create_from_identification(ID_INITIATOR, id); + message->add_payload(message, (payload_t*)id_payload); + + /* build authentication data */ + this->my_auth = authenticator_create_builder( + this->ike_sa, cfg, this->other_nonce, + this->my_packet->get_data(this->my_packet)); + if (!this->my_auth) { return FAILED; } } - + switch (this->my_auth->build(this->my_auth, message)) + { + case SUCCESS: + /* authentication step complete, reset authenticator */ + cfg = auth_cfg_create(); + cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, TRUE), TRUE); + this->my_cfgs->insert_last(this->my_cfgs, cfg); + this->my_auth->destroy(this->my_auth); + this->my_auth = NULL; + break; + case NEED_MORE: + break; + default: + return FAILED; + } + + /* check for additional authentication rounds */ + if (do_another_auth(this)) + { + if (message->get_payload(message, AUTHENTICATION)) + { + message->add_notify(message, FALSE, ANOTHER_AUTH_FOLLOWS, chunk_empty); + } + } + else + { + this->do_another_auth = FALSE; + } return NEED_MORE; } @@ -540,45 +458,135 @@ static status_t build_i(private_ike_auth_t *this, message_t *message) */ static status_t process_r(private_ike_auth_t *this, message_t *message) { - peer_cfg_t *config; + auth_cfg_t *cfg, *cand; + id_payload_t *id_payload; + identification_t *id; if (message->get_exchange_type(message) == IKE_SA_INIT) { return collect_other_init_data(this, message); } - if (process_id(this, message) != SUCCESS) + if (this->my_auth == NULL && this->do_another_auth) + { + /* handle (optional) IDr payload, apply proposed identity */ + id_payload = (id_payload_t*)message->get_payload(message, ID_RESPONDER); + if (id_payload) + { + id = id_payload->get_identification(id_payload); + } + else + { + id = identification_create_from_encoding(ID_ANY, chunk_empty); + } + this->ike_sa->set_my_id(this->ike_sa, id); + } + + if (!this->expect_another_auth) { return NEED_MORE; } + if (message->get_notify(message, MULTIPLE_AUTH_SUPPORTED)) + { + this->ike_sa->enable_extension(this->ike_sa, EXT_MULTIPLE_AUTH); + } - switch (process_auth(this, message)) + if (this->other_auth == NULL) + { + /* handle IDi payload */ + id_payload = (id_payload_t*)message->get_payload(message, ID_INITIATOR); + if (!id_payload) + { + DBG1(DBG_IKE, "IDi payload missing"); + return FAILED; + } + id = id_payload->get_identification(id_payload); + this->ike_sa->set_other_id(this->ike_sa, id); + cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + cfg->add(cfg, AUTH_RULE_IDENTITY, id->clone(id)); + + if (this->peer_cfg == NULL) + { + if (!load_cfg_candidates(this)) + { + this->authentication_failed = TRUE; + return NEED_MORE; + } + } + if (message->get_payload(message, AUTHENTICATION) == NULL) + { /* before authenticating with EAP, we need a EAP config */ + cand = get_auth_cfg(this, FALSE); + while (!cand || ( + (uintptr_t)cand->get(cand, AUTH_RULE_EAP_TYPE) == EAP_NAK && + (uintptr_t)cand->get(cand, AUTH_RULE_EAP_VENDOR) == 0)) + { /* peer requested EAP, but current config does not match */ + this->peer_cfg->destroy(this->peer_cfg); + this->peer_cfg = NULL; + if (!update_cfg_candidates(this, FALSE)) + { + this->authentication_failed = TRUE; + return NEED_MORE; + } + cand = get_auth_cfg(this, FALSE); + } + cfg->merge(cfg, cand, TRUE); + } + + /* verify authentication data */ + this->other_auth = authenticator_create_verifier( + this->ike_sa, message, this->my_nonce, + this->other_packet->get_data(this->other_packet)); + if (!this->other_auth) + { + this->authentication_failed = TRUE; + return NEED_MORE; + } + } + switch (this->other_auth->process(this->other_auth, message)) { case SUCCESS: - this->peer_authenticated = TRUE; - break; - case NOT_FOUND: - /* use EAP if no AUTH payload found */ - this->ike_sa->set_condition(this->ike_sa, COND_EAP_AUTHENTICATED, TRUE); + this->other_auth->destroy(this->other_auth); + this->other_auth = NULL; break; + case NEED_MORE: + if (message->get_payload(message, AUTHENTICATION)) + { /* AUTH verification successful, but another build() needed */ + break; + } + return NEED_MORE; default: + this->authentication_failed = TRUE; return NEED_MORE; } - - config = charon->backends->get_peer_cfg(charon->backends, - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa), - this->ike_sa->get_other_auth(this->ike_sa)); - if (config) + + /* store authentication information */ + cfg = auth_cfg_create(); + cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, FALSE), FALSE); + this->other_cfgs->insert_last(this->other_cfgs, cfg); + + /* another auth round done, invoke authorize hook */ + if (!charon->bus->authorize(charon->bus, this->other_cfgs, FALSE)) + { + DBG1(DBG_IKE, "round %d authorization hook forbids IKE_SA, cancelling", + this->other_cfgs->get_count(this->other_cfgs)); + this->authentication_failed = TRUE; + return NEED_MORE; + } + + if (!update_cfg_candidates(this, FALSE)) { - this->ike_sa->set_peer_cfg(this->ike_sa, config); - config->destroy(config); + this->authentication_failed = TRUE; + return NEED_MORE; } - if (!this->peer_authenticated) - { - this->eap_auth = eap_authenticator_create(this->ike_sa); + + if (message->get_notify(message, ANOTHER_AUTH_FOLLOWS) == NULL) + { + this->expect_another_auth = FALSE; + if (!update_cfg_candidates(this, TRUE)) + { + this->authentication_failed = TRUE; + return NEED_MORE; + } } return NEED_MORE; } @@ -588,52 +596,139 @@ static status_t process_r(private_ike_auth_t *this, message_t *message) */ static status_t build_r(private_ike_auth_t *this, message_t *message) { - peer_cfg_t *config; - eap_type_t eap_type; - u_int32_t eap_vendor; - eap_payload_t *eap_payload; - status_t status; - + auth_cfg_t *cfg; + if (message->get_exchange_type(message) == IKE_SA_INIT) { + if (multiple_auth_enabled()) + { + message->add_notify(message, FALSE, MULTIPLE_AUTH_SUPPORTED, + chunk_empty); + } return collect_my_init_data(this, message); } - if (!this->peer_authenticated && this->eap_auth == NULL) + if (this->authentication_failed || this->peer_cfg == NULL) { - /* peer not authenticated, nor does it want to use EAP */ message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); return FAILED; } - config = this->ike_sa->get_peer_cfg(this->ike_sa); - if (config == NULL) + if (this->my_auth == NULL && this->do_another_auth) { - DBG1(DBG_IKE, "no matching config found for '%D'...'%D'", - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa)); - message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); - return FAILED; + identification_t *id, *id_cfg; + id_payload_t *id_payload; + + /* add IDr */ + cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + cfg->purge(cfg, TRUE); + cfg->merge(cfg, get_auth_cfg(this, TRUE), TRUE); + + id_cfg = cfg->get(cfg, AUTH_RULE_IDENTITY); + id = this->ike_sa->get_my_id(this->ike_sa); + if (id->get_type(id) == ID_ANY) + { /* no IDr received, apply configured ID */ + if (!id_cfg || id_cfg->contains_wildcards(id_cfg)) + { + DBG1(DBG_CFG, "IDr not configured and negotiation failed"); + message->add_notify(message, TRUE, AUTHENTICATION_FAILED, + chunk_empty); + return FAILED; + } + this->ike_sa->set_my_id(this->ike_sa, id_cfg->clone(id_cfg)); + id = id_cfg; + } + else + { /* IDr received, check if it matches configuration */ + if (id_cfg && !id->matches(id, id_cfg)) + { + DBG1(DBG_CFG, "received IDr %D, but require %D", id, id_cfg); + message->add_notify(message, TRUE, AUTHENTICATION_FAILED, + chunk_empty); + return FAILED; + } + } + + id_payload = id_payload_create_from_identification(ID_RESPONDER, id); + message->add_payload(message, (payload_t*)id_payload); + + /* build authentication data */ + this->my_auth = authenticator_create_builder( + this->ike_sa, cfg, this->other_nonce, + this->my_packet->get_data(this->my_packet)); + if (!this->my_auth) + { + message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); + return FAILED; + } } - if (build_id(this, message) != SUCCESS || - build_auth(this, message) != SUCCESS) + if (this->other_auth) { - message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); - return FAILED; + switch (this->other_auth->build(this->other_auth, message)) + { + case SUCCESS: + this->other_auth->destroy(this->other_auth); + this->other_auth = NULL; + break; + case NEED_MORE: + break; + default: + if (!message->get_payload(message, EXTENSIBLE_AUTHENTICATION)) + { /* skip AUTHENTICATION_FAILED if we have EAP_FAILURE */ + message->add_notify(message, TRUE, AUTHENTICATION_FAILED, + chunk_empty); + } + return FAILED; + } } - - if (charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager, - this->ike_sa)) + if (this->my_auth) { - DBG1(DBG_IKE, "cancelling IKE_SA setup due uniqueness policy"); - message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty); - return FAILED; + switch (this->my_auth->build(this->my_auth, message)) + { + case SUCCESS: + cfg = auth_cfg_create(); + cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, TRUE), + TRUE); + this->my_cfgs->insert_last(this->my_cfgs, cfg); + this->my_auth->destroy(this->my_auth); + this->my_auth = NULL; + break; + case NEED_MORE: + break; + default: + message->add_notify(message, TRUE, AUTHENTICATION_FAILED, + chunk_empty); + return FAILED; + } } - /* use "traditional" authentication if we could authenticate peer */ - if (this->peer_authenticated) + /* check for additional authentication rounds */ + if (do_another_auth(this)) + { + message->add_notify(message, FALSE, ANOTHER_AUTH_FOLLOWS, chunk_empty); + } + else + { + this->do_another_auth = FALSE; + } + if (!this->do_another_auth && !this->expect_another_auth) { + if (charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager, + this->ike_sa)) + { + DBG1(DBG_IKE, "cancelling IKE_SA setup due uniqueness policy"); + message->add_notify(message, TRUE, AUTHENTICATION_FAILED, + chunk_empty); + return FAILED; + } + if (!charon->bus->authorize(charon->bus, this->other_cfgs, TRUE)) + { + DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling"); + message->add_notify(message, TRUE, AUTHENTICATION_FAILED, + chunk_empty); + return FAILED; + } this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%D]...%H[%D]", this->ike_sa->get_name(this->ike_sa), @@ -644,21 +739,6 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) this->ike_sa->get_other_id(this->ike_sa)); return SUCCESS; } - - /* initiate EAP authenitcation */ - eap_type = get_eap_type(config, &eap_vendor); - status = this->eap_auth->initiate(this->eap_auth, eap_type, - eap_vendor, &eap_payload); - message->add_payload(message, (payload_t*)eap_payload); - if (status != NEED_MORE) - { - DBG1(DBG_IKE, "unable to initiate EAP authentication"); - return FAILED; - } - - /* switch to EAP methods */ - this->public.task.build = (status_t(*)(task_t*,message_t*))build_eap_r; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_eap_r; return NEED_MORE; } @@ -667,18 +747,22 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) */ static status_t process_i(private_ike_auth_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; - peer_cfg_t *config; - auth_info_t *auth; + auth_cfg_t *cfg; if (message->get_exchange_type(message) == IKE_SA_INIT) { + if (message->get_notify(message, MULTIPLE_AUTH_SUPPORTED) && + multiple_auth_enabled()) + { + this->ike_sa->enable_extension(this->ike_sa, EXT_MULTIPLE_AUTH); + } return collect_other_init_data(this, message); } - 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) == NOTIFY) { @@ -714,7 +798,7 @@ static status_t process_i(private_ike_auth_t *this, message_t *message) { DBG1(DBG_IKE, "received %N notify error", notify_type_names, type); - iterator->destroy(iterator); + enumerator->destroy(enumerator); return FAILED; } DBG2(DBG_IKE, "received %N notify", @@ -724,39 +808,115 @@ static status_t process_i(private_ike_auth_t *this, message_t *message) } } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); - if (process_id(this, message) != SUCCESS || - process_auth(this, message) != SUCCESS) + if (this->my_auth) { - return FAILED; + switch (this->my_auth->process(this->my_auth, message)) + { + case SUCCESS: + cfg = auth_cfg_create(); + cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, TRUE), + TRUE); + this->my_cfgs->insert_last(this->my_cfgs, cfg); + this->my_auth->destroy(this->my_auth); + this->my_auth = NULL; + this->do_another_auth = do_another_auth(this); + break; + case NEED_MORE: + break; + default: + return FAILED; + } } - if (this->eap_auth) + if (this->expect_another_auth) { - /* switch to EAP authentication methods */ - this->public.task.build = (status_t(*)(task_t*,message_t*))build_eap_i; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_eap_i; - return process_eap_i(this, message); + if (this->other_auth == NULL) + { + id_payload_t *id_payload; + identification_t *id; + + /* responder is not allowed to do EAP */ + if (!message->get_payload(message, AUTHENTICATION)) + { + DBG1(DBG_IKE, "AUTH payload missing"); + return FAILED; + } + + /* handle IDr payload */ + id_payload = (id_payload_t*)message->get_payload(message, + ID_RESPONDER); + if (!id_payload) + { + DBG1(DBG_IKE, "IDr payload missing"); + return FAILED; + } + id = id_payload->get_identification(id_payload); + this->ike_sa->set_other_id(this->ike_sa, id); + cfg = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + cfg->add(cfg, AUTH_RULE_IDENTITY, id->clone(id)); + + /* verify authentication data */ + this->other_auth = authenticator_create_verifier( + this->ike_sa, message, this->my_nonce, + this->other_packet->get_data(this->other_packet)); + if (!this->other_auth) + { + return FAILED; + } + } + switch (this->other_auth->process(this->other_auth, message)) + { + case SUCCESS: + break; + case NEED_MORE: + return NEED_MORE; + default: + return FAILED; + } + /* store authentication information, reset authenticator */ + cfg = auth_cfg_create(); + cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, FALSE), FALSE); + this->other_cfgs->insert_last(this->other_cfgs, cfg); + this->other_auth->destroy(this->other_auth); + this->other_auth = NULL; + + /* another auth round done, invoke authorize hook */ + if (!charon->bus->authorize(charon->bus, this->other_cfgs, FALSE)) + { + DBG1(DBG_IKE, "round %d authorization forbids IKE_SA, cancelling", + this->other_cfgs->get_count(this->other_cfgs)); + return FAILED; + } } - config = this->ike_sa->get_peer_cfg(this->ike_sa); - auth = this->ike_sa->get_other_auth(this->ike_sa); - if (!auth->complies(auth, config->get_auth(config))) + if (message->get_notify(message, ANOTHER_AUTH_FOLLOWS) == NULL) { - DBG0(DBG_IKE, "authorization of '%D' for config %s failed", - this->ike_sa->get_other_id(this->ike_sa), config->get_name(config)); - return FAILED; + this->expect_another_auth = FALSE; } - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%D]...%H[%D]", - this->ike_sa->get_name(this->ike_sa), - this->ike_sa->get_unique_id(this->ike_sa), - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa)); - return SUCCESS; + if (!this->expect_another_auth && !this->do_another_auth && !this->my_auth) + { + if (!update_cfg_candidates(this, TRUE)) + { + return FAILED; + } + if (!charon->bus->authorize(charon->bus, this->other_cfgs, TRUE)) + { + DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling"); + return FAILED; + } + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%D]...%H[%D]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + return SUCCESS; + } + return NEED_MORE; } /** @@ -776,28 +936,25 @@ static void migrate(private_ike_auth_t *this, ike_sa_t *ike_sa) chunk_free(&this->other_nonce); DESTROY_IF(this->my_packet); DESTROY_IF(this->other_packet); - if (this->eap_auth) - { - this->eap_auth->authenticator_interface.destroy( - &this->eap_auth->authenticator_interface); - } + DESTROY_IF(this->peer_cfg); + DESTROY_IF(this->my_auth); + DESTROY_IF(this->other_auth); + this->my_cfgs->destroy_offset(this->my_cfgs, offsetof(auth_cfg_t, destroy)); + this->other_cfgs->destroy_offset(this->other_cfgs, offsetof(auth_cfg_t, destroy)); + this->candidates->destroy_offset(this->candidates, offsetof(peer_cfg_t, destroy)); this->my_packet = NULL; this->other_packet = NULL; - this->peer_authenticated = FALSE; - this->eap_auth = NULL; - this->eap_payload = NULL; this->ike_sa = ike_sa; - if (this->initiator) - { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; - } - else - { - this->public.task.build = (status_t(*)(task_t*,message_t*))build_r; - this->public.task.process = (status_t(*)(task_t*,message_t*))process_r; - } + this->peer_cfg = NULL; + this->my_auth = NULL; + this->other_auth = NULL; + this->do_another_auth = TRUE; + this->expect_another_auth = TRUE; + this->authentication_failed = FALSE; + this->my_cfgs = linked_list_create(); + this->other_cfgs = linked_list_create(); + this->candidates = linked_list_create(); } /** @@ -809,11 +966,12 @@ static void destroy(private_ike_auth_t *this) chunk_free(&this->other_nonce); DESTROY_IF(this->my_packet); DESTROY_IF(this->other_packet); - if (this->eap_auth) - { - this->eap_auth->authenticator_interface.destroy( - &this->eap_auth->authenticator_interface); - } + DESTROY_IF(this->my_auth); + DESTROY_IF(this->other_auth); + DESTROY_IF(this->peer_cfg); + this->my_cfgs->destroy_offset(this->my_cfgs, offsetof(auth_cfg_t, destroy)); + this->other_cfgs->destroy_offset(this->other_cfgs, offsetof(auth_cfg_t, destroy)); + this->candidates->destroy_offset(this->candidates, offsetof(peer_cfg_t, destroy)); free(this); } @@ -823,7 +981,7 @@ static void destroy(private_ike_auth_t *this) ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator) { private_ike_auth_t *this = malloc_thing(private_ike_auth_t); - + this->public.task.get_type = (task_type_t(*)(task_t*))get_type; this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; this->public.task.destroy = (void(*)(task_t*))destroy; @@ -845,9 +1003,16 @@ ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator) this->other_nonce = chunk_empty; this->my_packet = NULL; this->other_packet = NULL; - this->peer_authenticated = FALSE; - this->eap_auth = NULL; - this->eap_payload = NULL; + this->peer_cfg = NULL; + this->my_cfgs = linked_list_create(); + this->other_cfgs = linked_list_create(); + this->candidates = linked_list_create(); + this->my_auth = NULL; + this->other_auth = NULL; + this->do_another_auth = TRUE; + this->expect_another_auth = TRUE; + this->authentication_failed = FALSE; return &this->public; } + diff --git a/src/charon/sa/tasks/ike_auth_lifetime.c b/src/charon/sa/tasks/ike_auth_lifetime.c index 328f11d2c..a175aa53a 100644 --- a/src/charon/sa/tasks/ike_auth_lifetime.c +++ b/src/charon/sa/tasks/ike_auth_lifetime.c @@ -64,12 +64,12 @@ static void add_auth_lifetime(private_ike_auth_lifetime_t *this, message_t *mess */ static void process_payloads(private_ike_auth_lifetime_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; notify_payload_t *notify; - 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) == NOTIFY) { @@ -88,7 +88,7 @@ static void process_payloads(private_ike_auth_lifetime_t *this, message_t *messa } } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** diff --git a/src/charon/sa/tasks/ike_cert_post.c b/src/charon/sa/tasks/ike_cert_post.c index 825cf0711..da3ee4dce 100644 --- a/src/charon/sa/tasks/ike_cert_post.c +++ b/src/charon/sa/tasks/ike_cert_post.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 Tobias Brunner - * Copyright (C) 2006-2008 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 @@ -98,70 +98,68 @@ static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this, certifi } /** - * from ike_auth.c - */ -auth_class_t get_auth_class(peer_cfg_t *config); - -/** * add certificates to message */ static void build_certs(private_ike_cert_post_t *this, message_t *message) { peer_cfg_t *peer_cfg; + auth_cfg_t *auth; peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - if (peer_cfg && get_auth_class(peer_cfg) == AUTH_CLASS_PUBKEY) + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + if (!peer_cfg || + (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_PUBKEY) + { + return; + } + switch (peer_cfg->get_cert_policy(peer_cfg)) { - switch (peer_cfg->get_cert_policy(peer_cfg)) + case CERT_NEVER_SEND: + break; + case CERT_SEND_IF_ASKED: + if (!this->ike_sa->has_condition(this->ike_sa, COND_CERTREQ_SEEN)) + { + break; + } + /* FALL */ + case CERT_ALWAYS_SEND: { - case CERT_NEVER_SEND: + cert_payload_t *payload; + enumerator_t *enumerator; + certificate_t *cert; + auth_rule_t type; + + /* get subject cert first, then issuing certificates */ + cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT); + if (!cert) + { break; - case CERT_SEND_IF_ASKED: - if (!this->ike_sa->has_condition(this->ike_sa, COND_CERTREQ_SEEN)) - { - break; - } - /* FALL */ - case CERT_ALWAYS_SEND: + } + payload = build_cert_payload(this, cert); + if (!payload) { - cert_payload_t *payload; - enumerator_t *enumerator; - certificate_t *cert; - auth_info_t *auth; - auth_item_t item; - - auth = this->ike_sa->get_my_auth(this->ike_sa); - /* get subject cert first, then issuing certificates */ - if (!auth->get_item(auth, AUTHZ_SUBJECT_CERT, (void**)&cert)) - { - break; - } - payload = build_cert_payload(this, cert); - if (!payload) - { - break; - } - DBG1(DBG_IKE, "sending end entity cert \"%D\"", - cert->get_subject(cert)); - message->add_payload(message, (payload_t*)payload); - - enumerator = auth->create_item_enumerator(auth); - while (enumerator->enumerate(enumerator, &item, &cert)) + break; + } + DBG1(DBG_IKE, "sending end entity cert \"%D\"", + cert->get_subject(cert)); + message->add_payload(message, (payload_t*)payload); + + enumerator = auth->create_enumerator(auth); + while (enumerator->enumerate(enumerator, &type, &cert)) + { + if (type == AUTH_RULE_IM_CERT) { - if (item == AUTHZ_IM_CERT) + payload = cert_payload_create_from_cert(cert); + if (payload) { - payload = cert_payload_create_from_cert(cert); - if (payload) - { - DBG1(DBG_IKE, "sending issuer cert \"%D\"", - cert->get_subject(cert)); - message->add_payload(message, (payload_t*)payload); - } + DBG1(DBG_IKE, "sending issuer cert \"%D\"", + cert->get_subject(cert)); + message->add_payload(message, (payload_t*)payload); } } - enumerator->destroy(enumerator); - } - } + } + enumerator->destroy(enumerator); + } } } @@ -170,12 +168,11 @@ static void build_certs(private_ike_cert_post_t *this, message_t *message) */ static status_t build_i(private_ike_cert_post_t *this, message_t *message) { - if (message->get_exchange_type(message) == IKE_SA_INIT) - { - return NEED_MORE; + if (message->get_payload(message, AUTHENTICATION)) + { /* CERT payloads are sended along AUTH payloads */ + build_certs(this, message); } - build_certs(this, message); - return SUCCESS; + return NEED_MORE; } /** @@ -191,11 +188,14 @@ static status_t process_r(private_ike_cert_post_t *this, message_t *message) */ static status_t build_r(private_ike_cert_post_t *this, message_t *message) { - if (message->get_exchange_type(message) == IKE_SA_INIT) - { + if (message->get_payload(message, AUTHENTICATION)) + { /* CERT payloads are sended along AUTH payloads */ + build_certs(this, message); + } + if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) + { /* stay alive, we might have additional rounds with certs */ return NEED_MORE; } - build_certs(this, message); return SUCCESS; } @@ -204,8 +204,8 @@ static status_t build_r(private_ike_cert_post_t *this, message_t *message) */ static status_t process_i(private_ike_cert_post_t *this, message_t *message) { - if (message->get_exchange_type(message) == IKE_SA_INIT) - { + if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) + { /* stay alive, we might have additional rounds with CERTS */ return NEED_MORE; } return SUCCESS; diff --git a/src/charon/sa/tasks/ike_cert_pre.c b/src/charon/sa/tasks/ike_cert_pre.c index 79bc4f6e0..0ec7004c2 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 @@ -48,9 +48,9 @@ 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 http_cert_lookup_supported_sent; + bool do_http_lookup; }; /** @@ -58,23 +58,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); @@ -98,15 +97,12 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) { DBG1(DBG_IKE, "received cert request for \"%D\"", 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); } id->destroy(id); } @@ -129,7 +125,7 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -140,6 +136,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 +155,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 +172,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 */ + { /* the first is an end entity certificate */ DBG1(DBG_IKE, "received end entity cert \"%D\"", 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\"", 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 +264,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,14 +288,18 @@ 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) + { + break; + } + if (*req == NULL) { - *reqp = certreq_payload_create_type(CERT_X509); - message->add_payload(message, (payload_t*)*reqp); + *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)); + (*req)->add_keyid(*req, keyid->get_encoding(keyid)); + public->destroy(public); DBG1(DBG_IKE, "sending cert request for \"%D\"", cert->get_subject(cert)); break; @@ -311,7 +307,30 @@ static void add_certreq_payload(message_t *message, certreq_payload_t **reqp, 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,75 +338,53 @@ 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; + } } } @@ -396,11 +393,10 @@ static void build_certreqs(private_ike_cert_pre_t *this, message_t *message) */ 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 +404,12 @@ 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); return NEED_MORE; } @@ -426,9 +421,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->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) + { + return SUCCESS; + } + return NEED_MORE; } /** @@ -439,10 +437,38 @@ 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; + + /* as ike_auth is not processed yet, we don't know if authentication + * is complete (and we can return SUCCESS). Therefore we check for + * an AUTH payload without a ANOTHER_AUTH_FOLLOWS notify. */ + if (message->get_payload(message, AUTHENTICATION)) + { + enumerator_t *enumerator; + payload_t *payload; + notify_payload_t *notify; + bool done = TRUE; + + 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) + { + done = FALSE; + } + } + } + enumerator->destroy(enumerator); + if (done) + { + return SUCCESS; + } + } + return NEED_MORE; } /** @@ -493,7 +519,7 @@ 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; return &this->public; } diff --git a/src/charon/sa/tasks/ike_config.c b/src/charon/sa/tasks/ike_config.c index 04c9e57b8..cb769f9b4 100644 --- a/src/charon/sa/tasks/ike_config.c +++ b/src/charon/sa/tasks/ike_config.c @@ -260,11 +260,12 @@ static void process_attribute(private_ike_config_t *this, */ static void process_payloads(private_ike_config_t *this, message_t *message) { - iterator_t *iterator, *attributes; + enumerator_t *enumerator; + iterator_t *attributes; payload_t *payload; - 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) == CONFIGURATION) { @@ -290,7 +291,7 @@ static void process_payloads(private_ike_config_t *this, message_t *message) } } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -298,9 +299,8 @@ static void process_payloads(private_ike_config_t *this, message_t *message) */ static status_t build_i(private_ike_config_t *this, message_t *message) { - if (message->get_exchange_type(message) == IKE_AUTH && - message->get_payload(message, ID_INITIATOR)) - { + if (message->get_message_id(message) == 1) + { /* in first IKE_AUTH only */ peer_cfg_t *config; host_t *vip; @@ -327,9 +327,8 @@ static status_t build_i(private_ike_config_t *this, message_t *message) */ static status_t process_r(private_ike_config_t *this, message_t *message) { - if (message->get_exchange_type(message) == IKE_AUTH && - message->get_payload(message, ID_INITIATOR)) - { + if (message->get_message_id(message) == 1) + { /* in first IKE_AUTH only */ process_payloads(this, message); } return NEED_MORE; @@ -340,9 +339,8 @@ static status_t process_r(private_ike_config_t *this, message_t *message) */ static status_t build_r(private_ike_config_t *this, message_t *message) { - if (message->get_exchange_type(message) == IKE_AUTH && - message->get_payload(message, EXTENSIBLE_AUTHENTICATION) == NULL) - { + if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) + { /* in last IKE_AUTH exchange */ peer_cfg_t *config = this->ike_sa->get_peer_cfg(this->ike_sa); if (config && this->virtual_ip) @@ -355,7 +353,6 @@ static status_t build_r(private_ike_config_t *this, message_t *message) ip = charon->attributes->acquire_address(charon->attributes, config->get_pool(config), this->ike_sa->get_other_id(this->ike_sa), - this->ike_sa->get_other_auth(this->ike_sa), this->virtual_ip); } if (ip == NULL) @@ -384,9 +381,8 @@ static status_t build_r(private_ike_config_t *this, message_t *message) */ static status_t process_i(private_ike_config_t *this, message_t *message) { - if (message->get_exchange_type(message) == IKE_AUTH && - !message->get_payload(message, EXTENSIBLE_AUTHENTICATION)) - { + if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) + { /* in last IKE_AUTH exchange */ host_t *ip; peer_cfg_t *config; diff --git a/src/charon/sa/tasks/ike_init.c b/src/charon/sa/tasks/ike_init.c index 4f28909da..2aac7b02e 100644 --- a/src/charon/sa/tasks/ike_init.c +++ b/src/charon/sa/tasks/ike_init.c @@ -170,11 +170,11 @@ static void build_payloads(private_ike_init_t *this, message_t *message) */ static void process_payloads(private_ike_init_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; - - 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)) { @@ -182,7 +182,7 @@ static void process_payloads(private_ike_init_t *this, message_t *message) { sa_payload_t *sa_payload = (sa_payload_t*)payload; linked_list_t *proposal_list; - + proposal_list = sa_payload->get_proposals(sa_payload); this->proposal = this->config->select_proposal(this->config, proposal_list); @@ -225,7 +225,7 @@ static void process_payloads(private_ike_init_t *this, message_t *message) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -317,12 +317,12 @@ static status_t process_r(private_ike_init_t *this, message_t *message) #ifdef ME { chunk_t connect_id = chunk_empty; - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; - + /* check for a ME_CONNECTID notify */ - 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) == NOTIFY) { @@ -353,7 +353,7 @@ static status_t process_r(private_ike_init_t *this, message_t *message) } } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); if (connect_id.ptr) { @@ -458,12 +458,12 @@ static status_t build_r(private_ike_init_t *this, message_t *message) */ static status_t process_i(private_ike_init_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; - + /* check for erronous notifies */ - 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) == NOTIFY) { @@ -489,19 +489,22 @@ static status_t process_i(private_ike_init_t *this, message_t *message) this->ike_sa->reset(this->ike_sa); } - iterator->destroy(iterator); + enumerator->destroy(enumerator); return NEED_MORE; } case NAT_DETECTION_SOURCE_IP: case NAT_DETECTION_DESTINATION_IP: /* skip, handled in ike_natd_t */ break; + case MULTIPLE_AUTH_SUPPORTED: + /* handled in ike_auth_t */ + break; case COOKIE: { chunk_free(&this->cookie); this->cookie = chunk_clone(notify->get_notification_data(notify)); this->ike_sa->reset(this->ike_sa); - iterator->destroy(iterator); + enumerator->destroy(enumerator); DBG2(DBG_IKE, "received %N notify", notify_type_names, type); return NEED_MORE; } @@ -511,7 +514,7 @@ static status_t process_i(private_ike_init_t *this, message_t *message) { DBG1(DBG_IKE, "received %N notify error", notify_type_names, type); - iterator->destroy(iterator); + enumerator->destroy(enumerator); return FAILED; } DBG2(DBG_IKE, "received %N notify", @@ -521,7 +524,7 @@ static status_t process_i(private_ike_init_t *this, message_t *message) } } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); process_payloads(this, message); diff --git a/src/charon/sa/tasks/ike_me.c b/src/charon/sa/tasks/ike_me.c index 32c264c43..07dfb20a5 100644 --- a/src/charon/sa/tasks/ike_me.c +++ b/src/charon/sa/tasks/ike_me.c @@ -166,11 +166,11 @@ static void gather_and_add_endpoints(private_ike_me_t *this, message_t *message) */ static void process_payloads(private_ike_me_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; - - 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) != NOTIFY) { @@ -237,7 +237,7 @@ static void process_payloads(private_ike_me_t *this, message_t *message) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** diff --git a/src/charon/sa/tasks/ike_mobike.c b/src/charon/sa/tasks/ike_mobike.c index b2ef2731f..29bb61730 100644 --- a/src/charon/sa/tasks/ike_mobike.c +++ b/src/charon/sa/tasks/ike_mobike.c @@ -97,12 +97,12 @@ static void flush_additional_addresses(private_ike_mobike_t *this) */ static void process_payloads(private_ike_mobike_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; bool first = TRUE; - iterator = message->get_payload_iterator(message); - while (iterator->iterate(iterator, (void**)&payload)) + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { int family = AF_INET; notify_payload_t *notify; @@ -181,7 +181,7 @@ static void process_payloads(private_ike_mobike_t *this, message_t *message) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); } /** @@ -332,9 +332,8 @@ static void transmit(private_ike_mobike_t *this, packet_t *packet) */ static status_t build_i(private_ike_mobike_t *this, message_t *message) { - if (message->get_exchange_type(message) == IKE_AUTH && - message->get_payload(message, ID_INITIATOR)) - { + if (message->get_message_id(message) == 1) + { /* only in first IKE_AUTH */ message->add_notify(message, FALSE, MOBIKE_SUPPORTED, chunk_empty); build_address_list(this, message); } @@ -381,9 +380,8 @@ static status_t build_i(private_ike_mobike_t *this, message_t *message) */ static status_t process_r(private_ike_mobike_t *this, message_t *message) { - if (message->get_exchange_type(message) == IKE_AUTH && - message->get_payload(message, ID_INITIATOR)) - { + if (message->get_message_id(message) == 1) + { /* only first IKE_AUTH */ process_payloads(this, message); } else if (message->get_exchange_type(message) == INFORMATIONAL) diff --git a/src/charon/sa/tasks/ike_natd.c b/src/charon/sa/tasks/ike_natd.c index a20af7ce7..f6bb2d43b 100644 --- a/src/charon/sa/tasks/ike_natd.c +++ b/src/charon/sa/tasks/ike_natd.c @@ -166,7 +166,7 @@ static notify_payload_t *build_natd_payload(private_ike_natd_t *this, */ static void process_payloads(private_ike_natd_t *this, message_t *message) { - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; notify_payload_t *notify; chunk_t hash, src_hash, dst_hash; @@ -184,8 +184,8 @@ static void process_payloads(private_ike_natd_t *this, message_t *message) DBG3(DBG_IKE, "precalculated src_hash %B", &src_hash); DBG3(DBG_IKE, "precalculated dst_hash %B", &dst_hash); - 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) != NOTIFY) { @@ -235,7 +235,7 @@ static void process_payloads(private_ike_natd_t *this, message_t *message) break; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); chunk_free(&src_hash); chunk_free(&dst_hash); diff --git a/src/charon/sa/tasks/ike_rekey.c b/src/charon/sa/tasks/ike_rekey.c index 6dbad5ff6..3c49f329a 100644 --- a/src/charon/sa/tasks/ike_rekey.c +++ b/src/charon/sa/tasks/ike_rekey.c @@ -194,12 +194,12 @@ static status_t build_r(private_ike_rekey_t *this, message_t *message) static status_t process_i(private_ike_rekey_t *this, message_t *message) { ike_sa_id_t *to_delete; - iterator_t *iterator; + enumerator_t *enumerator; payload_t *payload; - + /* handle NO_ADDITIONAL_SAS notify */ - 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) == NOTIFY) { @@ -213,12 +213,12 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message) charon->processor->queue_job(charon->processor, (job_t*)rekey_ike_sa_job_create( this->ike_sa->get_id(this->ike_sa), TRUE)); - iterator->destroy(iterator); + enumerator->destroy(enumerator); return SUCCESS; } } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); switch (this->ike_init->task.process(&this->ike_init->task, message)) { |