diff options
Diffstat (limited to 'src/libcharon/sa')
24 files changed, 779 insertions, 558 deletions
diff --git a/src/libcharon/sa/authenticators/authenticator.c b/src/libcharon/sa/authenticators/authenticator.c index cd340e53e..83f5fbaad 100644 --- a/src/libcharon/sa/authenticators/authenticator.c +++ b/src/libcharon/sa/authenticators/authenticator.c @@ -39,7 +39,8 @@ ENUM_END(auth_method_names, AUTH_ECDSA_521); */ authenticator_t *authenticator_create_builder(ike_sa_t *ike_sa, auth_cfg_t *cfg, chunk_t received_nonce, chunk_t sent_nonce, - chunk_t received_init, chunk_t sent_init) + chunk_t received_init, chunk_t sent_init, + char reserved[3]) { switch ((uintptr_t)cfg->get(cfg, AUTH_RULE_AUTH_CLASS)) { @@ -47,13 +48,14 @@ authenticator_t *authenticator_create_builder(ike_sa_t *ike_sa, auth_cfg_t *cfg, /* defaults to PUBKEY */ case AUTH_CLASS_PUBKEY: return (authenticator_t*)pubkey_authenticator_create_builder(ike_sa, - received_nonce, sent_init); + received_nonce, sent_init, reserved); case AUTH_CLASS_PSK: return (authenticator_t*)psk_authenticator_create_builder(ike_sa, - received_nonce, sent_init); + received_nonce, sent_init, reserved); case AUTH_CLASS_EAP: return (authenticator_t*)eap_authenticator_create_builder(ike_sa, - received_nonce, sent_nonce, received_init, sent_init); + received_nonce, sent_nonce, + received_init, sent_init, reserved); default: return NULL; } @@ -65,7 +67,8 @@ authenticator_t *authenticator_create_builder(ike_sa_t *ike_sa, auth_cfg_t *cfg, authenticator_t *authenticator_create_verifier( ike_sa_t *ike_sa, message_t *message, chunk_t received_nonce, chunk_t sent_nonce, - chunk_t received_init, chunk_t sent_init) + chunk_t received_init, chunk_t sent_init, + char reserved[3]) { auth_payload_t *auth_payload; @@ -73,7 +76,8 @@ authenticator_t *authenticator_create_verifier( if (auth_payload == NULL) { return (authenticator_t*)eap_authenticator_create_verifier(ike_sa, - received_nonce, sent_nonce, received_init, sent_init); + received_nonce, sent_nonce, + received_init, sent_init, reserved); } switch (auth_payload->get_auth_method(auth_payload)) { @@ -82,10 +86,10 @@ authenticator_t *authenticator_create_verifier( case AUTH_ECDSA_384: case AUTH_ECDSA_521: return (authenticator_t*)pubkey_authenticator_create_verifier(ike_sa, - sent_nonce, received_init); + sent_nonce, received_init, reserved); case AUTH_PSK: return (authenticator_t*)psk_authenticator_create_verifier(ike_sa, - sent_nonce, received_init); + sent_nonce, received_init, reserved); default: return NULL; } diff --git a/src/libcharon/sa/authenticators/authenticator.h b/src/libcharon/sa/authenticators/authenticator.h index 89178b5cf..d27e006a3 100644 --- a/src/libcharon/sa/authenticators/authenticator.h +++ b/src/libcharon/sa/authenticators/authenticator.h @@ -130,12 +130,14 @@ struct authenticator_t { * @param sent_nonce nonce sent in IKE_SA_INIT * @param received_init received IKE_SA_INIT message data * @param sent_init sent IKE_SA_INIT message data + * @param reserved reserved bytes of the ID payload * @return authenticator, NULL if not supported */ authenticator_t *authenticator_create_builder( ike_sa_t *ike_sa, auth_cfg_t *cfg, chunk_t received_nonce, chunk_t sent_nonce, - chunk_t received_init, chunk_t sent_init); + chunk_t received_init, chunk_t sent_init, + char reserved[3]); /** * Create an authenticator to verify signatures. @@ -146,11 +148,13 @@ authenticator_t *authenticator_create_builder( * @param sent_nonce nonce sent in IKE_SA_INIT * @param received_init received IKE_SA_INIT message data * @param sent_init sent IKE_SA_INIT message data + * @param reserved reserved bytes of the ID payload * @return authenticator, NULL if not supported */ authenticator_t *authenticator_create_verifier( ike_sa_t *ike_sa, message_t *message, chunk_t received_nonce, chunk_t sent_nonce, - chunk_t received_init, chunk_t sent_init); + chunk_t received_init, chunk_t sent_init, + char reserved[3]); #endif /** AUTHENTICATOR_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/eap_authenticator.c b/src/libcharon/sa/authenticators/eap_authenticator.c index 8b22fd1d7..dea02755d 100644 --- a/src/libcharon/sa/authenticators/eap_authenticator.c +++ b/src/libcharon/sa/authenticators/eap_authenticator.c @@ -58,6 +58,11 @@ struct private_eap_authenticator_t { chunk_t sent_init; /** + * Reserved bytes of ID payload + */ + char reserved[3]; + + /** * Current EAP method processing */ eap_method_t *method; @@ -422,7 +427,7 @@ static bool verify_auth(private_eap_authenticator_t *this, message_t *message, other_id = this->ike_sa->get_other_id(this->ike_sa); keymat = this->ike_sa->get_keymat(this->ike_sa); auth_data = keymat->get_psk_sig(keymat, TRUE, init, nonce, - this->msk, other_id); + this->msk, other_id, this->reserved); recv_auth_data = auth_payload->get_data(auth_payload); if (!auth_data.len || !chunk_equals(auth_data, recv_auth_data)) { @@ -458,7 +463,8 @@ static void build_auth(private_eap_authenticator_t *this, message_t *message, DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N", my_id, auth_class_names, AUTH_CLASS_EAP); - auth_data = keymat->get_psk_sig(keymat, FALSE, init, nonce, this->msk, my_id); + auth_data = keymat->get_psk_sig(keymat, FALSE, init, nonce, + this->msk, my_id, this->reserved); auth_payload = auth_payload_create(); auth_payload->set_auth_method(auth_payload, AUTH_PSK); auth_payload->set_data(auth_payload, auth_data); @@ -642,7 +648,8 @@ METHOD(authenticator_t, destroy, void, */ eap_authenticator_t *eap_authenticator_create_builder(ike_sa_t *ike_sa, chunk_t received_nonce, chunk_t sent_nonce, - chunk_t received_init, chunk_t sent_init) + chunk_t received_init, chunk_t sent_init, + char reserved[3]) { private_eap_authenticator_t *this; @@ -661,6 +668,7 @@ eap_authenticator_t *eap_authenticator_create_builder(ike_sa_t *ike_sa, .sent_init = sent_init, .sent_nonce = sent_nonce, ); + memcpy(this->reserved, reserved, sizeof(this->reserved)); return &this->public; } @@ -670,7 +678,8 @@ eap_authenticator_t *eap_authenticator_create_builder(ike_sa_t *ike_sa, */ eap_authenticator_t *eap_authenticator_create_verifier(ike_sa_t *ike_sa, chunk_t received_nonce, chunk_t sent_nonce, - chunk_t received_init, chunk_t sent_init) + chunk_t received_init, chunk_t sent_init, + char reserved[3]) { private_eap_authenticator_t *this; @@ -689,6 +698,7 @@ eap_authenticator_t *eap_authenticator_create_verifier(ike_sa_t *ike_sa, .sent_init = sent_init, .sent_nonce = sent_nonce, ); + memcpy(this->reserved, reserved, sizeof(this->reserved)); return &this->public; } diff --git a/src/libcharon/sa/authenticators/eap_authenticator.h b/src/libcharon/sa/authenticators/eap_authenticator.h index 41eb6a8c9..726411a18 100644 --- a/src/libcharon/sa/authenticators/eap_authenticator.h +++ b/src/libcharon/sa/authenticators/eap_authenticator.h @@ -75,11 +75,13 @@ struct eap_authenticator_t { * @param sent_nonce nonce sent in IKE_SA_INIT * @param received_init received IKE_SA_INIT message data * @param sent_init sent IKE_SA_INIT message data + * @param reserved reserved bytes of ID payload * @return EAP authenticator */ eap_authenticator_t *eap_authenticator_create_builder(ike_sa_t *ike_sa, chunk_t received_nonce, chunk_t sent_nonce, - chunk_t received_init, chunk_t sent_init); + chunk_t received_init, chunk_t sent_init, + char reserved[3]); /** * Create an authenticator to authenticate EAP clients. @@ -89,10 +91,12 @@ eap_authenticator_t *eap_authenticator_create_builder(ike_sa_t *ike_sa, * @param sent_nonce nonce sent in IKE_SA_INIT * @param received_init received IKE_SA_INIT message data * @param sent_init sent IKE_SA_INIT message data + * @param reserved reserved bytes of ID payload * @return EAP authenticator */ eap_authenticator_t *eap_authenticator_create_verifier(ike_sa_t *ike_sa, chunk_t received_nonce, chunk_t sent_nonce, - chunk_t received_init, chunk_t sent_init); + chunk_t received_init, chunk_t sent_init, + char reserved[3]); #endif /** EAP_AUTHENTICATOR_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/psk_authenticator.c b/src/libcharon/sa/authenticators/psk_authenticator.c index e69f30dcf..21fc0f9b8 100644 --- a/src/libcharon/sa/authenticators/psk_authenticator.c +++ b/src/libcharon/sa/authenticators/psk_authenticator.c @@ -45,12 +45,15 @@ struct private_psk_authenticator_t { * IKE_SA_INIT message data to include in AUTH calculation */ chunk_t ike_sa_init; + + /** + * Reserved bytes of ID payload + */ + char reserved[3]; }; -/* - * Implementation of authenticator_t.build for builder - */ -static status_t build(private_psk_authenticator_t *this, message_t *message) +METHOD(authenticator_t, build, status_t, + private_psk_authenticator_t *this, message_t *message) { identification_t *my_id, *other_id; auth_payload_t *auth_payload; @@ -70,7 +73,7 @@ static status_t build(private_psk_authenticator_t *this, message_t *message) return NOT_FOUND; } auth_data = keymat->get_psk_sig(keymat, FALSE, this->ike_sa_init, - this->nonce, key->get_key(key), my_id); + this->nonce, key->get_key(key), my_id, this->reserved); key->destroy(key); DBG2(DBG_IKE, "successfully created shared key MAC"); auth_payload = auth_payload_create(); @@ -82,10 +85,8 @@ static status_t build(private_psk_authenticator_t *this, message_t *message) return SUCCESS; } -/** - * Implementation of authenticator_t.process for verifier - */ -static status_t process(private_psk_authenticator_t *this, message_t *message) +METHOD(authenticator_t, process, status_t, + private_psk_authenticator_t *this, message_t *message) { chunk_t auth_data, recv_auth_data; identification_t *my_id, *other_id; @@ -113,7 +114,7 @@ static status_t process(private_psk_authenticator_t *this, message_t *message) keys_found++; auth_data = keymat->get_psk_sig(keymat, TRUE, this->ike_sa_init, - this->nonce, key->get_key(key), other_id); + this->nonce, key->get_key(key), other_id, this->reserved); if (auth_data.len && chunk_equals(auth_data, recv_auth_data)) { DBG1(DBG_IKE, "authentication of '%Y' with %N successful", @@ -141,19 +142,8 @@ static status_t process(private_psk_authenticator_t *this, message_t *message) return SUCCESS; } -/** - * Implementation of authenticator_t.process for builder - * Implementation of authenticator_t.build for verifier - */ -static status_t return_failed() -{ - return FAILED; -} - -/** - * Implementation of authenticator_t.destroy. - */ -static void destroy(private_psk_authenticator_t *this) +METHOD(authenticator_t, destroy, void, + private_psk_authenticator_t *this) { free(this); } @@ -162,18 +152,25 @@ static void destroy(private_psk_authenticator_t *this) * Described in header. */ psk_authenticator_t *psk_authenticator_create_builder(ike_sa_t *ike_sa, - chunk_t received_nonce, chunk_t sent_init) + chunk_t received_nonce, chunk_t sent_init, + char reserved[3]) { - private_psk_authenticator_t *this = malloc_thing(private_psk_authenticator_t); - - this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *message))build; - this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))return_failed; - this->public.authenticator.is_mutual = (bool(*)(authenticator_t*))return_false; - this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy; - - this->ike_sa = ike_sa; - this->ike_sa_init = sent_init; - this->nonce = received_nonce; + private_psk_authenticator_t *this; + + INIT(this, + .public = { + .authenticator = { + .build = _build, + .process = (void*)return_failed, + .is_mutual = (void*)return_false, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .ike_sa_init = sent_init, + .nonce = received_nonce, + ); + memcpy(this->reserved, reserved, sizeof(this->reserved)); return &this->public; } @@ -182,18 +179,25 @@ psk_authenticator_t *psk_authenticator_create_builder(ike_sa_t *ike_sa, * Described in header. */ psk_authenticator_t *psk_authenticator_create_verifier(ike_sa_t *ike_sa, - chunk_t sent_nonce, chunk_t received_init) + chunk_t sent_nonce, chunk_t received_init, + char reserved[3]) { - private_psk_authenticator_t *this = malloc_thing(private_psk_authenticator_t); - - this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *messageh))return_failed; - this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))process; - this->public.authenticator.is_mutual = (bool(*)(authenticator_t*))return_false; - this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy; - - this->ike_sa = ike_sa; - this->ike_sa_init = received_init; - this->nonce = sent_nonce; + private_psk_authenticator_t *this; + + INIT(this, + .public = { + .authenticator = { + .build = (void*)return_failed, + .process = _process, + .is_mutual = (void*)return_false, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .ike_sa_init = received_init, + .nonce = sent_nonce, + ); + memcpy(this->reserved, reserved, sizeof(this->reserved)); return &this->public; } diff --git a/src/libcharon/sa/authenticators/psk_authenticator.h b/src/libcharon/sa/authenticators/psk_authenticator.h index 0fab11095..8cf1a0f98 100644 --- a/src/libcharon/sa/authenticators/psk_authenticator.h +++ b/src/libcharon/sa/authenticators/psk_authenticator.h @@ -42,10 +42,12 @@ struct psk_authenticator_t { * @param ike_sa associated ike_sa * @param received_nonce nonce received in IKE_SA_INIT * @param sent_init sent IKE_SA_INIT message data + * @param reserved reserved bytes of ID payload * @return PSK authenticator */ psk_authenticator_t *psk_authenticator_create_builder(ike_sa_t *ike_sa, - chunk_t received_nonce, chunk_t sent_init); + chunk_t received_nonce, chunk_t sent_init, + char reserved[3]); /** * Create an authenticator to verify PSK signatures. @@ -53,9 +55,11 @@ psk_authenticator_t *psk_authenticator_create_builder(ike_sa_t *ike_sa, * @param ike_sa associated ike_sa * @param sent_nonce nonce sent in IKE_SA_INIT * @param received_init received IKE_SA_INIT message data + * @param reserved reserved bytes of ID payload * @return PSK authenticator */ psk_authenticator_t *psk_authenticator_create_verifier(ike_sa_t *ike_sa, - chunk_t sent_nonce, chunk_t received_init); + chunk_t sent_nonce, chunk_t received_init, + char reserved[3]); #endif /** PSK_AUTHENTICATOR_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/pubkey_authenticator.c b/src/libcharon/sa/authenticators/pubkey_authenticator.c index 54b4338bb..247891670 100644 --- a/src/libcharon/sa/authenticators/pubkey_authenticator.c +++ b/src/libcharon/sa/authenticators/pubkey_authenticator.c @@ -46,12 +46,15 @@ struct private_pubkey_authenticator_t { * IKE_SA_INIT message data to include in AUTH calculation */ chunk_t ike_sa_init; + + /** + * Reserved bytes of ID payload + */ + char reserved[3]; }; -/** - * Implementation of authenticator_t.build for builder - */ -static status_t build(private_pubkey_authenticator_t *this, message_t *message) +METHOD(authenticator_t, build, status_t, + private_pubkey_authenticator_t *this, message_t *message) { chunk_t octets, auth_data; status_t status = FAILED; @@ -109,7 +112,7 @@ static status_t build(private_pubkey_authenticator_t *this, message_t *message) } keymat = this->ike_sa->get_keymat(this->ike_sa); octets = keymat->get_auth_octets(keymat, FALSE, this->ike_sa_init, - this->nonce, id); + this->nonce, id, this->reserved); if (private->sign(private, scheme, octets, &auth_data)) { auth_payload = auth_payload_create(); @@ -128,10 +131,8 @@ static status_t build(private_pubkey_authenticator_t *this, message_t *message) return status; } -/** - * Implementation of authenticator_t.process for verifier - */ -static status_t process(private_pubkey_authenticator_t *this, message_t *message) +METHOD(authenticator_t, process, status_t, + private_pubkey_authenticator_t *this, message_t *message) { public_key_t *public; auth_method_t auth_method; @@ -175,7 +176,7 @@ static status_t process(private_pubkey_authenticator_t *this, message_t *message id = this->ike_sa->get_other_id(this->ike_sa); keymat = this->ike_sa->get_keymat(this->ike_sa); octets = keymat->get_auth_octets(keymat, TRUE, this->ike_sa_init, - this->nonce, id); + this->nonce, id, this->reserved); auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); enumerator = lib->credmgr->create_public_enumerator(lib->credmgr, key_type, id, auth); @@ -206,19 +207,8 @@ static status_t process(private_pubkey_authenticator_t *this, message_t *message return status; } -/** - * Implementation of authenticator_t.process for builder - * Implementation of authenticator_t.build for verifier - */ -static status_t return_failed() -{ - return FAILED; -} - -/** - * Implementation of authenticator_t.destroy. - */ -static void destroy(private_pubkey_authenticator_t *this) +METHOD(authenticator_t, destroy, void, + private_pubkey_authenticator_t *this) { free(this); } @@ -227,18 +217,25 @@ static void destroy(private_pubkey_authenticator_t *this) * Described in header. */ pubkey_authenticator_t *pubkey_authenticator_create_builder(ike_sa_t *ike_sa, - chunk_t received_nonce, chunk_t sent_init) + chunk_t received_nonce, chunk_t sent_init, + char reserved[3]) { - private_pubkey_authenticator_t *this = malloc_thing(private_pubkey_authenticator_t); + private_pubkey_authenticator_t *this; - this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *message))build; - this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))return_failed; - this->public.authenticator.is_mutual = (bool(*)(authenticator_t*))return_false; - this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy; - - this->ike_sa = ike_sa; - this->ike_sa_init = sent_init; - this->nonce = received_nonce; + INIT(this, + .public = { + .authenticator = { + .build = _build, + .process = (void*)return_failed, + .is_mutual = (void*)return_false, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .ike_sa_init = sent_init, + .nonce = received_nonce, + ); + memcpy(this->reserved, reserved, sizeof(this->reserved)); return &this->public; } @@ -247,18 +244,25 @@ pubkey_authenticator_t *pubkey_authenticator_create_builder(ike_sa_t *ike_sa, * Described in header. */ pubkey_authenticator_t *pubkey_authenticator_create_verifier(ike_sa_t *ike_sa, - chunk_t sent_nonce, chunk_t received_init) + chunk_t sent_nonce, chunk_t received_init, + char reserved[3]) { - private_pubkey_authenticator_t *this = malloc_thing(private_pubkey_authenticator_t); - - this->public.authenticator.build = (status_t(*)(authenticator_t*, message_t *message))return_failed; - this->public.authenticator.process = (status_t(*)(authenticator_t*, message_t *message))process; - this->public.authenticator.is_mutual = (bool(*)(authenticator_t*))return_false; - this->public.authenticator.destroy = (void(*)(authenticator_t*))destroy; + private_pubkey_authenticator_t *this; - this->ike_sa = ike_sa; - this->ike_sa_init = received_init; - this->nonce = sent_nonce; + INIT(this, + .public = { + .authenticator = { + .build = (void*)return_failed, + .process = _process, + .is_mutual = (void*)return_false, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .ike_sa_init = received_init, + .nonce = sent_nonce, + ); + memcpy(this->reserved, reserved, sizeof(this->reserved)); return &this->public; } diff --git a/src/libcharon/sa/authenticators/pubkey_authenticator.h b/src/libcharon/sa/authenticators/pubkey_authenticator.h index be369cb89..4c3937ecc 100644 --- a/src/libcharon/sa/authenticators/pubkey_authenticator.h +++ b/src/libcharon/sa/authenticators/pubkey_authenticator.h @@ -43,10 +43,12 @@ struct pubkey_authenticator_t { * @param ike_sa associated ike_sa * @param received_nonce nonce received in IKE_SA_INIT * @param sent_init sent IKE_SA_INIT message data + * @param reserved reserved bytes of ID payload * @return public key authenticator */ pubkey_authenticator_t *pubkey_authenticator_create_builder(ike_sa_t *ike_sa, - chunk_t received_nonce, chunk_t sent_init); + chunk_t received_nonce, chunk_t sent_init, + char reserved[3]); /** * Create an authenticator to verify public key signatures. @@ -54,9 +56,11 @@ pubkey_authenticator_t *pubkey_authenticator_create_builder(ike_sa_t *ike_sa, * @param ike_sa associated ike_sa * @param sent_nonce nonce sent in IKE_SA_INIT * @param received_init received IKE_SA_INIT message data + * @param reserved reserved bytes of ID payload * @return public key authenticator */ pubkey_authenticator_t *pubkey_authenticator_create_verifier(ike_sa_t *ike_sa, - chunk_t sent_nonce, chunk_t received_init); + chunk_t sent_nonce, chunk_t received_init, + char reserved[3]); #endif /** PUBKEY_AUTHENTICATOR_H_ @}*/ diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index b6ef31da0..495929965 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -559,13 +559,14 @@ METHOD(child_sa_t, alloc_cpi, u_int16_t, METHOD(child_sa_t, install, status_t, private_child_sa_t *this, chunk_t encr, chunk_t integ, u_int32_t spi, - u_int16_t cpi, bool inbound, linked_list_t *my_ts, + u_int16_t cpi, bool inbound, bool tfcv3, linked_list_t *my_ts, linked_list_t *other_ts) { u_int16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size; traffic_selector_t *src_ts = NULL, *dst_ts = NULL; time_t now; lifetime_cfg_t *lifetime; + u_int32_t tfc = 0; host_t *src, *dst; status_t status; bool update = FALSE; @@ -590,6 +591,11 @@ METHOD(child_sa_t, install, status_t, dst = this->other_addr; this->other_spi = spi; this->other_cpi = cpi; + + if (tfcv3) + { + tfc = this->config->get_tfc(this->config); + } } DBG2(DBG_CHD, "adding %s %N SA", inbound ? "inbound" : "outbound", @@ -620,7 +626,7 @@ METHOD(child_sa_t, install, status_t, lifetime->time.rekey = 0; } - if (this->mode == MODE_BEET) + if (this->mode == MODE_BEET || this->mode == MODE_TRANSPORT) { /* BEET requires the bound address from the traffic selectors. * TODO: We add just the first traffic selector for now, as the @@ -639,7 +645,7 @@ METHOD(child_sa_t, install, status_t, status = hydra->kernel_interface->add_sa(hydra->kernel_interface, src, dst, spi, proto_ike2ip(this->protocol), this->reqid, - inbound ? this->mark_in : this->mark_out, + inbound ? this->mark_in : this->mark_out, tfc, lifetime, enc_alg, encr, int_alg, integ, this->mode, this->ipcomp, cpi, this->encap, update, src_ts, dst_ts); diff --git a/src/libcharon/sa/child_sa.h b/src/libcharon/sa/child_sa.h index 95bc297b0..f17ef01ac 100644 --- a/src/libcharon/sa/child_sa.h +++ b/src/libcharon/sa/child_sa.h @@ -313,12 +313,13 @@ struct child_sa_t { * @param spi SPI to use, allocated for inbound * @param cpi CPI to use, allocated for outbound * @param inbound TRUE to install an inbound SA, FALSE for outbound + * @param tfcv3 TRUE if peer supports ESPv3 TFC * @param my_ts negotiated local traffic selector list * @param other_ts negotiated remote traffic selector list * @return SUCCESS or FAILED */ status_t (*install)(child_sa_t *this, chunk_t encr, chunk_t integ, - u_int32_t spi, u_int16_t cpi, bool inbound, + u_int32_t spi, u_int16_t cpi, bool inbound, bool tfcv3, linked_list_t *my_ts, linked_list_t *other_ts); /** * Install the policies using some traffic selectors. diff --git a/src/libcharon/sa/connect_manager.c b/src/libcharon/sa/connect_manager.c index 1fb286863..972cc98ad 100644 --- a/src/libcharon/sa/connect_manager.c +++ b/src/libcharon/sa/connect_manager.c @@ -1194,7 +1194,10 @@ static job_requeue_t initiate_mediated(initiate_data_t *data) DBG1(DBG_IKE, "establishing mediated connection failed"); charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, sa); } - charon->ike_sa_manager->checkin(charon->ike_sa_manager, sa); + else + { + charon->ike_sa_manager->checkin(charon->ike_sa_manager, sa); + } } iterator->destroy(iterator); } diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index a4e4028ab..9b6f9d06d 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -50,6 +50,7 @@ #include <processing/jobs/send_dpd_job.h> #include <processing/jobs/send_keepalive_job.h> #include <processing/jobs/rekey_ike_sa_job.h> +#include <encoding/payloads/unknown_payload.h> #ifdef ME #include <sa/tasks/ike_me.h> @@ -559,13 +560,6 @@ METHOD(ike_sa_t, send_dpd, status_t, time_t diff, delay; delay = this->peer_cfg->get_dpd(this->peer_cfg); - - if (delay == 0) - { - /* DPD disabled */ - return SUCCESS; - } - if (this->task_manager->busy(this->task_manager)) { /* an exchange is in the air, no need to start a DPD check */ @@ -578,7 +572,7 @@ METHOD(ike_sa_t, send_dpd, status_t, last_in = get_use_time(this, TRUE); now = time_monotonic(NULL); diff = now - last_in; - if (diff >= delay) + if (!delay || diff >= delay) { /* to long ago, initiate dead peer detection */ task_t *task; @@ -604,8 +598,11 @@ METHOD(ike_sa_t, send_dpd, status_t, } } /* recheck in "interval" seconds */ - job = (job_t*)send_dpd_job_create(this->ike_sa_id); - lib->scheduler->schedule_job(lib->scheduler, job, delay - diff); + if (delay) + { + job = (job_t*)send_dpd_job_create(this->ike_sa_id); + lib->scheduler->schedule_job(lib->scheduler, job, delay - diff); + } return SUCCESS; } @@ -680,7 +677,10 @@ METHOD(ike_sa_t, set_state, void, } /* start DPD checks */ - send_dpd(this); + if (this->peer_cfg->get_dpd(this->peer_cfg)) + { + send_dpd(this); + } } break; } @@ -825,7 +825,7 @@ METHOD(ike_sa_t, float_ports, void, } METHOD(ike_sa_t, update_hosts, void, - private_ike_sa_t *this, host_t *me, host_t *other) + private_ike_sa_t *this, host_t *me, host_t *other, bool force) { bool update = FALSE; @@ -858,7 +858,7 @@ METHOD(ike_sa_t, update_hosts, void, if (!other->equals(other, this->other_host)) { /* update others adress if we are NOT NATed */ - if (!has_condition(this, COND_NAT_HERE)) + if (force || !has_condition(this, COND_NAT_HERE)) { set_other_host(this, other->clone(other)); update = TRUE; @@ -891,8 +891,14 @@ METHOD(ike_sa_t, update_hosts, void, METHOD(ike_sa_t, generate_message, status_t, private_ike_sa_t *this, message_t *message, packet_t **packet) { + if (message->is_encoded(message)) + { /* already done */ + *packet = message->get_packet(message); + return SUCCESS; + } this->stats[STAT_OUTBOUND] = time_monotonic(NULL); message->set_ike_sa_id(message, this->ike_sa_id); + charon->bus->message(charon->bus, message, FALSE); return message->generate(message, this->keymat->get_aead(this->keymat, FALSE), packet); } @@ -901,7 +907,7 @@ METHOD(ike_sa_t, generate_message, status_t, * send a notify back to the sender */ static void send_notify_response(private_ike_sa_t *this, message_t *request, - notify_type_t type) + notify_type_t type, chunk_t data) { message_t *response; packet_t *packet; @@ -910,7 +916,7 @@ static void send_notify_response(private_ike_sa_t *this, message_t *request, response->set_exchange_type(response, request->get_exchange_type(request)); response->set_request(response, FALSE); response->set_message_id(response, request->get_message_id(request)); - response->add_notify(response, FALSE, type, chunk_empty); + response->add_notify(response, FALSE, type, data); if (this->my_host->is_anyaddr(this->my_host)) { this->my_host->destroy(this->my_host); @@ -1175,6 +1181,7 @@ METHOD(ike_sa_t, process_message, status_t, { status_t status; bool is_request; + u_int8_t type = 0; if (this->state == IKE_PASSIVE) { /* do not handle messages in passive state */ @@ -1185,9 +1192,29 @@ METHOD(ike_sa_t, process_message, status_t, status = message->parse_body(message, this->keymat->get_aead(this->keymat, TRUE)); + if (status == SUCCESS) + { /* check for unsupported critical payloads */ + enumerator_t *enumerator; + unknown_payload_t *unknown; + payload_t *payload; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + unknown = (unknown_payload_t*)payload; + type = payload->get_type(payload); + if (!payload_is_known(type) && + unknown->is_critical(unknown)) + { + DBG1(DBG_ENC, "payload type %N is not supported, " + "but its critical!", payload_type_names, type); + status = NOT_SUPPORTED; + } + } + enumerator->destroy(enumerator); + } if (status != SUCCESS) { - if (is_request) { switch (status) @@ -1196,21 +1223,28 @@ METHOD(ike_sa_t, process_message, status_t, DBG1(DBG_IKE, "critical unknown payloads found"); if (is_request) { - send_notify_response(this, message, UNSUPPORTED_CRITICAL_PAYLOAD); + send_notify_response(this, message, + UNSUPPORTED_CRITICAL_PAYLOAD, + chunk_from_thing(type)); + this->task_manager->incr_mid(this->task_manager, FALSE); } break; case PARSE_ERROR: DBG1(DBG_IKE, "message parsing failed"); if (is_request) { - send_notify_response(this, message, INVALID_SYNTAX); + send_notify_response(this, message, + INVALID_SYNTAX, chunk_empty); + this->task_manager->incr_mid(this->task_manager, FALSE); } break; case VERIFY_ERROR: DBG1(DBG_IKE, "message verification failed"); if (is_request) { - send_notify_response(this, message, INVALID_SYNTAX); + send_notify_response(this, message, + INVALID_SYNTAX, chunk_empty); + this->task_manager->incr_mid(this->task_manager, FALSE); } break; case FAILED: @@ -1219,10 +1253,6 @@ METHOD(ike_sa_t, process_message, status_t, break; case INVALID_STATE: DBG1(DBG_IKE, "found encrypted message, but no keys available"); - if (is_request) - { - send_notify_response(this, message, INVALID_SYNTAX); - } default: break; } @@ -1252,7 +1282,8 @@ METHOD(ike_sa_t, process_message, status_t, /* no config found for these hosts, destroy */ DBG1(DBG_IKE, "no IKE config found for %H...%H, sending %N", me, other, notify_type_names, NO_PROPOSAL_CHOSEN); - send_notify_response(this, message, NO_PROPOSAL_CHOSEN); + send_notify_response(this, message, + NO_PROPOSAL_CHOSEN, chunk_empty); return DESTROY_ME; } /* add a timeout if peer does not establish it completely */ diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index c0007e27d..988100bcc 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -343,8 +343,9 @@ struct ike_sa_t { * * @param me new local host address, or NULL * @param other new remote host address, or NULL + * @param force force update */ - void (*update_hosts)(ike_sa_t *this, host_t *me, host_t *other); + void (*update_hosts)(ike_sa_t *this, host_t *me, host_t *other, bool force); /** * Get the own identification. diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index fa94bb86d..d695c7f7c 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -1,6 +1,7 @@ /* + * Copyright (C) 2005-2011 Martin Willi + * Copyright (C) 2011 revosec AG * Copyright (C) 2008 Tobias Brunner - * Copyright (C) 2005-2008 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -85,7 +86,9 @@ struct entry_t { chunk_t init_hash; /** - * remote host address, required for DoS detection + * remote host address, required for DoS detection and duplicate + * checking (host with same my_id and other_id is *not* considered + * a duplicate if the address family differs) */ host_t *other; @@ -241,6 +244,9 @@ struct connected_peers_t { /** remote identity */ identification_t *other_id; + /** ip address family of peer */ + int family; + /** list of ike_sa_id_t objects of IKE_SAs between the two identities */ linked_list_t *sas; }; @@ -257,10 +263,12 @@ static void connected_peers_destroy(connected_peers_t *this) * Function that matches connected_peers_t objects by the given ids. */ static bool connected_peers_match(connected_peers_t *connected_peers, - identification_t *my_id, identification_t *other_id) + identification_t *my_id, identification_t *other_id, + uintptr_t family) { return my_id->equals(my_id, connected_peers->my_id) && - other_id->equals(other_id, connected_peers->other_id); + other_id->equals(other_id, connected_peers->other_id) && + family == connected_peers->family; } typedef struct segment_t segment_t; @@ -396,7 +404,7 @@ static void lock_all_segments(private_ike_sa_manager_t *this) { u_int i; - for (i = 0; i < this->segment_count; ++i) + for (i = 0; i < this->segment_count; i++) { this->segments[i].mutex->lock(this->segments[i].mutex); } @@ -409,7 +417,7 @@ static void unlock_all_segments(private_ike_sa_manager_t *this) { u_int i; - for (i = 0; i < this->segment_count; ++i) + for (i = 0; i < this->segment_count; i++) { this->segments[i].mutex->unlock(this->segments[i].mutex); } @@ -453,10 +461,8 @@ struct private_enumerator_t { enumerator_t *current; }; -/** - * Implementation of private_enumerator_t.enumerator.enumerate. - */ -static bool enumerate(private_enumerator_t *this, entry_t **entry, u_int *segment) +METHOD(enumerator_t, enumerate, bool, + private_enumerator_t *this, entry_t **entry, u_int *segment) { if (this->entry) { @@ -502,10 +508,8 @@ static bool enumerate(private_enumerator_t *this, entry_t **entry, u_int *segmen return FALSE; } -/** - * Implementation of private_enumerator_t.enumerator.destroy. - */ -static void enumerator_destroy(private_enumerator_t *this) +METHOD(enumerator_t, enumerator_destroy, void, + private_enumerator_t *this) { if (this->entry) { @@ -524,16 +528,15 @@ static void enumerator_destroy(private_enumerator_t *this) */ static enumerator_t* create_table_enumerator(private_ike_sa_manager_t *this) { - private_enumerator_t *enumerator = malloc_thing(private_enumerator_t); - - enumerator->enumerator.enumerate = (void*)enumerate; - enumerator->enumerator.destroy = (void*)enumerator_destroy; - enumerator->manager = this; - enumerator->segment = 0; - enumerator->entry = NULL; - enumerator->row = 0; - enumerator->current = NULL; - + private_enumerator_t *enumerator; + + INIT(enumerator, + .enumerator = { + .enumerate = (void*)_enumerate, + .destroy = _enumerator_destroy, + }, + .manager = this, + ); return &enumerator->enumerator; } @@ -544,11 +547,14 @@ static enumerator_t* create_table_enumerator(private_ike_sa_manager_t *this) static u_int put_entry(private_ike_sa_manager_t *this, entry_t *entry) { linked_list_t *list; - u_int row = ike_sa_id_hash(entry->ike_sa_id) & this->table_mask; - u_int segment = row & this->segment_mask; + u_int row, segment; + + row = ike_sa_id_hash(entry->ike_sa_id) & this->table_mask; + segment = row & this->segment_mask; lock_single_segment(this, segment); - if ((list = this->ike_sa_table[row]) == NULL) + list = this->ike_sa_table[row]; + if (!list) { list = this->ike_sa_table[row] = linked_list_create(); } @@ -564,14 +570,17 @@ static u_int put_entry(private_ike_sa_manager_t *this, entry_t *entry) static void remove_entry(private_ike_sa_manager_t *this, entry_t *entry) { linked_list_t *list; - u_int row = ike_sa_id_hash(entry->ike_sa_id) & this->table_mask; - u_int segment = row & this->segment_mask; + u_int row, segment; - if ((list = this->ike_sa_table[row]) != NULL) + row = ike_sa_id_hash(entry->ike_sa_id) & this->table_mask; + segment = row & this->segment_mask; + list = this->ike_sa_table[row]; + if (list) { entry_t *current; + enumerator_t *enumerator; - enumerator_t *enumerator = list->create_enumerator(list); + enumerator = list->create_enumerator(list); while (enumerator->enumerate(enumerator, ¤t)) { if (current == entry) @@ -609,11 +618,14 @@ static status_t get_entry_by_match_function(private_ike_sa_manager_t *this, { entry_t *current; linked_list_t *list; - u_int row = ike_sa_id_hash(ike_sa_id) & this->table_mask; - u_int seg = row & this->segment_mask; + u_int row, seg; + + row = ike_sa_id_hash(ike_sa_id) & this->table_mask; + seg = row & this->segment_mask; lock_single_segment(this, seg); - if ((list = this->ike_sa_table[row]) != NULL) + list = this->ike_sa_table[row]; + if (list) { if (list->find_first(list, match, (void**)¤t, p1, p2) == SUCCESS) { @@ -697,19 +709,20 @@ static void put_half_open(private_ike_sa_manager_t *this, entry_t *entry) { half_open_t *half_open = NULL; linked_list_t *list; - chunk_t addr = entry->other->get_address(entry->other); - u_int row = chunk_hash(addr) & this->table_mask; - u_int segment = row & this->segment_mask; + chunk_t addr; + u_int row, segment; + rwlock_t *lock; - rwlock_t *lock = this->half_open_segments[segment].lock; + addr = entry->other->get_address(entry->other); + row = chunk_hash(addr) & this->table_mask; + segment = row & this->segment_mask; + lock = this->half_open_segments[segment].lock; lock->write_lock(lock); - if ((list = this->half_open_table[row]) == NULL) - { - list = this->half_open_table[row] = linked_list_create(); - } - else + list = this->half_open_table[row]; + if (list) { half_open_t *current; + if (list->find_first(list, (linked_list_match_t)half_open_match, (void**)¤t, &addr) == SUCCESS) { @@ -718,12 +731,17 @@ static void put_half_open(private_ike_sa_manager_t *this, entry_t *entry) this->half_open_segments[segment].count++; } } + else + { + list = this->half_open_table[row] = linked_list_create(); + } if (!half_open) { - half_open = malloc_thing(half_open_t); - half_open->other = chunk_clone(addr); - half_open->count = 1; + INIT(half_open, + .other = chunk_clone(addr), + .count = 1, + ); list->insert_last(list, half_open); this->half_open_segments[segment].count++; } @@ -736,16 +754,22 @@ static void put_half_open(private_ike_sa_manager_t *this, entry_t *entry) static void remove_half_open(private_ike_sa_manager_t *this, entry_t *entry) { linked_list_t *list; - chunk_t addr = entry->other->get_address(entry->other); - u_int row = chunk_hash(addr) & this->table_mask; - u_int segment = row & this->segment_mask; + chunk_t addr; + u_int row, segment; + rwlock_t *lock; - rwlock_t *lock = this->half_open_segments[segment].lock; + addr = entry->other->get_address(entry->other); + row = chunk_hash(addr) & this->table_mask; + segment = row & this->segment_mask; + lock = this->half_open_segments[segment].lock; lock->write_lock(lock); - if ((list = this->half_open_table[row]) != NULL) + list = this->half_open_table[row]; + if (list) { half_open_t *current; - enumerator_t *enumerator = list->create_enumerator(list); + enumerator_t *enumerator; + + enumerator = list->create_enumerator(list); while (enumerator->enumerate(enumerator, ¤t)) { if (half_open_match(current, &addr)) @@ -769,24 +793,26 @@ static void remove_half_open(private_ike_sa_manager_t *this, entry_t *entry) */ static void put_connected_peers(private_ike_sa_manager_t *this, entry_t *entry) { - linked_list_t *list; connected_peers_t *connected_peers = NULL; - chunk_t my_id = entry->my_id->get_encoding(entry->my_id), - other_id = entry->other_id->get_encoding(entry->other_id); - u_int row = chunk_hash_inc(other_id, chunk_hash(my_id)) & this->table_mask; - u_int segment = row & this->segment_mask; + chunk_t my_id, other_id; + linked_list_t *list; + u_int row, segment; + rwlock_t *lock; - rwlock_t *lock = this->connected_peers_segments[segment].lock; + my_id = entry->my_id->get_encoding(entry->my_id); + other_id = entry->other_id->get_encoding(entry->other_id); + row = chunk_hash_inc(other_id, chunk_hash(my_id)) & this->table_mask; + segment = row & this->segment_mask; + lock = this->connected_peers_segments[segment].lock; lock->write_lock(lock); - if ((list = this->connected_peers_table[row]) == NULL) - { - list = this->connected_peers_table[row] = linked_list_create(); - } - else + list = this->connected_peers_table[row]; + if (list) { connected_peers_t *current; + if (list->find_first(list, (linked_list_match_t)connected_peers_match, - (void**)¤t, entry->my_id, entry->other_id) == SUCCESS) + (void**)¤t, entry->my_id, entry->other_id, + (uintptr_t)entry->other->get_family(entry->other)) == SUCCESS) { connected_peers = current; if (connected_peers->sas->find_first(connected_peers->sas, @@ -798,13 +824,19 @@ static void put_connected_peers(private_ike_sa_manager_t *this, entry_t *entry) } } } + else + { + list = this->connected_peers_table[row] = linked_list_create(); + } if (!connected_peers) { - connected_peers = malloc_thing(connected_peers_t); - connected_peers->my_id = entry->my_id->clone(entry->my_id); - connected_peers->other_id = entry->other_id->clone(entry->other_id); - connected_peers->sas = linked_list_create(); + INIT(connected_peers, + .my_id = entry->my_id->clone(entry->my_id), + .other_id = entry->other_id->clone(entry->other_id), + .family = entry->other->get_family(entry->other), + .sas = linked_list_create(), + ); list->insert_last(list, connected_peers); } connected_peers->sas->insert_last(connected_peers->sas, @@ -818,24 +850,34 @@ static void put_connected_peers(private_ike_sa_manager_t *this, entry_t *entry) */ static void remove_connected_peers(private_ike_sa_manager_t *this, entry_t *entry) { + chunk_t my_id, other_id; linked_list_t *list; - chunk_t my_id = entry->my_id->get_encoding(entry->my_id), - other_id = entry->other_id->get_encoding(entry->other_id); - u_int row = chunk_hash_inc(other_id, chunk_hash(my_id)) & this->table_mask; - u_int segment = row & this->segment_mask; + u_int row, segment; + rwlock_t *lock; + + my_id = entry->my_id->get_encoding(entry->my_id); + other_id = entry->other_id->get_encoding(entry->other_id); + row = chunk_hash_inc(other_id, chunk_hash(my_id)) & this->table_mask; + segment = row & this->segment_mask; - rwlock_t *lock = this->connected_peers_segments[segment].lock; + lock = this->connected_peers_segments[segment].lock; lock->write_lock(lock); - if ((list = this->connected_peers_table[row]) != NULL) + list = this->connected_peers_table[row]; + if (list) { connected_peers_t *current; - enumerator_t *enumerator = list->create_enumerator(list); + enumerator_t *enumerator; + + enumerator = list->create_enumerator(list); while (enumerator->enumerate(enumerator, ¤t)) { - if (connected_peers_match(current, entry->my_id, entry->other_id)) + if (connected_peers_match(current, entry->my_id, entry->other_id, + (uintptr_t)entry->other->get_family(entry->other))) { ike_sa_id_t *ike_sa_id; - enumerator_t *inner = current->sas->create_enumerator(current->sas); + enumerator_t *inner; + + inner = current->sas->create_enumerator(current->sas); while (inner->enumerate(inner, &ike_sa_id)) { if (ike_sa_id->equals(ike_sa_id, entry->ike_sa_id)) @@ -861,20 +903,21 @@ static void remove_connected_peers(private_ike_sa_manager_t *this, entry_t *entr } /** - * Implementation of private_ike_sa_manager_t.get_next_spi. + * Get a random SPI for new IKE_SAs */ -static u_int64_t get_next_spi(private_ike_sa_manager_t *this) +static u_int64_t get_spi(private_ike_sa_manager_t *this) { - u_int64_t spi; + u_int64_t spi = 0; - this->rng->get_bytes(this->rng, sizeof(spi), (u_int8_t*)&spi); + if (this->rng) + { + this->rng->get_bytes(this->rng, sizeof(spi), (u_int8_t*)&spi); + } return spi; } -/** - * Implementation of of ike_sa_manager.checkout. - */ -static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id) +METHOD(ike_sa_manager_t, checkout, ike_sa_t*, + private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id) { ike_sa_t *ike_sa = NULL; entry_t *entry; @@ -897,62 +940,46 @@ static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id return ike_sa; } -/** - * Implementation of of ike_sa_manager.checkout_new. - */ -static ike_sa_t *checkout_new(private_ike_sa_manager_t* this, bool initiator) +METHOD(ike_sa_manager_t, checkout_new, ike_sa_t*, + private_ike_sa_manager_t* this, bool initiator) { ike_sa_id_t *ike_sa_id; ike_sa_t *ike_sa; - entry_t *entry; - u_int segment; if (initiator) { - ike_sa_id = ike_sa_id_create(get_next_spi(this), 0, TRUE); + ike_sa_id = ike_sa_id_create(get_spi(this), 0, TRUE); } else { - ike_sa_id = ike_sa_id_create(0, get_next_spi(this), FALSE); + ike_sa_id = ike_sa_id_create(0, get_spi(this), FALSE); } ike_sa = ike_sa_create(ike_sa_id); + ike_sa_id->destroy(ike_sa_id); DBG2(DBG_MGR, "created IKE_SA %s[%u]", ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa)); - if (!initiator) - { - ike_sa_id->destroy(ike_sa_id); - return ike_sa; - } - - entry = entry_create(); - entry->ike_sa_id = ike_sa_id; - entry->ike_sa = ike_sa; - segment = put_entry(this, entry); - entry->checked_out = TRUE; - unlock_single_segment(this, segment); - return entry->ike_sa; + return ike_sa; } -/** - * Implementation of of ike_sa_manager.checkout_by_message. - */ -static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this, - message_t *message) +METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, + private_ike_sa_manager_t* this, message_t *message) { u_int segment; entry_t *entry; ike_sa_t *ike_sa = NULL; - ike_sa_id_t *id = message->get_ike_sa_id(message); + ike_sa_id_t *id; + id = message->get_ike_sa_id(message); id = id->clone(id); id->switch_initiator(id); DBG2(DBG_MGR, "checkout IKE_SA by message"); if (message->get_request(message) && - message->get_exchange_type(message) == IKE_SA_INIT) + message->get_exchange_type(message) == IKE_SA_INIT && + this->hasher) { /* IKE_SA_INIT request. Check for an IKE_SA with such a message hash. */ chunk_t data, hash; @@ -988,7 +1015,7 @@ static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this, message->get_exchange_type(message) == IKE_SA_INIT) { /* no IKE_SA found, create a new one */ - id->set_responder_spi(id, get_next_spi(this)); + id->set_responder_spi(id, get_spi(this)); entry = entry_create(); entry->ike_sa = ike_sa_create(id); entry->ike_sa_id = id->clone(id); @@ -1048,11 +1075,8 @@ static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this, return ike_sa; } -/** - * Implementation of of ike_sa_manager.checkout_by_config. - */ -static ike_sa_t* checkout_by_config(private_ike_sa_manager_t *this, - peer_cfg_t *peer_cfg) +METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*, + private_ike_sa_manager_t *this, peer_cfg_t *peer_cfg) { enumerator_t *enumerator; entry_t *entry; @@ -1107,11 +1131,8 @@ static ike_sa_t* checkout_by_config(private_ike_sa_manager_t *this, return ike_sa; } -/** - * Implementation of of ike_sa_manager.checkout_by_id. - */ -static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this, u_int32_t id, - bool child) +METHOD(ike_sa_manager_t, checkout_by_id, ike_sa_t*, + private_ike_sa_manager_t *this, u_int32_t id, bool child) { enumerator_t *enumerator; iterator_t *children; @@ -1164,11 +1185,8 @@ static ike_sa_t* checkout_by_id(private_ike_sa_manager_t *this, u_int32_t id, return ike_sa; } -/** - * Implementation of of ike_sa_manager.checkout_by_name. - */ -static ike_sa_t* checkout_by_name(private_ike_sa_manager_t *this, char *name, - bool child) +METHOD(ike_sa_manager_t, checkout_by_name, ike_sa_t*, + private_ike_sa_manager_t *this, char *name, bool child) { enumerator_t *enumerator; iterator_t *children; @@ -1233,20 +1251,15 @@ static bool enumerator_filter(private_ike_sa_manager_t *this, return FALSE; } -/** - * Implementation of ike_sa_manager_t.create_enumerator. - */ -static enumerator_t *create_enumerator(private_ike_sa_manager_t* this) +METHOD(ike_sa_manager_t, create_enumerator, enumerator_t*, + private_ike_sa_manager_t* this) { - return enumerator_create_filter( - create_table_enumerator(this), - (void*)enumerator_filter, this, NULL); + return enumerator_create_filter(create_table_enumerator(this), + (void*)enumerator_filter, this, NULL); } -/** - * Implementation of ike_sa_manager_t.checkin. - */ -static void checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) +METHOD(ike_sa_manager_t, checkin, void, + private_ike_sa_manager_t *this, ike_sa_t *ike_sa) { /* to check the SA back in, we look for the pointer of the ike_sa * in all entries. @@ -1311,13 +1324,16 @@ static void checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) segment = put_entry(this, entry); } - /* apply identities for duplicate test (only as responder) */ - if (!entry->ike_sa_id->is_initiator(entry->ike_sa_id) && - ike_sa->get_state(ike_sa) == IKE_ESTABLISHED && + /* apply identities for duplicate test */ + if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED && entry->my_id == NULL && entry->other_id == NULL) { entry->my_id = my_id->clone(my_id); entry->other_id = other_id->clone(other_id); + if (!entry->other) + { + entry->other = other->clone(other); + } put_connected_peers(this, entry); } @@ -1326,10 +1342,8 @@ static void checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) charon->bus->set_sa(charon->bus, NULL); } -/** - * Implementation of ike_sa_manager_t.checkin_and_destroy. - */ -static void checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) +METHOD(ike_sa_manager_t, checkin_and_destroy, void, + private_ike_sa_manager_t *this, ike_sa_t *ike_sa) { /* deletion is a bit complex, we must ensure that no thread is waiting for * this SA. @@ -1366,8 +1380,7 @@ static void checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ike_sa { remove_half_open(this, entry); } - if (!entry->ike_sa_id->is_initiator(entry->ike_sa_id) && - entry->my_id && entry->other_id) + if (entry->my_id && entry->other_id) { remove_connected_peers(this, entry); } @@ -1384,11 +1397,8 @@ static void checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ike_sa charon->bus->set_sa(charon->bus, NULL); } - -/** - * Implementation of ike_sa_manager_t.check_uniqueness. - */ -static bool check_uniqueness(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) +METHOD(ike_sa_manager_t, check_uniqueness, bool, + private_ike_sa_manager_t *this, ike_sa_t *ike_sa, bool force_replace) { bool cancel = FALSE; peer_cfg_t *peer_cfg; @@ -1402,7 +1412,7 @@ static bool check_uniqueness(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) peer_cfg = ike_sa->get_peer_cfg(ike_sa); policy = peer_cfg->get_unique_policy(peer_cfg); - if (policy == UNIQUE_NO) + if (policy == UNIQUE_NO && !force_replace) { return FALSE; } @@ -1416,12 +1426,16 @@ static bool check_uniqueness(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) lock = this->connected_peers_segments[segment & this->segment_mask].lock; lock->read_lock(lock); - if ((list = this->connected_peers_table[row]) != NULL) + list = this->connected_peers_table[row]; + if (list) { connected_peers_t *current; + host_t *other_host; + other_host = ike_sa->get_other_host(ike_sa); if (list->find_first(list, (linked_list_match_t)connected_peers_match, - (void**)¤t, me, other) == SUCCESS) + (void**)¤t, me, other, + (uintptr_t)other_host->get_family(other_host)) == SUCCESS) { /* clone the list, so we can release the lock */ duplicate_ids = current->sas->clone_offset(current->sas, @@ -1446,6 +1460,13 @@ static bool check_uniqueness(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) { continue; } + if (force_replace) + { + DBG1(DBG_IKE, "destroying duplicate IKE_SA for peer '%Y', " + "received INITIAL_CONTACT", other); + checkin_and_destroy(this, duplicate); + continue; + } peer_cfg = duplicate->get_peer_cfg(duplicate); if (peer_cfg && peer_cfg->equals(peer_cfg, ike_sa->get_peer_cfg(ike_sa))) { @@ -1490,21 +1511,49 @@ static bool check_uniqueness(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) return cancel; } -/** - * Implementation of ike_sa_manager_t.get_half_open_count. - */ -static int get_half_open_count(private_ike_sa_manager_t *this, host_t *ip) +METHOD(ike_sa_manager_t, has_contact, bool, + private_ike_sa_manager_t *this, identification_t *me, + identification_t *other, int family) +{ + linked_list_t *list; + u_int row, segment; + rwlock_t *lock; + bool found = FALSE; + + row = chunk_hash_inc(other->get_encoding(other), + chunk_hash(me->get_encoding(me))) & this->table_mask; + segment = row & this->segment_mask; + lock = this->connected_peers_segments[segment & this->segment_mask].lock; + lock->read_lock(lock); + list = this->connected_peers_table[row]; + if (list) + { + if (list->find_first(list, (linked_list_match_t)connected_peers_match, + NULL, me, other, family) == SUCCESS) + { + found = TRUE; + } + } + lock->unlock(lock); + + return found; +} + +METHOD(ike_sa_manager_t, get_half_open_count, int, + private_ike_sa_manager_t *this, host_t *ip) { + linked_list_t *list; + u_int segment, row; + rwlock_t *lock; + chunk_t addr; int count = 0; if (ip) { - linked_list_t *list; - chunk_t addr = ip->get_address(ip); - u_int row = chunk_hash(addr) & this->table_mask; - u_int segment = row & this->segment_mask; - - rwlock_t *lock = this->half_open_segments[segment & this->segment_mask].lock; + addr = ip->get_address(ip); + row = chunk_hash(addr) & this->table_mask; + segment = row & this->segment_mask; + lock = this->half_open_segments[segment & this->segment_mask].lock; lock->read_lock(lock); if ((list = this->half_open_table[row]) != NULL) { @@ -1520,25 +1569,19 @@ static int get_half_open_count(private_ike_sa_manager_t *this, host_t *ip) } else { - u_int segment; - - for (segment = 0; segment < this->segment_count; ++segment) + for (segment = 0; segment < this->segment_count; segment++) { - rwlock_t *lock; lock = this->half_open_segments[segment & this->segment_mask].lock; lock->read_lock(lock); count += this->half_open_segments[segment].count; lock->unlock(lock); } } - return count; } -/** - * Implementation of ike_sa_manager_t.flush. - */ -static void flush(private_ike_sa_manager_t *this) +METHOD(ike_sa_manager_t, flush, void, + private_ike_sa_manager_t *this) { /* destroy all list entries */ enumerator_t *enumerator; @@ -1602,8 +1645,7 @@ static void flush(private_ike_sa_manager_t *this) { remove_half_open(this, entry); } - if (!entry->ike_sa_id->is_initiator(entry->ike_sa_id) && - entry->my_id && entry->other_id) + if (entry->my_id && entry->other_id) { remove_connected_peers(this, entry); } @@ -1615,37 +1657,26 @@ static void flush(private_ike_sa_manager_t *this) unlock_all_segments(this); this->rng->destroy(this->rng); + this->rng = NULL; this->hasher->destroy(this->hasher); + this->hasher = NULL; } -/** - * Implementation of ike_sa_manager_t.destroy. - */ -static void destroy(private_ike_sa_manager_t *this) +METHOD(ike_sa_manager_t, destroy, void, + private_ike_sa_manager_t *this) { u_int i; - for (i = 0; i < this->table_size; ++i) + for (i = 0; i < this->table_size; i++) { - linked_list_t *list; - - if ((list = this->ike_sa_table[i]) != NULL) - { - list->destroy(list); - } - if ((list = this->half_open_table[i]) != NULL) - { - list->destroy(list); - } - if ((list = this->connected_peers_table[i]) != NULL) - { - list->destroy(list); - } + DESTROY_IF(this->ike_sa_table[i]); + DESTROY_IF(this->half_open_table[i]); + DESTROY_IF(this->connected_peers_table[i]); } free(this->ike_sa_table); free(this->half_open_table); free(this->connected_peers_table); - for (i = 0; i < this->segment_count; ++i) + for (i = 0; i < this->segment_count; i++) { this->segments[i].mutex->destroy(this->segments[i].mutex); this->half_open_segments[i].lock->destroy(this->half_open_segments[i].lock); @@ -1681,25 +1712,28 @@ static u_int get_nearest_powerof2(u_int n) */ ike_sa_manager_t *ike_sa_manager_create() { + private_ike_sa_manager_t *this; u_int i; - private_ike_sa_manager_t *this = malloc_thing(private_ike_sa_manager_t); - - /* assign public functions */ - this->public.flush = (void(*)(ike_sa_manager_t*))flush; - this->public.destroy = (void(*)(ike_sa_manager_t*))destroy; - this->public.checkout = (ike_sa_t*(*)(ike_sa_manager_t*, ike_sa_id_t*))checkout; - this->public.checkout_new = (ike_sa_t*(*)(ike_sa_manager_t*,bool))checkout_new; - this->public.checkout_by_message = (ike_sa_t*(*)(ike_sa_manager_t*,message_t*))checkout_by_message; - this->public.checkout_by_config = (ike_sa_t*(*)(ike_sa_manager_t*,peer_cfg_t*))checkout_by_config; - this->public.checkout_by_id = (ike_sa_t*(*)(ike_sa_manager_t*,u_int32_t,bool))checkout_by_id; - this->public.checkout_by_name = (ike_sa_t*(*)(ike_sa_manager_t*,char*,bool))checkout_by_name; - this->public.check_uniqueness = (bool(*)(ike_sa_manager_t*, ike_sa_t *ike_sa))check_uniqueness; - this->public.create_enumerator = (enumerator_t*(*)(ike_sa_manager_t*))create_enumerator; - this->public.checkin = (void(*)(ike_sa_manager_t*,ike_sa_t*))checkin; - this->public.checkin_and_destroy = (void(*)(ike_sa_manager_t*,ike_sa_t*))checkin_and_destroy; - this->public.get_half_open_count = (int(*)(ike_sa_manager_t*,host_t*))get_half_open_count; - - /* initialize private variables */ + + INIT(this, + .public = { + .checkout = _checkout, + .checkout_new = _checkout_new, + .checkout_by_message = _checkout_by_message, + .checkout_by_config = _checkout_by_config, + .checkout_by_id = _checkout_by_id, + .checkout_by_name = _checkout_by_name, + .check_uniqueness = _check_uniqueness, + .has_contact = _has_contact, + .create_enumerator = _create_enumerator, + .checkin = _checkin, + .checkin_and_destroy = _checkin_and_destroy, + .get_half_open_count = _get_half_open_count, + .flush = _flush, + .destroy = _destroy, + }, + ); + this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_PREFERRED); if (this->hasher == NULL) { @@ -1715,6 +1749,7 @@ ike_sa_manager_t *ike_sa_manager_create() free(this); return NULL; } + this->table_size = get_nearest_powerof2(lib->settings->get_int(lib->settings, "charon.ikesa_table_size", DEFAULT_HASHTABLE_SIZE)); this->table_size = max(1, min(this->table_size, MAX_HASHTABLE_SIZE)); @@ -1724,11 +1759,10 @@ ike_sa_manager_t *ike_sa_manager_create() "charon.ikesa_table_segments", DEFAULT_SEGMENT_COUNT)); this->segment_count = max(1, min(this->segment_count, this->table_size)); this->segment_mask = this->segment_count - 1; - this->ike_sa_table = calloc(this->table_size, sizeof(linked_list_t*)); this->segments = (segment_t*)calloc(this->segment_count, sizeof(segment_t)); - for (i = 0; i < this->segment_count; ++i) + for (i = 0; i < this->segment_count; i++) { this->segments[i].mutex = mutex_create(MUTEX_TYPE_RECURSIVE); this->segments[i].count = 0; @@ -1737,7 +1771,7 @@ ike_sa_manager_t *ike_sa_manager_create() /* we use the same table parameters for the table to track half-open SAs */ this->half_open_table = calloc(this->table_size, sizeof(linked_list_t*)); this->half_open_segments = calloc(this->segment_count, sizeof(shareable_segment_t)); - for (i = 0; i < this->segment_count; ++i) + for (i = 0; i < this->segment_count; i++) { this->half_open_segments[i].lock = rwlock_create(RWLOCK_TYPE_DEFAULT); this->half_open_segments[i].count = 0; @@ -1746,7 +1780,7 @@ ike_sa_manager_t *ike_sa_manager_create() /* also for the hash table used for duplicate tests */ this->connected_peers_table = calloc(this->table_size, sizeof(linked_list_t*)); this->connected_peers_segments = calloc(this->segment_count, sizeof(shareable_segment_t)); - for (i = 0; i < this->segment_count; ++i) + for (i = 0; i < this->segment_count; i++) { this->connected_peers_segments[i].lock = rwlock_create(RWLOCK_TYPE_DEFAULT); this->connected_peers_segments[i].count = 0; diff --git a/src/libcharon/sa/ike_sa_manager.h b/src/libcharon/sa/ike_sa_manager.h index f4eabf808..ec157ab3a 100644 --- a/src/libcharon/sa/ike_sa_manager.h +++ b/src/libcharon/sa/ike_sa_manager.h @@ -52,9 +52,6 @@ struct ike_sa_manager_t { /** * Create and check out a new IKE_SA. * - * @note If initiator equals FALSE, the returned IKE_SA is not registered - * in the manager. - * * @param initiator TRUE for initiator, FALSE otherwise * @returns created and checked out IKE_SA */ @@ -109,10 +106,23 @@ struct ike_sa_manager_t { * deadlocks occur otherwise. * * @param ike_sa ike_sa to check + * @param force_replace replace existing SAs, regardless of unique policy * @return TRUE, if the given IKE_SA has duplicates and * should be deleted */ - bool (*check_uniqueness)(ike_sa_manager_t *this, ike_sa_t *ike_sa); + bool (*check_uniqueness)(ike_sa_manager_t *this, ike_sa_t *ike_sa, + bool force_replace); + + /** + * Check if we already have a connected IKE_SA between two identities. + * + * @param me own identity + * @param other remote identity + * @param family address family to include in uniqueness check + * @return TRUE if we have a connected IKE_SA + */ + bool (*has_contact)(ike_sa_manager_t *this, identification_t *me, + identification_t *other, int family); /** * Check out an IKE_SA a unique ID. diff --git a/src/libcharon/sa/keymat.c b/src/libcharon/sa/keymat.c index 878ad124f..33ece24b2 100644 --- a/src/libcharon/sa/keymat.c +++ b/src/libcharon/sa/keymat.c @@ -214,7 +214,7 @@ static bool derive_ike_traditional(private_keymat_t *this, u_int16_t enc_alg, { DBG1(DBG_IKE, "%N %N (key size %d) not supported!", transform_type_names, ENCRYPTION_ALGORITHM, - encryption_algorithm_names, enc_alg, key_size); + encryption_algorithm_names, enc_alg, enc_size); signer_i->destroy(signer_i); signer_r->destroy(signer_r); return FALSE; @@ -540,7 +540,7 @@ METHOD(keymat_t, get_aead, aead_t*, METHOD(keymat_t, get_auth_octets, chunk_t, private_keymat_t *this, bool verify, chunk_t ike_sa_init, - chunk_t nonce, identification_t *id) + chunk_t nonce, identification_t *id, char reserved[3]) { chunk_t chunk, idx, octets; chunk_t skp; @@ -548,8 +548,8 @@ METHOD(keymat_t, get_auth_octets, chunk_t, skp = verify ? this->skp_verify : this->skp_build; chunk = chunk_alloca(4); - memset(chunk.ptr, 0, chunk.len); chunk.ptr[0] = id->get_type(id); + memcpy(chunk.ptr + 1, reserved, 3); idx = chunk_cata("cc", chunk, id->get_encoding(id)); DBG3(DBG_IKE, "IDx' %B", &idx); @@ -570,7 +570,7 @@ METHOD(keymat_t, get_auth_octets, chunk_t, METHOD(keymat_t, get_psk_sig, chunk_t, private_keymat_t *this, bool verify, chunk_t ike_sa_init, - chunk_t nonce, chunk_t secret, identification_t *id) + chunk_t nonce, chunk_t secret, identification_t *id, char reserved[3]) { chunk_t key_pad, key, sig, octets; @@ -578,7 +578,7 @@ METHOD(keymat_t, get_psk_sig, chunk_t, { /* EAP uses SK_p if no MSK has been established */ secret = verify ? this->skp_verify : this->skp_build; } - octets = get_auth_octets(this, verify, ike_sa_init, nonce, id); + octets = get_auth_octets(this, verify, ike_sa_init, nonce, id, reserved); /* AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>) */ key_pad = chunk_create(IKEV2_KEY_PAD, IKEV2_KEY_PAD_LENGTH); this->prf->set_key(this->prf, secret); diff --git a/src/libcharon/sa/keymat.h b/src/libcharon/sa/keymat.h index 4f01aa411..11e0fa79a 100644 --- a/src/libcharon/sa/keymat.h +++ b/src/libcharon/sa/keymat.h @@ -117,10 +117,12 @@ struct keymat_t { * @param ike_sa_init encoded ike_sa_init message * @param nonce nonce value * @param id identity + * @param reserved reserved bytes of id_payload * @return authentication octets */ chunk_t (*get_auth_octets)(keymat_t *this, bool verify, chunk_t ike_sa_init, - chunk_t nonce, identification_t *id); + chunk_t nonce, identification_t *id, + char reserved[3]); /** * Build the shared secret signature used for PSK and EAP authentication. * @@ -133,10 +135,12 @@ struct keymat_t { * @param nonce nonce value * @param secret optional secret to include into signature * @param id identity + * @param reserved reserved bytes of id_payload * @return signature octets */ chunk_t (*get_psk_sig)(keymat_t *this, bool verify, chunk_t ike_sa_init, - chunk_t nonce, chunk_t secret, identification_t *id); + chunk_t nonce, chunk_t secret, + identification_t *id, char reserved[3]); /** * Destroy a keymat_t. */ diff --git a/src/libcharon/sa/task_manager.c b/src/libcharon/sa/task_manager.c index 18703ce36..9467d1586 100644 --- a/src/libcharon/sa/task_manager.c +++ b/src/libcharon/sa/task_manager.c @@ -465,7 +465,6 @@ METHOD(task_manager_t, initiate, status_t, /* update exchange type if a task changed it */ this->initiating.type = message->get_exchange_type(message); - charon->bus->message(charon->bus, message, FALSE); status = this->ike_sa->generate_message(this->ike_sa, message, &this->initiating.packet); if (status != SUCCESS) @@ -654,7 +653,6 @@ static status_t build_response(private_task_manager_t *this, message_t *request) /* message complete, send it */ DESTROY_IF(this->responding.packet); this->responding.packet = NULL; - charon->bus->message(charon->bus, message, FALSE); status = this->ike_sa->generate_message(this->ike_sa, message, &this->responding.packet); message->destroy(message); @@ -882,8 +880,12 @@ static status_t process_request(private_task_manager_t *this, METHOD(task_manager_t, process_message, status_t, private_task_manager_t *this, message_t *msg) { - u_int32_t mid = msg->get_message_id(msg); - host_t *me = msg->get_destination(msg), *other = msg->get_source(msg); + host_t *me, *other; + u_int32_t mid; + + mid = msg->get_message_id(msg); + me = msg->get_destination(msg); + other = msg->get_source(msg); if (msg->get_request(msg)) { @@ -895,10 +897,14 @@ METHOD(task_manager_t, process_message, status_t, { /* only do host updates based on verified messages */ if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE)) { /* with MOBIKE, we do no implicit updates */ - this->ike_sa->update_hosts(this->ike_sa, me, other); + this->ike_sa->update_hosts(this->ike_sa, me, other, mid == 1); } } charon->bus->message(charon->bus, msg, TRUE); + if (msg->get_exchange_type(msg) == EXCHANGE_TYPE_UNDEFINED) + { /* ignore messages altered to EXCHANGE_TYPE_UNDEFINED */ + return SUCCESS; + } if (process_request(this, msg) != SUCCESS) { flush(this); @@ -909,15 +915,15 @@ METHOD(task_manager_t, process_message, status_t, else if ((mid == this->responding.mid - 1) && this->responding.packet) { packet_t *clone; - host_t *me, *other; + host_t *host; DBG1(DBG_IKE, "received retransmit of request with ID %d, " "retransmitting response", mid); clone = this->responding.packet->clone(this->responding.packet); - me = msg->get_destination(msg); - other = msg->get_source(msg); - clone->set_source(clone, me->clone(me)); - clone->set_destination(clone, other->clone(other)); + host = msg->get_destination(msg); + clone->set_source(clone, host->clone(host)); + host = msg->get_source(msg); + clone->set_destination(clone, host->clone(host)); charon->sender->send(charon->sender, clone); } else @@ -936,10 +942,14 @@ METHOD(task_manager_t, process_message, status_t, { /* only do host updates based on verified messages */ if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE)) { /* with MOBIKE, we do no implicit updates */ - this->ike_sa->update_hosts(this->ike_sa, me, other); + this->ike_sa->update_hosts(this->ike_sa, me, other, FALSE); } } charon->bus->message(charon->bus, msg, TRUE); + if (msg->get_exchange_type(msg) == EXCHANGE_TYPE_UNDEFINED) + { /* ignore messages altered to EXCHANGE_TYPE_UNDEFINED */ + return SUCCESS; + } if (process_response(this, msg) != SUCCESS) { flush(this); @@ -1002,6 +1012,19 @@ METHOD(task_manager_t, busy, bool, return (this->active_tasks->get_count(this->active_tasks) > 0); } +METHOD(task_manager_t, incr_mid, void, + private_task_manager_t *this, bool initiate) +{ + if (initiate) + { + this->initiating.mid++; + } + else + { + this->responding.mid++; + } +} + METHOD(task_manager_t, reset, void, private_task_manager_t *this, u_int32_t initiate, u_int32_t respond) { @@ -1085,6 +1108,7 @@ task_manager_t *task_manager_create(ike_sa_t *ike_sa) .queue_task = _queue_task, .initiate = _initiate, .retransmit = _retransmit, + .incr_mid = _incr_mid, .reset = _reset, .adopt_tasks = _adopt_tasks, .busy = _busy, diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h index 14fccd5f9..5bc6c80c4 100644 --- a/src/libcharon/sa/task_manager.h +++ b/src/libcharon/sa/task_manager.h @@ -149,6 +149,16 @@ struct task_manager_t { void (*adopt_tasks) (task_manager_t *this, task_manager_t *other); /** + * Increment a message ID counter, in- or outbound. + * + * If a message is processed outside of the manager, this call increments + * the message ID counters of the task manager. + * + * @param inititate TRUE to increment the initiating ID + */ + void (*incr_mid)(task_manager_t *this, bool initiate); + + /** * Reset message ID counters of the task manager. * * The IKEv2 protocol requires to restart exchanges with message IDs diff --git a/src/libcharon/sa/tasks/child_create.c b/src/libcharon/sa/tasks/child_create.c index 57beedba9..fc02a334b 100644 --- a/src/libcharon/sa/tasks/child_create.c +++ b/src/libcharon/sa/tasks/child_create.c @@ -117,6 +117,11 @@ struct private_child_create_t { ipsec_mode_t mode; /** + * peer accepts TFC padding for this SA + */ + bool tfcv3; + + /** * IPComp transform to use */ ipcomp_transform_t ipcomp; @@ -455,17 +460,21 @@ static status_t select_and_install(private_child_create_t *this, { if (this->initiator) { - status_i = this->child_sa->install(this->child_sa, encr_r, integ_r, - this->my_spi, this->my_cpi, TRUE, my_ts, other_ts); - status_o = this->child_sa->install(this->child_sa, encr_i, integ_i, - this->other_spi, this->other_cpi, FALSE, my_ts, other_ts); + status_i = this->child_sa->install(this->child_sa, + encr_r, integ_r, this->my_spi, this->my_cpi, + TRUE, this->tfcv3, my_ts, other_ts); + status_o = this->child_sa->install(this->child_sa, + encr_i, integ_i, this->other_spi, this->other_cpi, + FALSE, this->tfcv3, my_ts, other_ts); } else { - status_i = this->child_sa->install(this->child_sa, encr_i, integ_i, - this->my_spi, this->my_cpi, TRUE, my_ts, other_ts); - status_o = this->child_sa->install(this->child_sa, encr_r, integ_r, - this->other_spi, this->other_cpi, FALSE, my_ts, other_ts); + status_i = this->child_sa->install(this->child_sa, + encr_i, integ_i, this->my_spi, this->my_cpi, + TRUE, this->tfcv3, my_ts, other_ts); + status_o = this->child_sa->install(this->child_sa, + encr_r, integ_r, this->other_spi, this->other_cpi, + FALSE, this->tfcv3, my_ts, other_ts); } } chunk_clear(&integ_i); @@ -631,7 +640,13 @@ static void handle_notify(private_child_create_t *this, notify_payload_t *notify ipcomp_transform_names, ipcomp); break; } + break; } + case ESP_TFC_PADDING_NOT_SUPPORTED: + DBG1(DBG_IKE, "received %N, not using ESPv3 TFC padding", + notify_type_names, notify->get_notify_type(notify)); + this->tfcv3 = FALSE; + break; default: break; } @@ -691,10 +706,8 @@ static void process_payloads(private_child_create_t *this, message_t *message) enumerator->destroy(enumerator); } -/** - * Implementation of task_t.build for initiator - */ -static status_t build_i(private_child_create_t *this, message_t *message) +METHOD(task_t, build_i, status_t, + private_child_create_t *this, message_t *message) { host_t *me, *other, *vip; peer_cfg_t *peer_cfg; @@ -831,10 +844,8 @@ static status_t build_i(private_child_create_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.process for responder - */ -static status_t process_r(private_child_create_t *this, message_t *message) +METHOD(task_t, process_r, status_t, + private_child_create_t *this, message_t *message) { switch (message->get_exchange_type(message)) { @@ -877,10 +888,8 @@ static void handle_child_sa_failure(private_child_create_t *this, } } -/** - * Implementation of task_t.build for responder - */ -static status_t build_r(private_child_create_t *this, message_t *message) +METHOD(task_t, build_r, status_t, + private_child_create_t *this, message_t *message) { peer_cfg_t *peer_cfg; payload_t *payload; @@ -958,7 +967,7 @@ static status_t build_r(private_child_create_t *this, message_t *message) case INTERNAL_ADDRESS_FAILURE: case FAILED_CP_REQUIRED: { - DBG1(DBG_IKE,"configuration payload negotation " + DBG1(DBG_IKE,"configuration payload negotiation " "failed, no CHILD_SA built"); enumerator->destroy(enumerator); handle_child_sa_failure(this, message); @@ -1029,10 +1038,8 @@ static status_t build_r(private_child_create_t *this, message_t *message) return SUCCESS; } -/** - * Implementation of task_t.process for initiator - */ -static status_t process_i(private_child_create_t *this, message_t *message) +METHOD(task_t, process_i, status_t, + private_child_create_t *this, message_t *message) { enumerator_t *enumerator; payload_t *payload; @@ -1103,7 +1110,21 @@ static status_t process_i(private_child_create_t *this, message_t *message) return NEED_MORE; } default: + { + if (message->get_exchange_type(message) == CREATE_CHILD_SA) + { /* handle notifies if not handled in IKE_AUTH */ + if (type <= 16383) + { + DBG1(DBG_IKE, "received %N notify error", + notify_type_names, type); + enumerator->destroy(enumerator); + return SUCCESS; + } + DBG2(DBG_IKE, "received %N notify", + notify_type_names, type); + } break; + } } } } @@ -1155,34 +1176,20 @@ static status_t process_i(private_child_create_t *this, message_t *message) return SUCCESS; } -/** - * Implementation of task_t.get_type - */ -static task_type_t get_type(private_child_create_t *this) -{ - return CHILD_CREATE; -} - -/** - * Implementation of child_create_t.use_reqid - */ -static void use_reqid(private_child_create_t *this, u_int32_t reqid) +METHOD(child_create_t, use_reqid, void, + private_child_create_t *this, u_int32_t reqid) { this->reqid = reqid; } -/** - * Implementation of child_create_t.get_child - */ -static child_sa_t* get_child(private_child_create_t *this) +METHOD(child_create_t, get_child, child_sa_t*, + private_child_create_t *this) { return this->child_sa; } -/** - * Implementation of child_create_t.get_lower_nonce - */ -static chunk_t get_lower_nonce(private_child_create_t *this) +METHOD(child_create_t, get_lower_nonce, chunk_t, + private_child_create_t *this) { if (memcmp(this->my_nonce.ptr, this->other_nonce.ptr, min(this->my_nonce.len, this->other_nonce.len)) < 0) @@ -1195,10 +1202,14 @@ static chunk_t get_lower_nonce(private_child_create_t *this) } } -/** - * Implementation of task_t.migrate - */ -static void migrate(private_child_create_t *this, ike_sa_t *ike_sa) +METHOD(task_t, get_type, task_type_t, + private_child_create_t *this) +{ + return CHILD_CREATE; +} + +METHOD(task_t, migrate, void, + private_child_create_t *this, ike_sa_t *ike_sa) { chunk_free(&this->my_nonce); chunk_free(&this->other_nonce); @@ -1234,10 +1245,8 @@ static void migrate(private_child_create_t *this, ike_sa_t *ike_sa) this->established = FALSE; } -/** - * Implementation of task_t.destroy - */ -static void destroy(private_child_create_t *this) +METHOD(task_t, destroy, void, + private_child_create_t *this) { chunk_free(&this->my_nonce); chunk_free(&this->other_nonce); @@ -1273,52 +1282,45 @@ child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config, bool rekey, traffic_selector_t *tsi, traffic_selector_t *tsr) { - private_child_create_t *this = malloc_thing(private_child_create_t); - - this->public.get_child = (child_sa_t*(*)(child_create_t*))get_child; - this->public.get_lower_nonce = (chunk_t(*)(child_create_t*))get_lower_nonce; - this->public.use_reqid = (void(*)(child_create_t*,u_int32_t))use_reqid; - 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; + private_child_create_t *this; + + INIT(this, + .public = { + .get_child = _get_child, + .get_lower_nonce = _get_lower_nonce, + .use_reqid = _use_reqid, + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .config = config, + .packet_tsi = tsi ? tsi->clone(tsi) : NULL, + .packet_tsr = tsr ? tsr->clone(tsr) : NULL, + .dh_group = MODP_NONE, + .keymat = ike_sa->get_keymat(ike_sa), + .mode = MODE_TUNNEL, + .tfcv3 = TRUE, + .ipcomp = IPCOMP_NONE, + .ipcomp_received = IPCOMP_NONE, + .rekey = rekey, + ); + 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->public.task.build = _build_i; + this->public.task.process = _process_i; this->initiator = TRUE; config->get_ref(config); } 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->public.task.build = _build_r; + this->public.task.process = _process_r; this->initiator = FALSE; } - this->ike_sa = ike_sa; - 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->packet_tsi = tsi ? tsi->clone(tsi) : NULL; - this->packet_tsr = tsr ? tsr->clone(tsr) : NULL; - this->dh = NULL; - this->dh_group = MODP_NONE; - this->keymat = ike_sa->get_keymat(ike_sa); - this->child_sa = NULL; - this->mode = MODE_TUNNEL; - this->ipcomp = IPCOMP_NONE; - this->ipcomp_received = IPCOMP_NONE; - this->my_spi = 0; - this->other_spi = 0; - this->my_cpi = 0; - this->other_cpi = 0; - this->reqid = 0; - this->established = FALSE; - this->rekey = rekey; - return &this->public; } diff --git a/src/libcharon/sa/tasks/child_rekey.c b/src/libcharon/sa/tasks/child_rekey.c index fdaaea4b8..e74ca4eef 100644 --- a/src/libcharon/sa/tasks/child_rekey.c +++ b/src/libcharon/sa/tasks/child_rekey.c @@ -241,12 +241,11 @@ static child_sa_t *handle_collision(private_child_rekey_t *this) /* if we have the lower nonce, delete rekeyed SA. If not, delete * the redundant. */ if (memcmp(this_nonce.ptr, other_nonce.ptr, - min(this_nonce.len, other_nonce.len)) < 0) + min(this_nonce.len, other_nonce.len)) > 0) { child_sa_t *child_sa; - DBG1(DBG_IKE, "CHILD_SA rekey collision won, " - "deleting rekeyed child"); + DBG1(DBG_IKE, "CHILD_SA rekey collision won, deleting old child"); to_delete = this->child_sa; /* don't touch child other created, it has already been deleted */ if (!this->other_child_destroyed) @@ -259,7 +258,7 @@ static child_sa_t *handle_collision(private_child_rekey_t *this) else { DBG1(DBG_IKE, "CHILD_SA rekey collision lost, " - "deleting redundant child"); + "deleting rekeyed child"); to_delete = this->child_create->get_child(this->child_create); } } diff --git a/src/libcharon/sa/tasks/ike_auth.c b/src/libcharon/sa/tasks/ike_auth.c index b440ec811..0756c7d60 100644 --- a/src/libcharon/sa/tasks/ike_auth.c +++ b/src/libcharon/sa/tasks/ike_auth.c @@ -68,6 +68,11 @@ struct private_ike_auth_t { packet_t *other_packet; /** + * Reserved bytes of ID payload + */ + char reserved[3]; + + /** * currently active authenticator, to authenticate us */ authenticator_t *my_auth; @@ -101,6 +106,11 @@ struct private_ike_auth_t { * should we send a AUTHENTICATION_FAILED notify? */ bool authentication_failed; + + /** + * received an INITIAL_CONTACT? + */ + bool initial_contact; }; /** @@ -160,6 +170,24 @@ static status_t collect_other_init_data(private_ike_auth_t *this, } /** + * Get and store reserved bytes of id_payload, required for AUTH payload + */ +static void get_reserved_id_bytes(private_ike_auth_t *this, id_payload_t *id) +{ + u_int8_t *byte; + int i; + + for (i = 0; i < countof(this->reserved); i++) + { + byte = payload_get_field(&id->payload_interface, RESERVED_BYTE, i); + if (byte) + { + this->reserved[i] = *byte; + } + } +} + +/** * Get the next authentication configuration */ static auth_cfg_t *get_auth_cfg(private_ike_auth_t *this, bool local) @@ -329,10 +357,8 @@ static bool update_cfg_candidates(private_ike_auth_t *this, bool strict) return this->peer_cfg != NULL; } -/** - * Implementation of task_t.build for initiator - */ -static status_t build_i(private_ike_auth_t *this, message_t *message) +METHOD(task_t, build_i, status_t, + private_ike_auth_t *this, message_t *message) { auth_cfg_t *cfg; @@ -367,7 +393,7 @@ static status_t build_i(private_ike_auth_t *this, message_t *message) /* check if an authenticator is in progress */ if (this->my_auth == NULL) { - identification_t *id; + identification_t *idi, *idr = NULL; id_payload_t *id_payload; /* clean up authentication config from a previous round */ @@ -378,33 +404,48 @@ static status_t build_i(private_ike_auth_t *this, message_t *message) cfg = get_auth_cfg(this, FALSE); if (cfg) { - id = cfg->get(cfg, AUTH_RULE_IDENTITY); - if (id && !id->contains_wildcards(id)) + idr = cfg->get(cfg, AUTH_RULE_IDENTITY); + if (idr && !idr->contains_wildcards(idr)) { - this->ike_sa->set_other_id(this->ike_sa, id->clone(id)); + this->ike_sa->set_other_id(this->ike_sa, idr->clone(idr)); id_payload = id_payload_create_from_identification( - ID_RESPONDER, id); + ID_RESPONDER, idr); 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) + idi = cfg->get(cfg, AUTH_RULE_IDENTITY); + if (!idi) { 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); + this->ike_sa->set_my_id(this->ike_sa, idi->clone(idi)); + id_payload = id_payload_create_from_identification(ID_INITIATOR, idi); + get_reserved_id_bytes(this, id_payload); message->add_payload(message, (payload_t*)id_payload); + if (idr && message->get_message_id(message) == 1 && + this->peer_cfg->get_unique_policy(this->peer_cfg) != UNIQUE_NO) + { + host_t *host; + + host = this->ike_sa->get_other_host(this->ike_sa); + if (!charon->ike_sa_manager->has_contact(charon->ike_sa_manager, + idi, idr, host->get_family(host))) + { + message->add_notify(message, FALSE, INITIAL_CONTACT, chunk_empty); + } + } + /* build authentication data */ this->my_auth = authenticator_create_builder(this->ike_sa, cfg, this->other_nonce, this->my_nonce, this->other_packet->get_data(this->other_packet), - this->my_packet->get_data(this->my_packet)); + this->my_packet->get_data(this->my_packet), + this->reserved); if (!this->my_auth) { return FAILED; @@ -441,10 +482,8 @@ static status_t build_i(private_ike_auth_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.process for responder - */ -static status_t process_r(private_ike_auth_t *this, message_t *message) +METHOD(task_t, process_r, status_t, + private_ike_auth_t *this, message_t *message) { auth_cfg_t *cfg, *cand; id_payload_t *id_payload; @@ -498,6 +537,7 @@ static status_t process_r(private_ike_auth_t *this, message_t *message) return FAILED; } id = id_payload->get_identification(id_payload); + get_reserved_id_bytes(this, 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)); @@ -548,7 +588,8 @@ static status_t process_r(private_ike_auth_t *this, message_t *message) this->other_auth = authenticator_create_verifier(this->ike_sa, message, this->other_nonce, this->my_nonce, this->other_packet->get_data(this->other_packet), - this->my_packet->get_data(this->my_packet)); + this->my_packet->get_data(this->my_packet), + this->reserved); if (!this->other_auth) { this->authentication_failed = TRUE; @@ -572,10 +613,13 @@ static status_t process_r(private_ike_auth_t *this, message_t *message) return NEED_MORE; } - /* store authentication information */ - cfg = auth_cfg_create(); - cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, FALSE), FALSE); - this->ike_sa->add_auth_cfg(this->ike_sa, FALSE, cfg); + /* If authenticated (with non-EAP) and received INITIAL_CONTACT, + * delete any existing IKE_SAs with that peer. */ + if (message->get_message_id(message) == 1 && + message->get_notify(message, INITIAL_CONTACT)) + { + this->initial_contact = TRUE; + } /* another auth round done, invoke authorize hook */ if (!charon->bus->authorize(charon->bus, FALSE)) @@ -585,6 +629,11 @@ static status_t process_r(private_ike_auth_t *this, message_t *message) return NEED_MORE; } + /* store authentication information */ + cfg = auth_cfg_create(); + cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, FALSE), FALSE); + this->ike_sa->add_auth_cfg(this->ike_sa, FALSE, cfg); + if (!update_cfg_candidates(this, FALSE)) { this->authentication_failed = TRUE; @@ -603,10 +652,8 @@ static status_t process_r(private_ike_auth_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.build for responder - */ -static status_t build_r(private_ike_auth_t *this, message_t *message) +METHOD(task_t, build_r, status_t, + private_ike_auth_t *this, message_t *message) { auth_cfg_t *cfg; @@ -662,8 +709,16 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) } id_payload = id_payload_create_from_identification(ID_RESPONDER, id); + get_reserved_id_bytes(this, id_payload); message->add_payload(message, (payload_t*)id_payload); + if (this->initial_contact) + { + charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager, + this->ike_sa, TRUE); + this->initial_contact = FALSE; + } + if ((uintptr_t)cfg->get(cfg, AUTH_RULE_AUTH_CLASS) == AUTH_CLASS_EAP) { /* EAP-only authentication */ if (!this->ike_sa->supports_extension(this->ike_sa, @@ -682,7 +737,8 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) this->my_auth = authenticator_create_builder(this->ike_sa, cfg, this->other_nonce, this->my_nonce, this->other_packet->get_data(this->other_packet), - this->my_packet->get_data(this->my_packet)); + this->my_packet->get_data(this->my_packet), + this->reserved); if (!this->my_auth) { message->add_notify(message, TRUE, AUTHENTICATION_FAILED, @@ -744,7 +800,7 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) if (!this->do_another_auth && !this->expect_another_auth) { if (charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager, - this->ike_sa)) + this->ike_sa, FALSE)) { DBG1(DBG_IKE, "cancelling IKE_SA setup due uniqueness policy"); message->add_notify(message, TRUE, AUTHENTICATION_FAILED, @@ -772,10 +828,8 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.process for initiator - */ -static status_t process_i(private_ike_auth_t *this, message_t *message) +METHOD(task_t, process_i, status_t, + private_ike_auth_t *this, message_t *message) { enumerator_t *enumerator; payload_t *payload; @@ -857,6 +911,7 @@ static status_t process_i(private_ike_auth_t *this, message_t *message) return FAILED; } id = id_payload->get_identification(id_payload); + get_reserved_id_bytes(this, 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)); @@ -867,7 +922,8 @@ static status_t process_i(private_ike_auth_t *this, message_t *message) this->other_auth = authenticator_create_verifier(this->ike_sa, message, this->other_nonce, this->my_nonce, this->other_packet->get_data(this->other_packet), - this->my_packet->get_data(this->my_packet)); + this->my_packet->get_data(this->my_packet), + this->reserved); if (!this->other_auth) { return FAILED; @@ -893,17 +949,17 @@ static status_t process_i(private_ike_auth_t *this, message_t *message) this->other_auth->destroy(this->other_auth); this->other_auth = NULL; } - /* store authentication information, reset authenticator */ - cfg = auth_cfg_create(); - cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, FALSE), FALSE); - this->ike_sa->add_auth_cfg(this->ike_sa, FALSE, cfg); - /* another auth round done, invoke authorize hook */ if (!charon->bus->authorize(charon->bus, FALSE)) { DBG1(DBG_IKE, "authorization forbids IKE_SA, cancelling"); 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->ike_sa->add_auth_cfg(this->ike_sa, FALSE, cfg); } if (this->my_auth) @@ -964,18 +1020,14 @@ static status_t process_i(private_ike_auth_t *this, message_t *message) return NEED_MORE; } -/** - * Implementation of task_t.get_type - */ -static task_type_t get_type(private_ike_auth_t *this) +METHOD(task_t, get_type, task_type_t, + private_ike_auth_t *this) { return IKE_AUTHENTICATE; } -/** - * Implementation of task_t.migrate - */ -static void migrate(private_ike_auth_t *this, ike_sa_t *ike_sa) +METHOD(task_t, migrate, void, + private_ike_auth_t *this, ike_sa_t *ike_sa) { chunk_free(&this->my_nonce); chunk_free(&this->other_nonce); @@ -998,10 +1050,8 @@ static void migrate(private_ike_auth_t *this, ike_sa_t *ike_sa) this->candidates = linked_list_create(); } -/** - * Implementation of task_t.destroy - */ -static void destroy(private_ike_auth_t *this) +METHOD(task_t, destroy, void, + private_ike_auth_t *this) { chunk_free(&this->my_nonce); chunk_free(&this->other_nonce); @@ -1019,37 +1069,29 @@ 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; - + private_ike_auth_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .build = _build_r, + .process = _process_r, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .initiator = initiator, + .candidates = linked_list_create(), + .do_another_auth = TRUE, + .expect_another_auth = TRUE, + ); 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; - } - 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->public.task.build = _build_i; + this->public.task.process = _process_i; } - - this->ike_sa = ike_sa; - this->initiator = initiator; - this->my_nonce = chunk_empty; - this->other_nonce = chunk_empty; - this->my_packet = NULL; - this->other_packet = NULL; - this->peer_cfg = NULL; - 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/libcharon/sa/tasks/ike_cert_pre.c b/src/libcharon/sa/tasks/ike_cert_pre.c index 1c0c54727..a59b8dcce 100644 --- a/src/libcharon/sa/tasks/ike_cert_pre.c +++ b/src/libcharon/sa/tasks/ike_cert_pre.c @@ -76,6 +76,7 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) { certreq_payload_t *certreq = (certreq_payload_t*)payload; enumerator_t *enumerator; + u_int unknown = 0; chunk_t keyid; this->ike_sa->set_condition(this->ike_sa, COND_CERTREQ_SEEN, TRUE); @@ -103,12 +104,18 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) } else { - DBG1(DBG_IKE, "received cert request for unknown ca " + DBG2(DBG_IKE, "received cert request for unknown ca " "with keyid %Y", id); + unknown++; } id->destroy(id); } enumerator->destroy(enumerator); + if (unknown) + { + DBG1(DBG_IKE, "received %u cert requests for an unknown ca", + unknown); + } break; } case NOTIFY: @@ -253,11 +260,19 @@ static void process_certs(private_ike_cert_pre_t *this, message_t *message) } break; } + case ENC_CRL: + cert = cert_payload->get_cert(cert_payload); + if (cert) + { + DBG1(DBG_IKE, "received CRL \"%Y\"", + cert->get_subject(cert)); + auth->add(auth, AUTH_HELPER_REVOCATION_CERT, cert); + } + break; case ENC_PKCS7_WRAPPED_X509: case ENC_PGP: case ENC_DNS_SIGNED_KEY: case ENC_KERBEROS_TOKEN: - case ENC_CRL: case ENC_ARL: case ENC_SPKI: case ENC_X509_ATTRIBUTE: diff --git a/src/libcharon/sa/tasks/ike_rekey.c b/src/libcharon/sa/tasks/ike_rekey.c index 1a6c140c4..44c55036e 100644 --- a/src/libcharon/sa/tasks/ike_rekey.c +++ b/src/libcharon/sa/tasks/ike_rekey.c @@ -255,19 +255,20 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message) /* if we have the lower nonce, delete rekeyed SA. If not, delete * the redundant. */ if (memcmp(this_nonce.ptr, other_nonce.ptr, - min(this_nonce.len, other_nonce.len)) < 0) + min(this_nonce.len, other_nonce.len)) > 0) { /* peer should delete this SA. Add a timeout just in case. */ job_t *job = (job_t*)delete_ike_sa_job_create( other->new_sa->get_id(other->new_sa), TRUE); lib->scheduler->schedule_job(lib->scheduler, job, 10); - DBG1(DBG_IKE, "IKE_SA rekey collision won, deleting rekeyed IKE_SA"); + DBG1(DBG_IKE, "IKE_SA rekey collision won, waiting for delete"); charon->ike_sa_manager->checkin(charon->ike_sa_manager, other->new_sa); other->new_sa = NULL; } else { - DBG1(DBG_IKE, "IKE_SA rekey collision lost, deleting redundant IKE_SA"); + DBG1(DBG_IKE, "IKE_SA rekey collision lost, " + "deleting redundant IKE_SA"); /* apply host for a proper delete */ host = this->ike_sa->get_my_host(this->ike_sa); this->new_sa->set_my_host(this->new_sa, host->clone(host)); |