]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
Added support to sync IKEv1 SAs key material in HA plugin
authorMartin Willi <martin@revosec.ch>
Thu, 19 Jan 2012 10:11:22 +0000 (11:11 +0100)
committerMartin Willi <martin@revosec.ch>
Tue, 20 Mar 2012 16:31:37 +0000 (17:31 +0100)
src/libcharon/plugins/ha/ha_dispatcher.c
src/libcharon/plugins/ha/ha_ike.c
src/libcharon/plugins/ha/ha_message.c
src/libcharon/plugins/ha/ha_message.h

index f0e6e5ecfbbd6b1c4623750ef703c8e6e300f572..b20ced473a8ba6ee60243fca1f39a47c15ac99dd 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <daemon.h>
 #include <sa/ikev2/keymat_v2.h>
+#include <sa/ikev1/keymat_v1.h>
 #include <processing/jobs/callback_job.h>
 
 typedef struct private_ha_dispatcher_t private_ha_dispatcher_t;
@@ -77,6 +78,11 @@ struct ha_diffie_hellman_t {
         * Shared secret
         */
        chunk_t secret;
+
+       /**
+        * Own public value
+        */
+       chunk_t pub;
 };
 
 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;
 }
 
+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,
        ha_diffie_hellman_t *this)
 {
@@ -95,16 +107,18 @@ METHOD(diffie_hellman_t, dh_destroy, void,
 /**
  * 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;
 
        INIT(this,
                .dh = {
                        .get_shared_secret = _dh_get_shared_secret,
+                       .get_my_public_value = _dh_get_my_public_value,
                        .destroy = _dh_destroy,
                },
                .secret = secret,
+               .pub = pub,
        );
 
        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;
        enumerator_t *enumerator;
        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;
        chunk_t nonce_i = chunk_empty, nonce_r = 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;
 
        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:
                                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;
                        case HA_IKE_REKEY_ID:
                                old_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
                                                                                                                  value.ike_sa_id);
                                break;
+                       case HA_IKE_VERSION:
+                               version = value.u8;
+                               break;
                        case HA_NONCE_I:
                                nonce_i = value.chunk;
                                break;
@@ -146,6 +165,15 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
                        case HA_SECRET:
                                secret = value.chunk;
                                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:
                                old_skd = value.chunk;
                                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);
                }
                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)
                {
                        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,
                                                        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);
                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 encr_i, integ_i, encr_r, integ_r;
        linked_list_t *local_ts, *remote_ts;
-       diffie_hellman_t *dh;
+       diffie_hellman_t *dh = NULL;
 
        enumerator = message->create_attribute_enumerator(message);
        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, 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)
        {
                keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa);
 
-               ok = keymat_v2->derive_child_keys(keymat_v2,
-                                               proposal, secret.ptr ? dh : NULL, nonce_i, nonce_r,
-                                               &encr_i, &integ_i, &encr_r, &integ_r);
+               ok = keymat_v2->derive_child_keys(keymat_v2, proposal, dh,
+                                               nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r);
+       }
+       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);
        }
-       dh->destroy(dh);
+       DESTROY_IF(dh);
        if (!ok)
        {
                DBG1(DBG_CHD, "HA CHILD_SA key derivation failed");
index bcdd09b3e4d6564f1e4261d9b6957da5a1651970..bee6e2a6d3355a13b09b2781102b64b492cd38d2 100644 (file)
@@ -89,6 +89,7 @@ METHOD(listener_t, ike_keys, bool,
        }
 
        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));
 
        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_SECRET, 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->cache->cache(this->cache, ike_sa, m);
index f98f78dd426499da545398ad5f0efde7160fcd3b..7df705a8a5a9d99f5b04fe37d9d553f88ce5a8b2 100644 (file)
@@ -213,6 +213,7 @@ METHOD(ha_message_t, add_attribute, void,
                        break;
                }
                /* u_int8_t */
+               case HA_IKE_VERSION:
                case HA_INITIATOR:
                case HA_IPSEC_MODE:
                case HA_IPCOMP:
@@ -263,6 +264,9 @@ METHOD(ha_message_t, add_attribute, void,
                case HA_NONCE_I:
                case HA_NONCE_R:
                case HA_SECRET:
+               case HA_LOCAL_DH:
+               case HA_REMOTE_DH:
+               case HA_PSK:
                case HA_OLD_SKD:
                {
                        chunk_t chunk;
@@ -426,6 +430,7 @@ METHOD(enumerator_t, attribute_enumerate, bool,
                        return TRUE;
                }
                /* u_int8_t */
+               case HA_IKE_VERSION:
                case HA_INITIATOR:
                case HA_IPSEC_MODE:
                case HA_IPCOMP:
@@ -479,6 +484,9 @@ METHOD(enumerator_t, attribute_enumerate, bool,
                case HA_NONCE_I:
                case HA_NONCE_R:
                case HA_SECRET:
+               case HA_LOCAL_DH:
+               case HA_REMOTE_DH:
+               case HA_PSK:
                case HA_OLD_SKD:
                {
                        size_t len;
index 1f8eabd629c5a600f637d0d5d3711a963323fc23..b937d39b506c5111426f3ff6382d37d15ecd9e9c 100644 (file)
@@ -76,7 +76,7 @@ extern enum_name_t *ha_message_type_names;
 enum ha_message_attribute_t {
        /** ike_sa_id_t*, to identify IKE_SA */
        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,
        /** identification_t*, local identity */
        HA_LOCAL_ID,
@@ -142,6 +142,14 @@ enum ha_message_attribute_t {
        HA_SEGMENT,
        /** u_int16_t, Extended Sequence numbers */
        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,
 };
 
 /**