#include "sa_provider_common.h"
#if OPENSSL_VERSION_NUMBER >= 0x30000000
#include "client_test_helpers.h"
#include "digest_util.h"
#include <gtest/gtest.h>
#include <openssl/core_names.h>
#include <openssl/evp.h>
#include <openssl/kdf.h>
#ifdef __APPLE__
#define htobe32(x) htonl(x)
#endif
using namespace client_test_helpers;
TEST_P(SaProviderKdfTest, deriveTest) {
const auto* const kdf_algorithm = std::get<0>(GetParam());
const auto* const digest_name = std::get<1>(GetParam());
OSSL_LIB_CTX* lib_ctx = sa_get_provider();
ASSERT_NE(lib_ctx, nullptr);
auto clear_key = random(SYM_128_KEY_SIZE);
sa_rights rights;
sa_rights_set_allow_all(&rights);
auto key = create_sa_key_symmetric(&rights, clear_key);
std::shared_ptr<EVP_KDF> const evp_kdf(EVP_KDF_fetch(lib_ctx, kdf_algorithm, nullptr), EVP_KDF_free);
ASSERT_NE(evp_kdf, nullptr);
std::shared_ptr<EVP_KDF_CTX> const evp_kdf_ctx(EVP_KDF_CTX_new(evp_kdf.get()), EVP_KDF_CTX_free);
ASSERT_NE(evp_kdf_ctx, nullptr);
std::vector<uint8_t> clear_derived_key(SYM_128_KEY_SIZE);
auto derived_key = create_uninitialized_sa_key();
auto salt = random(AES_BLOCK_SIZE);
auto info = random(AES_BLOCK_SIZE);
if (strcmp(kdf_algorithm, "HKDF") == 0) {
ASSERT_TRUE(hkdf(clear_derived_key, clear_key, salt, info, digest_algorithm_from_name(digest_name)));
OSSL_PARAM params[] = {
OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, key.get(), sizeof(sa_key)),
OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, const_cast<char*>(digest_name),
strlen(digest_name)),
OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, salt.data(), salt.size()),
OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, info.data(), info.size()),
OSSL_PARAM_END};
int const result = EVP_KDF_derive(evp_kdf_ctx.get(), reinterpret_cast<unsigned char*>(derived_key.get()),
SYM_128_KEY_SIZE, params);
ASSERT_EQ(result, 1);
} else if (strcmp(kdf_algorithm, "CONCAT") == 0) {
ASSERT_TRUE(concat_kdf(clear_derived_key, clear_key, info, digest_algorithm_from_name(digest_name)));
OSSL_PARAM params[] = {
OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, key.get(), sizeof(sa_key)),
OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, const_cast<char*>(digest_name),
strlen(digest_name)),
OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, info.data(), info.size()),
OSSL_PARAM_END};
int const result = EVP_KDF_derive(evp_kdf_ctx.get(), reinterpret_cast<unsigned char*>(derived_key.get()),
SYM_128_KEY_SIZE, params);
ASSERT_EQ(result, 1);
} else if (strcmp(kdf_algorithm, "ANSI_X963") == 0) {
ASSERT_TRUE(ansi_x963_kdf(clear_derived_key, clear_key, info, digest_algorithm_from_name(digest_name)));
OSSL_PARAM params[] = {
OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, key.get(), sizeof(sa_key)),
OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, const_cast<char*>(digest_name),
strlen(digest_name)),
OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, info.data(), info.size()),
OSSL_PARAM_END};
int const result = EVP_KDF_derive(evp_kdf_ctx.get(), reinterpret_cast<unsigned char*>(derived_key.get()),
SYM_128_KEY_SIZE, params);
ASSERT_EQ(result, 1);
} else if (strcmp(kdf_algorithm, "CMAC") == 0) {
std::vector<uint8_t> other_data(37);
std::copy(salt.begin(), salt.end(), other_data.begin());
size_t position = salt.size();
other_data[position++] = 0;
std::copy(info.begin(), info.end(), other_data.begin() + static_cast<int64_t>(position));
position += info.size();
uint32_t length = htobe32(SYM_128_KEY_SIZE);
auto* p_length = reinterpret_cast<uint8_t*>(&length);
std::copy(p_length, p_length + 4, other_data.begin() + static_cast<int64_t>(position));
ASSERT_TRUE(cmac_kdf(clear_derived_key, clear_key, other_data, 1));
int one = 1;
OSSL_PARAM params[] = {
OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, key.get(), sizeof(sa_key)),
OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, const_cast<char*>(digest_name),
strlen(digest_name)),
OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, salt.data(), salt.size()),
OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, info.data(), info.size()),
OSSL_PARAM_construct_int(OSSL_KDF_PARAM_KBKDF_USE_SEPARATOR, &one),
OSSL_PARAM_construct_int(OSSL_KDF_PARAM_KBKDF_USE_L, &one),
OSSL_PARAM_END};
int const result = EVP_KDF_derive(evp_kdf_ctx.get(), reinterpret_cast<unsigned char*>(derived_key.get()),
SYM_128_KEY_SIZE, params);
ASSERT_EQ(result, 1);
}
ASSERT_TRUE(key_check_sym(*derived_key, clear_derived_key));
}
INSTANTIATE_TEST_SUITE_P(
SaProviderKdfHashTests,
SaProviderKdfTest,
::testing::Combine(
::testing::Values("HKDF", "CONCAT", "ANSI_X963"),
::testing::Values("SHA1", "SHA256", "SHA384", "SHA512")));
INSTANTIATE_TEST_SUITE_P(
SaProviderKdfCmacTests,
SaProviderKdfTest,
::testing::Combine(
::testing::Values("CMAC"),
::testing::Values("")));
#endif