Extract SHA224/256 from bcm Change-Id: I953441ccf99321184a5b664cc446551fa5e295b4 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/70947 Reviewed-by: David Benjamin <davidben@google.com> Commit-Queue: Bob Beck <bbe@google.com>
diff --git a/build.json b/build.json index 23c0634..2e675d8 100644 --- a/build.json +++ b/build.json
@@ -303,6 +303,7 @@ "crypto/rsa_extra/rsa_crypt.c", "crypto/rsa_extra/rsa_print.c", "crypto/sha/sha1.c", + "crypto/sha/sha256.c", "crypto/siphash/siphash.c", "crypto/slhdsa/fors.c", "crypto/slhdsa/merkle.c",
diff --git a/crypto/fipsmodule/bcm.c b/crypto/fipsmodule/bcm.c index 81e03cb..55375ea 100644 --- a/crypto/fipsmodule/bcm.c +++ b/crypto/fipsmodule/bcm.c
@@ -194,7 +194,7 @@ assert_within(start, RSA_sign, end); assert_within(start, BCM_rand_bytes, end); assert_within(start, EC_GROUP_cmp, end); - assert_within(start, SHA256_Update, end); + assert_within(start, BCM_sha256_update, end); assert_within(start, ecdsa_verify_fixed, end); assert_within(start, EVP_AEAD_CTX_seal, end);
diff --git a/crypto/fipsmodule/bcm_interface.h b/crypto/fipsmodule/bcm_interface.h index 8c07281..222a9db 100644 --- a/crypto/fipsmodule/bcm_interface.h +++ b/crypto/fipsmodule/bcm_interface.h
@@ -98,7 +98,8 @@ // BCM_SHA1_transform is a low-level function that performs a single, SHA-1 // block transformation using the state from |sha| and |SHA_CBLOCK| bytes from // |block|. -bcm_infallible BCM_sha1_transform(SHA_CTX *c, const uint8_t data[BCM_SHA_CBLOCK]); +bcm_infallible BCM_sha1_transform(SHA_CTX *c, + const uint8_t data[BCM_SHA_CBLOCK]); // BCM_sha1_update adds |len| bytes from |data| to |sha|. bcm_infallible BCM_sha1_update(SHA_CTX *c, const void *data, size_t len); @@ -125,6 +126,55 @@ const uint8_t xkey[BCM_SHA_DIGEST_LENGTH]); +// SHA-224 + +// SHA224_DIGEST_LENGTH is the length of a SHA-224 digest. +#define BCM_SHA224_DIGEST_LENGTH 28 + +// BCM_sha224_unit initialises |sha|. +bcm_infallible BCM_sha224_init(SHA256_CTX *sha); + +// BCM_sha224_update adds |len| bytes from |data| to |sha|. +bcm_infallible BCM_sha224_update(SHA256_CTX *sha, const void *data, size_t len); + +// BCM_sha224_Final adds the final padding to |sha| and writes the resulting +// digest to |out|, which must have at least |SHA224_DIGEST_LENGTH| bytes of +// space. It aborts on programmer error. +bcm_infallible BCM_sha224_final(uint8_t out[BCM_SHA224_DIGEST_LENGTH], + SHA256_CTX *sha); + + +// SHA-256 + +// BCM_SHA256_DIGEST_LENGTH is the length of a SHA-256 digest. +#define BCM_SHA256_DIGEST_LENGTH 32 + +// BCM_sha256_init initialises |sha|. +bcm_infallible BCM_sha256_init(SHA256_CTX *sha); + +// BCM_sha256_update adds |len| bytes from |data| to |sha|. +bcm_infallible BCM_sha256_update(SHA256_CTX *sha, const void *data, size_t len); + +// BCM_sha256_final adds the final padding to |sha| and writes the resulting +// digest to |out|, which must have at least |BCM_SHA256_DIGEST_LENGTH| bytes of +// space. It aborts on programmer error. +bcm_infallible BCM_sha256_final(uint8_t out[BCM_SHA256_DIGEST_LENGTH], + SHA256_CTX *sha); + +// BCM_sha256_transform is a low-level function that performs a single, SHA-256 +// block transformation using the state from |sha| and |BCM_SHA256_CBLOCK| bytes +// from |block|. +bcm_infallible BCM_sha256_transform(SHA256_CTX *sha, + const uint8_t block[BCM_SHA256_CBLOCK]); + +// BCM_sha256_transform_blocks is a low-level function that takes |num_blocks| * +// |BCM_SHA256_CBLOCK| bytes of data and performs SHA-256 transforms on it to +// update |state|. +bcm_infallible BCM_sha256_transform_blocks(uint32_t state[8], + const uint8_t *data, + size_t num_blocks); + + #if defined(__cplusplus) } // extern C #endif
diff --git a/crypto/fipsmodule/digest/digests.c.inc b/crypto/fipsmodule/digest/digests.c.inc index 4773a23..216af52 100644 --- a/crypto/fipsmodule/digest/digests.c.inc +++ b/crypto/fipsmodule/digest/digests.c.inc
@@ -98,20 +98,20 @@ static void sha224_init(EVP_MD_CTX *ctx) { - CHECK(SHA224_Init(ctx->md_data)); + BCM_sha224_init(ctx->md_data); } static void sha224_update(EVP_MD_CTX *ctx, const void *data, size_t count) { - CHECK(SHA224_Update(ctx->md_data, data, count)); + BCM_sha224_update(ctx->md_data, data, count); } static void sha224_final(EVP_MD_CTX *ctx, uint8_t *md) { - CHECK(SHA224_Final(md, ctx->md_data)); + BCM_sha224_final(md, ctx->md_data); } DEFINE_METHOD_FUNCTION(EVP_MD, EVP_sha224) { out->type = NID_sha224; - out->md_size = SHA224_DIGEST_LENGTH; + out->md_size = BCM_SHA224_DIGEST_LENGTH; out->flags = 0; out->init = sha224_init; out->update = sha224_update; @@ -122,20 +122,20 @@ static void sha256_init(EVP_MD_CTX *ctx) { - CHECK(SHA256_Init(ctx->md_data)); + BCM_sha256_init(ctx->md_data); } static void sha256_update(EVP_MD_CTX *ctx, const void *data, size_t count) { - CHECK(SHA256_Update(ctx->md_data, data, count)); + BCM_sha256_update(ctx->md_data, data, count); } static void sha256_final(EVP_MD_CTX *ctx, uint8_t *md) { - CHECK(SHA256_Final(md, ctx->md_data)); + BCM_sha256_final(md, ctx->md_data); } DEFINE_METHOD_FUNCTION(EVP_MD, EVP_sha256) { out->type = NID_sha256; - out->md_size = SHA256_DIGEST_LENGTH; + out->md_size = BCM_SHA256_DIGEST_LENGTH; out->flags = 0; out->init = sha256_init; out->update = sha256_update;
diff --git a/crypto/fipsmodule/ec/ec_key.c.inc b/crypto/fipsmodule/ec/ec_key.c.inc index 1eef021..376fa65 100644 --- a/crypto/fipsmodule/ec/ec_key.c.inc +++ b/crypto/fipsmodule/ec/ec_key.c.inc
@@ -75,7 +75,6 @@ #include <openssl/err.h> #include <openssl/ex_data.h> #include <openssl/mem.h> -#include <openssl/sha.h> #include <openssl/thread.h> #include "internal.h" @@ -346,7 +345,7 @@ } if (key->priv_key) { - uint8_t digest[SHA256_DIGEST_LENGTH] = {0}; + uint8_t digest[BCM_SHA256_DIGEST_LENGTH] = {0}; uint8_t sig[ECDSA_MAX_FIXED_LEN]; size_t sig_len; if (!ecdsa_sign_fixed(digest, sizeof(digest), sig, &sig_len, sizeof(sig),
diff --git a/crypto/fipsmodule/ecdh/ecdh.c.inc b/crypto/fipsmodule/ecdh/ecdh.c.inc index eeb591f..d16c3c1 100644 --- a/crypto/fipsmodule/ecdh/ecdh.c.inc +++ b/crypto/fipsmodule/ecdh/ecdh.c.inc
@@ -105,12 +105,19 @@ } FIPS_service_indicator_lock_state(); + SHA256_CTX ctx; switch (out_len) { case SHA224_DIGEST_LENGTH: - SHA224(buf, buflen, out); + BCM_sha224_init(&ctx); + BCM_sha224_update(&ctx, buf, buflen); + BCM_sha224_final(out, &ctx); + OPENSSL_cleanse(&ctx, sizeof(ctx)); break; case SHA256_DIGEST_LENGTH: - SHA256(buf, buflen, out); + BCM_sha256_init(&ctx); + BCM_sha256_update(&ctx, buf, buflen); + BCM_sha256_final(out, &ctx); + OPENSSL_cleanse(&ctx, sizeof(ctx)); break; case SHA384_DIGEST_LENGTH: SHA384(buf, buflen, out);
diff --git a/crypto/fipsmodule/rsa/rsa.c.inc b/crypto/fipsmodule/rsa/rsa.c.inc index 9b97655..8cb6c5d 100644 --- a/crypto/fipsmodule/rsa/rsa.c.inc +++ b/crypto/fipsmodule/rsa/rsa.c.inc
@@ -487,14 +487,14 @@ }, { NID_sha224, - SHA224_DIGEST_LENGTH, + BCM_SHA224_DIGEST_LENGTH, 19, {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1c}, }, { NID_sha256, - SHA256_DIGEST_LENGTH, + BCM_SHA256_DIGEST_LENGTH, 19, {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20},
diff --git a/crypto/fipsmodule/sha/sha256.c.inc b/crypto/fipsmodule/sha/sha256.c.inc index b7c616b..91188ab 100644 --- a/crypto/fipsmodule/sha/sha256.c.inc +++ b/crypto/fipsmodule/sha/sha256.c.inc
@@ -54,19 +54,18 @@ * copied and put under another distribution licence * [including the GNU Public Licence.] */ -#include <openssl/sha.h> - #include <string.h> #include <openssl/mem.h> #include "../../internal.h" +#include "../bcm_interface.h" #include "../digest/md32_common.h" #include "../service_indicator/internal.h" #include "internal.h" -int SHA224_Init(SHA256_CTX *sha) { +bcm_infallible BCM_sha224_init(SHA256_CTX *sha) { OPENSSL_memset(sha, 0, sizeof(SHA256_CTX)); sha->h[0] = 0xc1059ed8UL; sha->h[1] = 0x367cd507UL; @@ -76,11 +75,11 @@ sha->h[5] = 0x68581511UL; sha->h[6] = 0x64f98fa7UL; sha->h[7] = 0xbefa4fa4UL; - sha->md_len = SHA224_DIGEST_LENGTH; - return 1; + sha->md_len = BCM_SHA224_DIGEST_LENGTH; + return bcm_infallible_approved; } -int SHA256_Init(SHA256_CTX *sha) { +bcm_infallible BCM_sha256_init(SHA256_CTX *sha) { OPENSSL_memset(sha, 0, sizeof(SHA256_CTX)); sha->h[0] = 0x6a09e667UL; sha->h[1] = 0xbb67ae85UL; @@ -90,28 +89,8 @@ sha->h[5] = 0x9b05688cUL; sha->h[6] = 0x1f83d9abUL; sha->h[7] = 0x5be0cd19UL; - sha->md_len = SHA256_DIGEST_LENGTH; - return 1; -} - -uint8_t *SHA224(const uint8_t *data, size_t len, - uint8_t out[SHA224_DIGEST_LENGTH]) { - SHA256_CTX ctx; - SHA224_Init(&ctx); - SHA224_Update(&ctx, data, len); - SHA224_Final(out, &ctx); - OPENSSL_cleanse(&ctx, sizeof(ctx)); - return out; -} - -uint8_t *SHA256(const uint8_t *data, size_t len, - uint8_t out[SHA256_DIGEST_LENGTH]) { - SHA256_CTX ctx; - SHA256_Init(&ctx); - SHA256_Update(&ctx, data, len); - SHA256_Final(out, &ctx); - OPENSSL_cleanse(&ctx, sizeof(ctx)); - return out; + sha->md_len = BCM_SHA256_DIGEST_LENGTH; + return bcm_infallible_approved; } #if !defined(SHA256_ASM) @@ -119,31 +98,28 @@ size_t num); #endif -void SHA256_Transform(SHA256_CTX *c, const uint8_t data[SHA256_CBLOCK]) { +bcm_infallible BCM_sha256_transform(SHA256_CTX *c, + const uint8_t data[BCM_SHA256_CBLOCK]) { sha256_block_data_order(c->h, data, 1); + return bcm_infallible_approved; } -int SHA256_Update(SHA256_CTX *c, const void *data, size_t len) { - crypto_md32_update(&sha256_block_data_order, c->h, c->data, SHA256_CBLOCK, +bcm_infallible BCM_sha256_update(SHA256_CTX *c, const void *data, size_t len) { + crypto_md32_update(&sha256_block_data_order, c->h, c->data, BCM_SHA256_CBLOCK, &c->num, &c->Nh, &c->Nl, data, len); - return 1; + return bcm_infallible_approved; } -int SHA224_Update(SHA256_CTX *ctx, const void *data, size_t len) { - return SHA256_Update(ctx, data, len); +bcm_infallible BCM_sha224_update(SHA256_CTX *ctx, const void *data, + size_t len) { + return BCM_sha256_update(ctx, data, len); } -static int sha256_final_impl(uint8_t *out, size_t md_len, SHA256_CTX *c) { - crypto_md32_final(&sha256_block_data_order, c->h, c->data, SHA256_CBLOCK, +static void sha256_final_impl(uint8_t *out, size_t md_len, SHA256_CTX *c) { + crypto_md32_final(&sha256_block_data_order, c->h, c->data, BCM_SHA256_CBLOCK, &c->num, c->Nh, c->Nl, /*is_big_endian=*/1); - // TODO(davidben): This overflow check one of the few places a low-level hash - // 'final' function can fail. SHA-512 does not have a corresponding check. - // These functions already misbehave if the caller arbitrarily mutates |c|, so - // can we assume one of |SHA256_Init| or |SHA224_Init| was used? - if (md_len > SHA256_DIGEST_LENGTH) { - return 0; - } + BSSL_CHECK(md_len <= BCM_SHA256_DIGEST_LENGTH); assert(md_len % 4 == 0); const size_t out_words = md_len / 4; @@ -153,23 +129,26 @@ } FIPS_service_indicator_update_state(); - return 1; } -int SHA256_Final(uint8_t out[SHA256_DIGEST_LENGTH], SHA256_CTX *c) { - // Ideally we would assert |sha->md_len| is |SHA256_DIGEST_LENGTH| to match - // the size hint, but calling code often pairs |SHA224_Init| with +bcm_infallible BCM_sha256_final(uint8_t out[BCM_SHA256_DIGEST_LENGTH], + SHA256_CTX *c) { + // Ideally we would assert |sha->md_len| is |BCM_SHA256_DIGEST_LENGTH| to + // match the size hint, but calling code often pairs |SHA224_Init| with // |SHA256_Final| and expects |sha->md_len| to carry the size over. // // TODO(davidben): Add an assert and fix code to match them up. - return sha256_final_impl(out, c->md_len, c); + sha256_final_impl(out, c->md_len, c); + return bcm_infallible_approved; } -int SHA224_Final(uint8_t out[SHA224_DIGEST_LENGTH], SHA256_CTX *ctx) { +bcm_infallible BCM_sha224_final(uint8_t out[BCM_SHA224_DIGEST_LENGTH], + SHA256_CTX *ctx) { // This function must be paired with |SHA224_Init|, which sets |ctx->md_len| - // to |SHA224_DIGEST_LENGTH|. - assert(ctx->md_len == SHA224_DIGEST_LENGTH); - return sha256_final_impl(out, SHA224_DIGEST_LENGTH, ctx); + // to |BCM_SHA224_DIGEST_LENGTH|. + assert(ctx->md_len == BCM_SHA224_DIGEST_LENGTH); + sha256_final_impl(out, BCM_SHA224_DIGEST_LENGTH, ctx); + return bcm_infallible_approved; } #if !defined(SHA256_ASM) @@ -344,9 +323,11 @@ #endif // !defined(SHA256_ASM) -void SHA256_TransformBlocks(uint32_t state[8], const uint8_t *data, - size_t num_blocks) { +bcm_infallible BCM_sha256_transform_blocks(uint32_t state[8], + const uint8_t *data, + size_t num_blocks) { sha256_block_data_order(state, data, num_blocks); + return bcm_infallible_approved; } #undef Sigma0
diff --git a/crypto/sha/sha256.c b/crypto/sha/sha256.c new file mode 100644 index 0000000..d7f30cf --- /dev/null +++ b/crypto/sha/sha256.c
@@ -0,0 +1,87 @@ +/* Copyright (c) 2024, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include <openssl/sha.h> + +#include <openssl/mem.h> + +#include "../fipsmodule/bcm_interface.h" + + +int SHA224_Init(SHA256_CTX *sha) { + BCM_sha224_init(sha); + return 1; +} + +int SHA224_Update(SHA256_CTX *sha, const void *data, size_t len) { + BCM_sha224_update(sha, data, len); + return 1; +} + +int SHA224_Final(uint8_t out[SHA224_DIGEST_LENGTH], SHA256_CTX *sha) { + BCM_sha224_final(out, sha); + return 1; +} + +uint8_t *SHA224(const uint8_t *data, size_t len, + uint8_t out[SHA224_DIGEST_LENGTH]) { + SHA256_CTX ctx; + BCM_sha224_init(&ctx); + BCM_sha224_update(&ctx, data, len); + BCM_sha224_final(out, &ctx); + OPENSSL_cleanse(&ctx, sizeof(ctx)); + return out; +} + +int SHA256_Init(SHA256_CTX *sha) { + BCM_sha256_init(sha); + return 1; +} + +int SHA256_Update(SHA256_CTX *sha, const void *data, size_t len) { + BCM_sha256_update(sha, data, len); + return 1; +} + +int SHA256_Final(uint8_t out[SHA256_DIGEST_LENGTH], SHA256_CTX *sha) { + // TODO(bbe): This overflow check one of the few places a low-level hash + // 'final' function can fail. SHA-512 does not have a corresponding check. + // The BCM function is infallible and will abort if this is done incorrectly. + // we should verify nothing crashes with this removed and eliminate the 0 + // return. + if (sha->md_len > SHA256_DIGEST_LENGTH) { + return 0; + } + BCM_sha256_final(out, sha); + return 1; +} + +uint8_t *SHA256(const uint8_t *data, size_t len, + uint8_t out[SHA256_DIGEST_LENGTH]) { + SHA256_CTX ctx; + BCM_sha256_init(&ctx); + BCM_sha256_update(&ctx, data, len); + BCM_sha256_final(out, &ctx); + OPENSSL_cleanse(&ctx, sizeof(ctx)); + return out; +} + +void SHA256_Transform(SHA256_CTX *sha, const uint8_t block[SHA256_CBLOCK]) { + BCM_sha256_transform(sha, block); +} + +void SHA256_TransformBlocks(uint32_t state[8], const uint8_t *data, + size_t num_blocks) { + BCM_sha256_transform_blocks(state, data, num_blocks); +}
diff --git a/gen/sources.bzl b/gen/sources.bzl index 4337039..dce527b 100644 --- a/gen/sources.bzl +++ b/gen/sources.bzl
@@ -398,6 +398,7 @@ "crypto/rsa_extra/rsa_crypt.c", "crypto/rsa_extra/rsa_print.c", "crypto/sha/sha1.c", + "crypto/sha/sha256.c", "crypto/siphash/siphash.c", "crypto/slhdsa/fors.c", "crypto/slhdsa/merkle.c",
diff --git a/gen/sources.cmake b/gen/sources.cmake index 1202372..cf8d5f9 100644 --- a/gen/sources.cmake +++ b/gen/sources.cmake
@@ -412,6 +412,7 @@ crypto/rsa_extra/rsa_crypt.c crypto/rsa_extra/rsa_print.c crypto/sha/sha1.c + crypto/sha/sha256.c crypto/siphash/siphash.c crypto/slhdsa/fors.c crypto/slhdsa/merkle.c
diff --git a/gen/sources.gni b/gen/sources.gni index e83637f..41b4cc1 100644 --- a/gen/sources.gni +++ b/gen/sources.gni
@@ -398,6 +398,7 @@ "crypto/rsa_extra/rsa_crypt.c", "crypto/rsa_extra/rsa_print.c", "crypto/sha/sha1.c", + "crypto/sha/sha256.c", "crypto/siphash/siphash.c", "crypto/slhdsa/fors.c", "crypto/slhdsa/merkle.c",
diff --git a/gen/sources.json b/gen/sources.json index 908debb..ec5a7e7 100644 --- a/gen/sources.json +++ b/gen/sources.json
@@ -382,6 +382,7 @@ "crypto/rsa_extra/rsa_crypt.c", "crypto/rsa_extra/rsa_print.c", "crypto/sha/sha1.c", + "crypto/sha/sha256.c", "crypto/siphash/siphash.c", "crypto/slhdsa/fors.c", "crypto/slhdsa/merkle.c",
diff --git a/include/openssl/bcm_public.h b/include/openssl/bcm_public.h index f3797df..9bb0dbb 100644 --- a/include/openssl/bcm_public.h +++ b/include/openssl/bcm_public.h
@@ -53,6 +53,17 @@ unsigned num; }; +// SHA256_CBLOCK is the block size of SHA-256. +#define BCM_SHA256_CBLOCK 64 + +// SHA256_CTX +struct sha256_state_st { + uint32_t h[8]; + uint32_t Nl, Nh; + uint8_t data[BCM_SHA256_CBLOCK]; + unsigned num, md_len; +}; + #if defined(__cplusplus) } // extern C
diff --git a/include/openssl/sha.h b/include/openssl/sha.h index 65a996c..bfaeb78 100644 --- a/include/openssl/sha.h +++ b/include/openssl/sha.h
@@ -130,7 +130,7 @@ // SHA224_Final adds the final padding to |sha| and writes the resulting digest // to |out|, which must have at least |SHA224_DIGEST_LENGTH| bytes of space. It -// returns one on success and zero on programmer error. +// returns 1. OPENSSL_EXPORT int SHA224_Final(uint8_t out[SHA224_DIGEST_LENGTH], SHA256_CTX *sha); @@ -181,14 +181,6 @@ const uint8_t *data, size_t num_blocks); -struct sha256_state_st { - uint32_t h[8]; - uint32_t Nl, Nh; - uint8_t data[SHA256_CBLOCK]; - unsigned num, md_len; -}; - - // SHA-384. // SHA384_CBLOCK is the block size of SHA-384.