From 972832d9148a9c057e6ea1930cbb71fe88b45b48 Mon Sep 17 00:00:00 2001 From: Justin W Smith <103147162+justsmth@users.noreply.github.com> Date: Mon, 1 Jul 2024 15:50:45 -0400 Subject: [PATCH 1/4] AT_HWCAP2 not always defined (#1682) ### Issues: Addresses: https://github.com/aws/aws-lc-rs/issues/427 ### Description of changes: * Allow fallback when `AT_HWCAP2` is not defined (for older glibc). > > AT_HWCAP2 (since glibc 2.18) > Further machine-dependent hints about processor > capabilities. > ### Testing: * I've not yet been able to setup an environment that replicates [the failure seen downstream](https://github.com/rust-lang/rustup/actions/runs/9720503984/job/26831972336?pr=3898) for `arm-unknown-linux-gnueabihf`: ``` In file included from /cargo/registry/src/index.crates.io-6f17d22bba15001f/aws-lc-sys-0.18.0/aws-lc/crypto/fipsmodule/bcm.c:81: /cargo/registry/src/index.crates.io-6f17d22bba15001f/aws-lc-sys-0.18.0/aws-lc/crypto/fipsmodule/cpucap/cpu_arm_linux.c: In function 'aws_lc_0_18_0_OPENSSL_cpuid_setup': /cargo/registry/src/index.crates.io-6f17d22bba15001f/aws-lc-sys-0.18.0/aws-lc/crypto/fipsmodule/cpucap/cpu_arm_linux.c:121:38: error: 'AT_HWCAP2' undeclared (first use in this function); did you mean 'AT_HWCAP'? unsigned long hwcap2 = getauxval(AT_HWCAP2); ^~~~~~~~~ AT_HWCAP /cargo/registry/src/index.crates.io-6f17d22bba15001f/aws-lc-sys-0.18.0/aws-lc/crypto/fipsmodule/cpucap/cpu_arm_linux.c:121:38: note: each undeclared identifier is reported only once for each function it appears in /cargo/registry/src/index.crates.io-6f17d22bba15001f/aws-lc-sys-0.18.0/aws-lc/crypto/fipsmodule/bcm.c: At top level: cc1: error: unrecognized command line option '-Wno-c11-extensions' [-Werror] cc1: all warnings being treated as errors ninja: build stopped: subcommand failed. ``` By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and the ISC license. --- crypto/fipsmodule/cpucap/cpu_arm_freebsd.c | 2 ++ crypto/fipsmodule/cpucap/cpu_arm_linux.c | 4 ++++ crypto/fipsmodule/cpucap/cpu_ppc64le.c | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/crypto/fipsmodule/cpucap/cpu_arm_freebsd.c b/crypto/fipsmodule/cpucap/cpu_arm_freebsd.c index 209a49f084..ac71ac27b1 100644 --- a/crypto/fipsmodule/cpucap/cpu_arm_freebsd.c +++ b/crypto/fipsmodule/cpucap/cpu_arm_freebsd.c @@ -30,7 +30,9 @@ void OPENSSL_cpuid_setup(void) { // left at zero. The rest of this function will then gracefully report // the features are absent. elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap)); +#if defined(AT_HWCAP2) elf_aux_info(AT_HWCAP2, &hwcap2, sizeof(hwcap2)); +#endif // Matching OpenSSL, only report other features if NEON is present. if (hwcap & HWCAP_NEON) { diff --git a/crypto/fipsmodule/cpucap/cpu_arm_linux.c b/crypto/fipsmodule/cpucap/cpu_arm_linux.c index e4ab5ab492..a2c5a18096 100644 --- a/crypto/fipsmodule/cpucap/cpu_arm_linux.c +++ b/crypto/fipsmodule/cpucap/cpu_arm_linux.c @@ -118,7 +118,11 @@ void OPENSSL_cpuid_setup(void) { // this is now rare (see Chrome's Net.NeedsHWCAP2Workaround metric), but AES // and PMULL extensions are very useful, so we still carry the workaround // for now. +#if defined(AT_HWCAP2) unsigned long hwcap2 = getauxval(AT_HWCAP2); +#else + unsigned long hwcap2 = 0; +#endif if (hwcap2 == 0) { hwcap2 = crypto_get_arm_hwcap2_from_cpuinfo(&cpuinfo); g_needs_hwcap2_workaround = hwcap2 != 0; diff --git a/crypto/fipsmodule/cpucap/cpu_ppc64le.c b/crypto/fipsmodule/cpucap/cpu_ppc64le.c index 61fe953846..db420dcc72 100644 --- a/crypto/fipsmodule/cpucap/cpu_ppc64le.c +++ b/crypto/fipsmodule/cpucap/cpu_ppc64le.c @@ -68,7 +68,11 @@ static void handle_cpu_env(unsigned long *out, const char *in) { extern uint8_t OPENSSL_cpucap_initialized; void OPENSSL_cpuid_setup(void) { +#if defined(AT_HWCAP2) OPENSSL_ppc64le_hwcap2 = getauxval(AT_HWCAP2); +#else + OPENSSL_ppc64le_hwcap2 = 0; +#endif OPENSSL_cpucap_initialized = 1; // OPENSSL_ppccap is a 64-bit hex string which may start with "0x". From dd7bb4a6e9501a959373cff1440968963ba486fa Mon Sep 17 00:00:00 2001 From: dkostic <25055813+dkostic@users.noreply.github.com> Date: Mon, 1 Jul 2024 13:27:15 -0700 Subject: [PATCH 2/4] Added generic EC scalar rwnaf encoding for ec_nistp (#1664) Scalar encoding for scalar multiplication for curves P-384 and P-521 was implemented for each curve separately and with hard-coded parameters. This commit refactors the encoding function to be generic and uses removes the hard-coded ones. --- crypto/fipsmodule/ec/ec_nistp.c | 44 +++++++++++++++++++++++++++++++++ crypto/fipsmodule/ec/ec_nistp.h | 3 +++ crypto/fipsmodule/ec/p384.c | 41 ++---------------------------- crypto/fipsmodule/ec/p521.c | 40 ++---------------------------- 4 files changed, 51 insertions(+), 77 deletions(-) diff --git a/crypto/fipsmodule/ec/ec_nistp.c b/crypto/fipsmodule/ec/ec_nistp.c index 41b7e0bfac..be377c4c21 100644 --- a/crypto/fipsmodule/ec/ec_nistp.c +++ b/crypto/fipsmodule/ec/ec_nistp.c @@ -259,3 +259,47 @@ void ec_nistp_point_add(const ec_nistp_meth *ctx, cmovznz(z3, ctx->felem_num_limbs, z2nz, z1, z_out); } +// Returns i-th bit of the scalar (zero or one). +// The caller is responsible for making sure i is within bounds of the scalar. +static int16_t get_bit(const EC_SCALAR *in, size_t i) { +// |in->words| is an array of BN_ULONGs which can be either 8 or 4 bytes long. +#if defined(OPENSSL_64_BIT) + OPENSSL_STATIC_ASSERT(sizeof(BN_ULONG) == 8, bn_ulong_not_eight_bytes); + return (in->words[i >> 6] >> (i & 63)) & 1; +#else + OPENSSL_STATIC_ASSERT(sizeof(BN_ULONG) == 4, bn_ulong_not_four_bytes); + return (in->words[i >> 5] >> (i & 31)) & 1; +#endif +} + +#define DIV_AND_CEIL(a, b) ((a + b - 1) / b) + +// Compute "regular" wNAF representation of a scalar, see +// Joye, Tunstall, "Exponent Recoding and Regular Exponentiation Algorithms", +// AfricaCrypt 2009, Alg 6. +// It forces an odd scalar and outputs digits in +// {\pm 1, \pm 3, \pm 5, \pm 7, \pm 9, ...} +// i.e. signed odd digits with _no zeroes_ -- that makes it "regular". +void scalar_rwnaf(int16_t *out, size_t window_size, + const EC_SCALAR *scalar, size_t scalar_bit_size) { + assert(window_size < 14); + + // The assert above ensures this works correctly. + const int16_t window_mask = (1 << (window_size + 1)) - 1; + int16_t window = (int16_t)(scalar->words[0] & (BN_ULONG)window_mask); + window |= 1; + + const size_t num_windows = DIV_AND_CEIL(scalar_bit_size, window_size); + for (size_t i = 0; i < num_windows - 1; i++) { + int16_t d = (window & window_mask) - (int16_t)(1 << window_size); + out[i] = d; + window = (window - d) >> window_size; + for (size_t j = 1; j <= window_size; j++) { + size_t idx = (i + 1) * window_size + j; + if (idx < scalar_bit_size) { + window |= get_bit(scalar, idx) << j; + } + } + } + out[num_windows - 1] = window; +} diff --git a/crypto/fipsmodule/ec/ec_nistp.h b/crypto/fipsmodule/ec/ec_nistp.h index d17dd25912..da4476265a 100644 --- a/crypto/fipsmodule/ec/ec_nistp.h +++ b/crypto/fipsmodule/ec/ec_nistp.h @@ -95,5 +95,8 @@ void ec_nistp_point_add(const ec_nistp_meth *ctx, const ec_nistp_felem_limb *x2, const ec_nistp_felem_limb *y2, const ec_nistp_felem_limb *z2); + +void scalar_rwnaf(int16_t *out, size_t window_size, + const EC_SCALAR *scalar, size_t scalar_bit_size); #endif // EC_NISTP_H diff --git a/crypto/fipsmodule/ec/p384.c b/crypto/fipsmodule/ec/p384.c index 8f0160954e..5dfb06b4e9 100644 --- a/crypto/fipsmodule/ec/p384.c +++ b/crypto/fipsmodule/ec/p384.c @@ -470,21 +470,6 @@ static int ec_GFp_nistp384_cmp_x_coordinate(const EC_GROUP *group, // // For detailed analysis of different window sizes see the bottom of this file. - -// p384_get_bit returns the |i|-th bit in |in| -static crypto_word_t p384_get_bit(const EC_SCALAR *in, int i) { - if (i < 0 || i >= 384) { - return 0; - } -#if defined(OPENSSL_64_BIT) - assert(sizeof(BN_ULONG) == 8); - return (in->words[i >> 6] >> (i & 63)) & 1; -#else - assert(sizeof(BN_ULONG) == 4); - return (in->words[i >> 5] >> (i & 31)) & 1; -#endif -} - // Constants for scalar encoding in the scalar multiplication functions. #define P384_MUL_WSIZE (5) // window size w // Assert the window size is 5 because the pre-computed table in |p384_table.h| @@ -493,7 +478,6 @@ OPENSSL_STATIC_ASSERT(P384_MUL_WSIZE == 5, p384_scalar_mul_window_size_is_not_equal_to_five) #define P384_MUL_TWO_TO_WSIZE (1 << P384_MUL_WSIZE) -#define P384_MUL_WSIZE_MASK ((P384_MUL_TWO_TO_WSIZE << 1) - 1) // Number of |P384_MUL_WSIZE|-bit windows in a 384-bit value #define P384_MUL_NWINDOWS ((384 + P384_MUL_WSIZE - 1)/P384_MUL_WSIZE) @@ -506,27 +490,6 @@ OPENSSL_STATIC_ASSERT(P384_MUL_WSIZE == 5, #define P384_MUL_TABLE_SIZE (P384_MUL_TWO_TO_WSIZE >> 1) #define P384_MUL_PUB_TABLE_SIZE (1 << (P384_MUL_PUB_WSIZE - 1)) -// Compute "regular" wNAF representation of a scalar, see -// Joye, Tunstall, "Exponent Recoding and Regular Exponentiation Algorithms", -// AfricaCrypt 2009, Alg 6. -// It forces an odd scalar and outputs digits in -// {\pm 1, \pm 3, \pm 5, \pm 7, \pm 9, ...} -// i.e. signed odd digits with _no zeroes_ -- that makes it "regular". -static void p384_felem_mul_scalar_rwnaf(int16_t *out, const EC_SCALAR *in) { - int16_t window, d; - - window = (in->words[0] & P384_MUL_WSIZE_MASK) | 1; - for (size_t i = 0; i < P384_MUL_NWINDOWS - 1; i++) { - d = (window & P384_MUL_WSIZE_MASK) - P384_MUL_TWO_TO_WSIZE; - out[i] = d; - window = (window - d) >> P384_MUL_WSIZE; - for (size_t j = 1; j <= P384_MUL_WSIZE; j++) { - window += p384_get_bit(in, (i + 1) * P384_MUL_WSIZE + j) << j; - } - } - out[P384_MUL_NWINDOWS - 1] = window; -} - // p384_select_point selects the |idx|-th projective point from the given // precomputed table and copies it to |out| in constant time. static void p384_select_point(p384_felem out[3], @@ -614,7 +577,7 @@ static void ec_GFp_nistp384_point_mul(const EC_GROUP *group, EC_JACOBIAN *r, // Recode the scalar. int16_t rnaf[P384_MUL_NWINDOWS] = {0}; - p384_felem_mul_scalar_rwnaf(rnaf, scalar); + scalar_rwnaf(rnaf, P384_MUL_WSIZE, scalar, 384); // Initialize the accumulator |res| with the table entry corresponding to // the most significant digit of the recoded scalar (note that this digit @@ -738,7 +701,7 @@ static void ec_GFp_nistp384_point_mul_base(const EC_GROUP *group, int16_t rnaf[P384_MUL_NWINDOWS] = {0}; // Recode the scalar. - p384_felem_mul_scalar_rwnaf(rnaf, scalar); + scalar_rwnaf(rnaf, P384_MUL_WSIZE, scalar, 384); // Process the 4 groups of digits starting from group (3) down to group (0). for (int i = 3; i >= 0; i--) { diff --git a/crypto/fipsmodule/ec/p521.c b/crypto/fipsmodule/ec/p521.c index 2489213143..299eae050c 100644 --- a/crypto/fipsmodule/ec/p521.c +++ b/crypto/fipsmodule/ec/p521.c @@ -407,20 +407,6 @@ static void ec_GFp_nistp521_dbl(const EC_GROUP *group, EC_JACOBIAN *r, // The precomputed table of base point multiples is generated by the code in // |make_tables.go| script. -// p521_get_bit returns the |i|-th bit in |in| -static crypto_word_t p521_get_bit(const EC_SCALAR *in, int i) { - if (i < 0 || i >= 521) { - return 0; - } -#if defined(OPENSSL_64_BIT) - assert(sizeof(BN_ULONG) == 8); - return (in->words[i >> 6] >> (i & 63)) & 1; -#else - assert(sizeof(BN_ULONG) == 4); - return (in->words[i >> 5] >> (i & 31)) & 1; -#endif -} - // Constants for scalar encoding in the scalar multiplication functions. #define P521_MUL_WSIZE (5) // window size w // Assert the window size is 5 because the pre-computed table in |p521_table.h| @@ -429,7 +415,6 @@ OPENSSL_STATIC_ASSERT(P521_MUL_WSIZE == 5, p521_scalar_mul_window_size_is_not_equal_to_five) #define P521_MUL_TWO_TO_WSIZE (1 << P521_MUL_WSIZE) -#define P521_MUL_WSIZE_MASK ((P521_MUL_TWO_TO_WSIZE << 1) - 1) // Number of |P521_MUL_WSIZE|-bit windows in a 521-bit value #define P521_MUL_NWINDOWS ((521 + P521_MUL_WSIZE - 1)/P521_MUL_WSIZE) @@ -442,27 +427,6 @@ OPENSSL_STATIC_ASSERT(P521_MUL_WSIZE == 5, #define P521_MUL_TABLE_SIZE (P521_MUL_TWO_TO_WSIZE >> 1) #define P521_MUL_PUB_TABLE_SIZE (1 << (P521_MUL_PUB_WSIZE - 1)) -// Compute "regular" wNAF representation of a scalar, see -// Joye, Tunstall, "Exponent Recoding and Regular Exponentiation Algorithms", -// AfricaCrypt 2009, Alg 6. -// It forces an odd scalar and outputs digits in -// {\pm 1, \pm 3, \pm 5, \pm 7, \pm 9, ...} -// i.e. signed odd digits with _no zeroes_ -- that makes it "regular". -static void p521_felem_mul_scalar_rwnaf(int16_t *out, const EC_SCALAR *in) { - int16_t window, d; - - window = (in->words[0] & P521_MUL_WSIZE_MASK) | 1; - for (size_t i = 0; i < P521_MUL_NWINDOWS - 1; i++) { - d = (window & P521_MUL_WSIZE_MASK) - P521_MUL_TWO_TO_WSIZE; - out[i] = d; - window = (window - d) >> P521_MUL_WSIZE; - for (size_t j = 1; j <= P521_MUL_WSIZE; j++) { - window += p521_get_bit(in, (i + 1) * P521_MUL_WSIZE + j) << j; - } - } - out[P521_MUL_NWINDOWS - 1] = window; -} - // p521_select_point selects the |idx|-th projective point from the given // precomputed table and copies it to |out| in constant time. static void p521_select_point(p521_felem out[3], @@ -550,7 +514,7 @@ static void ec_GFp_nistp521_point_mul(const EC_GROUP *group, EC_JACOBIAN *r, // Recode the scalar. int16_t rnaf[P521_MUL_NWINDOWS] = {0}; - p521_felem_mul_scalar_rwnaf(rnaf, scalar); + scalar_rwnaf(rnaf, P521_MUL_WSIZE, scalar, 521); // Initialize the accumulator |res| with the table entry corresponding to // the most significant digit of the recoded scalar (note that this digit @@ -674,7 +638,7 @@ static void ec_GFp_nistp521_point_mul_base(const EC_GROUP *group, int16_t rnaf[P521_MUL_NWINDOWS] = {0}; // Recode the scalar. - p521_felem_mul_scalar_rwnaf(rnaf, scalar); + scalar_rwnaf(rnaf, P521_MUL_WSIZE, scalar, 521); // Process the 4 groups of digits starting from group (3) down to group (0). for (int i = 3; i >= 0; i--) { From 05d3bfd6303c65d7392dee1a47d6e161c36a04e5 Mon Sep 17 00:00:00 2001 From: Andrew Hopkins Date: Mon, 1 Jul 2024 13:28:11 -0700 Subject: [PATCH 3/4] Prepare for release v1.31.0 (#1683) ### Description of changes: [Draft release](https://github.com/aws/aws-lc/releases/edit/untagged-11ac3412a1f5ec7633c3) By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and the ISC license. --- crypto/fipsmodule/service_indicator/service_indicator_test.cc | 4 ++-- include/openssl/base.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crypto/fipsmodule/service_indicator/service_indicator_test.cc b/crypto/fipsmodule/service_indicator/service_indicator_test.cc index 0139e60205..2d5006f123 100644 --- a/crypto/fipsmodule/service_indicator/service_indicator_test.cc +++ b/crypto/fipsmodule/service_indicator/service_indicator_test.cc @@ -4280,7 +4280,7 @@ TEST(ServiceIndicatorTest, DRBG) { // Since this is running in FIPS mode it should end in FIPS // Update this when the AWS-LC version number is modified TEST(ServiceIndicatorTest, AWSLCVersionString) { - ASSERT_STREQ(awslc_version_string(), "AWS-LC FIPS 1.30.1"); + ASSERT_STREQ(awslc_version_string(), "AWS-LC FIPS 1.31.0"); } #else @@ -4323,6 +4323,6 @@ TEST(ServiceIndicatorTest, BasicTest) { // Since this is not running in FIPS mode it shouldn't end in FIPS // Update this when the AWS-LC version number is modified TEST(ServiceIndicatorTest, AWSLCVersionString) { - ASSERT_STREQ(awslc_version_string(), "AWS-LC 1.30.1"); + ASSERT_STREQ(awslc_version_string(), "AWS-LC 1.31.0"); } #endif // AWSLC_FIPS diff --git a/include/openssl/base.h b/include/openssl/base.h index 16796c526d..f7c0b7bc6e 100644 --- a/include/openssl/base.h +++ b/include/openssl/base.h @@ -122,7 +122,7 @@ extern "C" { // ServiceIndicatorTest.AWSLCVersionString // Note: there are two versions of this test. Only one test is compiled // depending on FIPS mode. -#define AWSLC_VERSION_NUMBER_STRING "1.30.1" +#define AWSLC_VERSION_NUMBER_STRING "1.31.0" #if defined(BORINGSSL_SHARED_LIBRARY) From 21c5e48f38706975117867a8c70473a2d43280cf Mon Sep 17 00:00:00 2001 From: kexgaber Date: Mon, 1 Jul 2024 14:19:25 -0700 Subject: [PATCH 4/4] Update HMAC to fail when null value is passed to out parameter (#1662) ### Issues: CryptoAlg-2522 ### Description of changes: Currently, `NULL` passed as the value of `out` can result in a segmentation fault. This change adds checks to the HMAC one-shot API and HMAC_final function to handle scenarios where `NULL` is passed as a value to the `out` parameter to return from the functions and prevent further computation. ### Testing: Added additional test case in `crypto/hmac_extra/hmac_test.cc` to verify the behavior when `NULL` is passed as a value to `out` in both functions. ### Call-outs: - OpenSSL supports this differently by allowing the computation to occur but allocating a throw-away array [OpenSSL implementation](https://github.com/openssl/openssl/blob/1977c00f00ad0546421a5ec0b40c1326aee4cddb/crypto/hmac/hmac.c#L233) - We should also evaluate if this change should be back-ported to the FIPS branches By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and the ISC license. Co-authored-by: Sean McGrail <549813+skmcgrail@users.noreply.github.com> --- crypto/fipsmodule/hmac/hmac.c | 9 +++++++++ crypto/hmac_extra/hmac_test.cc | 25 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/crypto/fipsmodule/hmac/hmac.c b/crypto/fipsmodule/hmac/hmac.c index 0393888e58..a9d55c5210 100644 --- a/crypto/fipsmodule/hmac/hmac.c +++ b/crypto/fipsmodule/hmac/hmac.c @@ -185,6 +185,11 @@ OPENSSL_STATIC_ASSERT(HMAC_STATE_UNINITIALIZED == 0, HMAC_STATE_UNINITIALIZED_is uint8_t *HMAC(const EVP_MD *evp_md, const void *key, size_t key_len, const uint8_t *data, size_t data_len, uint8_t *out, unsigned int *out_len) { + + if (out == NULL) { + // Prevent further work from being done + return NULL; + } HMAC_CTX ctx; OPENSSL_memset(&ctx, 0, sizeof(HMAC_CTX)); @@ -341,6 +346,10 @@ int HMAC_Update(HMAC_CTX *ctx, const uint8_t *data, size_t data_len) { } int HMAC_Final(HMAC_CTX *ctx, uint8_t *out, unsigned int *out_len) { + if (out == NULL) { + return 0; + } + const HmacMethods *methods = ctx->methods; if (!hmac_ctx_is_initialized(ctx)) { return 0; diff --git a/crypto/hmac_extra/hmac_test.cc b/crypto/hmac_extra/hmac_test.cc index 96d00a9e86..e7a50a2ed4 100644 --- a/crypto/hmac_extra/hmac_test.cc +++ b/crypto/hmac_extra/hmac_test.cc @@ -351,3 +351,28 @@ TEST(HMACTest, EVP_DigestVerify) { EXPECT_EQ(EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE, ERR_GET_REASON(ERR_get_error())); } + +TEST(HMACTest, HandlesNullOutputParameters) { + bssl::ScopedHMAC_CTX ctx; + const EVP_MD *digest = EVP_sha256(); + // make key and input valid + const uint8_t key[32] = {0}; + const uint8_t input[16] = {0}; + + // Test one-shot API with out and out_len as NULL + ASSERT_FALSE(HMAC(digest, &key[0], sizeof(key), &input[0], sizeof(input), + nullptr,nullptr)); + unsigned mac_len; + // Test one-shot API with only out as NULL + ASSERT_FALSE(HMAC(digest, &key[0], sizeof(key), &input[0], sizeof(input), + nullptr, &mac_len)); + + // Test HMAC_ctx + ASSERT_TRUE(HMAC_Init_ex(ctx.get(), &key[0], sizeof(key), digest, nullptr)); + ASSERT_TRUE(HMAC_Update(ctx.get(), &input[0], sizeof(input))); + ASSERT_FALSE(HMAC_Final(ctx.get(), nullptr, nullptr)); + + ASSERT_TRUE(HMAC_Init_ex(ctx.get(), &key[0], sizeof(key), digest, nullptr)); + ASSERT_TRUE(HMAC_Update(ctx.get(), &input[0], sizeof(input))); + ASSERT_FALSE(HMAC_Final(ctx.get(), nullptr, &mac_len)); +}