]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
wip: keymat_v2: Cache initial IKE messages for auth octets
authorTobias Brunner <tobias@strongswan.org>
Tue, 10 Jul 2018 14:26:58 +0000 (16:26 +0200)
committerTobias Brunner <tobias@strongswan.org>
Tue, 14 May 2019 08:54:45 +0000 (10:54 +0200)
This avoids pre-generating the message to be sent and supports fragments
as used for IKE_AUX.

In scenarios with IKE_AUX this basically changes the auth octets as follows:

  InitiatorSignedOctets = RealMessage1(INIT) | RealMessage3(AUX) | ...
                          NonceRData | MACedIDForI

and

  ResponderSignedOctets = RealMessage2(INIT) | RealMessage4(AUX) | ...
                          NonceIData | MACedIDForR

wip: Since this requires keeping around quite some data, alternatives would
be to hash the message (with some negotiated or fixed hash function) or
applying the PRF (if it is QC-safe, e.g. with a zero key or the ones we
derived from DH).

src/charon-tkm/src/tkm/tkm_keymat.c
src/libcharon/Android.mk
src/libcharon/Makefile.am
src/libcharon/sa/ikev2/init_packet_cache.c [new file with mode: 0644]
src/libcharon/sa/ikev2/init_packet_cache.h [new file with mode: 0644]
src/libcharon/sa/ikev2/keymat_v2.c
src/libcharon/sa/ikev2/keymat_v2.h
src/libcharon/sa/ikev2/task_manager_v2.c
src/libcharon/sa/ikev2/tasks/ike_auth.c

index 937bed8d92631ea2eadaf9dde3f911555dc255f0..3685ac4163e6c57695dbb8a017bd306446ed8799 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Tobias Brunner
+ * Copyright (C) 2015-2018 Tobias Brunner
  * Copyright (C) 2012 Reto Buerki
  * Copyright (C) 2012 Adrian-Ken Rueegsegger
  * HSR Hochschule fuer Technik Rapperswil
@@ -18,6 +18,7 @@
 #include <daemon.h>
 #include <tkm/constants.h>
 #include <tkm/client.h>
+#include <sa/ikev2/init_packet_cache.h>
 #include <crypto/hashers/hash_algorithm_set.h>
 
 #include "tkm.h"
