diff options
author | Tobias Nießen <tniessen@tnie.de> | 2022-08-25 19:36:08 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-25 19:36:08 +0300 |
commit | 4d49d6507e33c8f01de96488e9be6fdaee059d55 (patch) | |
tree | 404c658f41827f0a3f8b84255e9fc87244af8eda /src | |
parent | bb4dff783ddb3b20c67041f7ccef796c335c2407 (diff) |
crypto: simplify control flow in HKDF
Unify the implementation and perform the same OpenSSL calls regardless
of whether the key and/or salt are empty. This simplifies the code and
improves coverage.
Refs: https://github.com/nodejs/node/pull/44201
PR-URL: https://github.com/nodejs/node/pull/44272
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/crypto/crypto_hkdf.cc | 66 |
1 files changed, 26 insertions, 40 deletions
diff --git a/src/crypto/crypto_hkdf.cc b/src/crypto/crypto_hkdf.cc index bff8cc60c4c..081a930e69f 100644 --- a/src/crypto/crypto_hkdf.cc +++ b/src/crypto/crypto_hkdf.cc @@ -112,47 +112,33 @@ bool HKDFTraits::DeriveBits( // TODO(panva): Once support for OpenSSL 1.1.1 is dropped the whole // of HKDFTraits::DeriveBits can be refactored to use // EVP_KDF which does handle zero length key. - if (params.key->GetSymmetricKeySize() != 0) { - if (!EVP_PKEY_CTX_hkdf_mode(ctx.get(), - EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND) || - !EVP_PKEY_CTX_set1_hkdf_salt( - ctx.get(), params.salt.data<unsigned char>(), params.salt.size()) || - !EVP_PKEY_CTX_set1_hkdf_key(ctx.get(), - reinterpret_cast<const unsigned char*>( - params.key->GetSymmetricKey()), - params.key->GetSymmetricKeySize())) { - return false; - } + + std::string_view salt; + if (params.salt.size() != 0) { + salt = {params.salt.data<char>(), params.salt.size()}; } else { - // Workaround for EVP_PKEY_derive HKDF not handling zero length keys. - unsigned char temp_key[EVP_MAX_MD_SIZE]; - unsigned int len = sizeof(temp_key); - if (params.salt.size() != 0) { - if (HMAC(params.digest, - params.salt.data(), - params.salt.size(), - nullptr, - 0, - temp_key, - &len) == nullptr) { - return false; - } - } else { - char salt[EVP_MAX_MD_SIZE] = {0}; - if (HMAC(params.digest, - salt, - EVP_MD_size(params.digest), - nullptr, - 0, - temp_key, - &len) == nullptr) { - return false; - } - } - if (!EVP_PKEY_CTX_hkdf_mode(ctx.get(), EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) || - !EVP_PKEY_CTX_set1_hkdf_key(ctx.get(), temp_key, len)) { - return false; - } + static const char default_salt[EVP_MAX_MD_SIZE] = {0}; + salt = {default_salt, static_cast<unsigned>(EVP_MD_size(params.digest))}; + } + + // We do not use EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND and instead implement + // the extraction step ourselves because EVP_PKEY_derive does not handle + // zero-length keys, which are required for Web Crypto. + unsigned char pseudorandom_key[EVP_MAX_MD_SIZE]; + unsigned int prk_len = sizeof(pseudorandom_key); + if (HMAC( + params.digest, + salt.data(), + salt.size(), + reinterpret_cast<const unsigned char*>(params.key->GetSymmetricKey()), + params.key->GetSymmetricKeySize(), + pseudorandom_key, + &prk_len) == nullptr) { + return false; + } + if (!EVP_PKEY_CTX_hkdf_mode(ctx.get(), EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) || + !EVP_PKEY_CTX_set1_hkdf_key(ctx.get(), pseudorandom_key, prk_len)) { + return false; } size_t length = params.length; |