diff options
Diffstat (limited to 'src/libcharon/sa')
-rw-r--r-- | src/libcharon/sa/child_sa.c | 41 | ||||
-rw-r--r-- | src/libcharon/sa/ike_sa.c | 19 | ||||
-rw-r--r-- | src/libcharon/sa/ikev1/keymat_v1.c | 25 | ||||
-rw-r--r-- | src/libcharon/sa/ikev1/task_manager_v1.c | 17 | ||||
-rw-r--r-- | src/libcharon/sa/ikev1/tasks/isakmp_vendor.c | 3 | ||||
-rw-r--r-- | src/libcharon/sa/ikev1/tasks/quick_mode.c | 40 | ||||
-rw-r--r-- | src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c | 4 | ||||
-rw-r--r-- | src/libcharon/sa/ikev2/keymat_v2.c | 56 | ||||
-rw-r--r-- | src/libcharon/sa/ikev2/task_manager_v2.c | 25 | ||||
-rw-r--r-- | src/libcharon/sa/ikev2/tasks/child_create.c | 69 | ||||
-rw-r--r-- | src/libcharon/sa/ikev2/tasks/ike_init.c | 8 |
11 files changed, 185 insertions, 122 deletions
diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index 8a405d93c..e4364de12 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -111,12 +111,17 @@ struct private_child_sa_t { */ bool static_reqid; - /* + /** * Unique CHILD_SA identifier */ uint32_t unique_id; /** + * Whether FWD policieis in the outbound direction should be installed + */ + bool policies_fwd_out; + + /** * inbound mark used for this child_sa */ mark_t mark_in; @@ -931,15 +936,19 @@ static status_t install_policies_internal(private_child_sa_t *this, * policies of two SAs we install them with reduced priority. As they * basically act as bypass policies for drop policies we use a higher * priority than is used for them. */ - out_id.dir = POLICY_FWD; - other_sa->reqid = 0; - if (priority == POLICY_PRIORITY_DEFAULT) + if (this->policies_fwd_out) { - out_policy.prio = POLICY_PRIORITY_ROUTED; + out_id.dir = POLICY_FWD; + other_sa->reqid = 0; + if (priority == POLICY_PRIORITY_DEFAULT) + { + out_policy.prio = POLICY_PRIORITY_ROUTED; + } + status |= charon->kernel->add_policy(charon->kernel, &out_id, + &out_policy); + /* reset the reqid for any other further policies */ + other_sa->reqid = this->reqid; } - status |= charon->kernel->add_policy(charon->kernel, &out_id, &out_policy); - /* reset the reqid for any other further policies */ - other_sa->reqid = this->reqid; } return status; } @@ -988,14 +997,17 @@ static void del_policies_internal(private_child_sa_t *this, in_id.dir = POLICY_FWD; charon->kernel->del_policy(charon->kernel, &in_id, &in_policy); - out_id.dir = POLICY_FWD; - other_sa->reqid = 0; - if (priority == POLICY_PRIORITY_DEFAULT) + if (this->policies_fwd_out) { - out_policy.prio = POLICY_PRIORITY_ROUTED; + out_id.dir = POLICY_FWD; + other_sa->reqid = 0; + if (priority == POLICY_PRIORITY_DEFAULT) + { + out_policy.prio = POLICY_PRIORITY_ROUTED; + } + charon->kernel->del_policy(charon->kernel, &out_id, &out_policy); + other_sa->reqid = this->reqid; } - charon->kernel->del_policy(charon->kernel, &out_id, &out_policy); - other_sa->reqid = this->reqid; } } @@ -1443,6 +1455,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other, .mark_in = config->get_mark(config, TRUE), .mark_out = config->get_mark(config, FALSE), .install_time = time_monotonic(NULL), + .policies_fwd_out = config->install_fwd_out_policy(config), ); this->config = config; diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 009277ddd..7b87918d3 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -921,6 +921,7 @@ METHOD(ike_sa_t, reset, void, this->ike_sa_id->is_initiator(this->ike_sa_id)); this->task_manager->reset(this->task_manager, 0, 0); + this->task_manager->queue_ike(this->task_manager); } METHOD(ike_sa_t, get_keymat, keymat_t*, @@ -1780,16 +1781,12 @@ METHOD(ike_sa_t, delete_, status_t, { switch (this->state) { - case IKE_REKEYING: - if (this->version == IKEV1) - { /* SA has been reauthenticated, delete */ - charon->bus->ike_updown(charon->bus, &this->public, FALSE); - break; - } - /* FALL */ case IKE_ESTABLISHED: - if (time_monotonic(NULL) >= this->stats[STAT_DELETE]) - { /* IKE_SA hard lifetime hit */ + case IKE_REKEYING: + if (time_monotonic(NULL) >= this->stats[STAT_DELETE] && + !(this->version == IKEV1 && this->state == IKE_REKEYING)) + { /* IKE_SA hard lifetime hit, ignored for reauthenticated + * IKEv1 SAs */ charon->bus->alert(charon->bus, ALERT_IKE_SA_EXPIRED); } this->task_manager->queue_ike_delete(this->task_manager); @@ -1831,7 +1828,6 @@ METHOD(ike_sa_t, reauth, status_t, DBG0(DBG_IKE, "reinitiating IKE_SA %s[%d]", get_name(this), this->unique_id); reset(this); - this->task_manager->queue_ike(this->task_manager); return this->task_manager->initiate(this->task_manager); } /* we can't reauthenticate as responder when we use EAP or virtual IPs. @@ -2335,7 +2331,6 @@ METHOD(ike_sa_t, retransmit, status_t, this->keyingtry + 1, tries); reset(this); resolve_hosts(this); - this->task_manager->queue_ike(this->task_manager); return this->task_manager->initiate(this->task_manager); } DBG1(DBG_IKE, "establishing IKE_SA failed, peer not responding"); @@ -2980,7 +2975,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, .flush_auth_cfg = lib->settings->get_bool(lib->settings, "%s.flush_auth_cfg", FALSE, lib->ns), .fragment_size = lib->settings->get_int(lib->settings, - "%s.fragment_size", 0, lib->ns), + "%s.fragment_size", 1280, lib->ns), .follow_redirects = lib->settings->get_bool(lib->settings, "%s.follow_redirects", TRUE, lib->ns), ); diff --git a/src/libcharon/sa/ikev1/keymat_v1.c b/src/libcharon/sa/ikev1/keymat_v1.c index be6b03bef..d1d4cbd9b 100644 --- a/src/libcharon/sa/ikev1/keymat_v1.c +++ b/src/libcharon/sa/ikev1/keymat_v1.c @@ -75,11 +75,6 @@ struct private_keymat_v1_t { hasher_t *hasher; /** - * Key used for authentication during main mode - */ - chunk_t skeyid; - - /** * Key to derive key material from for non-ISAKMP SAs, rekeying */ chunk_t skeyid_d; @@ -269,12 +264,12 @@ static bool expand_skeyid_e(chunk_t skeyid_e, size_t key_size, prf_t *prf, * Create a simple implementation of the aead_t interface which only encrypts * or decrypts data. */ -static aead_t *create_aead(proposal_t *proposal, prf_t *prf, chunk_t skeyid_e) +static aead_t *create_aead(proposal_t *proposal, prf_t *prf, chunk_t skeyid_e, + chunk_t *ka) { private_aead_t *this; uint16_t alg, key_size; crypter_t *crypter; - chunk_t ka; if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &key_size)) @@ -292,17 +287,16 @@ static aead_t *create_aead(proposal_t *proposal, prf_t *prf, chunk_t skeyid_e) return NULL; } key_size = crypter->get_key_size(crypter); - if (!expand_skeyid_e(skeyid_e, crypter->get_key_size(crypter), prf, &ka)) + if (!expand_skeyid_e(skeyid_e, crypter->get_key_size(crypter), prf, ka)) { return NULL; } - DBG4(DBG_IKE, "encryption key Ka %B", &ka); - if (!crypter->set_key(crypter, ka)) + DBG4(DBG_IKE, "encryption key Ka %B", ka); + if (!crypter->set_key(crypter, *ka)) { - chunk_clear(&ka); + chunk_clear(ka); return NULL; } - chunk_clear(&ka); INIT(this, .aead = { @@ -392,7 +386,7 @@ METHOD(keymat_v1_t, derive_ike_keys, bool, auth_method_t auth, shared_key_t *shared_key) { chunk_t g_xy, g_xi, g_xr, dh_me, spi_i, spi_r, nonces, data, skeyid_e; - chunk_t skeyid; + chunk_t skeyid, ka; uint16_t alg; spi_i = chunk_alloca(sizeof(uint64_t)); @@ -550,11 +544,14 @@ METHOD(keymat_v1_t, derive_ike_keys, bool, } chunk_clear(&skeyid); - this->aead = create_aead(proposal, this->prf, skeyid_e); + this->aead = create_aead(proposal, this->prf, skeyid_e, &ka); if (!this->aead) { return FALSE; } + charon->bus->ike_derived_keys(charon->bus, ka, chunk_empty, this->skeyid_a, + chunk_empty); + chunk_clear(&ka); if (!this->hasher && !this->public.create_hasher(&this->public, proposal)) { return FALSE; diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index b0c4f5f84..3b0c1cfd1 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -515,13 +515,13 @@ METHOD(task_manager_t, initiate, status_t, new_mid = TRUE; break; } - if (activate_task(this, TASK_ISAKMP_DELETE)) + if (activate_task(this, TASK_QUICK_DELETE)) { exchange = INFORMATIONAL_V1; new_mid = TRUE; break; } - if (activate_task(this, TASK_QUICK_DELETE)) + if (activate_task(this, TASK_ISAKMP_DELETE)) { exchange = INFORMATIONAL_V1; new_mid = TRUE; @@ -547,6 +547,14 @@ METHOD(task_manager_t, initiate, status_t, break; } break; + case IKE_REKEYING: + if (activate_task(this, TASK_ISAKMP_DELETE)) + { + exchange = INFORMATIONAL_V1; + new_mid = TRUE; + break; + } + break; default: break; } @@ -1181,7 +1189,7 @@ static status_t process_response(private_task_manager_t *this, } enumerator->destroy(enumerator); - if (this->initiating.retransmitted) + if (this->initiating.retransmitted > 1) { packet_t *packet = NULL; array_get(this->initiating.packets, 0, &packet); @@ -1661,6 +1669,9 @@ METHOD(task_manager_t, queue_ike_delete, void, enumerator_t *enumerator; child_sa_t *child_sa; + /* cancel any currently active task to get the DELETE done quickly */ + flush_queue(this, TASK_QUEUE_ACTIVE); + enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa); while (enumerator->enumerate(enumerator, &child_sa)) { diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c b/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c index f28b83e8a..dc86fc504 100644 --- a/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c +++ b/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c @@ -102,6 +102,7 @@ static struct { { "DPD", EXT_DPD, TRUE, 16, "\xaf\xca\xd7\x13\x68\xa1\xf1\xc9\x6b\x86\x96\xfc\x77\x57\x01\x00"}, + /* CISCO-UNITY, similar to DPD the last two bytes indicate the version */ { "Cisco Unity", EXT_CISCO_UNITY, FALSE, 16, "\x12\xf5\xf2\x8c\x45\x71\x68\xa9\x70\x2d\x9f\xe2\x74\xcc\x01\x00"}, @@ -190,6 +191,8 @@ static bool is_known_vid(chunk_t data, int i) break; case EXT_MS_WINDOWS: return data.len == 20 && memeq(data.ptr, vendor_ids[i].id, 16); + case EXT_CISCO_UNITY: + return data.len == 16 && memeq(data.ptr, vendor_ids[i].id, 14); default: return chunk_equals(data, chunk_create(vendor_ids[i].id, vendor_ids[i].len)); diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index bbd1cb09f..6b896416a 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -348,10 +348,6 @@ static bool install(private_quick_mode_t *this) this->initiator, FALSE, FALSE, tsr, tsi); } } - chunk_clear(&integ_i); - chunk_clear(&integ_r); - chunk_clear(&encr_i); - chunk_clear(&encr_r); if (status_i != SUCCESS || status_o != SUCCESS) { @@ -361,22 +357,38 @@ static bool install(private_quick_mode_t *this) (status_o != SUCCESS) ? "outbound " : ""); tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy)); tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy)); - return FALSE; - } - - if (this->initiator) - { - status = this->child_sa->add_policies(this->child_sa, tsi, tsr); + status = FAILED; } else { - status = this->child_sa->add_policies(this->child_sa, tsr, tsi); + if (this->initiator) + { + status = this->child_sa->add_policies(this->child_sa, tsi, tsr); + } + else + { + status = this->child_sa->add_policies(this->child_sa, tsr, tsi); + } + tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy)); + tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy)); + if (status != SUCCESS) + { + DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel"); + } + else + { + charon->bus->child_derived_keys(charon->bus, this->child_sa, + this->initiator, encr_i, encr_r, + integ_i, integ_r); + } } - tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy)); - tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy)); + chunk_clear(&integ_i); + chunk_clear(&integ_r); + chunk_clear(&encr_i); + chunk_clear(&encr_r); + if (status != SUCCESS) { - DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel"); return FALSE; } diff --git a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c index 6fd34e0a6..592f49770 100644 --- a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c +++ b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c @@ -161,8 +161,8 @@ static array_t *select_signature_schemes(keymat_v2_t *keymat, if (key_type == KEY_RSA) { signature_scheme_t schemes[] = { - SIGN_RSA_EMSA_PKCS1_SHA384, - SIGN_RSA_EMSA_PKCS1_SHA256, + SIGN_RSA_EMSA_PKCS1_SHA2_384, + SIGN_RSA_EMSA_PKCS1_SHA2_256, SIGN_RSA_EMSA_PKCS1_SHA1, }, contained; bool found; diff --git a/src/libcharon/sa/ikev2/keymat_v2.c b/src/libcharon/sa/ikev2/keymat_v2.c index e37399841..58efdbabe 100644 --- a/src/libcharon/sa/ikev2/keymat_v2.c +++ b/src/libcharon/sa/ikev2/keymat_v2.c @@ -103,7 +103,7 @@ static bool derive_ike_aead(private_keymat_v2_t *this, uint16_t alg, uint16_t key_size, prf_plus_t *prf_plus) { aead_t *aead_i, *aead_r; - chunk_t key = chunk_empty; + chunk_t sk_ei = chunk_empty, sk_er = chunk_empty; u_int salt_size; switch (alg) @@ -146,23 +146,22 @@ static bool derive_ike_aead(private_keymat_v2_t *this, uint16_t alg, { goto failure; } - if (!prf_plus->allocate_bytes(prf_plus, key_size, &key)) + if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_ei)) { goto failure; } - DBG4(DBG_IKE, "Sk_ei secret %B", &key); - if (!aead_i->set_key(aead_i, key)) + DBG4(DBG_IKE, "Sk_ei secret %B", &sk_ei); + if (!aead_i->set_key(aead_i, sk_ei)) { goto failure; } - chunk_clear(&key); - if (!prf_plus->allocate_bytes(prf_plus, key_size, &key)) + if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_er)) { goto failure; } - DBG4(DBG_IKE, "Sk_er secret %B", &key); - if (!aead_r->set_key(aead_r, key)) + DBG4(DBG_IKE, "Sk_er secret %B", &sk_er); + if (!aead_r->set_key(aead_r, sk_er)) { goto failure; } @@ -178,11 +177,14 @@ static bool derive_ike_aead(private_keymat_v2_t *this, uint16_t alg, this->aead_out = aead_r; } aead_i = aead_r = NULL; + charon->bus->ike_derived_keys(charon->bus, sk_ei, sk_er, chunk_empty, + chunk_empty); failure: DESTROY_IF(aead_i); DESTROY_IF(aead_r); - chunk_clear(&key); + chunk_clear(&sk_ei); + chunk_clear(&sk_er); return this->aead_in && this->aead_out; } @@ -196,7 +198,8 @@ static bool derive_ike_traditional(private_keymat_v2_t *this, uint16_t enc_alg, signer_t *signer_i, *signer_r; iv_gen_t *ivg_i, *ivg_r; size_t key_size; - chunk_t key = chunk_empty; + chunk_t sk_ei = chunk_empty, sk_er = chunk_empty, + sk_ai = chunk_empty, sk_ar = chunk_empty; signer_i = lib->crypto->create_signer(lib->crypto, int_alg); signer_r = lib->crypto->create_signer(lib->crypto, int_alg); @@ -220,48 +223,45 @@ static bool derive_ike_traditional(private_keymat_v2_t *this, uint16_t enc_alg, /* SK_ai/SK_ar used for integrity protection */ key_size = signer_i->get_key_size(signer_i); - if (!prf_plus->allocate_bytes(prf_plus, key_size, &key)) + if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_ai)) { goto failure; } - DBG4(DBG_IKE, "Sk_ai secret %B", &key); - if (!signer_i->set_key(signer_i, key)) + DBG4(DBG_IKE, "Sk_ai secret %B", &sk_ai); + if (!signer_i->set_key(signer_i, sk_ai)) { goto failure; } - chunk_clear(&key); - if (!prf_plus->allocate_bytes(prf_plus, key_size, &key)) + if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_ar)) { goto failure; } - DBG4(DBG_IKE, "Sk_ar secret %B", &key); - if (!signer_r->set_key(signer_r, key)) + DBG4(DBG_IKE, "Sk_ar secret %B", &sk_ar); + if (!signer_r->set_key(signer_r, sk_ar)) { goto failure; } - chunk_clear(&key); /* SK_ei/SK_er used for encryption */ key_size = crypter_i->get_key_size(crypter_i); - if (!prf_plus->allocate_bytes(prf_plus, key_size, &key)) + if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_ei)) { goto failure; } - DBG4(DBG_IKE, "Sk_ei secret %B", &key); - if (!crypter_i->set_key(crypter_i, key)) + DBG4(DBG_IKE, "Sk_ei secret %B", &sk_ei); + if (!crypter_i->set_key(crypter_i, sk_ei)) { goto failure; } - chunk_clear(&key); - if (!prf_plus->allocate_bytes(prf_plus, key_size, &key)) + if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_er)) { goto failure; } - DBG4(DBG_IKE, "Sk_er secret %B", &key); - if (!crypter_r->set_key(crypter_r, key)) + DBG4(DBG_IKE, "Sk_er secret %B", &sk_er); + if (!crypter_r->set_key(crypter_r, sk_er)) { goto failure; } @@ -284,9 +284,13 @@ static bool derive_ike_traditional(private_keymat_v2_t *this, uint16_t enc_alg, } signer_i = signer_r = NULL; crypter_i = crypter_r = NULL; + charon->bus->ike_derived_keys(charon->bus, sk_ei, sk_er, sk_ai, sk_ar); failure: - chunk_clear(&key); + chunk_clear(&sk_ai); + chunk_clear(&sk_ar); + chunk_clear(&sk_ei); + chunk_clear(&sk_er); DESTROY_IF(signer_i); DESTROY_IF(signer_r); DESTROY_IF(crypter_i); diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index 41a4e1b75..60a262ffc 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -709,7 +709,7 @@ static status_t process_response(private_task_manager_t *this, } enumerator->destroy(enumerator); - if (this->initiating.retransmitted) + if (this->initiating.retransmitted > 1) { packet_t *packet = NULL; array_get(this->initiating.packets, 0, &packet); @@ -1827,15 +1827,22 @@ METHOD(task_manager_t, queue_dpd, void, if (this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE) && this->ike_sa->has_condition(this->ike_sa, COND_NAT_HERE)) { - /* use mobike enabled DPD to detect NAT mapping changes */ - mobike = ike_mobike_create(this->ike_sa, TRUE); - mobike->dpd(mobike); - queue_task(this, &mobike->task); - } - else - { - queue_task(this, (task_t*)ike_dpd_create(TRUE)); +#ifdef ME + peer_cfg_t *cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (cfg->get_peer_id(cfg) || + this->ike_sa->has_condition(this->ike_sa, COND_ORIGINAL_INITIATOR)) +#else + if (this->ike_sa->has_condition(this->ike_sa, COND_ORIGINAL_INITIATOR)) +#endif + { + /* use mobike enabled DPD to detect NAT mapping changes */ + mobike = ike_mobike_create(this->ike_sa, TRUE); + mobike->dpd(mobike); + queue_task(this, &mobike->task); + return; + } } + queue_task(this, (task_t*)ike_dpd_create(TRUE)); } METHOD(task_manager_t, adopt_tasks, void, diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c index 64a82850b..71cb6b8ea 100644 --- a/src/libcharon/sa/ikev2/tasks/child_create.c +++ b/src/libcharon/sa/ikev2/tasks/child_create.c @@ -666,10 +666,6 @@ static status_t select_and_install(private_child_create_t *this, FALSE, this->tfcv3, my_ts, other_ts); } } - chunk_clear(&integ_i); - chunk_clear(&integ_r); - chunk_clear(&encr_i); - chunk_clear(&encr_r); if (status_i != SUCCESS || status_o != SUCCESS) { @@ -679,41 +675,62 @@ static status_t select_and_install(private_child_create_t *this, (status_o != SUCCESS) ? "outbound " : ""); charon->bus->alert(charon->bus, ALERT_INSTALL_CHILD_SA_FAILED, this->child_sa); - return FAILED; - } - - if (this->initiator) - { - status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts); + status = FAILED; } else { - /* use a copy of the traffic selectors, as the POST hook should not - * change payloads */ - my_ts = this->tsr->clone_offset(this->tsr, + if (this->initiator) + { + status = this->child_sa->add_policies(this->child_sa, + my_ts, other_ts); + } + else + { + /* use a copy of the traffic selectors, as the POST hook should not + * change payloads */ + my_ts = this->tsr->clone_offset(this->tsr, offsetof(traffic_selector_t, clone)); - other_ts = this->tsi->clone_offset(this->tsi, + other_ts = this->tsi->clone_offset(this->tsi, offsetof(traffic_selector_t, clone)); - charon->bus->narrow(charon->bus, this->child_sa, - NARROW_RESPONDER_POST, my_ts, other_ts); - if (my_ts->get_count(my_ts) == 0 || other_ts->get_count(other_ts) == 0) + charon->bus->narrow(charon->bus, this->child_sa, + NARROW_RESPONDER_POST, my_ts, other_ts); + if (my_ts->get_count(my_ts) == 0 || + other_ts->get_count(other_ts) == 0) + { + status = FAILED; + } + else + { + status = this->child_sa->add_policies(this->child_sa, + my_ts, other_ts); + } + my_ts->destroy_offset(my_ts, + offsetof(traffic_selector_t, destroy)); + other_ts->destroy_offset(other_ts, + offsetof(traffic_selector_t, destroy)); + } + if (status != SUCCESS) { - status = FAILED; + DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel"); + charon->bus->alert(charon->bus, ALERT_INSTALL_CHILD_POLICY_FAILED, + this->child_sa); + status = NOT_FOUND; } else { - status = this->child_sa->add_policies(this->child_sa, - my_ts, other_ts); + charon->bus->child_derived_keys(charon->bus, this->child_sa, + this->initiator, encr_i, encr_r, + integ_i, integ_r); } - my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); - other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy)); } + chunk_clear(&integ_i); + chunk_clear(&integ_r); + chunk_clear(&encr_i); + chunk_clear(&encr_r); + if (status != SUCCESS) { - DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel"); - charon->bus->alert(charon->bus, ALERT_INSTALL_CHILD_POLICY_FAILED, - this->child_sa); - return NOT_FOUND; + return status; } charon->bus->child_keys(charon->bus, this->child_sa, this->initiator, diff --git a/src/libcharon/sa/ikev2/tasks/ike_init.c b/src/libcharon/sa/ikev2/tasks/ike_init.c index 801b6d8f3..d82e206b8 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_init.c +++ b/src/libcharon/sa/ikev2/tasks/ike_init.c @@ -457,6 +457,11 @@ static void process_payloads(private_ike_init_t *this, message_t *message) } enumerator->destroy(enumerator); + if (this->proposal) + { + this->ike_sa->set_proposal(this->ike_sa, this->proposal); + } + if (ke_payload && this->proposal && this->proposal->has_dh_group(this->proposal, this->dh_group)) { @@ -614,7 +619,6 @@ METHOD(task_t, build_r, status_t, message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); return FAILED; } - this->ike_sa->set_proposal(this->ike_sa, this->proposal); /* check if we'd have to redirect the client */ if (!this->old_sa && @@ -651,6 +655,7 @@ METHOD(task_t, build_r, status_t, else { DBG1(DBG_IKE, "no acceptable proposal found"); + message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty); } return FAILED; } @@ -849,7 +854,6 @@ METHOD(task_t, process_i, status_t, DBG1(DBG_IKE, "peers proposal selection invalid"); return FAILED; } - this->ike_sa->set_proposal(this->ike_sa, this->proposal); if (this->dh == NULL || !this->proposal->has_dh_group(this->proposal, this->dh_group)) |