/*
- * Copyright (C) 2011-2015 Tobias Brunner
+ * Copyright (C) 2011-2016 Tobias Brunner
* Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil
*
this->mutex->unlock(this->mutex);
}
+METHOD(bus_t, ike_derived_keys, void,
+ private_bus_t *this, chunk_t sk_ei, chunk_t sk_er, chunk_t sk_ai,
+ chunk_t sk_ar)
+{
+ enumerator_t *enumerator;
+ ike_sa_t *ike_sa;
+ entry_t *entry;
+ bool keep;
+
+ ike_sa = this->thread_sa->get(this->thread_sa);
+
+ this->mutex->lock(this->mutex);
+ enumerator = this->listeners->create_enumerator(this->listeners);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (entry->calling || !entry->listener->ike_derived_keys)
+ {
+ continue;
+ }
+ entry->calling++;
+ keep = entry->listener->ike_derived_keys(entry->listener, ike_sa, sk_ei,
+ sk_er, sk_ai, sk_ar);
+ entry->calling--;
+ if (!keep)
+ {
+ unregister_listener(this, entry, enumerator);
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->mutex->unlock(this->mutex);
+}
+
METHOD(bus_t, child_keys, void,
private_bus_t *this, child_sa_t *child_sa, bool initiator,
diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r)
this->mutex->unlock(this->mutex);
}
+METHOD(bus_t, child_derived_keys, void,
+ private_bus_t *this, child_sa_t *child_sa, bool initiator,
+ chunk_t encr_i, chunk_t encr_r, chunk_t integ_i, chunk_t integ_r)
+{
+ enumerator_t *enumerator;
+ ike_sa_t *ike_sa;
+ entry_t *entry;
+ bool keep;
+
+ ike_sa = this->thread_sa->get(this->thread_sa);
+
+ this->mutex->lock(this->mutex);
+ enumerator = this->listeners->create_enumerator(this->listeners);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ if (entry->calling || !entry->listener->child_derived_keys)
+ {
+ continue;
+ }
+ entry->calling++;
+ keep = entry->listener->child_derived_keys(entry->listener, ike_sa,
+ child_sa, initiator, encr_i, encr_r,
+ integ_i, integ_r);
+ entry->calling--;
+ if (!keep)
+ {
+ unregister_listener(this, entry, enumerator);
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->mutex->unlock(this->mutex);
+}
+
METHOD(bus_t, child_updown, void,
private_bus_t *this, child_sa_t *child_sa, bool up)
{
.child_state_change = _child_state_change,
.message = _message,
.ike_keys = _ike_keys,
+ .ike_derived_keys = _ike_derived_keys,
.child_keys = _child_keys,
+ .child_derived_keys = _child_derived_keys,
.ike_updown = _ike_updown,
.ike_rekey = _ike_rekey,
.ike_update = _ike_update,
/*
- * Copyright (C) 2012-2015 Tobias Brunner
+ * Copyright (C) 2012-2016 Tobias Brunner
* Copyright (C) 2006-2009 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* @param ike_sa IKE_SA this keymat belongs to
* @param dh diffie hellman shared secret
* @param dh_other others DH public value (IKEv1 only)
- * @param nonce_i initiators nonce
- * @param nonce_r responders nonce
+ * @param nonce_i initiator's nonce
+ * @param nonce_r responder's nonce
* @param rekey IKE_SA we are rekeying, if any (IKEv2 only)
* @param shared shared key used for key derivation (IKEv1-PSK only)
*/
ike_sa_t *rekey, shared_key_t *shared);
/**
+ * IKE_SA derived keys hook.
+ *
+ * @param sk_ei SK_ei, or Ka for IKEv1
+ * @param sk_er SK_er
+ * @param sk_ai SK_ai, or SKEYID_a for IKEv1
+ * @param sk_ar SK_ar
+ */
+ void (*ike_derived_keys)(bus_t *this, chunk_t sk_ei, chunk_t sk_er,
+ chunk_t sk_ai, chunk_t sk_ar);
+
+ /**
* CHILD_SA keymat hook.
*
* @param child_sa CHILD_SA this keymat is used for
* @param initiator initiator of the CREATE_CHILD_SA exchange
* @param dh diffie hellman shared secret
- * @param nonce_i initiators nonce
- * @param nonce_r responders nonce
+ * @param nonce_i initiator's nonce
+ * @param nonce_r responder's nonce
*/
void (*child_keys)(bus_t *this, child_sa_t *child_sa, bool initiator,
diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r);
/**
+ * CHILD_SA derived keys hook.
+ *
+ * @param child_sa CHILD_SA these keys are used for
+ * @param initiator initiator of the CREATE_CHILD_SA exchange
+ * @param encr_i initiator's encryption key
+ * @param encr_o responder's encryption key
+ * @param integ_i initiator's integrity key
+ * @param integ_r responder's integrity key
+ */
+ void (*child_derived_keys)(bus_t *this, child_sa_t *child_sa,
+ bool initiator, chunk_t encr_i, chunk_t encr_r,
+ chunk_t integ_i, chunk_t integ_r);
+
+ /**
* IKE_SA up/down hook.
*
* @param ike_sa IKE_SA coming up/going down
/*
- * Copyright (C) 2011-2015 Tobias Brunner
+ * Copyright (C) 2011-2016 Tobias Brunner
* Copyright (C) 2009 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* @param ike_sa IKE_SA this keymat belongs to
* @param dh diffie hellman shared secret
* @param dh_other others DH public value (IKEv1 only)
- * @param nonce_i initiators nonce
- * @param nonce_r responders nonce
+ * @param nonce_i initiator's nonce
+ * @param nonce_r responder's nonce
* @param rekey IKE_SA we are rekeying, if any (IKEv2 only)
* @param shared shared key used for key derivation (IKEv1-PSK only)
* @return TRUE to stay registered, FALSE to unregister
ike_sa_t *rekey, shared_key_t *shared);
/**
+ * Hook called with derived IKE_SA keys.
+ *
+ * @param ike_sa IKE_SA these keys belong to
+ * @param sk_ei SK_ei, or Ka for IKEv1
+ * @param sk_er SK_er
+ * @param sk_ai SK_ai, or SKEYID_a for IKEv1
+ * @param sk_ar SK_ar
+ */
+ bool (*ike_derived_keys)(listener_t *this, ike_sa_t *ike_sa, chunk_t sk_ei,
+ chunk_t sk_er, chunk_t sk_ai, chunk_t sk_ar);
+
+ /**
* Hook called with CHILD_SA key material.
*
* @param ike_sa IKE_SA the child sa belongs to
* @param child_sa CHILD_SA this keymat is used for
* @param initiator initiator of the CREATE_CHILD_SA exchange
* @param dh diffie hellman shared secret
- * @param nonce_i initiators nonce
- * @param nonce_r responders nonce
+ * @param nonce_i initiator's nonce
+ * @param nonce_r responder's nonce
* @return TRUE to stay registered, FALSE to unregister
*/
bool (*child_keys)(listener_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
chunk_t nonce_i, chunk_t nonce_r);
/**
+ * Hook called with derived CHILD_SA keys.
+ *
+ * @param ike_sa IKE_SA the child sa belongs to
+ * @param child_sa CHILD_SA these keys are used for
+ * @param initiator initiator of the CREATE_CHILD_SA exchange
+ * @param encr_i initiator's encryption key
+ * @param encr_o responder's encryption key
+ * @param integ_i initiator's integrity key
+ * @param integ_r responder's integrity key
+ */
+ bool (*child_derived_keys)(listener_t *this, ike_sa_t *ike_sa,
+ child_sa_t *child_sa, bool initiator,
+ chunk_t encr_i, chunk_t encr_r,
+ chunk_t integ_i, chunk_t integ_r);
+
+ /**
* Hook called if an IKE_SA gets up or down.
*
* @param ike_sa IKE_SA coming up/going down
hasher_t *hasher;
/**
- * Key used for authentication during main mode
- */
- chunk_t skeyid;
-
- /**
* Key to derive key material from for non-ISAKMP SAs, rekeying
*/
chunk_t skeyid_d;
* Create a simple implementation of the aead_t interface which only encrypts
* or decrypts data.
*/
-static aead_t *create_aead(proposal_t *proposal, prf_t *prf, chunk_t skeyid_e)
+static aead_t *create_aead(proposal_t *proposal, prf_t *prf, chunk_t skeyid_e,
+ chunk_t *ka)
{
private_aead_t *this;
uint16_t alg, key_size;
crypter_t *crypter;
- chunk_t ka;
if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg,
&key_size))
return NULL;
}
key_size = crypter->get_key_size(crypter);
- if (!expand_skeyid_e(skeyid_e, crypter->get_key_size(crypter), prf, &ka))
+ if (!expand_skeyid_e(skeyid_e, crypter->get_key_size(crypter), prf, ka))
{
return NULL;
}
- DBG4(DBG_IKE, "encryption key Ka %B", &ka);
- if (!crypter->set_key(crypter, ka))
+ DBG4(DBG_IKE, "encryption key Ka %B", ka);
+ if (!crypter->set_key(crypter, *ka))
{
- chunk_clear(&ka);
+ chunk_clear(ka);
return NULL;
}
- chunk_clear(&ka);
INIT(this,
.aead = {
auth_method_t auth, shared_key_t *shared_key)
{
chunk_t g_xy, g_xi, g_xr, dh_me, spi_i, spi_r, nonces, data, skeyid_e;
- chunk_t skeyid;
+ chunk_t skeyid, ka;
uint16_t alg;
spi_i = chunk_alloca(sizeof(uint64_t));
}
chunk_clear(&skeyid);
- this->aead = create_aead(proposal, this->prf, skeyid_e);
+ this->aead = create_aead(proposal, this->prf, skeyid_e, &ka);
if (!this->aead)
{
return FALSE;
}
+ charon->bus->ike_derived_keys(charon->bus, ka, chunk_empty, this->skeyid_a,
+ chunk_empty);
+ chunk_clear(&ka);
if (!this->hasher && !this->public.create_hasher(&this->public, proposal))
{
return FALSE;
this->initiator, FALSE, FALSE, tsr, tsi);
}
}
- chunk_clear(&integ_i);
- chunk_clear(&integ_r);
- chunk_clear(&encr_i);
- chunk_clear(&encr_r);
if (status_i != SUCCESS || status_o != SUCCESS)
{
(status_o != SUCCESS) ? "outbound " : "");
tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
- return FALSE;
- }
-
- if (this->initiator)
- {
- status = this->child_sa->add_policies(this->child_sa, tsi, tsr);
+ status = FAILED;
}
else
{
- status = this->child_sa->add_policies(this->child_sa, tsr, tsi);
+ if (this->initiator)
+ {
+ status = this->child_sa->add_policies(this->child_sa, tsi, tsr);
+ }
+ else
+ {
+ status = this->child_sa->add_policies(this->child_sa, tsr, tsi);
+ }
+ tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
+ tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");
+ }
+ else
+ {
+ charon->bus->child_derived_keys(charon->bus, this->child_sa,
+ this->initiator, encr_i, encr_r,
+ integ_i, integ_r);
+ }
}
- tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
- tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
+ chunk_clear(&integ_i);
+ chunk_clear(&integ_r);
+ chunk_clear(&encr_i);
+ chunk_clear(&encr_r);
+
if (status != SUCCESS)
{
- DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");
return FALSE;
}
uint16_t key_size, prf_plus_t *prf_plus)
{
aead_t *aead_i, *aead_r;
- chunk_t key = chunk_empty;
+ chunk_t sk_ei = chunk_empty, sk_er = chunk_empty;
u_int salt_size;
switch (alg)
{
goto failure;
}
- if (!prf_plus->allocate_bytes(prf_plus, key_size, &key))
+ if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_ei))
{
goto failure;
}
- DBG4(DBG_IKE, "Sk_ei secret %B", &key);
- if (!aead_i->set_key(aead_i, key))
+ DBG4(DBG_IKE, "Sk_ei secret %B", &sk_ei);
+ if (!aead_i->set_key(aead_i, sk_ei))
{
goto failure;
}
- chunk_clear(&key);
- if (!prf_plus->allocate_bytes(prf_plus, key_size, &key))
+ if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_er))
{
goto failure;
}
- DBG4(DBG_IKE, "Sk_er secret %B", &key);
- if (!aead_r->set_key(aead_r, key))
+ DBG4(DBG_IKE, "Sk_er secret %B", &sk_er);
+ if (!aead_r->set_key(aead_r, sk_er))
{
goto failure;
}
this->aead_out = aead_r;
}
aead_i = aead_r = NULL;
+ charon->bus->ike_derived_keys(charon->bus, sk_ei, sk_er, chunk_empty,
+ chunk_empty);
failure:
DESTROY_IF(aead_i);
DESTROY_IF(aead_r);
- chunk_clear(&key);
+ chunk_clear(&sk_ei);
+ chunk_clear(&sk_er);
return this->aead_in && this->aead_out;
}
signer_t *signer_i, *signer_r;
iv_gen_t *ivg_i, *ivg_r;
size_t key_size;
- chunk_t key = chunk_empty;
+ chunk_t sk_ei = chunk_empty, sk_er = chunk_empty,
+ sk_ai = chunk_empty, sk_ar = chunk_empty;
signer_i = lib->crypto->create_signer(lib->crypto, int_alg);
signer_r = lib->crypto->create_signer(lib->crypto, int_alg);
/* SK_ai/SK_ar used for integrity protection */
key_size = signer_i->get_key_size(signer_i);
- if (!prf_plus->allocate_bytes(prf_plus, key_size, &key))
+ if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_ai))
{
goto failure;
}
- DBG4(DBG_IKE, "Sk_ai secret %B", &key);
- if (!signer_i->set_key(signer_i, key))
+ DBG4(DBG_IKE, "Sk_ai secret %B", &sk_ai);
+ if (!signer_i->set_key(signer_i, sk_ai))
{
goto failure;
}
- chunk_clear(&key);
- if (!prf_plus->allocate_bytes(prf_plus, key_size, &key))
+ if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_ar))
{
goto failure;
}
- DBG4(DBG_IKE, "Sk_ar secret %B", &key);
- if (!signer_r->set_key(signer_r, key))
+ DBG4(DBG_IKE, "Sk_ar secret %B", &sk_ar);
+ if (!signer_r->set_key(signer_r, sk_ar))
{
goto failure;
}
- chunk_clear(&key);
/* SK_ei/SK_er used for encryption */
key_size = crypter_i->get_key_size(crypter_i);
- if (!prf_plus->allocate_bytes(prf_plus, key_size, &key))
+ if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_ei))
{
goto failure;
}
- DBG4(DBG_IKE, "Sk_ei secret %B", &key);
- if (!crypter_i->set_key(crypter_i, key))
+ DBG4(DBG_IKE, "Sk_ei secret %B", &sk_ei);
+ if (!crypter_i->set_key(crypter_i, sk_ei))
{
goto failure;
}
- chunk_clear(&key);
- if (!prf_plus->allocate_bytes(prf_plus, key_size, &key))
+ if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_er))
{
goto failure;
}
- DBG4(DBG_IKE, "Sk_er secret %B", &key);
- if (!crypter_r->set_key(crypter_r, key))
+ DBG4(DBG_IKE, "Sk_er secret %B", &sk_er);
+ if (!crypter_r->set_key(crypter_r, sk_er))
{
goto failure;
}
}
signer_i = signer_r = NULL;
crypter_i = crypter_r = NULL;
+ charon->bus->ike_derived_keys(charon->bus, sk_ei, sk_er, sk_ai, sk_ar);
failure:
- chunk_clear(&key);
+ chunk_clear(&sk_ai);
+ chunk_clear(&sk_ar);
+ chunk_clear(&sk_ei);
+ chunk_clear(&sk_er);
DESTROY_IF(signer_i);
DESTROY_IF(signer_r);
DESTROY_IF(crypter_i);
FALSE, this->tfcv3, my_ts, other_ts);
}
}
- chunk_clear(&integ_i);
- chunk_clear(&integ_r);
- chunk_clear(&encr_i);
- chunk_clear(&encr_r);
if (status_i != SUCCESS || status_o != SUCCESS)
{
(status_o != SUCCESS) ? "outbound " : "");
charon->bus->alert(charon->bus, ALERT_INSTALL_CHILD_SA_FAILED,
this->child_sa);
- return FAILED;
- }
-
- if (this->initiator)
- {
- status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts);
+ status = FAILED;
}
else
{
- /* use a copy of the traffic selectors, as the POST hook should not
- * change payloads */
- my_ts = this->tsr->clone_offset(this->tsr,
+ if (this->initiator)
+ {
+ status = this->child_sa->add_policies(this->child_sa,
+ my_ts, other_ts);
+ }
+ else
+ {
+ /* use a copy of the traffic selectors, as the POST hook should not
+ * change payloads */
+ my_ts = this->tsr->clone_offset(this->tsr,
offsetof(traffic_selector_t, clone));
- other_ts = this->tsi->clone_offset(this->tsi,
+ other_ts = this->tsi->clone_offset(this->tsi,
offsetof(traffic_selector_t, clone));
- charon->bus->narrow(charon->bus, this->child_sa,
- NARROW_RESPONDER_POST, my_ts, other_ts);
- if (my_ts->get_count(my_ts) == 0 || other_ts->get_count(other_ts) == 0)
+ charon->bus->narrow(charon->bus, this->child_sa,
+ NARROW_RESPONDER_POST, my_ts, other_ts);
+ if (my_ts->get_count(my_ts) == 0 ||
+ other_ts->get_count(other_ts) == 0)
+ {
+ status = FAILED;
+ }
+ else
+ {
+ status = this->child_sa->add_policies(this->child_sa,
+ my_ts, other_ts);
+ }
+ my_ts->destroy_offset(my_ts,
+ offsetof(traffic_selector_t, destroy));
+ other_ts->destroy_offset(other_ts,
+ offsetof(traffic_selector_t, destroy));
+ }
+ if (status != SUCCESS)
{
- status = FAILED;
+ DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");
+ charon->bus->alert(charon->bus, ALERT_INSTALL_CHILD_POLICY_FAILED,
+ this->child_sa);
+ status = NOT_FOUND;
}
else
{
- status = this->child_sa->add_policies(this->child_sa,
- my_ts, other_ts);
+ charon->bus->child_derived_keys(charon->bus, this->child_sa,
+ this->initiator, encr_i, encr_r,
+ integ_i, integ_r);
}
- my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
- other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
}
+ chunk_clear(&integ_i);
+ chunk_clear(&integ_r);
+ chunk_clear(&encr_i);
+ chunk_clear(&encr_r);
+
if (status != SUCCESS)
{
- DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");
- charon->bus->alert(charon->bus, ALERT_INSTALL_CHILD_POLICY_FAILED,
- this->child_sa);
- return NOT_FOUND;
+ return status;
}
charon->bus->child_keys(charon->bus, this->child_sa, this->initiator,