Merge commit 'derived-keys'
authorTobias Brunner <tobias@strongswan.org>
Tue, 4 Oct 2016 08:02:12 +0000 (10:02 +0200)
committerTobias Brunner <tobias@strongswan.org>
Tue, 4 Oct 2016 08:06:00 +0000 (10:06 +0200)
Adds new listener hooks that work similar to the existing ike|child_keys
hooks but receive the derived IKE and CHILD_SA keys.

src/libcharon/bus/bus.c
src/libcharon/bus/bus.h
src/libcharon/bus/listeners/listener.h
src/libcharon/sa/ikev1/keymat_v1.c
src/libcharon/sa/ikev1/tasks/quick_mode.c
src/libcharon/sa/ikev2/keymat_v2.c
src/libcharon/sa/ikev2/tasks/child_create.c

index ba44a22..6b3cea8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2015 Tobias Brunner
+ * Copyright (C) 2011-2016 Tobias Brunner
  * Copyright (C) 2006 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -601,6 +601,38 @@ METHOD(bus_t, ike_keys, void,
        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)
@@ -633,6 +665,39 @@ METHOD(bus_t, child_keys, void,
        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)
 {
@@ -1069,7 +1134,9 @@ bus_t *bus_create()
                        .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,
index 305cbe4..1e810a4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2015 Tobias Brunner
+ * Copyright (C) 2012-2016 Tobias Brunner
  * Copyright (C) 2006-2009 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -349,8 +349,8 @@ struct bus_t {
         * @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)
         */
@@ -359,18 +359,43 @@ struct bus_t {
                                         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
index be2726e..be0dfbe 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2015 Tobias Brunner
+ * Copyright (C) 2011-2016 Tobias Brunner
  * Copyright (C) 2009 Martin Willi
  * Hochschule fuer Technik Rapperswil
  *
@@ -84,8 +84,8 @@ struct listener_t {
         * @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
@@ -95,14 +95,26 @@ struct listener_t {
                                         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,
@@ -110,6 +122,22 @@ struct listener_t {
                                           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
index be6b03b..d1d4cbd 100644 (file)
@@ -75,11 +75,6 @@ struct private_keymat_v1_t {
        hasher_t *hasher;
 
        /**
-        * Key used for authentication during main mode
-        */
-       chunk_t skeyid;
-
-       /**
         * Key to derive key material from for non-ISAKMP SAs, rekeying
         */
        chunk_t skeyid_d;
@@ -269,12 +264,12 @@ static bool expand_skeyid_e(chunk_t skeyid_e, size_t key_size, prf_t *prf,
  * Create a simple implementation of the aead_t interface which only encrypts
  * or decrypts data.
  */
-static aead_t *create_aead(proposal_t *proposal, prf_t *prf, chunk_t skeyid_e)
+static aead_t *create_aead(proposal_t *proposal, prf_t *prf, chunk_t skeyid_e,
+                                                  chunk_t *ka)
 {
        private_aead_t *this;
        uint16_t alg, key_size;
        crypter_t *crypter;
-       chunk_t ka;
 
        if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg,
                                                                 &key_size))
@@ -292,17 +287,16 @@ static aead_t *create_aead(proposal_t *proposal, prf_t *prf, chunk_t skeyid_e)
                return NULL;
        }
        key_size = crypter->get_key_size(crypter);
-       if (!expand_skeyid_e(skeyid_e, crypter->get_key_size(crypter), prf, &ka))
+       if (!expand_skeyid_e(skeyid_e, crypter->get_key_size(crypter), prf, ka))
        {
                return NULL;
        }
-       DBG4(DBG_IKE, "encryption key Ka %B", &ka);
-       if (!crypter->set_key(crypter, ka))
+       DBG4(DBG_IKE, "encryption key Ka %B", ka);
+       if (!crypter->set_key(crypter, *ka))
        {
-               chunk_clear(&ka);
+               chunk_clear(ka);
                return NULL;
        }
-       chunk_clear(&ka);
 
        INIT(this,
                .aead = {
@@ -392,7 +386,7 @@ METHOD(keymat_v1_t, derive_ike_keys, bool,
        auth_method_t auth, shared_key_t *shared_key)
 {
        chunk_t g_xy, g_xi, g_xr, dh_me, spi_i, spi_r, nonces, data, skeyid_e;
-       chunk_t skeyid;
+       chunk_t skeyid, ka;
        uint16_t alg;
 
        spi_i = chunk_alloca(sizeof(uint64_t));
@@ -550,11 +544,14 @@ METHOD(keymat_v1_t, derive_ike_keys, bool,
        }
        chunk_clear(&skeyid);
 
-       this->aead = create_aead(proposal, this->prf, skeyid_e);
+       this->aead = create_aead(proposal, this->prf, skeyid_e, &ka);
        if (!this->aead)
        {
                return FALSE;
        }
+       charon->bus->ike_derived_keys(charon->bus, ka, chunk_empty, this->skeyid_a,
+                                                                 chunk_empty);
+       chunk_clear(&ka);
        if (!this->hasher && !this->public.create_hasher(&this->public, proposal))
        {
                return FALSE;
index bbd1cb0..6b89641 100644 (file)
@@ -348,10 +348,6 @@ static bool install(private_quick_mode_t *this)
                                                                        this->initiator, FALSE, FALSE, tsr, tsi);
                }
        }
-       chunk_clear(&integ_i);
-       chunk_clear(&integ_r);
-       chunk_clear(&encr_i);
-       chunk_clear(&encr_r);
 
        if (status_i != SUCCESS || status_o != SUCCESS)
        {
@@ -361,22 +357,38 @@ static bool install(private_quick_mode_t *this)
                        (status_o != SUCCESS) ? "outbound " : "");
                tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
                tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
-               return FALSE;
-       }
-
-       if (this->initiator)
-       {
-               status = this->child_sa->add_policies(this->child_sa, tsi, tsr);
+               status = FAILED;
        }
        else
        {
-               status = this->child_sa->add_policies(this->child_sa, tsr, tsi);
+               if (this->initiator)
+               {
+                       status = this->child_sa->add_policies(this->child_sa, tsi, tsr);
+               }
+               else
+               {
+                       status = this->child_sa->add_policies(this->child_sa, tsr, tsi);
+               }
+               tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
+               tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
+               if (status != SUCCESS)
+               {
+                       DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");
+               }
+               else
+               {
+                       charon->bus->child_derived_keys(charon->bus, this->child_sa,
+                                                                                       this->initiator, encr_i, encr_r,
+                                                                                       integ_i, integ_r);
+               }
        }
-       tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
-       tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
+       chunk_clear(&integ_i);
+       chunk_clear(&integ_r);
+       chunk_clear(&encr_i);
+       chunk_clear(&encr_r);
+
        if (status != SUCCESS)
        {
-               DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");
                return FALSE;
        }
 
index e373998..58efdba 100644 (file)
@@ -103,7 +103,7 @@ static bool derive_ike_aead(private_keymat_v2_t *this, uint16_t alg,
                                                        uint16_t key_size, prf_plus_t *prf_plus)
 {
        aead_t *aead_i, *aead_r;
-       chunk_t key = chunk_empty;
+       chunk_t sk_ei = chunk_empty, sk_er = chunk_empty;
        u_int salt_size;
 
        switch (alg)
@@ -146,23 +146,22 @@ static bool derive_ike_aead(private_keymat_v2_t *this, uint16_t alg,
        {
                goto failure;
        }
-       if (!prf_plus->allocate_bytes(prf_plus, key_size, &key))
+       if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_ei))
        {
                goto failure;
        }
-       DBG4(DBG_IKE, "Sk_ei secret %B", &key);
-       if (!aead_i->set_key(aead_i, key))
+       DBG4(DBG_IKE, "Sk_ei secret %B", &sk_ei);
+       if (!aead_i->set_key(aead_i, sk_ei))
        {
                goto failure;
        }
-       chunk_clear(&key);
 
-       if (!prf_plus->allocate_bytes(prf_plus, key_size, &key))
+       if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_er))
        {
                goto failure;
        }
-       DBG4(DBG_IKE, "Sk_er secret %B", &key);
-       if (!aead_r->set_key(aead_r, key))
+       DBG4(DBG_IKE, "Sk_er secret %B", &sk_er);
+       if (!aead_r->set_key(aead_r, sk_er))
        {
                goto failure;
        }
@@ -178,11 +177,14 @@ static bool derive_ike_aead(private_keymat_v2_t *this, uint16_t alg,
                this->aead_out = aead_r;
        }
        aead_i = aead_r = NULL;
+       charon->bus->ike_derived_keys(charon->bus, sk_ei, sk_er, chunk_empty,
+                                                                 chunk_empty);
 
 failure:
        DESTROY_IF(aead_i);
        DESTROY_IF(aead_r);
-       chunk_clear(&key);
+       chunk_clear(&sk_ei);
+       chunk_clear(&sk_er);
        return this->aead_in && this->aead_out;
 }
 
@@ -196,7 +198,8 @@ static bool derive_ike_traditional(private_keymat_v2_t *this, uint16_t enc_alg,
        signer_t *signer_i, *signer_r;
        iv_gen_t *ivg_i, *ivg_r;
        size_t key_size;
-       chunk_t key = chunk_empty;
+       chunk_t sk_ei = chunk_empty, sk_er = chunk_empty,
+                       sk_ai = chunk_empty, sk_ar = chunk_empty;
 
        signer_i = lib->crypto->create_signer(lib->crypto, int_alg);
        signer_r = lib->crypto->create_signer(lib->crypto, int_alg);
@@ -220,48 +223,45 @@ static bool derive_ike_traditional(private_keymat_v2_t *this, uint16_t enc_alg,
        /* SK_ai/SK_ar used for integrity protection */
        key_size = signer_i->get_key_size(signer_i);
 
-       if (!prf_plus->allocate_bytes(prf_plus, key_size, &key))
+       if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_ai))
        {
                goto failure;
        }
-       DBG4(DBG_IKE, "Sk_ai secret %B", &key);
-       if (!signer_i->set_key(signer_i, key))
+       DBG4(DBG_IKE, "Sk_ai secret %B", &sk_ai);
+       if (!signer_i->set_key(signer_i, sk_ai))
        {
                goto failure;
        }
-       chunk_clear(&key);
 
-       if (!prf_plus->allocate_bytes(prf_plus, key_size, &key))
+       if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_ar))
        {
                goto failure;
        }
