diff --git a/prf-plus-modularization.patch b/prf-plus-modularization.patch index e9a9c7a..7c2842e 100644 --- a/prf-plus-modularization.patch +++ b/prf-plus-modularization.patch @@ -242,7 +242,7 @@ Index: strongswan-5.9.5/src/libcharon/sa/ikev2/keymat_v2.c u_int salt_size; switch (alg) -@@ -131,201 +129,178 @@ static bool derive_ike_aead(private_keym +@@ -131,201 +129,177 @@ static bool derive_ike_aead(private_keym return FALSE; } @@ -480,9 +480,9 @@ Index: strongswan-5.9.5/src/libcharon/sa/ikev2/keymat_v2.c chunk_t sk_ai = chunk_empty, sk_ar = chunk_empty, sk_pi, sk_pr; - prf_plus_t *prf_plus = NULL; - uint16_t alg, key_size, int_alg; -+ kdf_t *prf_plus = NULL; +- prf_t *rekey_prf = NULL; ++ kdf_t *prf = NULL, *prf_plus = NULL; + uint16_t prf_alg, key_size, enc_alg, enc_size, int_alg; - prf_t *rekey_prf = NULL; + bool success = FALSE; spi_i = chunk_alloca(sizeof(uint64_t)); @@ -553,7 +553,7 @@ Index: strongswan-5.9.5/src/libcharon/sa/ikev2/keymat_v2.c return FALSE; } DBG4(DBG_IKE, "shared Diffie Hellman secret %B", &secret); -@@ -333,7 +308,7 @@ METHOD(keymat_v2_t, derive_ike_keys, boo +@@ -333,7 +307,7 @@ METHOD(keymat_v2_t, derive_ike_keys, boo full_nonce = chunk_cat("cc", nonce_i, nonce_r); /* but the PRF may need a fixed key which only uses the first bytes of * the nonces. */ @@ -562,7 +562,7 @@ Index: strongswan-5.9.5/src/libcharon/sa/ikev2/keymat_v2.c { case PRF_AES128_CMAC: /* while variable keys may be used according to RFC 4615, RFC 7296 -@@ -345,9 +320,8 @@ METHOD(keymat_v2_t, derive_ike_keys, boo +@@ -345,9 +319,8 @@ METHOD(keymat_v2_t, derive_ike_keys, boo case PRF_CAMELLIA128_XCBC: /* draft-kanno-ipsecme-camellia-xcbc refers to rfc 4434, we * assume fixed key length. */ @@ -574,13 +574,18 @@ Index: strongswan-5.9.5/src/libcharon/sa/ikev2/keymat_v2.c break; default: /* all other algorithms use variable key length, full nonce */ -@@ -366,10 +340,10 @@ METHOD(keymat_v2_t, derive_ike_keys, boo +@@ -365,19 +338,22 @@ METHOD(keymat_v2_t, derive_ike_keys, boo + if (rekey_function == PRF_UNDEFINED) /* not rekeying */ { /* SKEYSEED = prf(Ni | Nr, g^ir) */ - if (this->prf->set_key(this->prf, fixed_nonce) && +- if (this->prf->set_key(this->prf, fixed_nonce) && - this->prf->allocate_bytes(this->prf, secret, &skeyseed) && - this->prf->set_key(this->prf, skeyseed)) -+ this->prf->allocate_bytes(this->prf, secret, &skeyseed)) ++ prf = lib->crypto->create_kdf(lib->crypto, KDF_PRF, this->prf_alg); ++ if (prf && ++ prf->set_param(prf, KDF_PARAM_KEY, fixed_nonce) && ++ prf->set_param(prf, KDF_PARAM_SALT, secret) && ++ prf->allocate_bytes(prf, 0, &skeyseed)) { - prf_plus = prf_plus_create(this->prf, TRUE, prf_plus_seed); + prf_plus = lib->crypto->create_kdf(lib->crypto, KDF_PRF_PLUS, @@ -588,13 +593,26 @@ Index: strongswan-5.9.5/src/libcharon/sa/ikev2/keymat_v2.c } } else -@@ -389,117 +363,96 @@ METHOD(keymat_v2_t, derive_ike_keys, boo + { + /* SKEYSEED = prf(SK_d (old), [g^ir (new)] | Ni | Nr) + * use OLD SAs PRF functions for both prf_plus and prf */ +- rekey_prf = lib->crypto->create_prf(lib->crypto, rekey_function); +- if (!rekey_prf) ++ prf = lib->crypto->create_kdf(lib->crypto, KDF_PRF, rekey_function); ++ if (!prf) + { + DBG1(DBG_IKE, "PRF of old SA %N not supported!", + pseudo_random_function_names, rekey_function); +@@ -388,118 +364,97 @@ METHOD(keymat_v2_t, derive_ike_keys, boo + return FALSE; } secret = chunk_cat("sc", secret, full_nonce); - if (rekey_prf->set_key(rekey_prf, rekey_skd) && +- if (rekey_prf->set_key(rekey_prf, rekey_skd) && - rekey_prf->allocate_bytes(rekey_prf, secret, &skeyseed) && - rekey_prf->set_key(rekey_prf, skeyseed)) -+ rekey_prf->allocate_bytes(rekey_prf, secret, &skeyseed)) ++ if (prf->set_param(prf, KDF_PARAM_KEY, rekey_skd) && ++ prf->set_param(prf, KDF_PARAM_SALT, secret) && ++ prf->allocate_bytes(prf, 0, &skeyseed)) { - prf_plus = prf_plus_create(rekey_prf, TRUE, prf_plus_seed); + prf_plus = lib->crypto->create_kdf(lib->crypto, KDF_PRF_PLUS, @@ -602,37 +620,37 @@ Index: strongswan-5.9.5/src/libcharon/sa/ikev2/keymat_v2.c } } DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed); - -+ if (prf_plus && -+ (!prf_plus->set_param(prf_plus, KDF_PARAM_KEY, skeyseed) || -+ !prf_plus->set_param(prf_plus, KDF_PARAM_SALT, prf_plus_seed))) -+ { -+ prf_plus->destroy(prf_plus); -+ prf_plus = NULL; -+ } -+ - chunk_clear(&skeyseed); +- +- chunk_clear(&skeyseed); chunk_clear(&secret); chunk_free(&full_nonce); chunk_free(&fixed_nonce); - chunk_clear(&prf_plus_seed); -+ DESTROY_IF(rekey_prf); +- chunk_clear(&prf_plus_seed); ++ DESTROY_IF(prf); - if (!prf_plus) +- if (!prf_plus) ++ if (prf_plus && ++ (!prf_plus->set_param(prf_plus, KDF_PARAM_KEY, skeyseed) || ++ !prf_plus->set_param(prf_plus, KDF_PARAM_SALT, prf_plus_seed))) { - goto failure; +- goto failure; ++ prf_plus->destroy(prf_plus); ++ prf_plus = NULL; } ++ chunk_clear(&skeyseed); ++ chunk_clear(&prf_plus_seed); - /* KEYMAT = SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr */ - - /* SK_d is used for generating CHILD_SA key mat => store for later use */ - key_size = this->prf->get_key_size(this->prf); - if (!prf_plus->allocate_bytes(prf_plus, key_size, &this->skd)) -- { -- goto failure; -- } ++ if (!prf_plus) + { + goto failure; + } - DBG4(DBG_IKE, "Sk_d secret %B", &this->skd); -- + - if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &key_size)) + /* KEYMAT = SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr + * @@ -752,7 +770,7 @@ Index: strongswan-5.9.5/src/libcharon/sa/ikev2/keymat_v2.c !prf_plus->allocate_bytes(prf_plus, key.len, new_key)) { DBG1(DBG_IKE, "unable to derive %s with PPK", name); -@@ -510,20 +463,6 @@ static bool derive_ppk_key(prf_t *prf, c +@@ -510,20 +465,6 @@ static bool derive_ppk_key(prf_t *prf, c return TRUE; } @@ -773,7 +791,7 @@ Index: strongswan-5.9.5/src/libcharon/sa/ikev2/keymat_v2.c METHOD(keymat_v2_t, derive_ike_keys_ppk, bool, private_keymat_v2_t *this, chunk_t ppk) { -@@ -548,14 +487,9 @@ METHOD(keymat_v2_t, derive_ike_keys_ppk, +@@ -548,14 +489,9 @@ METHOD(keymat_v2_t, derive_ike_keys_ppk, DBG4(DBG_IKE, "derive keys using PPK %B", &ppk); @@ -791,7 +809,7 @@ Index: strongswan-5.9.5/src/libcharon/sa/ikev2/keymat_v2.c { chunk_clear(&skd); chunk_clear(&new_skpi); -@@ -583,8 +517,8 @@ METHOD(keymat_v2_t, derive_child_keys, b +@@ -583,8 +519,8 @@ METHOD(keymat_v2_t, derive_child_keys, b chunk_t *encr_r, chunk_t *integ_r) { uint16_t enc_alg, int_alg, enc_size = 0, int_size = 0; @@ -802,7 +820,7 @@ Index: strongswan-5.9.5/src/libcharon/sa/ikev2/keymat_v2.c if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &enc_alg, &enc_size)) -@@ -650,11 +584,6 @@ METHOD(keymat_v2_t, derive_child_keys, b +@@ -650,11 +586,6 @@ METHOD(keymat_v2_t, derive_child_keys, b int_size /= 8; } @@ -814,7 +832,7 @@ Index: strongswan-5.9.5/src/libcharon/sa/ikev2/keymat_v2.c if (dh) { if (!dh->get_shared_secret(dh, &secret)) -@@ -666,30 +595,30 @@ METHOD(keymat_v2_t, derive_child_keys, b +@@ -666,30 +597,30 @@ METHOD(keymat_v2_t, derive_child_keys, b seed = chunk_cata("scc", secret, nonce_i, nonce_r); DBG4(DBG_CHD, "seed %B", &seed); @@ -859,7 +877,7 @@ Index: strongswan-5.9.5/src/libcharon/sa/ikev2/keymat_v2.c if (enc_size) { DBG4(DBG_CHD, "encryption initiator key %B", encr_i); -@@ -729,7 +658,7 @@ METHOD(keymat_v2_t, get_auth_octets, boo +@@ -729,7 +660,7 @@ METHOD(keymat_v2_t, get_auth_octets, boo if (ppk.ptr) { DBG4(DBG_IKE, "PPK %B", &ppk); @@ -868,7 +886,7 @@ Index: strongswan-5.9.5/src/libcharon/sa/ikev2/keymat_v2.c { return FALSE; } -@@ -775,7 +704,7 @@ METHOD(keymat_v2_t, get_psk_sig, bool, +@@ -775,7 +706,7 @@ METHOD(keymat_v2_t, get_psk_sig, bool, secret = verify ? this->skp_verify : this->skp_build; if (ppk.ptr) { @@ -877,6 +895,42 @@ Index: strongswan-5.9.5/src/libcharon/sa/ikev2/keymat_v2.c { return FALSE; } +Index: strongswan-5.9.5/src/libcharon/tests/utils/mock_dh.c +=================================================================== +--- strongswan-5.9.5.orig/src/libcharon/tests/utils/mock_dh.c ++++ strongswan-5.9.5/src/libcharon/tests/utils/mock_dh.c +@@ -18,6 +18,13 @@ + + typedef struct private_diffie_hellman_t private_diffie_hellman_t; + ++/** Mock DH public and shared key */ ++static chunk_t mock_key = chunk_from_chars( ++ 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, ++ 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, ++ 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, ++ 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08); ++ + /** + * Private data + */ +@@ -37,7 +44,7 @@ struct private_diffie_hellman_t { + METHOD(diffie_hellman_t, get_my_public_value, bool, + private_diffie_hellman_t *this, chunk_t *value) + { +- *value = chunk_empty; ++ *value = chunk_clone(mock_key); + return TRUE; + } + +@@ -50,7 +57,7 @@ METHOD(diffie_hellman_t, set_other_publi + METHOD(diffie_hellman_t, get_shared_secret, bool, + private_diffie_hellman_t *this, chunk_t *secret) + { +- *secret = chunk_empty; ++ *secret = chunk_clone(mock_key); + return TRUE; + } + Index: strongswan-5.9.5/src/libstrongswan/Android.mk =================================================================== --- strongswan-5.9.5.orig/src/libstrongswan/Android.mk @@ -1362,7 +1416,7 @@ Index: strongswan-5.9.5/src/libstrongswan/crypto/crypto_tester.c * List of DRBG test vectors */ linked_list_t *drbg; -@@ -1186,6 +1191,185 @@ failure: +@@ -1186,6 +1191,211 @@ failure: return !failed; } @@ -1392,6 +1446,7 @@ Index: strongswan-5.9.5/src/libstrongswan/crypto/crypto_tester.c +{ + switch (alg) + { ++ case KDF_PRF: + case KDF_PRF_PLUS: + return create_kdf_args(create, alg, vector->arg.prf); + case KDF_UNDEFINED: @@ -1410,6 +1465,7 @@ Index: strongswan-5.9.5/src/libstrongswan/crypto/crypto_tester.c + + switch (alg) + { ++ case KDF_PRF: + case KDF_PRF_PLUS: + { + pseudo_random_function_t prf; @@ -1484,6 +1540,17 @@ Index: strongswan-5.9.5/src/libstrongswan/crypto/crypto_tester.c + { + goto failure; + } ++ if (kdf_has_fixed_output_length(alg)) ++ { ++ if (kdf->get_length(kdf) != vector->out.len) ++ { ++ goto failure; ++ } ++ } ++ else if (kdf->get_length(kdf) != SIZE_MAX) ++ { ++ goto failure; ++ } + /* allocated bytes */ + if (!kdf->allocate_bytes(kdf, vector->out.len, &out)) + { @@ -1493,6 +1560,19 @@ Index: strongswan-5.9.5/src/libstrongswan/crypto/crypto_tester.c + { + goto failure; + } ++ /* allocate without knowing the length */ ++ if (kdf_has_fixed_output_length(alg)) ++ { ++ chunk_free(&out); ++ if (!kdf->allocate_bytes(kdf, 0, &out)) ++ { ++ goto failure; ++ } ++ if (!chunk_equals(out, vector->out)) ++ { ++ goto failure; ++ } ++ } + /* bytes to existing buffer */ + memset(out.ptr, 0, out.len); + if (!kdf->get_bytes(kdf, out.len, out.ptr)) @@ -1548,7 +1628,7 @@ Index: strongswan-5.9.5/src/libstrongswan/crypto/crypto_tester.c /** * Benchmark a DRBG */ -@@ -1622,6 +1806,12 @@ METHOD(crypto_tester_t, add_xof_vector, +@@ -1622,6 +1832,12 @@ METHOD(crypto_tester_t, add_xof_vector, this->xof->insert_last(this->xof, vector); } @@ -1561,7 +1641,7 @@ Index: strongswan-5.9.5/src/libstrongswan/crypto/crypto_tester.c METHOD(crypto_tester_t, add_drbg_vector, void, private_crypto_tester_t *this, drbg_test_vector_t *vector) { -@@ -1649,6 +1839,7 @@ METHOD(crypto_tester_t, destroy, void, +@@ -1649,6 +1865,7 @@ METHOD(crypto_tester_t, destroy, void, this->hasher->destroy(this->hasher); this->prf->destroy(this->prf); this->xof->destroy(this->xof); @@ -1569,7 +1649,7 @@ Index: strongswan-5.9.5/src/libstrongswan/crypto/crypto_tester.c this->drbg->destroy(this->drbg); this->rng->destroy(this->rng); this->dh->destroy(this->dh); -@@ -1670,6 +1861,7 @@ crypto_tester_t *crypto_tester_create() +@@ -1670,6 +1887,7 @@ crypto_tester_t *crypto_tester_create() .test_hasher = _test_hasher, .test_prf = _test_prf, .test_xof = _test_xof, @@ -1577,7 +1657,7 @@ Index: strongswan-5.9.5/src/libstrongswan/crypto/crypto_tester.c .test_drbg = _test_drbg, .test_rng = _test_rng, .test_dh = _test_dh, -@@ -1679,6 +1871,7 @@ crypto_tester_t *crypto_tester_create() +@@ -1679,6 +1897,7 @@ crypto_tester_t *crypto_tester_create() .add_hasher_vector = _add_hasher_vector, .add_prf_vector = _add_prf_vector, .add_xof_vector = _add_xof_vector, @@ -1585,7 +1665,7 @@ Index: strongswan-5.9.5/src/libstrongswan/crypto/crypto_tester.c .add_drbg_vector = _add_drbg_vector, .add_rng_vector = _add_rng_vector, .add_dh_vector = _add_dh_vector, -@@ -1690,6 +1883,7 @@ crypto_tester_t *crypto_tester_create() +@@ -1690,6 +1909,7 @@ crypto_tester_t *crypto_tester_create() .hasher = linked_list_create(), .prf = linked_list_create(), .xof = linked_list_create(), @@ -1674,7 +1754,7 @@ Index: strongswan-5.9.5/src/libstrongswan/crypto/kdfs/kdf.c =================================================================== --- /dev/null +++ strongswan-5.9.5/src/libstrongswan/crypto/kdfs/kdf.c -@@ -0,0 +1,28 @@ +@@ -0,0 +1,45 @@ +/* + * Copyright (C) 2022 Tobias Brunner, codelabs GmbH + * @@ -1701,13 +1781,30 @@ Index: strongswan-5.9.5/src/libstrongswan/crypto/kdfs/kdf.c + +ENUM(key_derivation_function_names, KDF_UNDEFINED, KDF_PRF_PLUS, + "KDF_UNDEFINED", ++ "KDF_PRF", + "KDF_PRF_PLUS", +); ++ ++/* ++ * Described in header ++ */ ++bool kdf_has_fixed_output_length(key_derivation_function_t type) ++{ ++ switch (type) ++ { ++ case KDF_PRF: ++ return TRUE; ++ case KDF_PRF_PLUS: ++ case KDF_UNDEFINED: ++ break; ++ } ++ return FALSE; ++} Index: strongswan-5.9.5/src/libstrongswan/crypto/kdfs/kdf.h =================================================================== --- /dev/null +++ strongswan-5.9.5/src/libstrongswan/crypto/kdfs/kdf.h -@@ -0,0 +1,124 @@ +@@ -0,0 +1,152 @@ +/* + * Copyright (C) 2022 Tobias Brunner, codelabs GmbH + * @@ -1752,6 +1849,12 @@ Index: strongswan-5.9.5/src/libstrongswan/crypto/kdfs/kdf.h + KDF_UNDEFINED, + + /** ++ * RFC 7296 prf, expects a pseudo_random_function_t in the constructor, ++ * parameters are KEY and SALT. Has a fixed output length. ++ */ ++ KDF_PRF, ++ ++ /** + * RFC 7296 prf+, expects a pseudo_random_function_t in the constructor, + * parameters are KEY and SALT. + */ @@ -1796,8 +1899,17 @@ Index: strongswan-5.9.5/src/libstrongswan/crypto/kdfs/kdf.h + key_derivation_function_t (*get_type)(kdf_t *this); + + /** ++ * Output length for KDFs that produce a fixed amount of output. ++ * ++ * @return fixed output length, SIZE_MAX for variable length ++ */ ++ size_t (*get_length)(kdf_t *this); ++ ++ /** + * Derives a key of the given length and writes it to the buffer. + * ++ * @note Fails if out_len doesn't match for KDFs with fixed output length. ++ * + * @param out_len number of key bytes requested + * @param buffer pointer where the derived key will be written + * @return TRUE if key derived successfully @@ -1808,7 +1920,12 @@ Index: strongswan-5.9.5/src/libstrongswan/crypto/kdfs/kdf.h + /** + * Derives a key of the given length and allocates space for it. + * -+ * @param out_len number of key bytes requested ++ * @note Fails if out_len doesn't match for KDFs with fixed output length. ++ * However, for simplified usage, 0 can be passed for out_len to ++ * automatically allocate a chunk of the correct size. ++ * ++ * @param out_len number of key bytes requested, or 0 for KDFs with fixed ++ * output length + * @param chunk chunk which will hold the derived key + * @return TRUE if key derived successfully + */ @@ -1831,6 +1948,14 @@ Index: strongswan-5.9.5/src/libstrongswan/crypto/kdfs/kdf.h + void (*destroy)(kdf_t *this); +}; + ++/** ++ * Check if the given KDF type has a fixed output length. ++ * ++ * @param type KDF type ++ * @return TRUE if the KDF type has a fixed output length ++ */ ++bool kdf_has_fixed_output_length(key_derivation_function_t type); ++ +#endif /** KDF_H_ @}*/ Index: strongswan-5.9.5/src/libstrongswan/crypto/pkcs5.c =================================================================== @@ -2183,7 +2308,7 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/botan/botan_kdf.c =================================================================== --- /dev/null +++ strongswan-5.9.5/src/libstrongswan/plugins/botan/botan_kdf.c -@@ -0,0 +1,185 @@ +@@ -0,0 +1,224 @@ +/* + * Copyright (C) 2022 Tobias Brunner, codelabs GmbH + * @@ -2229,6 +2354,11 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/botan/botan_kdf.c + kdf_t public; + + /** ++ * KDF type. ++ */ ++ key_derivation_function_t type; ++ ++ /** + * Name of the KDF algorithm in Botan. + */ + char *name; @@ -2243,23 +2373,45 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/botan/botan_kdf.c + */ + chunk_t salt; + -+#if BOTAN_VERSION_MAJOR == 2 + /** -+ * Used for a manual length check in get_bytes(). ++ * Length of the hash output. + */ + size_t hash_size; -+#endif +}; + +METHOD(kdf_t, get_type, key_derivation_function_t, + private_kdf_t *this) +{ -+ return KDF_PRF_PLUS; ++ return this->type; ++} ++ ++METHOD(kdf_t, get_length, size_t, ++ private_kdf_t *this) ++{ ++ if (this->type == KDF_PRF_PLUS) ++ { ++ return SIZE_MAX; ++ } ++ return this->hash_size; +} + +METHOD(kdf_t, get_bytes, bool, + private_kdf_t *this, size_t out_len, uint8_t *buffer) +{ ++ if (this->type == KDF_PRF) ++ { ++ /* IKEv2 uses the nonces as PRF key and the DH secret as salt, however, ++ * HKDF-Extract() does the same again (mapping the salt to the HMAC key), ++ * so we have to switch key and salt here */ ++ if (out_len != get_length(this) || ++ botan_kdf(this->name, buffer, out_len, this->salt.ptr, this->salt.len, ++ this->key.ptr, this->key.len, NULL, 0)) ++ { ++ return FALSE; ++ } ++ return TRUE; ++ } ++ +#if BOTAN_VERSION_MAJOR == 2 + /* Botan 2 doesn't check the length, just silently prevents wrapping the + * counter and returns truncated output, so do this manually */ @@ -2279,6 +2431,11 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/botan/botan_kdf.c +METHOD(kdf_t, allocate_bytes, bool, + private_kdf_t *this, size_t out_len, chunk_t *chunk) +{ ++ if (this->type == KDF_PRF) ++ { ++ out_len = out_len ?: get_length(this); ++ } ++ + *chunk = chunk_alloc(out_len); + + if (!get_bytes(this, out_len, chunk->ptr)) @@ -2327,9 +2484,9 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/botan/botan_kdf.c + private_kdf_t *this; + pseudo_random_function_t prf_alg; + const char *hash_name; -+ char *name, buf[8]; ++ char *name, buf[HASH_SIZE_SHA512]; + -+ if (algo != KDF_PRF_PLUS) ++ if (algo != KDF_PRF && algo != KDF_PRF_PLUS) + { + return NULL; + } @@ -2340,7 +2497,14 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/botan/botan_kdf.c + { + return NULL; + } -+ if (asprintf(&name, "HKDF-Expand(%s)", hash_name) <= 0) ++ if (algo == KDF_PRF) ++ { ++ if (asprintf(&name, "HKDF-Extract(%s)", hash_name) <= 0) ++ { ++ return NULL; ++ } ++ } ++ else if (asprintf(&name, "HKDF-Expand(%s)", hash_name) <= 0) + { + return NULL; + } @@ -2348,19 +2512,19 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/botan/botan_kdf.c + INIT(this, + .public = { + .get_type = _get_type, ++ .get_length = _get_length, + .get_bytes = _get_bytes, + .allocate_bytes = _allocate_bytes, + .set_param = _set_param, + .destroy = _destroy, + }, ++ .type = algo, + .name = name, -+#if BOTAN_VERSION_MAJOR == 2 + .hash_size = hasher_hash_size(hasher_algorithm_from_prf(prf_alg)), -+#endif + ); + + /* test if we can actually use the algorithm */ -+ if (!get_bytes(this, sizeof(buf), buf)) ++ if (!get_bytes(this, algo == KDF_PRF ? get_length(this) : sizeof(buf), buf)) + { + destroy(this); + return NULL; @@ -2431,13 +2595,14 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/botan/botan_plugin.c #include "botan_rsa_public_key.h" #include "botan_rsa_private_key.h" #include "botan_ec_diffie_hellman.h" -@@ -209,6 +210,12 @@ METHOD(plugin_t, get_features, int, +@@ -209,6 +210,13 @@ METHOD(plugin_t, get_features, int, #endif #endif /* BOTAN_HAS_HMAC */ + /* kdfs */ +#ifdef BOTAN_HAS_HKDF + PLUGIN_REGISTER(SIGNER, botan_kdf_create), ++ PLUGIN_PROVIDE(KDF, KDF_PRF), + PLUGIN_PROVIDE(KDF, KDF_PRF_PLUS), +#endif /* BOTAN_HAS_HKDF */ + @@ -2463,14 +2628,285 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/kdf/Makefile.am + +libstrongswan_kdf_la_SOURCES = \ + kdf_plugin.h kdf_plugin.c \ -+ kdf_prf_plus.h kdf_prf_plus.c ++ kdf_kdf.h kdf_kdf.c + +libstrongswan_kdf_la_LDFLAGS = -module -avoid-version +Index: strongswan-5.9.5/src/libstrongswan/plugins/kdf/kdf_kdf.c +=================================================================== +--- /dev/null ++++ strongswan-5.9.5/src/libstrongswan/plugins/kdf/kdf_kdf.c +@@ -0,0 +1,205 @@ ++/* ++ * Copyright (C) 2022 Tobias Brunner, codelabs GmbH ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++ ++#include "kdf_kdf.h" ++ ++typedef struct private_kdf_t private_kdf_t; ++ ++/** ++ * Private data. ++ */ ++struct private_kdf_t { ++ ++ /** ++ * Public interface. ++ */ ++ kdf_t public; ++ ++ /** ++ * KDF type. ++ */ ++ key_derivation_function_t type; ++ ++ /** ++ * Underlying PRF. ++ */ ++ prf_t *prf; ++ ++ /** ++ * Salt value. ++ */ ++ chunk_t salt; ++}; ++ ++METHOD(kdf_t, get_type, key_derivation_function_t, ++ private_kdf_t *this) ++{ ++ return this->type; ++} ++ ++METHOD(kdf_t, get_length, size_t, ++ private_kdf_t *this) ++{ ++ if (this->type == KDF_PRF_PLUS) ++ { ++ return SIZE_MAX; ++ } ++ return this->prf->get_block_size(this->prf); ++} ++ ++METHOD(kdf_t, get_bytes_prf_plus, bool, ++ private_kdf_t *this, size_t out_len, uint8_t *buffer) ++{ ++ chunk_t block, previous = chunk_empty; ++ uint8_t counter = 1, *out = buffer; ++ size_t len; ++ bool success = TRUE; ++ ++ block = chunk_alloca(this->prf->get_block_size(this->prf)); ++ if (out_len > block.len * 255) ++ { ++ return FALSE; ++ } ++ ++ while (out_len) ++ { ++ if (!this->prf->get_bytes(this->prf, previous, NULL) || ++ !this->prf->get_bytes(this->prf, this->salt, NULL) || ++ !this->prf->get_bytes(this->prf, chunk_from_thing(counter), ++ block.ptr)) ++ { ++ success = FALSE; ++ break; ++ } ++ len = min(out_len, block.len); ++ memcpy(out, block.ptr, len); ++ previous = chunk_create(out, block.len); ++ ++ out_len -= len; ++ out += len; ++ counter++; ++ } ++ memwipe(block.ptr, block.len); ++ return success; ++} ++ ++METHOD(kdf_t, get_bytes, bool, ++ private_kdf_t *this, size_t out_len, uint8_t *buffer) ++{ ++ if (out_len != get_length(this)) ++ { ++ return FALSE; ++ } ++ return this->prf->get_bytes(this->prf, this->salt, buffer); ++} ++ ++METHOD(kdf_t, allocate_bytes, bool, ++ private_kdf_t *this, size_t out_len, chunk_t *chunk) ++{ ++ if (this->type == KDF_PRF) ++ { ++ out_len = out_len ?: get_length(this); ++ } ++ ++ *chunk = chunk_alloc(out_len); ++ ++ if (!this->public.get_bytes(&this->public, out_len, chunk->ptr)) ++ { ++ chunk_free(chunk); ++ return FALSE; ++ } ++ return TRUE; ++} ++ ++METHOD(kdf_t, set_param, bool, ++ private_kdf_t *this, kdf_param_t param, ...) ++{ ++ chunk_t chunk; ++ bool success = FALSE; ++ ++ switch (param) ++ { ++ case KDF_PARAM_KEY: ++ VA_ARGS_GET(param, chunk); ++ success = this->prf->set_key(this->prf, chunk); ++ break; ++ case KDF_PARAM_SALT: ++ VA_ARGS_GET(param, chunk); ++ chunk_clear(&this->salt); ++ this->salt = chunk_clone(chunk); ++ success = TRUE; ++ break; ++ } ++ return success; ++} ++ ++METHOD(kdf_t, destroy, void, ++ private_kdf_t *this) ++{ ++ this->prf->destroy(this->prf); ++ chunk_clear(&this->salt); ++ free(this); ++} ++ ++/* ++ * Described in header ++ */ ++kdf_t *kdf_kdf_create(key_derivation_function_t algo, va_list args) ++{ ++ private_kdf_t *this; ++ pseudo_random_function_t prf_alg; ++ prf_t *prf; ++ ++ if (algo != KDF_PRF && algo != KDF_PRF_PLUS) ++ { ++ return NULL; ++ } ++ ++ VA_ARGS_VGET(args, prf_alg); ++ prf = lib->crypto->create_prf(lib->crypto, prf_alg); ++ if (!prf) ++ { ++ DBG1(DBG_LIB, "failed to create %N for %N", ++ pseudo_random_function_names, prf_alg, ++ key_derivation_function_names, algo); ++ return NULL; ++ } ++ ++ INIT(this, ++ .public = { ++ .get_type = _get_type, ++ .get_length = _get_length, ++ .get_bytes = _get_bytes, ++ .allocate_bytes = _allocate_bytes, ++ .set_param = _set_param, ++ .destroy = _destroy, ++ }, ++ .type = algo, ++ .prf = prf, ++ ); ++ ++ if (algo == KDF_PRF_PLUS) ++ { ++ this->public.get_bytes = _get_bytes_prf_plus; ++ } ++ return &this->public; ++} +Index: strongswan-5.9.5/src/libstrongswan/plugins/kdf/kdf_kdf.h +=================================================================== +--- /dev/null ++++ strongswan-5.9.5/src/libstrongswan/plugins/kdf/kdf_kdf.h +@@ -0,0 +1,56 @@ ++/* ++ * Copyright (C) 2022 Tobias Brunner, codelabs GmbH ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++ ++/** ++ * Implements a KDF wrapper around PRFs, and prf+ as defined in RFC 7296, ++ * section 2.13: ++ * ++ * @verbatim ++ prf+ (K,S) = T1 | T2 | T3 | T4 | ... ++ ++ where: ++ T1 = prf (K, S | 0x01) ++ T2 = prf (K, T1 | S | 0x02) ++ T3 = prf (K, T2 | S | 0x03) ++ T4 = prf (K, T3 | S | 0x04) ++ ... ++ * @endverbatim ++ * ++ * @defgroup kdf_kdf kdf_kdf ++ * @{ @ingroup kdf_p ++ */ ++ ++#ifndef KDF_KDF_H_ ++#define KDF_KDF_H_ ++ ++#include ++ ++/** ++ * Create a kdf_t object ++ * ++ * @param algo KDF_PRF_PLUS ++ * @param args pseudo_random_function_t of the underlying PRF ++ * @return kdf_t object, NULL if not supported ++ */ ++kdf_t *kdf_kdf_create(key_derivation_function_t algo, va_list args); ++ ++#endif /** KDF_KDF_H_ @}*/ Index: strongswan-5.9.5/src/libstrongswan/plugins/kdf/kdf_plugin.c =================================================================== --- /dev/null +++ strongswan-5.9.5/src/libstrongswan/plugins/kdf/kdf_plugin.c -@@ -0,0 +1,88 @@ +@@ -0,0 +1,95 @@ +/* + * Copyright (C) 2022 Tobias Brunner, codelabs GmbH + * @@ -2494,7 +2930,7 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/kdf/kdf_plugin.c + */ + +#include "kdf_plugin.h" -+#include "kdf_prf_plus.h" ++#include "kdf_kdf.h" + +#include + @@ -2521,7 +2957,14 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/kdf/kdf_plugin.c + private_kdf_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { -+ PLUGIN_REGISTER(KDF, kdf_prf_plus_create), ++ PLUGIN_REGISTER(KDF, kdf_kdf_create), ++ PLUGIN_PROVIDE(KDF, KDF_PRF), ++ PLUGIN_SDEPEND(PRF, PRF_HMAC_SHA1), ++ PLUGIN_SDEPEND(PRF, PRF_HMAC_SHA2_256), ++ PLUGIN_SDEPEND(PRF, PRF_HMAC_SHA2_384), ++ PLUGIN_SDEPEND(PRF, PRF_HMAC_SHA2_512), ++ PLUGIN_SDEPEND(PRF, PRF_AES128_XCBC), ++ PLUGIN_SDEPEND(PRF, PRF_AES128_CMAC), + PLUGIN_PROVIDE(KDF, KDF_PRF_PLUS), + PLUGIN_SDEPEND(PRF, PRF_HMAC_SHA1), + PLUGIN_SDEPEND(PRF, PRF_HMAC_SHA2_256), @@ -2613,239 +3056,6 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/kdf/kdf_plugin.h +}; + +#endif /** KDF_PLUGIN_H_ @}*/ -Index: strongswan-5.9.5/src/libstrongswan/plugins/kdf/kdf_prf_plus.c -=================================================================== ---- /dev/null -+++ strongswan-5.9.5/src/libstrongswan/plugins/kdf/kdf_prf_plus.c -@@ -0,0 +1,168 @@ -+/* -+ * Copyright (C) 2022 Tobias Brunner, codelabs GmbH -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+#include "kdf_prf_plus.h" -+ -+typedef struct private_kdf_t private_kdf_t; -+ -+/** -+ * Private data. -+ */ -+struct private_kdf_t { -+ -+ /** -+ * Public interface. -+ */ -+ kdf_t public; -+ -+ /** -+ * Underlying PRF. -+ */ -+ prf_t *prf; -+ -+ /** -+ * Salt value. -+ */ -+ chunk_t salt; -+}; -+ -+METHOD(kdf_t, get_type, key_derivation_function_t, -+ private_kdf_t *this) -+{ -+ return KDF_PRF_PLUS; -+} -+ -+METHOD(kdf_t, get_bytes, bool, -+ private_kdf_t *this, size_t out_len, uint8_t *buffer) -+{ -+ chunk_t block, previous = chunk_empty; -+ uint8_t counter = 1, *out = buffer; -+ size_t len; -+ bool success = TRUE; -+ -+ block = chunk_alloca(this->prf->get_block_size(this->prf)); -+ if (out_len > block.len * 255) -+ { -+ return FALSE; -+ } -+ -+ while (out_len) -+ { -+ if (!this->prf->get_bytes(this->prf, previous, NULL) || -+ !this->prf->get_bytes(this->prf, this->salt, NULL) || -+ !this->prf->get_bytes(this->prf, chunk_from_thing(counter), -+ block.ptr)) -+ { -+ success = FALSE; -+ break; -+ } -+ len = min(out_len, block.len); -+ memcpy(out, block.ptr, len); -+ previous = chunk_create(out, block.len); -+ -+ out_len -= len; -+ out += len; -+ counter++; -+ } -+ memwipe(block.ptr, block.len); -+ return success; -+} -+ -+METHOD(kdf_t, allocate_bytes, bool, -+ private_kdf_t *this, size_t out_len, chunk_t *chunk) -+{ -+ *chunk = chunk_alloc(out_len); -+ -+ if (!get_bytes(this, out_len, chunk->ptr)) -+ { -+ chunk_free(chunk); -+ return FALSE; -+ } -+ return TRUE; -+} -+ -+METHOD(kdf_t, set_param, bool, -+ private_kdf_t *this, kdf_param_t param, ...) -+{ -+ chunk_t chunk; -+ bool success = FALSE; -+ -+ switch (param) -+ { -+ case KDF_PARAM_KEY: -+ VA_ARGS_GET(param, chunk); -+ success = this->prf->set_key(this->prf, chunk); -+ break; -+ case KDF_PARAM_SALT: -+ VA_ARGS_GET(param, chunk); -+ chunk_clear(&this->salt); -+ this->salt = chunk_clone(chunk); -+ success = TRUE; -+ break; -+ } -+ return success; -+} -+ -+METHOD(kdf_t, destroy, void, -+ private_kdf_t *this) -+{ -+ this->prf->destroy(this->prf); -+ chunk_clear(&this->salt); -+ free(this); -+} -+ -+/* -+ * Described in header -+ */ -+kdf_t *kdf_prf_plus_create(key_derivation_function_t algo, va_list args) -+{ -+ private_kdf_t *this; -+ pseudo_random_function_t prf_alg; -+ prf_t *prf; -+ -+ if (algo != KDF_PRF_PLUS) -+ { -+ return NULL; -+ } -+ -+ VA_ARGS_VGET(args, prf_alg); -+ prf = lib->crypto->create_prf(lib->crypto, prf_alg); -+ if (!prf) -+ { -+ DBG1(DBG_LIB, "failed to create %N for prf+", -+ pseudo_random_function_names, prf_alg); -+ return NULL; -+ } -+ -+ INIT(this, -+ .public = { -+ .get_type = _get_type, -+ .get_bytes = _get_bytes, -+ .allocate_bytes = _allocate_bytes, -+ .set_param = _set_param, -+ .destroy = _destroy, -+ }, -+ .prf = prf, -+ ); -+ -+ return &this->public; -+} -Index: strongswan-5.9.5/src/libstrongswan/plugins/kdf/kdf_prf_plus.h -=================================================================== ---- /dev/null -+++ strongswan-5.9.5/src/libstrongswan/plugins/kdf/kdf_prf_plus.h -@@ -0,0 +1,55 @@ -+/* -+ * Copyright (C) 2022 Tobias Brunner, codelabs GmbH -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a copy -+ * of this software and associated documentation files (the "Software"), to deal -+ * in the Software without restriction, including without limitation the rights -+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+ * copies of the Software, and to permit persons to whom the Software is -+ * furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+ * THE SOFTWARE. -+ */ -+ -+/** -+ * Implements prf+ as defined in RFC 7296, section 2.13: -+ * -+ * @verbatim -+ prf+ (K,S) = T1 | T2 | T3 | T4 | ... -+ -+ where: -+ T1 = prf (K, S | 0x01) -+ T2 = prf (K, T1 | S | 0x02) -+ T3 = prf (K, T2 | S | 0x03) -+ T4 = prf (K, T3 | S | 0x04) -+ ... -+ * @endverbatim -+ * -+ * @defgroup kdf_prf_plus kdf_prf_plus -+ * @{ @ingroup kdf_p -+ */ -+ -+#ifndef KDF_PRF_PLUS_H_ -+#define KDF_PRF_PLUS_H_ -+ -+#include -+ -+/** -+ * Create a kdf_t object -+ * -+ * @param algo KDF_PRF_PLUS -+ * @param args pseudo_random_function_t of the underlying PRF -+ * @return kdf_t object, NULL if not supported -+ */ -+kdf_t *kdf_prf_plus_create(key_derivation_function_t algo, va_list args); -+ -+#endif /** KDF_PRF_PLUS_H_ @}*/ Index: strongswan-5.9.5/src/libstrongswan/plugins/openssl/Makefile.am =================================================================== --- strongswan-5.9.5.orig/src/libstrongswan/plugins/openssl/Makefile.am @@ -2862,7 +3072,7 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/openssl/openssl_kdf.c =================================================================== --- /dev/null +++ strongswan-5.9.5/src/libstrongswan/plugins/openssl/openssl_kdf.c -@@ -0,0 +1,175 @@ +@@ -0,0 +1,223 @@ +/* + * Copyright (C) 2022 Tobias Brunner, codelabs GmbH + * @@ -2908,6 +3118,11 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/openssl/openssl_kdf.c + kdf_t public; + + /** ++ * KDF type. ++ */ ++ key_derivation_function_t type; ++ ++ /** + * Hasher to use for underlying PRF. + */ + const EVP_MD *hasher; @@ -2928,20 +3143,54 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/openssl/openssl_kdf.c +METHOD(kdf_t, get_type, key_derivation_function_t, + private_kdf_t *this) +{ -+ return KDF_PRF_PLUS; ++ return this->type; ++} ++ ++METHOD(kdf_t, get_length, size_t, ++ private_kdf_t *this) ++{ ++ if (this->type == KDF_PRF_PLUS) ++ { ++ return SIZE_MAX; ++ } ++ return EVP_MD_size(this->hasher); ++} ++ ++/** ++ * Set the parameters as a appropriate for the given KDF type. ++ */ ++static bool set_params(private_kdf_t *this, EVP_PKEY_CTX *ctx) ++{ ++ /* IKEv2 uses the nonces as PRF key and the DH secret as salt, however, ++ * HKDF-Extract() does the same again (mapping the salt to the HMAC key), ++ * so we have to switch key and salt here */ ++ if (this->type == KDF_PRF) ++ { ++ return EVP_PKEY_CTX_hkdf_mode(ctx, EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY) > 0 && ++ EVP_PKEY_CTX_set1_hkdf_key(ctx, this->salt.ptr, this->salt.len) > 0 && ++ EVP_PKEY_CTX_set1_hkdf_salt(ctx, this->key.ptr, this->key.len) > 0; ++ } ++ /* for HKDF-Expand() we map the salt to the "info" field */ ++ return EVP_PKEY_CTX_hkdf_mode(ctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) > 0 && ++ EVP_PKEY_CTX_set1_hkdf_key(ctx, this->key.ptr, this->key.len) > 0 && ++ EVP_PKEY_CTX_add1_hkdf_info(ctx, this->salt.ptr, this->salt.len) > 0; +} + +METHOD(kdf_t, get_bytes, bool, + private_kdf_t *this, size_t out_len, uint8_t *buffer) +{ -+ EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); ++ EVP_PKEY_CTX *ctx; + ++ if (this->type == KDF_PRF && out_len != get_length(this)) ++ { ++ return FALSE; ++ } ++ ++ ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); + if (!ctx || + EVP_PKEY_derive_init(ctx) <= 0 || + EVP_PKEY_CTX_set_hkdf_md(ctx, this->hasher) <= 0 || -+ EVP_PKEY_CTX_hkdf_mode(ctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) <= 0 || -+ EVP_PKEY_CTX_set1_hkdf_key(ctx, this->key.ptr, this->key.len) <= 0 || -+ EVP_PKEY_CTX_add1_hkdf_info(ctx, this->salt.ptr, this->salt.len) <= 0 || ++ !set_params(this, ctx) || + EVP_PKEY_derive(ctx, buffer, &out_len) <= 0) + { + EVP_PKEY_CTX_free(ctx); @@ -2954,6 +3203,11 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/openssl/openssl_kdf.c +METHOD(kdf_t, allocate_bytes, bool, + private_kdf_t *this, size_t out_len, chunk_t *chunk) +{ ++ if (this->type == KDF_PRF) ++ { ++ out_len = out_len ?: get_length(this); ++ } ++ + *chunk = chunk_alloc(out_len); + + if (!get_bytes(this, out_len, chunk->ptr)) @@ -3000,9 +3254,9 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/openssl/openssl_kdf.c +{ + private_kdf_t *this; + pseudo_random_function_t prf_alg; -+ char *name, buf[8]; ++ char *name, buf[EVP_MAX_MD_SIZE]; + -+ if (algo != KDF_PRF_PLUS) ++ if (algo != KDF_PRF && algo != KDF_PRF_PLUS) + { + return NULL; + } @@ -3018,18 +3272,22 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/openssl/openssl_kdf.c + INIT(this, + .public = { + .get_type = _get_type, ++ .get_length = _get_length, + .get_bytes = _get_bytes, + .allocate_bytes = _allocate_bytes, + .set_param = _set_param, + .destroy = _destroy, + }, ++ .type = algo, + .hasher = EVP_get_digestbyname(name), -+ /* use a lengthy key to test the implementation below to make sure the -+ * algorithms are usable, see openssl_hmac.c for details */ ++ /* use a lengthy key/salt to test the implementation below to make sure ++ * the algorithms are usable, see openssl_hmac.c for details */ + .key = chunk_clone(chunk_from_str("00000000000000000000000000000000")), ++ .salt = chunk_clone(chunk_from_str("00000000000000000000000000000000")), + ); + -+ if (!this->hasher || !get_bytes(this, sizeof(buf), buf)) ++ if (!this->hasher || ++ !get_bytes(this, algo == KDF_PRF ? get_length(this) : sizeof(buf), buf)) + { + destroy(this); + return NULL; @@ -3122,19 +3380,20 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/openssl/openssl_plugin.c }; /** -@@ -662,6 +655,11 @@ METHOD(plugin_t, get_features, int, +@@ -662,6 +655,12 @@ METHOD(plugin_t, get_features, int, PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_512_256), PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_512_512), #endif +#if OPENSSL_VERSION_NUMBER >= 0x10101000L + /* HKDF is available since 1.1.0, expand-only mode only since 1.1.1 */ + PLUGIN_REGISTER(KDF, openssl_kdf_create), ++ PLUGIN_PROVIDE(KDF, KDF_PRF), + PLUGIN_PROVIDE(KDF, KDF_PRF_PLUS), +#endif #endif /* OPENSSL_NO_HMAC */ #if (OPENSSL_VERSION_NUMBER >= 0x1000100fL && !defined(OPENSSL_NO_AES)) || \ (OPENSSL_VERSION_NUMBER >= 0x1010000fL && !defined(OPENSSL_NO_CHACHA)) -@@ -887,15 +885,6 @@ METHOD(plugin_t, get_features, int, +@@ -887,15 +886,6 @@ METHOD(plugin_t, get_features, int, METHOD(plugin_t, destroy, void, private_openssl_plugin_t *this) { @@ -3150,7 +3409,7 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/openssl/openssl_plugin.c /* OpenSSL 1.1.0 cleans up itself at exit and while OPENSSL_cleanup() exists we * can't call it as we couldn't re-initialize the library (as required by the * unit tests and the Android app) */ -@@ -1009,20 +998,16 @@ plugin_t *openssl_plugin_create() +@@ -1009,20 +999,16 @@ plugin_t *openssl_plugin_create() DBG1(DBG_LIB, "unable to load OpenSSL FIPS provider"); return NULL; } @@ -3347,10 +3606,11 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/test_vectors/Makefile.am =================================================================== --- strongswan-5.9.5.orig/src/libstrongswan/plugins/test_vectors/Makefile.am +++ strongswan-5.9.5/src/libstrongswan/plugins/test_vectors/Makefile.am -@@ -30,6 +30,7 @@ libstrongswan_test_vectors_la_SOURCES = +@@ -30,6 +30,8 @@ libstrongswan_test_vectors_la_SOURCES = test_vectors/cast.c \ test_vectors/des.c \ test_vectors/idea.c \ ++ test_vectors/kdf_prf.c \ + test_vectors/kdf_prf_plus.c \ test_vectors/null.c \ test_vectors/rc2.c \ @@ -3359,10 +3619,16 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/test_vectors/test_vectors.h =================================================================== --- strongswan-5.9.5.orig/src/libstrongswan/plugins/test_vectors/test_vectors.h +++ strongswan-5.9.5/src/libstrongswan/plugins/test_vectors/test_vectors.h -@@ -220,6 +220,14 @@ TEST_VECTOR_HASHER(sha3_256_255) +@@ -220,6 +220,20 @@ TEST_VECTOR_HASHER(sha3_256_255) TEST_VECTOR_HASHER(sha3_384_255) TEST_VECTOR_HASHER(sha3_512_255) ++TEST_VECTOR_KDF(prf_sha256_1) ++TEST_VECTOR_KDF(prf_sha256_2) ++TEST_VECTOR_KDF(prf_sha384_1) ++TEST_VECTOR_KDF(prf_sha384_2) ++TEST_VECTOR_KDF(prf_sha512_1) ++TEST_VECTOR_KDF(prf_sha512_2) +TEST_VECTOR_KDF(prf_plus_sha256_old) +TEST_VECTOR_KDF(prf_plus_sha256_1) +TEST_VECTOR_KDF(prf_plus_sha256_2) @@ -3374,6 +3640,247 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/test_vectors/test_vectors.h TEST_VECTOR_PRF(aes_xcbc_p1) TEST_VECTOR_PRF(aes_xcbc_p2) TEST_VECTOR_PRF(aes_xcbc_p3) +Index: strongswan-5.9.5/src/libstrongswan/plugins/test_vectors/test_vectors/kdf_prf.c +=================================================================== +--- /dev/null ++++ strongswan-5.9.5/src/libstrongswan/plugins/test_vectors/test_vectors/kdf_prf.c +@@ -0,0 +1,236 @@ ++/* ++ * Copyright (C) 2022 Tobias Brunner, codelabs GmbH ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++ ++#include ++ ++/** ++ * The following test vectors are from CAVP/SP 800-135 for IKEv2. ++ * ++ * key = Ni | Nr, salt = g^ir (one vector with min. and one with max. size for ++ * nonces) ++ */ ++kdf_test_vector_t prf_sha256_1 = { ++ .alg = KDF_PRF, .arg.prf = PRF_HMAC_SHA2_256, ++ .key = chunk_from_chars( ++ 0xed,0x80,0xdc,0x79,0x91,0x2c,0x32,0xa9,0x35,0xfb,0x6d,0x1a,0x3f,0xea,0xc0,0x78), ++ .salt = chunk_from_chars( ++ 0x42,0x96,0x8e,0x5d,0x0c,0xcc,0x3c,0xfc,0x5a,0x3e,0x4b,0xc1,0xbb,0xa3,0x70,0xce, ++ 0xa1,0xfa,0xe0,0xd5,0x4c,0x49,0xcc,0xba,0x34,0xb2,0xbe,0xe8,0x04,0xbe,0xeb,0x2e, ++ 0x9e,0x8c,0x57,0xa4,0xe0,0x1b,0xd4,0x51,0x02,0xcf,0x24,0x33,0xaa,0xcc,0x6c,0xfe, ++ 0xc0,0x67,0x92,0xf3,0x63,0xe5,0x17,0x0e,0x6a,0xa6,0x65,0x02,0x74,0xe9,0x06,0x64, ++ 0x8e,0x44,0x9d,0x27,0xa8,0xf0,0x0b,0x5b,0x44,0x26,0x19,0x82,0xc9,0x83,0x5c,0x74, ++ 0x8a,0x75,0x1e,0xc5,0x13,0x8e,0xaa,0xcc,0x5e,0x02,0x56,0x61,0x33,0x95,0x38,0xa6, ++ 0x1b,0xf4,0x18,0xe4,0x54,0x69,0x9e,0x19,0xc3,0x2d,0xb8,0xd9,0xce,0x5d,0xd8,0x6b, ++ 0x22,0x0f,0x1e,0x89,0xaf,0xc5,0x87,0x2e,0x68,0xbe,0x36,0xcb,0x1a,0x0c,0x88,0x66), ++ .out = chunk_from_chars( ++ 0x37,0xfd,0xe9,0x0b,0x81,0xd6,0x36,0x92,0x62,0x0f,0x67,0x36,0x7b,0x62,0x09,0x2e, ++ 0x3e,0xfd,0xc6,0xa0,0x35,0x09,0x13,0x7d,0x73,0x10,0x04,0x76,0x7f,0xf3,0x50,0x10), ++}; ++ ++kdf_test_vector_t prf_sha256_2 = { ++ .alg = KDF_PRF, .arg.prf = PRF_HMAC_SHA2_256, ++ .key = chunk_from_chars( ++ 0xef,0xa7,0x29,0x13,0x18,0x22,0x78,0xff,0xbd,0x14,0xe7,0x89,0x20,0xc0,0x62,0x51, ++ 0x9a,0xba,0xb8,0xc1,0x6e,0x5e,0xd7,0x0c,0x08,0x41,0xa4,0x8c,0xdb,0x98,0x23,0x7e, ++ 0xe9,0x3f,0x73,0x5f,0xb2,0xdf,0x18,0x43,0x58,0xaa,0xdc,0x13,0xd8,0x3f,0x43,0xfe, ++ 0x8d,0x87,0x05,0x17,0x6c,0x8c,0xa3,0x13,0x82,0x5a,0x1b,0xcd,0xf7,0x79,0x11,0xc5, ++ 0x98,0x00,0x16,0x71,0xff,0xbf,0x01,0x4e,0x37,0xa8,0xc0,0x4d,0x49,0xa7,0x83,0x9d, ++ 0xfe,0xa6,0xcd,0xc5,0x87,0x68,0x8d,0x45,0x88,0xfe,0x43,0x23,0x5b,0x71,0x69,0x3f, ++ 0xfd,0x07,0x29,0x33,0x86,0xb6,0xbf,0x4c,0x19,0x9e,0x33,0x61,0x65,0xb2,0x60,0x78, ++ 0x77,0x36,0xf5,0x4b,0xe9,0x5d,0xb6,0x91,0x16,0x38,0x8b,0xc2,0xec,0xa2,0xb3,0xb2, ++ 0x94,0x84,0x71,0x74,0x17,0xbb,0x3c,0x71,0x81,0x4c,0xe1,0x3b,0x84,0x44,0x6d,0xc3, ++ 0x96,0x4c,0x30,0x29,0x84,0xf9,0x77,0x81,0xf6,0x31,0x66,0x24,0x08,0x90,0x10,0x7c, ++ 0x2e,0x75,0x1a,0x00,0x43,0x6f,0x7c,0x3c,0x9f,0xf1,0x27,0x60,0xe4,0x9d,0x91,0x56, ++ 0x3b,0xe6,0x03,0xfd,0x96,0x41,0xa0,0xa6,0x49,0x18,0xa9,0x32,0x91,0xed,0x11,0x3d, ++ 0xb1,0x2f,0x97,0x07,0x60,0x9d,0x17,0x20,0x96,0xeb,0x58,0xf9,0x15,0x44,0x74,0xda, ++ 0x40,0xc1,0xf5,0xc0,0x90,0x3e,0x9c,0xa2,0xf9,0x1b,0xa6,0x60,0x07,0x75,0xdf,0x71, ++ 0x66,0xca,0xf8,0xe3,0x27,0x85,0x9e,0x67,0x62,0x32,0xd3,0x40,0x46,0x04,0x4c,0xee, ++ 0x43,0xf9,0x01,0x9f,0x04,0x68,0x56,0x12,0x63,0x5b,0x99,0xcb,0xeb,0xcb,0x36,0x3d, ++ 0x56,0x5e,0xaf,0x0e,0x54,0x7e,0xec,0xb9,0x41,0xc9,0x94,0xdf,0xd4,0x71,0xed,0x56, ++ 0x43,0xc0,0x87,0x74,0x4f,0x77,0x09,0xcc,0x3e,0x25,0x10,0xf2,0x74,0x26,0xc6,0x2c, ++ 0x0f,0xf3,0xac,0xb3,0xc2,0x76,0x61,0xd2,0x6a,0x6d,0x83,0xc2,0xa2,0x5e,0x13,0xa6, ++ 0xd4,0x65,0xbd,0x04,0x7f,0x90,0x55,0x00,0xe5,0xeb,0xbe,0x42,0x66,0x43,0x0d,0x56, ++ 0x67,0x14,0x0f,0x77,0xe7,0x97,0x71,0x2a,0x8c,0x8f,0x63,0xc5,0x83,0xf4,0xb4,0x64, ++ 0x9b,0x72,0x89,0x9e,0xa3,0x4a,0xbf,0xdb,0x17,0x61,0x7c,0x46,0x0c,0x35,0xf2,0x50, ++ 0x64,0x94,0x49,0x4f,0x22,0x3e,0x25,0x1a,0xc7,0x1a,0x5b,0x9b,0x7e,0xea,0x87,0xf4, ++ 0xf5,0xe3,0x33,0xa3,0xc1,0xbb,0xb4,0xbb,0x09,0x25,0x8b,0x6a,0x4b,0x5f,0x8c,0x9f, ++ 0xb8,0x2b,0xf4,0x2d,0xa9,0xd4,0xa4,0x65,0x43,0xc6,0xa9,0xeb,0x9a,0xa3,0x0e,0xa9, ++ 0xda,0x80,0x19,0x15,0xab,0xcc,0x17,0x12,0xd0,0x82,0xf2,0x92,0xa6,0x3f,0xd9,0xaf, ++ 0x71,0x54,0xa9,0x7c,0xc7,0x38,0x59,0xa4,0xbe,0x3c,0xba,0x35,0x9d,0x32,0x18,0x00, ++ 0x4e,0x14,0xdf,0x02,0xd0,0x9e,0xdf,0x0a,0xd5,0x79,0x6b,0xb0,0x10,0x99,0x52,0x93, ++ 0xab,0x5d,0x04,0x2c,0x31,0x05,0x53,0x80,0xcc,0x9c,0xb2,0xe3,0x61,0x79,0x82,0xc4, ++ 0x5f,0x6b,0xce,0x1f,0xb8,0xa4,0x0e,0xf9,0xea,0xc4,0x8a,0xe1,0x77,0x20,0xdf,0xec, ++ 0xc7,0x1e,0xc8,0x57,0xea,0x33,0xf3,0x2e,0xb3,0x46,0xba,0x60,0x36,0xe8,0xf9,0xcc, ++ 0xd7,0xbc,0xad,0xc6,0xc1,0xab,0x92,0xa8,0x0c,0x57,0xe7,0x89,0x59,0xd8,0xb8,0x28), ++ .salt = chunk_from_chars( ++ 0xb0,0x70,0x20,0x8f,0x89,0x47,0xdf,0x4f,0x7d,0x12,0x76,0x16,0x1f,0x40,0x7f,0x7b, ++ 0x7f,0x5c,0x4a,0x49,0xac,0x79,0xf0,0xcc,0x0c,0x7d,0x4e,0x28,0x48,0x4c,0x6f,0x85, ++ 0x84,0xf0,0x00,0x7b,0x9b,0xf0,0xe0,0x5f,0xdb,0x59,0x61,0xa1,0x7d,0x3a,0xa8,0x5c, ++ 0x6e,0x3f,0x55,0x71,0x29,0x6a,0x43,0xba,0x89,0x6c,0xdc,0x88,0xc1,0xa4,0x45,0x7f, ++ 0xb1,0x2c,0xbe,0x56,0xca,0x4a,0x20,0xc9,0xa7,0xe1,0x9a,0xdc,0x67,0x45,0x3c,0x4a, ++ 0xde,0x53,0x9e,0x25,0x9f,0x82,0x5f,0xf9,0x4c,0x9a,0x83,0xf8,0x39,0x60,0x2f,0x86, ++ 0x51,0xc9,0x27,0x6d,0x8e,0x44,0x4e,0xcb,0x95,0xa0,0x54,0x0e,0xe7,0xea,0x32,0x20, ++ 0xa9,0x22,0x34,0x5e,0xd9,0x9e,0xf7,0xe7,0xad,0x32,0xb1,0x9d,0x46,0x10,0xe9,0xef), ++ .out = chunk_from_chars( ++ 0x29,0xbd,0x11,0x55,0x68,0xae,0x09,0x88,0x27,0x0f,0xc3,0x86,0xd3,0x95,0xfe,0x37, ++ 0x07,0xa4,0xd0,0x62,0x89,0xf3,0x52,0xbb,0xa4,0xc0,0x0a,0x9a,0xd8,0x55,0xa0,0x8d), ++}; ++ ++kdf_test_vector_t prf_sha384_1 = { ++ .alg = KDF_PRF, .arg.prf = PRF_HMAC_SHA2_384, ++ .key = chunk_from_chars( ++ 0xd6,0x72,0xb0,0xbc,0x85,0x28,0x29,0xb9,0x35,0x09,0xf3,0xb7,0x24,0x70,0x63,0x64), ++ .salt = chunk_from_chars( ++ 0x4d,0xf0,0x40,0xb7,0x09,0x78,0x62,0x9c,0x49,0x43,0x7c,0xff,0x41,0xa0,0xd4,0x6c, ++ 0xbe,0xa6,0x8c,0x8d,0x75,0xb3,0x70,0xff,0xc1,0x1d,0x7b,0x38,0x71,0x44,0xea,0x83, ++ 0xbb,0x59,0x03,0xfb,0xb9,0x2e,0x47,0x3d,0xf5,0x0a,0x9b,0x19,0xea,0x43,0xe9,0xc2, ++ 0xf3,0xda,0x9a,0x84,0x9c,0x03,0x86,0x42,0x76,0xc6,0xf2,0x64,0xec,0xf0,0x2a,0x60, ++ 0xd4,0x0b,0xa6,0x5c,0x06,0x65,0x6b,0x63,0x3f,0x02,0xa8,0x74,0x27,0xe9,0x28,0xeb, ++ 0x66,0xa2,0xda,0xbd,0x9d,0xc0,0x57,0x44,0x71,0x7b,0xca,0xf7,0xae,0x78,0xc2,0x96, ++ 0x87,0x2f,0x5c,0x48,0xd1,0xa8,0x12,0x0c,0x21,0x55,0xb7,0x0c,0x56,0x5c,0xe2,0x71, ++ 0x99,0x8e,0x3e,0x44,0xaf,0x26,0x3d,0x48,0x7e,0xa3,0xba,0x7f,0x56,0x13,0x2d,0x7d), ++ .out = chunk_from_chars( ++ 0x54,0x43,0x6a,0x9e,0xa9,0x5d,0x6f,0xf7,0x9b,0x96,0x7f,0x4b,0x07,0xf6,0xde,0x97, ++ 0x6a,0x37,0x6e,0x8e,0xa2,0x6a,0xa9,0x57,0x47,0x09,0xaf,0xc6,0x02,0x43,0xc9,0xc1, ++ 0x41,0xda,0x4c,0xa0,0xe1,0x58,0xe6,0x27,0xa7,0x5e,0xa8,0x7f,0x6f,0xeb,0x07,0xef), ++}; ++ ++kdf_test_vector_t prf_sha384_2 = { ++ .alg = KDF_PRF, .arg.prf = PRF_HMAC_SHA2_384, ++ .key = chunk_from_chars( ++ 0x9e,0x2a,0x62,0xf9,0x36,0x28,0x93,0xdd,0xf8,0x47,0x16,0xfe,0xc2,0xf2,0x3f,0x9d, ++ 0xcb,0xd9,0x01,0x0d,0xf6,0xfe,0x9e,0x0e,0xb4,0x6d,0x03,0xd9,0x14,0xf3,0x04,0xd8, ++ 0xfe,0x4d,0x3e,0xe2,0xd6,0xa0,0x3b,0x40,0xe5,0x6a,0x32,0x5e,0x82,0x2a,0x17,0x36, ++ 0x19,0x29,0x18,0x4a,0xde,0x09,0xea,0xa4,0x45,0x27,0x8d,0x38,0x70,0x41,0x7a,0x7c, ++ 0xf5,0x65,0x58,0x4f,0x57,0x2a,0xd3,0x4f,0xf7,0x2b,0xc7,0x78,0x1a,0x39,0xa4,0x8b, ++ 0x54,0xb5,0x5d,0x6e,0xb0,0xed,0x68,0x55,0x1b,0x22,0x2c,0x7a,0xfa,0xda,0x0b,0xc8, ++ 0x22,0x36,0xec,0x31,0xce,0x6c,0x04,0x6b,0x3b,0x2e,0xdb,0x2d,0xef,0x61,0xf4,0xd2, ++ 0xd8,0x57,0xb2,0xd1,0xcb,0x36,0x96,0xc0,0x23,0xe0,0x8c,0x08,0xd6,0xab,0xd0,0x4d, ++ 0x4f,0x69,0x09,0x2b,0x14,0x58,0x37,0x35,0xb9,0xe9,0x18,0xae,0xe5,0xa3,0x99,0x9d, ++ 0xcb,0xf5,0x8f,0xda,0xd6,0xfc,0xd4,0x7c,0x95,0x92,0x98,0x77,0x03,0x0e,0x54,0xb7, ++ 0x08,0x23,0x5f,0x2a,0x2e,0x11,0xe7,0xc5,0x85,0x84,0x61,0x9a,0xa2,0xfa,0x69,0x31, ++ 0x53,0x44,0xd3,0x65,0x7b,0x55,0x72,0x0a,0x25,0xeb,0xe8,0x8e,0xa0,0x77,0x69,0x72, ++ 0xc9,0xe2,0x24,0x69,0xb7,0xed,0x5d,0xa9,0x6b,0x3c,0x76,0x85,0xf7,0xb0,0x56,0x99, ++ 0x60,0xbd,0x64,0x4f,0x13,0x0b,0x44,0xa0,0xd5,0x51,0xbb,0x0e,0x90,0x2e,0xd6,0x8a, ++ 0xb3,0x84,0xfd,0xc2,0xfa,0xca,0xf7,0x9b,0xbf,0x8d,0x6d,0x37,0x36,0xdf,0xa9,0x52, ++ 0xcd,0x70,0xf4,0x74,0x6f,0x1a,0x4a,0xea,0xc2,0xbd,0xbe,0xca,0x97,0xb7,0x8f,0xc1, ++ 0x77,0x78,0x78,0xc1,0x28,0x59,0x43,0x35,0x52,0xa7,0x7d,0x7f,0x94,0x2e,0x5b,0x60, ++ 0x47,0x69,0x91,0xa1,0xe3,0xd0,0x42,0x7c,0xd6,0x77,0x34,0x5a,0x1c,0xe2,0x06,0x3a, ++ 0x2e,0x0e,0xc5,0x47,0xa9,0xd8,0x21,0xda,0x75,0x9f,0x1a,0x91,0xb5,0x88,0x17,0xbd, ++ 0x0d,0xc4,0xef,0xfc,0x12,0x6f,0x6f,0x4e,0xb0,0xb9,0x11,0xe9,0x04,0xed,0x21,0xdc, ++ 0x43,0x9d,0x65,0x8a,0x77,0x3f,0x97,0xe1,0x79,0xad,0x20,0xbc,0x3c,0x63,0x60,0x9f, ++ 0x28,0x74,0x06,0x2e,0x83,0x5f,0x6a,0xe0,0x8d,0x59,0x65,0x4f,0x9c,0x88,0x61,0xe5, ++ 0x27,0x03,0x9e,0xea,0xc3,0x2b,0x9e,0xed,0x29,0x3b,0xd8,0xb1,0xe0,0xe7,0xc6,0x7b, ++ 0xf1,0xd7,0x55,0x24,0x6a,0x1b,0x06,0x3f,0xf0,0x06,0x32,0xa4,0x6d,0xd5,0xcf,0x69, ++ 0x48,0xf0,0xee,0xd9,0xb6,0x5c,0x59,0x39,0xdf,0xd2,0x14,0x80,0xa6,0x3d,0xf0,0xca, ++ 0xb0,0xa7,0x50,0x9c,0x42,0x45,0xa1,0xbe,0x75,0x47,0xcc,0xc6,0xf7,0x3c,0x72,0x4b, ++ 0x48,0xb7,0x86,0x70,0x12,0xe0,0xca,0x3e,0x47,0x2e,0x0d,0x55,0x06,0x49,0xa7,0x34, ++ 0x44,0x0f,0xef,0xfc,0x8e,0x73,0x68,0x2c,0xb6,0x04,0x53,0xe7,0xa4,0x7e,0x72,0xfe, ++ 0x08,0x74,0xeb,0x40,0xac,0xd0,0xd4,0x8e,0x4e,0x57,0x19,0x74,0x16,0x11,0x2b,0xcd, ++ 0xc8,0xbb,0x7a,0x58,0xbe,0xa7,0x45,0xfd,0xd6,0x4c,0x16,0xf6,0x66,0xc8,0x8d,0x9e, ++ 0x3b,0xd2,0x35,0xb1,0x37,0x20,0x6f,0x6c,0xdb,0xa1,0x90,0xbe,0x65,0xec,0x03,0x3c, ++ 0x19,0x1f,0x67,0x6b,0x42,0x8e,0xc1,0x20,0x5d,0xc5,0xe9,0x45,0x82,0x85,0x08,0xd8), ++ .salt = chunk_from_chars( ++ 0xae,0x50,0x50,0x82,0xac,0x47,0xff,0x9a,0xa3,0x54,0xb7,0xaf,0x2b,0x07,0x2c,0xb4, ++ 0x9c,0xec,0x83,0x8d,0x00,0xee,0x36,0x13,0x88,0x1a,0x99,0x77,0xb2,0x15,0x95,0x99, ++ 0xa0,0x24,0x95,0xf0,0xe5,0x2d,0x96,0x1a,0x51,0x6c,0x6b,0xb6,0x1e,0xd0,0x3a,0x86, ++ 0x37,0xbb,0x50,0x7c,0x5c,0x27,0xba,0xb5,0x8d,0xf1,0x54,0xe8,0xe5,0x01,0x48,0x21, ++ 0x84,0x0c,0xfc,0x50,0xb3,0xa4,0x78,0xb4,0x5d,0xd1,0x68,0xeb,0x18,0x0d,0x69,0xcb, ++ 0xa6,0x1a,0x1b,0x42,0x59,0x19,0x3a,0x51,0xa7,0xa4,0x95,0xc9,0x58,0x05,0x38,0x2e, ++ 0x3a,0xbf,0x55,0x87,0x68,0x8f,0x34,0xb6,0x3f,0x71,0x16,0x39,0x82,0xde,0x3d,0xdf, ++ 0x7f,0x26,0x3b,0xb6,0x9f,0x65,0xc3,0xec,0xae,0x61,0x65,0xbf,0x7f,0xdd,0x53,0x17), ++ .out = chunk_from_chars( ++ 0xff,0x66,0xe9,0xd0,0x92,0xdc,0x01,0xe0,0xb8,0x1f,0x93,0x9f,0x52,0xf5,0xc0,0x7d, ++ 0x38,0xd8,0x05,0xb9,0x86,0x28,0xce,0x1a,0xc5,0xfe,0x94,0xc0,0x98,0x57,0x76,0x47, ++ 0x33,0x9f,0xad,0x68,0x94,0x1f,0xfe,0x21,0xe0,0x1e,0xfb,0x4e,0x70,0x50,0x21,0x3b), ++}; ++ ++kdf_test_vector_t prf_sha512_1 = { ++ .alg = KDF_PRF, .arg.prf = PRF_HMAC_SHA2_512, ++ .key = chunk_from_chars( ++ 0xdf,0x79,0x31,0xdb,0x9b,0x42,0x9e,0x10,0xb8,0xaa,0x8e,0x4d,0x46,0x04,0x23,0x93), ++ .salt = chunk_from_chars( ++ 0x1e,0x3b,0x00,0x7d,0x2d,0xa9,0x13,0xca,0x60,0xec,0xc9,0x8c,0x25,0xa2,0x2d,0xb0, ++ 0x80,0x73,0xd5,0xc3,0x5c,0x11,0xb2,0x52,0x4b,0x29,0x8a,0x92,0x2b,0x6a,0xbf,0xe6, ++ 0xac,0xf7,0x35,0x9d,0xb6,0x6a,0xe5,0xf8,0x5d,0x67,0xaa,0xcf,0xf6,0x86,0x41,0x9c, ++ 0xd8,0x66,0x6d,0x05,0xae,0x79,0x77,0xce,0xfa,0xd7,0xf5,0x4d,0xd8,0xe3,0x12,0xa8, ++ 0xe8,0xe5,0xe0,0x37,0x0f,0x88,0x14,0x2f,0xbd,0xd6,0x59,0xdd,0x6f,0xde,0x22,0xbd, ++ 0xd5,0x31,0xf5,0x40,0x28,0x81,0xa8,0xde,0x85,0xc1,0x02,0x4e,0x59,0x5e,0xc9,0x3c, ++ 0x57,0x56,0x18,0xaf,0x7f,0xd3,0xdb,0xac,0x79,0x82,0x91,0x90,0x78,0xd7,0x1c,0xc1, ++ 0x3e,0xff,0x19,0x10,0xa0,0x32,0x75,0x0e,0x1f,0xf4,0x28,0x67,0x5d,0xe1,0x89,0xee), ++ .out = chunk_from_chars( ++ 0xda,0xf9,0xbd,0x6f,0x2f,0x91,0x2d,0xa5,0x53,0x86,0x79,0x66,0xaf,0x38,0x6e,0x67, ++ 0x90,0x9a,0x8d,0xf0,0xca,0x7e,0x84,0xb8,0x3b,0x35,0x5c,0xb7,0xd7,0xf1,0x02,0x6f, ++ 0x17,0xd8,0xea,0x34,0xb5,0xd5,0x7f,0xd0,0xd1,0xba,0x38,0x95,0x28,0xfc,0xa1,0xe8, ++ 0x1d,0x1c,0x8c,0xe5,0x11,0xb2,0x8a,0x24,0x58,0x24,0x11,0x43,0xfe,0xe3,0x0c,0xcc), ++}; ++ ++kdf_test_vector_t prf_sha512_2 = { ++ .alg = KDF_PRF, .arg.prf = PRF_HMAC_SHA2_512, ++ .key = chunk_from_chars( ++ 0xd8,0x96,0x84,0xe3,0xcb,0x17,0xf3,0xaa,0xbd,0x85,0x3a,0x78,0xdb,0x3e,0xcd,0x5a, ++ 0xac,0xc1,0xed,0x71,0xc7,0x0b,0x88,0xa2,0x97,0x56,0xf4,0x6f,0xc7,0x19,0x7c,0x80, ++ 0x4e,0xc0,0x01,0x54,0x40,0x02,0xa8,0xae,0xa3,0x60,0x68,0x4b,0x18,0x00,0x6d,0xef, ++ 0x0d,0xbd,0x86,0x33,0xb1,0x01,0x9f,0xbc,0xfa,0x85,0xb9,0x4c,0xac,0x2b,0xb8,0x21, ++ 0x25,0x84,0xbe,0x62,0xad,0xab,0x0e,0xe4,0xbb,0x8a,0x36,0xae,0xe2,0x52,0x75,0xef, ++ 0x07,0x13,0x90,0x48,0x0e,0xef,0xa2,0x09,0x2e,0xb3,0x08,0xaa,0x73,0x37,0xc5,0xce, ++ 0xb6,0x06,0x9a,0xb6,0x90,0xe8,0x96,0x2f,0xbf,0xe0,0x98,0x6e,0x4f,0x5c,0x18,0xf4, ++ 0x86,0x86,0x1e,0xd3,0xf1,0xdc,0xbe,0xe4,0xc9,0xe4,0xa7,0x66,0x9d,0x74,0x0c,0xa2, ++ 0xb0,0xe8,0xed,0x40,0x31,0xb0,0xa4,0x99,0xdc,0x31,0x5c,0xed,0xe7,0xef,0x03,0x39, ++ 0x9c,0xbc,0x33,0xdc,0xd6,0x29,0x70,0x34,0x9f,0x12,0x20,0x88,0x1b,0x55,0x45,0x2e, ++ 0x0c,0x6c,0x9b,0x52,0xa8,0x8b,0x67,0xf5,0x97,0x58,0x67,0x95,0xb2,0x25,0x70,0x73, ++ 0x3f,0xd4,0xff,0x2c,0xc2,0xad,0x93,0x1d,0x83,0x30,0x16,0x5a,0x9e,0x45,0x0e,0x38, ++ 0x88,0x59,0xce,0x62,0x4f,0x01,0xdb,0x17,0xc2,0x50,0x2b,0x4e,0x66,0xad,0xf9,0x65, ++ 0x27,0x36,0x3d,0x6f,0x90,0x6b,0x20,0x23,0xe8,0xed,0x74,0xd5,0xaf,0x0a,0xa6,0x02, ++ 0x46,0xb0,0xb9,0x2f,0x49,0xc4,0x93,0x3e,0xf3,0x12,0xf8,0xa2,0x54,0x34,0xee,0x96, ++ 0x98,0xd6,0xd9,0x20,0x43,0x45,0xbd,0x10,0xbb,0x11,0xaa,0x39,0x86,0x56,0x16,0xd5, ++ 0xad,0x1b,0x57,0x44,0x70,0x6c,0xfd,0x4e,0xa1,0x40,0x8e,0x20,0xc8,0xfd,0xcf,0x85, ++ 0x51,0xee,0xe8,0x81,0x4b,0x7b,0x37,0x33,0x0b,0x05,0x26,0xf0,0xbc,0x5e,0xe1,0x5d, ++ 0x4e,0xcd,0xa7,0xa1,0xbd,0x25,0xaa,0x97,0xf2,0x45,0x84,0xd8,0x5d,0x3f,0x52,0x49, ++ 0x69,0x4b,0x9f,0x43,0x53,0x9e,0x69,0xea,0x35,0xbf,0xe7,0xfd,0x44,0x07,0xbc,0x8e, ++ 0x9d,0xca,0x8a,0x9f,0xae,0x4b,0xdc,0x6b,0x7b,0xb3,0x8c,0x6d,0x68,0xf8,0x99,0xe1, ++ 0xd3,0x2c,0x85,0xbc,0xd6,0x17,0xa5,0x67,0x67,0x8c,0xf8,0x5d,0x22,0x17,0xa4,0xe8, ++ 0x6a,0x75,0x56,0x24,0xb6,0x40,0x02,0x35,0x4c,0x02,0x68,0x42,0xbc,0x95,0x42,0x49, ++ 0x1a,0xf1,0xc3,0xd6,0x29,0x09,0x70,0x55,0x9a,0xf1,0x1b,0xdc,0x2c,0x83,0xb5,0x4c, ++ 0x74,0x14,0x49,0x05,0xc0,0xa3,0x58,0xf3,0x15,0x3d,0xb7,0x67,0xa5,0xda,0x2a,0x86, ++ 0x27,0xf6,0x96,0x27,0xe1,0xd4,0x1e,0xde,0x9c,0x90,0x7c,0x79,0xb5,0x1f,0xf8,0x15, ++ 0xe4,0x64,0x5c,0x33,0x75,0xe0,0xf6,0x3f,0x84,0xfc,0xf5,0xd7,0xc3,0x40,0x7a,0x1d, ++ 0xd6,0x83,0x9e,0x19,0x06,0xa1,0xe3,0x80,0x2c,0xcf,0x5e,0x82,0x30,0xd9,0x5c,0xf4, ++ 0xb8,0x27,0xb4,0x1c,0x48,0x34,0x25,0xa8,0xa6,0x0b,0xfa,0x51,0x89,0xda,0xc4,0x38, ++ 0x06,0x0f,0x2f,0x5c,0xd5,0x26,0x66,0x2f,0x29,0x06,0xc1,0xdd,0x64,0xf4,0x84,0x4e, ++ 0x94,0x2c,0xa8,0x4d,0xae,0xce,0x6d,0xd7,0xbb,0xf7,0x19,0x4d,0x8c,0xe5,0x6b,0xc2, ++ 0x83,0x10,0x85,0xa7,0xd3,0x10,0xe4,0x94,0x4c,0xfa,0xe7,0x62,0x60,0xaa,0xbf,0x6b), ++ .salt = chunk_from_chars( ++ 0x9c,0xb4,0xbf,0x24,0x46,0x17,0x0a,0xc3,0x81,0x02,0x52,0x66,0xa1,0xa4,0xb8,0x65, ++ 0x13,0xdf,0x60,0xea,0x7d,0x07,0xb1,0xb2,0x13,0x9d,0x78,0xf3,0x31,0xef,0x7e,0xb7, ++ 0xbe,0x8b,0x15,0xd8,0x6c,0xd8,0x5e,0x2a,0x6a,0x34,0xa5,0x58,0x69,0xf8,0xdc,0xc9, ++ 0x75,0x4f,0x49,0x69,0x73,0x31,0xb9,0xb6,0x50,0xce,0x25,0x6e,0xdb,0x33,0x71,0xa9, ++ 0x4b,0x7c,0x2a,0x13,0x2f,0x2f,0xc9,0x9d,0x22,0x30,0x37,0x17,0xc3,0x67,0x39,0xd1, ++ 0x7c,0x0e,0x97,0x18,0xd7,0xc0,0x52,0xe7,0xab,0x4d,0x48,0x58,0xad,0xeb,0x9b,0x8b, ++ 0x4d,0x33,0x03,0xa9,0xe1,0xb6,0xbe,0xf2,0x9f,0x03,0x03,0x5b,0xee,0xd0,0x71,0xd3, ++ 0xbb,0x81,0x0d,0x85,0x39,0x71,0xa7,0x48,0xc5,0x6c,0x59,0xe0,0xba,0xfb,0x9b,0x5a), ++ .out = chunk_from_chars( ++ 0xe5,0x70,0xe7,0x48,0x46,0x34,0x30,0x0d,0x7a,0xdd,0xf5,0xa8,0x52,0x7c,0x13,0x8b, ++ 0x76,0x96,0xdb,0xc3,0xd8,0xbe,0x09,0x69,0xb7,0x52,0x15,0x31,0x8a,0x11,0xad,0xa2, ++ 0x13,0x53,0x8f,0x62,0x93,0xb0,0xee,0xe5,0xb3,0x09,0xad,0x8f,0x5d,0x8d,0x94,0xdb, ++ 0xe5,0x73,0x61,0x27,0xe0,0xd2,0x56,0x0f,0x28,0x1c,0x9c,0x58,0x6b,0xf7,0xc8,0x6f), ++}; Index: strongswan-5.9.5/src/libstrongswan/plugins/test_vectors/test_vectors/kdf_prf_plus.c =================================================================== --- /dev/null @@ -3740,7 +4247,7 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/wolfssl/wolfssl_kdf.c =================================================================== --- /dev/null +++ strongswan-5.9.5/src/libstrongswan/plugins/wolfssl/wolfssl_kdf.c -@@ -0,0 +1,161 @@ +@@ -0,0 +1,196 @@ +/* + * Copyright (C) 2022 Tobias Brunner, codelabs GmbH + * @@ -3786,9 +4293,14 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/wolfssl/wolfssl_kdf.c + kdf_t public; + + /** ++ * KDF type. ++ */ ++ key_derivation_function_t type; ++ ++ /** + * Hash algorithm type. + */ -+ int type; ++ enum wc_HashType hash; + + /** + * Key for KDF. @@ -3804,13 +4316,36 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/wolfssl/wolfssl_kdf.c +METHOD(kdf_t, get_type, key_derivation_function_t, + private_kdf_t *this) +{ -+ return KDF_PRF_PLUS; ++ return this->type; ++} ++ ++METHOD(kdf_t, get_length, size_t, ++ private_kdf_t *this) ++{ ++ if (this->type == KDF_PRF_PLUS) ++ { ++ return SIZE_MAX; ++ } ++ return wc_HashGetDigestSize(this->hash); +} + +METHOD(kdf_t, get_bytes, bool, + private_kdf_t *this, size_t out_len, uint8_t *buffer) +{ -+ if (wc_HKDF_Expand(this->type, this->key.ptr, this->key.len, ++ if (this->type == KDF_PRF) ++ { ++ /* IKEv2 uses the nonces as PRF key and the DH secret as salt, however, ++ * HKDF-Extract() does the same again (mapping the salt to the HMAC key), ++ * so we have to switch key and salt here */ ++ if (out_len != get_length(this) || ++ wc_HKDF_Extract(this->hash, this->key.ptr, this->key.len, ++ this->salt.ptr, this->salt.len, buffer)) ++ { ++ return FALSE; ++ } ++ return TRUE; ++ } ++ if (wc_HKDF_Expand(this->hash, this->key.ptr, this->key.len, + this->salt.ptr, this->salt.len, buffer, out_len)) + { + return FALSE; @@ -3821,6 +4356,11 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/wolfssl/wolfssl_kdf.c +METHOD(kdf_t, allocate_bytes, bool, + private_kdf_t *this, size_t out_len, chunk_t *chunk) +{ ++ if (this->type == KDF_PRF) ++ { ++ out_len = out_len ?: get_length(this); ++ } ++ + *chunk = chunk_alloc(out_len); + + if (!get_bytes(this, out_len, chunk->ptr)) @@ -3867,16 +4407,16 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/wolfssl/wolfssl_kdf.c +{ + private_kdf_t *this; + pseudo_random_function_t prf_alg; -+ enum wc_HashType type; -+ char buf[8]; ++ enum wc_HashType hash; ++ char buf[HASH_SIZE_SHA512]; + -+ if (algo != KDF_PRF_PLUS) ++ if (algo != KDF_PRF && algo != KDF_PRF_PLUS) + { + return NULL; + } + + VA_ARGS_VGET(args, prf_alg); -+ if (!wolfssl_hash2type(hasher_algorithm_from_prf(prf_alg), &type)) ++ if (!wolfssl_hash2type(hasher_algorithm_from_prf(prf_alg), &hash)) + { + return NULL; + } @@ -3884,16 +4424,18 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/wolfssl/wolfssl_kdf.c + INIT(this, + .public = { + .get_type = _get_type, ++ .get_length = _get_length, + .get_bytes = _get_bytes, + .allocate_bytes = _allocate_bytes, + .set_param = _set_param, + .destroy = _destroy, + }, -+ .type = type, ++ .type = algo, ++ .hash = hash, + ); + + /* test if we can actually use the algorithm */ -+ if (!get_bytes(this, sizeof(buf), buf)) ++ if (!get_bytes(this, algo == KDF_PRF ? get_length(this) : sizeof(buf), buf)) + { + destroy(this); + return NULL; @@ -3964,12 +4506,13 @@ Index: strongswan-5.9.5/src/libstrongswan/plugins/wolfssl/wolfssl_plugin.c #include "wolfssl_rsa_private_key.h" #include "wolfssl_rsa_public_key.h" #include "wolfssl_rng.h" -@@ -185,6 +186,10 @@ METHOD(plugin_t, get_features, int, +@@ -185,6 +186,11 @@ METHOD(plugin_t, get_features, int, PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_512_256), PLUGIN_PROVIDE(SIGNER, AUTH_HMAC_SHA2_512_512), #endif +#ifdef HAVE_HKDF + PLUGIN_REGISTER(KDF, wolfssl_kdf_create), ++ PLUGIN_PROVIDE(KDF, KDF_PRF), + PLUGIN_PROVIDE(KDF, KDF_PRF_PLUS), +#endif #endif /* NO_HMAC */ diff --git a/strongswan.changes b/strongswan.changes index 2cfec7b..d1b71e6 100644 --- a/strongswan.changes +++ b/strongswan.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Wed Mar 16 12:57:46 UTC 2022 - Marcus Meissner + +- prf-plus-modularization.patch: updated from upstream branch + after certifier feedback, SKEYSEED generated via HKDF-Extract. + ------------------------------------------------------------------- Thu Mar 3 14:49:26 UTC 2022 - Marcus Meissner