]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
keymat_v1: Derive CHILD_SA keys without using prf_plus_t
authorTobias Brunner <tobias@strongswan.org>
Tue, 15 Feb 2022 09:13:53 +0000 (10:13 +0100)
committerTobias Brunner <tobias@strongswan.org>
Thu, 14 Apr 2022 17:02:56 +0000 (19:02 +0200)
We already expand skeyid_e in a similar fashion so do this analogous
without relying on prf_plus_t.

src/libcharon/sa/ikev1/keymat_v1.c

index 0651269bdd75a129a4eb8e7cbbbf2f86c7db5774..9eedce21ccb320f71b2f39f26338f33d84271fbc 100644 (file)
@@ -16,7 +16,6 @@
 #include "keymat_v1.h"
 
 #include <daemon.h>
-#include <crypto/prf_plus.h>
 #include <sa/ikev1/iv_manager.h>
 #include <encoding/generator.h>
 #include <encoding/payloads/nonce_payload.h>
@@ -508,6 +507,36 @@ METHOD(keymat_v1_t, derive_ike_keys, bool,
                                                                                this->aead->get_block_size(this->aead));
 }
 
+/**
+ * Derive key material for CHILD_SAs according to section 5.5. in RFC 2409.
+ */
+static bool derive_child_keymat(private_keymat_v1_t *this, chunk_t seed,
+                                                               uint16_t enc_size, chunk_t *encr,
+                                                               uint16_t int_size, chunk_t *integ)
+{
+       size_t block_size, i;
+       chunk_t keymat, prev = chunk_empty;
+
+       block_size = this->prf->get_block_size(this->prf);
+       keymat = chunk_alloc(round_up(enc_size + int_size, block_size));
+       keymat.len = enc_size + int_size;
+
+       for (i = 0; i < keymat.len; i += block_size)
+       {
+               if (!this->prf->get_bytes(this->prf, prev, NULL) ||
+                       !this->prf->get_bytes(this->prf, seed, keymat.ptr + i))
+               {
+                       chunk_clear(&keymat);
+                       return FALSE;
+               }
+               prev = chunk_create(keymat.ptr + i, block_size);
+       }
+
+       chunk_split(keymat, "aa", enc_size, encr, int_size, integ);
+       chunk_clear(&keymat);
+       return TRUE;
+}
+
 METHOD(keymat_v1_t, derive_child_keys, bool,
        private_keymat_v1_t *this, proposal_t *proposal, diffie_hellman_t *dh,
        uint32_t spi_i, uint32_t spi_r, chunk_t nonce_i, chunk_t nonce_r,
@@ -515,8 +544,7 @@ METHOD(keymat_v1_t, derive_child_keys, bool,
 {
        uint16_t enc_alg, int_alg, enc_size = 0, int_size = 0;
        uint8_t protocol;
-       prf_plus_t *prf_plus;
-       chunk_t seed, secret = chunk_empty;
+       chunk_t seed = chunk_empty, secret = chunk_empty;
        bool success = FALSE;
 
        if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM,
@@ -600,11 +628,7 @@ METHOD(keymat_v1_t, derive_child_keys, bool,
        seed = chunk_cata("ccccc", secret, chunk_from_thing(protocol),
                                          chunk_from_thing(spi_r), nonce_i, nonce_r);
        DBG4(DBG_CHD, "initiator SA seed %B", &seed);
-
-       prf_plus = prf_plus_create(this->prf, FALSE, seed);
-       if (!prf_plus ||
-               !prf_plus->allocate_bytes(prf_plus, enc_size, encr_i) ||
-               !prf_plus->allocate_bytes(prf_plus, int_size, integ_i))
+       if (!derive_child_keymat(this, seed, enc_size, encr_i, int_size, integ_i))
        {
                goto failure;
        }
@@ -612,11 +636,7 @@ METHOD(keymat_v1_t, derive_child_keys, bool,
        seed = chunk_cata("ccccc", secret, chunk_from_thing(protocol),
                                          chunk_from_thing(spi_i), nonce_i, nonce_r);
        DBG4(DBG_CHD, "responder SA seed %B", &seed);
-       prf_plus->destroy(prf_plus);
-       prf_plus = prf_plus_create(this->prf, FALSE, seed);
-       if (!prf_plus ||
-               !prf_plus->allocate_bytes(prf_plus, enc_size, encr_r) ||
-               !prf_plus->allocate_bytes(prf_plus, int_size, integ_r))
+       if (!derive_child_keymat(this, seed, enc_size, encr_r, int_size, integ_r))
        {
                goto failure;
        }
@@ -641,7 +661,7 @@ failure:
                chunk_clear(encr_r);
                chunk_clear(integ_r);
        }
-       DESTROY_IF(prf_plus);
+       memwipe(seed.ptr, seed.len);
        chunk_clear(&secret);
 
        return success;