-       DBG4(DBG_IKE, "Sk_ar secret %B", &key);
-       if (!signer_r->set_key(signer_r, key))
+       DBG4(DBG_IKE, "Sk_ar secret %B", &sk_ar);
+       if (!signer_r->set_key(signer_r, sk_ar))
        {
                goto failure;
        }
-       chunk_clear(&key);
 
        /* SK_ei/SK_er used for encryption */
        key_size = crypter_i->get_key_size(crypter_i);
 
-       if (!prf_plus->allocate_bytes(prf_plus, key_size, &key))
+       if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_ei))
        {
                goto failure;
        }
-       DBG4(DBG_IKE, "Sk_ei secret %B", &key);
-       if (!crypter_i->set_key(crypter_i, key))
+       DBG4(DBG_IKE, "Sk_ei secret %B", &sk_ei);
+       if (!crypter_i->set_key(crypter_i, sk_ei))
        {
                goto failure;
        }
-       chunk_clear(&key);
 
-       if (!prf_plus->allocate_bytes(prf_plus, key_size, &key))
+       if (!prf_plus->allocate_bytes(prf_plus, key_size, &sk_er))
        {
                goto failure;
        }
-       DBG4(DBG_IKE, "Sk_er secret %B", &key);
-       if (!crypter_r->set_key(crypter_r, key))
+       DBG4(DBG_IKE, "Sk_er secret %B", &sk_er);
+       if (!crypter_r->set_key(crypter_r, sk_er))
        {
                goto failure;
        }
