From 9cb3c104183ab2b2f465584cdbf5a144585623b5 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 15 Feb 2022 10:13:53 +0100 Subject: [PATCH] keymat_v1: Derive CHILD_SA keys without using prf_plus_t 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 | 48 +++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/src/libcharon/sa/ikev1/keymat_v1.c b/src/libcharon/sa/ikev1/keymat_v1.c index 0651269bdd..9eedce21cc 100644 --- a/src/libcharon/sa/ikev1/keymat_v1.c +++ b/src/libcharon/sa/ikev1/keymat_v1.c @@ -16,7 +16,6 @@ #include "keymat_v1.h" #include -#include #include #include #include @@ -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;