@@ -77,6 +78,11 @@ struct private_tkm_keymat_t {
         * Set of hash algorithms supported by peer for signature authentication
         */
        hash_algorithm_set_t *hash_algorithms;
+
+       /**
+        * Initial packet data
+        */
+       init_packet_cache_t *packets;
 };
 
 /**
@@ -383,6 +389,36 @@ METHOD(keymat_t, get_aead, aead_t*,
        return in ? this->aead_in : this->aead_out;
 }
 
+METHOD(keymat_v2_t, add_packet, void,
+       private_tkm_keymat_t *this, bool sent, uint32_t mid, uint16_t fnr,
+       chunk_t data)
+{
+       if (!this->packets)
+       {
+               this->packets = init_packet_cache_create();
+       }
+       this->packets->add_packet(this->packets, sent, mid, fnr, data);
+}
+
+METHOD(keymat_v2_t, get_packets, chunk_t,
+       private_tkm_keymat_t *this, bool sent)
+{
+       if (this->packets)
+       {
+               return this->packets->get_packets(this->packets, sent);
+       }
+       return chunk_empty;
+}
+
+METHOD(keymat_v2_t, clear_packets, void,
+       private_tkm_keymat_t *this)
+{
+       if (this->packets)
+       {
+               this->packets->clear_packets(this->packets);
+       }
+}
+
 METHOD(keymat_v2_t, get_auth_octets, bool,
        private_tkm_keymat_t *this, bool verify, chunk_t ike_sa_init,
        chunk_t nonce, chunk_t ppk, identification_t *id, char reserved[3],
@@ -473,6 +509,7 @@ METHOD(keymat_t, destroy, void,
                }
        }
 
+       DESTROY_IF(this->packets);
        DESTROY_IF(this->hash_algorithms);
        DESTROY_IF(this->aead_in);
        DESTROY_IF(this->aead_out);
@@ -527,6 +564,9 @@ tkm_keymat_t *tkm_keymat_create(bool initiator)
                                .derive_ike_keys_ppk = (void*)return_false,
                                .derive_child_keys = _derive_child_keys,
                                .get_skd = _get_skd,
+                               .add_packet = _add_packet,
+                               .get_packets = _get_packets,
+                               .clear_packets = _clear_packets,
                                .get_auth_octets = _get_auth_octets,
                                .get_psk_sig = _get_psk_sig,
                                .add_hash_algorithm = _add_hash_algorithm,
index 2c0e6d77cf4270cc59b0e5c5f65dd225048730b2..5deee2f8ac91ae78e8b3cd3cd195803f4aa6c26e 100644 (file)
@@ -92,6 +92,7 @@ sa/task.c sa/task.h
 libcharon_la_SOURCES += \
 sa/ikev2/keymat_v2.c sa/ikev2/keymat_v2.h \
 sa/ikev2/task_manager_v2.c sa/ikev2/task_manager_v2.h \
+sa/ikev2/init_packet_cache.c sa/ikev2/init_packet_cache.h \
 sa/ikev2/authenticators/eap_authenticator.c sa/ikev2/authenticators/eap_authenticator.h \
 sa/ikev2/authenticators/psk_authenticator.c sa/ikev2/authenticators/psk_authenticator.h \
 sa/ikev2/authenticators/pubkey_authenticator.c sa/ikev2/authenticators/pubkey_authenticator.h \
index 799a9a07247831704ec3c274574354a4b47d70eb..404ba3ed0195ad8eb0bbcdb3f7d847c3288de574 100644 (file)
@@ -91,6 +91,7 @@ if USE_IKEV2
 libcharon_la_SOURCES += \
 sa/ikev2/keymat_v2.c sa/ikev2/keymat_v2.h \
 sa/ikev2/task_manager_v2.c sa/ikev2/task_manager_v2.h \
+sa/ikev2/init_packet_cache.c sa/ikev2/init_packet_cache.h \
 sa/ikev2/authenticators/eap_authenticator.c sa/ikev2/authenticators/eap_authenticator.h \
 sa/ikev2/authenticators/psk_authenticator.c sa/ikev2/authenticators/psk_authenticator.h \
 sa/ikev2/authenticators/pubkey_authenticator.c sa/ikev2/authenticators/pubkey_authenticator.h \
diff --git a/src/libcharon/sa/ikev2/init_packet_cache.c b/src/libcharon/sa/ikev2/init_packet_cache.c
new file mode 100644 (file)
index 0000000..43f2a6c
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "init_packet_cache.h"
+
+#include <daemon.h>
+#include <bio/bio_writer.h>
+#include <collections/array.h>
+
+typedef struct private_init_packet_cache_t private_init_packet_cache_t;
+
+/**
+ * Private data
+ */
+struct private_init_packet_cache_t {
+
+       /**
+        * Public interface.
+        */
+       init_packet_cache_t public;
+
+       /**
+        * Cached packet data
+        */
+       array_t *packets;
+};
+
+/**
+ * Data for an initial packet
+ */
+typedef struct {
+       /** Message ID */
+       uint32_t mid;
+       /** Fragment number */
+       uint16_t fnr;
+       /** Whether the packet was sent, or received */
+       bool sent;
+       /** Actual data */
+       chunk_t data;
+} packet_data_t;
+
+/**
+ * Destroy cached data
+ */
+static void packet_destroy(packet_data_t *this)
+{
+       chunk_free(&this->data);
+       free(this);
+}
+
+METHOD(init_packet_cache_t, add_packet, void,
+       private_init_packet_cache_t *this, bool sent, uint32_t mid, uint16_t fnr,
+       chunk_t data)
+{
+       packet_data_t *packet;
+       int i, insert_at = -1;
+
+       for (i = 0; i < array_count(this->packets); i++)
+       {
+               array_get(this->packets, i, &packet);
+               if (packet->sent != sent)
+               {
+                       continue;
+               }
+               if (packet->mid == mid)
+               {
+                       if (packet->fnr == fnr)
+                       {
+                               /* replace current data */
+                               chunk_free(&packet->data);
+                               packet->data = chunk_clone(data);
+                               return;
+                       }
+                       if (packet->fnr > fnr)
+                       {
+                               insert_at = i;
+                               break;
+                       }
+                       continue;
+               }
+               if (packet->mid > mid)
+               {
+                       insert_at = i;
+                       break;
+               }
+       }
+       INIT(packet,
+               .mid = mid,
+               .fnr = fnr,
+               .sent = sent,
+               .data = chunk_clone(data),
+       );
+       array_insert_create(&this->packets, insert_at, packet);
+}
+
+METHOD(init_packet_cache_t, get_packets, chunk_t,
+       private_init_packet_cache_t *this, bool sent)
+{
+       packet_data_t *packet;
+       bio_writer_t *writer;
+       chunk_t data;
+       uint32_t len = 0;
+       int i;
+
+       for (i = 0; i < array_count(this->packets); i++)
+       {
+               array_get(this->packets, i, &packet);
+               if (packet->sent == sent)
+               {
+                       len += packet->data.len;
+               }
+       }
+
+       writer = bio_writer_create(len);
+       for (i = 0; i < array_count(this->packets); i++)
+       {
+               array_get(this->packets, i, &packet);
+               if (packet->sent == sent)
+               {
+                       writer->write_data(writer, packet->data);
+               }
+       }
+       data = writer->extract_buf(writer);
+       writer->destroy(writer);
+       return data;
+}
+
+METHOD(init_packet_cache_t, clear_packets, void,
+       private_init_packet_cache_t *this)
+{
+       array_destroy_function(this->packets, (void*)packet_destroy, NULL);
+       this->packets = NULL;
+}
+
+METHOD(init_packet_cache_t, destroy, void,
+       private_init_packet_cache_t *this)
+{
+       clear_packets(this);
+       free(this);
+}
+
+/*
+ * Described in header
+ */
+init_packet_cache_t *init_packet_cache_create()
+{
+       private_init_packet_cache_t *this;
+
+       INIT(this,
+               .public = {
+                       .add_packet = _add_packet,
+                       .get_packets = _get_packets,
+                       .clear_packets = _clear_packets,
+                       .destroy = _destroy,
+               },
+       );
+
+       return &this->public;
+}
diff --git a/src/libcharon/sa/ikev2/init_packet_cache.h b/src/libcharon/sa/ikev2/init_packet_cache.h
new file mode 100644 (file)
index 0000000..8a20bf9
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup init_packet_cache init_packet_cache
+ * @{ @ingroup ikev2
+ */
+
+#ifndef INIT_PACKET_CACHE_H_
+#define INIT_PACKET_CACHE_H_
+
+#include <library.h>
+
+typedef struct init_packet_cache_t init_packet_cache_t;
+
+/**
+ * Helper class to cache packet data of initial IKE messages for use in auth
+ * octets.
+ */
+struct init_packet_cache_t {
+
+       /**
+        * Cache data of an initial IKE packet (IKE_SA_INIT/IKE_AUX) for use in the
+        * auth octets.
+        *
+        * @param sent                  TRUE if message was sent, FALSE if received
+        * @param mid                   message ID of the packet
+        * @param fnr                   fragment number of the packet
+        * @param data                  IKE message or fragment data (cloned)
+        */
+       void (*add_packet)(init_packet_cache_t *this, bool sent, uint32_t mid,
+                                          uint16_t fnr, chunk_t data);
+
+       /**
+        * Get cached data of all initial IKE packets for use in the auth octets.
+        *
+        * @param sent                  TRUE for sent packets, FALSE for received packets
+        * @return                              concatenated packet data (allocated)
+        */
+       chunk_t (*get_packets)(init_packet_cache_t *this, bool sent);
+
+       /**
+        * Clear all cached initial IKE packet data.
+        */
+       void (*clear_packets)(init_packet_cache_t *this);
+
+       /**
+        * Destroy this instance.
+        */
+       void (*destroy)(init_packet_cache_t *this);
+};
+
+/**
+ * Create a init_packet_cache_t instance.
+ *
+ * @return                                     created instance
+ */
+init_packet_cache_t *init_packet_cache_create();
+
+#endif /** INIT_PACKET_CACHE_H_ @}*/
index 7ac36e7cfeb1ec0625d9dbc2929312b90cd27c69..174e957506e660074ecd38e345d4b708cccace5c 100644 (file)
@@ -17,6 +17,7 @@
 #include "keymat_v2.h"
 
 #include <daemon.h>
+#include <sa/ikev2/init_packet_cache.h>
 #include <crypto/prf_plus.h>
 #include <crypto/hashers/hash_algorithm_set.h>
 
@@ -76,6 +77,11 @@ struct private_keymat_v2_t {
         * Set of hash algorithms supported by peer for signature authentication
         */
        hash_algorithm_set_t *hash_algorithms;
+
+       /**
+        * Initial packet data
+        */
+       init_packet_cache_t *packets;
 };
 
 METHOD(keymat_t, get_version, ike_version_t,
@@ -741,8 +747,38 @@ METHOD(keymat_t, get_aead, aead_t*,
        return in ? this->aead_in : this->aead_out;
 }
 
+METHOD(keymat_v2_t, add_packet, void,
+       private_keymat_v2_t *this, bool sent, uint32_t mid, uint16_t fnr,
+       chunk_t data)
+{
+       if (!this->packets)
+       {
+               this->packets = init_packet_cache_create();
+       }
+       this->packets->add_packet(this->packets, sent, mid, fnr, data);
+}
+
+METHOD(keymat_v2_t, get_packets, chunk_t,
+       private_keymat_v2_t *this, bool sent)
+{
+       if (this->packets)
+       {
+               return this->packets->get_packets(this->packets, sent);
+       }
+       return chunk_empty;
+}
+
+METHOD(keymat_v2_t, clear_packets, void,
+       private_keymat_v2_t *this)
+{
+       if (this->packets)
+       {
+               this->packets->clear_packets(this->packets);
+       }
+}
+
 METHOD(keymat_v2_t, get_auth_octets, bool,
-       private_keymat_v2_t *this, bool verify, chunk_t ike_sa_init,
+       private_keymat_v2_t *this, bool verify, chunk_t packets,
        chunk_t nonce, chunk_t ppk, identification_t *id, char reserved[3],
        chunk_t *octets, array_t *schemes)
 {
@@ -775,7 +811,7 @@ METHOD(keymat_v2_t, get_auth_octets, bool,
                return FALSE;
        }
        chunk_clear(&skp_ppk);
-       *octets = chunk_cat("ccm", ike_sa_init, nonce, chunk);
+       *octets = chunk_cat("ccm", packets, nonce, chunk);
        DBG3(DBG_IKE, "octets = message + nonce + prf(Sk_px, IDx') %B", octets);
        return TRUE;
 }
@@ -787,7 +823,7 @@ METHOD(keymat_v2_t, get_auth_octets, bool,
 #define IKEV2_KEY_PAD_LENGTH 17
 
 METHOD(keymat_v2_t, get_psk_sig, bool,
-       private_keymat_v2_t *this, bool verify, chunk_t ike_sa_init, chunk_t nonce,
+       private_keymat_v2_t *this, bool verify, chunk_t packets, chunk_t nonce,
        chunk_t secret, chunk_t ppk, identification_t *id, char reserved[3],
        chunk_t *sig)
 {
@@ -807,7 +843,7 @@ METHOD(keymat_v2_t, get_psk_sig, bool,
                        secret = skp_ppk;
                }
        }
-       if (!get_auth_octets(this, verify, ike_sa_init, nonce, ppk, id, reserved,
+       if (!get_auth_octets(this, verify, packets, nonce, ppk, id, reserved,
                                                 &octets, NULL))
        {
                goto failure;
@@ -834,7 +870,6 @@ failure:
        chunk_free(&octets);
        chunk_free(&key);
        return success;
-
 }
 
 METHOD(keymat_v2_t, hash_algorithm_supported, bool,
@@ -867,6 +902,7 @@ METHOD(keymat_t, destroy, void,
        chunk_clear(&this->skp_verify);
        chunk_clear(&this->skp_build);
        DESTROY_IF(this->hash_algorithms);
+       DESTROY_IF(this->packets);
        free(this);
 }
 
@@ -891,6 +927,9 @@ keymat_v2_t *keymat_v2_create(bool initiator)
                        .derive_ike_keys_ppk = _derive_ike_keys_ppk,
                        .derive_child_keys = _derive_child_keys,
                        .get_skd = _get_skd,
+                       .add_packet = _add_packet,
+                       .get_packets = _get_packets,
+                       .clear_packets = _clear_packets,
                        .get_auth_octets = _get_auth_octets,
                        .get_psk_sig = _get_psk_sig,
                        .add_hash_algorithm = _add_hash_algorithm,
index a7d0003a65ff155d442a30ae1580cff6526b25a6..053f451f5554806b564a698771f7b075bdc82ae7 100644 (file)
@@ -113,6 +113,31 @@ struct keymat_v2_t {
         */
        pseudo_random_function_t (*get_skd)(keymat_v2_t *this, chunk_t *skd);
 
+       /**
+        * Cache data of an initial IKE packet (IKE_SA_INIT/IKE_AUX) for use in the
+        * auth octets.
+        *
+        * @param sent                  TRUE if message was sent, FALSE if received
+        * @param mid                   message ID of the packet
+        * @param fnr                   fragment number of the packet
+        * @param data                  IKE message or fragment data (cloned)
+        */
+       void (*add_packet)(keymat_v2_t *this, bool sent, uint32_t mid, uint16_t fnr,
+                                          chunk_t data);
+
+       /**
+        * Get cached data of all initial IKE packets for use in the auth octets.
+        *
+        * @param sent                  TRUE for sent packets, FALSE for received packets
+        * @return                              concatenated packet data (allocated)
+        */
+       chunk_t (*get_packets)(keymat_v2_t *this, bool sent);
+
+       /**
+        * Clear all cached initial IKE packets after the authentication succeeded.
+        */
+       void (*clear_packets)(keymat_v2_t *this);
+
        /**
         * Generate octets to use for authentication procedure (RFC4306 2.15).
         *
@@ -121,21 +146,22 @@ struct keymat_v2_t {
         * the get_psk_sig() method instead.
         *
         * @param verify                TRUE to create for verification, FALSE to sign
-        * @param ike_sa_init   encoded ike_sa_init message
+        * @param packets               initial packet data
         * @param nonce                 nonce value
         * @param ppk                   optional postquantum preshared key
         * @param id                    identity
         * @param reserved              reserved bytes of id_payload
-        * @param octests               chunk receiving allocated auth octets
+        * @param octets                chunk receiving allocated auth octets
         * @param schemes               array containing signature schemes
         *                                              (signature_params_t*) in case they need to be
         *                                              modified by the keymat implementation
         * @return                              TRUE if octets created successfully
         */
-       bool (*get_auth_octets)(keymat_v2_t *this, bool verify, chunk_t ike_sa_init,
+       bool (*get_auth_octets)(keymat_v2_t *this, bool verify, chunk_t packets,
                                                        chunk_t nonce, chunk_t ppk, identification_t *id,
                                                        char reserved[3], chunk_t *octets,
                                                        array_t *schemes);
+
        /**
         * Build the shared secret signature used for PSK and EAP authentication.
         *
@@ -144,7 +170,7 @@ struct keymat_v2_t {
         * used as secret (used for EAP methods without MSK).
         *
         * @param verify                TRUE to create for verification, FALSE to sign
-        * @param ike_sa_init   encoded ike_sa_init message
+        * @param packets               initial packet data
         * @param nonce                 nonce value
         * @param secret                optional secret to include into signature
         * @param ppk                   optional postquantum preshared key
@@ -153,7 +179,7 @@ struct keymat_v2_t {
         * @param sign                  chunk receiving allocated signature octets
         * @return                              TRUE if signature created successfully
         */
-       bool (*get_psk_sig)(keymat_v2_t *this, bool verify, chunk_t ike_sa_init,
+       bool (*get_psk_sig)(keymat_v2_t *this, bool verify, chunk_t packets,
                                                chunk_t nonce, chunk_t secret, chunk_t ppk,
                                                identification_t *id, char reserved[3], chunk_t *sig);
 
index 37e7aa592495858b8c33f303b2aa58a1f1227655..a3af9d6279b4c5dc5f54a599d0e6d38b7f9d7429 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <collections/array.h>
 #include <daemon.h>
+#include <sa/ikev2/keymat_v2.h>
 #include <sa/ikev2/tasks/ike_init.h>
 #include <sa/ikev2/tasks/ike_natd.h>
 #include <sa/ikev2/tasks/ike_mobike.h>
@@ -40,6 +41,7 @@
 #include <sa/ikev2/tasks/child_create.h>
 #include <sa/ikev2/tasks/child_rekey.h>
 #include <sa/ikev2/tasks/child_delete.h>
+#include <encoding/payloads/encrypted_fragment_payload.h>
 #include <encoding/payloads/delete_payload.h>
 #include <encoding/payloads/unknown_payload.h>
 #include <processing/jobs/retransmit_job.h>
@@ -325,6 +327,63 @@ static bool generate_message(private_task_manager_t *this, message_t *message,
        return TRUE;
 }
 
+/**
+ * Check if the given message has to be cached for authentication
+ */
+static inline bool cache_required(private_task_manager_t *this, message_t *msg)
+{
+       /* collect IKE_SA_INIT and IKE_AUX while connecting */
+       return msg->get_exchange_type(msg) == IKE_SA_INIT ||
+                       (msg->get_exchange_type(msg) == IKE_AUX &&
+                        this->ike_sa->get_state(this->ike_sa) == IKE_CONNECTING);
+}
+
+/**
+ * Cache the initial IKE packet data for sent messages/fragments
+ */
+static void cache_sent_message(private_task_manager_t *this, message_t *msg,
+                                                          array_t *packets)
+{
+       keymat_v2_t *keymat;
+       packet_t *packet;
+       uint32_t mid;
+       int i;
+
+       if (!cache_required(this, msg))
+       {
+               return;
+       }
+
+       keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
+       mid = msg->get_message_id(msg);
+
+       for (i = 0; i < array_count(packets); i++)
+       {
+               array_get(packets, i, &packet);
+               keymat->add_packet(keymat, TRUE, mid, i+1, packet->get_data(packet));
+       }
+}
+
+/**
+ * Cache the initial IKE packet data for received messages/fragments (fragment
+ * may be NULL for unfragmented messages)
+ */
+static void cache_received_message(private_task_manager_t *this, message_t *msg,
+                                                                  encrypted_fragment_payload_t *fragment)
+{
+       keymat_v2_t *keymat;
+
+       if (!cache_required(this, msg))
+       {
+               return;
+       }
+
+       keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
+       keymat->add_packet(keymat, FALSE, msg->get_message_id(msg),
+                                          fragment ? fragment->get_fragment_number(fragment) : 1,
+                                          msg->get_packet_data(msg));
+}
+
 METHOD(task_manager_t, retransmit, status_t,
        private_task_manager_t *this, uint32_t message_id)
 {
@@ -674,6 +733,8 @@ METHOD(task_manager_t, initiate, status_t,
 
        if (result)
        {
+               cache_sent_message(this, message, this->initiating.packets);
+
                enumerator = array_create_enumerator(this->active_tasks);
                while (enumerator->enumerate(enumerator, &task))
                {
@@ -947,6 +1008,8 @@ static status_t build_response(private_task_manager_t *this, message_t *request)
 
        if (result && !delete)
        {
+               cache_sent_message(this, message, this->responding.packets);
+
                enumerator = array_create_enumerator(this->passive_tasks);
                while (enumerator->enumerate(enumerator, &task))
                {
@@ -1307,16 +1370,23 @@ METHOD(task_manager_t, get_mid, uint32_t,
  *
  * Returns SUCCESS if the message is not a fragment, and NEED_MORE if it was
  * handled properly.  Error states are  returned if the fragment was invalid or
- * the reassembled message could not have been processed properly.
+ * the reassembled message could not be processed properly.
  */
 static status_t handle_fragment(private_task_manager_t *this,
                                                                message_t **defrag, message_t *msg)
 {
-       message_t *reassembled;
+       encrypted_fragment_payload_t *fragment;
        status_t status;
 
-       if (!msg->get_payload(msg, PLV2_FRAGMENT))
+       fragment = (encrypted_fragment_payload_t*)msg->get_payload(msg,
+                                                                                                                          PLV2_FRAGMENT);
+       if (!fragment)
        {
+               /* ignore reassembled messages, we collected their fragments below */
+               if (msg != *defrag)
+               {
+                       cache_received_message(this, msg, NULL);
+               }
                return SUCCESS;
        }
        if (!*defrag)
@@ -1328,18 +1398,22 @@ static status_t handle_fragment(private_task_manager_t *this,
                }
        }
        status = (*defrag)->add_fragment(*defrag, msg);
+
+       if (status == NEED_MORE || status == SUCCESS)
+       {
+               cache_received_message(this, msg, fragment);
+       }
        if (status == SUCCESS)
        {
                /* reinject the reassembled message */
-               reassembled = *defrag;
-               *defrag = NULL;
-               status = this->ike_sa->process_message(this->ike_sa, reassembled);
+               status = this->ike_sa->process_message(this->ike_sa, *defrag);
                if (status == SUCCESS)
                {
                        /* avoid processing the last fragment */
                        status = NEED_MORE;
                }
-               reassembled->destroy(reassembled);
+               (*defrag)->destroy(*defrag);
+               *defrag = NULL;
        }
        return status;
 }
index be553dfb128ef9e01923c1014ddbfe1a177fc96f..e5224837915ebbf79a59484b3cefab9bbf53aa6a 100644 (file)
@@ -71,14 +71,14 @@ struct private_ike_auth_t {
        chunk_t ppk;
 
        /**
-        * IKE_SA_INIT message sent by us
+        * Data of initial packets sent by us
         */
-       packet_t *my_packet;
+       chunk_t my_packets;
 
        /**
-        * IKE_SA_INIT message sent by peer
+        * Data of initial packets sent by peer
         */
-       packet_t *other_packet;
+       chunk_t other_packets;
 
        /**
         * Reserved bytes of ID payload
@@ -165,13 +165,6 @@ static status_t collect_my_init_data(private_ike_auth_t *this,
                return FAILED;
        }
        this->my_nonce = nonce->get_nonce(nonce);
-
-       /* pre-generate the message, keep a copy */
-       if (this->ike_sa->generate_message(this->ike_sa, message,
-                                                                          &this->my_packet) != SUCCESS)
-       {
-               return FAILED;
-       }
        return NEED_MORE;
 }
 
@@ -191,9 +184,6 @@ static status_t collect_other_init_data(private_ike_auth_t *this,
                return FAILED;
        }
        this->other_nonce = nonce->get_nonce(nonce);
-
-       /* keep a copy of the received packet */
-       this->other_packet = message->get_packet(message);
        return NEED_MORE;
 }
 
@@ -638,6 +628,16 @@ METHOD(task_t, build_i, status_t,
                return NEED_MORE;
        }
 
+       if (!this->my_packets.ptr)
+       {
+               keymat_v2_t *keymat;
+
+               keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
+               this->my_packets = keymat->get_packets(keymat, TRUE);
+               this->other_packets = keymat->get_packets(keymat, FALSE);
+               keymat->clear_packets(keymat);
+       }
+
        /* check if an authenticator is in progress */
        if (!this->my_auth)
        {
@@ -695,10 +695,9 @@ METHOD(task_t, build_i, status_t,
 
                /* 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->reserved);
+                                                                               this->other_nonce, this->my_nonce,
+                                                                               this->other_packets, this->my_packets,
+                                                                               this->reserved);
                if (!this->my_auth)
                {
                        charon->bus->alert(charon->bus, ALERT_LOCAL_AUTH_FAILED);
@@ -803,6 +802,16 @@ METHOD(task_t, process_r, status_t,
                this->first_auth = TRUE;
        }
 
+       if (!this->my_packets.ptr)
+       {
+               keymat_v2_t *keymat;
+
+               keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa);
+               this->my_packets = keymat->get_packets(keymat, TRUE);
+               this->other_packets = keymat->get_packets(keymat, FALSE);
+               keymat->clear_packets(keymat);
+       }
+
        if (!this->other_auth)
        {
                /* handle IDi payload */
@@ -862,10 +871,9 @@ METHOD(task_t, process_r, status_t,
 
                /* verify authentication data */
                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->reserved);
+                                                                       message, this->other_nonce, this->my_nonce,
+                                                                       this->other_packets, this->my_packets,
+                                                                       this->reserved);
                if (!this->other_auth)
                {
                        this->authentication_failed = TRUE;
@@ -1041,10 +1049,9 @@ METHOD(task_t, build_r, status_t,
                {
                        /* 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->reserved);
+                                                                               this->other_nonce, this->my_nonce,
+                                                                               this->other_packets, this->my_packets,
+                                                                               this->reserved);
                        if (!this->my_auth)
                        {
                                goto local_auth_failed;
@@ -1343,10 +1350,9 @@ METHOD(task_t, process_i, status_t,
                        {
                                /* verify authentication data */
                                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->reserved);
+                                                                       message, this->other_nonce, this->my_nonce,
+                                                                       this->other_packets, this->my_packets,
+                                                                       this->reserved);
                                if (!this->other_auth)
                                {
                                        goto peer_auth_failed;
@@ -1512,16 +1518,14 @@ METHOD(task_t, migrate, void,
        clear_ppk(this);
        chunk_free(&this->my_nonce);
        chunk_free(&this->other_nonce);
-       DESTROY_IF(this->my_packet);
-       DESTROY_IF(this->other_packet);
+       chunk_free(&this->my_packets);
+       chunk_free(&this->other_packets);
        DESTROY_IF(this->peer_cfg);
        DESTROY_IF(this->my_auth);
        DESTROY_IF(this->other_auth);
        DESTROY_IF(this->redirect_to);
        this->candidates->destroy_offset(this->candidates, offsetof(peer_cfg_t, destroy));
 
-       this->my_packet = NULL;
-       this->other_packet = NULL;
        this->ike_sa = ike_sa;
        this->peer_cfg = NULL;
        this->my_auth = NULL;
@@ -1540,8 +1544,8 @@ METHOD(task_t, destroy, void,
        clear_ppk(this);
        chunk_free(&this->my_nonce);
        chunk_free(&this->other_nonce);
-       DESTROY_IF(this->my_packet);
-       DESTROY_IF(this->other_packet);
+       chunk_free(&this->my_packets);
+       chunk_free(&this->other_packets);
        DESTROY_IF(this->my_auth);
        DESTROY_IF(this->other_auth);
        DESTROY_IF(this->peer_cfg);