@@ -284,9 +284,13 @@ static bool derive_ike_traditional(private_keymat_v2_t *this, uint16_t enc_alg,
        }
        signer_i = signer_r = NULL;
        crypter_i = crypter_r = NULL;
+       charon->bus->ike_derived_keys(charon->bus, sk_ei, sk_er, sk_ai, sk_ar);
 
 failure:
-       chunk_clear(&key);
+       chunk_clear(&sk_ai);
+       chunk_clear(&sk_ar);
+       chunk_clear(&sk_ei);
+       chunk_clear(&sk_er);
        DESTROY_IF(signer_i);
        DESTROY_IF(signer_r);
        DESTROY_IF(crypter_i);
index 64a8285..71cb6b8 100644 (file)
@@ -666,10 +666,6 @@ static status_t select_and_install(private_child_create_t *this,
                                                        FALSE, this->tfcv3, my_ts, other_ts);
                }
        }
-       chunk_clear(&integ_i);
-       chunk_clear(&integ_r);
-       chunk_clear(&encr_i);
-       chunk_clear(&encr_r);
 
        if (status_i != SUCCESS || status_o != SUCCESS)
        {
@@ -679,41 +675,62 @@ static status_t select_and_install(private_child_create_t *this,
                        (status_o != SUCCESS) ? "outbound " : "");
                charon->bus->alert(charon->bus, ALERT_INSTALL_CHILD_SA_FAILED,
                                                   this->child_sa);
-               return FAILED;
-       }
-
-       if (this->initiator)
-       {
-               status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts);
+               status = FAILED;
        }
        else
        {
-               /* use a copy of the traffic selectors, as the POST hook should not
-                * change payloads */
-               my_ts = this->tsr->clone_offset(this->tsr,
+               if (this->initiator)
+               {
+                       status = this->child_sa->add_policies(this->child_sa,
+                                                                                                 my_ts, other_ts);
+               }
+               else
+               {
+                       /* use a copy of the traffic selectors, as the POST hook should not
+                        * change payloads */
+                       my_ts = this->tsr->clone_offset(this->tsr,
                                                                                offsetof(traffic_selector_t, clone));
-               other_ts = this->tsi->clone_offset(this->tsi,
+                       other_ts = this->tsi->clone_offset(this->tsi,
                                                                                offsetof(traffic_selector_t, clone));
-               charon->bus->narrow(charon->bus, this->child_sa,
-                                                       NARROW_RESPONDER_POST, my_ts, other_ts);
-               if (my_ts->get_count(my_ts) == 0 || other_ts->get_count(other_ts) == 0)
+                       charon->bus->narrow(charon->bus, this->child_sa,
+                                                               NARROW_RESPONDER_POST, my_ts, other_ts);
+                       if (my_ts->get_count(my_ts) == 0 ||
+                               other_ts->get_count(other_ts) == 0)
+                       {
+                               status = FAILED;
+                       }
+                       else
+                       {
+                               status = this->child_sa->add_policies(this->child_sa,
+                                                                                                         my_ts, other_ts);
+                       }
+                       my_ts->destroy_offset(my_ts,
+                                                                 offsetof(traffic_selector_t, destroy));
+                       other_ts->destroy_offset(other_ts,
+                                                                 offsetof(traffic_selector_t, destroy));
+               }
+               if (status != SUCCESS)
                {
-                       status = FAILED;
+                       DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");
+                       charon->bus->alert(charon->bus, ALERT_INSTALL_CHILD_POLICY_FAILED,
+                                                          this->child_sa);
+                       status = NOT_FOUND;
                }
                else
                {
-                       status = this->child_sa->add_policies(this->child_sa,
-                                                                                                  my_ts, other_ts);
+                       charon->bus->child_derived_keys(charon->bus, this->child_sa,
+                                                                                       this->initiator, encr_i, encr_r,
+                                                                                       integ_i, integ_r);
                }
-               my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
-               other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
        }
+       chunk_clear(&integ_i);
+       chunk_clear(&integ_r);
+       chunk_clear(&encr_i);
+       chunk_clear(&encr_r);
+
        if (status != SUCCESS)
        {
-               DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");
-               charon->bus->alert(charon->bus, ALERT_INSTALL_CHILD_POLICY_FAILED,
-                                                  this->child_sa);
-               return NOT_FOUND;
+               return status;
        }
 
        charon->bus->child_keys(charon->bus, this->child_sa, this->initiator,