Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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: #44201
PR-URL: #44272
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
  • Loading branch information
tniessen authored and RafaelGSS committed Sep 5, 2022
1 parent e001aaf commit c3dbe18
Showing 1 changed file with 26 additions and 40 deletions.
66 changes: 26 additions & 40 deletions src/crypto/crypto_hkdf.cc
Expand Up @@ -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;
Expand Down

0 comments on commit c3dbe18

Please sign in to comment.