From 3d268285f9c1a9795496af0ffd4a04c5238ebd49 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 10 Oct 2024 00:01:16 +0100 Subject: [PATCH] sha: support FIPS-compliant OpenSSL for SHA1 --- cmake/SelectHashes.cmake | 9 +++-- src/util/CMakeLists.txt | 2 +- src/util/git2_features.h.in | 3 +- src/util/hash/openssl.c | 80 +++++++++++++++++++++++++++++++++++-- src/util/hash/openssl.h | 16 +++++--- src/util/hash/sha.h | 5 ++- 6 files changed, 101 insertions(+), 14 deletions(-) diff --git a/cmake/SelectHashes.cmake b/cmake/SelectHashes.cmake index 59ae53b20..06cfabc3c 100644 --- a/cmake/SelectHashes.cmake +++ b/cmake/SelectHashes.cmake @@ -28,6 +28,8 @@ if(USE_SHA1 STREQUAL "CollisionDetection") set(GIT_SHA1_COLLISIONDETECT 1) elseif(USE_SHA1 STREQUAL "OpenSSL") set(GIT_SHA1_OPENSSL 1) +elseif(USE_SHA1 STREQUAL "OpenSSL-FIPS") + set(GIT_SHA1_OPENSSL_FIPS 1) elseif(USE_SHA1 STREQUAL "OpenSSL-Dynamic") set(GIT_SHA1_OPENSSL 1) set(GIT_SHA1_OPENSSL_DYNAMIC 1) @@ -66,12 +68,12 @@ if(USE_SHA256 STREQUAL "Builtin") set(GIT_SHA256_BUILTIN 1) elseif(USE_SHA256 STREQUAL "OpenSSL") set(GIT_SHA256_OPENSSL 1) +elseif(USE_SHA256 STREQUAL "OpenSSL-FIPS") + set(GIT_SHA256_OPENSSL_FIPS 1) elseif(USE_SHA256 STREQUAL "OpenSSL-Dynamic") set(GIT_SHA256_OPENSSL 1) set(GIT_SHA256_OPENSSL_DYNAMIC 1) list(APPEND LIBGIT2_SYSTEM_LIBS dl) -elseif(USE_SHA256 STREQUAL "OpenSSL-FIPS") - set(GIT_SHA256_OPENSSL_FIPS 1) elseif(USE_SHA256 STREQUAL "CommonCrypto") set(GIT_SHA256_COMMON_CRYPTO 1) elseif(USE_SHA256 STREQUAL "mbedTLS") @@ -83,7 +85,8 @@ else() endif() # add library requirements -if(USE_SHA1 STREQUAL "OpenSSL" OR USE_SHA256 STREQUAL "OpenSSL") +if(USE_SHA1 STREQUAL "OpenSSL" OR USE_SHA256 STREQUAL "OpenSSL" OR + USE_SHA1 STREQUAL "OpenSSL-FIPS" OR USE_SHA256 STREQUAL "OpenSSL-FIPS") if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") list(APPEND LIBGIT2_PC_LIBS "-lssl") else() diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index dc992dfc4..a92505fe9 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -36,7 +36,7 @@ if(USE_SHA1 STREQUAL "CollisionDetection") target_compile_definitions(util PRIVATE SHA1DC_NO_STANDARD_INCLUDES=1) target_compile_definitions(util PRIVATE SHA1DC_CUSTOM_INCLUDE_SHA1_C=\"git2_util.h\") target_compile_definitions(util PRIVATE SHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C=\"git2_util.h\") -elseif(USE_SHA1 STREQUAL "OpenSSL" OR USE_SHA1 STREQUAL "OpenSSL-Dynamic") +elseif(USE_SHA1 STREQUAL "OpenSSL" OR USE_SHA1 STREQUAL "OpenSSL-Dynamic" OR USE_SHA1 STREQUAL "OpenSSL-FIPS") add_definitions(-DOPENSSL_API_COMPAT=0x10100000L) file(GLOB UTIL_SRC_SHA1 hash/openssl.*) elseif(USE_SHA1 STREQUAL "CommonCrypto") diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index a99c8bc37..9408f9b00 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -54,6 +54,7 @@ #cmakedefine GIT_SHA1_WIN32 1 #cmakedefine GIT_SHA1_COMMON_CRYPTO 1 #cmakedefine GIT_SHA1_OPENSSL 1 +#cmakedefine GIT_SHA1_OPENSSL_FIPS 1 #cmakedefine GIT_SHA1_OPENSSL_DYNAMIC 1 #cmakedefine GIT_SHA1_MBEDTLS 1 @@ -61,8 +62,8 @@ #cmakedefine GIT_SHA256_WIN32 1 #cmakedefine GIT_SHA256_COMMON_CRYPTO 1 #cmakedefine GIT_SHA256_OPENSSL 1 -#cmakedefine GIT_SHA256_OPENSSL_DYNAMIC 1 #cmakedefine GIT_SHA256_OPENSSL_FIPS 1 +#cmakedefine GIT_SHA256_OPENSSL_DYNAMIC 1 #cmakedefine GIT_SHA256_MBEDTLS 1 #cmakedefine GIT_RAND_GETENTROPY 1 diff --git a/src/util/hash/openssl.c b/src/util/hash/openssl.c index fae48f0a1..06297eea9 100644 --- a/src/util/hash/openssl.c +++ b/src/util/hash/openssl.c @@ -120,6 +120,79 @@ int git_hash_sha1_final(unsigned char *out, git_hash_sha1_ctx *ctx) #endif +#ifdef GIT_SHA1_OPENSSL_FIPS + +static const EVP_MD *SHA1_ENGINE_DIGEST_TYPE = NULL; + +int git_hash_sha1_global_init(void) +{ + SHA1_ENGINE_DIGEST_TYPE = EVP_sha1(); + return SHA1_ENGINE_DIGEST_TYPE != NULL ? 0 : -1; +} + +int git_hash_sha1_ctx_init(git_hash_sha1_ctx *ctx) +{ + return git_hash_sha1_init(ctx); +} + +void git_hash_sha1_ctx_cleanup(git_hash_sha1_ctx *ctx) +{ +#if OPENSSL_VERSION_NUMBER < 0x10100000L + EVP_MD_CTX_destroy(ctx->c); +#else + EVP_MD_CTX_free(ctx->c); +#endif +} + +int git_hash_sha1_init(git_hash_sha1_ctx *ctx) +{ + GIT_ASSERT_ARG(ctx); + GIT_ASSERT(SHA1_ENGINE_DIGEST_TYPE); + +#if OPENSSL_VERSION_NUMBER < 0x10100000L + ctx->c = EVP_MD_CTX_create(); +#else + ctx->c = EVP_MD_CTX_new(); +#endif + + GIT_ASSERT(ctx->c); + + if (EVP_DigestInit_ex(ctx->c, SHA1_ENGINE_DIGEST_TYPE, NULL) != 1) { + git_hash_sha1_ctx_cleanup(ctx); + git_error_set(GIT_ERROR_SHA, "failed to initialize sha1 context"); + return -1; + } + + return 0; +} + +int git_hash_sha1_update(git_hash_sha1_ctx *ctx, const void *data, size_t len) +{ + GIT_ASSERT_ARG(ctx); + + if (EVP_DigestUpdate(ctx->c, data, len) != 1) { + git_error_set(GIT_ERROR_SHA, "failed to update sha1"); + return -1; + } + + return 0; +} + +int git_hash_sha1_final(unsigned char *out, git_hash_sha1_ctx *ctx) +{ + unsigned int len = 0; + GIT_ASSERT_ARG(ctx); + + if (EVP_DigestFinal(ctx->c, out, &len) != 1) { + git_error_set(GIT_ERROR_SHA, "failed to finalize sha1"); + return -1; + } + + return 0; +} + +#endif + #ifdef GIT_SHA256_OPENSSL # ifdef GIT_OPENSSL_DYNAMIC @@ -196,7 +269,7 @@ int git_hash_sha256_final(unsigned char *out, git_hash_sha256_ctx *ctx) #ifdef GIT_SHA256_OPENSSL_FIPS -static const EVP_MD* SHA256_ENGINE_DIGEST_TYPE = NULL; +static const EVP_MD *SHA256_ENGINE_DIGEST_TYPE = NULL; int git_hash_sha256_global_init(void) { @@ -221,13 +294,14 @@ void git_hash_sha256_ctx_cleanup(git_hash_sha256_ctx *ctx) int git_hash_sha256_init(git_hash_sha256_ctx *ctx) { GIT_ASSERT_ARG(ctx); - GIT_ASSERT(SHA256_ENGINE_DIGEST_TYPE); + #if OPENSSL_VERSION_NUMBER < 0x10100000L ctx->c = EVP_MD_CTX_create(); #else ctx->c = EVP_MD_CTX_new(); #endif + GIT_ASSERT(ctx->c); if (EVP_DigestInit_ex(ctx->c, SHA256_ENGINE_DIGEST_TYPE, NULL) != 1) { @@ -264,4 +338,4 @@ int git_hash_sha256_final(unsigned char *out, git_hash_sha256_ctx *ctx) return 0; } -#endif \ No newline at end of file +#endif diff --git a/src/util/hash/openssl.h b/src/util/hash/openssl.h index 96ff922d9..8be37fd44 100644 --- a/src/util/hash/openssl.h +++ b/src/util/hash/openssl.h @@ -11,11 +11,11 @@ #include "hash/sha.h" #ifndef GIT_OPENSSL_DYNAMIC -#ifdef GIT_SHA256_OPENSSL_FIPS -#include -#else -#include -#endif +# if defined(GIT_SHA1_OPENSSL_FIPS) || defined(GIT_SHA256_OPENSSL_FIPS) +# include +# else +# include +# endif #else typedef struct { @@ -40,6 +40,12 @@ struct git_hash_sha1_ctx { }; #endif +#ifdef GIT_SHA1_OPENSSL_FIPS +struct git_hash_sha1_ctx { + EVP_MD_CTX* c; +}; +#endif + #ifdef GIT_SHA256_OPENSSL struct git_hash_sha256_ctx { SHA256_CTX c; diff --git a/src/util/hash/sha.h b/src/util/hash/sha.h index be224000a..8e7eeae8c 100644 --- a/src/util/hash/sha.h +++ b/src/util/hash/sha.h @@ -17,7 +17,10 @@ typedef struct git_hash_sha256_ctx git_hash_sha256_ctx; # include "common_crypto.h" #endif -#if defined(GIT_SHA1_OPENSSL) || defined(GIT_SHA256_OPENSSL) || defined(GIT_SHA256_OPENSSL_FIPS) +#if defined(GIT_SHA1_OPENSSL) || \ + defined(GIT_SHA1_OPENSSL_FIPS) || \ + defined(GIT_SHA256_OPENSSL) || \ + defined(GIT_SHA256_OPENSSL_FIPS) # include "openssl.h" #endif