diff options
author | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2007-06-03 17:36:35 +0000 |
---|---|---|
committer | Rene Mayrhofer <rene@mayrhofer.eu.org> | 2007-06-03 17:36:35 +0000 |
commit | 08ee5250bd9c43fda5f24d10b791ca2c4c17fcee (patch) | |
tree | d4e2fc7144e288d624555a38955593e1ee066531 /src/charon/sa/tasks | |
parent | b0d8ed94fe9e74afb49fdf5f11e4add29879c65c (diff) | |
download | vyos-strongswan-08ee5250bd9c43fda5f24d10b791ca2c4c17fcee.tar.gz vyos-strongswan-08ee5250bd9c43fda5f24d10b791ca2c4c17fcee.zip |
[svn-upgrade] Integrating new upstream version, strongswan (4.1.3)
Diffstat (limited to 'src/charon/sa/tasks')
-rw-r--r-- | src/charon/sa/tasks/child_create.c | 259 | ||||
-rw-r--r-- | src/charon/sa/tasks/child_create.h | 6 | ||||
-rw-r--r-- | src/charon/sa/tasks/child_delete.c | 22 | ||||
-rw-r--r-- | src/charon/sa/tasks/child_rekey.c | 19 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_auth.c | 66 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_cert.c | 50 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_config.c | 45 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_config.h | 5 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_delete.c | 3 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_init.c | 137 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_rekey.c | 77 |
11 files changed, 425 insertions, 264 deletions
diff --git a/src/charon/sa/tasks/child_create.c b/src/charon/sa/tasks/child_create.c index 781d679f2..f70730b05 100644 --- a/src/charon/sa/tasks/child_create.c +++ b/src/charon/sa/tasks/child_create.c @@ -26,6 +26,7 @@ #include <daemon.h> #include <crypto/diffie_hellman.h> #include <encoding/payloads/sa_payload.h> +#include <encoding/payloads/ke_payload.h> #include <encoding/payloads/ts_payload.h> #include <encoding/payloads/nonce_payload.h> #include <encoding/payloads/notify_payload.h> @@ -64,9 +65,9 @@ struct private_child_create_t { chunk_t other_nonce; /** - * policy to create the CHILD_SA from + * config to create the CHILD_SA from */ - policy_t *policy; + child_cfg_t *config; /** * list of proposal candidates @@ -89,6 +90,16 @@ struct private_child_create_t { linked_list_t *tsr; /** + * optional diffie hellman exchange + */ + diffie_hellman_t *dh; + + /** + * group used for DH exchange + */ + diffie_hellman_group_t dh_group; + + /** * mode the new CHILD_SA uses (transport/tunnel/beet) */ mode_t mode; @@ -162,21 +173,29 @@ static bool ts_list_is_host(linked_list_t *list, host_t *host) } /** - * Install a CHILD_SA for usage + * Install a CHILD_SA for usage, return value: + * - FAILED: no acceptable proposal + * - INVALID_ARG: diffie hellman group inacceptable + * - NOT_FOUND: TS inacceptable */ -static status_t select_and_install(private_child_create_t *this) +static status_t select_and_install(private_child_create_t *this, bool no_dh) { prf_plus_t *prf_plus; status_t status; - chunk_t nonce_i, nonce_r, seed; + chunk_t nonce_i, nonce_r, secret, seed; linked_list_t *my_ts, *other_ts; host_t *me, *other, *other_vip, *my_vip; - if (this->proposals == NULL || this->tsi == NULL || this->tsr == NULL) + if (this->proposals == NULL) { - SIG(CHILD_UP_FAILED, "SA/TS payloads missing in message"); + SIG(CHILD_UP_FAILED, "SA payload missing in message"); return FAILED; } + if (this->tsi == NULL || this->tsr == NULL) + { + SIG(CHILD_UP_FAILED, "TS payloads missing in message"); + return NOT_FOUND; + } if (this->initiator) { @@ -198,36 +217,61 @@ static status_t select_and_install(private_child_create_t *this) my_vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); other_vip = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE); - this->proposal = this->policy->select_proposal(this->policy, this->proposals); - + this->proposal = this->config->select_proposal(this->config, this->proposals, + no_dh); if (this->proposal == NULL) { SIG(CHILD_UP_FAILED, "no acceptable proposal found"); return FAILED; } - if (this->initiator && my_vip) - { /* if we have a virtual IP, shorten our TS to the minimum */ - my_ts = this->policy->select_my_traffic_selectors(this->policy, my_ts, - my_vip); + if (!this->proposal->has_dh_group(this->proposal, this->dh_group)) + { + algorithm_t *algo; + if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, + &algo)) + { + u_int16_t group = algo->algorithm; + SIG(CHILD_UP_FAILED, "DH group %N inacceptable, requesting %N", + diffie_hellman_group_names, this->dh_group, + diffie_hellman_group_names, group); + this->dh_group = group; + return INVALID_ARG; + } + else + { + SIG(CHILD_UP_FAILED, "no acceptable proposal found"); + return FAILED; + } + } + + if (my_vip == NULL) + { + my_vip = me; + } + else if (this->initiator) + { /* to setup firewall rules correctly, CHILD_SA needs the virtual IP */ this->child_sa->set_virtual_ip(this->child_sa, my_vip); } - else - { /* shorten in the host2host case only */ - my_ts = this->policy->select_my_traffic_selectors(this->policy, - my_ts, me); - } - if (other_vip) - { /* if other has a virtual IP, shorten it's traffic selectors to it */ - other_ts = this->policy->select_other_traffic_selectors(this->policy, - other_ts, other_vip); + if (other_vip == NULL) + { + other_vip = other; } - else - { /* use his host for the host2host case */ - other_ts = this->policy->select_other_traffic_selectors(this->policy, - other_ts, other); + + my_ts = this->config->get_traffic_selectors(this->config, TRUE, my_ts, + my_vip); + other_ts = this->config->get_traffic_selectors(this->config, FALSE, other_ts, + other_vip); + + if (my_ts->get_count(my_ts) == 0 || other_ts->get_count(other_ts) == 0) + { + my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); + other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy)); + SIG(CHILD_UP_FAILED, "no acceptable traffic selectors found"); + return NOT_FOUND; } + this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy)); this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy)); if (this->initiator) @@ -241,13 +285,6 @@ static status_t select_and_install(private_child_create_t *this) this->tsi = other_ts; } - if (this->tsi->get_count(this->tsi) == 0 || - this->tsr->get_count(this->tsr) == 0) - { - SIG(CHILD_UP_FAILED, "no acceptable traffic selectors found"); - return FAILED; - } - if (!this->initiator) { /* check if requested mode is acceptable, downgrade if required */ @@ -279,7 +316,20 @@ static status_t select_and_install(private_child_create_t *this) } } - seed = chunk_cata("cc", nonce_i, nonce_r); + if (this->dh) + { + if (this->dh->get_shared_secret(this->dh, &secret) != SUCCESS) + { + SIG(CHILD_UP_FAILED, "DH exchange incomplete"); + return FAILED; + } + DBG3(DBG_IKE, "DH secret %B", &secret); + seed = chunk_cata("mcc", secret, nonce_i, nonce_r); + } + else + { + seed = chunk_cata("cc", nonce_i, nonce_r); + } prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed); if (this->initiator) @@ -297,7 +347,7 @@ static status_t select_and_install(private_child_create_t *this) if (status != SUCCESS) { SIG(CHILD_UP_FAILED, "unable to install IPsec SA (SAD) in kernel"); - return status; + return FAILED; } status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts, @@ -306,7 +356,7 @@ static status_t select_and_install(private_child_create_t *this) if (status != SUCCESS) { SIG(CHILD_UP_FAILED, "unable to install IPsec policies (SPD) in kernel"); - return status; + return NOT_FOUND; } /* add to IKE_SA, and remove from task */ this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); @@ -321,8 +371,9 @@ static status_t select_and_install(private_child_create_t *this) static void build_payloads(private_child_create_t *this, message_t *message) { sa_payload_t *sa_payload; - ts_payload_t *ts_payload; nonce_payload_t *nonce_payload; + ke_payload_t *ke_payload; + ts_payload_t *ts_payload; /* add SA payload */ if (this->initiator) @@ -343,6 +394,13 @@ static void build_payloads(private_child_create_t *this, message_t *message) message->add_payload(message, (payload_t*)nonce_payload); } + /* diffie hellman exchange, if PFS enabled */ + if (this->dh) + { + ke_payload = ke_payload_create_from_diffie_hellman(this->dh); + message->add_payload(message, (payload_t*)ke_payload); + } + /* add TSi/TSr payloads */ ts_payload = ts_payload_create_from_traffic_selectors(TRUE, this->tsi); message->add_payload(message, (payload_t*)ts_payload); @@ -371,6 +429,7 @@ static void process_payloads(private_child_create_t *this, message_t *message) iterator_t *iterator; payload_t *payload; sa_payload_t *sa_payload; + ke_payload_t *ke_payload; ts_payload_t *ts_payload; notify_payload_t *notify_payload; @@ -386,6 +445,19 @@ static void process_payloads(private_child_create_t *this, message_t *message) sa_payload = (sa_payload_t*)payload; this->proposals = sa_payload->get_proposals(sa_payload); break; + case KEY_EXCHANGE: + ke_payload = (ke_payload_t*)payload; + if (!this->initiator) + { + this->dh_group = ke_payload->get_dh_group_number(ke_payload); + this->dh = diffie_hellman_create(this->dh_group); + } + if (this->dh) + { + this->dh->set_other_public_value(this->dh, + ke_payload->get_key_exchange_data(ke_payload)); + } + break; case TRAFFIC_SELECTOR_INITIATOR: ts_payload = (ts_payload_t*)payload; this->tsi = ts_payload->get_traffic_selectors(ts_payload); @@ -421,6 +493,7 @@ static void process_payloads(private_child_create_t *this, message_t *message) static status_t build_i(private_child_create_t *this, message_t *message) { host_t *me, *other, *vip; + peer_cfg_t *peer_cfg; switch (message->get_exchange_type(message)) { @@ -432,6 +505,10 @@ static status_t build_i(private_child_create_t *this, message_t *message) message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty); return SUCCESS; } + if (this->dh_group == MODP_NONE) + { + this->dh_group = this->config->get_dh_group(this->config); + } break; case IKE_AUTH: if (!message->get_payload(message, ID_INITIATOR)) @@ -448,25 +525,30 @@ static status_t build_i(private_child_create_t *this, message_t *message) me = this->ike_sa->get_my_host(this->ike_sa); other = this->ike_sa->get_other_host(this->ike_sa); - vip = this->policy->get_virtual_ip(this->policy, NULL); + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + vip = peer_cfg->get_my_virtual_ip(peer_cfg); if (vip) { /* propose a 0.0.0.0/0 subnet when we use virtual ip */ - this->tsi = this->policy->get_my_traffic_selectors(this->policy, NULL); + this->tsi = this->config->get_traffic_selectors(this->config, TRUE, + NULL, NULL); vip->destroy(vip); } else { /* but shorten a 0.0.0.0/0 subnet to the actual address if host2host */ - this->tsi = this->policy->get_my_traffic_selectors(this->policy, me); + this->tsi = this->config->get_traffic_selectors(this->config, TRUE, + NULL, me); } - this->tsr = this->policy->get_other_traffic_selectors(this->policy, other); - this->proposals = this->policy->get_proposals(this->policy); - this->mode = this->policy->get_mode(this->policy); + this->tsr = this->config->get_traffic_selectors(this->config, FALSE, + NULL, other); + this->proposals = this->config->get_proposals(this->config, + this->dh_group == MODP_NONE); + this->mode = this->config->get_mode(this->config); this->child_sa = child_sa_create(me, other, this->ike_sa->get_my_id(this->ike_sa), this->ike_sa->get_other_id(this->ike_sa), - this->policy, this->reqid, + this->config, this->reqid, this->ike_sa->is_natt_enabled(this->ike_sa)); if (this->child_sa->alloc(this->child_sa, this->proposals) != SUCCESS) @@ -475,6 +557,11 @@ static status_t build_i(private_child_create_t *this, message_t *message) return FAILED; } + if (this->dh_group != MODP_NONE) + { + this->dh = diffie_hellman_create(this->dh_group); + } + build_payloads(this, message); this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy)); @@ -492,6 +579,8 @@ 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: @@ -517,18 +606,13 @@ static status_t process_r(private_child_create_t *this, message_t *message) return NEED_MORE; } - this->policy = charon->policies->get_policy(charon->policies, - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa), - this->tsr, this->tsi, - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa)); - - if (this->policy && this->ike_sa->get_policy(this->ike_sa) == NULL) + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (peer_cfg) { - this->ike_sa->set_policy(this->ike_sa, this->policy); + this->config = peer_cfg->select_child_cfg(peer_cfg, this->tsr, this->tsi, + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa)); } - return NEED_MORE; } @@ -537,6 +621,8 @@ static status_t process_r(private_child_create_t *this, message_t *message) */ static status_t build_r(private_child_create_t *this, message_t *message) { + bool no_dh = TRUE; + switch (message->get_exchange_type(message)) { case IKE_SA_INIT: @@ -547,6 +633,7 @@ static status_t build_r(private_child_create_t *this, message_t *message) message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty); return SUCCESS; } + no_dh = FALSE; break; case IKE_AUTH: if (message->get_payload(message, EXTENSIBLE_AUTHENTICATION)) @@ -565,10 +652,11 @@ static status_t build_r(private_child_create_t *this, message_t *message) return SUCCESS; } - if (this->policy == NULL) + if (this->config == NULL) { - SIG(CHILD_UP_FAILED, "no acceptable policy found"); - message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty); + SIG(CHILD_UP_FAILED, "traffic selectors %#R=== %#R inacceptable", + this->tsr, this->tsi); + message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty); return SUCCESS; } @@ -576,13 +664,27 @@ static status_t build_r(private_child_create_t *this, message_t *message) 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->policy, this->reqid, + this->config, this->reqid, this->ike_sa->is_natt_enabled(this->ike_sa)); - if (select_and_install(this) != SUCCESS) + switch (select_and_install(this, no_dh)) { - message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty); - return SUCCESS; + case SUCCESS: + break; + case NOT_FOUND: + message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty); + return SUCCESS; + case INVALID_ARG: + { + u_int16_t group = htons(this->dh_group); + message->add_notify(message, FALSE, INVALID_KE_PAYLOAD, + chunk_from_thing(group)); + return SUCCESS; + } + case FAILED: + default: + message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty); + return SUCCESS; } build_payloads(this, message); @@ -599,6 +701,7 @@ static status_t process_i(private_child_create_t *this, message_t *message) { iterator_t *iterator; payload_t *payload; + bool no_dh = TRUE; switch (message->get_exchange_type(message)) { @@ -606,6 +709,7 @@ static status_t process_i(private_child_create_t *this, message_t *message) return get_nonce(message, &this->other_nonce); case CREATE_CHILD_SA: get_nonce(message, &this->other_nonce); + no_dh = FALSE; break; case IKE_AUTH: if (message->get_payload(message, EXTENSIBLE_AUTHENTICATION)) @@ -643,6 +747,22 @@ static status_t process_i(private_child_create_t *this, message_t *message) /* an error in CHILD_SA creation is not critical */ return SUCCESS; } + case INVALID_KE_PAYLOAD: + { + chunk_t data; + diffie_hellman_group_t bad_group; + + bad_group = this->dh_group; + data = notify->get_notification_data(notify); + this->dh_group = ntohs(*((u_int16_t*)data.ptr)); + DBG1(DBG_IKE, "peer didn't accept DH group %N, " + "it requested %N", diffie_hellman_group_names, + bad_group, diffie_hellman_group_names, this->dh_group); + + this->public.task.migrate(&this->public.task, this->ike_sa); + iterator->destroy(iterator); + return NEED_MORE; + } default: break; } @@ -652,7 +772,7 @@ static status_t process_i(private_child_create_t *this, message_t *message) process_payloads(this, message); - if (select_and_install(this) == SUCCESS) + if (select_and_install(this, no_dh) == SUCCESS) { SIG(CHILD_UP_SUCCESS, "established CHILD_SA successfully"); } @@ -716,6 +836,7 @@ static void migrate(private_child_create_t *this, ike_sa_t *ike_sa) } DESTROY_IF(this->child_sa); DESTROY_IF(this->proposal); + DESTROY_IF(this->dh); if (this->proposals) { this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy)); @@ -725,6 +846,7 @@ static void migrate(private_child_create_t *this, ike_sa_t *ike_sa) this->proposals = NULL; this->tsi = NULL; this->tsr = NULL; + this->dh = NULL; this->child_sa = NULL; this->mode = MODE_TUNNEL; this->reqid = 0; @@ -751,19 +873,20 @@ static void destroy(private_child_create_t *this) DESTROY_IF(this->child_sa); } DESTROY_IF(this->proposal); + DESTROY_IF(this->dh); if (this->proposals) { this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy)); } - DESTROY_IF(this->policy); + DESTROY_IF(this->config); free(this); } /* * Described in header. */ -child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy) +child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config) { private_child_create_t *this = malloc_thing(private_child_create_t); @@ -773,12 +896,12 @@ child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy) 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; - if (policy) + if (config) { this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; this->initiator = TRUE; - policy->get_ref(policy); + config->get_ref(config); } else { @@ -788,13 +911,15 @@ child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy) } this->ike_sa = ike_sa; - this->policy = policy; + this->config = config; this->my_nonce = chunk_empty; this->other_nonce = chunk_empty; this->proposals = NULL; this->proposal = NULL; this->tsi = NULL; this->tsr = NULL; + this->dh = NULL; + this->dh_group = MODP_NONE; this->child_sa = NULL; this->mode = MODE_TUNNEL; this->reqid = 0; diff --git a/src/charon/sa/tasks/child_create.h b/src/charon/sa/tasks/child_create.h index 200d37457..9f4815215 100644 --- a/src/charon/sa/tasks/child_create.h +++ b/src/charon/sa/tasks/child_create.h @@ -28,7 +28,7 @@ typedef struct child_create_t child_create_t; #include <library.h> #include <sa/ike_sa.h> #include <sa/tasks/task.h> -#include <config/policies/policy.h> +#include <config/child_cfg.h> /** * @brief Task of type CHILD_CREATE, established a new CHILD_SA. @@ -80,9 +80,9 @@ struct child_create_t { * @brief Create a new child_create task. * * @param ike_sa IKE_SA this task works for - * @param policy policy if task initiator, NULL if responder + * @param config child_cfg if task initiator, NULL if responder * @return child_create task to handle by the task_manager */ -child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy); +child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config); #endif /* CHILD_CREATE_H_ */ diff --git a/src/charon/sa/tasks/child_delete.c b/src/charon/sa/tasks/child_delete.c index 23d509de5..d0b34a276 100644 --- a/src/charon/sa/tasks/child_delete.c +++ b/src/charon/sa/tasks/child_delete.c @@ -177,10 +177,29 @@ static void destroy_children(private_child_delete_t *this) } /** + * send closing signals for all CHILD_SAs over the bus + */ +static void log_children(private_child_delete_t *this) +{ + iterator_t *iterator; + child_sa_t *child_sa; + + iterator = this->child_sas->create_iterator(this->child_sas, TRUE); + while (iterator->iterate(iterator, (void**)&child_sa)) + { + SIG(CHILD_DOWN_START, "closing CHILD_SA %#R=== %#R", + child_sa->get_traffic_selectors(child_sa, TRUE), + child_sa->get_traffic_selectors(child_sa, FALSE)); + } + iterator->destroy(iterator); +} + +/** * Implementation of task_t.build for initiator */ static status_t build_i(private_child_delete_t *this, message_t *message) { + log_children(this); build_payloads(this, message); return NEED_MORE; } @@ -196,6 +215,7 @@ static status_t process_i(private_child_delete_t *this, message_t *message) process_payloads(this, message); destroy_children(this); + SIG(CHILD_DOWN_SUCCESS, "CHILD_SA closed"); return SUCCESS; } @@ -205,6 +225,7 @@ static status_t process_i(private_child_delete_t *this, message_t *message) static status_t process_r(private_child_delete_t *this, message_t *message) { process_payloads(this, message); + log_children(this); return NEED_MORE; } @@ -219,6 +240,7 @@ static status_t build_r(private_child_delete_t *this, message_t *message) build_payloads(this, message); } destroy_children(this); + SIG(CHILD_DOWN_SUCCESS, "CHILD_SA closed"); return SUCCESS; } diff --git a/src/charon/sa/tasks/child_rekey.c b/src/charon/sa/tasks/child_rekey.c index 745895dbb..4f3c69034 100644 --- a/src/charon/sa/tasks/child_rekey.c +++ b/src/charon/sa/tasks/child_rekey.c @@ -27,7 +27,7 @@ #include <encoding/payloads/notify_payload.h> #include <sa/tasks/child_create.h> #include <sa/tasks/child_delete.h> -#include <queues/jobs/rekey_child_sa_job.h> +#include <processing/jobs/rekey_child_sa_job.h> typedef struct private_child_rekey_t private_child_rekey_t; @@ -183,7 +183,12 @@ static status_t process_i(private_child_rekey_t *this, message_t *message) u_int32_t spi; child_sa_t *to_delete; - this->child_create->task.process(&this->child_create->task, message); + if (this->child_create->task.process(&this->child_create->task, message) == NEED_MORE) + { + /* bad DH group while rekeying, try again */ + this->child_create->task.migrate(&this->child_create->task, this->ike_sa); + return NEED_MORE; + } if (message->get_payload(message, SECURITY_ASSOCIATION) == NULL) { /* establishing new child failed, reuse old. but not when we @@ -192,8 +197,8 @@ static status_t process_i(private_child_rekey_t *this, message_t *message) this->collision->get_type(this->collision) == CHILD_DELETE)) { job_t *job; - u_int32_t retry = charon->configuration->get_retry_interval( - charon->configuration); + u_int32_t retry = RETRY_INTERVAL - (random() % RETRY_JITTER); + job = (job_t*)rekey_child_sa_job_create( this->child_sa->get_reqid(this->child_sa), this->child_sa->get_protocol(this->child_sa), @@ -315,8 +320,8 @@ static void destroy(private_child_rekey_t *this) */ child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, child_sa_t *child_sa) { + child_cfg_t *config; private_child_rekey_t *this = malloc_thing(private_child_rekey_t); - policy_t *policy; this->public.collide = (void (*)(child_rekey_t*,task_t*))collide; this->public.task.get_type = (task_type_t(*)(task_t*))get_type; @@ -327,8 +332,8 @@ child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, child_sa_t *child_sa) this->public.task.build = (status_t(*)(task_t*,message_t*))build_i; this->public.task.process = (status_t(*)(task_t*,message_t*))process_i; this->initiator = TRUE; - policy = child_sa->get_policy(child_sa); - this->child_create = child_create_create(ike_sa, policy); + config = child_sa->get_config(child_sa); + this->child_create = child_create_create(ike_sa, config); } else { diff --git a/src/charon/sa/tasks/ike_auth.c b/src/charon/sa/tasks/ike_auth.c index 541e1bb37..d0dd49aee 100644 --- a/src/charon/sa/tasks/ike_auth.c +++ b/src/charon/sa/tasks/ike_auth.c @@ -100,18 +100,18 @@ static status_t build_auth(private_ike_auth_t *this, message_t *message) { authenticator_t *auth; auth_payload_t *auth_payload; - policy_t *policy; + peer_cfg_t *config; auth_method_t method; status_t status; /* create own authenticator and add auth payload */ - policy = this->ike_sa->get_policy(this->ike_sa); - if (!policy) + config = this->ike_sa->get_peer_cfg(this->ike_sa); + if (!config) { - SIG(IKE_UP_FAILED, "unable to authenticate, no policy found"); + SIG(IKE_UP_FAILED, "unable to authenticate, no peer config found"); return FAILED; } - method = policy->get_auth_method(policy); + method = config->get_auth_method(config); auth = authenticator_create(this->ike_sa, method); if (auth == NULL) @@ -140,15 +140,15 @@ static status_t build_id(private_ike_auth_t *this, message_t *message) { identification_t *me, *other; id_payload_t *id; - policy_t *policy; + peer_cfg_t *config; me = this->ike_sa->get_my_id(this->ike_sa); other = this->ike_sa->get_other_id(this->ike_sa); - policy = this->ike_sa->get_policy(this->ike_sa); + config = this->ike_sa->get_peer_cfg(this->ike_sa); if (me->contains_wildcards(me)) { - me = policy->get_my_id(policy); + me = config->get_my_id(config); if (me->contains_wildcards(me)) { SIG(IKE_UP_FAILED, "negotiation of own ID failed"); @@ -202,7 +202,7 @@ static status_t process_auth(private_ike_auth_t *this, message_t *message) auth->destroy(auth); if (status != SUCCESS) { - SIG(IKE_UP_FAILED, "authentication of %D using %N failed", + SIG(IKE_UP_FAILED, "authentication of '%D' with %N failed", this->ike_sa->get_other_id(this->ike_sa), auth_method_names, auth_method); return FAILED; @@ -215,7 +215,7 @@ static status_t process_auth(private_ike_auth_t *this, message_t *message) */ static status_t process_id(private_ike_auth_t *this, message_t *message) { - identification_t *id; + identification_t *id, *req; id_payload_t *idr, *idi; idi = (id_payload_t*)message->get_payload(message, ID_INITIATOR); @@ -230,6 +230,13 @@ static status_t process_id(private_ike_auth_t *this, message_t *message) if (this->initiator) { id = idr->get_identification(idr); + req = this->ike_sa->get_other_id(this->ike_sa); + if (!id->matches(id, req, NULL)) + { + SIG(IKE_UP_FAILED, "peer ID %D unacceptable, %D required", id, req); + id->destroy(id); + return FAILED; + } this->ike_sa->set_other_id(this->ike_sa, id); } else @@ -346,7 +353,7 @@ static status_t process_auth_eap(private_ike_auth_t *this, message_t *message) if (!this->peer_authenticated) { - SIG(IKE_UP_FAILED, "authentication of %D using %N failed", + SIG(IKE_UP_FAILED, "authentication of '%D' with %N failed", this->ike_sa->get_other_id(this->ike_sa), auth_method_names, AUTH_EAP); if (this->initiator) @@ -444,7 +451,7 @@ static status_t build_eap_r(private_ike_auth_t *this, message_t *message) this->public.task.process = (status_t(*)(task_t*,message_t*))process_auth_eap; break; default: - SIG(IKE_UP_FAILED, "authentication of %D using %N failed", + SIG(IKE_UP_FAILED, "authentication of '%D' with %N failed", this->ike_sa->get_other_id(this->ike_sa), auth_method_names, AUTH_EAP); status = FAILED; @@ -459,7 +466,7 @@ 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) { - policy_t *policy; + peer_cfg_t *config; if (message->get_exchange_type(message) == IKE_SA_INIT) { @@ -471,8 +478,8 @@ static status_t build_i(private_ike_auth_t *this, message_t *message) return FAILED; } - policy = this->ike_sa->get_policy(this->ike_sa); - if (policy->get_auth_method(policy) == AUTH_EAP) + config = this->ike_sa->get_peer_cfg(this->ike_sa); + if (config->get_auth_method(config) == AUTH_EAP) { this->eap_auth = eap_authenticator_create(this->ike_sa); } @@ -488,10 +495,12 @@ static status_t build_i(private_ike_auth_t *this, message_t *message) } /** - * Implementation of task_t.process for initiator + * Implementation of task_t.process for responder */ static status_t process_r(private_ike_auth_t *this, message_t *message) -{ +{ + peer_cfg_t *config; + if (message->get_exchange_type(message) == IKE_SA_INIT) { return collect_other_init_data(this, message); @@ -514,6 +523,17 @@ static status_t process_r(private_ike_auth_t *this, message_t *message) default: break; } + + config = charon->backends->get_peer_cfg(charon->backends, + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa), + this->ike_sa->get_other_ca(this->ike_sa)); + if (config) + { + this->ike_sa->set_peer_cfg(this->ike_sa, config); + config->destroy(config); + } + return NEED_MORE; } @@ -522,7 +542,7 @@ 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) { - policy_t *policy; + peer_cfg_t *config; eap_type_t eap_type; eap_payload_t *eap_payload; status_t status; @@ -532,10 +552,12 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) return collect_my_init_data(this, message); } - policy = this->ike_sa->get_policy(this->ike_sa); - if (policy == NULL) + config = this->ike_sa->get_peer_cfg(this->ike_sa); + if (config == NULL) { - SIG(IKE_UP_FAILED, "no acceptable policy found"); + SIG(IKE_UP_FAILED, "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; } @@ -567,7 +589,7 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) } /* initiate EAP authenitcation */ - eap_type = policy->get_eap_type(policy); + eap_type = config->get_eap_type(config); status = this->eap_auth->initiate(this->eap_auth, eap_type, &eap_payload); message->add_payload(message, (payload_t*)eap_payload); if (status != NEED_MORE) diff --git a/src/charon/sa/tasks/ike_cert.c b/src/charon/sa/tasks/ike_cert.c index 160600742..880ed9c42 100644 --- a/src/charon/sa/tasks/ike_cert.c +++ b/src/charon/sa/tasks/ike_cert.c @@ -84,7 +84,7 @@ static void process_certreqs(private_ike_cert_t *this, message_t *message) encoding = certreq->get_cert_encoding(certreq); if (encoding != CERT_X509_SIGNATURE) { - DBG1(DBG_IKE, "certreq payload %N not supported, ignored", + DBG1(DBG_IKE, "certreq payload %N not supported - ignored", cert_encoding_names, encoding); continue; } @@ -125,7 +125,7 @@ static void process_certs(private_ike_cert_t *this, message_t *message) encoding = cert_payload->get_cert_encoding(cert_payload); if (encoding != CERT_X509_SIGNATURE) { - DBG1(DBG_IKE, "certificate payload %N not supported, ignored", + DBG1(DBG_IKE, "certificate payload %N not supported - ignored", cert_encoding_names, encoding); continue; } @@ -134,31 +134,29 @@ static void process_certs(private_ike_cert_t *this, message_t *message) cert = x509_create_from_chunk(cert_data, 0); if (cert) { - if (charon->credentials->verify(charon->credentials, - cert, &found)) + if (charon->credentials->verify(charon->credentials, cert, &found)) { - DBG2(DBG_IKE, "received end entity certificate is trusted, " - "added to store"); - if (!found) + DBG2(DBG_IKE, "received end entity certificate is trusted - " + "added to store"); + if (found) { - charon->credentials->add_end_certificate( - charon->credentials, cert); + cert->destroy(cert); } else { - cert->destroy(cert); + charon->credentials->add_end_certificate(charon->credentials, cert); } } else { - DBG1(DBG_IKE, "received end entity certificate is not " - "trusted, discarded"); + DBG1(DBG_IKE, "received end entity certificate is not trusted - " + "discarded"); cert->destroy(cert); } } else { - DBG1(DBG_IKE, "parsing of received certificate failed, discarded"); + DBG1(DBG_IKE, "parsing of received certificate failed - discarded"); chunk_free(&cert_data); } } @@ -171,20 +169,20 @@ static void process_certs(private_ike_cert_t *this, message_t *message) */ static void build_certreqs(private_ike_cert_t *this, message_t *message) { - connection_t *connection; - policy_t *policy; + ike_cfg_t *ike_cfg; + peer_cfg_t *peer_cfg; identification_t *ca; certreq_payload_t *certreq; - connection = this->ike_sa->get_connection(this->ike_sa); + ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); - if (connection->get_certreq_policy(connection) != CERT_NEVER_SEND) + if (ike_cfg->send_certreq(ike_cfg) != CERT_NEVER_SEND) { - policy = this->ike_sa->get_policy(this->ike_sa); + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - if (policy) + if (peer_cfg) { - ca = policy->get_other_ca(policy); + ca = peer_cfg->get_other_ca(peer_cfg); if (ca && ca->get_type(ca) != ID_ANY) { @@ -212,17 +210,15 @@ static void build_certreqs(private_ike_cert_t *this, message_t *message) */ static void build_certs(private_ike_cert_t *this, message_t *message) { - policy_t *policy; - connection_t *connection; + peer_cfg_t *peer_cfg; x509_t *cert; cert_payload_t *payload; - policy = this->ike_sa->get_policy(this->ike_sa); - connection = this->ike_sa->get_connection(this->ike_sa); + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - if (policy && policy->get_auth_method(policy) == AUTH_RSA) + if (peer_cfg && peer_cfg->get_auth_method(peer_cfg) == AUTH_RSA) { - switch (connection->get_cert_policy(connection)) + switch (peer_cfg->get_cert_policy(peer_cfg)) { case CERT_NEVER_SEND: break; @@ -236,7 +232,7 @@ static void build_certs(private_ike_cert_t *this, message_t *message) { /* TODO: respect CA cert request */ cert = charon->credentials->get_certificate(charon->credentials, - policy->get_my_id(policy)); + peer_cfg->get_my_id(peer_cfg)); if (cert) { payload = cert_payload_create_from_x509(cert); diff --git a/src/charon/sa/tasks/ike_config.c b/src/charon/sa/tasks/ike_config.c index ce29b9220..3c73395a5 100644 --- a/src/charon/sa/tasks/ike_config.c +++ b/src/charon/sa/tasks/ike_config.c @@ -49,11 +49,6 @@ struct private_ike_config_t { bool initiator; /** - * associated policy with virtual IP configuration - */ - policy_t *policy; - - /** * virtual ip */ host_t *virtual_ip; @@ -266,7 +261,20 @@ 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)) { - this->virtual_ip = this->policy->get_virtual_ip(this->policy, NULL); + peer_cfg_t *config; + host_t *vip; + + /* reuse virtual IP if we already have one */ + vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); + if (vip) + { + this->virtual_ip = vip->clone(vip); + } + else + { + config = this->ike_sa->get_peer_cfg(this->ike_sa); + this->virtual_ip = config->get_my_virtual_ip(config); + } build_payloads(this, message, CFG_REQUEST); } @@ -295,17 +303,18 @@ 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) { - this->policy = this->ike_sa->get_policy(this->ike_sa); + peer_cfg_t *config = this->ike_sa->get_peer_cfg(this->ike_sa); - if (this->policy && this->virtual_ip) + if (config && this->virtual_ip) { host_t *ip; DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip); - ip = this->policy->get_virtual_ip(this->policy, this->virtual_ip); + ip = config->get_other_virtual_ip(config, this->virtual_ip); if (ip == NULL || ip->is_anyaddr(ip)) { DBG1(DBG_IKE, "not assigning a virtual IP to peer"); + DESTROY_IF(ip); return SUCCESS; } DBG1(DBG_IKE, "assigning virtual IP %H to peer", ip); @@ -340,13 +349,20 @@ static status_t process_i(private_ike_config_t *this, message_t *message) !message->get_payload(message, EXTENSIBLE_AUTHENTICATION)) { host_t *ip; + peer_cfg_t *config; DESTROY_IF(this->virtual_ip); this->virtual_ip = NULL; process_payloads(this, message); + + if (this->virtual_ip == NULL) + { /* force a configured virtual IP, even server didn't return one */ + config = this->ike_sa->get_peer_cfg(this->ike_sa); + this->virtual_ip = config->get_my_virtual_ip(config); + } - if (this->virtual_ip) + if (this->virtual_ip && !this->virtual_ip->is_anyaddr(this->virtual_ip)) { this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip); @@ -398,7 +414,7 @@ static void destroy(private_ike_config_t *this) /* * Described in header. */ -ike_config_t *ike_config_create(ike_sa_t *ike_sa, policy_t *policy) +ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator) { private_ike_config_t *this = malloc_thing(private_ike_config_t); @@ -406,21 +422,18 @@ ike_config_t *ike_config_create(ike_sa_t *ike_sa, policy_t *policy) this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate; this->public.task.destroy = (void(*)(task_t*))destroy; - if (policy) + if (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; - this->initiator = TRUE; } 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->initiator = FALSE; } - + this->initiator = initiator; this->ike_sa = ike_sa; - this->policy = policy; this->virtual_ip = NULL; this->dns = linked_list_create(); diff --git a/src/charon/sa/tasks/ike_config.h b/src/charon/sa/tasks/ike_config.h index 0c9b961b4..a7cfddff0 100644 --- a/src/charon/sa/tasks/ike_config.h +++ b/src/charon/sa/tasks/ike_config.h @@ -28,7 +28,6 @@ typedef struct ike_config_t ike_config_t; #include <library.h> #include <sa/ike_sa.h> #include <sa/tasks/task.h> -#include <config/policies/policy.h> /** * @brief Task of type IKE_CONFIG, sets up a virtual IP and other @@ -51,9 +50,9 @@ struct ike_config_t { * @brief Create a new ike_config task. * * @param ike_sa IKE_SA this task works for - * @param policy policy for the initiator, NULL for the responder + * @param initiator TRUE for initiator * @return ike_config task to handle by the task_manager */ -ike_config_t *ike_config_create(ike_sa_t *ike_sa, policy_t *policy); +ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator); #endif /* IKE_CONFIG_H_ */ diff --git a/src/charon/sa/tasks/ike_delete.c b/src/charon/sa/tasks/ike_delete.c index 9c4fdac0e..1a3656ca6 100644 --- a/src/charon/sa/tasks/ike_delete.c +++ b/src/charon/sa/tasks/ike_delete.c @@ -28,7 +28,7 @@ typedef struct private_ike_delete_t private_ike_delete_t; -/** +/**file * Private members of a ike_delete_t task. */ struct private_ike_delete_t { @@ -94,7 +94,6 @@ static status_t process_r(private_ike_delete_t *this, message_t *message) DBG1(DBG_IKE, "deleting IKE_SA on request"); break; case IKE_REKEYING: - DBG1(DBG_IKE, "initiated rekeying, but received delete for IKE_SA"); break; default: break; diff --git a/src/charon/sa/tasks/ike_init.c b/src/charon/sa/tasks/ike_init.c index 0b493666a..f78b5dd66 100644 --- a/src/charon/sa/tasks/ike_init.c +++ b/src/charon/sa/tasks/ike_init.c @@ -57,9 +57,9 @@ struct private_ike_init_t { bool initiator; /** - * Connection established by this IKE_SA + * IKE config to establish */ - connection_t *connection; + ike_cfg_t *config; /** * diffie hellman group to use @@ -69,7 +69,7 @@ struct private_ike_init_t { /** * Diffie hellman object used to generate public DH value. */ - diffie_hellman_t *diffie_hellman; + diffie_hellman_t *dh; /** * nonce chosen by us @@ -117,11 +117,11 @@ static void build_payloads(private_ike_init_t *this, message_t *message) id = this->ike_sa->get_id(this->ike_sa); - this->connection = this->ike_sa->get_connection(this->ike_sa); + this->config = this->ike_sa->get_ike_cfg(this->ike_sa); if (this->initiator) { - proposal_list = this->connection->get_proposals(this->connection); + proposal_list = this->config->get_proposals(this->config); if (this->old_sa) { /* include SPI of new IKE_SA when we are rekeying */ @@ -151,7 +151,7 @@ static void build_payloads(private_ike_init_t *this, message_t *message) nonce_payload->set_nonce(nonce_payload, this->my_nonce); message->add_payload(message, (payload_t*)nonce_payload); - ke_payload = ke_payload_create_from_diffie_hellman(this->diffie_hellman); + ke_payload = ke_payload_create_from_diffie_hellman(this->dh); message->add_payload(message, (payload_t*)ke_payload); } @@ -174,8 +174,8 @@ static void process_payloads(private_ike_init_t *this, message_t *message) linked_list_t *proposal_list; proposal_list = sa_payload->get_proposals(sa_payload); - this->proposal = this->connection->select_proposal( - this->connection, proposal_list); + this->proposal = this->config->select_proposal(this->config, + proposal_list); proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy)); break; @@ -183,34 +183,16 @@ static void process_payloads(private_ike_init_t *this, message_t *message) case KEY_EXCHANGE: { ke_payload_t *ke_payload = (ke_payload_t*)payload; - diffie_hellman_group_t dh_group; - chunk_t key_data; - dh_group = ke_payload->get_dh_group_number(ke_payload); - - if (this->initiator) + this->dh_group = ke_payload->get_dh_group_number(ke_payload); + if (!this->initiator) { - if (dh_group != this->dh_group) - { - DBG1(DBG_IKE, "received a DH group not requested (%N)", - diffie_hellman_group_names, dh_group); - break; - } + this->dh = diffie_hellman_create(this->dh_group); } - else + if (this->dh) { - this->dh_group = dh_group; - if (!this->connection->check_dh_group(this->connection, - dh_group)) - { - break; - } - this->diffie_hellman = diffie_hellman_create(dh_group); - } - if (this->diffie_hellman) - { - key_data = ke_payload->get_key_exchange_data(ke_payload); - this->diffie_hellman->set_other_public_value(this->diffie_hellman, key_data); + this->dh->set_other_public_value(this->dh, + ke_payload->get_key_exchange_data(ke_payload)); } break; } @@ -235,9 +217,9 @@ static status_t build_i(private_ike_init_t *this, message_t *message) randomizer_t *randomizer; status_t status; - this->connection = this->ike_sa->get_connection(this->ike_sa); + this->config = this->ike_sa->get_ike_cfg(this->ike_sa); SIG(IKE_UP_START, "initiating IKE_SA to %H", - this->connection->get_other_host(this->connection)); + this->config->get_other_host(this->config)); this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); if (this->retry++ >= MAX_RETRIES) @@ -247,11 +229,11 @@ static status_t build_i(private_ike_init_t *this, message_t *message) } /* if the DH group is set via use_dh_group(), we already have a DH object */ - if (!this->diffie_hellman) + if (!this->dh) { - this->dh_group = this->connection->get_dh_group(this->connection); - this->diffie_hellman = diffie_hellman_create(this->dh_group); - if (this->diffie_hellman == NULL) + this->dh_group = this->config->get_dh_group(this->config); + this->dh = diffie_hellman_create(this->dh_group); + if (this->dh == NULL) { SIG(IKE_UP_FAILED, "configured DH group %N not supported", diffie_hellman_group_names, this->dh_group); @@ -291,7 +273,7 @@ static status_t process_r(private_ike_init_t *this, message_t *message) { randomizer_t *randomizer; - this->connection = this->ike_sa->get_connection(this->ike_sa); + this->config = this->ike_sa->get_ike_cfg(this->ike_sa); SIG(IKE_UP_FAILED, "%H is initiating an IKE_SA", message->get_source(message)); this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); @@ -326,25 +308,29 @@ static status_t build_r(private_ike_init_t *this, message_t *message) return FAILED; } - if (this->diffie_hellman == NULL || - this->diffie_hellman->get_shared_secret(this->diffie_hellman, - &secret) != SUCCESS) + if (this->dh == NULL || + !this->proposal->has_dh_group(this->proposal, this->dh_group) || + this->dh->get_shared_secret(this->dh, &secret) != SUCCESS) { - chunk_t chunk; - u_int16_t dh_enc; - - SIG(IKE_UP_FAILED, "received inacceptable DH group (%N)", - diffie_hellman_group_names, this->dh_group); - this->dh_group = this->connection->get_dh_group(this->connection); - dh_enc = htons(this->dh_group); - chunk.ptr = (u_int8_t*)&dh_enc; - chunk.len = sizeof(dh_enc); - message->add_notify(message, TRUE, INVALID_KE_PAYLOAD, chunk); - DBG1(DBG_IKE, "requesting DH group %N", - diffie_hellman_group_names, this->dh_group); + algorithm_t *algo; + if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, + &algo)) + { + u_int16_t group = algo->algorithm; + SIG(CHILD_UP_FAILED, "DH group %N inacceptable, requesting %N", + diffie_hellman_group_names, this->dh_group, + diffie_hellman_group_names, group); + this->dh_group = group; + group = htons(group); + message->add_notify(message, FALSE, INVALID_KE_PAYLOAD, + chunk_from_thing(group)); + } + else + { + SIG(IKE_UP_FAILED, "no acceptable proposal found"); + } return FAILED; } - if (this->old_sa) { @@ -405,27 +391,20 @@ static status_t process_i(private_ike_init_t *this, message_t *message) case INVALID_KE_PAYLOAD: { chunk_t data; - diffie_hellman_group_t old_dh_group; + diffie_hellman_group_t bad_group; - old_dh_group = this->dh_group; + bad_group = this->dh_group; data = notify->get_notification_data(notify); this->dh_group = ntohs(*((u_int16_t*)data.ptr)); - - DBG1(DBG_IKE, "peer didn't accept DH group %N, it requested" - " %N", diffie_hellman_group_names, old_dh_group, - diffie_hellman_group_names, this->dh_group); - if (!this->connection->check_dh_group(this->connection, - this->dh_group)) - { - DBG1(DBG_IKE, "requested DH group %N not acceptable, " - "giving up", diffie_hellman_group_names, - this->dh_group); - iterator->destroy(iterator); - return FAILED; + DBG1(DBG_IKE, "peer didn't accept DH group %N, " + "it requested %N", diffie_hellman_group_names, + bad_group, diffie_hellman_group_names, this->dh_group); + + if (this->old_sa == NULL) + { /* reset the IKE_SA if we are not rekeying */ + this->ike_sa->reset(this->ike_sa); } - this->ike_sa->reset(this->ike_sa); - iterator->destroy(iterator); return NEED_MORE; } @@ -470,9 +449,9 @@ static status_t process_i(private_ike_init_t *this, message_t *message) return FAILED; } - if (this->diffie_hellman == NULL || - this->diffie_hellman->get_shared_secret(this->diffie_hellman, - &secret) != SUCCESS) + if (this->dh == NULL || + !this->proposal->has_dh_group(this->proposal, this->dh_group) || + this->dh->get_shared_secret(this->dh, &secret) != SUCCESS) { SIG(IKE_UP_FAILED, "peers DH group selection invalid"); return FAILED; @@ -539,12 +518,12 @@ static chunk_t get_lower_nonce(private_ike_init_t *this) static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa) { DESTROY_IF(this->proposal); - DESTROY_IF(this->diffie_hellman); + DESTROY_IF(this->dh); chunk_free(&this->other_nonce); this->ike_sa = ike_sa; this->proposal = NULL; - this->diffie_hellman = diffie_hellman_create(this->dh_group); + this->dh = diffie_hellman_create(this->dh_group); } /** @@ -553,7 +532,7 @@ static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa) static void destroy(private_ike_init_t *this) { DESTROY_IF(this->proposal); - DESTROY_IF(this->diffie_hellman); + DESTROY_IF(this->dh); chunk_free(&this->my_nonce); chunk_free(&this->other_nonce); chunk_free(&this->cookie); @@ -585,12 +564,12 @@ ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa) this->ike_sa = ike_sa; this->initiator = initiator; this->dh_group = MODP_NONE; - this->diffie_hellman = NULL; + this->dh = NULL; this->my_nonce = chunk_empty; this->other_nonce = chunk_empty; this->cookie = chunk_empty; this->proposal = NULL; - this->connection = NULL; + this->config = NULL; this->old_sa = old_sa; this->retry = 0; diff --git a/src/charon/sa/tasks/ike_rekey.c b/src/charon/sa/tasks/ike_rekey.c index a33e7ee34..d54fc3524 100644 --- a/src/charon/sa/tasks/ike_rekey.c +++ b/src/charon/sa/tasks/ike_rekey.c @@ -26,8 +26,8 @@ #include <daemon.h> #include <encoding/payloads/notify_payload.h> #include <sa/tasks/ike_init.h> -#include <queues/jobs/delete_ike_sa_job.h> -#include <queues/jobs/rekey_ike_sa_job.h> +#include <processing/jobs/delete_ike_sa_job.h> +#include <processing/jobs/rekey_ike_sa_job.h> typedef struct private_ike_rekey_t private_ike_rekey_t; @@ -73,21 +73,20 @@ struct private_ike_rekey_t { */ static status_t build_i(private_ike_rekey_t *this, message_t *message) { - connection_t *connection; - policy_t *policy; + peer_cfg_t *peer_cfg; - this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, - TRUE); - - connection = this->ike_sa->get_connection(this->ike_sa); - policy = this->ike_sa->get_policy(this->ike_sa); - this->new_sa->set_connection(this->new_sa, connection); - this->new_sa->set_policy(this->new_sa, policy); - - this->ike_init = ike_init_create(this->new_sa, TRUE, this->ike_sa); + /* create new SA only on first try */ + if (this->new_sa == NULL) + { + this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, + TRUE); + + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + this->new_sa->set_peer_cfg(this->new_sa, peer_cfg); + this->ike_init = ike_init_create(this->new_sa, TRUE, this->ike_sa); + this->ike_sa->set_state(this->ike_sa, IKE_REKEYING); + } this->ike_init->task.build(&this->ike_init->task, message); - - this->ike_sa->set_state(this->ike_sa, IKE_REKEYING); return NEED_MORE; } @@ -97,8 +96,7 @@ static status_t build_i(private_ike_rekey_t *this, message_t *message) */ static status_t process_r(private_ike_rekey_t *this, message_t *message) { - connection_t *connection; - policy_t *policy; + peer_cfg_t *peer_cfg; iterator_t *iterator; child_sa_t *child_sa; @@ -129,11 +127,8 @@ static status_t process_r(private_ike_rekey_t *this, message_t *message) this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, FALSE); - connection = this->ike_sa->get_connection(this->ike_sa); - policy = this->ike_sa->get_policy(this->ike_sa); - this->new_sa->set_connection(this->new_sa, connection); - this->new_sa->set_policy(this->new_sa, policy); - + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + this->new_sa->set_peer_cfg(this->new_sa, peer_cfg); this->ike_init = ike_init_create(this->new_sa, FALSE, this->ike_sa); this->ike_init->task.process(&this->ike_init->task, message); @@ -171,23 +166,29 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message) job_t *job; ike_sa_id_t *to_delete; - if (this->ike_init->task.process(&this->ike_init->task, message) == FAILED) + switch (this->ike_init->task.process(&this->ike_init->task, message)) { - /* rekeying failed, fallback to old SA */ - if (!(this->collision && - this->collision->get_type(this->collision) == IKE_DELETE)) - { - job_t *job; - u_int32_t retry = charon->configuration->get_retry_interval( - charon->configuration); - job = (job_t*)rekey_ike_sa_job_create( - this->ike_sa->get_id(this->ike_sa), FALSE); - DBG1(DBG_IKE, "IKE_SA rekeying failed, " - "trying again in %d seconds", retry); - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - charon->event_queue->add_relative(charon->event_queue, job, retry * 1000); - } - return SUCCESS; + case FAILED: + /* rekeying failed, fallback to old SA */ + if (!(this->collision && + this->collision->get_type(this->collision) == IKE_DELETE)) + { + job_t *job; + u_int32_t retry = RETRY_INTERVAL - (random() % RETRY_JITTER); + job = (job_t*)rekey_ike_sa_job_create( + this->ike_sa->get_id(this->ike_sa), FALSE); + DBG1(DBG_IKE, "IKE_SA rekeying failed, " + "trying again in %d seconds", retry); + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + charon->event_queue->add_relative(charon->event_queue, job, retry * 1000); + } + return SUCCESS; + case NEED_MORE: + /* bad dh group, try again */ + this->ike_init->task.migrate(&this->ike_init->task, this->new_sa); + return NEED_MORE; + default: + break; } this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED); |