summaryrefslogtreecommitdiff
path: root/src/libcharon/sa
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/sa')
-rw-r--r--src/libcharon/sa/authenticators/authenticator.c20
-rw-r--r--src/libcharon/sa/authenticators/authenticator.h8
-rw-r--r--src/libcharon/sa/authenticators/eap_authenticator.c18
-rw-r--r--src/libcharon/sa/authenticators/eap_authenticator.h8
-rw-r--r--src/libcharon/sa/authenticators/psk_authenticator.c94
-rw-r--r--src/libcharon/sa/authenticators/psk_authenticator.h8
-rw-r--r--src/libcharon/sa/authenticators/pubkey_authenticator.c90
-rw-r--r--src/libcharon/sa/authenticators/pubkey_authenticator.h8
-rw-r--r--src/libcharon/sa/child_sa.c12
-rw-r--r--src/libcharon/sa/child_sa.h3
-rw-r--r--src/libcharon/sa/connect_manager.c5
-rw-r--r--src/libcharon/sa/ike_sa.c79
-rw-r--r--src/libcharon/sa/ike_sa.h3
-rw-r--r--src/libcharon/sa/ike_sa_manager.c474
-rw-r--r--src/libcharon/sa/ike_sa_manager.h18
-rw-r--r--src/libcharon/sa/keymat.c10
-rw-r--r--src/libcharon/sa/keymat.h8
-rw-r--r--src/libcharon/sa/task_manager.c46
-rw-r--r--src/libcharon/sa/task_manager.h10
-rw-r--r--src/libcharon/sa/tasks/child_create.c182
-rw-r--r--src/libcharon/sa/tasks/child_rekey.c7
-rw-r--r--src/libcharon/sa/tasks/ike_auth.c200
-rw-r--r--src/libcharon/sa/tasks/ike_cert_pre.c19
-rw-r--r--src/libcharon/sa/tasks/ike_rekey.c7
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, &current))
{
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**)&current, 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**)&current, &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, &current))
{
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**)&current, entry->my_id, entry->other_id) == SUCCESS)
+ (void**)&current, 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, &current))
{
- 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**)&current, me, other) == SUCCESS)
+ (void**)&current, 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));