Added support to sync IKEv1 SAs key material in HA plugin
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include <daemon.h>
|
#include <daemon.h>
|
||||||
#include <sa/ikev2/keymat_v2.h>
|
#include <sa/ikev2/keymat_v2.h>
|
||||||
|
#include <sa/ikev1/keymat_v1.h>
|
||||||
#include <processing/jobs/callback_job.h>
|
#include <processing/jobs/callback_job.h>
|
||||||
|
|
||||||
typedef struct private_ha_dispatcher_t private_ha_dispatcher_t;
|
typedef struct private_ha_dispatcher_t private_ha_dispatcher_t;
|
||||||
@@ -77,6 +78,11 @@ struct ha_diffie_hellman_t {
|
|||||||
* Shared secret
|
* Shared secret
|
||||||
*/
|
*/
|
||||||
chunk_t secret;
|
chunk_t secret;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Own public value
|
||||||
|
*/
|
||||||
|
chunk_t pub;
|
||||||
};
|
};
|
||||||
|
|
||||||
METHOD(diffie_hellman_t, dh_get_shared_secret, status_t,
|
METHOD(diffie_hellman_t, dh_get_shared_secret, status_t,
|
||||||
@@ -86,6 +92,12 @@ METHOD(diffie_hellman_t, dh_get_shared_secret, status_t,
|
|||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
METHOD(diffie_hellman_t, dh_get_my_public_value, void,
|
||||||
|
ha_diffie_hellman_t *this, chunk_t *value)
|
||||||
|
{
|
||||||
|
*value = chunk_clone(this->pub);
|
||||||
|
}
|
||||||
|
|
||||||
METHOD(diffie_hellman_t, dh_destroy, void,
|
METHOD(diffie_hellman_t, dh_destroy, void,
|
||||||
ha_diffie_hellman_t *this)
|
ha_diffie_hellman_t *this)
|
||||||
{
|
{
|
||||||
@@ -95,16 +107,18 @@ METHOD(diffie_hellman_t, dh_destroy, void,
|
|||||||
/**
|
/**
|
||||||
* Create a HA synced DH implementation
|
* Create a HA synced DH implementation
|
||||||
*/
|
*/
|
||||||
static diffie_hellman_t *ha_diffie_hellman_create(chunk_t secret)
|
static diffie_hellman_t *ha_diffie_hellman_create(chunk_t secret, chunk_t pub)
|
||||||
{
|
{
|
||||||
ha_diffie_hellman_t *this;
|
ha_diffie_hellman_t *this;
|
||||||
|
|
||||||
INIT(this,
|
INIT(this,
|
||||||
.dh = {
|
.dh = {
|
||||||
.get_shared_secret = _dh_get_shared_secret,
|
.get_shared_secret = _dh_get_shared_secret,
|
||||||
|
.get_my_public_value = _dh_get_my_public_value,
|
||||||
.destroy = _dh_destroy,
|
.destroy = _dh_destroy,
|
||||||
},
|
},
|
||||||
.secret = secret,
|
.secret = secret,
|
||||||
|
.pub = pub,
|
||||||
);
|
);
|
||||||
|
|
||||||
return &this->dh;
|
return &this->dh;
|
||||||
@@ -119,9 +133,11 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
|
|||||||
ha_message_value_t value;
|
ha_message_value_t value;
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
ike_sa_t *ike_sa = NULL, *old_sa = NULL;
|
ike_sa_t *ike_sa = NULL, *old_sa = NULL;
|
||||||
|
ike_version_t version = IKEV2;
|
||||||
u_int16_t encr = 0, len = 0, integ = 0, prf = 0, old_prf = PRF_UNDEFINED;
|
u_int16_t encr = 0, len = 0, integ = 0, prf = 0, old_prf = PRF_UNDEFINED;
|
||||||
chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty;
|
chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty;
|
||||||
chunk_t secret = chunk_empty, old_skd = chunk_empty;
|
chunk_t secret = chunk_empty, old_skd = chunk_empty;
|
||||||
|
chunk_t dh_local = chunk_empty, dh_remote = chunk_empty, psk = chunk_empty;
|
||||||
bool ok = FALSE;
|
bool ok = FALSE;
|
||||||
|
|
||||||
enumerator = message->create_attribute_enumerator(message);
|
enumerator = message->create_attribute_enumerator(message);
|
||||||
@@ -131,12 +147,15 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
|
|||||||
{
|
{
|
||||||
case HA_IKE_ID:
|
case HA_IKE_ID:
|
||||||
ike_sa = ike_sa_create(value.ike_sa_id,
|
ike_sa = ike_sa_create(value.ike_sa_id,
|
||||||
value.ike_sa_id->is_initiator(value.ike_sa_id), IKEV2);
|
value.ike_sa_id->is_initiator(value.ike_sa_id), version);
|
||||||
break;
|
break;
|
||||||
case HA_IKE_REKEY_ID:
|
case HA_IKE_REKEY_ID:
|
||||||
old_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
|
old_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
|
||||||
value.ike_sa_id);
|
value.ike_sa_id);
|
||||||
break;
|
break;
|
||||||
|
case HA_IKE_VERSION:
|
||||||
|
version = value.u8;
|
||||||
|
break;
|
||||||
case HA_NONCE_I:
|
case HA_NONCE_I:
|
||||||
nonce_i = value.chunk;
|
nonce_i = value.chunk;
|
||||||
break;
|
break;
|
||||||
@@ -146,6 +165,15 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
|
|||||||
case HA_SECRET:
|
case HA_SECRET:
|
||||||
secret = value.chunk;
|
secret = value.chunk;
|
||||||
break;
|
break;
|
||||||
|
case HA_LOCAL_DH:
|
||||||
|
dh_local = value.chunk;
|
||||||
|
break;
|
||||||
|
case HA_REMOTE_DH:
|
||||||
|
dh_remote = value.chunk;
|
||||||
|
break;
|
||||||
|
case HA_PSK:
|
||||||
|
psk = value.chunk;
|
||||||
|
break;
|
||||||
case HA_OLD_SKD:
|
case HA_OLD_SKD:
|
||||||
old_skd = value.chunk;
|
old_skd = value.chunk;
|
||||||
break;
|
break;
|
||||||
@@ -189,7 +217,7 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
|
|||||||
proposal->add_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, prf, 0);
|
proposal->add_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, prf, 0);
|
||||||
}
|
}
|
||||||
charon->bus->set_sa(charon->bus, ike_sa);
|
charon->bus->set_sa(charon->bus, ike_sa);
|
||||||
dh = ha_diffie_hellman_create(secret);
|
dh = ha_diffie_hellman_create(secret, dh_local);
|
||||||
if (ike_sa->get_version(ike_sa) == IKEV2)
|
if (ike_sa->get_version(ike_sa) == IKEV2)
|
||||||
{
|
{
|
||||||
keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa);
|
keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa);
|
||||||
@@ -197,6 +225,22 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
|
|||||||
ok = keymat_v2->derive_ike_keys(keymat_v2, proposal, dh, nonce_i,
|
ok = keymat_v2->derive_ike_keys(keymat_v2, proposal, dh, nonce_i,
|
||||||
nonce_r, ike_sa->get_id(ike_sa), old_prf, old_skd);
|
nonce_r, ike_sa->get_id(ike_sa), old_prf, old_skd);
|
||||||
}
|
}
|
||||||
|
if (ike_sa->get_version(ike_sa) == IKEV1)
|
||||||
|
{
|
||||||
|
keymat_v1_t *keymat_v1 = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
|
||||||
|
shared_key_t *shared = NULL;
|
||||||
|
auth_method_t method = AUTH_RSA;
|
||||||
|
|
||||||
|
if (psk.len)
|
||||||
|
{
|
||||||
|
method = AUTH_PSK;
|
||||||
|
shared = shared_key_create(SHARED_IKE, chunk_clone(psk));
|
||||||
|
}
|
||||||
|
ok = keymat_v1->derive_ike_keys(keymat_v1, proposal,
|
||||||
|
dh, dh_remote, nonce_i, nonce_r,
|
||||||
|
ike_sa->get_id(ike_sa), method, shared);
|
||||||
|
DESTROY_IF(shared);
|
||||||
|
}
|
||||||
dh->destroy(dh);
|
dh->destroy(dh);
|
||||||
if (ok)
|
if (ok)
|
||||||
{
|
{
|
||||||
@@ -518,7 +562,7 @@ static void process_child_add(private_ha_dispatcher_t *this,
|
|||||||
chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty, secret = chunk_empty;
|
chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty, secret = chunk_empty;
|
||||||
chunk_t encr_i, integ_i, encr_r, integ_r;
|
chunk_t encr_i, integ_i, encr_r, integ_r;
|
||||||
linked_list_t *local_ts, *remote_ts;
|
linked_list_t *local_ts, *remote_ts;
|
||||||
diffie_hellman_t *dh;
|
diffie_hellman_t *dh = NULL;
|
||||||
|
|
||||||
enumerator = message->create_attribute_enumerator(message);
|
enumerator = message->create_attribute_enumerator(message);
|
||||||
while (enumerator->enumerate(enumerator, &attribute, &value))
|
while (enumerator->enumerate(enumerator, &attribute, &value))
|
||||||
@@ -612,16 +656,29 @@ static void process_child_add(private_ha_dispatcher_t *this,
|
|||||||
proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, len);
|
proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, len);
|
||||||
}
|
}
|
||||||
proposal->add_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS, esn, 0);
|
proposal->add_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS, esn, 0);
|
||||||
dh = ha_diffie_hellman_create(secret);
|
if (secret.len)
|
||||||
|
{
|
||||||
|
dh = ha_diffie_hellman_create(secret, chunk_empty);
|
||||||
|
}
|
||||||
if (ike_sa->get_version(ike_sa) == IKEV2)
|
if (ike_sa->get_version(ike_sa) == IKEV2)
|
||||||
{
|
{
|
||||||
keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa);
|
keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa);
|
||||||
|
|
||||||
ok = keymat_v2->derive_child_keys(keymat_v2,
|
ok = keymat_v2->derive_child_keys(keymat_v2, proposal, dh,
|
||||||
proposal, secret.ptr ? dh : NULL, nonce_i, nonce_r,
|
nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r);
|
||||||
&encr_i, &integ_i, &encr_r, &integ_r);
|
|
||||||
}
|
}
|
||||||
dh->destroy(dh);
|
if (ike_sa->get_version(ike_sa) == IKEV1)
|
||||||
|
{
|
||||||
|
keymat_v1_t *keymat_v1 = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
|
||||||
|
u_int32_t spi_i, spi_r;
|
||||||
|
|
||||||
|
spi_i = initiator ? inbound_spi : outbound_spi;
|
||||||
|
spi_r = initiator ? outbound_spi : inbound_spi;
|
||||||
|
|
||||||
|
ok = keymat_v1->derive_child_keys(keymat_v1, proposal, dh, spi_i, spi_r,
|
||||||
|
nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r);
|
||||||
|
}
|
||||||
|
DESTROY_IF(dh);
|
||||||
if (!ok)
|
if (!ok)
|
||||||
{
|
{
|
||||||
DBG1(DBG_CHD, "HA CHILD_SA key derivation failed");
|
DBG1(DBG_CHD, "HA CHILD_SA key derivation failed");
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ METHOD(listener_t, ike_keys, bool,
|
|||||||
}
|
}
|
||||||
|
|
||||||
m = ha_message_create(HA_IKE_ADD);
|
m = ha_message_create(HA_IKE_ADD);
|
||||||
|
m->add_attribute(m, HA_IKE_VERSION, ike_sa->get_version(ike_sa));
|
||||||
m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
|
m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
|
||||||
|
|
||||||
if (rekey && rekey->get_version(rekey) == IKEV2)
|
if (rekey && rekey->get_version(rekey) == IKEV2)
|
||||||
@@ -123,6 +124,17 @@ METHOD(listener_t, ike_keys, bool,
|
|||||||
m->add_attribute(m, HA_NONCE_R, nonce_r);
|
m->add_attribute(m, HA_NONCE_R, nonce_r);
|
||||||
m->add_attribute(m, HA_SECRET, secret);
|
m->add_attribute(m, HA_SECRET, secret);
|
||||||
chunk_clear(&secret);
|
chunk_clear(&secret);
|
||||||
|
if (ike_sa->get_version(ike_sa) == IKEV1)
|
||||||
|
{
|
||||||
|
dh->get_my_public_value(dh, &secret);
|
||||||
|
m->add_attribute(m, HA_LOCAL_DH, secret);
|
||||||
|
chunk_free(&secret);
|
||||||
|
m->add_attribute(m, HA_REMOTE_DH, dh_other);
|
||||||
|
if (shared)
|
||||||
|
{
|
||||||
|
m->add_attribute(m, HA_PSK, shared->get_key(shared));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this->socket->push(this->socket, m);
|
this->socket->push(this->socket, m);
|
||||||
this->cache->cache(this->cache, ike_sa, m);
|
this->cache->cache(this->cache, ike_sa, m);
|
||||||
|
|||||||
@@ -213,6 +213,7 @@ METHOD(ha_message_t, add_attribute, void,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* u_int8_t */
|
/* u_int8_t */
|
||||||
|
case HA_IKE_VERSION:
|
||||||
case HA_INITIATOR:
|
case HA_INITIATOR:
|
||||||
case HA_IPSEC_MODE:
|
case HA_IPSEC_MODE:
|
||||||
case HA_IPCOMP:
|
case HA_IPCOMP:
|
||||||
@@ -263,6 +264,9 @@ METHOD(ha_message_t, add_attribute, void,
|
|||||||
case HA_NONCE_I:
|
case HA_NONCE_I:
|
||||||
case HA_NONCE_R:
|
case HA_NONCE_R:
|
||||||
case HA_SECRET:
|
case HA_SECRET:
|
||||||
|
case HA_LOCAL_DH:
|
||||||
|
case HA_REMOTE_DH:
|
||||||
|
case HA_PSK:
|
||||||
case HA_OLD_SKD:
|
case HA_OLD_SKD:
|
||||||
{
|
{
|
||||||
chunk_t chunk;
|
chunk_t chunk;
|
||||||
@@ -426,6 +430,7 @@ METHOD(enumerator_t, attribute_enumerate, bool,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
/* u_int8_t */
|
/* u_int8_t */
|
||||||
|
case HA_IKE_VERSION:
|
||||||
case HA_INITIATOR:
|
case HA_INITIATOR:
|
||||||
case HA_IPSEC_MODE:
|
case HA_IPSEC_MODE:
|
||||||
case HA_IPCOMP:
|
case HA_IPCOMP:
|
||||||
@@ -479,6 +484,9 @@ METHOD(enumerator_t, attribute_enumerate, bool,
|
|||||||
case HA_NONCE_I:
|
case HA_NONCE_I:
|
||||||
case HA_NONCE_R:
|
case HA_NONCE_R:
|
||||||
case HA_SECRET:
|
case HA_SECRET:
|
||||||
|
case HA_LOCAL_DH:
|
||||||
|
case HA_REMOTE_DH:
|
||||||
|
case HA_PSK:
|
||||||
case HA_OLD_SKD:
|
case HA_OLD_SKD:
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ extern enum_name_t *ha_message_type_names;
|
|||||||
enum ha_message_attribute_t {
|
enum ha_message_attribute_t {
|
||||||
/** ike_sa_id_t*, to identify IKE_SA */
|
/** ike_sa_id_t*, to identify IKE_SA */
|
||||||
HA_IKE_ID = 1,
|
HA_IKE_ID = 1,
|
||||||
/** ike_Sa_id_t*, identifies IKE_SA which gets rekeyed */
|
/** ike_sa_id_t*, identifies IKE_SA which gets rekeyed */
|
||||||
HA_IKE_REKEY_ID,
|
HA_IKE_REKEY_ID,
|
||||||
/** identification_t*, local identity */
|
/** identification_t*, local identity */
|
||||||
HA_LOCAL_ID,
|
HA_LOCAL_ID,
|
||||||
@@ -142,6 +142,14 @@ enum ha_message_attribute_t {
|
|||||||
HA_SEGMENT,
|
HA_SEGMENT,
|
||||||
/** u_int16_t, Extended Sequence numbers */
|
/** u_int16_t, Extended Sequence numbers */
|
||||||
HA_ESN,
|
HA_ESN,
|
||||||
|
/** u_int8_t, IKE version */
|
||||||
|
HA_IKE_VERSION,
|
||||||
|
/** chunk_t, own DH public value */
|
||||||
|
HA_LOCAL_DH,
|
||||||
|
/** chunk_t, remote DH public value */
|
||||||
|
HA_REMOTE_DH,
|
||||||
|
/** chunk_t, shared secret for IKEv1 key derivation */
|
||||||
|
HA_PSK,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user