From 03b4575d9aa3711c626f0bbc69f2ca1ed730e45b Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Thu, 21 Nov 2024 15:42:08 +0100 Subject: [PATCH] fixup! Implement HKDF expand function based on RFC 8446 Change-Id: If7fc7984b2262a8ee8558435296ac8512d4cc33a --- src/openvpn/crypto_epoch.c | 12 +++- tests/unit_tests/openvpn/test_crypto.c | 76 ++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/src/openvpn/crypto_epoch.c b/src/openvpn/crypto_epoch.c index 5c3751f0c..4db8ae86d 100644 --- a/src/openvpn/crypto_epoch.c +++ b/src/openvpn/crypto_epoch.c @@ -90,14 +90,20 @@ ovpn_expand_label(const uint8_t *secret, size_t secret_len, } struct gc_arena gc = gc_new(); - /* 2 byte for the outlen encoded as uint16, 5 bytes for "ovpn " */ - int hkdf_label_len = 2 + 5 + label_len + context_len; + /* 2 byte for the outlen encoded as uint16, 5 bytes for "ovpn ", + * 1 byte for context len byte and 1 byte for label len byte */ + int hkdf_label_len = 2 + 5 + label_len + 1 + context_len; struct buffer hkdf_label = alloc_buf_gc(hkdf_label_len, &gc); + const uint8_t *label_prefix = (const uint8_t *) ("ovpn "); + int prefix_len = 5; buf_write_u16(&hkdf_label, out_len); - buf_write(&hkdf_label, "ovpn ", 5); + buf_write_u8(&hkdf_label, prefix_len + label_len); + buf_write(&hkdf_label, label_prefix, prefix_len); buf_write(&hkdf_label, label, label_len); + + buf_write_u8(&hkdf_label, context_len); if (context_len > 0) { buf_write(&hkdf_label, context, context_len); diff --git a/tests/unit_tests/openvpn/test_crypto.c b/tests/unit_tests/openvpn/test_crypto.c index 0bdb60fcc..13b87f4cf 100644 --- a/tests/unit_tests/openvpn/test_crypto.c +++ b/tests/unit_tests/openvpn/test_crypto.c @@ -42,6 +42,12 @@ #include "mss.h" #include "test_common.h" + +#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#include +#endif + static const char testtext[] = "Dummy text to test PEM encoding"; static void @@ -586,6 +592,75 @@ crypto_test_ovpn_label_expand(void **state) assert_memory_equal(out, out_expected, 16); } +void +crypto_test_ovpn_expand_openssl3(void **state) +{ +#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L + OSSL_LIB_CTX *libctx = NULL; + const char *properties = NULL; + + uint8_t secret[32] = + {0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf, + 0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63, + 0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31, + 0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5}; + + const uint8_t *label_prefix = (const uint8_t *) ("ovpn "); + const size_t label_prefix_len = 5; + const uint8_t *label = (const uint8_t *) ("unit test"); + const size_t labellen = 9; + uint8_t out[27]; + size_t outlen = sizeof(out); + + EVP_KDF *kdf = EVP_KDF_fetch(libctx, OSSL_KDF_NAME_TLS1_3_KDF, properties); + assert_non_null(kdf); + + const char *mdname = "SHA-256"; + + size_t hashlen = SHA256_DIGEST_LENGTH; + + EVP_KDF_CTX *kctx = EVP_KDF_CTX_new(kdf); + assert_non_null(kctx); + + OSSL_PARAM params[7]; + OSSL_PARAM *p = params; + + int mode = EVP_PKEY_HKDEF_MODE_EXPAND_ONLY; + + *p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_MODE, &mode); + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, + (char *) mdname, 0); + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, + (unsigned char *) secret, hashlen); + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_PREFIX, + (unsigned char *) label_prefix, + label_prefix_len); + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_LABEL, + (unsigned char *) label, labellen); + + /* + * *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_DATA, + * (unsigned char *)data, + * datalen); + */ + *p++ = OSSL_PARAM_construct_end(); + + int ret = EVP_KDF_derive(kctx, out, outlen, params); + EVP_KDF_CTX_free(kctx); + + assert_int_equal(ret, 1); + + /* Do the same derivation with our own function */ + uint8_t out_ovpn[27]; + + ovpn_expand_label(secret, sizeof(secret), label, 9, NULL, 0, out_ovpn, sizeof(out_ovpn)); + assert_memory_equal(out_ovpn, out, sizeof(out_ovpn)); + +#else /* if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L */ + skip(); +#endif /* if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L */ +} + struct epoch_test_state { struct key_type kt; @@ -831,6 +906,7 @@ main(void) cmocka_unit_test(crypto_test_hkdf_expand_testa2), cmocka_unit_test(crypto_test_hkdf_expand_testa3), cmocka_unit_test(crypto_test_ovpn_label_expand), + cmocka_unit_test(crypto_test_ovpn_expand_openssl3), cmocka_unit_test_prestate_setup_teardown(crypto_test_epoch_key_generation, crypto_test_epoch_setup, crypto_test_epoch_teardown,