From fa25f37ea6da87be11abf8809135c98e276d7029 Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Mon, 6 May 2024 11:06:53 -0400 Subject: [PATCH 01/26] Initial design for export of Merkle-Damgard hash state This commit provides a building block to implement HMAC with precomputed keys from https://github.com/aws/aws-lc/pull/1574. It adds internal functions to export the state of SHA-256 and use such exported state to initialize a SHA-256 context. Once the design is reviewed and approved, we will similar functions to the other Merkle-Damgard hash functions (MD4, MD5, SHA-1, SHA-2). --- crypto/digest_extra/digest_test.cc | 43 ++++++++++++++++++++ crypto/fipsmodule/sha/internal.h | 31 +++++++++++++++ crypto/fipsmodule/sha/sha256.c | 64 +++++++++++++++++++++++++++++- include/openssl/digest.h | 6 +++ 4 files changed, 143 insertions(+), 1 deletion(-) diff --git a/crypto/digest_extra/digest_test.cc b/crypto/digest_extra/digest_test.cc index 784db1ff79..0d3d7772f1 100644 --- a/crypto/digest_extra/digest_test.cc +++ b/crypto/digest_extra/digest_test.cc @@ -476,3 +476,46 @@ TEST(DigestTest, TransformBlocks) { EXPECT_TRUE(0 == OPENSSL_memcmp(ctx1.h, ctx2.h, sizeof(ctx1.h))); } + +// FIXME: Need to implement this for all hash functions used by HMAC +TEST(DigestTest, InitAndGetStateSHA256) { + const size_t nb_blocks = 10; + const size_t block_size = SHA256_CBLOCK; + uint8_t data[block_size * nb_blocks]; + for (size_t i = 0; i < sizeof(data); i++) { + data[i] = i*3; + } + + // SHA-256 + + // Compute the hash of the data for the baseline + SHA256_CTX ctx1; + EXPECT_TRUE(SHA256_Init(&ctx1)); + EXPECT_TRUE(SHA256_Update(&ctx1, data, sizeof(data))); + uint8_t hash1[SHA256_DIGEST_LENGTH]; + EXPECT_TRUE(SHA256_Final(hash1, &ctx1)); + + // Compute it by stopping in the middle, getting the state, and restoring it + SHA256_CTX ctx2; + EXPECT_TRUE(SHA256_Init(&ctx2)); + EXPECT_TRUE(SHA256_Update(&ctx2, data, 1)); + uint8_t state_h[SHA256_DIGEST_LENGTH]; + uint64_t state_n; + // we should not be able to export the state before a full block + EXPECT_FALSE(SHA256_get_state(&ctx2, state_h, &state_n)); + // finish 2 blocks + EXPECT_TRUE(SHA256_Update(&ctx2, data+1, 2*block_size-1)); + // now we should be able to export the state + EXPECT_TRUE(SHA256_get_state(&ctx2, state_h, &state_n)); + // check that state_n corresponds to 2 blocks + EXPECT_EQ(2*block_size*8, state_n); + + // and we continue on a fresh new context + SHA256_CTX ctx3; + EXPECT_TRUE(SHA256_Init_from_state(&ctx3, state_h, state_n)); + EXPECT_TRUE(SHA256_Update(&ctx2, data+2*block_size, (nb_blocks-2)*block_size)); + uint8_t hash2[SHA256_DIGEST_LENGTH]; + EXPECT_TRUE(SHA256_Final(hash2, &ctx2)); + + EXPECT_EQ(Bytes(hash1), Bytes(hash2)); +} diff --git a/crypto/fipsmodule/sha/internal.h b/crypto/fipsmodule/sha/internal.h index caeac4a976..30ebb9bdbb 100644 --- a/crypto/fipsmodule/sha/internal.h +++ b/crypto/fipsmodule/sha/internal.h @@ -19,6 +19,17 @@ extern "C" { #endif +// Internal SHA2 constants + +// SHA224_CHAINING_LENGTH is the chaining length in bytes of SHA-224 +// It corresponds to the length in bytes of the h part of the state +#define SHA224_CHAINING_LENGTH 32 + +// SHA256_CHAINING_LENGTH is the chaining length in bytes of SHA-256 +// It corresponds to the length in bytes of the h part of the state +#define SHA256_CHAINING_LENGTH 32 + + // SHA3 constants, from NIST FIPS202. // https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf #define SHA3_ROWS 5 @@ -92,6 +103,26 @@ void sha512_block_data_order(uint64_t *state, const uint8_t *in, #define KECCAK1600_ASM #endif +// SHA256_Init_from_state is a low-level function that initializes |sha| with a +// custom state. |h| is the hash state in big endian. |n| is the number of bits +// processed at this point. It must be a multiple of |SHA256_CBLOCK*8|. +// It returns one on success and zero on programmer error. +// External users should never use directly this function. +OPENSSL_EXPORT int SHA256_Init_from_state( + SHA256_CTX *sha, const uint8_t h[SHA256_CHAINING_LENGTH], uint64_t n); + +// SHA256_get_state is a low-level function that exports the hash state in big +// endian into |out_n| and the number of bits processed at this point in +// |out_n|. SHA256_Final must not have been called before (otherwise results +// are not guaranteed). Furthermore, the number of bytes processed by +// SHA256_Update must be a multiple of the block length |SHA256_CBLOCK| +// (otherwise it fails). It returns one on success and zero on programmer +// error. +// External users should never use directly this function. +OPENSSL_EXPORT int SHA256_get_state(SHA256_CTX *ctx, + uint8_t out_h[SHA256_CHAINING_LENGTH], + uint64_t *out_n); + // SHA3_224 writes the digest of |len| bytes from |data| to |out| and returns |out|. // There must be at least |SHA3_224_DIGEST_LENGTH| bytes of space in |out|. // On failure |SHA3_224| returns NULL. diff --git a/crypto/fipsmodule/sha/sha256.c b/crypto/fipsmodule/sha/sha256.c index 38164535cf..380935f8b4 100644 --- a/crypto/fipsmodule/sha/sha256.c +++ b/crypto/fipsmodule/sha/sha256.c @@ -93,6 +93,41 @@ int SHA256_Init(SHA256_CTX *sha) { return 1; } +OPENSSL_STATIC_ASSERT(SHA256_CHAINING_LENGTH==SHA224_CHAINING_LENGTH, + sha256_and_sha224_have_same_chaining_length) + +// sha256_init_from_state_impl is the implementation of +// SHA256_Init_from_state and SHA224_Init_from_state +// Note that the state h is always SHA256_CHAINING_LENGTH-byte long +static int sha256_init_from_state_impl(SHA256_CTX *sha, int md_len, + const uint8_t h[SHA256_CHAINING_LENGTH], + uint64_t n) { + if(n % ((uint64_t) SHA256_CBLOCK * 8) != 0) { + // n is not a multiple of the block size in bits, so it fails + return 0; + } + + OPENSSL_memset(sha, 0, sizeof(SHA256_CTX)); + sha->md_len = md_len; + + const size_t out_words = SHA256_CHAINING_LENGTH / 4; + for (size_t i = 0; i < out_words; i++) { + sha->h[i] = CRYPTO_load_u32_be(h); + h += 4; + } + + sha->Nh = n >> 32; + sha->Nl = n & 0xffffffff; + + return 1; +} + +int SHA256_Init_from_state(SHA256_CTX *sha, + const uint8_t h[SHA256_CHAINING_LENGTH], + uint64_t n) { + return sha256_init_from_state_impl(sha, SHA256_DIGEST_LENGTH, h, n); +} + uint8_t *SHA224(const uint8_t *data, size_t len, uint8_t out[SHA224_DIGEST_LENGTH]) { // We have to verify that all the SHA services actually succeed before @@ -163,7 +198,7 @@ static int sha256_final_impl(uint8_t *out, size_t md_len, SHA256_CTX *c) { return 1; } -int SHA256_Final(uint8_t out[SHA256_DIGEST_LENGTH], SHA256_CTX *c) { +int SHA256_Final(uint8_t out[SHA256_CHAINING_LENGTH], SHA256_CTX *c) { return sha256_final_impl(out, SHA256_DIGEST_LENGTH, c); } @@ -171,6 +206,33 @@ int SHA224_Final(uint8_t out[SHA224_DIGEST_LENGTH], SHA256_CTX *ctx) { return sha256_final_impl(out, SHA224_DIGEST_LENGTH, ctx); } +// sha256_get_state_impl is the implementation of +// SHA256_get_state and SHA224_get_state +// Note that the state out_h is always SHA256_CHAINING_LENGTH-byte long +static int sha256_get_state_impl(SHA256_CTX *ctx, + uint8_t out_h[SHA256_CHAINING_LENGTH], + uint64_t *out_n) { + if (ctx->Nl % ((uint64_t)SHA256_CBLOCK * 8) != 0) { + // ctx->Nl is not a multiple of the block size in bits, so it fails + return 0; + } + + const size_t out_words = SHA256_CHAINING_LENGTH / 4; + for (size_t i = 0; i < out_words; i++) { + CRYPTO_store_u32_be(out_h, ctx->h[i]); + out_h += 4; + } + + *out_n = (((uint64_t)ctx->Nh) << 32) + ctx->Nl; + + return 1; +} + +int SHA256_get_state(SHA256_CTX *ctx, uint8_t out_h[SHA256_CHAINING_LENGTH], + uint64_t *out_n) { + return sha256_get_state_impl(ctx, out_h, out_n); +} + #ifndef SHA256_ASM static const uint32_t K256[64] = { 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, diff --git a/include/openssl/digest.h b/include/openssl/digest.h index 2dcd47b110..7d6f058e18 100644 --- a/include/openssl/digest.h +++ b/include/openssl/digest.h @@ -171,6 +171,12 @@ OPENSSL_EXPORT int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, // at least this much space. #define EVP_MAX_MD_SIZE 64 // SHA-512 is the longest so far. +// EVP_MAX_MD_CHAINING_LENGTH is the largest chaining length supported, in +// bytes. This constant is only for Merkle-Damgard-based hashed functions +// like SHA-1, SHA-2, and MD5. +// This constant is only used internally by HMAC. +#define EVP_MAX_MD_CHAINING_LENGTH 64 // SHA-512 has the longest chaining length so far + // EVP_MAX_MD_BLOCK_SIZE is the largest digest block size supported, in // bytes. #define EVP_MAX_MD_BLOCK_SIZE 128 // SHA-512 is the longest so far. From 7058ed35ab006d5a4087e82a71b2046bf2bc2e52 Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Mon, 6 May 2024 13:11:02 -0400 Subject: [PATCH 02/26] Initial design for support of HMAC precomputed keys This commit implements an optimization of HMAC described in NIST-FIPS-198-1 (Section 6) and in RFC2104 (Section 4). Instead of using the original key, it is possible to use a precomputed key consisting of two intermediate hashing results. Using this precomputed key removes at least two calls to the hash compression function when computing a HMAC value. As an initial design, only SHA-256 is supported and all other hashes are disabled from HMAC. This makes some unit tests fail. Once this design is validated, we will add back the other hash functions. To allow partial testing, we updated hmac_tests.txt to only contain the HMAC-SHA256 tests. The original file is hmac_tests_full.txt Testing can be done in the CMake build folder using: * `crypto/crypto_test --gtest_filter='HMACTest.TestVectors'` for the changed unit tests. * `ninja acvp_tests` for the ACVP tests (failure is expected for anything using HMAC-xx where xx is not SHA-256). --- crypto/fipsmodule/hmac/hmac.c | 274 +++++++++++++++--- crypto/fipsmodule/hmac/internal.h | 27 ++ crypto/hmac_extra/hmac_test.cc | 106 ++++++- crypto/hmac_extra/hmac_tests.txt | 122 +------- crypto/hmac_extra/hmac_tests_full.txt | 145 +++++++++ include/openssl/hmac.h | 76 ++++- .../acvp/modulewrapper/modulewrapper.cc | 19 ++ 7 files changed, 607 insertions(+), 162 deletions(-) create mode 100644 crypto/fipsmodule/hmac/internal.h create mode 100644 crypto/hmac_extra/hmac_tests_full.txt diff --git a/crypto/fipsmodule/hmac/hmac.c b/crypto/fipsmodule/hmac/hmac.c index 00edf495c9..3700909e41 100644 --- a/crypto/fipsmodule/hmac/hmac.c +++ b/crypto/fipsmodule/hmac/hmac.c @@ -62,18 +62,24 @@ #include #include +#include "internal.h" #include "../../internal.h" #include "../service_indicator/internal.h" typedef int (*HashInit)(void *); -typedef int (*HashUpdate)(void *, const void*, size_t); -typedef int (*HashFinal)(uint8_t *, void*); +typedef int (*HashUpdate)(void *, const void *, size_t); +typedef int (*HashFinal)(uint8_t *, void *); +typedef int (*HashInitFromState)(void *, const uint8_t *, uint64_t); +typedef int (*HashGetState)(void *, uint8_t *, uint64_t *); struct hmac_methods_st { const EVP_MD* evp_md; + size_t chaining_length; // chaining length in bytes HashInit init; HashUpdate update; - HashFinal finalize; // Not named final to avoid keywords + HashFinal finalize; // Not named final to avoid keywords + HashInitFromState init_from_state; + HashGetState get_state; }; // We need trampolines from the generic void* methods we use to the properly typed underlying methods. @@ -87,6 +93,11 @@ struct hmac_methods_st { static int AWS_LC_TRAMPOLINE_##HASH_NAME##_Update(void *, const void *, \ size_t); \ static int AWS_LC_TRAMPOLINE_##HASH_NAME##_Final(uint8_t *, void *); \ + static int AWS_LC_TRAMPOLINE_##HASH_NAME##_Init_from_state( \ + void *, const uint8_t *, uint64_t); \ + static int AWS_LC_TRAMPOLINE_##HASH_NAME##_get_state(void *, uint8_t *, \ + uint64_t *); \ + static int AWS_LC_TRAMPOLINE_##HASH_NAME##_Final(uint8_t *, void *); \ static int AWS_LC_TRAMPOLINE_##HASH_NAME##_Init(void *ctx) { \ return HASH_NAME##_Init((HASH_CTX *)ctx); \ } \ @@ -97,7 +108,15 @@ struct hmac_methods_st { static int AWS_LC_TRAMPOLINE_##HASH_NAME##_Final(uint8_t *out, void *ctx) { \ return HASH_NAME##_Final(out, (HASH_CTX *)ctx); \ } \ - OPENSSL_STATIC_ASSERT(HASH_CBLOCK% 8 == 0, \ + static int AWS_LC_TRAMPOLINE_##HASH_NAME##_Init_from_state( \ + void *ctx, const uint8_t *h, uint64_t n) { \ + return HASH_NAME##_Init_from_state((HASH_CTX *)ctx, h, n); \ + } \ + static int AWS_LC_TRAMPOLINE_##HASH_NAME##_get_state( \ + void *ctx, uint8_t *out_h, uint64_t *out_n) { \ + return HASH_NAME##_get_state((HASH_CTX *)ctx, out_h, out_n); \ + } \ + OPENSSL_STATIC_ASSERT(HASH_CBLOCK % 8 == 0, \ HASH_NAME##_has_blocksize_not_divisible_by_eight_t) \ OPENSSL_STATIC_ASSERT(HASH_CBLOCK <= EVP_MAX_MD_BLOCK_SIZE, \ HASH_NAME##_has_overlarge_blocksize_t) \ @@ -108,26 +127,31 @@ struct hmac_methods_st { // The maximum number of HMAC implementations #define HMAC_METHOD_MAX 8 -MD_TRAMPOLINES_EXPLICIT(MD5, MD5_CTX, MD5_CBLOCK); -MD_TRAMPOLINES_EXPLICIT(SHA1, SHA_CTX, SHA_CBLOCK); -MD_TRAMPOLINES_EXPLICIT(SHA224, SHA256_CTX, SHA256_CBLOCK); +// FIXME: all hashes but SHA256 have been disabled to check first SHA256 +// MD_TRAMPOLINES_EXPLICIT(MD5, MD5_CTX, MD5_CBLOCK); +// MD_TRAMPOLINES_EXPLICIT(SHA1, SHA_CTX, SHA_CBLOCK); +// MD_TRAMPOLINES_EXPLICIT(SHA224, SHA256_CTX, SHA256_CBLOCK); MD_TRAMPOLINES_EXPLICIT(SHA256, SHA256_CTX, SHA256_CBLOCK); -MD_TRAMPOLINES_EXPLICIT(SHA384, SHA512_CTX, SHA512_CBLOCK); -MD_TRAMPOLINES_EXPLICIT(SHA512, SHA512_CTX, SHA512_CBLOCK); -MD_TRAMPOLINES_EXPLICIT(SHA512_224, SHA512_CTX, SHA512_CBLOCK); -MD_TRAMPOLINES_EXPLICIT(SHA512_256, SHA512_CTX, SHA512_CBLOCK); +// MD_TRAMPOLINES_EXPLICIT(SHA384, SHA512_CTX, SHA512_CBLOCK); +// MD_TRAMPOLINES_EXPLICIT(SHA512, SHA512_CTX, SHA512_CBLOCK); +// MD_TRAMPOLINES_EXPLICIT(SHA512_224, SHA512_CTX, SHA512_CBLOCK); +// MD_TRAMPOLINES_EXPLICIT(SHA512_256, SHA512_CTX, SHA512_CBLOCK); struct hmac_method_array_st { HmacMethods methods[HMAC_METHOD_MAX]; }; -#define DEFINE_IN_PLACE_METHODS(EVP_MD, HASH_NAME) { \ - out->methods[idx].evp_md = EVP_MD; \ - out->methods[idx].init = AWS_LC_TRAMPOLINE_##HASH_NAME##_Init; \ - out->methods[idx].update = AWS_LC_TRAMPOLINE_##HASH_NAME##_Update; \ - out->methods[idx].finalize = AWS_LC_TRAMPOLINE_##HASH_NAME##_Final; \ - idx++; \ - assert(idx <= HMAC_METHOD_MAX); \ +#define DEFINE_IN_PLACE_METHODS(EVP_MD, HASH_NAME) { \ + out->methods[idx].evp_md = EVP_MD; \ + out->methods[idx].chaining_length = HASH_NAME##_CHAINING_LENGTH; \ + out->methods[idx].init = AWS_LC_TRAMPOLINE_##HASH_NAME##_Init; \ + out->methods[idx].update = AWS_LC_TRAMPOLINE_##HASH_NAME##_Update; \ + out->methods[idx].finalize = AWS_LC_TRAMPOLINE_##HASH_NAME##_Final; \ + out->methods[idx].init_from_state = \ + AWS_LC_TRAMPOLINE_##HASH_NAME##_Init_from_state; \ + out->methods[idx].get_state = AWS_LC_TRAMPOLINE_##HASH_NAME##_get_state; \ + idx++; \ + assert(idx <= HMAC_METHOD_MAX); \ } DEFINE_LOCAL_DATA(struct hmac_method_array_st, AWSLC_hmac_in_place_methods) { @@ -135,14 +159,15 @@ DEFINE_LOCAL_DATA(struct hmac_method_array_st, AWSLC_hmac_in_place_methods) { int idx = 0; // Since we search these linearly it helps (just a bit) to put the most common ones first. // This isn't based on hard metrics and will not make a significant different on performance. + // FIXME: all hashes but SHA256 have been disabled to check first SHA256 DEFINE_IN_PLACE_METHODS(EVP_sha256(), SHA256); - DEFINE_IN_PLACE_METHODS(EVP_sha1(), SHA1); - DEFINE_IN_PLACE_METHODS(EVP_sha384(), SHA384); - DEFINE_IN_PLACE_METHODS(EVP_sha512(), SHA512); - DEFINE_IN_PLACE_METHODS(EVP_md5(), MD5); - DEFINE_IN_PLACE_METHODS(EVP_sha224(), SHA224); - DEFINE_IN_PLACE_METHODS(EVP_sha512_224(), SHA512_224); - DEFINE_IN_PLACE_METHODS(EVP_sha512_256(), SHA512_256); + // DEFINE_IN_PLACE_METHODS(EVP_sha1(), SHA1); + // DEFINE_IN_PLACE_METHODS(EVP_sha384(), SHA384); + // DEFINE_IN_PLACE_METHODS(EVP_sha512(), SHA512); + // DEFINE_IN_PLACE_METHODS(EVP_md5(), MD5); + // DEFINE_IN_PLACE_METHODS(EVP_sha224(), SHA224); + // DEFINE_IN_PLACE_METHODS(EVP_sha512_224(), SHA512_224); + // DEFINE_IN_PLACE_METHODS(EVP_sha512_256(), SHA512_256); } static const HmacMethods *GetInPlaceMethods(const EVP_MD *evp_md) { @@ -163,8 +188,12 @@ static const HmacMethods *GetInPlaceMethods(const EVP_MD *evp_md) { // This means that if init is called but nothing changes, we don't need to reset our state. // HMAC_STATE_IN_PROGRESS: Initialized with an md and key. Data processed. // This means that if init is called we do need to reset state. -// HMAC_STATE_READY_NEEDS_INIT: Identical to state 1 but API contract requires that Init be called prior to use. +// HMAC_STATE_READY_NEEDS_INIT: Identical to state HMAC_STATE_INIT_NO_DATA but API contract requires that Init be called prior to use. // This is an optimization because we can leave the context in a state ready for use after completion. +// HMAC_STATE_PRECOMPUTED_KEY_EXPORT_READY: Identical to state HMAC_STATE_READY_NEEDS_INIT but marked to allow precompute key export +// This state is treated as HMAC_STATE_READY_NEEDS_INIT by Init/Update/Final. +// This state is the only state that in which a precompute key can be exported. +// This state is set by HMAC_set_precomputed_key_export. // other: Invalid state and likely a result of using unitialized memory. Treated the same as 0. // // While we are within HMAC methods we allow for the state value and actual state of the context to diverge. @@ -174,6 +203,7 @@ static const HmacMethods *GetInPlaceMethods(const EVP_MD *evp_md) { #define HMAC_STATE_INIT_NO_DATA 1 #define HMAC_STATE_IN_PROGRESS 2 #define HMAC_STATE_READY_NEEDS_INIT 3 +#define HMAC_STATE_PRECOMPUTED_KEY_EXPORT_READY 4 // Static assertion to ensure that no one has changed the value of HMAC_STATE_UNINITIALIZED. // This really must stay with a zero value. @@ -211,6 +241,45 @@ uint8_t *HMAC(const EVP_MD *evp_md, const void *key, size_t key_len, } } +uint8_t *HMAC_with_precompute(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) { + HMAC_CTX ctx; + OPENSSL_memset(&ctx, 0, sizeof(HMAC_CTX)); + int result; + + // We have to avoid the underlying SHA services updating the indicator + // state, so we lock the state here. + // TODO: Here and also in HMAC, isn't the service indicator locked + // by the underlying functions anyways? + FIPS_service_indicator_lock_state(); + + uint8_t precomputed_key[HMAC_MAX_PRECOMPUTED_KEY_SIZE]; + size_t precomputed_key_len; + + result = + HMAC_Init_ex(&ctx, key, key_len, evp_md, NULL) && + HMAC_set_precomputed_key_export(&ctx) && + HMAC_get_precomputed_key(&ctx, precomputed_key, &precomputed_key_len) && + HMAC_Init_from_precomputed_key(&ctx, precomputed_key, precomputed_key_len, + evp_md) && + HMAC_Update(&ctx, data, data_len) && HMAC_Final(&ctx, out, out_len); + + FIPS_service_indicator_unlock_state(); + + // Regardless of our success we need to zeroize our working state. + HMAC_CTX_cleanup(&ctx); + OPENSSL_cleanse(precomputed_key, HMAC_MAX_PRECOMPUTED_KEY_SIZE); + if (result) { + HMAC_verify_service_indicator(evp_md); + return out; + } else { + OPENSSL_cleanse(out, EVP_MD_size(evp_md)); + return NULL; + } +} + void HMAC_CTX_init(HMAC_CTX *ctx) { OPENSSL_memset(ctx, 0, sizeof(HMAC_CTX)); } @@ -242,12 +311,34 @@ void HMAC_CTX_free(HMAC_CTX *ctx) { OPENSSL_free(ctx); } +// hmac_ctx_set_md_methods is used to set ctx->methods and ctx->md from md. +// It is called as part of the initialization of the ctx (HMAC_Init_*). +// It returns one on success, and zero otherwise. +static int hmac_ctx_set_md_methods(HMAC_CTX *ctx, const EVP_MD *md) { + if (md && (HMAC_STATE_UNINITIALIZED == ctx->state || ctx->md != md)) { + // The MD has changed + ctx->methods = GetInPlaceMethods(md); + if (ctx->methods == NULL) { + // Unsupported md + return 0; + } + ctx->md = md; + } else if (!hmac_ctx_is_initialized(ctx)) { + // We are not initialized but have not been provided with an md to + // initialize ourselves with. + return 0; + } + + return 1; +} + int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len, const EVP_MD *md, ENGINE *impl) { assert(impl == NULL); - if (HMAC_STATE_READY_NEEDS_INIT == ctx->state) { - ctx->state = HMAC_STATE_INIT_NO_DATA; // Mark that init has been called + if (HMAC_STATE_READY_NEEDS_INIT == ctx->state || + HMAC_STATE_PRECOMPUTED_KEY_EXPORT_READY == ctx->state) { + ctx->state = HMAC_STATE_INIT_NO_DATA; // Mark that init has been called } if (HMAC_STATE_INIT_NO_DATA == ctx->state) { @@ -265,16 +356,7 @@ int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len, // or the md and they key has changed. // (It is a misuse to just change the md so we also assume that the key changes when the md changes.) - if (md && (HMAC_STATE_UNINITIALIZED == ctx->state || ctx->md != md)) { - // The MD has changed - ctx->methods = GetInPlaceMethods(md); - if (ctx->methods == NULL) { - // Unsupported md - return 0; - } - ctx->md = md; - } else if (!hmac_ctx_is_initialized(ctx)) { - // We are not initialized but have not been provided with an md to initialize ourselves with. + if (!hmac_ctx_set_md_methods(ctx, md)) { return 0; } @@ -393,6 +475,122 @@ void HMAC_CTX_reset(HMAC_CTX *ctx) { // Cleanup intrinsicly inits to all zeros which is valid } +int HMAC_set_precomputed_key_export(HMAC_CTX *ctx) { + if (HMAC_STATE_INIT_NO_DATA != ctx->state && + HMAC_STATE_PRECOMPUTED_KEY_EXPORT_READY != ctx->state) { + // HMAC_set_precomputed_key_export can only be called after Hmac_Init_* + return 0; + } + ctx->state = HMAC_STATE_PRECOMPUTED_KEY_EXPORT_READY; + return 1; +} + +size_t HMAC_precomputed_key_size(const HMAC_CTX *ctx) { + return 2 * ctx->methods->chaining_length; +} + +int HMAC_get_precomputed_key(HMAC_CTX *ctx, uint8_t *out, size_t *out_len) { + if (HMAC_STATE_PRECOMPUTED_KEY_EXPORT_READY != ctx->state) { + return 0; + } + + const size_t chaining_length = ctx->methods->chaining_length; + size_t block_size = EVP_MD_block_size(ctx->md); + assert(2 * chaining_length <= HMAC_MAX_PRECOMPUTED_KEY_SIZE); + + uint64_t i_ctx_n; + uint64_t o_ctx_n; + + const int ok = ctx->methods->get_state(&ctx->i_ctx, out, &i_ctx_n) && + ctx->methods->get_state(&ctx->o_ctx, out + chaining_length, &o_ctx_n); + + // We should never arrive here as in our setting, get_state should always be + // successful since i_ctx/o_ctx have processed exactly one block + assert(ok); + + // Sanity check: we must have processed a single block at this time + assert(8 * block_size == i_ctx_n); + assert(8 * block_size == o_ctx_n); + + *out_len = chaining_length * 2; + + return 1; +} + +int HMAC_Init_from_precomputed_key(HMAC_CTX *ctx, + const uint8_t *precomputed_key, + size_t precomputed_key_len, + const EVP_MD *md) { + if (HMAC_STATE_READY_NEEDS_INIT == ctx->state || + HMAC_STATE_PRECOMPUTED_KEY_EXPORT_READY == ctx->state) { + ctx->state = HMAC_STATE_INIT_NO_DATA; // Mark that init has been called + } + + if (HMAC_STATE_INIT_NO_DATA == ctx->state) { + if (precomputed_key == NULL && (md == NULL || md == ctx->md)) { + // If nothing is changing then we can return without doing any further + // work. + return 1; + } + } + + // Now we assume that we need to re-initialize everything. + // See HMAC_Init_ex + + if (!hmac_ctx_set_md_methods(ctx, md)) { + return 0; + } + + const HmacMethods *methods = ctx->methods; + + const size_t chaining_length = methods->chaining_length; + const size_t block_size = EVP_MD_block_size(methods->evp_md); + assert(block_size <= EVP_MAX_MD_BLOCK_SIZE); + assert(2 * chaining_length <= HMAC_MAX_PRECOMPUTED_KEY_SIZE); + + if (2 * chaining_length != precomputed_key_len) { + return 0; + } + + // We require precomputed_key to be non-NULL, since here md changed + if (NULL == precomputed_key) { + return 0; + } + + // We have to avoid the underlying SHA services updating the indicator + // state, so we lock the state here. Technically this is not really needed, + // because the functions we call should not update the indicator state. + // But this is safer. + FIPS_service_indicator_lock_state(); + int result = 0; + + // Initialize i_ctx from the state stored in the first part of precomputed_key + // Recall that i_ctx is the state of the hash function after processing + // one block (ipad xor keyOrHashedKey) + if (!methods->init_from_state(&ctx->i_ctx, precomputed_key, block_size * 8)) { + goto end; + } + + // Same for o_ctx using the second part of precomputed_key + if (!methods->init_from_state(&ctx->o_ctx, precomputed_key + chaining_length, + block_size * 8)) { + goto end; + } + + OPENSSL_memcpy(&ctx->md_ctx, &ctx->i_ctx, sizeof(ctx->i_ctx)); + ctx->state = HMAC_STATE_INIT_NO_DATA; + + result = 1; +end: + FIPS_service_indicator_unlock_state(); + if (result != 1) { + // We're in some error state, so return our context to a known and + // well-defined zero state. + HMAC_CTX_cleanup(ctx); + } + return result; +} + int HMAC_Init(HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md) { if (key && md) { HMAC_CTX_init(ctx); diff --git a/crypto/fipsmodule/hmac/internal.h b/crypto/fipsmodule/hmac/internal.h new file mode 100644 index 0000000000..186052b590 --- /dev/null +++ b/crypto/fipsmodule/hmac/internal.h @@ -0,0 +1,27 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +#ifndef AWSLC_HEADER_HMAC_INTERNAL_H +#define AWSLC_HEADER_HMAC_INTERNAL_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +// HMAC_with_precompute is only used in FIPS ACVP harness, in order to test +// the computation of HMAC using precomputed keys (internally). It should not +// be used for any other purposes as it outputs the same results as HMAC and is +// slower than HMAC. +OPENSSL_EXPORT uint8_t *HMAC_with_precompute(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 defined(__cplusplus) +} // extern C +#endif + +#endif // AWSLC_HEADER_HMAC_INTERNAL_H diff --git a/crypto/hmac_extra/hmac_test.cc b/crypto/hmac_extra/hmac_test.cc index 96d00a9e86..c41c31dcfb 100644 --- a/crypto/hmac_extra/hmac_test.cc +++ b/crypto/hmac_extra/hmac_test.cc @@ -64,6 +64,7 @@ #include #include +#include "../../../crypto/fipsmodule/hmac/internal.h" #include "../test/file_test.h" #include "../test/test_util.h" #include "../test/wycheproof_util.h" @@ -210,7 +211,7 @@ TEST(HMACTest, TestVectors) { ASSERT_EQ(EVP_MD_size(digest), output.size()); // Test using the one-shot API. - unsigned expected_mac_len = EVP_MD_size(digest); + const unsigned expected_mac_len = EVP_MD_size(digest); std::unique_ptr mac(new uint8_t[expected_mac_len]); unsigned mac_len; ASSERT_TRUE(HMAC(digest, key.data(), key.size(), input.data(), input.size(), @@ -218,6 +219,13 @@ TEST(HMACTest, TestVectors) { EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len)); OPENSSL_memset(mac.get(), 0, expected_mac_len); // Clear the prior correct answer + // Test using the one-shot API with precompute + ASSERT_TRUE(HMAC_with_precompute(digest, key.data(), key.size(), + input.data(), input.size(), mac.get(), + &mac_len)); + EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len)); + OPENSSL_memset(mac.get(), 0, expected_mac_len); // Clear the prior correct answer + // Test using HMAC_CTX. bssl::ScopedHMAC_CTX ctx; ASSERT_TRUE( @@ -227,6 +235,33 @@ TEST(HMACTest, TestVectors) { EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len)); OPENSSL_memset(mac.get(), 0, expected_mac_len); // Clear the prior correct answer + // Test the precomputed key size is at most HMAC_MAX_PRECOMPUTED_KEY_SIZE + const size_t precomputed_key_len = HMAC_precomputed_key_size(ctx.get()); + ASSERT_LE(precomputed_key_len, (size_t) HMAC_MAX_PRECOMPUTED_KEY_SIZE); + uint8_t precomputed_key[HMAC_MAX_PRECOMPUTED_KEY_SIZE]; + + // Test that the precomputed key cannot be exported without calling + // HMAC_set_precomputed_key_export + size_t precomputed_key_len_out; + ASSERT_TRUE(HMAC_Init_ex(ctx.get(), key.data(), key.size(), digest, nullptr)); + ASSERT_FALSE(HMAC_get_precomputed_key(ctx.get(), precomputed_key, &precomputed_key_len_out)); + + // Test that the precomputed key cannot be exported if ctx not initialized + // and the precomputed_key_export flag cannot be set + bssl::ScopedHMAC_CTX ctx2; + ASSERT_FALSE(HMAC_set_precomputed_key_export(ctx2.get())); + ASSERT_FALSE(HMAC_get_precomputed_key(ctx2.get(), precomputed_key, &precomputed_key_len_out)); + + // Export the precomputed key for later use + ASSERT_TRUE(HMAC_set_precomputed_key_export(ctx.get())); + ASSERT_TRUE(HMAC_get_precomputed_key(ctx.get(), precomputed_key, &precomputed_key_len_out)); + ASSERT_EQ(precomputed_key_len, precomputed_key_len_out); + + // Test that at this point the context cannot be used with HMAC_Update + // nor HMAC_Final + ASSERT_FALSE(HMAC_Update(ctx.get(), input.data(), input.size())); + ASSERT_FALSE(HMAC_Final(ctx.get(), mac.get(), &mac_len)); + // Test that an HMAC_CTX may be reset with the same key. ASSERT_TRUE(HMAC_Init_ex(ctx.get(), nullptr, 0, digest, nullptr)); ASSERT_TRUE(HMAC_Update(ctx.get(), input.data(), input.size())); @@ -234,13 +269,27 @@ TEST(HMACTest, TestVectors) { EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len)); OPENSSL_memset(mac.get(), 0, expected_mac_len); // Clear the prior correct answer - // Test that an HMAC_CTX may be reset with the same key and an null md + // Same test but with HMAC_Init_from_precomputed_key + ASSERT_TRUE(HMAC_Init_from_precomputed_key(ctx.get(), nullptr, 0, digest)); + ASSERT_TRUE(HMAC_Update(ctx.get(), input.data(), input.size())); + ASSERT_TRUE(HMAC_Final(ctx.get(), mac.get(), &mac_len)); + EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len)); + OPENSSL_memset(mac.get(), 0, expected_mac_len); // Clear the prior correct answer + + // Test that an HMAC_CTX may be reset with the same key and a null md ASSERT_TRUE(HMAC_Init_ex(ctx.get(), nullptr, 0, nullptr, nullptr)); ASSERT_TRUE(HMAC_Update(ctx.get(), input.data(), input.size())); ASSERT_TRUE(HMAC_Final(ctx.get(), mac.get(), &mac_len)); EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len)); OPENSSL_memset(mac.get(), 0, expected_mac_len); // Clear the prior correct answer + // Same test but using the Init_with_precompute instead + ASSERT_TRUE(HMAC_Init_from_precomputed_key(ctx.get(), nullptr, 0, nullptr)); + ASSERT_TRUE(HMAC_Update(ctx.get(), input.data(), input.size())); + ASSERT_TRUE(HMAC_Final(ctx.get(), mac.get(), &mac_len)); + EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len)); + OPENSSL_memset(mac.get(), 0, expected_mac_len); // Clear the prior correct answer + // Some callers will call init multiple times and we need to ensure that doesn't break anything ASSERT_TRUE(HMAC_Init_ex(ctx.get(), key.data(), key.size(), digest, nullptr)); ASSERT_TRUE(HMAC_Init_ex(ctx.get(), nullptr, 0, nullptr, nullptr)); @@ -249,6 +298,59 @@ TEST(HMACTest, TestVectors) { EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len)); OPENSSL_memset(mac.get(), 0, expected_mac_len); // Clear the prior correct answer + // Same test but using a mix of Init_ex and Init_with_precompute + ASSERT_TRUE(HMAC_Init_ex(ctx.get(), key.data(), key.size(), digest, nullptr)); + ASSERT_TRUE(HMAC_Init_from_precomputed_key(ctx.get(), nullptr, 0, nullptr)); + ASSERT_TRUE(HMAC_Init_ex(ctx.get(), nullptr, 0, nullptr, nullptr)); + ASSERT_TRUE(HMAC_Init_from_precomputed_key(ctx.get(), nullptr, 0, nullptr)); + ASSERT_TRUE(HMAC_Update(ctx.get(), input.data(), input.size())); + ASSERT_TRUE(HMAC_Final(ctx.get(), mac.get(), &mac_len)); + EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len)); + OPENSSL_memset(mac.get(), 0, expected_mac_len); // Clear the prior correct answer + + // Test that the HMAC_CTX can be reset using the precomputed key + ASSERT_TRUE(HMAC_Init_from_precomputed_key(ctx.get(), precomputed_key, precomputed_key_len, nullptr)); + ASSERT_TRUE(HMAC_Update(ctx.get(), input.data(), input.size())); + ASSERT_TRUE(HMAC_Final(ctx.get(), mac.get(), &mac_len)); + EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len)); + OPENSSL_memset(mac.get(), 0, expected_mac_len); // Clear the prior correct answer + + // Same test but starting from an empty context + ctx.Reset(); + ASSERT_TRUE(HMAC_Init_from_precomputed_key(ctx.get(), precomputed_key, precomputed_key_len, digest)); + ASSERT_TRUE(HMAC_Update(ctx.get(), input.data(), input.size())); + ASSERT_TRUE(HMAC_Final(ctx.get(), mac.get(), &mac_len)); + EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len)); + OPENSSL_memset(mac.get(), 0, expected_mac_len); // Clear the prior correct answer + + // Some callers will call init_from_precomputed_key multiple times and we need to ensure that doesn't break anything + ASSERT_TRUE(HMAC_Init_from_precomputed_key(ctx.get(), precomputed_key, precomputed_key_len, nullptr)); + ASSERT_TRUE(HMAC_Init_from_precomputed_key(ctx.get(), nullptr, 0, nullptr)); + ASSERT_TRUE(HMAC_Update(ctx.get(), input.data(), input.size())); + ASSERT_TRUE(HMAC_Final(ctx.get(), mac.get(), &mac_len)); + EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len)); + OPENSSL_memset(mac.get(), 0, expected_mac_len); // Clear the prior correct answer + + // Test that we get the same precompute_key the second time + ASSERT_TRUE(HMAC_Init_ex(ctx.get(), key.data(), key.size(), digest, nullptr)); + uint8_t precomputed_key2[HMAC_MAX_PRECOMPUTED_KEY_SIZE]; + size_t precomputed_key_len_out2; + ASSERT_TRUE(HMAC_set_precomputed_key_export(ctx.get())); + ASSERT_TRUE(HMAC_set_precomputed_key_export(ctx.get())); // testing we can set it twice + ASSERT_TRUE(HMAC_get_precomputed_key(ctx.get(), precomputed_key2, &precomputed_key_len_out2)); + ASSERT_EQ(precomputed_key_len, precomputed_key_len_out2); + ASSERT_EQ(Bytes(precomputed_key, precomputed_key_len), Bytes(precomputed_key2, precomputed_key_len)); + OPENSSL_memset(precomputed_key2, 0, HMAC_MAX_PRECOMPUTED_KEY_SIZE); // Clear the prior correct answer + precomputed_key_len_out2 = 0; // Clear the prior correct answer + + // Same but initializing the ctx using the precompute key in the first place + ctx.Reset(); + ASSERT_TRUE(HMAC_Init_from_precomputed_key(ctx.get(), precomputed_key, precomputed_key_len, digest)); + ASSERT_TRUE(HMAC_set_precomputed_key_export(ctx.get())); + ASSERT_TRUE(HMAC_get_precomputed_key(ctx.get(), precomputed_key2, &precomputed_key_len_out2)); + ASSERT_EQ(precomputed_key_len, precomputed_key_len_out2); + ASSERT_EQ(Bytes(precomputed_key, precomputed_key_len), Bytes(precomputed_key2, precomputed_key_len)); + // Test feeding the input in byte by byte. ASSERT_TRUE(HMAC_Init_ex(ctx.get(), nullptr, 0, nullptr, nullptr)); for (size_t i = 0; i < input.size(); i++) { diff --git a/crypto/hmac_extra/hmac_tests.txt b/crypto/hmac_extra/hmac_tests.txt index 43c7a41002..12164b1fea 100644 --- a/crypto/hmac_extra/hmac_tests.txt +++ b/crypto/hmac_extra/hmac_tests.txt @@ -1,60 +1,3 @@ -HMAC = MD5 -# Note: The empty key results in passing NULL to HMAC_Init_ex, so this tests -# that HMAC_CTX and HMAC treat NULL as the empty key initially. -Key = -Input = "More text test vectors to stuff up EBCDIC machines :-)" -Output = e9139d1e6ee064ef8cf514fc7dc83e86 - -# HMAC tests from RFC 2104 -HMAC = MD5 -Key = 0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b -Input = "Hi There" -Output = 9294727a3638bb1c13f48ef8158bfc9d - -HMAC = MD5 -Key = "Jefe" -Input = "what do ya want for nothing?" -Output = 750c783e6ab0b503eaa86e310a5db738 - -HMAC = MD5 -Key = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -Input = DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD -Output = 56be34521d144c88dbb8c733f0e8b3f6 - -# HMAC tests from NIST test data - -HMAC = SHA1 -Input = "Sample message for keylen=blocklen" -Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F -Output = 5FD596EE78D5553C8FF4E72D266DFD192366DA29 - -HMAC = SHA1 -Input = "Sample message for keylenblocklen, but the NIST test vectors have a misleading input. -HMAC = SHA1 -Input = "Sample message for keylen=blocklen" -Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60616263 -Output = 2D51B2F7750E410584662E38F133435F4C4FD42A - -HMAC = SHA224 -Input = "Sample message for keylen=blocklen" -Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F -Output = C7405E3AE058E8CD30B08B4140248581ED174CB34E1224BCC1EFC81B - -HMAC = SHA224 -Input = "Sample message for keylenblocklen, but the NIST test vectors have a misleading input. -HMAC = SHA224 -Input = "Sample message for keylen=blocklen" -Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60616263 -Output = 91C52509E5AF8531601AE6230099D90BEF88AAEFB961F4080ABC014D - HMAC = SHA256 Input = "Sample message for keylen=blocklen" Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F @@ -71,44 +14,6 @@ Input = "Sample message for keylen=blocklen" Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60616263 Output = BDCCB6C72DDEADB500AE768386CB38CC41C63DBB0878DDB9C7A38A431B78378D -HMAC = SHA384 -Input = "Sample message for keylen=blocklen" -Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F -Output = 63C5DAA5E651847CA897C95814AB830BEDEDC7D25E83EEF9195CD45857A37F448947858F5AF50CC2B1B730DDF29671A9 - -HMAC = SHA384 -Input = "Sample message for keylenblocklen, but the NIST test vectors have a misleading input. -HMAC = SHA384 -Input = "Sample message for keylen=blocklen" -Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7 -Output = 5B664436DF69B0CA22551231A3F0A3D5B4F97991713CFA84BFF4D0792EFF96C27DCCBBB6F79B65D548B40E8564CEF594 - -HMAC = SHA512 -Input = "Sample message for keylen=blocklen" -Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F -Output = FC25E240658CA785B7A811A8D3F7B4CA48CFA26A8A366BF2CD1F836B05FCB024BD36853081811D6CEA4216EBAD79DA1CFCB95EA4586B8A0CE356596A55FB1347 - -HMAC = SHA512 -Input = "Sample message for keylenblocklen, but the NIST test vectors have a misleading input. -HMAC = SHA512 -Input = "Sample message for keylen=blocklen" -Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7 -Output = D93EC8D2DE1AD2A9957CB9B83F14E76AD6B5E0CCE285079A127D3B14BCCB7AA7286D4AC0D4CE64215F2BC9E6870B33D97438BE4AAA20CDA5C5A912B48B8E27F3 - -# Additional HMAC tests from OpenSSL. -HMAC = SHA1 -Input = "My test data" -Key = -Output = 61afdecb95429ef494d61fdee15990cabf0826fc - HMAC = SHA256 Input = "My test data" Key = @@ -117,29 +22,4 @@ Output = 2274b195d90ce8e03406f4b526a47e0787a88a65479938f1a5baa3ce0f079776 HMAC = SHA256 Input = "My test data" Key = "123456" -Output = bab53058ae861a7f191abe2d0145cbb123776a6369ee3f9d79ce455667e411dd - -HMAC = SHA1 -Input = "My test data" -Key = "12345" -Output = 7dbe8c764c068e3bcd6e6b0fbcd5e6fc197b15bb - -HMAC = SHA512/224 -Input = "My test data" -Key = -Output = fc993d20088ed6028478b8356aa818b82c6131f04292f97d86e77620 - -HMAC = SHA512/224 -Input = "My test data" -Key = "123456" -Output = 49d08109c1766ce6386d7b8bdaf5d014667083677096b82f56a73531 - -HMAC = SHA512/256 -Input = "My test data" -Key = -Output = 297753ca6b09b11dcfa97a0e9dcdc8c2c3eaac85a2c4bebe395b4630bd436aac - -HMAC = SHA512/256 -Input = "My test data" -Key = "123456" -Output = 2ed564c398a4fab30a1c4e071fd0f5b3c8a548d2e75ec3237ca5334071a63f40 +Output = bab53058ae861a7f191abe2d0145cbb123776a6369ee3f9d79ce455667e411dd \ No newline at end of file diff --git a/crypto/hmac_extra/hmac_tests_full.txt b/crypto/hmac_extra/hmac_tests_full.txt new file mode 100644 index 0000000000..43c7a41002 --- /dev/null +++ b/crypto/hmac_extra/hmac_tests_full.txt @@ -0,0 +1,145 @@ +HMAC = MD5 +# Note: The empty key results in passing NULL to HMAC_Init_ex, so this tests +# that HMAC_CTX and HMAC treat NULL as the empty key initially. +Key = +Input = "More text test vectors to stuff up EBCDIC machines :-)" +Output = e9139d1e6ee064ef8cf514fc7dc83e86 + +# HMAC tests from RFC 2104 +HMAC = MD5 +Key = 0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b +Input = "Hi There" +Output = 9294727a3638bb1c13f48ef8158bfc9d + +HMAC = MD5 +Key = "Jefe" +Input = "what do ya want for nothing?" +Output = 750c783e6ab0b503eaa86e310a5db738 + +HMAC = MD5 +Key = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +Input = DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD +Output = 56be34521d144c88dbb8c733f0e8b3f6 + +# HMAC tests from NIST test data + +HMAC = SHA1 +Input = "Sample message for keylen=blocklen" +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F +Output = 5FD596EE78D5553C8FF4E72D266DFD192366DA29 + +HMAC = SHA1 +Input = "Sample message for keylenblocklen, but the NIST test vectors have a misleading input. +HMAC = SHA1 +Input = "Sample message for keylen=blocklen" +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60616263 +Output = 2D51B2F7750E410584662E38F133435F4C4FD42A + +HMAC = SHA224 +Input = "Sample message for keylen=blocklen" +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F +Output = C7405E3AE058E8CD30B08B4140248581ED174CB34E1224BCC1EFC81B + +HMAC = SHA224 +Input = "Sample message for keylenblocklen, but the NIST test vectors have a misleading input. +HMAC = SHA224 +Input = "Sample message for keylen=blocklen" +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60616263 +Output = 91C52509E5AF8531601AE6230099D90BEF88AAEFB961F4080ABC014D + +HMAC = SHA256 +Input = "Sample message for keylen=blocklen" +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F +Output = 8BB9A1DB9806F20DF7F77B82138C7914D174D59E13DC4D0169C9057B133E1D62 + +HMAC = SHA256 +Input = "Sample message for keylenblocklen, but the NIST test vectors have a misleading input. +HMAC = SHA256 +Input = "Sample message for keylen=blocklen" +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60616263 +Output = BDCCB6C72DDEADB500AE768386CB38CC41C63DBB0878DDB9C7A38A431B78378D + +HMAC = SHA384 +Input = "Sample message for keylen=blocklen" +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F +Output = 63C5DAA5E651847CA897C95814AB830BEDEDC7D25E83EEF9195CD45857A37F448947858F5AF50CC2B1B730DDF29671A9 + +HMAC = SHA384 +Input = "Sample message for keylenblocklen, but the NIST test vectors have a misleading input. +HMAC = SHA384 +Input = "Sample message for keylen=blocklen" +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7 +Output = 5B664436DF69B0CA22551231A3F0A3D5B4F97991713CFA84BFF4D0792EFF96C27DCCBBB6F79B65D548B40E8564CEF594 + +HMAC = SHA512 +Input = "Sample message for keylen=blocklen" +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F +Output = FC25E240658CA785B7A811A8D3F7B4CA48CFA26A8A366BF2CD1F836B05FCB024BD36853081811D6CEA4216EBAD79DA1CFCB95EA4586B8A0CE356596A55FB1347 + +HMAC = SHA512 +Input = "Sample message for keylenblocklen, but the NIST test vectors have a misleading input. +HMAC = SHA512 +Input = "Sample message for keylen=blocklen" +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7 +Output = D93EC8D2DE1AD2A9957CB9B83F14E76AD6B5E0CCE285079A127D3B14BCCB7AA7286D4AC0D4CE64215F2BC9E6870B33D97438BE4AAA20CDA5C5A912B48B8E27F3 + +# Additional HMAC tests from OpenSSL. +HMAC = SHA1 +Input = "My test data" +Key = +Output = 61afdecb95429ef494d61fdee15990cabf0826fc + +HMAC = SHA256 +Input = "My test data" +Key = +Output = 2274b195d90ce8e03406f4b526a47e0787a88a65479938f1a5baa3ce0f079776 + +HMAC = SHA256 +Input = "My test data" +Key = "123456" +Output = bab53058ae861a7f191abe2d0145cbb123776a6369ee3f9d79ce455667e411dd + +HMAC = SHA1 +Input = "My test data" +Key = "12345" +Output = 7dbe8c764c068e3bcd6e6b0fbcd5e6fc197b15bb + +HMAC = SHA512/224 +Input = "My test data" +Key = +Output = fc993d20088ed6028478b8356aa818b82c6131f04292f97d86e77620 + +HMAC = SHA512/224 +Input = "My test data" +Key = "123456" +Output = 49d08109c1766ce6386d7b8bdaf5d014667083677096b82f56a73531 + +HMAC = SHA512/256 +Input = "My test data" +Key = +Output = 297753ca6b09b11dcfa97a0e9dcdc8c2c3eaac85a2c4bebe395b4630bd436aac + +HMAC = SHA512/256 +Input = "My test data" +Key = "123456" +Output = 2ed564c398a4fab30a1c4e071fd0f5b3c8a548d2e75ec3237ca5334071a63f40 diff --git a/include/openssl/hmac.h b/include/openssl/hmac.h index 436cb47644..d89b5596e2 100644 --- a/include/openssl/hmac.h +++ b/include/openssl/hmac.h @@ -125,7 +125,7 @@ OPENSSL_EXPORT int HMAC_Update(HMAC_CTX *ctx, const uint8_t *data, size_t data_len); // HMAC_Final completes the HMAC operation in |ctx| and writes the result to -// |out| and the sets |*out_len| to the length of the result. On entry, |out| +// |out| and then sets |*out_len| to the length of the result. On entry, |out| // must contain at least |HMAC_size| bytes of space. An output size of // |EVP_MAX_MD_SIZE| will always be large enough. It returns one on success or // zero on allocation failure. @@ -151,6 +151,80 @@ OPENSSL_EXPORT int HMAC_CTX_copy_ex(HMAC_CTX *dest, const HMAC_CTX *src); OPENSSL_EXPORT void HMAC_CTX_reset(HMAC_CTX *ctx); +// Precomputed key functions + +// HMAC_MAX_PRECOMPUTED_KEY_SIZE is the largest precomputed key size, in bytes. +#define HMAC_MAX_PRECOMPUTED_KEY_SIZE (2 * (EVP_MAX_MD_CHAINING_LENGTH)) + +// HMAC_set_precomputed_key_export sets the context |ctx| to allow export of the +// precomputed key using HMAC_get_precomputed_key. On entry, HMAC_CTX must have +// been initialized via HMAC_Init_*, and neither HMAC_Update nor HMAC_Final +// must have been called after the last HMAC_Init_ex. It returns one on success +// and zero on programmer error. +// After a successful call to HMAC_set_precomputed_key_export, HMAC_Update and +// HMAC_Final will fail. +// +// Note: The main reason for this function is to satisfy FIPS assertion AS09.16, +// since HMAC_get_precomputed_key returns key material (i.e., a CSP in NIST +// terminology). +OPENSSL_EXPORT int HMAC_set_precomputed_key_export(HMAC_CTX *ctx); + +// HMAC_precompute_size returns the size, in bytes, of the HMAC precomputed key +// that will be produced by |ctx|. On entry, |ctx| must have been set up with +// |HMAC_Init_ex|. +OPENSSL_EXPORT size_t HMAC_precomputed_key_size(const HMAC_CTX *ctx); + +// HMAC_get_precomputed_key writes the precomputed key to |out| and sets +// |*out_len| to the length of the result. On entry, the function +// HMAC_set_precomputed_key_export must have been called on |ctx|. Furthermore, +// |out| must contain at least |HMAC_precomputed_key_size| bytes of space. An +// output size of |HMAC_MAX_PRECOMPUTED_KEY_SIZE| will always be large enough. +// After a successful call to HMAC_get_precomputed_key, the context need to be +// set up again by HMAC_Init_*, like after a call to HMAC_Final. +// It returns one on success and zero on programmer error. +// +// The precomputed key is the concatenation: +// precomputed_key = key_ipad || key_opad +// where: +// key_ipad = Hash_Compression_Function(key' xor ipad) +// key_opad = Hash_Compression_Function(key' xor opad) +// key' = padding of key with 0 on the right to be of the block length +// if length of key is at most the block length +// or Hash(key) +// otherwise +// +// Knowledge of precomputed_key is sufficient to compute HMAC. Use of the +// precomputed key instead of the key reduces by 2 the number of hash +// compression function calls (or more if key is larger than the block length) +OPENSSL_EXPORT int HMAC_get_precomputed_key(HMAC_CTX *ctx, uint8_t *out, + size_t *out_len); + +// HMAC_Init_from_precomputed_key sets up an initialised |HMAC_CTX| to use |md| +// as the hash function and |precomputed_key| as the precomputed key (see +// HMAC_get_precomputed_key). For a non-initial call, |md| may be NULL, in which +// case the previous hash function will be used. If the hash function has not +// changed and |precomputed_key| is NULL, |ctx| reuses the previous key. It +// returns one on success or zero on failure. +// +// It is possible to mix and match HMAC_Init_ex and +// HMAC_Init_from_precomputed_key. +// If precomputed_key=NULL and md=previous MD or NULL, +// and if HMAC_Init_ex or HMAC_Init_from_precomputed_key was successfully called +// before, then +// HMAC_Init_ex(ctx, NULL, precomputed_key_len, md, engine=NULL) +// is equivalent to +// HMAC_Init_from_precomputed_key(ctx, NULL, precomputed_key_len, md) +// +// Note: Contrary to HMAC_Init_ex, it is not possible to use the empty key with +// that function. Passing NULL to |precomputed_key| is only allowed on a +// non-initial call where the same md is provided or md == NULL. Any other +// case will make the function fail and return zero. +OPENSSL_EXPORT int HMAC_Init_from_precomputed_key(HMAC_CTX *ctx, + const uint8_t *precomputed_key, + size_t precompute_key_len, + const EVP_MD *md); + + // Deprecated functions. OPENSSL_EXPORT int HMAC_Init(HMAC_CTX *ctx, const void *key, int key_len, diff --git a/util/fipstools/acvp/modulewrapper/modulewrapper.cc b/util/fipstools/acvp/modulewrapper/modulewrapper.cc index 48bc917b70..0e3244fe3a 100644 --- a/util/fipstools/acvp/modulewrapper/modulewrapper.cc +++ b/util/fipstools/acvp/modulewrapper/modulewrapper.cc @@ -50,6 +50,7 @@ #include "../../../../crypto/fipsmodule/ec/internal.h" #include "../../../../crypto/fipsmodule/rand/internal.h" +#include "../../../../crypto/fipsmodule/hmac/internal.h" #include "modulewrapper.h" @@ -1855,12 +1856,30 @@ static bool TDES_CBC(const Span args[], ReplyCallback write_reply template static bool HMAC(const Span args[], ReplyCallback write_reply) { const EVP_MD *const md = HashFunc(); + + // Normal HMAC computation uint8_t digest[EVP_MAX_MD_SIZE]; unsigned digest_len; if (::HMAC(md, args[1].data(), args[1].size(), args[0].data(), args[0].size(), digest, &digest_len) == nullptr) { return false; } + + // HMAC computation with precomputed keys + uint8_t digest_with_precompute[EVP_MAX_MD_SIZE]; + unsigned digest_with_precompute_len; + if (::HMAC_with_precompute(md, args[1].data(), args[1].size(), args[0].data(), + args[0].size(), digest_with_precompute, + &digest_with_precompute_len) == nullptr) { + return false; + } + + // The two HMAC computations must yield exactly the same results + if (digest_len != digest_with_precompute_len || + memcmp(digest, digest_with_precompute, digest_len) != 0) { + return false; + } + return write_reply({Span(digest, digest_len)}); } From 3a3a9ada6710d873aab120da5f5c60d6dfe97d52 Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Mon, 10 Jun 2024 17:27:07 -0400 Subject: [PATCH 03/26] Addressing comments from review of PR #1574 --- crypto/fipsmodule/hmac/hmac.c | 30 +++++++++++++++---------- crypto/fipsmodule/hmac/internal.h | 1 + crypto/fipsmodule/sha/internal.h | 4 ++-- crypto/fipsmodule/sha/sha256.c | 2 +- crypto/hmac_extra/hmac_test.cc | 32 +++++++++++++++++++------- include/openssl/hmac.h | 37 ++++++++++++++++++------------- 6 files changed, 67 insertions(+), 39 deletions(-) diff --git a/crypto/fipsmodule/hmac/hmac.c b/crypto/fipsmodule/hmac/hmac.c index 3700909e41..4cf2f2f2dc 100644 --- a/crypto/fipsmodule/hmac/hmac.c +++ b/crypto/fipsmodule/hmac/hmac.c @@ -251,8 +251,6 @@ uint8_t *HMAC_with_precompute(const EVP_MD *evp_md, const void *key, // We have to avoid the underlying SHA services updating the indicator // state, so we lock the state here. - // TODO: Here and also in HMAC, isn't the service indicator locked - // by the underlying functions anyways? FIPS_service_indicator_lock_state(); uint8_t precomputed_key[HMAC_MAX_PRECOMPUTED_KEY_SIZE]; @@ -264,7 +262,8 @@ uint8_t *HMAC_with_precompute(const EVP_MD *evp_md, const void *key, HMAC_get_precomputed_key(&ctx, precomputed_key, &precomputed_key_len) && HMAC_Init_from_precomputed_key(&ctx, precomputed_key, precomputed_key_len, evp_md) && - HMAC_Update(&ctx, data, data_len) && HMAC_Final(&ctx, out, out_len); + HMAC_Update(&ctx, data, data_len) && + HMAC_Final(&ctx, out, out_len); FIPS_service_indicator_unlock_state(); @@ -272,7 +271,11 @@ uint8_t *HMAC_with_precompute(const EVP_MD *evp_md, const void *key, HMAC_CTX_cleanup(&ctx); OPENSSL_cleanse(precomputed_key, HMAC_MAX_PRECOMPUTED_KEY_SIZE); if (result) { - HMAC_verify_service_indicator(evp_md); + // Contrary to what happens in the |HMAC| function, we do not update the + // service indicator here (i.e., we do not call + // |HMAC_verify_service_indicator|), because the function + // |HMAC_with_precompute| is not FIPS-approved per se and is only used in + // tests. return out; } else { OPENSSL_cleanse(out, EVP_MD_size(evp_md)); @@ -485,19 +488,20 @@ int HMAC_set_precomputed_key_export(HMAC_CTX *ctx) { return 1; } -size_t HMAC_precomputed_key_size(const HMAC_CTX *ctx) { - return 2 * ctx->methods->chaining_length; -} - int HMAC_get_precomputed_key(HMAC_CTX *ctx, uint8_t *out, size_t *out_len) { if (HMAC_STATE_PRECOMPUTED_KEY_EXPORT_READY != ctx->state) { return 0; } const size_t chaining_length = ctx->methods->chaining_length; - size_t block_size = EVP_MD_block_size(ctx->md); - assert(2 * chaining_length <= HMAC_MAX_PRECOMPUTED_KEY_SIZE); - + *out_len = chaining_length * 2; + assert(*out_len <= HMAC_MAX_PRECOMPUTED_KEY_SIZE); + if (NULL == out) { + // When out is NULL, we just set out_len. + // We keep the state as HMAC_STATE_PRECOMPUTED_KEY_EXPORT_READY + // to allow an actual export of the precomputed key immediately afterward. + return 1; + } uint64_t i_ctx_n; uint64_t o_ctx_n; @@ -509,10 +513,12 @@ int HMAC_get_precomputed_key(HMAC_CTX *ctx, uint8_t *out, size_t *out_len) { assert(ok); // Sanity check: we must have processed a single block at this time + size_t block_size = EVP_MD_block_size(ctx->md); assert(8 * block_size == i_ctx_n); assert(8 * block_size == o_ctx_n); - *out_len = chaining_length * 2; + // The context is ready to be used to compute HMAC values at this point. + ctx->state = HMAC_STATE_INIT_NO_DATA; return 1; } diff --git a/crypto/fipsmodule/hmac/internal.h b/crypto/fipsmodule/hmac/internal.h index 186052b590..f708851ede 100644 --- a/crypto/fipsmodule/hmac/internal.h +++ b/crypto/fipsmodule/hmac/internal.h @@ -14,6 +14,7 @@ extern "C" { // the computation of HMAC using precomputed keys (internally). It should not // be used for any other purposes as it outputs the same results as HMAC and is // slower than HMAC. +// This function does not update the FIPS indicator. OPENSSL_EXPORT uint8_t *HMAC_with_precompute(const EVP_MD *evp_md, const void *key, size_t key_len, const uint8_t *data, diff --git a/crypto/fipsmodule/sha/internal.h b/crypto/fipsmodule/sha/internal.h index 30ebb9bdbb..9eafceb53a 100644 --- a/crypto/fipsmodule/sha/internal.h +++ b/crypto/fipsmodule/sha/internal.h @@ -107,7 +107,7 @@ void sha512_block_data_order(uint64_t *state, const uint8_t *in, // custom state. |h| is the hash state in big endian. |n| is the number of bits // processed at this point. It must be a multiple of |SHA256_CBLOCK*8|. // It returns one on success and zero on programmer error. -// External users should never use directly this function. +// This function is for internal use only and should never be directly called. OPENSSL_EXPORT int SHA256_Init_from_state( SHA256_CTX *sha, const uint8_t h[SHA256_CHAINING_LENGTH], uint64_t n); @@ -118,7 +118,7 @@ OPENSSL_EXPORT int SHA256_Init_from_state( // SHA256_Update must be a multiple of the block length |SHA256_CBLOCK| // (otherwise it fails). It returns one on success and zero on programmer // error. -// External users should never use directly this function. +// This function is for internal use only and should never be directly called. OPENSSL_EXPORT int SHA256_get_state(SHA256_CTX *ctx, uint8_t out_h[SHA256_CHAINING_LENGTH], uint64_t *out_n); diff --git a/crypto/fipsmodule/sha/sha256.c b/crypto/fipsmodule/sha/sha256.c index 380935f8b4..57508cdf4e 100644 --- a/crypto/fipsmodule/sha/sha256.c +++ b/crypto/fipsmodule/sha/sha256.c @@ -198,7 +198,7 @@ static int sha256_final_impl(uint8_t *out, size_t md_len, SHA256_CTX *c) { return 1; } -int SHA256_Final(uint8_t out[SHA256_CHAINING_LENGTH], SHA256_CTX *c) { +int SHA256_Final(uint8_t out[SHA256_DIGEST_LENGTH], SHA256_CTX *c) { return sha256_final_impl(out, SHA256_DIGEST_LENGTH, c); } diff --git a/crypto/hmac_extra/hmac_test.cc b/crypto/hmac_extra/hmac_test.cc index c41c31dcfb..4243fa351a 100644 --- a/crypto/hmac_extra/hmac_test.cc +++ b/crypto/hmac_extra/hmac_test.cc @@ -235,9 +235,6 @@ TEST(HMACTest, TestVectors) { EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len)); OPENSSL_memset(mac.get(), 0, expected_mac_len); // Clear the prior correct answer - // Test the precomputed key size is at most HMAC_MAX_PRECOMPUTED_KEY_SIZE - const size_t precomputed_key_len = HMAC_precomputed_key_size(ctx.get()); - ASSERT_LE(precomputed_key_len, (size_t) HMAC_MAX_PRECOMPUTED_KEY_SIZE); uint8_t precomputed_key[HMAC_MAX_PRECOMPUTED_KEY_SIZE]; // Test that the precomputed key cannot be exported without calling @@ -252,16 +249,27 @@ TEST(HMACTest, TestVectors) { ASSERT_FALSE(HMAC_set_precomputed_key_export(ctx2.get())); ASSERT_FALSE(HMAC_get_precomputed_key(ctx2.get(), precomputed_key, &precomputed_key_len_out)); - // Export the precomputed key for later use + // Get the precomputed key length for later use + // And test the precomputed key size is at most HMAC_MAX_PRECOMPUTED_KEY_SIZE ASSERT_TRUE(HMAC_set_precomputed_key_export(ctx.get())); - ASSERT_TRUE(HMAC_get_precomputed_key(ctx.get(), precomputed_key, &precomputed_key_len_out)); - ASSERT_EQ(precomputed_key_len, precomputed_key_len_out); + size_t precomputed_key_len; + HMAC_get_precomputed_key(ctx.get(), nullptr, &precomputed_key_len); + ASSERT_LE(precomputed_key_len, (size_t) HMAC_MAX_PRECOMPUTED_KEY_SIZE); - // Test that at this point the context cannot be used with HMAC_Update - // nor HMAC_Final + // Test that at this point, the context can be used with HMAC_Update ASSERT_FALSE(HMAC_Update(ctx.get(), input.data(), input.size())); ASSERT_FALSE(HMAC_Final(ctx.get(), mac.get(), &mac_len)); + // Export the precomputed key for later use + ASSERT_TRUE(HMAC_get_precomputed_key(ctx.get(), precomputed_key, &precomputed_key_len_out)); + ASSERT_EQ(precomputed_key_len, precomputed_key_len_out); + + // Test that at this point, the context can be used with HMAC_Update + ASSERT_TRUE(HMAC_Update(ctx.get(), input.data(), input.size())); + ASSERT_TRUE(HMAC_Final(ctx.get(), mac.get(), &mac_len)); + EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len)); + OPENSSL_memset(mac.get(), 0, expected_mac_len); // Clear the prior correct answer + // Test that an HMAC_CTX may be reset with the same key. ASSERT_TRUE(HMAC_Init_ex(ctx.get(), nullptr, 0, digest, nullptr)); ASSERT_TRUE(HMAC_Update(ctx.get(), input.data(), input.size())); @@ -343,6 +351,14 @@ TEST(HMACTest, TestVectors) { OPENSSL_memset(precomputed_key2, 0, HMAC_MAX_PRECOMPUTED_KEY_SIZE); // Clear the prior correct answer precomputed_key_len_out2 = 0; // Clear the prior correct answer + // Test that at this point, the context cannot be used to re-export the precomputed key + ASSERT_FALSE(HMAC_get_precomputed_key(ctx.get(), precomputed_key2, &precomputed_key_len_out2)); + // Check that precomputed_key_len_out2 and precomputed_key2 were not modified and are still zero + uint8_t zero_precomputed_key[HMAC_MAX_PRECOMPUTED_KEY_SIZE]; + OPENSSL_memset(zero_precomputed_key, 0, HMAC_MAX_PRECOMPUTED_KEY_SIZE); + ASSERT_EQ((size_t)0, precomputed_key_len_out2); + ASSERT_EQ(Bytes(zero_precomputed_key, HMAC_MAX_PRECOMPUTED_KEY_SIZE), Bytes(precomputed_key2, HMAC_MAX_PRECOMPUTED_KEY_SIZE)); + // Same but initializing the ctx using the precompute key in the first place ctx.Reset(); ASSERT_TRUE(HMAC_Init_from_precomputed_key(ctx.get(), precomputed_key, precomputed_key_len, digest)); diff --git a/include/openssl/hmac.h b/include/openssl/hmac.h index d89b5596e2..c31555386f 100644 --- a/include/openssl/hmac.h +++ b/include/openssl/hmac.h @@ -169,19 +169,23 @@ OPENSSL_EXPORT void HMAC_CTX_reset(HMAC_CTX *ctx); // terminology). OPENSSL_EXPORT int HMAC_set_precomputed_key_export(HMAC_CTX *ctx); -// HMAC_precompute_size returns the size, in bytes, of the HMAC precomputed key -// that will be produced by |ctx|. On entry, |ctx| must have been set up with -// |HMAC_Init_ex|. -OPENSSL_EXPORT size_t HMAC_precomputed_key_size(const HMAC_CTX *ctx); - // HMAC_get_precomputed_key writes the precomputed key to |out| and sets // |*out_len| to the length of the result. On entry, the function -// HMAC_set_precomputed_key_export must have been called on |ctx|. Furthermore, -// |out| must contain at least |HMAC_precomputed_key_size| bytes of space. An -// output size of |HMAC_MAX_PRECOMPUTED_KEY_SIZE| will always be large enough. -// After a successful call to HMAC_get_precomputed_key, the context need to be -// set up again by HMAC_Init_*, like after a call to HMAC_Final. -// It returns one on success and zero on programmer error. +// HMAC_set_precomputed_key_export must have been called on |ctx|. +// +// If |out| is NULL, only |out_len| is set. After such a call, +// HMAC_get_precomputed_key can directly be called again with a non-null |out|. +// But HMAC_Update and HMAC_Final will still fail. +// +// If |out| is not NULL, |out| must contain at least |out_len| bytes of space +// (as output by HMAC_get_precomputed_key). An output size of +// |HMAC_MAX_PRECOMPUTED_KEY_SIZE| will always be large enough. After a +// successful call to HMAC_get_precomputed_key with a non-NULL |out|, the +// context can directly be used for computing an HMAC, as if it was set up by +// HMAC_Init_*. In particular, in particular, HMAC_Update and HMAC_Final can be +// called. Further calls to HMAC_get_precomputed_key will fail. +// +// The function returns one on success and zero on programmer error. // // The precomputed key is the concatenation: // precomputed_key = key_ipad || key_opad @@ -206,17 +210,18 @@ OPENSSL_EXPORT int HMAC_get_precomputed_key(HMAC_CTX *ctx, uint8_t *out, // changed and |precomputed_key| is NULL, |ctx| reuses the previous key. It // returns one on success or zero on failure. // -// It is possible to mix and match HMAC_Init_ex and -// HMAC_Init_from_precomputed_key. -// If precomputed_key=NULL and md=previous MD or NULL, +// |HMAC_Init_ex| and |HMAC_Init_from_precomputed_key| are interchangeable when +// the input key is NULL. If precomputed_key=NULL and md=previous MD or NULL, // and if HMAC_Init_ex or HMAC_Init_from_precomputed_key was successfully called // before, then // HMAC_Init_ex(ctx, NULL, precomputed_key_len, md, engine=NULL) // is equivalent to // HMAC_Init_from_precomputed_key(ctx, NULL, precomputed_key_len, md) // -// Note: Contrary to HMAC_Init_ex, it is not possible to use the empty key with -// that function. Passing NULL to |precomputed_key| is only allowed on a +// Note: Contrary to input keys to HMAC_Init_ex, which can be the empty key, +// an input precomputed key (for HMAC_Init_from_precomputed_key) +// cannot be the empty key. The notion of empty precomputed key is not +// well-defined. Passing NULL to |precomputed_key| is only allowed on a // non-initial call where the same md is provided or md == NULL. Any other // case will make the function fail and return zero. OPENSSL_EXPORT int HMAC_Init_from_precomputed_key(HMAC_CTX *ctx, From f4b67b157f5405c44237b52dc6f62b1a85123db7 Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Mon, 10 Jun 2024 17:50:49 -0400 Subject: [PATCH 04/26] Clarifying definition of EVP_MAX_MD_CHAINING_LENGTH following review --- include/openssl/digest.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/openssl/digest.h b/include/openssl/digest.h index 7d6f058e18..a1a0486fcc 100644 --- a/include/openssl/digest.h +++ b/include/openssl/digest.h @@ -173,7 +173,9 @@ OPENSSL_EXPORT int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, // EVP_MAX_MD_CHAINING_LENGTH is the largest chaining length supported, in // bytes. This constant is only for Merkle-Damgard-based hashed functions -// like SHA-1, SHA-2, and MD5. +// like SHA-1, SHA-2, and MD5. The chaining length is defined as the output +// length of the hash in bytes, before any truncation (e.g., 32 for SHA-224 and +// SHA-256, 64 for SHA-384 and SHA-512). // This constant is only used internally by HMAC. #define EVP_MAX_MD_CHAINING_LENGTH 64 // SHA-512 has the longest chaining length so far From 8b5dbea07af2beb959705346ede9373e9d75cdc4 Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Mon, 10 Jun 2024 18:03:59 -0400 Subject: [PATCH 05/26] Remove redundant function declaration in HMAC/SHA256 trampoline --- crypto/fipsmodule/hmac/hmac.c | 1 - 1 file changed, 1 deletion(-) diff --git a/crypto/fipsmodule/hmac/hmac.c b/crypto/fipsmodule/hmac/hmac.c index 64850fcbf0..49c36f883a 100644 --- a/crypto/fipsmodule/hmac/hmac.c +++ b/crypto/fipsmodule/hmac/hmac.c @@ -97,7 +97,6 @@ struct hmac_methods_st { void *, const uint8_t *, uint64_t); \ static int AWS_LC_TRAMPOLINE_##HASH_NAME##_get_state(void *, uint8_t *, \ uint64_t *); \ - static int AWS_LC_TRAMPOLINE_##HASH_NAME##_Final(uint8_t *, void *); \ static int AWS_LC_TRAMPOLINE_##HASH_NAME##_Init(void *ctx) { \ return HASH_NAME##_Init((HASH_CTX *)ctx); \ } \ From 6734e0207ccf10004bf935a6dd0a69d872da7c83 Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Thu, 13 Jun 2024 13:15:49 -0400 Subject: [PATCH 06/26] Function comments improvements from review of PR #1574 --- crypto/fipsmodule/hmac/internal.h | 2 +- include/openssl/hmac.h | 29 ++++++++++------------------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/crypto/fipsmodule/hmac/internal.h b/crypto/fipsmodule/hmac/internal.h index f708851ede..084ef5341c 100644 --- a/crypto/fipsmodule/hmac/internal.h +++ b/crypto/fipsmodule/hmac/internal.h @@ -14,7 +14,7 @@ extern "C" { // the computation of HMAC using precomputed keys (internally). It should not // be used for any other purposes as it outputs the same results as HMAC and is // slower than HMAC. -// This function does not update the FIPS indicator. +// This function does not update the FIPS service indicator. OPENSSL_EXPORT uint8_t *HMAC_with_precompute(const EVP_MD *evp_md, const void *key, size_t key_len, const uint8_t *data, diff --git a/include/openssl/hmac.h b/include/openssl/hmac.h index c31555386f..ca764bf5bb 100644 --- a/include/openssl/hmac.h +++ b/include/openssl/hmac.h @@ -203,27 +203,18 @@ OPENSSL_EXPORT int HMAC_set_precomputed_key_export(HMAC_CTX *ctx); OPENSSL_EXPORT int HMAC_get_precomputed_key(HMAC_CTX *ctx, uint8_t *out, size_t *out_len); -// HMAC_Init_from_precomputed_key sets up an initialised |HMAC_CTX| to use |md| -// as the hash function and |precomputed_key| as the precomputed key (see -// HMAC_get_precomputed_key). For a non-initial call, |md| may be NULL, in which -// case the previous hash function will be used. If the hash function has not -// changed and |precomputed_key| is NULL, |ctx| reuses the previous key. It -// returns one on success or zero on failure. -// -// |HMAC_Init_ex| and |HMAC_Init_from_precomputed_key| are interchangeable when -// the input key is NULL. If precomputed_key=NULL and md=previous MD or NULL, -// and if HMAC_Init_ex or HMAC_Init_from_precomputed_key was successfully called -// before, then -// HMAC_Init_ex(ctx, NULL, precomputed_key_len, md, engine=NULL) -// is equivalent to -// HMAC_Init_from_precomputed_key(ctx, NULL, precomputed_key_len, md) +// HMAC_Init_from_precomputed_key sets up an initialised |HMAC_CTX| to use +// |md| as the hash function and |precomputed_key| as the precomputed key +// (see |HMAC_get_precomputed_key|). +// For a non-initial call, |md| may be NULL, in which case the previous hash +// function is used. If the hash function has not changed and |precomputed_key| +// is NULL, the previous key is used. This non-initial call is interchangeable +// with calling |HMAC_Init_ex| with the same parameters. It returns one on +// success or zero on failure. // // Note: Contrary to input keys to HMAC_Init_ex, which can be the empty key, -// an input precomputed key (for HMAC_Init_from_precomputed_key) -// cannot be the empty key. The notion of empty precomputed key is not -// well-defined. Passing NULL to |precomputed_key| is only allowed on a -// non-initial call where the same md is provided or md == NULL. Any other -// case will make the function fail and return zero. +// an input precomputed key cannot be empty in an initial call to +// HMAC_Init_from_precomputed_key. Otherwise, the call fails and returns zero. OPENSSL_EXPORT int HMAC_Init_from_precomputed_key(HMAC_CTX *ctx, const uint8_t *precomputed_key, size_t precompute_key_len, From 7c68e2f13c52c7172cffc43c6906a3c2fc60ac09 Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda <1146316+fabrice102@users.noreply.github.com> Date: Thu, 13 Jun 2024 13:17:52 -0400 Subject: [PATCH 07/26] Update function comment in crypto/fipsmodule/hmac/internal.h Co-authored-by: Nevine Ebeid <66388554+nebeid@users.noreply.github.com> --- crypto/fipsmodule/hmac/internal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crypto/fipsmodule/hmac/internal.h b/crypto/fipsmodule/hmac/internal.h index 084ef5341c..a3c4defe2b 100644 --- a/crypto/fipsmodule/hmac/internal.h +++ b/crypto/fipsmodule/hmac/internal.h @@ -12,8 +12,8 @@ extern "C" { // HMAC_with_precompute is only used in FIPS ACVP harness, in order to test // the computation of HMAC using precomputed keys (internally). It should not -// be used for any other purposes as it outputs the same results as HMAC and is -// slower than HMAC. +// be used for any other purposes as it outputs the same results as |HMAC| and is +// slower than |HMAC|. // This function does not update the FIPS service indicator. OPENSSL_EXPORT uint8_t *HMAC_with_precompute(const EVP_MD *evp_md, const void *key, size_t key_len, From 1f6b5108cfa4b6c47ab5bae2d9dde3aaee6bb06d Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Fri, 14 Jun 2024 15:12:55 -0400 Subject: [PATCH 08/26] Function comments improvements from review of PR #1574 --- include/openssl/hmac.h | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/include/openssl/hmac.h b/include/openssl/hmac.h index ca764bf5bb..898e23060e 100644 --- a/include/openssl/hmac.h +++ b/include/openssl/hmac.h @@ -160,7 +160,7 @@ OPENSSL_EXPORT void HMAC_CTX_reset(HMAC_CTX *ctx); // precomputed key using HMAC_get_precomputed_key. On entry, HMAC_CTX must have // been initialized via HMAC_Init_*, and neither HMAC_Update nor HMAC_Final // must have been called after the last HMAC_Init_ex. It returns one on success -// and zero on programmer error. +// and zero on error. // After a successful call to HMAC_set_precomputed_key_export, HMAC_Update and // HMAC_Final will fail. // @@ -171,21 +171,20 @@ OPENSSL_EXPORT int HMAC_set_precomputed_key_export(HMAC_CTX *ctx); // HMAC_get_precomputed_key writes the precomputed key to |out| and sets // |*out_len| to the length of the result. On entry, the function -// HMAC_set_precomputed_key_export must have been called on |ctx|. +// |HMAC_set_precomputed_key_export| must have been called on |ctx|. // // If |out| is NULL, only |out_len| is set. After such a call, -// HMAC_get_precomputed_key can directly be called again with a non-null |out|. -// But HMAC_Update and HMAC_Final will still fail. +// |HMAC_get_precomputed_key| can directly be called again with a non-null +// |out|. But |HMAC_Update| and |HMAC_Final| will still fail. // // If |out| is not NULL, |out| must contain at least |out_len| bytes of space -// (as output by HMAC_get_precomputed_key). An output size of +// (as output by |HMAC_get_precomputed_key|). An output size of // |HMAC_MAX_PRECOMPUTED_KEY_SIZE| will always be large enough. After a -// successful call to HMAC_get_precomputed_key with a non-NULL |out|, the -// context can directly be used for computing an HMAC, as if it was set up by -// HMAC_Init_*. In particular, in particular, HMAC_Update and HMAC_Final can be -// called. Further calls to HMAC_get_precomputed_key will fail. +// successful call to |HMAC_get_precomputed_key| with a non-NULL |out|, the +// context can be directly used for computing an HMAC using |HMAC_Update| and +// |HMAC_Final|. // -// The function returns one on success and zero on programmer error. +// The function returns one on success and zero on error. // // The precomputed key is the concatenation: // precomputed_key = key_ipad || key_opad @@ -212,9 +211,9 @@ OPENSSL_EXPORT int HMAC_get_precomputed_key(HMAC_CTX *ctx, uint8_t *out, // with calling |HMAC_Init_ex| with the same parameters. It returns one on // success or zero on failure. // -// Note: Contrary to input keys to HMAC_Init_ex, which can be the empty key, +// Note: Contrary to input keys to |HMAC_Init_ex|, which can be the empty key, // an input precomputed key cannot be empty in an initial call to -// HMAC_Init_from_precomputed_key. Otherwise, the call fails and returns zero. +// |HMAC_Init_from_precomputed_key|. Otherwise, the call fails and returns zero. OPENSSL_EXPORT int HMAC_Init_from_precomputed_key(HMAC_CTX *ctx, const uint8_t *precomputed_key, size_t precompute_key_len, From a11cb336d6fd0e3a61a47f16896ced974dc83baf Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Fri, 14 Jun 2024 16:13:07 -0400 Subject: [PATCH 09/26] Improve error management and check out_len - from review of PR #1574 1. Improve error management: add `OPENSSL_PUT_ERROR` when appropriate. 2. Change behaviour of `out_len` from `HMAC_get_precomputed_key` as per review. --- crypto/fipsmodule/hmac/hmac.c | 20 ++++++++++++++++++-- crypto/hmac_extra/hmac_test.cc | 21 +++++++++++++++------ include/openssl/hmac.h | 20 +++++++++++++------- 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/crypto/fipsmodule/hmac/hmac.c b/crypto/fipsmodule/hmac/hmac.c index 49c36f883a..6e9ac9ae22 100644 --- a/crypto/fipsmodule/hmac/hmac.c +++ b/crypto/fipsmodule/hmac/hmac.c @@ -481,6 +481,7 @@ int HMAC_set_precomputed_key_export(HMAC_CTX *ctx) { if (HMAC_STATE_INIT_NO_DATA != ctx->state && HMAC_STATE_PRECOMPUTED_KEY_EXPORT_READY != ctx->state) { // HMAC_set_precomputed_key_export can only be called after Hmac_Init_* + OPENSSL_PUT_ERROR(HMAC, HMAC_R_NOT_CALLED_JUST_AFTER_INIT); return 0; } ctx->state = HMAC_STATE_PRECOMPUTED_KEY_EXPORT_READY; @@ -489,18 +490,32 @@ int HMAC_set_precomputed_key_export(HMAC_CTX *ctx) { int HMAC_get_precomputed_key(HMAC_CTX *ctx, uint8_t *out, size_t *out_len) { if (HMAC_STATE_PRECOMPUTED_KEY_EXPORT_READY != ctx->state) { + OPENSSL_PUT_ERROR(EVP, HMAC_R_SET_PRECOMPUTED_KEY_EXPORT_NOT_CALLED); + return 0; + } + + if (NULL == out_len) { + OPENSSL_PUT_ERROR(EVP, HMAC_R_MISSING_PARAMETERS); return 0; } const size_t chaining_length = ctx->methods->chaining_length; - *out_len = chaining_length * 2; - assert(*out_len <= HMAC_MAX_PRECOMPUTED_KEY_SIZE); + size_t actual_out_len = chaining_length * 2; + assert(actual_out_len <= HMAC_MAX_PRECOMPUTED_KEY_SIZE); if (NULL == out) { // When out is NULL, we just set out_len. // We keep the state as HMAC_STATE_PRECOMPUTED_KEY_EXPORT_READY // to allow an actual export of the precomputed key immediately afterward. + *out_len = actual_out_len; return 1; } + // When out is not NULL, we need to check that *out_len is large enough + if (*out_len < actual_out_len) { + OPENSSL_PUT_ERROR(HMAC, HMAC_R_BUFFER_TOO_SMALL); + return 0; + } + *out_len = actual_out_len; + uint64_t i_ctx_n; uint64_t o_ctx_n; @@ -559,6 +574,7 @@ int HMAC_Init_from_precomputed_key(HMAC_CTX *ctx, // We require precomputed_key to be non-NULL, since here md changed if (NULL == precomputed_key) { + OPENSSL_PUT_ERROR(HMAC, HMAC_R_MISSING_PARAMETERS); return 0; } diff --git a/crypto/hmac_extra/hmac_test.cc b/crypto/hmac_extra/hmac_test.cc index 4243fa351a..face05cc34 100644 --- a/crypto/hmac_extra/hmac_test.cc +++ b/crypto/hmac_extra/hmac_test.cc @@ -239,7 +239,7 @@ TEST(HMACTest, TestVectors) { // Test that the precomputed key cannot be exported without calling // HMAC_set_precomputed_key_export - size_t precomputed_key_len_out; + size_t precomputed_key_len_out = HMAC_MAX_PRECOMPUTED_KEY_SIZE; ASSERT_TRUE(HMAC_Init_ex(ctx.get(), key.data(), key.size(), digest, nullptr)); ASSERT_FALSE(HMAC_get_precomputed_key(ctx.get(), precomputed_key, &precomputed_key_len_out)); @@ -247,6 +247,7 @@ TEST(HMACTest, TestVectors) { // and the precomputed_key_export flag cannot be set bssl::ScopedHMAC_CTX ctx2; ASSERT_FALSE(HMAC_set_precomputed_key_export(ctx2.get())); + precomputed_key_len_out = HMAC_MAX_PRECOMPUTED_KEY_SIZE; ASSERT_FALSE(HMAC_get_precomputed_key(ctx2.get(), precomputed_key, &precomputed_key_len_out)); // Get the precomputed key length for later use @@ -261,6 +262,7 @@ TEST(HMACTest, TestVectors) { ASSERT_FALSE(HMAC_Final(ctx.get(), mac.get(), &mac_len)); // Export the precomputed key for later use + precomputed_key_len_out = HMAC_MAX_PRECOMPUTED_KEY_SIZE; ASSERT_TRUE(HMAC_get_precomputed_key(ctx.get(), precomputed_key, &precomputed_key_len_out)); ASSERT_EQ(precomputed_key_len, precomputed_key_len_out); @@ -339,24 +341,31 @@ TEST(HMACTest, TestVectors) { EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len)); OPENSSL_memset(mac.get(), 0, expected_mac_len); // Clear the prior correct answer - // Test that we get the same precompute_key the second time - ASSERT_TRUE(HMAC_Init_ex(ctx.get(), key.data(), key.size(), digest, nullptr)); + // Test that we get an error if the out_len is not large enough uint8_t precomputed_key2[HMAC_MAX_PRECOMPUTED_KEY_SIZE]; size_t precomputed_key_len_out2; + ASSERT_TRUE(HMAC_Init_ex(ctx.get(), key.data(), key.size(), digest, nullptr)); ASSERT_TRUE(HMAC_set_precomputed_key_export(ctx.get())); ASSERT_TRUE(HMAC_set_precomputed_key_export(ctx.get())); // testing we can set it twice + precomputed_key_len_out2 = precomputed_key_len - 1; // slightly too short + ASSERT_FALSE(HMAC_get_precomputed_key(ctx.get(), precomputed_key2, &precomputed_key_len_out2)); + precomputed_key_len_out2 = 0; // 0-size should also fail + ASSERT_FALSE(HMAC_get_precomputed_key(ctx.get(), precomputed_key2, &precomputed_key_len_out2)); + + // Test that we get the same precompute_key the second time we correctly call HMAC_get_precomputed_key + precomputed_key_len_out2 = precomputed_key_len; // testing with the out_len is the exact value ASSERT_TRUE(HMAC_get_precomputed_key(ctx.get(), precomputed_key2, &precomputed_key_len_out2)); ASSERT_EQ(precomputed_key_len, precomputed_key_len_out2); ASSERT_EQ(Bytes(precomputed_key, precomputed_key_len), Bytes(precomputed_key2, precomputed_key_len)); OPENSSL_memset(precomputed_key2, 0, HMAC_MAX_PRECOMPUTED_KEY_SIZE); // Clear the prior correct answer - precomputed_key_len_out2 = 0; // Clear the prior correct answer // Test that at this point, the context cannot be used to re-export the precomputed key + precomputed_key_len_out2 = HMAC_MAX_PRECOMPUTED_KEY_SIZE; ASSERT_FALSE(HMAC_get_precomputed_key(ctx.get(), precomputed_key2, &precomputed_key_len_out2)); - // Check that precomputed_key_len_out2 and precomputed_key2 were not modified and are still zero + // Check that precomputed_key_len_out2 and precomputed_key2 were not modified and are still their original value uint8_t zero_precomputed_key[HMAC_MAX_PRECOMPUTED_KEY_SIZE]; OPENSSL_memset(zero_precomputed_key, 0, HMAC_MAX_PRECOMPUTED_KEY_SIZE); - ASSERT_EQ((size_t)0, precomputed_key_len_out2); + ASSERT_EQ((size_t)HMAC_MAX_PRECOMPUTED_KEY_SIZE, precomputed_key_len_out2); ASSERT_EQ(Bytes(zero_precomputed_key, HMAC_MAX_PRECOMPUTED_KEY_SIZE), Bytes(precomputed_key2, HMAC_MAX_PRECOMPUTED_KEY_SIZE)); // Same but initializing the ctx using the precompute key in the first place diff --git a/include/openssl/hmac.h b/include/openssl/hmac.h index 898e23060e..9a9311c261 100644 --- a/include/openssl/hmac.h +++ b/include/openssl/hmac.h @@ -169,16 +169,14 @@ OPENSSL_EXPORT void HMAC_CTX_reset(HMAC_CTX *ctx); // terminology). OPENSSL_EXPORT int HMAC_set_precomputed_key_export(HMAC_CTX *ctx); -// HMAC_get_precomputed_key writes the precomputed key to |out| and sets -// |*out_len| to the length of the result. On entry, the function -// |HMAC_set_precomputed_key_export| must have been called on |ctx|. -// -// If |out| is NULL, only |out_len| is set. After such a call, +// HMAC_get_precomputed_key exports the precomputed key. If |out| is NULL, +// |out_len| is set to the size of the precomputed key. After such a call, // |HMAC_get_precomputed_key| can directly be called again with a non-null // |out|. But |HMAC_Update| and |HMAC_Final| will still fail. // -// If |out| is not NULL, |out| must contain at least |out_len| bytes of space -// (as output by |HMAC_get_precomputed_key|). An output size of +// If |out| is not NULL, |*out_len| must contain the number of bytes of space +// available at |out|. If sufficient, the precomputed key will be written in +// |out| and |out_len| will be updated with the true length. An output size of // |HMAC_MAX_PRECOMPUTED_KEY_SIZE| will always be large enough. After a // successful call to |HMAC_get_precomputed_key| with a non-NULL |out|, the // context can be directly used for computing an HMAC using |HMAC_Update| and @@ -220,6 +218,14 @@ OPENSSL_EXPORT int HMAC_Init_from_precomputed_key(HMAC_CTX *ctx, const EVP_MD *md); +// Errors + +#define HMAC_R_MISSING_PARAMETERS 100 +#define HMAC_R_BUFFER_TOO_SMALL 102 +#define HMAC_R_SET_PRECOMPUTED_KEY_EXPORT_NOT_CALLED 103 +#define HMAC_R_NOT_CALLED_JUST_AFTER_INIT 104 + + // Deprecated functions. OPENSSL_EXPORT int HMAC_Init(HMAC_CTX *ctx, const void *key, int key_len, From 41fd25dd8b33b6f46fc88133e65e06835a11b155 Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda <1146316+fabrice102@users.noreply.github.com> Date: Fri, 14 Jun 2024 18:38:48 -0400 Subject: [PATCH 10/26] Apply suggestions from code review Co-authored-by: Nevine Ebeid <66388554+nebeid@users.noreply.github.com> --- crypto/hmac_extra/hmac_test.cc | 2 +- util/fipstools/acvp/modulewrapper/modulewrapper.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crypto/hmac_extra/hmac_test.cc b/crypto/hmac_extra/hmac_test.cc index face05cc34..752631bb7e 100644 --- a/crypto/hmac_extra/hmac_test.cc +++ b/crypto/hmac_extra/hmac_test.cc @@ -257,7 +257,7 @@ TEST(HMACTest, TestVectors) { HMAC_get_precomputed_key(ctx.get(), nullptr, &precomputed_key_len); ASSERT_LE(precomputed_key_len, (size_t) HMAC_MAX_PRECOMPUTED_KEY_SIZE); - // Test that at this point, the context can be used with HMAC_Update + // Test that at this point, the context cannot be used with HMAC_Update ASSERT_FALSE(HMAC_Update(ctx.get(), input.data(), input.size())); ASSERT_FALSE(HMAC_Final(ctx.get(), mac.get(), &mac_len)); diff --git a/util/fipstools/acvp/modulewrapper/modulewrapper.cc b/util/fipstools/acvp/modulewrapper/modulewrapper.cc index 0e3244fe3a..3c375fb737 100644 --- a/util/fipstools/acvp/modulewrapper/modulewrapper.cc +++ b/util/fipstools/acvp/modulewrapper/modulewrapper.cc @@ -1857,7 +1857,7 @@ template static bool HMAC(const Span args[], ReplyCallback write_reply) { const EVP_MD *const md = HashFunc(); - // Normal HMAC computation + // Approved HMAC computation uint8_t digest[EVP_MAX_MD_SIZE]; unsigned digest_len; if (::HMAC(md, args[1].data(), args[1].size(), args[0].data(), args[0].size(), From 6f14823defd5525a8db29cef4825005e8faec4c2 Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Fri, 14 Jun 2024 18:49:37 -0400 Subject: [PATCH 11/26] Apply suggestions from code review --- crypto/hmac_extra/hmac_test.cc | 4 ++-- include/openssl/hmac.h | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/crypto/hmac_extra/hmac_test.cc b/crypto/hmac_extra/hmac_test.cc index 752631bb7e..c3735ed62f 100644 --- a/crypto/hmac_extra/hmac_test.cc +++ b/crypto/hmac_extra/hmac_test.cc @@ -293,7 +293,7 @@ TEST(HMACTest, TestVectors) { EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len)); OPENSSL_memset(mac.get(), 0, expected_mac_len); // Clear the prior correct answer - // Same test but using the Init_with_precompute instead + // Same test but using the Init_from_precomputed_key instead ASSERT_TRUE(HMAC_Init_from_precomputed_key(ctx.get(), nullptr, 0, nullptr)); ASSERT_TRUE(HMAC_Update(ctx.get(), input.data(), input.size())); ASSERT_TRUE(HMAC_Final(ctx.get(), mac.get(), &mac_len)); @@ -308,7 +308,7 @@ TEST(HMACTest, TestVectors) { EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len)); OPENSSL_memset(mac.get(), 0, expected_mac_len); // Clear the prior correct answer - // Same test but using a mix of Init_ex and Init_with_precompute + // Same test but using a mix of Init_ex and Init_from_precomputed_key ASSERT_TRUE(HMAC_Init_ex(ctx.get(), key.data(), key.size(), digest, nullptr)); ASSERT_TRUE(HMAC_Init_from_precomputed_key(ctx.get(), nullptr, 0, nullptr)); ASSERT_TRUE(HMAC_Init_ex(ctx.get(), nullptr, 0, nullptr, nullptr)); diff --git a/include/openssl/hmac.h b/include/openssl/hmac.h index 9a9311c261..95f873218c 100644 --- a/include/openssl/hmac.h +++ b/include/openssl/hmac.h @@ -218,14 +218,6 @@ OPENSSL_EXPORT int HMAC_Init_from_precomputed_key(HMAC_CTX *ctx, const EVP_MD *md); -// Errors - -#define HMAC_R_MISSING_PARAMETERS 100 -#define HMAC_R_BUFFER_TOO_SMALL 102 -#define HMAC_R_SET_PRECOMPUTED_KEY_EXPORT_NOT_CALLED 103 -#define HMAC_R_NOT_CALLED_JUST_AFTER_INIT 104 - - // Deprecated functions. OPENSSL_EXPORT int HMAC_Init(HMAC_CTX *ctx, const void *key, int key_len, @@ -278,4 +270,12 @@ BSSL_NAMESPACE_END #endif + +// Errors + +#define HMAC_R_MISSING_PARAMETERS 100 +#define HMAC_R_BUFFER_TOO_SMALL 102 +#define HMAC_R_SET_PRECOMPUTED_KEY_EXPORT_NOT_CALLED 103 +#define HMAC_R_NOT_CALLED_JUST_AFTER_INIT 104 + #endif // OPENSSL_HEADER_HMAC_H From 73debcf697ec6e405169d893258985da76c67e9a Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda <1146316+fabrice102@users.noreply.github.com> Date: Fri, 14 Jun 2024 18:53:41 -0400 Subject: [PATCH 12/26] Function comments improvements from review of PR #1574 Co-authored-by: Nevine Ebeid <66388554+nebeid@users.noreply.github.com> --- util/fipstools/acvp/modulewrapper/modulewrapper.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/util/fipstools/acvp/modulewrapper/modulewrapper.cc b/util/fipstools/acvp/modulewrapper/modulewrapper.cc index 3c375fb737..cf5bf0fc4d 100644 --- a/util/fipstools/acvp/modulewrapper/modulewrapper.cc +++ b/util/fipstools/acvp/modulewrapper/modulewrapper.cc @@ -1866,6 +1866,8 @@ static bool HMAC(const Span args[], ReplyCallback write_reply) { } // HMAC computation with precomputed keys + // The purpose of this call is to test |HMAC_set_precomputed_key_export| and + // |HMAC_get_precomputed_key|, which are called by |HMAC_with_precompute|. uint8_t digest_with_precompute[EVP_MAX_MD_SIZE]; unsigned digest_with_precompute_len; if (::HMAC_with_precompute(md, args[1].data(), args[1].size(), args[0].data(), From 580159cfa5bbc9960978215f392ac894482a6b44 Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Wed, 19 Jun 2024 19:09:16 -0400 Subject: [PATCH 13/26] Extend PR #1574 to the other hash functions Previous commits in this PR/branch were restricted to SHA-256 to verify the design. Restore the full HMAC tests, which were restricted to HMAC-SHA-256 in a previous commit from this PR/branch. --- crypto/digest_extra/digest_test.cc | 123 +++++++++++++++------- crypto/fipsmodule/hmac/hmac.c | 32 +++--- crypto/fipsmodule/md5/internal.h | 24 +++++ crypto/fipsmodule/md5/md5.c | 39 +++++++ crypto/fipsmodule/sha/internal.h | 141 +++++++++++++++++++++++++ crypto/fipsmodule/sha/sha1.c | 39 +++++++ crypto/fipsmodule/sha/sha256.c | 11 ++ crypto/fipsmodule/sha/sha512.c | 99 ++++++++++++++++++ crypto/hmac_extra/hmac_tests.txt | 122 +++++++++++++++++++++- crypto/hmac_extra/hmac_tests_full.txt | 145 -------------------------- 10 files changed, 577 insertions(+), 198 deletions(-) delete mode 100644 crypto/hmac_extra/hmac_tests_full.txt diff --git a/crypto/digest_extra/digest_test.cc b/crypto/digest_extra/digest_test.cc index 0d3d7772f1..7bd33b00d5 100644 --- a/crypto/digest_extra/digest_test.cc +++ b/crypto/digest_extra/digest_test.cc @@ -34,6 +34,7 @@ #include #include +#include "../fipsmodule/md5/internal.h" #include "../fipsmodule/sha/internal.h" #include "../internal.h" #include "../test/test_util.h" @@ -477,45 +478,93 @@ TEST(DigestTest, TransformBlocks) { EXPECT_TRUE(0 == OPENSSL_memcmp(ctx1.h, ctx2.h, sizeof(ctx1.h))); } -// FIXME: Need to implement this for all hash functions used by HMAC -TEST(DigestTest, InitAndGetStateSHA256) { - const size_t nb_blocks = 10; - const size_t block_size = SHA256_CBLOCK; - uint8_t data[block_size * nb_blocks]; - for (size_t i = 0; i < sizeof(data); i++) { - data[i] = i*3; +// DIGEST_TEST_InitAndGetState_Body expands to the body of the various +// InitAndGetState* tests below. +// Because EXPECT_* do not output the proper line when used in a macro, +// we need to add diagnostic information `<< ...` after each EXPECT_* +#define DIGEST_TEST_InitAndGetState_Body(HASH_NAME, HASH_CTX, HASH_CBLOCK) \ + { \ + const size_t nb_blocks = 10; \ + const size_t block_size = HASH_CBLOCK; \ + uint8_t data[block_size * nb_blocks]; \ + for (size_t i = 0; i < sizeof(data); i++) { \ + data[i] = i * 3; \ + } \ + \ + /* Compute the hash of the data for the baseline */ \ + HASH_CTX ctx1; \ + EXPECT_TRUE(HASH_NAME##_Init(&ctx1)) << "init 1"; \ + EXPECT_TRUE(HASH_NAME##_Update(&ctx1, data, sizeof(data))) << "update 1"; \ + uint8_t hash1[HASH_NAME##_DIGEST_LENGTH]; \ + EXPECT_TRUE(HASH_NAME##_Final(hash1, &ctx1)) << "final 1"; \ + \ + /* Compute it by stopping in the middle, getting the state, and restoring \ + * it */ \ + HASH_CTX ctx2; \ + EXPECT_TRUE(HASH_NAME##_Init(&ctx2)) << "init 2"; \ + EXPECT_TRUE(HASH_NAME##_Update(&ctx2, data, 1)) << "update 2a"; \ + uint8_t state_h[HASH_NAME##_CHAINING_LENGTH]; \ + uint64_t state_n; \ + /* we should not be able to export the state before a full block */ \ + EXPECT_FALSE(HASH_NAME##_get_state(&ctx2, state_h, &state_n)) \ + << "get_state 2a"; \ + /* finish 2 blocks */ \ + EXPECT_TRUE(HASH_NAME##_Update(&ctx2, data + 1, 2 * block_size - 1)) \ + << "update 2b"; \ + /* now we should be able to export the state */ \ + EXPECT_TRUE(HASH_NAME##_get_state(&ctx2, state_h, &state_n)) \ + << "get_state 2b"; \ + /* check that state_n corresponds to 2 blocks */ \ + EXPECT_EQ(2 * block_size * 8, state_n) << "correct state_n"; \ + \ + /* and we continue on a fresh new context */ \ + HASH_CTX ctx3; \ + EXPECT_TRUE(HASH_NAME##_Init_from_state(&ctx3, state_h, state_n)) \ + << "init 3"; \ + EXPECT_TRUE(HASH_NAME##_Update(&ctx3, data + 2 * block_size, \ + (nb_blocks - 2) * block_size)) \ + << "update 3"; \ + uint8_t hash2[HASH_NAME##_DIGEST_LENGTH]; \ + EXPECT_TRUE(HASH_NAME##_Final(hash2, &ctx3)) << "final 3"; \ + \ + EXPECT_EQ(Bytes(hash1), Bytes(hash2)) << "same hash"; \ } - // SHA-256 +// The macro DIGEST_TEST_InitAndGetState_Body only contains the body of the +// tests and not the TEST(...) { part, so that IDE can still easily recognize +// those as tests. - // Compute the hash of the data for the baseline - SHA256_CTX ctx1; - EXPECT_TRUE(SHA256_Init(&ctx1)); - EXPECT_TRUE(SHA256_Update(&ctx1, data, sizeof(data))); - uint8_t hash1[SHA256_DIGEST_LENGTH]; - EXPECT_TRUE(SHA256_Final(hash1, &ctx1)); +TEST(DigestTest, InitAndGetStateMD5) { + DIGEST_TEST_InitAndGetState_Body(MD5, MD5_CTX, MD5_CBLOCK); +} - // Compute it by stopping in the middle, getting the state, and restoring it - SHA256_CTX ctx2; - EXPECT_TRUE(SHA256_Init(&ctx2)); - EXPECT_TRUE(SHA256_Update(&ctx2, data, 1)); - uint8_t state_h[SHA256_DIGEST_LENGTH]; - uint64_t state_n; - // we should not be able to export the state before a full block - EXPECT_FALSE(SHA256_get_state(&ctx2, state_h, &state_n)); - // finish 2 blocks - EXPECT_TRUE(SHA256_Update(&ctx2, data+1, 2*block_size-1)); - // now we should be able to export the state - EXPECT_TRUE(SHA256_get_state(&ctx2, state_h, &state_n)); - // check that state_n corresponds to 2 blocks - EXPECT_EQ(2*block_size*8, state_n); - - // and we continue on a fresh new context - SHA256_CTX ctx3; - EXPECT_TRUE(SHA256_Init_from_state(&ctx3, state_h, state_n)); - EXPECT_TRUE(SHA256_Update(&ctx2, data+2*block_size, (nb_blocks-2)*block_size)); - uint8_t hash2[SHA256_DIGEST_LENGTH]; - EXPECT_TRUE(SHA256_Final(hash2, &ctx2)); - - EXPECT_EQ(Bytes(hash1), Bytes(hash2)); +// Define SHA1_DIGEST_LENGTH to make the macro work... +#define SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH +TEST(DigestTest, InitAndGetStateSHA1) { + DIGEST_TEST_InitAndGetState_Body(SHA1, SHA_CTX, SHA_CBLOCK); +} + +TEST(DigestTest, InitAndGetStateSHA224) { + DIGEST_TEST_InitAndGetState_Body(SHA224, SHA256_CTX, SHA256_CBLOCK); +} + +TEST(DigestTest, InitAndGetStateSHA256) { + DIGEST_TEST_InitAndGetState_Body(SHA256, SHA256_CTX, SHA256_CBLOCK); } + +TEST(DigestTest, InitAndGetStateSHA384) { + DIGEST_TEST_InitAndGetState_Body(SHA384, SHA512_CTX, SHA512_CBLOCK); +} + +TEST(DigestTest, InitAndGetStateSHA512) { + DIGEST_TEST_InitAndGetState_Body(SHA512, SHA512_CTX, SHA512_CBLOCK); +} + +TEST(DigestTest, InitAndGetStateSHA512_224) { + DIGEST_TEST_InitAndGetState_Body(SHA512_224, SHA512_CTX, SHA512_CBLOCK); +} + +TEST(DigestTest, InitAndGetStateSHA512_256) { + DIGEST_TEST_InitAndGetState_Body(SHA512_256, SHA512_CTX, SHA512_CBLOCK); +} + diff --git a/crypto/fipsmodule/hmac/hmac.c b/crypto/fipsmodule/hmac/hmac.c index 6e9ac9ae22..eab17aefa3 100644 --- a/crypto/fipsmodule/hmac/hmac.c +++ b/crypto/fipsmodule/hmac/hmac.c @@ -66,6 +66,9 @@ #include "../../internal.h" #include "../service_indicator/internal.h" +#include "../md5/internal.h" +#include "../sha/internal.h" + typedef int (*HashInit)(void *); typedef int (*HashUpdate)(void *, const void *, size_t); typedef int (*HashFinal)(uint8_t *, void *); @@ -126,15 +129,14 @@ struct hmac_methods_st { // The maximum number of HMAC implementations #define HMAC_METHOD_MAX 8 -// FIXME: all hashes but SHA256 have been disabled to check first SHA256 -// MD_TRAMPOLINES_EXPLICIT(MD5, MD5_CTX, MD5_CBLOCK) -// MD_TRAMPOLINES_EXPLICIT(SHA1, SHA_CTX, SHA_CBLOCK) -// MD_TRAMPOLINES_EXPLICIT(SHA224, SHA256_CTX, SHA256_CBLOCK) +MD_TRAMPOLINES_EXPLICIT(MD5, MD5_CTX, MD5_CBLOCK) +MD_TRAMPOLINES_EXPLICIT(SHA1, SHA_CTX, SHA_CBLOCK) +MD_TRAMPOLINES_EXPLICIT(SHA224, SHA256_CTX, SHA256_CBLOCK) MD_TRAMPOLINES_EXPLICIT(SHA256, SHA256_CTX, SHA256_CBLOCK) -// MD_TRAMPOLINES_EXPLICIT(SHA384, SHA512_CTX, SHA512_CBLOCK) -// MD_TRAMPOLINES_EXPLICIT(SHA512, SHA512_CTX, SHA512_CBLOCK) -// MD_TRAMPOLINES_EXPLICIT(SHA512_224, SHA512_CTX, SHA512_CBLOCK) -// MD_TRAMPOLINES_EXPLICIT(SHA512_256, SHA512_CTX, SHA512_CBLOCK) +MD_TRAMPOLINES_EXPLICIT(SHA384, SHA512_CTX, SHA512_CBLOCK) +MD_TRAMPOLINES_EXPLICIT(SHA512, SHA512_CTX, SHA512_CBLOCK) +MD_TRAMPOLINES_EXPLICIT(SHA512_224, SHA512_CTX, SHA512_CBLOCK) +MD_TRAMPOLINES_EXPLICIT(SHA512_256, SHA512_CTX, SHA512_CBLOCK) struct hmac_method_array_st { HmacMethods methods[HMAC_METHOD_MAX]; @@ -160,13 +162,13 @@ DEFINE_LOCAL_DATA(struct hmac_method_array_st, AWSLC_hmac_in_place_methods) { // This isn't based on hard metrics and will not make a significant different on performance. // FIXME: all hashes but SHA256 have been disabled to check first SHA256 DEFINE_IN_PLACE_METHODS(EVP_sha256(), SHA256); - // DEFINE_IN_PLACE_METHODS(EVP_sha1(), SHA1); - // DEFINE_IN_PLACE_METHODS(EVP_sha384(), SHA384); - // DEFINE_IN_PLACE_METHODS(EVP_sha512(), SHA512); - // DEFINE_IN_PLACE_METHODS(EVP_md5(), MD5); - // DEFINE_IN_PLACE_METHODS(EVP_sha224(), SHA224); - // DEFINE_IN_PLACE_METHODS(EVP_sha512_224(), SHA512_224); - // DEFINE_IN_PLACE_METHODS(EVP_sha512_256(), SHA512_256); + DEFINE_IN_PLACE_METHODS(EVP_sha1(), SHA1); + DEFINE_IN_PLACE_METHODS(EVP_sha384(), SHA384); + DEFINE_IN_PLACE_METHODS(EVP_sha512(), SHA512); + DEFINE_IN_PLACE_METHODS(EVP_md5(), MD5); + DEFINE_IN_PLACE_METHODS(EVP_sha224(), SHA224); + DEFINE_IN_PLACE_METHODS(EVP_sha512_224(), SHA512_224); + DEFINE_IN_PLACE_METHODS(EVP_sha512_256(), SHA512_256); } static const HmacMethods *GetInPlaceMethods(const EVP_MD *evp_md) { diff --git a/crypto/fipsmodule/md5/internal.h b/crypto/fipsmodule/md5/internal.h index 845dd432a9..92f7e6fb84 100644 --- a/crypto/fipsmodule/md5/internal.h +++ b/crypto/fipsmodule/md5/internal.h @@ -21,6 +21,30 @@ extern "C" { #endif +// MD5_CHAINING_LENGTH is the chaining length in bytes of MD5 +// It corresponds to the length in bytes of the h part of the state +#define MD5_CHAINING_LENGTH 16 + +// MD5_Init_from_state is a low-level function that initializes |sha| with a +// custom state. |h| is the hash state in big endian. |n| is the number of bits +// processed at this point. It must be a multiple of |MD5_CBLOCK*8|. +// It returns one on success and zero on programmer error. +// This function is for internal use only and should never be directly called. +OPENSSL_EXPORT int MD5_Init_from_state(MD5_CTX *sha, + const uint8_t h[MD5_CHAINING_LENGTH], + uint64_t n); + +// MD5_get_state is a low-level function that exports the hash state in big +// endian into |out_n| and the number of bits processed at this point in +// |out_n|. MD5_Final must not have been called before (otherwise results +// are not guaranteed). Furthermore, the number of bytes processed by +// MD5_Update must be a multiple of the block length |MD5_CBLOCK| +// (otherwise it fails). It returns one on success and zero on programmer +// error. +// This function is for internal use only and should never be directly called. +OPENSSL_EXPORT int MD5_get_state(MD5_CTX *ctx, + uint8_t out_h[MD5_CHAINING_LENGTH], + uint64_t *out_n); #if !defined(OPENSSL_NO_ASM) && \ (defined(OPENSSL_X86_64) || defined(OPENSSL_X86) || defined(OPENSSL_AARCH64)) diff --git a/crypto/fipsmodule/md5/md5.c b/crypto/fipsmodule/md5/md5.c index 1691526766..bf53ce18f7 100644 --- a/crypto/fipsmodule/md5/md5.c +++ b/crypto/fipsmodule/md5/md5.c @@ -83,6 +83,27 @@ int MD5_Init(MD5_CTX *md5) { return 1; } +int MD5_Init_from_state(MD5_CTX *md5, const uint8_t h[MD5_CHAINING_LENGTH], + uint64_t n) { + if (n % ((uint64_t)MD5_CBLOCK * 8) != 0) { + // n is not a multiple of the block size in bits, so it fails + return 0; + } + + OPENSSL_memset(md5, 0, sizeof(MD5_CTX)); + + const size_t out_words = MD5_CHAINING_LENGTH / 4; + for (size_t i = 0; i < out_words; i++) { + md5->h[i] = CRYPTO_load_u32_be(h); + h += 4; + } + + md5->Nh = n >> 32; + md5->Nl = n & 0xffffffff; + + return 1; +} + #if defined(MD5_ASM) #define md5_block_data_order md5_block_asm_data_order #else @@ -111,6 +132,24 @@ int MD5_Final(uint8_t out[MD5_DIGEST_LENGTH], MD5_CTX *c) { return 1; } +int MD5_get_state(MD5_CTX *ctx, uint8_t out_h[MD5_CHAINING_LENGTH], + uint64_t *out_n) { + if (ctx->Nl % ((uint64_t)MD5_CBLOCK * 8) != 0) { + // ctx->Nl is not a multiple of the block size in bits, so it fails + return 0; + } + + const size_t out_words = MD5_CHAINING_LENGTH / 4; + for (size_t i = 0; i < out_words; i++) { + CRYPTO_store_u32_be(out_h, ctx->h[i]); + out_h += 4; + } + + *out_n = (((uint64_t)ctx->Nh) << 32) + ctx->Nl; + + return 1; +} + // As pointed out by Wei Dai , the above can be // simplified to the code below. Wei attributes these optimizations // to Peter Gutmann's SHS code, and he attributes it to Rich Schroeppel. diff --git a/crypto/fipsmodule/sha/internal.h b/crypto/fipsmodule/sha/internal.h index 9eafceb53a..62557a0ddf 100644 --- a/crypto/fipsmodule/sha/internal.h +++ b/crypto/fipsmodule/sha/internal.h @@ -21,6 +21,10 @@ extern "C" { // Internal SHA2 constants +// SHA1_CHAINING_LENGTH is the chaining length in bytes of SHA-1 +// It corresponds to the length in bytes of the h part of the state +#define SHA1_CHAINING_LENGTH 20 + // SHA224_CHAINING_LENGTH is the chaining length in bytes of SHA-224 // It corresponds to the length in bytes of the h part of the state #define SHA224_CHAINING_LENGTH 32 @@ -29,6 +33,22 @@ extern "C" { // It corresponds to the length in bytes of the h part of the state #define SHA256_CHAINING_LENGTH 32 +// SHA384_CHAINING_LENGTH is the chaining length in bytes of SHA-384 +// It corresponds to the length in bytes of the h part of the state +#define SHA384_CHAINING_LENGTH 64 + +// SHA512_CHAINING_LENGTH is the chaining length in bytes of SHA-512 +// It corresponds to the length in bytes of the h part of the state +#define SHA512_CHAINING_LENGTH 64 + +// SHA512_224_CHAINING_LENGTH is the chaining length in bytes of SHA-512-224 +// It corresponds to the length in bytes of the h part of the state +#define SHA512_224_CHAINING_LENGTH 64 + +// SHA512_256_CHAINING_LENGTH is the chaining length in bytes of SHA-512-256 +// It corresponds to the length in bytes of the h part of the state +#define SHA512_256_CHAINING_LENGTH 64 + // SHA3 constants, from NIST FIPS202. // https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf @@ -103,6 +123,47 @@ void sha512_block_data_order(uint64_t *state, const uint8_t *in, #define KECCAK1600_ASM #endif +// SHA1_Init_from_state is a low-level function that initializes |sha| with a +// custom state. |h| is the hash state in big endian. |n| is the number of bits +// processed at this point. It must be a multiple of |SHA256_CBLOCK*8|. +// It returns one on success and zero on programmer error. +// This function is for internal use only and should never be directly called. +OPENSSL_EXPORT int SHA1_Init_from_state(SHA_CTX *sha, + const uint8_t h[SHA1_CHAINING_LENGTH], + uint64_t n); + +// SHA1_get_state is a low-level function that exports the hash state in big +// endian into |out_n| and the number of bits processed at this point in +// |out_n|. SHA1_Final must not have been called before (otherwise results +// are not guaranteed). Furthermore, the number of bytes processed by +// SHA1_Update must be a multiple of the block length |SHA1_CBLOCK| +// (otherwise it fails). It returns one on success and zero on programmer +// error. +// This function is for internal use only and should never be directly called. +OPENSSL_EXPORT int SHA1_get_state(SHA_CTX *ctx, + uint8_t out_h[SHA1_CHAINING_LENGTH], + uint64_t *out_n); + +// SHA224_Init_from_state is a low-level function that initializes |sha| with a +// custom state. |h| is the hash state in big endian. |n| is the number of bits +// processed at this point. It must be a multiple of |SHA256_CBLOCK*8|. +// It returns one on success and zero on programmer error. +// This function is for internal use only and should never be directly called. +OPENSSL_EXPORT int SHA224_Init_from_state( + SHA256_CTX *sha, const uint8_t h[SHA224_CHAINING_LENGTH], uint64_t n); + +// SHA224_get_state is a low-level function that exports the hash state in big +// endian into |out_n| and the number of bits processed at this point in +// |out_n|. SHA224_Final must not have been called before (otherwise results +// are not guaranteed). Furthermore, the number of bytes processed by +// SHA224_Update must be a multiple of the block length |SHA224_CBLOCK| +// (otherwise it fails). It returns one on success and zero on programmer +// error. +// This function is for internal use only and should never be directly called. +OPENSSL_EXPORT int SHA224_get_state(SHA256_CTX *ctx, + uint8_t out_h[SHA224_CHAINING_LENGTH], + uint64_t *out_n); + // SHA256_Init_from_state is a low-level function that initializes |sha| with a // custom state. |h| is the hash state in big endian. |n| is the number of bits // processed at this point. It must be a multiple of |SHA256_CBLOCK*8|. @@ -123,6 +184,86 @@ OPENSSL_EXPORT int SHA256_get_state(SHA256_CTX *ctx, uint8_t out_h[SHA256_CHAINING_LENGTH], uint64_t *out_n); +// SHA384_Init_from_state is a low-level function that initializes |sha| with a +// custom state. |h| is the hash state in big endian. |n| is the number of bits +// processed at this point. It must be a multiple of |SHA512_CBLOCK*8|. +// It returns one on success and zero on programmer error. +// This function is for internal use only and should never be directly called. +OPENSSL_EXPORT int SHA384_Init_from_state( + SHA512_CTX *sha, const uint8_t h[SHA384_CHAINING_LENGTH], uint64_t n); + +// SHA384_get_state is a low-level function that exports the hash state in big +// endian into |out_n| and the number of bits processed at this point in +// |out_n|. SHA384_Final must not have been called before (otherwise results +// are not guaranteed). Furthermore, the number of bytes processed by +// SHA384_Update must be a multiple of the block length |SHA384_CBLOCK| +// (otherwise it fails). It returns one on success and zero on programmer +// error. +// This function is for internal use only and should never be directly called. +OPENSSL_EXPORT int SHA384_get_state(SHA512_CTX *ctx, + uint8_t out_h[SHA384_CHAINING_LENGTH], + uint64_t *out_n); + +// SHA512_Init_from_state is a low-level function that initializes |sha| with a +// custom state. |h| is the hash state in big endian. |n| is the number of bits +// processed at this point. It must be a multiple of |SHA512_CBLOCK*8|. +// It returns one on success and zero on programmer error. +// This function is for internal use only and should never be directly called. +OPENSSL_EXPORT int SHA512_Init_from_state( + SHA512_CTX *sha, const uint8_t h[SHA512_CHAINING_LENGTH], uint64_t n); + +// SHA512_get_state is a low-level function that exports the hash state in big +// endian into |out_n| and the number of bits processed at this point in +// |out_n|. SHA512_Final must not have been called before (otherwise results +// are not guaranteed). Furthermore, the number of bytes processed by +// SHA512_Update must be a multiple of the block length |SHA512_CBLOCK| +// (otherwise it fails). It returns one on success and zero on programmer +// error. +// This function is for internal use only and should never be directly called. +OPENSSL_EXPORT int SHA512_get_state(SHA512_CTX *ctx, + uint8_t out_h[SHA512_CHAINING_LENGTH], + uint64_t *out_n); + +// SHA512_224_Init_from_state is a low-level function that initializes |sha| +// with a custom state. |h| is the hash state in big endian. |n| is the number +// of bits processed at this point. It must be a multiple of |SHA512_CBLOCK*8|. +// It returns one on success and zero on programmer error. +// This function is for internal use only and should never be directly called. +OPENSSL_EXPORT int SHA512_224_Init_from_state( + SHA512_CTX *sha, const uint8_t h[SHA512_224_CHAINING_LENGTH], uint64_t n); + +// SHA512_224_get_state is a low-level function that exports the hash state in +// big endian into |out_n| and the number of bits processed at this point in +// |out_n|. SHA512_224_Final must not have been called before (otherwise results +// are not guaranteed). Furthermore, the number of bytes processed by +// SHA512_224_Update must be a multiple of the block length |SHA512_CBLOCK| +// (otherwise it fails). It returns one on success and zero on programmer +// error. +// This function is for internal use only and should never be directly called. +OPENSSL_EXPORT int SHA512_224_get_state( + SHA512_CTX *ctx, uint8_t out_h[SHA512_224_CHAINING_LENGTH], + uint64_t *out_n); + +// SHA512_256_Init_from_state is a low-level function that initializes |sha| +// with a custom state. |h| is the hash state in big endian. |n| is the number +// of bits processed at this point. It must be a multiple of |SHA512_CBLOCK*8|. +// It returns one on success and zero on programmer error. +// This function is for internal use only and should never be directly called. +OPENSSL_EXPORT int SHA512_256_Init_from_state( + SHA512_CTX *sha, const uint8_t h[SHA512_256_CHAINING_LENGTH], uint64_t n); + +// SHA512_256_get_state is a low-level function that exports the hash state in +// big endian into |out_n| and the number of bits processed at this point in +// |out_n|. SHA512_256_Final must not have been called before (otherwise results +// are not guaranteed). Furthermore, the number of bytes processed by +// SHA512_256_Update must be a multiple of the block length |SHA512_CBLOCK| +// (otherwise it fails). It returns one on success and zero on programmer +// error. +// This function is for internal use only and should never be directly called. +OPENSSL_EXPORT int SHA512_256_get_state( + SHA512_CTX *ctx, uint8_t out_h[SHA512_256_CHAINING_LENGTH], + uint64_t *out_n); + // SHA3_224 writes the digest of |len| bytes from |data| to |out| and returns |out|. // There must be at least |SHA3_224_DIGEST_LENGTH| bytes of space in |out|. // On failure |SHA3_224| returns NULL. diff --git a/crypto/fipsmodule/sha/sha1.c b/crypto/fipsmodule/sha/sha1.c index fc426fbe83..5459e23427 100644 --- a/crypto/fipsmodule/sha/sha1.c +++ b/crypto/fipsmodule/sha/sha1.c @@ -75,6 +75,27 @@ int SHA1_Init(SHA_CTX *sha) { return 1; } +int SHA1_Init_from_state(SHA_CTX *sha, const uint8_t h[SHA1_CHAINING_LENGTH], + uint64_t n) { + if (n % ((uint64_t)SHA_CBLOCK * 8) != 0) { + // n is not a multiple of the block size in bits, so it fails + return 0; + } + + OPENSSL_memset(sha, 0, sizeof(SHA_CTX)); + + const size_t out_words = SHA1_CHAINING_LENGTH / 4; + for (size_t i = 0; i < out_words; i++) { + sha->h[i] = CRYPTO_load_u32_be(h); + h += 4; + } + + sha->Nh = n >> 32; + sha->Nl = n & 0xffffffff; + + return 1; +} + uint8_t *SHA1(const uint8_t *data, size_t len, uint8_t out[SHA_DIGEST_LENGTH]) { // We have to verify that all the SHA services actually succeed before // updating the indicator state, so we lock the state here. @@ -119,6 +140,24 @@ int SHA1_Final(uint8_t out[SHA_DIGEST_LENGTH], SHA_CTX *c) { return 1; } +int SHA1_get_state(SHA_CTX *ctx, uint8_t out_h[SHA1_CHAINING_LENGTH], + uint64_t *out_n) { + if (ctx->Nl % ((uint64_t)SHA_CBLOCK * 8) != 0) { + // ctx->Nl is not a multiple of the block size in bits, so it fails + return 0; + } + + const size_t out_words = SHA1_CHAINING_LENGTH / 4; + for (size_t i = 0; i < out_words; i++) { + CRYPTO_store_u32_be(out_h, ctx->h[i]); + out_h += 4; + } + + *out_n = (((uint64_t)ctx->Nh) << 32) + ctx->Nl; + + return 1; +} + #define Xupdate(a, ix, ia, ib, ic, id) \ do { \ (a) = ((ia) ^ (ib) ^ (ic) ^ (id)); \ diff --git a/crypto/fipsmodule/sha/sha256.c b/crypto/fipsmodule/sha/sha256.c index 57508cdf4e..1b97987af9 100644 --- a/crypto/fipsmodule/sha/sha256.c +++ b/crypto/fipsmodule/sha/sha256.c @@ -122,6 +122,12 @@ static int sha256_init_from_state_impl(SHA256_CTX *sha, int md_len, return 1; } +int SHA224_Init_from_state(SHA256_CTX *sha, + const uint8_t h[SHA224_CHAINING_LENGTH], + uint64_t n) { + return sha256_init_from_state_impl(sha, SHA224_DIGEST_LENGTH, h, n); +} + int SHA256_Init_from_state(SHA256_CTX *sha, const uint8_t h[SHA256_CHAINING_LENGTH], uint64_t n) { @@ -228,6 +234,11 @@ static int sha256_get_state_impl(SHA256_CTX *ctx, return 1; } +int SHA224_get_state(SHA256_CTX *ctx, uint8_t out_h[SHA224_CHAINING_LENGTH], + uint64_t *out_n) { + return sha256_get_state_impl(ctx, out_h, out_n); +} + int SHA256_get_state(SHA256_CTX *ctx, uint8_t out_h[SHA256_CHAINING_LENGTH], uint64_t *out_n) { return sha256_get_state_impl(ctx, out_h, out_n); diff --git a/crypto/fipsmodule/sha/sha512.c b/crypto/fipsmodule/sha/sha512.c index 1eb95e1a7f..ba9146fa90 100644 --- a/crypto/fipsmodule/sha/sha512.c +++ b/crypto/fipsmodule/sha/sha512.c @@ -141,6 +141,63 @@ int SHA512_256_Init(SHA512_CTX *sha) { return 1; } +OPENSSL_STATIC_ASSERT(SHA512_CHAINING_LENGTH==SHA384_CHAINING_LENGTH, + sha512_and_sha384_have_same_chaining_length) +OPENSSL_STATIC_ASSERT(SHA512_CHAINING_LENGTH==SHA512_224_CHAINING_LENGTH, + sha512_and_sha512_224_have_same_chaining_length) +OPENSSL_STATIC_ASSERT(SHA512_CHAINING_LENGTH==SHA512_256_CHAINING_LENGTH, + sha512_and_sha512_256_have_same_chaining_length) + +// sha512_init_from_state_impl is the implementation of +// SHA512_Init_from_state and SHA224_Init_from_state +// Note that the state h is always SHA512_CHAINING_LENGTH-byte long +static int sha512_init_from_state_impl(SHA512_CTX *sha, int md_len, + const uint8_t h[SHA512_CHAINING_LENGTH], + uint64_t n) { + if(n % ((uint64_t) SHA512_CBLOCK * 8) != 0) { + // n is not a multiple of the block size in bits, so it fails + return 0; + } + + OPENSSL_memset(sha, 0, sizeof(SHA512_CTX)); + sha->md_len = md_len; + + const size_t out_words = SHA512_CHAINING_LENGTH / 8; + for (size_t i = 0; i < out_words; i++) { + sha->h[i] = CRYPTO_load_u64_be(h); + h += 8; + } + + sha->Nh = n >> 32; + sha->Nl = n & 0xffffffff; + + return 1; +} + +int SHA384_Init_from_state(SHA512_CTX *sha, + const uint8_t h[SHA384_CHAINING_LENGTH], + uint64_t n) { + return sha512_init_from_state_impl(sha, SHA384_DIGEST_LENGTH, h, n); +} + +int SHA512_Init_from_state(SHA512_CTX *sha, + const uint8_t h[SHA512_CHAINING_LENGTH], + uint64_t n) { + return sha512_init_from_state_impl(sha, SHA512_DIGEST_LENGTH, h, n); +} + +int SHA512_224_Init_from_state(SHA512_CTX *sha, + const uint8_t h[SHA512_224_CHAINING_LENGTH], + uint64_t n) { + return sha512_init_from_state_impl(sha, SHA512_224_DIGEST_LENGTH, h, n); +} + +int SHA512_256_Init_from_state(SHA512_CTX *sha, + const uint8_t h[SHA512_256_CHAINING_LENGTH], + uint64_t n) { + return sha512_init_from_state_impl(sha, SHA512_256_DIGEST_LENGTH, h, n); +} + uint8_t *SHA384(const uint8_t *data, size_t len, uint8_t out[SHA384_DIGEST_LENGTH]) { // We have to verify that all the SHA services actually succeed before @@ -353,6 +410,48 @@ static int sha512_final_impl(uint8_t *out, size_t md_len, SHA512_CTX *sha) { return 1; } +// sha512_get_state_impl is the implementation of +// SHA512_get_state and SHA224_get_state +// Note that the state out_h is always SHA512_CHAINING_LENGTH-byte long +static int sha512_get_state_impl(SHA512_CTX *ctx, + uint8_t out_h[SHA512_CHAINING_LENGTH], + uint64_t *out_n) { + if (ctx->Nl % ((uint64_t)SHA512_CBLOCK * 8) != 0) { + // ctx->Nl is not a multiple of the block size in bits, so it fails + return 0; + } + + const size_t out_words = SHA512_CHAINING_LENGTH / 8; + for (size_t i = 0; i < out_words; i++) { + CRYPTO_store_u64_be(out_h, ctx->h[i]); + out_h += 8; + } + + *out_n = (((uint64_t)ctx->Nh) << 32) + ctx->Nl; + + return 1; +} + +int SHA384_get_state(SHA512_CTX *ctx, uint8_t out_h[SHA384_CHAINING_LENGTH], + uint64_t *out_n) { + return sha512_get_state_impl(ctx, out_h, out_n); +} + +int SHA512_get_state(SHA512_CTX *ctx, uint8_t out_h[SHA512_CHAINING_LENGTH], + uint64_t *out_n) { + return sha512_get_state_impl(ctx, out_h, out_n); +} + +int SHA512_224_get_state(SHA512_CTX *ctx, uint8_t out_h[SHA512_224_CHAINING_LENGTH], + uint64_t *out_n) { + return sha512_get_state_impl(ctx, out_h, out_n); +} + +int SHA512_256_get_state(SHA512_CTX *ctx, uint8_t out_h[SHA512_256_CHAINING_LENGTH], + uint64_t *out_n) { + return sha512_get_state_impl(ctx, out_h, out_n); +} + #ifndef SHA512_ASM static const uint64_t K512[80] = { UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd), diff --git a/crypto/hmac_extra/hmac_tests.txt b/crypto/hmac_extra/hmac_tests.txt index 12164b1fea..43c7a41002 100644 --- a/crypto/hmac_extra/hmac_tests.txt +++ b/crypto/hmac_extra/hmac_tests.txt @@ -1,3 +1,60 @@ +HMAC = MD5 +# Note: The empty key results in passing NULL to HMAC_Init_ex, so this tests +# that HMAC_CTX and HMAC treat NULL as the empty key initially. +Key = +Input = "More text test vectors to stuff up EBCDIC machines :-)" +Output = e9139d1e6ee064ef8cf514fc7dc83e86 + +# HMAC tests from RFC 2104 +HMAC = MD5 +Key = 0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b +Input = "Hi There" +Output = 9294727a3638bb1c13f48ef8158bfc9d + +HMAC = MD5 +Key = "Jefe" +Input = "what do ya want for nothing?" +Output = 750c783e6ab0b503eaa86e310a5db738 + +HMAC = MD5 +Key = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +Input = DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD +Output = 56be34521d144c88dbb8c733f0e8b3f6 + +# HMAC tests from NIST test data + +HMAC = SHA1 +Input = "Sample message for keylen=blocklen" +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F +Output = 5FD596EE78D5553C8FF4E72D266DFD192366DA29 + +HMAC = SHA1 +Input = "Sample message for keylenblocklen, but the NIST test vectors have a misleading input. +HMAC = SHA1 +Input = "Sample message for keylen=blocklen" +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60616263 +Output = 2D51B2F7750E410584662E38F133435F4C4FD42A + +HMAC = SHA224 +Input = "Sample message for keylen=blocklen" +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F +Output = C7405E3AE058E8CD30B08B4140248581ED174CB34E1224BCC1EFC81B + +HMAC = SHA224 +Input = "Sample message for keylenblocklen, but the NIST test vectors have a misleading input. +HMAC = SHA224 +Input = "Sample message for keylen=blocklen" +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60616263 +Output = 91C52509E5AF8531601AE6230099D90BEF88AAEFB961F4080ABC014D + HMAC = SHA256 Input = "Sample message for keylen=blocklen" Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F @@ -14,6 +71,44 @@ Input = "Sample message for keylen=blocklen" Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60616263 Output = BDCCB6C72DDEADB500AE768386CB38CC41C63DBB0878DDB9C7A38A431B78378D +HMAC = SHA384 +Input = "Sample message for keylen=blocklen" +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F +Output = 63C5DAA5E651847CA897C95814AB830BEDEDC7D25E83EEF9195CD45857A37F448947858F5AF50CC2B1B730DDF29671A9 + +HMAC = SHA384 +Input = "Sample message for keylenblocklen, but the NIST test vectors have a misleading input. +HMAC = SHA384 +Input = "Sample message for keylen=blocklen" +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7 +Output = 5B664436DF69B0CA22551231A3F0A3D5B4F97991713CFA84BFF4D0792EFF96C27DCCBBB6F79B65D548B40E8564CEF594 + +HMAC = SHA512 +Input = "Sample message for keylen=blocklen" +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F +Output = FC25E240658CA785B7A811A8D3F7B4CA48CFA26A8A366BF2CD1F836B05FCB024BD36853081811D6CEA4216EBAD79DA1CFCB95EA4586B8A0CE356596A55FB1347 + +HMAC = SHA512 +Input = "Sample message for keylenblocklen, but the NIST test vectors have a misleading input. +HMAC = SHA512 +Input = "Sample message for keylen=blocklen" +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7 +Output = D93EC8D2DE1AD2A9957CB9B83F14E76AD6B5E0CCE285079A127D3B14BCCB7AA7286D4AC0D4CE64215F2BC9E6870B33D97438BE4AAA20CDA5C5A912B48B8E27F3 + +# Additional HMAC tests from OpenSSL. +HMAC = SHA1 +Input = "My test data" +Key = +Output = 61afdecb95429ef494d61fdee15990cabf0826fc + HMAC = SHA256 Input = "My test data" Key = @@ -22,4 +117,29 @@ Output = 2274b195d90ce8e03406f4b526a47e0787a88a65479938f1a5baa3ce0f079776 HMAC = SHA256 Input = "My test data" Key = "123456" -Output = bab53058ae861a7f191abe2d0145cbb123776a6369ee3f9d79ce455667e411dd \ No newline at end of file +Output = bab53058ae861a7f191abe2d0145cbb123776a6369ee3f9d79ce455667e411dd + +HMAC = SHA1 +Input = "My test data" +Key = "12345" +Output = 7dbe8c764c068e3bcd6e6b0fbcd5e6fc197b15bb + +HMAC = SHA512/224 +Input = "My test data" +Key = +Output = fc993d20088ed6028478b8356aa818b82c6131f04292f97d86e77620 + +HMAC = SHA512/224 +Input = "My test data" +Key = "123456" +Output = 49d08109c1766ce6386d7b8bdaf5d014667083677096b82f56a73531 + +HMAC = SHA512/256 +Input = "My test data" +Key = +Output = 297753ca6b09b11dcfa97a0e9dcdc8c2c3eaac85a2c4bebe395b4630bd436aac + +HMAC = SHA512/256 +Input = "My test data" +Key = "123456" +Output = 2ed564c398a4fab30a1c4e071fd0f5b3c8a548d2e75ec3237ca5334071a63f40 diff --git a/crypto/hmac_extra/hmac_tests_full.txt b/crypto/hmac_extra/hmac_tests_full.txt deleted file mode 100644 index 43c7a41002..0000000000 --- a/crypto/hmac_extra/hmac_tests_full.txt +++ /dev/null @@ -1,145 +0,0 @@ -HMAC = MD5 -# Note: The empty key results in passing NULL to HMAC_Init_ex, so this tests -# that HMAC_CTX and HMAC treat NULL as the empty key initially. -Key = -Input = "More text test vectors to stuff up EBCDIC machines :-)" -Output = e9139d1e6ee064ef8cf514fc7dc83e86 - -# HMAC tests from RFC 2104 -HMAC = MD5 -Key = 0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b -Input = "Hi There" -Output = 9294727a3638bb1c13f48ef8158bfc9d - -HMAC = MD5 -Key = "Jefe" -Input = "what do ya want for nothing?" -Output = 750c783e6ab0b503eaa86e310a5db738 - -HMAC = MD5 -Key = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -Input = DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD -Output = 56be34521d144c88dbb8c733f0e8b3f6 - -# HMAC tests from NIST test data - -HMAC = SHA1 -Input = "Sample message for keylen=blocklen" -Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F -Output = 5FD596EE78D5553C8FF4E72D266DFD192366DA29 - -HMAC = SHA1 -Input = "Sample message for keylenblocklen, but the NIST test vectors have a misleading input. -HMAC = SHA1 -Input = "Sample message for keylen=blocklen" -Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60616263 -Output = 2D51B2F7750E410584662E38F133435F4C4FD42A - -HMAC = SHA224 -Input = "Sample message for keylen=blocklen" -Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F -Output = C7405E3AE058E8CD30B08B4140248581ED174CB34E1224BCC1EFC81B - -HMAC = SHA224 -Input = "Sample message for keylenblocklen, but the NIST test vectors have a misleading input. -HMAC = SHA224 -Input = "Sample message for keylen=blocklen" -Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60616263 -Output = 91C52509E5AF8531601AE6230099D90BEF88AAEFB961F4080ABC014D - -HMAC = SHA256 -Input = "Sample message for keylen=blocklen" -Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F -Output = 8BB9A1DB9806F20DF7F77B82138C7914D174D59E13DC4D0169C9057B133E1D62 - -HMAC = SHA256 -Input = "Sample message for keylenblocklen, but the NIST test vectors have a misleading input. -HMAC = SHA256 -Input = "Sample message for keylen=blocklen" -Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60616263 -Output = BDCCB6C72DDEADB500AE768386CB38CC41C63DBB0878DDB9C7A38A431B78378D - -HMAC = SHA384 -Input = "Sample message for keylen=blocklen" -Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F -Output = 63C5DAA5E651847CA897C95814AB830BEDEDC7D25E83EEF9195CD45857A37F448947858F5AF50CC2B1B730DDF29671A9 - -HMAC = SHA384 -Input = "Sample message for keylenblocklen, but the NIST test vectors have a misleading input. -HMAC = SHA384 -Input = "Sample message for keylen=blocklen" -Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7 -Output = 5B664436DF69B0CA22551231A3F0A3D5B4F97991713CFA84BFF4D0792EFF96C27DCCBBB6F79B65D548B40E8564CEF594 - -HMAC = SHA512 -Input = "Sample message for keylen=blocklen" -Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F -Output = FC25E240658CA785B7A811A8D3F7B4CA48CFA26A8A366BF2CD1F836B05FCB024BD36853081811D6CEA4216EBAD79DA1CFCB95EA4586B8A0CE356596A55FB1347 - -HMAC = SHA512 -Input = "Sample message for keylenblocklen, but the NIST test vectors have a misleading input. -HMAC = SHA512 -Input = "Sample message for keylen=blocklen" -Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7 -Output = D93EC8D2DE1AD2A9957CB9B83F14E76AD6B5E0CCE285079A127D3B14BCCB7AA7286D4AC0D4CE64215F2BC9E6870B33D97438BE4AAA20CDA5C5A912B48B8E27F3 - -# Additional HMAC tests from OpenSSL. -HMAC = SHA1 -Input = "My test data" -Key = -Output = 61afdecb95429ef494d61fdee15990cabf0826fc - -HMAC = SHA256 -Input = "My test data" -Key = -Output = 2274b195d90ce8e03406f4b526a47e0787a88a65479938f1a5baa3ce0f079776 - -HMAC = SHA256 -Input = "My test data" -Key = "123456" -Output = bab53058ae861a7f191abe2d0145cbb123776a6369ee3f9d79ce455667e411dd - -HMAC = SHA1 -Input = "My test data" -Key = "12345" -Output = 7dbe8c764c068e3bcd6e6b0fbcd5e6fc197b15bb - -HMAC = SHA512/224 -Input = "My test data" -Key = -Output = fc993d20088ed6028478b8356aa818b82c6131f04292f97d86e77620 - -HMAC = SHA512/224 -Input = "My test data" -Key = "123456" -Output = 49d08109c1766ce6386d7b8bdaf5d014667083677096b82f56a73531 - -HMAC = SHA512/256 -Input = "My test data" -Key = -Output = 297753ca6b09b11dcfa97a0e9dcdc8c2c3eaac85a2c4bebe395b4630bd436aac - -HMAC = SHA512/256 -Input = "My test data" -Key = "123456" -Output = 2ed564c398a4fab30a1c4e071fd0f5b3c8a548d2e75ec3237ca5334071a63f40 From 35b4f90c6f91c5f171180de7dee92da5a55c821e Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Wed, 19 Jun 2024 19:27:40 -0400 Subject: [PATCH 14/26] Fix warnings when assert disabled in release mode --- crypto/fipsmodule/hmac/hmac.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crypto/fipsmodule/hmac/hmac.c b/crypto/fipsmodule/hmac/hmac.c index eab17aefa3..9eedace75f 100644 --- a/crypto/fipsmodule/hmac/hmac.c +++ b/crypto/fipsmodule/hmac/hmac.c @@ -527,11 +527,13 @@ int HMAC_get_precomputed_key(HMAC_CTX *ctx, uint8_t *out, size_t *out_len) { // We should never arrive here as in our setting, get_state should always be // successful since i_ctx/o_ctx have processed exactly one block assert(ok); + (void)ok; // avoid unused variable warning when asserts disabled // Sanity check: we must have processed a single block at this time size_t block_size = EVP_MD_block_size(ctx->md); assert(8 * block_size == i_ctx_n); assert(8 * block_size == o_ctx_n); + (void)block_size; // avoid unused variable warning when asserts disabled // The context is ready to be used to compute HMAC values at this point. ctx->state = HMAC_STATE_INIT_NO_DATA; From 31a27df5dddc61c7136d393af14444894a75565d Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Wed, 19 Jun 2024 19:32:05 -0400 Subject: [PATCH 15/26] Improving comment --- crypto/fipsmodule/hmac/hmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/fipsmodule/hmac/hmac.c b/crypto/fipsmodule/hmac/hmac.c index 9eedace75f..e3fd533fb0 100644 --- a/crypto/fipsmodule/hmac/hmac.c +++ b/crypto/fipsmodule/hmac/hmac.c @@ -524,7 +524,7 @@ int HMAC_get_precomputed_key(HMAC_CTX *ctx, uint8_t *out, size_t *out_len) { const int ok = ctx->methods->get_state(&ctx->i_ctx, out, &i_ctx_n) && ctx->methods->get_state(&ctx->o_ctx, out + chaining_length, &o_ctx_n); - // We should never arrive here as in our setting, get_state should always be + // ok should always be true as in our setting: get_state should always be // successful since i_ctx/o_ctx have processed exactly one block assert(ok); (void)ok; // avoid unused variable warning when asserts disabled From e867e8f712a59c408f49cd04ec2392bd7bacf192 Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Thu, 20 Jun 2024 10:32:31 -0400 Subject: [PATCH 16/26] Fix bug in HMAC_with_precompute Recent changes require `out_len` to be set to the available number of bytes of `out` when calling `HMAC_get_precomputed_key`. --- crypto/fipsmodule/hmac/hmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/fipsmodule/hmac/hmac.c b/crypto/fipsmodule/hmac/hmac.c index e3fd533fb0..9bbb35e321 100644 --- a/crypto/fipsmodule/hmac/hmac.c +++ b/crypto/fipsmodule/hmac/hmac.c @@ -255,7 +255,7 @@ uint8_t *HMAC_with_precompute(const EVP_MD *evp_md, const void *key, FIPS_service_indicator_lock_state(); uint8_t precomputed_key[HMAC_MAX_PRECOMPUTED_KEY_SIZE]; - size_t precomputed_key_len; + size_t precomputed_key_len = HMAC_MAX_PRECOMPUTED_KEY_SIZE; result = HMAC_Init_ex(&ctx, key, key_len, evp_md, NULL) && From 57aec5b18a72a6606434ad25132e8a83375d4f4f Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Thu, 20 Jun 2024 10:50:38 -0400 Subject: [PATCH 17/26] Add service indicator tests for HMAC with precomputed keys --- .../service_indicator_test.cc | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/crypto/fipsmodule/service_indicator/service_indicator_test.cc b/crypto/fipsmodule/service_indicator/service_indicator_test.cc index 229617c77a..7523e7b7df 100644 --- a/crypto/fipsmodule/service_indicator/service_indicator_test.cc +++ b/crypto/fipsmodule/service_indicator/service_indicator_test.cc @@ -1338,6 +1338,37 @@ TEST_P(HMACServiceIndicatorTest, HMACTest) { EXPECT_EQ(approved, test.expect_approved); EXPECT_EQ(Bytes(test.expected_digest, expected_mac_len), Bytes(mac.data(), mac_len)); + + // Test using precomputed keys + // First, extract the precomputed key + ctx.Reset(); + uint8_t precomputed_key[HMAC_MAX_PRECOMPUTED_KEY_SIZE]; + size_t precomputed_key_len = HMAC_MAX_PRECOMPUTED_KEY_SIZE; + CALL_SERVICE_AND_CHECK_APPROVED( + approved, ASSERT_TRUE( + HMAC_Init_ex(ctx.get(), kHMACKey, sizeof(kHMACKey), digest, nullptr))); + EXPECT_EQ(approved, AWSLC_NOT_APPROVED); + CALL_SERVICE_AND_CHECK_APPROVED( + approved, ASSERT_TRUE(HMAC_set_precomputed_key_export(ctx.get()))); + EXPECT_EQ(approved, AWSLC_NOT_APPROVED); + CALL_SERVICE_AND_CHECK_APPROVED( + approved, ASSERT_TRUE(HMAC_get_precomputed_key( + ctx.get(), precomputed_key, &precomputed_key_len))); + EXPECT_EQ(approved, AWSLC_NOT_APPROVED); + // Second, use the precomputed key to compute the hash + ctx.Reset(); + CALL_SERVICE_AND_CHECK_APPROVED( + approved, ASSERT_TRUE(HMAC_Init_from_precomputed_key( + ctx.get(), precomputed_key, precomputed_key_len, digest))); + EXPECT_EQ(approved, AWSLC_NOT_APPROVED); + CALL_SERVICE_AND_CHECK_APPROVED(approved, + ASSERT_TRUE(HMAC_Update(ctx.get(), kPlaintext, sizeof(kPlaintext)))); + EXPECT_EQ(approved, AWSLC_NOT_APPROVED); + CALL_SERVICE_AND_CHECK_APPROVED(approved, + ASSERT_TRUE(HMAC_Final(ctx.get(), mac.data(), &mac_len))); + EXPECT_EQ(approved, test.expect_approved); + EXPECT_EQ(Bytes(test.expected_digest, expected_mac_len), + Bytes(mac.data(), mac_len)); } const uint8_t kHKDF_ikm_tc1[] = { // RFC 5869 Test Case 1 From e16bd402642ca065b4042e3b3090baa8d752063d Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Fri, 5 Jul 2024 17:23:09 -0400 Subject: [PATCH 18/26] Fix SHA-512 Init_with_stae/get_state + comment improvements Fix SHA-512 Init_with_stae/get_state handling of Nh/Nl: Nh/Nl are uint64_t for SHA-512 instead of uint32_t everywhere else. Improvements of some comments --- crypto/digest_extra/digest_test.cc | 2 +- crypto/fipsmodule/md5/internal.h | 9 ++-- crypto/fipsmodule/sha/internal.h | 87 ++++++++++++------------------ crypto/fipsmodule/sha/sha512.c | 12 +++-- 4 files changed, 47 insertions(+), 63 deletions(-) diff --git a/crypto/digest_extra/digest_test.cc b/crypto/digest_extra/digest_test.cc index 7bd33b00d5..e113b1f94f 100644 --- a/crypto/digest_extra/digest_test.cc +++ b/crypto/digest_extra/digest_test.cc @@ -480,7 +480,7 @@ TEST(DigestTest, TransformBlocks) { // DIGEST_TEST_InitAndGetState_Body expands to the body of the various // InitAndGetState* tests below. -// Because EXPECT_* do not output the proper line when used in a macro, +// Because EXPECT_* outputs the line where the macro is called/expanded, // we need to add diagnostic information `<< ...` after each EXPECT_* #define DIGEST_TEST_InitAndGetState_Body(HASH_NAME, HASH_CTX, HASH_CBLOCK) \ { \ diff --git a/crypto/fipsmodule/md5/internal.h b/crypto/fipsmodule/md5/internal.h index 92f7e6fb84..e50b5582b8 100644 --- a/crypto/fipsmodule/md5/internal.h +++ b/crypto/fipsmodule/md5/internal.h @@ -28,7 +28,7 @@ extern "C" { // MD5_Init_from_state is a low-level function that initializes |sha| with a // custom state. |h| is the hash state in big endian. |n| is the number of bits // processed at this point. It must be a multiple of |MD5_CBLOCK*8|. -// It returns one on success and zero on programmer error. +// It returns one on success and zero on error. // This function is for internal use only and should never be directly called. OPENSSL_EXPORT int MD5_Init_from_state(MD5_CTX *sha, const uint8_t h[MD5_CHAINING_LENGTH], @@ -36,11 +36,10 @@ OPENSSL_EXPORT int MD5_Init_from_state(MD5_CTX *sha, // MD5_get_state is a low-level function that exports the hash state in big // endian into |out_n| and the number of bits processed at this point in -// |out_n|. MD5_Final must not have been called before (otherwise results +// |out_n|. |MD5_Final| must not have been called before (otherwise results // are not guaranteed). Furthermore, the number of bytes processed by -// MD5_Update must be a multiple of the block length |MD5_CBLOCK| -// (otherwise it fails). It returns one on success and zero on programmer -// error. +// |MD5_Update| must be a multiple of the block length |MD5_CBLOCK| +// (otherwise it fails). It returns one on success and zero on error. // This function is for internal use only and should never be directly called. OPENSSL_EXPORT int MD5_get_state(MD5_CTX *ctx, uint8_t out_h[MD5_CHAINING_LENGTH], diff --git a/crypto/fipsmodule/sha/internal.h b/crypto/fipsmodule/sha/internal.h index 62557a0ddf..1172296ff5 100644 --- a/crypto/fipsmodule/sha/internal.h +++ b/crypto/fipsmodule/sha/internal.h @@ -21,32 +21,14 @@ extern "C" { // Internal SHA2 constants -// SHA1_CHAINING_LENGTH is the chaining length in bytes of SHA-1 +// SHA*_CHAINING_LENGTH is the chaining length in bytes of SHA-* // It corresponds to the length in bytes of the h part of the state #define SHA1_CHAINING_LENGTH 20 - -// SHA224_CHAINING_LENGTH is the chaining length in bytes of SHA-224 -// It corresponds to the length in bytes of the h part of the state #define SHA224_CHAINING_LENGTH 32 - -// SHA256_CHAINING_LENGTH is the chaining length in bytes of SHA-256 -// It corresponds to the length in bytes of the h part of the state #define SHA256_CHAINING_LENGTH 32 - -// SHA384_CHAINING_LENGTH is the chaining length in bytes of SHA-384 -// It corresponds to the length in bytes of the h part of the state #define SHA384_CHAINING_LENGTH 64 - -// SHA512_CHAINING_LENGTH is the chaining length in bytes of SHA-512 -// It corresponds to the length in bytes of the h part of the state #define SHA512_CHAINING_LENGTH 64 - -// SHA512_224_CHAINING_LENGTH is the chaining length in bytes of SHA-512-224 -// It corresponds to the length in bytes of the h part of the state #define SHA512_224_CHAINING_LENGTH 64 - -// SHA512_256_CHAINING_LENGTH is the chaining length in bytes of SHA-512-256 -// It corresponds to the length in bytes of the h part of the state #define SHA512_256_CHAINING_LENGTH 64 @@ -126,7 +108,7 @@ void sha512_block_data_order(uint64_t *state, const uint8_t *in, // SHA1_Init_from_state is a low-level function that initializes |sha| with a // custom state. |h| is the hash state in big endian. |n| is the number of bits // processed at this point. It must be a multiple of |SHA256_CBLOCK*8|. -// It returns one on success and zero on programmer error. +// It returns one on success and zero on error. // This function is for internal use only and should never be directly called. OPENSSL_EXPORT int SHA1_Init_from_state(SHA_CTX *sha, const uint8_t h[SHA1_CHAINING_LENGTH], @@ -134,11 +116,10 @@ OPENSSL_EXPORT int SHA1_Init_from_state(SHA_CTX *sha, // SHA1_get_state is a low-level function that exports the hash state in big // endian into |out_n| and the number of bits processed at this point in -// |out_n|. SHA1_Final must not have been called before (otherwise results +// |out_n|. |SHA1_Final| must not have been called before (otherwise results // are not guaranteed). Furthermore, the number of bytes processed by // SHA1_Update must be a multiple of the block length |SHA1_CBLOCK| -// (otherwise it fails). It returns one on success and zero on programmer -// error. +// (otherwise it fails). It returns one on success and zero on error. // This function is for internal use only and should never be directly called. OPENSSL_EXPORT int SHA1_get_state(SHA_CTX *ctx, uint8_t out_h[SHA1_CHAINING_LENGTH], @@ -147,18 +128,17 @@ OPENSSL_EXPORT int SHA1_get_state(SHA_CTX *ctx, // SHA224_Init_from_state is a low-level function that initializes |sha| with a // custom state. |h| is the hash state in big endian. |n| is the number of bits // processed at this point. It must be a multiple of |SHA256_CBLOCK*8|. -// It returns one on success and zero on programmer error. +// It returns one on success and zero on error. // This function is for internal use only and should never be directly called. OPENSSL_EXPORT int SHA224_Init_from_state( SHA256_CTX *sha, const uint8_t h[SHA224_CHAINING_LENGTH], uint64_t n); // SHA224_get_state is a low-level function that exports the hash state in big // endian into |out_n| and the number of bits processed at this point in -// |out_n|. SHA224_Final must not have been called before (otherwise results +// |out_n|. |SHA224_Final| must not have been called before (otherwise results // are not guaranteed). Furthermore, the number of bytes processed by -// SHA224_Update must be a multiple of the block length |SHA224_CBLOCK| -// (otherwise it fails). It returns one on success and zero on programmer -// error. +// |SHA224_Update| must be a multiple of the block length |SHA224_CBLOCK| +// (otherwise it fails). It returns one on success and zero on error. // This function is for internal use only and should never be directly called. OPENSSL_EXPORT int SHA224_get_state(SHA256_CTX *ctx, uint8_t out_h[SHA224_CHAINING_LENGTH], @@ -167,18 +147,17 @@ OPENSSL_EXPORT int SHA224_get_state(SHA256_CTX *ctx, // SHA256_Init_from_state is a low-level function that initializes |sha| with a // custom state. |h| is the hash state in big endian. |n| is the number of bits // processed at this point. It must be a multiple of |SHA256_CBLOCK*8|. -// It returns one on success and zero on programmer error. +// It returns one on success and zero on error. // This function is for internal use only and should never be directly called. OPENSSL_EXPORT int SHA256_Init_from_state( SHA256_CTX *sha, const uint8_t h[SHA256_CHAINING_LENGTH], uint64_t n); // SHA256_get_state is a low-level function that exports the hash state in big // endian into |out_n| and the number of bits processed at this point in -// |out_n|. SHA256_Final must not have been called before (otherwise results +// |out_n|. |SHA256_Final| must not have been called before (otherwise results // are not guaranteed). Furthermore, the number of bytes processed by -// SHA256_Update must be a multiple of the block length |SHA256_CBLOCK| -// (otherwise it fails). It returns one on success and zero on programmer -// error. +// |SHA256_Update| must be a multiple of the block length |SHA256_CBLOCK| +// (otherwise it fails). It returns one on success and zero on error. // This function is for internal use only and should never be directly called. OPENSSL_EXPORT int SHA256_get_state(SHA256_CTX *ctx, uint8_t out_h[SHA256_CHAINING_LENGTH], @@ -187,7 +166,7 @@ OPENSSL_EXPORT int SHA256_get_state(SHA256_CTX *ctx, // SHA384_Init_from_state is a low-level function that initializes |sha| with a // custom state. |h| is the hash state in big endian. |n| is the number of bits // processed at this point. It must be a multiple of |SHA512_CBLOCK*8|. -// It returns one on success and zero on programmer error. +// It returns one on success and zero on error. // This function is for internal use only and should never be directly called. OPENSSL_EXPORT int SHA384_Init_from_state( SHA512_CTX *sha, const uint8_t h[SHA384_CHAINING_LENGTH], uint64_t n); @@ -196,9 +175,9 @@ OPENSSL_EXPORT int SHA384_Init_from_state( // endian into |out_n| and the number of bits processed at this point in // |out_n|. SHA384_Final must not have been called before (otherwise results // are not guaranteed). Furthermore, the number of bytes processed by -// SHA384_Update must be a multiple of the block length |SHA384_CBLOCK| -// (otherwise it fails). It returns one on success and zero on programmer -// error. +// |SHA384_Update| must be a multiple of the block length |SHA384_CBLOCK| and +// must be less than 2^61 (otherwise it fails). It returns one on success and +// zero on error. // This function is for internal use only and should never be directly called. OPENSSL_EXPORT int SHA384_get_state(SHA512_CTX *ctx, uint8_t out_h[SHA384_CHAINING_LENGTH], @@ -207,18 +186,18 @@ OPENSSL_EXPORT int SHA384_get_state(SHA512_CTX *ctx, // SHA512_Init_from_state is a low-level function that initializes |sha| with a // custom state. |h| is the hash state in big endian. |n| is the number of bits // processed at this point. It must be a multiple of |SHA512_CBLOCK*8|. -// It returns one on success and zero on programmer error. +// It returns one on success and zero on error. // This function is for internal use only and should never be directly called. OPENSSL_EXPORT int SHA512_Init_from_state( SHA512_CTX *sha, const uint8_t h[SHA512_CHAINING_LENGTH], uint64_t n); // SHA512_get_state is a low-level function that exports the hash state in big // endian into |out_n| and the number of bits processed at this point in -// |out_n|. SHA512_Final must not have been called before (otherwise results +// |out_n|. |SHA512_Final| must not have been called before (otherwise results // are not guaranteed). Furthermore, the number of bytes processed by -// SHA512_Update must be a multiple of the block length |SHA512_CBLOCK| -// (otherwise it fails). It returns one on success and zero on programmer -// error. +// |SHA512_Update| must be a multiple of the block length |SHA512_CBLOCK| and +// must be less than 2^61 (otherwise it fails). It returns one on success and +// zero on error. // This function is for internal use only and should never be directly called. OPENSSL_EXPORT int SHA512_get_state(SHA512_CTX *ctx, uint8_t out_h[SHA512_CHAINING_LENGTH], @@ -227,18 +206,18 @@ OPENSSL_EXPORT int SHA512_get_state(SHA512_CTX *ctx, // SHA512_224_Init_from_state is a low-level function that initializes |sha| // with a custom state. |h| is the hash state in big endian. |n| is the number // of bits processed at this point. It must be a multiple of |SHA512_CBLOCK*8|. -// It returns one on success and zero on programmer error. +// It returns one on success and zero on error. // This function is for internal use only and should never be directly called. OPENSSL_EXPORT int SHA512_224_Init_from_state( SHA512_CTX *sha, const uint8_t h[SHA512_224_CHAINING_LENGTH], uint64_t n); // SHA512_224_get_state is a low-level function that exports the hash state in // big endian into |out_n| and the number of bits processed at this point in -// |out_n|. SHA512_224_Final must not have been called before (otherwise results -// are not guaranteed). Furthermore, the number of bytes processed by -// SHA512_224_Update must be a multiple of the block length |SHA512_CBLOCK| -// (otherwise it fails). It returns one on success and zero on programmer -// error. +// |out_n|. |SHA512_224_Final| must not have been called before (otherwise +// results are not guaranteed). Furthermore, the number of bytes processed by +// |SHA512_224_Update| must be a multiple of the block length |SHA512_CBLOCK| +// and must be less than 2^61 (otherwise it fails). It returns one on success +// and zero on error. // This function is for internal use only and should never be directly called. OPENSSL_EXPORT int SHA512_224_get_state( SHA512_CTX *ctx, uint8_t out_h[SHA512_224_CHAINING_LENGTH], @@ -247,18 +226,18 @@ OPENSSL_EXPORT int SHA512_224_get_state( // SHA512_256_Init_from_state is a low-level function that initializes |sha| // with a custom state. |h| is the hash state in big endian. |n| is the number // of bits processed at this point. It must be a multiple of |SHA512_CBLOCK*8|. -// It returns one on success and zero on programmer error. +// It returns one on success and zero on error. // This function is for internal use only and should never be directly called. OPENSSL_EXPORT int SHA512_256_Init_from_state( SHA512_CTX *sha, const uint8_t h[SHA512_256_CHAINING_LENGTH], uint64_t n); // SHA512_256_get_state is a low-level function that exports the hash state in // big endian into |out_n| and the number of bits processed at this point in -// |out_n|. SHA512_256_Final must not have been called before (otherwise results -// are not guaranteed). Furthermore, the number of bytes processed by -// SHA512_256_Update must be a multiple of the block length |SHA512_CBLOCK| -// (otherwise it fails). It returns one on success and zero on programmer -// error. +// |out_n|. |SHA512_256_Final| must not have been called before (otherwise +// results are not guaranteed). Furthermore, the number of bytes processed by +// |SHA512_256_Update| must be a multiple of the block length |SHA512_CBLOCK| +// and must be less than 2^61 (otherwise it fails). It returns one on success +// and zero on error. // This function is for internal use only and should never be directly called. OPENSSL_EXPORT int SHA512_256_get_state( SHA512_CTX *ctx, uint8_t out_h[SHA512_256_CHAINING_LENGTH], diff --git a/crypto/fipsmodule/sha/sha512.c b/crypto/fipsmodule/sha/sha512.c index ba9146fa90..ddc01dc16c 100644 --- a/crypto/fipsmodule/sha/sha512.c +++ b/crypto/fipsmodule/sha/sha512.c @@ -168,8 +168,8 @@ static int sha512_init_from_state_impl(SHA512_CTX *sha, int md_len, h += 8; } - sha->Nh = n >> 32; - sha->Nl = n & 0xffffffff; + sha->Nh = 0; + sha->Nl = n; return 1; } @@ -421,13 +421,19 @@ static int sha512_get_state_impl(SHA512_CTX *ctx, return 0; } + if (ctx->Nh != 0) { + // |sha512_get_state_impl| assumes that at most 2^64 bits have been + // processed by the hash function + return 0; + } + const size_t out_words = SHA512_CHAINING_LENGTH / 8; for (size_t i = 0; i < out_words; i++) { CRYPTO_store_u64_be(out_h, ctx->h[i]); out_h += 8; } - *out_n = (((uint64_t)ctx->Nh) << 32) + ctx->Nl; + *out_n = ctx->Nl; // we know that ctx->Nh = 0 return 1; } From 866fd7f31959cc0ef34ddab59deafdd3a8f96700 Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Fri, 5 Jul 2024 17:40:40 -0400 Subject: [PATCH 19/26] Unit test for HMAC_with_precompute service indicator Check that HMAC_with_precompute does not set the service indicator to approved. --- .../service_indicator/service_indicator_test.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/crypto/fipsmodule/service_indicator/service_indicator_test.cc b/crypto/fipsmodule/service_indicator/service_indicator_test.cc index 7523e7b7df..0bf1b2afcd 100644 --- a/crypto/fipsmodule/service_indicator/service_indicator_test.cc +++ b/crypto/fipsmodule/service_indicator/service_indicator_test.cc @@ -30,6 +30,7 @@ #include "../../test/abi_test.h" #include "../../test/test_util.h" #include "../bn/internal.h" +#include "../hmac/internal.h" #include "../rand/internal.h" #include "../sha/internal.h" @@ -1339,6 +1340,15 @@ TEST_P(HMACServiceIndicatorTest, HMACTest) { EXPECT_EQ(Bytes(test.expected_digest, expected_mac_len), Bytes(mac.data(), mac_len)); + // Test using the one-shot non-approved internal API HMAC_with_precompute + CALL_SERVICE_AND_CHECK_APPROVED( + approved, ASSERT_TRUE(HMAC_with_precompute( + digest, kHMACKey, sizeof(kHMACKey), kPlaintext, + sizeof(kPlaintext), mac.data(), &mac_len))); + EXPECT_EQ(approved, AWSLC_NOT_APPROVED); + EXPECT_EQ(Bytes(test.expected_digest, expected_mac_len), + Bytes(mac.data(), mac_len)); + // Test using precomputed keys // First, extract the precomputed key ctx.Reset(); From 7a99180cb2e5da755419de915c7f7c391b4f911c Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Mon, 8 Jul 2024 11:31:02 -0400 Subject: [PATCH 20/26] Unit test for hash Init_with_state/get_state after hashing > 2^32 bits Would catch the bug fixed in commit e16bd402642ca065b4042e3b3090baa8d752063d --- crypto/digest_extra/digest_test.cc | 175 +++++++++++++++++++++++++---- 1 file changed, 154 insertions(+), 21 deletions(-) diff --git a/crypto/digest_extra/digest_test.cc b/crypto/digest_extra/digest_test.cc index e113b1f94f..40310d617e 100644 --- a/crypto/digest_extra/digest_test.cc +++ b/crypto/digest_extra/digest_test.cc @@ -478,11 +478,12 @@ TEST(DigestTest, TransformBlocks) { EXPECT_TRUE(0 == OPENSSL_memcmp(ctx1.h, ctx2.h, sizeof(ctx1.h))); } -// DIGEST_TEST_InitAndGetState_Body expands to the body of the various -// InitAndGetState* tests below. +// DIGEST_TEST_InitAndGetStateBasic_Body expands to the body of the various +// InitAndGetStateBasic* tests below. // Because EXPECT_* outputs the line where the macro is called/expanded, // we need to add diagnostic information `<< ...` after each EXPECT_* -#define DIGEST_TEST_InitAndGetState_Body(HASH_NAME, HASH_CTX, HASH_CBLOCK) \ +#define DIGEST_TEST_InitAndGetStateBasic_Body(HASH_NAME, HASH_CTX, \ + HASH_CBLOCK) \ { \ const size_t nb_blocks = 10; \ const size_t block_size = HASH_CBLOCK; \ @@ -527,44 +528,176 @@ TEST(DigestTest, TransformBlocks) { uint8_t hash2[HASH_NAME##_DIGEST_LENGTH]; \ EXPECT_TRUE(HASH_NAME##_Final(hash2, &ctx3)) << "final 3"; \ \ + /* finally check the resulting hash matches the baseline hash */ \ EXPECT_EQ(Bytes(hash1), Bytes(hash2)) << "same hash"; \ } -// The macro DIGEST_TEST_InitAndGetState_Body only contains the body of the -// tests and not the TEST(...) { part, so that IDE can still easily recognize -// those as tests. -TEST(DigestTest, InitAndGetStateMD5) { - DIGEST_TEST_InitAndGetState_Body(MD5, MD5_CTX, MD5_CBLOCK); +// DIGEST_TEST_InitAndGetStateLarge_Body expands to the body of the various +// InitAndGetStateLarge* tests below. +// Compared to DIGEST_TEST_InitAndGetStateBasic_Body, it allows testing +// hashing an arbitrary amount of data. +// Of particular interest is the choice of NB_1000_BLOCKS to be such that +// the number of hash bits n > 2^32, therefore overflowing uint32_t (used for +// SHA-1/SHA-256 but not SHA-512 which uses uint64_t). +// Concretely, the test evaluates the hash function over (NB_1000_BLOCKS+2)*1000 +// blocks, exporting the state after NB_1000_BLOCKS * 1000 blocks. +// Because EXPECT_* outputs the line where the macro is called/expanded, we need +// to add diagnostic information `<< ...` after each EXPECT_* +#define DIGEST_TEST_InitAndGetStateLarge_Body(HASH_NAME, HASH_CTX, \ + HASH_CBLOCK, NB_1000_BLOCKS) \ + { \ + const size_t block_size = HASH_CBLOCK; \ + uint8_t data_1000_blocks[block_size * 1000]; \ + for (size_t i = 0; i < sizeof(data_1000_blocks); i++) { \ + data_1000_blocks[i] = i * 3; \ + } \ + \ + /* Compute the hash of the NB_1000_BLOCKS+2 times the data_1000_blocks for \ + * the baseline */ \ + HASH_CTX ctx1; \ + EXPECT_TRUE(HASH_NAME##_Init(&ctx1)) << "init 1"; \ + for (size_t i = 0; i < NB_1000_BLOCKS + 2; i++) { \ + EXPECT_TRUE(HASH_NAME##_Update(&ctx1, data_1000_blocks, \ + sizeof(data_1000_blocks))) \ + << "update 1 - i=" << i; \ + } \ + uint8_t hash1[HASH_NAME##_DIGEST_LENGTH]; \ + EXPECT_TRUE(HASH_NAME##_Final(hash1, &ctx1)) << "final 1"; \ + \ + /* Compute it by stopping after NB_1000_BLOCKS, getting the state, and \ + * restoring it */ \ + HASH_CTX ctx2; \ + EXPECT_TRUE(HASH_NAME##_Init(&ctx2)) << "init 2"; \ + /* Hash NB_1000_BLOCKS blocks minus one single byte */ \ + for (size_t i = 0; i < NB_1000_BLOCKS - 1; i++) { \ + EXPECT_TRUE(HASH_NAME##_Update(&ctx2, data_1000_blocks, \ + sizeof(data_1000_blocks))) \ + << "update 2a - i=" << i; \ + } \ + EXPECT_TRUE(HASH_NAME##_Update(&ctx2, data_1000_blocks, \ + sizeof(data_1000_blocks) - 1)) \ + << "update 2b"; \ + uint8_t state_h[HASH_NAME##_CHAINING_LENGTH]; \ + uint64_t state_n; \ + /* we should not be able to export the state because did not hash a \ + * multiple of blocks (since we skip the last byte) */ \ + EXPECT_FALSE(HASH_NAME##_get_state(&ctx2, state_h, &state_n)) \ + << "get_state 2b"; \ + /* finish the current block, i.e., hash the last byte */ \ + EXPECT_TRUE(HASH_NAME##_Update( \ + &ctx2, data_1000_blocks + sizeof(data_1000_blocks) - 1, 1)) \ + << "update 2c"; \ + /* now we should be able to export the state */ \ + EXPECT_TRUE(HASH_NAME##_get_state(&ctx2, state_h, &state_n)) \ + << "get_state 2c"; \ + /* check that state_n corresponds to NB_1000_BLOCKS blocks */ \ + EXPECT_EQ((uint64_t)(NB_1000_BLOCKS) * sizeof(data_1000_blocks) * 8, \ + state_n) \ + << "correct state_n"; \ + \ + /* and we continue on a fresh new context: \ + * we just need to hash the remaining 2 * 1000 blocks */ \ + HASH_CTX ctx3; \ + EXPECT_TRUE(HASH_NAME##_Init_from_state(&ctx3, state_h, state_n)) \ + << "init 3"; \ + for (size_t i = 0; i < 2; i++) { \ + EXPECT_TRUE(HASH_NAME##_Update(&ctx3, data_1000_blocks, \ + sizeof(data_1000_blocks))) \ + << "update 3 - i=" << i; \ + } \ + uint8_t hash2[HASH_NAME##_DIGEST_LENGTH]; \ + EXPECT_TRUE(HASH_NAME##_Final(hash2, &ctx3)) << "final 3"; \ + \ + /* finally check the resulting hash matches the baseline hash */ \ + EXPECT_EQ(Bytes(hash1), Bytes(hash2)) << "same hash"; \ + } + + +TEST(DigestTest, InitAndGetStateMD5Basic) { + DIGEST_TEST_InitAndGetStateBasic_Body(MD5, MD5_CTX, MD5_CBLOCK); +} + +TEST(DigestTest, InitAndGetStateMD5Large) { + // Hash more than 2^32 bits to find potential overflows + DIGEST_TEST_InitAndGetStateLarge_Body( + MD5, MD5_CTX, MD5_CBLOCK, (1L << 32) / MD5_CBLOCK / 8 / 1000 + 10); } // Define SHA1_DIGEST_LENGTH to make the macro work... #define SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH -TEST(DigestTest, InitAndGetStateSHA1) { - DIGEST_TEST_InitAndGetState_Body(SHA1, SHA_CTX, SHA_CBLOCK); +TEST(DigestTest, InitAndGetStateSHA1Basic) { + DIGEST_TEST_InitAndGetStateBasic_Body(SHA1, SHA_CTX, SHA_CBLOCK); +} + +TEST(DigestTest, InitAndGetStateSHA1Large) { + // Hash more than 2^32 bits to find potential overflows + DIGEST_TEST_InitAndGetStateLarge_Body( + SHA1, SHA_CTX, SHA_CBLOCK, (1L << 32) / SHA_CBLOCK / 8 / 1000 + 10); +} + +TEST(DigestTest, InitAndGetStateSHA224Basic) { + DIGEST_TEST_InitAndGetStateBasic_Body(SHA224, SHA256_CTX, SHA256_CBLOCK); } -TEST(DigestTest, InitAndGetStateSHA224) { - DIGEST_TEST_InitAndGetState_Body(SHA224, SHA256_CTX, SHA256_CBLOCK); +TEST(DigestTest, InitAndGetStateSHA224Large) { + // Hash more than 2^32 bits to find potential overflows + DIGEST_TEST_InitAndGetStateLarge_Body( + SHA224, SHA256_CTX, SHA224_CBLOCK, + (1L << 32) / SHA224_CBLOCK / 8 / 1000 + 10); } -TEST(DigestTest, InitAndGetStateSHA256) { - DIGEST_TEST_InitAndGetState_Body(SHA256, SHA256_CTX, SHA256_CBLOCK); +TEST(DigestTest, InitAndGetStateSHA256Basic) { + DIGEST_TEST_InitAndGetStateBasic_Body(SHA256, SHA256_CTX, SHA256_CBLOCK); } -TEST(DigestTest, InitAndGetStateSHA384) { - DIGEST_TEST_InitAndGetState_Body(SHA384, SHA512_CTX, SHA512_CBLOCK); +TEST(DigestTest, InitAndGetStateSHA256Large) { + // Hash more than 2^32 bits to find potential overflows + DIGEST_TEST_InitAndGetStateLarge_Body( + SHA256, SHA256_CTX, SHA256_CBLOCK, + (1L << 32) / SHA256_CBLOCK / 8 / 1000 + 10); } -TEST(DigestTest, InitAndGetStateSHA512) { - DIGEST_TEST_InitAndGetState_Body(SHA512, SHA512_CTX, SHA512_CBLOCK); +TEST(DigestTest, InitAndGetStateSHA384Basic) { + DIGEST_TEST_InitAndGetStateBasic_Body(SHA384, SHA512_CTX, SHA512_CBLOCK); } -TEST(DigestTest, InitAndGetStateSHA512_224) { - DIGEST_TEST_InitAndGetState_Body(SHA512_224, SHA512_CTX, SHA512_CBLOCK); +TEST(DigestTest, InitAndGetStateSHA384Large) { + // Hash more than 2^32 bits to find potential overflows + DIGEST_TEST_InitAndGetStateLarge_Body( + SHA384, SHA512_CTX, SHA384_CBLOCK, + (1L << 32) / SHA384_CBLOCK / 8 / 1000 + 10); +} + +TEST(DigestTest, InitAndGetStateSHA512Basic) { + DIGEST_TEST_InitAndGetStateBasic_Body(SHA512, SHA512_CTX, SHA512_CBLOCK); +} + +TEST(DigestTest, InitAndGetStateSHA512Large) { + // Hash more than 2^32 bits to find potential overflows + DIGEST_TEST_InitAndGetStateLarge_Body( + SHA512, SHA512_CTX, SHA512_CBLOCK, + (1L << 32) / SHA512_CBLOCK / 8 / 1000 + 10); +} + +TEST(DigestTest, InitAndGetStateSHA512_224Basic) { + DIGEST_TEST_InitAndGetStateBasic_Body(SHA512_224, SHA512_CTX, SHA512_CBLOCK); +} + +TEST(DigestTest, InitAndGetStateSHA512_224Large) { + // Hash more than 2^32 bits to find potential overflows + DIGEST_TEST_InitAndGetStateLarge_Body( + SHA512_224, SHA512_CTX, SHA512_CBLOCK, + (1L << 32) / SHA512_CBLOCK / 8 / 1000 + 10); } TEST(DigestTest, InitAndGetStateSHA512_256) { - DIGEST_TEST_InitAndGetState_Body(SHA512_256, SHA512_CTX, SHA512_CBLOCK); + DIGEST_TEST_InitAndGetStateBasic_Body(SHA512_256, SHA512_CTX, SHA512_CBLOCK); } +TEST(DigestTest, InitAndGetStateSHA512_256Large) { + // Hash more than 2^32 bits to find potential overflows + DIGEST_TEST_InitAndGetStateLarge_Body( + SHA512_256, SHA512_CTX, SHA512_CBLOCK, + (1L << 32) / SHA512_CBLOCK / 8 / 1000 + 10); +} From 7227a2c68dbb7e15d1ecce4a9e7f3c487ef5c252 Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Mon, 8 Jul 2024 11:52:50 -0400 Subject: [PATCH 21/26] Fixing type of some constants With some compilers 1L is not 64-bit. Manually cast to uint64_t. --- crypto/digest_extra/digest_test.cc | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/crypto/digest_extra/digest_test.cc b/crypto/digest_extra/digest_test.cc index 40310d617e..7318768b1f 100644 --- a/crypto/digest_extra/digest_test.cc +++ b/crypto/digest_extra/digest_test.cc @@ -621,7 +621,8 @@ TEST(DigestTest, InitAndGetStateMD5Basic) { TEST(DigestTest, InitAndGetStateMD5Large) { // Hash more than 2^32 bits to find potential overflows DIGEST_TEST_InitAndGetStateLarge_Body( - MD5, MD5_CTX, MD5_CBLOCK, (1L << 32) / MD5_CBLOCK / 8 / 1000 + 10); + MD5, MD5_CTX, MD5_CBLOCK, + (((uint64_t)1) << 32) / MD5_CBLOCK / 8 / 1000 + 10); } // Define SHA1_DIGEST_LENGTH to make the macro work... @@ -633,7 +634,8 @@ TEST(DigestTest, InitAndGetStateSHA1Basic) { TEST(DigestTest, InitAndGetStateSHA1Large) { // Hash more than 2^32 bits to find potential overflows DIGEST_TEST_InitAndGetStateLarge_Body( - SHA1, SHA_CTX, SHA_CBLOCK, (1L << 32) / SHA_CBLOCK / 8 / 1000 + 10); + SHA1, SHA_CTX, SHA_CBLOCK, + (((uint64_t)1) << 32) / SHA_CBLOCK / 8 / 1000 + 10); } TEST(DigestTest, InitAndGetStateSHA224Basic) { @@ -644,7 +646,7 @@ TEST(DigestTest, InitAndGetStateSHA224Large) { // Hash more than 2^32 bits to find potential overflows DIGEST_TEST_InitAndGetStateLarge_Body( SHA224, SHA256_CTX, SHA224_CBLOCK, - (1L << 32) / SHA224_CBLOCK / 8 / 1000 + 10); + (((uint64_t)1) << 32) / SHA224_CBLOCK / 8 / 1000 + 10); } TEST(DigestTest, InitAndGetStateSHA256Basic) { @@ -655,7 +657,7 @@ TEST(DigestTest, InitAndGetStateSHA256Large) { // Hash more than 2^32 bits to find potential overflows DIGEST_TEST_InitAndGetStateLarge_Body( SHA256, SHA256_CTX, SHA256_CBLOCK, - (1L << 32) / SHA256_CBLOCK / 8 / 1000 + 10); + (((uint64_t)1) << 32) / SHA256_CBLOCK / 8 / 1000 + 10); } TEST(DigestTest, InitAndGetStateSHA384Basic) { @@ -666,7 +668,7 @@ TEST(DigestTest, InitAndGetStateSHA384Large) { // Hash more than 2^32 bits to find potential overflows DIGEST_TEST_InitAndGetStateLarge_Body( SHA384, SHA512_CTX, SHA384_CBLOCK, - (1L << 32) / SHA384_CBLOCK / 8 / 1000 + 10); + (((uint64_t)1) << 32) / SHA384_CBLOCK / 8 / 1000 + 10); } TEST(DigestTest, InitAndGetStateSHA512Basic) { @@ -677,7 +679,7 @@ TEST(DigestTest, InitAndGetStateSHA512Large) { // Hash more than 2^32 bits to find potential overflows DIGEST_TEST_InitAndGetStateLarge_Body( SHA512, SHA512_CTX, SHA512_CBLOCK, - (1L << 32) / SHA512_CBLOCK / 8 / 1000 + 10); + (((uint64_t)1) << 32) / SHA512_CBLOCK / 8 / 1000 + 10); } TEST(DigestTest, InitAndGetStateSHA512_224Basic) { @@ -688,7 +690,7 @@ TEST(DigestTest, InitAndGetStateSHA512_224Large) { // Hash more than 2^32 bits to find potential overflows DIGEST_TEST_InitAndGetStateLarge_Body( SHA512_224, SHA512_CTX, SHA512_CBLOCK, - (1L << 32) / SHA512_CBLOCK / 8 / 1000 + 10); + (((uint64_t)1) << 32) / SHA512_CBLOCK / 8 / 1000 + 10); } TEST(DigestTest, InitAndGetStateSHA512_256) { @@ -699,5 +701,5 @@ TEST(DigestTest, InitAndGetStateSHA512_256Large) { // Hash more than 2^32 bits to find potential overflows DIGEST_TEST_InitAndGetStateLarge_Body( SHA512_256, SHA512_CTX, SHA512_CBLOCK, - (1L << 32) / SHA512_CBLOCK / 8 / 1000 + 10); + (((uint64_t)1) << 32) / SHA512_CBLOCK / 8 / 1000 + 10); } From 6df5d2e3ab508e58521b2066682774743252f290 Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Mon, 8 Jul 2024 12:26:50 -0400 Subject: [PATCH 22/26] Adding unit tests to increase coverage --- crypto/digest_extra/digest_test.cc | 6 ++++++ crypto/hmac_extra/hmac_test.cc | 12 +++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/crypto/digest_extra/digest_test.cc b/crypto/digest_extra/digest_test.cc index 7318768b1f..758b80d348 100644 --- a/crypto/digest_extra/digest_test.cc +++ b/crypto/digest_extra/digest_test.cc @@ -530,6 +530,12 @@ TEST(DigestTest, TransformBlocks) { \ /* finally check the resulting hash matches the baseline hash */ \ EXPECT_EQ(Bytes(hash1), Bytes(hash2)) << "same hash"; \ + \ + /* Check that Init_from_state requires the number of bits to be a \ + * multiple of the block size */ \ + HASH_CTX ctx4; \ + EXPECT_FALSE(HASH_NAME##_Init_from_state(&ctx4, state_h, 1)) \ + << "init 4 n not multiple of block size"; \ } diff --git a/crypto/hmac_extra/hmac_test.cc b/crypto/hmac_extra/hmac_test.cc index c3735ed62f..553c6e154d 100644 --- a/crypto/hmac_extra/hmac_test.cc +++ b/crypto/hmac_extra/hmac_test.cc @@ -341,7 +341,7 @@ TEST(HMACTest, TestVectors) { EXPECT_EQ(Bytes(output), Bytes(mac.get(), mac_len)); OPENSSL_memset(mac.get(), 0, expected_mac_len); // Clear the prior correct answer - // Test that we get an error if the out_len is not large enough + // Test that we get an error if the out_len is not large enough or is null uint8_t precomputed_key2[HMAC_MAX_PRECOMPUTED_KEY_SIZE]; size_t precomputed_key_len_out2; ASSERT_TRUE(HMAC_Init_ex(ctx.get(), key.data(), key.size(), digest, nullptr)); @@ -351,6 +351,7 @@ TEST(HMACTest, TestVectors) { ASSERT_FALSE(HMAC_get_precomputed_key(ctx.get(), precomputed_key2, &precomputed_key_len_out2)); precomputed_key_len_out2 = 0; // 0-size should also fail ASSERT_FALSE(HMAC_get_precomputed_key(ctx.get(), precomputed_key2, &precomputed_key_len_out2)); + ASSERT_FALSE(HMAC_get_precomputed_key(ctx.get(), precomputed_key2, nullptr)); // Test that we get the same precompute_key the second time we correctly call HMAC_get_precomputed_key precomputed_key_len_out2 = precomputed_key_len; // testing with the out_len is the exact value @@ -386,6 +387,15 @@ TEST(HMACTest, TestVectors) { // Test consuming HMAC through the |EVP_PKEY_HMAC| interface. RunHMACTestEVP(key, input, output, digest); + + // Test that initializing without the precomputed_key does not work + ctx.Reset(); + ASSERT_FALSE(HMAC_Init_from_precomputed_key(ctx.get(), nullptr, precomputed_key_len, digest)); + + // Test that initializing with the wrong precomputed_key_len does not work + ctx.Reset(); + ASSERT_FALSE(HMAC_Init_from_precomputed_key(ctx.get(), nullptr, 1, digest)); + ASSERT_FALSE(HMAC_Init_from_precomputed_key(ctx.get(), nullptr, precomputed_key_len+1, digest)); }); } From 43510e5d10c7575603b2dff7ce1cc7bec35b788a Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Thu, 11 Jul 2024 12:01:15 -0400 Subject: [PATCH 23/26] Style and comment improvements from review of PR aws/aws-lc#1574 --- crypto/digest_extra/digest_test.cc | 23 +++-- crypto/fipsmodule/sha/internal.h | 144 ++++++----------------------- 2 files changed, 40 insertions(+), 127 deletions(-) diff --git a/crypto/digest_extra/digest_test.cc b/crypto/digest_extra/digest_test.cc index 758b80d348..d5579ad564 100644 --- a/crypto/digest_extra/digest_test.cc +++ b/crypto/digest_extra/digest_test.cc @@ -544,8 +544,11 @@ TEST(DigestTest, TransformBlocks) { // Compared to DIGEST_TEST_InitAndGetStateBasic_Body, it allows testing // hashing an arbitrary amount of data. // Of particular interest is the choice of NB_1000_BLOCKS to be such that -// the number of hash bits n > 2^32, therefore overflowing uint32_t (used for -// SHA-1/SHA-256 but not SHA-512 which uses uint64_t). +// the number of hash bits n > 2^32: this allows to test an important corner +// case. Indeed, HASH_CTX->Nl can be uint64_t (for SHA-512, SHA-384, +// SHA-512/224, SHA-512/256) or uint32_t (for all other hash functions). In the +// latter case, when n > 2^32 bits, the 32 most significant bits of the 64-bit +// value n are stored in HASH_CTX->Nh. // Concretely, the test evaluates the hash function over (NB_1000_BLOCKS+2)*1000 // blocks, exporting the state after NB_1000_BLOCKS * 1000 blocks. // Because EXPECT_* outputs the line where the macro is called/expanded, we need @@ -625,7 +628,7 @@ TEST(DigestTest, InitAndGetStateMD5Basic) { } TEST(DigestTest, InitAndGetStateMD5Large) { - // Hash more than 2^32 bits to find potential overflows + // Hash more than 2^32 bits DIGEST_TEST_InitAndGetStateLarge_Body( MD5, MD5_CTX, MD5_CBLOCK, (((uint64_t)1) << 32) / MD5_CBLOCK / 8 / 1000 + 10); @@ -638,7 +641,7 @@ TEST(DigestTest, InitAndGetStateSHA1Basic) { } TEST(DigestTest, InitAndGetStateSHA1Large) { - // Hash more than 2^32 bits to find potential overflows + // Hash more than 2^32 bits DIGEST_TEST_InitAndGetStateLarge_Body( SHA1, SHA_CTX, SHA_CBLOCK, (((uint64_t)1) << 32) / SHA_CBLOCK / 8 / 1000 + 10); @@ -649,7 +652,7 @@ TEST(DigestTest, InitAndGetStateSHA224Basic) { } TEST(DigestTest, InitAndGetStateSHA224Large) { - // Hash more than 2^32 bits to find potential overflows + // Hash more than 2^32 bits DIGEST_TEST_InitAndGetStateLarge_Body( SHA224, SHA256_CTX, SHA224_CBLOCK, (((uint64_t)1) << 32) / SHA224_CBLOCK / 8 / 1000 + 10); @@ -660,7 +663,7 @@ TEST(DigestTest, InitAndGetStateSHA256Basic) { } TEST(DigestTest, InitAndGetStateSHA256Large) { - // Hash more than 2^32 bits to find potential overflows + // Hash more than 2^32 bits DIGEST_TEST_InitAndGetStateLarge_Body( SHA256, SHA256_CTX, SHA256_CBLOCK, (((uint64_t)1) << 32) / SHA256_CBLOCK / 8 / 1000 + 10); @@ -671,7 +674,7 @@ TEST(DigestTest, InitAndGetStateSHA384Basic) { } TEST(DigestTest, InitAndGetStateSHA384Large) { - // Hash more than 2^32 bits to find potential overflows + // Hash more than 2^32 bits DIGEST_TEST_InitAndGetStateLarge_Body( SHA384, SHA512_CTX, SHA384_CBLOCK, (((uint64_t)1) << 32) / SHA384_CBLOCK / 8 / 1000 + 10); @@ -682,7 +685,7 @@ TEST(DigestTest, InitAndGetStateSHA512Basic) { } TEST(DigestTest, InitAndGetStateSHA512Large) { - // Hash more than 2^32 bits to find potential overflows + // Hash more than 2^32 bits DIGEST_TEST_InitAndGetStateLarge_Body( SHA512, SHA512_CTX, SHA512_CBLOCK, (((uint64_t)1) << 32) / SHA512_CBLOCK / 8 / 1000 + 10); @@ -693,7 +696,7 @@ TEST(DigestTest, InitAndGetStateSHA512_224Basic) { } TEST(DigestTest, InitAndGetStateSHA512_224Large) { - // Hash more than 2^32 bits to find potential overflows + // Hash more than 2^32 bits DIGEST_TEST_InitAndGetStateLarge_Body( SHA512_224, SHA512_CTX, SHA512_CBLOCK, (((uint64_t)1) << 32) / SHA512_CBLOCK / 8 / 1000 + 10); @@ -704,7 +707,7 @@ TEST(DigestTest, InitAndGetStateSHA512_256) { } TEST(DigestTest, InitAndGetStateSHA512_256Large) { - // Hash more than 2^32 bits to find potential overflows + // Hash more than 2^32 bits DIGEST_TEST_InitAndGetStateLarge_Body( SHA512_256, SHA512_CTX, SHA512_CBLOCK, (((uint64_t)1) << 32) / SHA512_CBLOCK / 8 / 1000 + 10); diff --git a/crypto/fipsmodule/sha/internal.h b/crypto/fipsmodule/sha/internal.h index 1172296ff5..e07bbd11f0 100644 --- a/crypto/fipsmodule/sha/internal.h +++ b/crypto/fipsmodule/sha/internal.h @@ -105,140 +105,50 @@ void sha512_block_data_order(uint64_t *state, const uint8_t *in, #define KECCAK1600_ASM #endif -// SHA1_Init_from_state is a low-level function that initializes |sha| with a +// SHAx_Init_from_state is a low-level function that initializes |sha| with a // custom state. |h| is the hash state in big endian. |n| is the number of bits -// processed at this point. It must be a multiple of |SHA256_CBLOCK*8|. -// It returns one on success and zero on error. -// This function is for internal use only and should never be directly called. -OPENSSL_EXPORT int SHA1_Init_from_state(SHA_CTX *sha, - const uint8_t h[SHA1_CHAINING_LENGTH], - uint64_t n); - -// SHA1_get_state is a low-level function that exports the hash state in big -// endian into |out_n| and the number of bits processed at this point in -// |out_n|. |SHA1_Final| must not have been called before (otherwise results -// are not guaranteed). Furthermore, the number of bytes processed by -// SHA1_Update must be a multiple of the block length |SHA1_CBLOCK| -// (otherwise it fails). It returns one on success and zero on error. -// This function is for internal use only and should never be directly called. -OPENSSL_EXPORT int SHA1_get_state(SHA_CTX *ctx, - uint8_t out_h[SHA1_CHAINING_LENGTH], - uint64_t *out_n); - -// SHA224_Init_from_state is a low-level function that initializes |sha| with a -// custom state. |h| is the hash state in big endian. |n| is the number of bits -// processed at this point. It must be a multiple of |SHA256_CBLOCK*8|. -// It returns one on success and zero on error. +// processed at this point. It must be a multiple of |SHAy_CBLOCK*8|, +// where SHAy=SHA1 if SHAx=SHA1, SHAy=SHA256 if SHAx=SHA224 or SHA256, and +// SHAy=SHA512 otherwise. +// This function returns one on success and zero on error. // This function is for internal use only and should never be directly called. +OPENSSL_EXPORT int SHA1_Init_from_state( + SHA_CTX *sha, const uint8_t h[SHA1_CHAINING_LENGTH], uint64_t n); OPENSSL_EXPORT int SHA224_Init_from_state( SHA256_CTX *sha, const uint8_t h[SHA224_CHAINING_LENGTH], uint64_t n); - -// SHA224_get_state is a low-level function that exports the hash state in big -// endian into |out_n| and the number of bits processed at this point in -// |out_n|. |SHA224_Final| must not have been called before (otherwise results -// are not guaranteed). Furthermore, the number of bytes processed by -// |SHA224_Update| must be a multiple of the block length |SHA224_CBLOCK| -// (otherwise it fails). It returns one on success and zero on error. -// This function is for internal use only and should never be directly called. -OPENSSL_EXPORT int SHA224_get_state(SHA256_CTX *ctx, - uint8_t out_h[SHA224_CHAINING_LENGTH], - uint64_t *out_n); - -// SHA256_Init_from_state is a low-level function that initializes |sha| with a -// custom state. |h| is the hash state in big endian. |n| is the number of bits -// processed at this point. It must be a multiple of |SHA256_CBLOCK*8|. -// It returns one on success and zero on error. -// This function is for internal use only and should never be directly called. OPENSSL_EXPORT int SHA256_Init_from_state( SHA256_CTX *sha, const uint8_t h[SHA256_CHAINING_LENGTH], uint64_t n); - -// SHA256_get_state is a low-level function that exports the hash state in big -// endian into |out_n| and the number of bits processed at this point in -// |out_n|. |SHA256_Final| must not have been called before (otherwise results -// are not guaranteed). Furthermore, the number of bytes processed by -// |SHA256_Update| must be a multiple of the block length |SHA256_CBLOCK| -// (otherwise it fails). It returns one on success and zero on error. -// This function is for internal use only and should never be directly called. -OPENSSL_EXPORT int SHA256_get_state(SHA256_CTX *ctx, - uint8_t out_h[SHA256_CHAINING_LENGTH], - uint64_t *out_n); - -// SHA384_Init_from_state is a low-level function that initializes |sha| with a -// custom state. |h| is the hash state in big endian. |n| is the number of bits -// processed at this point. It must be a multiple of |SHA512_CBLOCK*8|. -// It returns one on success and zero on error. -// This function is for internal use only and should never be directly called. OPENSSL_EXPORT int SHA384_Init_from_state( SHA512_CTX *sha, const uint8_t h[SHA384_CHAINING_LENGTH], uint64_t n); - -// SHA384_get_state is a low-level function that exports the hash state in big -// endian into |out_n| and the number of bits processed at this point in -// |out_n|. SHA384_Final must not have been called before (otherwise results -// are not guaranteed). Furthermore, the number of bytes processed by -// |SHA384_Update| must be a multiple of the block length |SHA384_CBLOCK| and -// must be less than 2^61 (otherwise it fails). It returns one on success and -// zero on error. -// This function is for internal use only and should never be directly called. -OPENSSL_EXPORT int SHA384_get_state(SHA512_CTX *ctx, - uint8_t out_h[SHA384_CHAINING_LENGTH], - uint64_t *out_n); - -// SHA512_Init_from_state is a low-level function that initializes |sha| with a -// custom state. |h| is the hash state in big endian. |n| is the number of bits -// processed at this point. It must be a multiple of |SHA512_CBLOCK*8|. -// It returns one on success and zero on error. -// This function is for internal use only and should never be directly called. OPENSSL_EXPORT int SHA512_Init_from_state( SHA512_CTX *sha, const uint8_t h[SHA512_CHAINING_LENGTH], uint64_t n); - -// SHA512_get_state is a low-level function that exports the hash state in big -// endian into |out_n| and the number of bits processed at this point in -// |out_n|. |SHA512_Final| must not have been called before (otherwise results -// are not guaranteed). Furthermore, the number of bytes processed by -// |SHA512_Update| must be a multiple of the block length |SHA512_CBLOCK| and -// must be less than 2^61 (otherwise it fails). It returns one on success and -// zero on error. -// This function is for internal use only and should never be directly called. -OPENSSL_EXPORT int SHA512_get_state(SHA512_CTX *ctx, - uint8_t out_h[SHA512_CHAINING_LENGTH], - uint64_t *out_n); - -// SHA512_224_Init_from_state is a low-level function that initializes |sha| -// with a custom state. |h| is the hash state in big endian. |n| is the number -// of bits processed at this point. It must be a multiple of |SHA512_CBLOCK*8|. -// It returns one on success and zero on error. -// This function is for internal use only and should never be directly called. OPENSSL_EXPORT int SHA512_224_Init_from_state( SHA512_CTX *sha, const uint8_t h[SHA512_224_CHAINING_LENGTH], uint64_t n); +OPENSSL_EXPORT int SHA512_256_Init_from_state( + SHA512_CTX *sha, const uint8_t h[SHA512_256_CHAINING_LENGTH], uint64_t n); -// SHA512_224_get_state is a low-level function that exports the hash state in -// big endian into |out_n| and the number of bits processed at this point in -// |out_n|. |SHA512_224_Final| must not have been called before (otherwise -// results are not guaranteed). Furthermore, the number of bytes processed by -// |SHA512_224_Update| must be a multiple of the block length |SHA512_CBLOCK| -// and must be less than 2^61 (otherwise it fails). It returns one on success -// and zero on error. +// SHAx_get_state is a low-level function that exports the hash state in big +// endian into |out_n| and the number of bits processed at this point in +// |out_n|. |SHAx_Final| must not have been called before (otherwise results +// are not guaranteed). Furthermore, the number of bytes processed by +// |SHAx_Update| must be a multiple of the block length |SHAy_CBLOCK| and +// must be less than 2^61 (otherwise it fails). See comment above about +// SHAx_Init_from_state for the definition of SHAy. +// This function returns one on success and zero on error. // This function is for internal use only and should never be directly called. +OPENSSL_EXPORT int SHA1_get_state( + SHA_CTX *ctx, uint8_t out_h[SHA1_CHAINING_LENGTH], uint64_t *out_n); +OPENSSL_EXPORT int SHA224_get_state( + SHA256_CTX *ctx, uint8_t out_h[SHA224_CHAINING_LENGTH], uint64_t *out_n); +OPENSSL_EXPORT int SHA256_get_state( + SHA256_CTX *ctx, uint8_t out_h[SHA256_CHAINING_LENGTH], uint64_t *out_n); +OPENSSL_EXPORT int SHA384_get_state( + SHA512_CTX *ctx, uint8_t out_h[SHA384_CHAINING_LENGTH], uint64_t *out_n); +OPENSSL_EXPORT int SHA512_get_state( + SHA512_CTX *ctx, uint8_t out_h[SHA512_CHAINING_LENGTH], uint64_t *out_n); OPENSSL_EXPORT int SHA512_224_get_state( SHA512_CTX *ctx, uint8_t out_h[SHA512_224_CHAINING_LENGTH], uint64_t *out_n); - -// SHA512_256_Init_from_state is a low-level function that initializes |sha| -// with a custom state. |h| is the hash state in big endian. |n| is the number -// of bits processed at this point. It must be a multiple of |SHA512_CBLOCK*8|. -// It returns one on success and zero on error. -// This function is for internal use only and should never be directly called. -OPENSSL_EXPORT int SHA512_256_Init_from_state( - SHA512_CTX *sha, const uint8_t h[SHA512_256_CHAINING_LENGTH], uint64_t n); - -// SHA512_256_get_state is a low-level function that exports the hash state in -// big endian into |out_n| and the number of bits processed at this point in -// |out_n|. |SHA512_256_Final| must not have been called before (otherwise -// results are not guaranteed). Furthermore, the number of bytes processed by -// |SHA512_256_Update| must be a multiple of the block length |SHA512_CBLOCK| -// and must be less than 2^61 (otherwise it fails). It returns one on success -// and zero on error. -// This function is for internal use only and should never be directly called. OPENSSL_EXPORT int SHA512_256_get_state( SHA512_CTX *ctx, uint8_t out_h[SHA512_256_CHAINING_LENGTH], uint64_t *out_n); From 4ec5b37817b02a8a2061e9e66446e9e95ffcf123 Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Wed, 17 Jul 2024 15:52:08 -0400 Subject: [PATCH 24/26] Add hmac.errordata `crypto/err/hmac.errordata` generated using `go run ./util/make_errors.go hmac` CMakeLists file updated to add the errordata file. --- crypto/CMakeLists.txt | 1 + crypto/err/hmac.errordata | 4 ++++ 2 files changed, 5 insertions(+) create mode 100644 crypto/err/hmac.errordata diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt index d7590a214f..53062912f9 100644 --- a/crypto/CMakeLists.txt +++ b/crypto/CMakeLists.txt @@ -253,6 +253,7 @@ if(GO_EXECUTABLE) err/engine.errordata err/evp.errordata err/hkdf.errordata + err/hmac.errordata err/obj.errordata err/ocsp.errordata err/pem.errordata diff --git a/crypto/err/hmac.errordata b/crypto/err/hmac.errordata new file mode 100644 index 0000000000..a2039f8427 --- /dev/null +++ b/crypto/err/hmac.errordata @@ -0,0 +1,4 @@ +HMAC,102,BUFFER_TOO_SMALL +HMAC,100,MISSING_PARAMETERS +HMAC,104,NOT_CALLED_JUST_AFTER_INIT +HMAC,103,SET_PRECOMPUTED_KEY_EXPORT_NOT_CALLED From 34e5089dceb6930a68ed10fb4ef70f91e561fe44 Mon Sep 17 00:00:00 2001 From: Sean McGrail Date: Wed, 17 Jul 2024 21:25:05 +0000 Subject: [PATCH 25/26] python3 ./util/generate_build_files.py --- generated-src/err_data.c | 986 ++++++++++++++++++++------------------- 1 file changed, 496 insertions(+), 490 deletions(-) diff --git a/generated-src/err_data.c b/generated-src/err_data.c index 957d14637c..2e69d3f54c 100644 --- a/generated-src/err_data.c +++ b/generated-src/err_data.c @@ -76,54 +76,54 @@ const uint32_t kOpenSSLReasonValues[] = { 0xc3b00f7, 0xc3b8921, 0x10320892, - 0x10329981, - 0x1033198d, - 0x103399a6, - 0x103419b9, + 0x103299c2, + 0x103319ce, + 0x103399e7, + 0x103419fa, 0x10349064, 0x10350db0, - 0x103599cc, - 0x103619f6, - 0x10369a09, - 0x10371a28, - 0x10379a41, - 0x10381a56, - 0x10389a74, - 0x10391a83, - 0x10399a9f, - 0x103a1aba, - 0x103a9ac9, - 0x103b1ae5, - 0x103b9b00, - 0x103c1b26, + 0x10359a0d, + 0x10361a37, + 0x10369a4a, + 0x10371a69, + 0x10379a82, + 0x10381a97, + 0x10389ab5, + 0x10391ac4, + 0x10399ae0, + 0x103a1afb, + 0x103a9b0a, + 0x103b1b26, + 0x103b9b41, + 0x103c1b67, 0x103c80f7, - 0x103d1b37, - 0x103d9b4b, - 0x103e1b6a, - 0x103e9b79, - 0x103f1b90, - 0x103f9ba3, + 0x103d1b78, + 0x103d9b8c, + 0x103e1bab, + 0x103e9bba, + 0x103f1bd1, + 0x103f9be4, 0x10400d74, - 0x10409bb6, - 0x10411bd4, - 0x10419be7, - 0x10421c01, - 0x10429c11, - 0x10431c25, - 0x10439c3b, - 0x10441c53, - 0x10449c68, - 0x10451c7c, - 0x10459c8e, + 0x10409bf7, + 0x10411c15, + 0x10419c28, + 0x10421c42, + 0x10429c52, + 0x10431c66, + 0x10439c7c, + 0x10441c94, + 0x10449ca9, + 0x10451cbd, + 0x10459ccf, 0x10460635, 0x1046899a, - 0x10471ca3, - 0x10479cba, - 0x10481ccf, - 0x10489cdd, + 0x10471ce4, + 0x10479cfb, + 0x10481d10, + 0x10489d1e, 0x10490fb0, - 0x10499b17, - 0x104a19e1, + 0x10499b58, + 0x104a1a22, 0x107c1072, 0x14320d38, 0x14328d65, @@ -175,24 +175,24 @@ const uint32_t kOpenSSLReasonValues[] = { 0x18fa1201, 0x18fa9224, 0x18fb1239, - 0x203213a9, - 0x20329396, - 0x243215b7, + 0x203213ea, + 0x203293d7, + 0x243215f8, 0x243289f2, - 0x243315c9, - 0x243395d6, - 0x243415e3, - 0x243495f5, - 0x24351604, - 0x24359621, - 0x2436162e, - 0x2436963c, - 0x2437164a, - 0x24379672, - 0x2438167b, - 0x24389688, - 0x2439169b, - 0x24399658, + 0x2433160a, + 0x24339617, + 0x24341624, + 0x24349636, + 0x24351645, + 0x24359662, + 0x2436166f, + 0x2436967d, + 0x2437168b, + 0x243796b3, + 0x243816bc, + 0x243896c9, + 0x243916dc, + 0x24399699, 0x28320da4, 0x28328dbc, 0x28330d74, @@ -202,52 +202,52 @@ const uint32_t kOpenSSLReasonValues[] = { 0x283500f7, 0x28358d52, 0x2836099a, - 0x2c32370c, - 0x2c3296b2, - 0x2c33371a, - 0x2c33b72c, - 0x2c343740, - 0x2c34b752, - 0x2c35376d, - 0x2c35b77f, - 0x2c3637af, + 0x2c32374d, + 0x2c3296f3, + 0x2c33375b, + 0x2c33b76d, + 0x2c343781, + 0x2c34b793, + 0x2c3537ae, + 0x2c35b7c0, + 0x2c3637f0, 0x2c36833a, - 0x2c3737bc, - 0x2c37b7e8, - 0x2c383826, - 0x2c38b83d, - 0x2c39385b, - 0x2c39b86b, - 0x2c3a387d, - 0x2c3ab891, - 0x2c3b38a2, - 0x2c3bb8c1, - 0x2c3c16c4, - 0x2c3c96da, - 0x2c3d3906, - 0x2c3d96f3, - 0x2c3e3930, - 0x2c3eb93e, - 0x2c3f3956, - 0x2c3fb96e, - 0x2c403998, - 0x2c4093a9, - 0x2c4139a9, - 0x2c41b9cf, + 0x2c3737fd, + 0x2c37b829, + 0x2c383867, + 0x2c38b87e, + 0x2c39389c, + 0x2c39b8ac, + 0x2c3a38be, + 0x2c3ab8d2, + 0x2c3b38e3, + 0x2c3bb902, + 0x2c3c1705, + 0x2c3c971b, + 0x2c3d3947, + 0x2c3d9734, + 0x2c3e3971, + 0x2c3eb97f, + 0x2c3f3997, + 0x2c3fb9af, + 0x2c4039d9, + 0x2c4093ea, + 0x2c4139ea, + 0x2c41ba10, 0x2c42136f, - 0x2c42b9e0, + 0x2c42ba21, 0x2c43076d, - 0x2c43b8b3, - 0x2c4437fb, - 0x2c44b97b, - 0x2c453792, - 0x2c45b7ce, - 0x2c46384b, - 0x2c46b8d5, - 0x2c4738ea, - 0x2c47b923, - 0x2c48380d, - 0x2c48b9bc, + 0x2c43b8f4, + 0x2c44383c, + 0x2c44b9bc, + 0x2c4537d3, + 0x2c45b80f, + 0x2c46388c, + 0x2c46b916, + 0x2c47392b, + 0x2c47b964, + 0x2c48384e, + 0x2c48b9fd, 0x30320000, 0x30328015, 0x3033001f, @@ -387,269 +387,269 @@ const uint32_t kOpenSSLReasonValues[] = { 0x3c418ea4, 0x3c420fb0, 0x3c428f3a, - 0x40321d6f, - 0x40329d85, - 0x40331db3, - 0x40339dbd, - 0x40341dd4, - 0x40349df2, - 0x40351e02, - 0x40359e14, - 0x40361e21, - 0x40369e2d, - 0x40371e42, - 0x40379e7b, - 0x40381e86, - 0x40389e98, + 0x40321db0, + 0x40329dc6, + 0x40331df4, + 0x40339dfe, + 0x40341e15, + 0x40349e33, + 0x40351e43, + 0x40359e55, + 0x40361e62, + 0x40369e6e, + 0x40371e83, + 0x40379ebc, + 0x40381ec7, + 0x40389ed9, 0x40391064, - 0x40399ea8, - 0x403a1ebb, - 0x403a9edc, - 0x403b1eed, - 0x403b9efd, + 0x40399ee9, + 0x403a1efc, + 0x403a9f1d, + 0x403b1f2e, + 0x403b9f3e, 0x403c0071, 0x403c8090, - 0x403d1f5e, - 0x403d9f74, - 0x403e1f83, - 0x403e9fbb, - 0x403f1fd5, - 0x403f9ffd, - 0x40402012, - 0x4040a026, - 0x40412061, - 0x4041a07c, - 0x40422095, - 0x4042a0a8, - 0x404320bc, - 0x4043a0ea, - 0x40442101, + 0x403d1f9f, + 0x403d9fb5, + 0x403e1fc4, + 0x403e9ffc, + 0x403f2016, + 0x403fa03e, + 0x40402053, + 0x4040a067, + 0x404120a2, + 0x4041a0bd, + 0x404220d6, + 0x4042a0e9, + 0x404320fd, + 0x4043a12b, + 0x40442142, 0x404480b9, - 0x40452116, - 0x4045a128, - 0x4046214c, - 0x4046a16c, - 0x4047217a, - 0x4047a1a1, - 0x40482212, - 0x4048a2cc, - 0x404922e3, - 0x4049a2fd, - 0x404a2314, - 0x404aa332, - 0x404b234a, - 0x404ba377, - 0x404c238d, - 0x404ca39f, - 0x404d23c0, - 0x404da3f9, - 0x404e240d, - 0x404ea41a, - 0x404f24cb, - 0x404fa541, - 0x405025b0, - 0x4050a5c4, - 0x405125f7, - 0x40522607, - 0x4052a62b, - 0x40532643, - 0x4053a656, - 0x4054266b, - 0x4054a68e, - 0x405526b9, - 0x4055a6f6, - 0x4056271b, - 0x4056a734, - 0x4057274c, - 0x4057a75f, - 0x40582774, - 0x4058a79b, - 0x405927ca, - 0x4059a7f7, - 0x405aa80b, - 0x405b2823, - 0x405ba834, - 0x405c2847, - 0x405ca886, - 0x405d2893, - 0x405da8b8, - 0x405e28f6, + 0x40452157, + 0x4045a169, + 0x4046218d, + 0x4046a1ad, + 0x404721bb, + 0x4047a1e2, + 0x40482253, + 0x4048a30d, + 0x40492324, + 0x4049a33e, + 0x404a2355, + 0x404aa373, + 0x404b238b, + 0x404ba3b8, + 0x404c23ce, + 0x404ca3e0, + 0x404d2401, + 0x404da43a, + 0x404e244e, + 0x404ea45b, + 0x404f250c, + 0x404fa582, + 0x405025f1, + 0x4050a605, + 0x40512638, + 0x40522648, + 0x4052a66c, + 0x40532684, + 0x4053a697, + 0x405426ac, + 0x4054a6cf, + 0x405526fa, + 0x4055a737, + 0x4056275c, + 0x4056a775, + 0x4057278d, + 0x4057a7a0, + 0x405827b5, + 0x4058a7dc, + 0x4059280b, + 0x4059a838, + 0x405aa84c, + 0x405b2864, + 0x405ba875, + 0x405c2888, + 0x405ca8c7, + 0x405d28d4, + 0x405da8f9, + 0x405e2937, 0x405e8b2d, - 0x405f2917, - 0x405fa924, - 0x40602932, - 0x4060a954, - 0x406129b5, - 0x4061a9ed, - 0x40622a04, - 0x4062aa15, - 0x40632a62, - 0x4063aa77, - 0x40642a8e, - 0x4064aaba, - 0x40652ad5, - 0x4065aaec, - 0x40662b04, - 0x4066ab2e, - 0x40672b59, - 0x4067ac5c, - 0x40682ca4, - 0x4068acc5, - 0x40692cf7, - 0x4069ad25, - 0x406a2d46, - 0x406aad66, - 0x406b2eee, - 0x406baf11, - 0x406c2f27, - 0x406cb231, - 0x406d3260, - 0x406db288, - 0x406e32b6, - 0x406eb303, - 0x406f335c, - 0x406fb394, - 0x407033a7, - 0x4070b3c4, + 0x405f2958, + 0x405fa965, + 0x40602973, + 0x4060a995, + 0x406129f6, + 0x4061aa2e, + 0x40622a45, + 0x4062aa56, + 0x40632aa3, + 0x4063aab8, + 0x40642acf, + 0x4064aafb, + 0x40652b16, + 0x4065ab2d, + 0x40662b45, + 0x4066ab6f, + 0x40672b9a, + 0x4067ac9d, + 0x40682ce5, + 0x4068ad06, + 0x40692d38, + 0x4069ad66, + 0x406a2d87, + 0x406aada7, + 0x406b2f2f, + 0x406baf52, + 0x406c2f68, + 0x406cb272, + 0x406d32a1, + 0x406db2c9, + 0x406e32f7, + 0x406eb344, + 0x406f339d, + 0x406fb3d5, + 0x407033e8, + 0x4070b405, 0x4071084d, - 0x4071b3d6, - 0x407233e9, - 0x4072b41f, - 0x40733437, - 0x407398dc, - 0x4074344b, - 0x4074b465, - 0x40753476, - 0x4075b48a, - 0x40763498, - 0x40769688, - 0x407734bd, - 0x4077b4fd, - 0x40783518, - 0x4078b551, - 0x40793568, - 0x4079b57e, - 0x407a35aa, - 0x407ab5bd, - 0x407b35d2, - 0x407bb5e4, - 0x407c3615, - 0x407cb61e, - 0x407d2ce0, - 0x407da569, - 0x407e352d, - 0x407ea7ab, - 0x407f218e, - 0x407fa361, - 0x408024db, - 0x4080a1b6, - 0x40812619, - 0x4081a468, - 0x408232a1, - 0x40829f09, - 0x40832786, - 0x4083aa9f, - 0x408421ca, - 0x4084a7e3, - 0x40852858, - 0x4085a97c, - 0x408628d8, - 0x4086a583, - 0x408732e7, - 0x4087a9ca, - 0x40881f47, - 0x4088ac6f, - 0x40891f96, - 0x40899f23, - 0x408a2f5f, - 0x408a9cf4, - 0x408b35f9, - 0x408bb371, - 0x408c2868, - 0x408c9d2c, - 0x408d22b2, - 0x408da1fc, - 0x408e23e2, - 0x408ea6d6, - 0x408f2c83, - 0x408fa998, - 0x40902b7a, - 0x4090a8aa, - 0x40912f47, - 0x40919d52, - 0x40921fe3, - 0x4092b322, - 0x40933402, - 0x4093a594, - 0x409421de, - 0x4094af78, - 0x40952a26, - 0x4095b58a, - 0x409632ce, - 0x4096a4f4, - 0x409725df, - 0x4097a431, - 0x40982043, - 0x4098aa3a, - 0x4099333e, - 0x4099a703, - 0x409a269c, - 0x409a9d10, - 0x409b2238, - 0x409ba263, - 0x409c34df, - 0x409ca28b, - 0x409d24b0, - 0x409da47e, - 0x409e20d4, - 0x409ea529, - 0x409f2511, - 0x409fa22b, - 0x40a02551, - 0x40a0a44b, - 0x40a12499, - 0x40fa2c42, - 0x40faab9e, - 0x40fb2c21, - 0x40fbabb8, - 0x40fcac00, - 0x40fd2bd9, - 0x40fd9e54, - 0x40fe1e68, - 0x41f42e19, - 0x41f92eab, - 0x41fe2d9e, - 0x41feb054, - 0x41ff3182, - 0x42032e32, - 0x42082e54, - 0x4208ae90, - 0x42092d82, - 0x4209aeca, - 0x420a2dd9, - 0x420aadb9, - 0x420b2df9, - 0x420bae72, - 0x420c319e, - 0x420caf88, - 0x420d303b, - 0x420db072, - 0x421230a5, - 0x42173165, - 0x4217b0e7, - 0x421c3109, - 0x421f30c4, - 0x42213216, - 0x42263148, - 0x422b31f4, - 0x422bb016, - 0x422c31d6, - 0x422cafc9, - 0x422d2fa2, - 0x422db1b5, - 0x422e2ff5, - 0x42303124, - 0x4230b08c, + 0x4071b417, + 0x4072342a, + 0x4072b460, + 0x40733478, + 0x4073991d, + 0x4074348c, + 0x4074b4a6, + 0x407534b7, + 0x4075b4cb, + 0x407634d9, + 0x407696c9, + 0x407734fe, + 0x4077b53e, + 0x40783559, + 0x4078b592, + 0x407935a9, + 0x4079b5bf, + 0x407a35eb, + 0x407ab5fe, + 0x407b3613, + 0x407bb625, + 0x407c3656, + 0x407cb65f, + 0x407d2d21, + 0x407da5aa, + 0x407e356e, + 0x407ea7ec, + 0x407f21cf, + 0x407fa3a2, + 0x4080251c, + 0x4080a1f7, + 0x4081265a, + 0x4081a4a9, + 0x408232e2, + 0x40829f4a, + 0x408327c7, + 0x4083aae0, + 0x4084220b, + 0x4084a824, + 0x40852899, + 0x4085a9bd, + 0x40862919, + 0x4086a5c4, + 0x40873328, + 0x4087aa0b, + 0x40881f88, + 0x4088acb0, + 0x40891fd7, + 0x40899f64, + 0x408a2fa0, + 0x408a9d35, + 0x408b363a, + 0x408bb3b2, + 0x408c28a9, + 0x408c9d6d, + 0x408d22f3, + 0x408da23d, + 0x408e2423, + 0x408ea717, + 0x408f2cc4, + 0x408fa9d9, + 0x40902bbb, + 0x4090a8eb, + 0x40912f88, + 0x40919d93, + 0x40922024, + 0x4092b363, + 0x40933443, + 0x4093a5d5, + 0x4094221f, + 0x4094afb9, + 0x40952a67, + 0x4095b5cb, + 0x4096330f, + 0x4096a535, + 0x40972620, + 0x4097a472, + 0x40982084, + 0x4098aa7b, + 0x4099337f, + 0x4099a744, + 0x409a26dd, + 0x409a9d51, + 0x409b2279, + 0x409ba2a4, + 0x409c3520, + 0x409ca2cc, + 0x409d24f1, + 0x409da4bf, + 0x409e2115, + 0x409ea56a, + 0x409f2552, + 0x409fa26c, + 0x40a02592, + 0x40a0a48c, + 0x40a124da, + 0x40fa2c83, + 0x40faabdf, + 0x40fb2c62, + 0x40fbabf9, + 0x40fcac41, + 0x40fd2c1a, + 0x40fd9e95, + 0x40fe1ea9, + 0x41f42e5a, + 0x41f92eec, + 0x41fe2ddf, + 0x41feb095, + 0x41ff31c3, + 0x42032e73, + 0x42082e95, + 0x4208aed1, + 0x42092dc3, + 0x4209af0b, + 0x420a2e1a, + 0x420aadfa, + 0x420b2e3a, + 0x420baeb3, + 0x420c31df, + 0x420cafc9, + 0x420d307c, + 0x420db0b3, + 0x421230e6, + 0x421731a6, + 0x4217b128, + 0x421c314a, + 0x421f3105, + 0x42213257, + 0x42263189, + 0x422b3235, + 0x422bb057, + 0x422c3217, + 0x422cb00a, + 0x422d2fe3, + 0x422db1f6, + 0x422e3036, + 0x42303165, + 0x4230b0cd, 0x42310b85, 0x44320778, 0x44328787, @@ -668,133 +668,133 @@ const uint32_t kOpenSSLReasonValues[] = { 0x4439084d, 0x4439885b, 0x443a086e, - 0x483216b2, - 0x483296c4, - 0x483316da, - 0x483396f3, - 0x4c321730, - 0x4c329740, - 0x4c331753, - 0x4c339773, + 0x483216f3, + 0x48329705, + 0x4833171b, + 0x48339734, + 0x4c321771, + 0x4c329781, + 0x4c331794, + 0x4c3397b4, 0x4c3400b9, 0x4c3480f7, - 0x4c35177f, - 0x4c35978d, - 0x4c3617a9, - 0x4c3697cf, - 0x4c3717de, - 0x4c3797ec, - 0x4c381801, - 0x4c38980d, - 0x4c39182d, - 0x4c399857, - 0x4c3a1870, - 0x4c3a9889, + 0x4c3517c0, + 0x4c3597ce, + 0x4c3617ea, + 0x4c369810, + 0x4c37181f, + 0x4c37982d, + 0x4c381842, + 0x4c38984e, + 0x4c39186e, + 0x4c399898, + 0x4c3a18b1, + 0x4c3a98ca, 0x4c3b0635, - 0x4c3b98a2, - 0x4c3c18b4, - 0x4c3c98c3, - 0x4c3d18dc, + 0x4c3b98e3, + 0x4c3c18f5, + 0x4c3c9904, + 0x4c3d191d, 0x4c3d8d97, - 0x4c3e1949, - 0x4c3e98eb, - 0x4c3f196b, - 0x4c3f9688, - 0x4c401901, - 0x4c40971c, - 0x4c411939, - 0x4c4197bc, - 0x4c421925, - 0x4c429704, - 0x503239f2, - 0x5032ba01, - 0x50333a0c, - 0x5033ba1c, - 0x50343a35, - 0x5034ba4f, - 0x50353a5d, - 0x5035ba73, - 0x50363a85, - 0x5036ba9b, - 0x50373ab4, - 0x5037bac7, - 0x50383adf, - 0x5038baf0, - 0x50393b05, - 0x5039bb19, - 0x503a3b39, - 0x503abb4f, - 0x503b3b67, - 0x503bbb79, - 0x503c3b95, - 0x503cbbac, - 0x503d3bc5, - 0x503dbbdb, - 0x503e3be8, - 0x503ebbfe, - 0x503f3c10, + 0x4c3e198a, + 0x4c3e992c, + 0x4c3f19ac, + 0x4c3f96c9, + 0x4c401942, + 0x4c40975d, + 0x4c41197a, + 0x4c4197fd, + 0x4c421966, + 0x4c429745, + 0x50323a33, + 0x5032ba42, + 0x50333a4d, + 0x5033ba5d, + 0x50343a76, + 0x5034ba90, + 0x50353a9e, + 0x5035bab4, + 0x50363ac6, + 0x5036badc, + 0x50373af5, + 0x5037bb08, + 0x50383b20, + 0x5038bb31, + 0x50393b46, + 0x5039bb5a, + 0x503a3b7a, + 0x503abb90, + 0x503b3ba8, + 0x503bbbba, + 0x503c3bd6, + 0x503cbbed, + 0x503d3c06, + 0x503dbc1c, + 0x503e3c29, + 0x503ebc3f, + 0x503f3c51, 0x503f83b3, - 0x50403c23, - 0x5040bc33, - 0x50413c4d, - 0x5041bc5c, - 0x50423c76, - 0x5042bc93, - 0x50433ca3, - 0x5043bcb3, - 0x50443cd0, + 0x50403c64, + 0x5040bc74, + 0x50413c8e, + 0x5041bc9d, + 0x50423cb7, + 0x5042bcd4, + 0x50433ce4, + 0x5043bcf4, + 0x50443d11, 0x50448469, - 0x50453ce4, - 0x5045bd02, - 0x50463d15, - 0x5046bd2b, - 0x50473d3d, - 0x5047bd52, - 0x50483d78, - 0x5048bd86, - 0x50493d99, - 0x5049bdae, - 0x504a3dc4, - 0x504abdd4, - 0x504b3df4, - 0x504bbe07, - 0x504c3e2a, - 0x504cbe58, - 0x504d3e85, - 0x504dbea2, - 0x504e3ebd, - 0x504ebed9, - 0x504f3eeb, - 0x504fbf02, - 0x50503f11, + 0x50453d25, + 0x5045bd43, + 0x50463d56, + 0x5046bd6c, + 0x50473d7e, + 0x5047bd93, + 0x50483db9, + 0x5048bdc7, + 0x50493dda, + 0x5049bdef, + 0x504a3e05, + 0x504abe15, + 0x504b3e35, + 0x504bbe48, + 0x504c3e6b, + 0x504cbe99, + 0x504d3ec6, + 0x504dbee3, + 0x504e3efe, + 0x504ebf1a, + 0x504f3f2c, + 0x504fbf43, + 0x50503f52, 0x50508729, - 0x50513f24, - 0x5051bcc2, - 0x50523e6a, + 0x50513f65, + 0x5051bd03, + 0x50523eab, 0x583210b7, - 0x5c3293b5, - 0x5c3313ce, - 0x5c33941f, - 0x5c341456, - 0x5c349469, - 0x5c361482, - 0x5c3714c2, - 0x5c3794e9, - 0x5c38150e, - 0x5c399522, - 0x5c3a953e, - 0x5c3b1550, - 0x5c3b95a0, - 0x5c3c13a9, - 0x5c3c940d, - 0x5c3d13d9, - 0x5c3d93f3, - 0x5c3e1439, - 0x5c3e956d, - 0x5c3f157c, - 0x5c3f9591, - 0x5c411493, - 0x5c4194a1, + 0x5c3293f6, + 0x5c33140f, + 0x5c339460, + 0x5c341497, + 0x5c3494aa, + 0x5c3614c3, + 0x5c371503, + 0x5c37952a, + 0x5c38154f, + 0x5c399563, + 0x5c3a957f, + 0x5c3b1591, + 0x5c3b95e1, + 0x5c3c13ea, + 0x5c3c944e, + 0x5c3d141a, + 0x5c3d9434, + 0x5c3e147a, + 0x5c3e95ae, + 0x5c3f15bd, + 0x5c3f95d2, + 0x5c4114d4, + 0x5c4194e2, 0x68321064, 0x68328dbc, 0x68330dcf, @@ -807,6 +807,10 @@ const uint32_t kOpenSSLReasonValues[] = { 0x6c328d86, 0x6c331035, 0x6c33904e, + 0x70320dbc, + 0x70330090, + 0x703393b1, + 0x70341396, 0x74320a95, 0x743280b9, 0x74330d97, @@ -844,21 +848,21 @@ const uint32_t kOpenSSLReasonValues[] = { 0x78478b85, 0x78480b42, 0x7c321385, - 0x803217cf, + 0x80321810, 0x80328090, - 0x803336db, + 0x8033371c, 0x803380b9, - 0x803436ea, - 0x8034b652, - 0x80353670, - 0x8035b6fe, - 0x803636b2, - 0x8036b661, - 0x803736a4, - 0x8037b63f, - 0x803836c5, - 0x8038b681, - 0x80393696, + 0x8034372b, + 0x8034b693, + 0x803536b1, + 0x8035b73f, + 0x803636f3, + 0x8036b6a2, + 0x803736e5, + 0x8037b680, + 0x80383706, + 0x8038b6c2, + 0x803936d7, }; const size_t kOpenSSLReasonValuesLen = sizeof(kOpenSSLReasonValues) / sizeof(kOpenSSLReasonValues[0]); @@ -1120,6 +1124,8 @@ const char kOpenSSLReasonStringData[] = "UNKNOWN_PUBLIC_KEY_TYPE\0" "UNSUPPORTED_ALGORITHM\0" "OUTPUT_TOO_LARGE\0" + "NOT_CALLED_JUST_AFTER_INIT\0" + "SET_PRECOMPUTED_KEY_EXPORT_NOT_CALLED\0" "INVALID_OID_STRING\0" "UNKNOWN_NID\0" "CERTIFICATE_VERIFY_ERROR\0" From cd102d61e5dd9023f59b47d8439e097048a2250c Mon Sep 17 00:00:00 2001 From: Fabrice Benhamouda Date: Thu, 18 Jul 2024 16:27:40 -0400 Subject: [PATCH 26/26] Fix Windows ARM64 compilation + comment improvements From review from PR aws/aws-lc#1574 --- crypto/fipsmodule/hmac/hmac.c | 5 ++++- crypto/fipsmodule/sha/internal.h | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/crypto/fipsmodule/hmac/hmac.c b/crypto/fipsmodule/hmac/hmac.c index 5dc9af2d3f..4b9ca9ac99 100644 --- a/crypto/fipsmodule/hmac/hmac.c +++ b/crypto/fipsmodule/hmac/hmac.c @@ -528,7 +528,10 @@ int HMAC_get_precomputed_key(HMAC_CTX *ctx, uint8_t *out, size_t *out_len) { *out_len = actual_out_len; uint64_t i_ctx_n; - uint64_t o_ctx_n; + // Initializing o_ctx_n to zero to remove warning from Windows ARM64 compiler + // "error : variable 'o_ctx_n' is used uninitialized whenever '&&' condition + // is false". Note this should not be necessary because get_state cannot fail. + uint64_t o_ctx_n = 0; const int ok = ctx->methods->get_state(&ctx->i_ctx, out, &i_ctx_n) && ctx->methods->get_state(&ctx->o_ctx, out + chaining_length, &o_ctx_n); diff --git a/crypto/fipsmodule/sha/internal.h b/crypto/fipsmodule/sha/internal.h index e07bbd11f0..f782a15edc 100644 --- a/crypto/fipsmodule/sha/internal.h +++ b/crypto/fipsmodule/sha/internal.h @@ -128,12 +128,12 @@ OPENSSL_EXPORT int SHA512_256_Init_from_state( SHA512_CTX *sha, const uint8_t h[SHA512_256_CHAINING_LENGTH], uint64_t n); // SHAx_get_state is a low-level function that exports the hash state in big -// endian into |out_n| and the number of bits processed at this point in +// endian into |out_h| and the number of bits processed at this point in // |out_n|. |SHAx_Final| must not have been called before (otherwise results // are not guaranteed). Furthermore, the number of bytes processed by // |SHAx_Update| must be a multiple of the block length |SHAy_CBLOCK| and // must be less than 2^61 (otherwise it fails). See comment above about -// SHAx_Init_from_state for the definition of SHAy. +// |SHAx_Init_from_state| for the definition of SHAy. // This function returns one on success and zero on error. // This function is for internal use only and should never be directly called. OPENSSL_EXPORT int SHA1_get_state(