diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 3bed061fd..df43ff569 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -373,6 +373,34 @@ jobs: CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DEXPERIMENTAL_SHA256=ON SKIP_SSH_TESTS: true SKIP_NEGOTIATE_TESTS: true + - name: "Linux (SHA256-FIPS, Xenial, Clang, OpenSSL)" + id: linux-sha256-fips + container: + name: xenial + env: + CC: clang + CMAKE_GENERATOR: Ninja + CMAKE_OPTIONS: -DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON -DUSE_SSH=ON -DUSE_SHA256="OpenSSL-FIPS" + os: ubuntu-latest + - name: "macOS (SHA256-FIPS)" + id: macos-sha256-fips + os: macos-13 + setup-script: osx + env: + CC: clang + CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON -DEXPERIMENTAL_SHA256=ON -DUSE_SHA256="OpenSSL-FIPS" + PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true + - name: "Windows (SHA256-FIPS, amd64, Visual Studio)" + id: windows-sha256-fips + os: windows-2022 + env: + ARCH: amd64 + CMAKE_GENERATOR: Visual Studio 17 2022 + CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON -DEXPERIMENTAL_SHA256=ON -DUSE_SHA256="OpenSSL-FIPS" + SKIP_SSH_TESTS: true + SKIP_NEGOTIATE_TESTS: true fail-fast: false env: ${{ matrix.platform.env }} runs-on: ${{ matrix.platform.os }} diff --git a/cmake/SelectHashes.cmake b/cmake/SelectHashes.cmake index 5c007e587..59ae53b20 100644 --- a/cmake/SelectHashes.cmake +++ b/cmake/SelectHashes.cmake @@ -70,6 +70,8 @@ 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") diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index ee35eb961..dc992dfc4 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -53,7 +53,7 @@ list(SORT UTIL_SRC_SHA1) if(USE_SHA256 STREQUAL "Builtin") file(GLOB UTIL_SRC_SHA256 hash/builtin.* hash/rfc6234/*) -elseif(USE_SHA256 STREQUAL "OpenSSL" OR USE_SHA256 STREQUAL "OpenSSL-Dynamic") +elseif(USE_SHA256 STREQUAL "OpenSSL" OR USE_SHA256 STREQUAL "OpenSSL-Dynamic" OR USE_SHA256 STREQUAL "OpenSSL-FIPS") add_definitions(-DOPENSSL_API_COMPAT=0x10100000L) file(GLOB UTIL_SRC_SHA256 hash/openssl.*) elseif(USE_SHA256 STREQUAL "CommonCrypto") diff --git a/src/util/git2_features.h.in b/src/util/git2_features.h.in index 52b732846..a99c8bc37 100644 --- a/src/util/git2_features.h.in +++ b/src/util/git2_features.h.in @@ -62,6 +62,7 @@ #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_MBEDTLS 1 #cmakedefine GIT_RAND_GETENTROPY 1 diff --git a/src/util/hash/openssl.c b/src/util/hash/openssl.c index eaf91e74c..fae48f0a1 100644 --- a/src/util/hash/openssl.c +++ b/src/util/hash/openssl.c @@ -193,3 +193,75 @@ int git_hash_sha256_final(unsigned char *out, git_hash_sha256_ctx *ctx) } #endif + +#ifdef GIT_SHA256_OPENSSL_FIPS + +static const EVP_MD* SHA256_ENGINE_DIGEST_TYPE = NULL; + +int git_hash_sha256_global_init(void) +{ + SHA256_ENGINE_DIGEST_TYPE = EVP_sha256(); + return SHA256_ENGINE_DIGEST_TYPE != NULL ? 0 : -1; +} + +int git_hash_sha256_ctx_init(git_hash_sha256_ctx *ctx) +{ + return git_hash_sha256_init(ctx); +} + +void git_hash_sha256_ctx_cleanup(git_hash_sha256_ctx *ctx) +{ +#if OPENSSL_VERSION_NUMBER < 0x10100000L + EVP_MD_CTX_destroy(ctx->c); +#else + EVP_MD_CTX_free(ctx->c); +#endif +} + +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) { + git_hash_sha256_ctx_cleanup(ctx); + git_error_set(GIT_ERROR_SHA, "failed to initialize sha256 context"); + return -1; + } + + return 0; +} + +int git_hash_sha256_update(git_hash_sha256_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 sha256"); + return -1; + } + + return 0; +} + +int git_hash_sha256_final(unsigned char *out, git_hash_sha256_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 sha256"); + return -1; + } + + return 0; +} + +#endif \ No newline at end of file diff --git a/src/util/hash/openssl.h b/src/util/hash/openssl.h index 7cb089abc..96ff922d9 100644 --- a/src/util/hash/openssl.h +++ b/src/util/hash/openssl.h @@ -11,7 +11,11 @@ #include "hash/sha.h" #ifndef GIT_OPENSSL_DYNAMIC -# include +#ifdef GIT_SHA256_OPENSSL_FIPS +#include +#else +#include +#endif #else typedef struct { @@ -42,4 +46,10 @@ struct git_hash_sha256_ctx { }; #endif +#ifdef GIT_SHA256_OPENSSL_FIPS +struct git_hash_sha256_ctx { + EVP_MD_CTX* c; +}; +#endif + #endif diff --git a/src/util/hash/sha.h b/src/util/hash/sha.h index 4f596234c..be224000a 100644 --- a/src/util/hash/sha.h +++ b/src/util/hash/sha.h @@ -17,7 +17,7 @@ typedef struct git_hash_sha256_ctx git_hash_sha256_ctx; # include "common_crypto.h" #endif -#if defined(GIT_SHA1_OPENSSL) || defined(GIT_SHA256_OPENSSL) +#if defined(GIT_SHA1_OPENSSL) || defined(GIT_SHA256_OPENSSL) || defined(GIT_SHA256_OPENSSL_FIPS) # include "openssl.h" #endif