diff --git a/.github/workflows/build_openssl3.yml b/.github/workflows/build_openssl3.yml new file mode 100644 index 00000000..9899ec44 --- /dev/null +++ b/.github/workflows/build_openssl3.yml @@ -0,0 +1,68 @@ +name: Build and Test (OpenSSL 3) + +on: + push: + branches: + - main + pull_request: + branches: + - main + schedule: + - cron: '30 3 * * 1' + +env: + CTEST_OUTPUT_ON_FAILURE: 1 + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [windows-latest, ubuntu-latest, macos-latest] + include: + - os: windows-latest + vcpkg-cmake-file: "$env:VCPKG_INSTALLATION_ROOT\\scripts\\buildsystems\\vcpkg.cmake" + ossl3-vcpkg-dir: "alternatives\\openssl_3" + ctest-target: RUN_TESTS + - os: ubuntu-latest + vcpkg-cmake-file: "$VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" + ossl3-vcpkg-dir: "alternatives/openssl_3" + ctest-target: test + - os: macos-latest + vcpkg-cmake-file: "$VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" + ossl3-vcpkg-dir: "alternatives/openssl_3" + ctest-target: test + + env: + CMAKE_BUILD_DIR: ${{ github.workspace }}/build + CMAKE_TEST_DIR: ${{ github.workspace }}/build/test + + steps: + - uses: actions/checkout@v2 + + - name: dependencies (macos) + if: ${{ matrix.os == 'macos-latest' }} + run: | + brew install llvm pkg-config + ln -s "/usr/local/opt/llvm/bin/clang-format" "/usr/local/bin/clang-format" + ln -s "/usr/local/opt/llvm/bin/clang-tidy" "/usr/local/bin/clang-tidy" + + - name: Restore cache + uses: actions/cache@v2 + with: + path: | + ${{ env.CMAKE_BUILD_DIR }}/vcpkg_installed + key: ${{ runner.os }}-${{ hashFiles( '**/vcpkg.json' ) }} + + - name: Configure to use clang-tidy and sanitizers + run: | + cmake -B "${{ env.CMAKE_BUILD_DIR }}" -DTESTING=ON -DCLANG_TIDY=ON -DSANITIZERS=ON -DVCPKG_MANIFEST_DIR="${{ matrix.ossl3-vcpkg-dir }}" -DCMAKE_TOOLCHAIN_FILE="${{ matrix.vcpkg-cmake-file}}" . + + - name: Build + run: | + cmake --build "${{ env.CMAKE_BUILD_DIR }}" + + - name: Unit tests + run: | + cmake --build "${{ env.CMAKE_BUILD_DIR }}" --target "${{ matrix.ctest-target}}" diff --git a/CMakeLists.txt b/CMakeLists.txt index f9181691..6bf7f0de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,14 +70,27 @@ endif() ### Dependencies ### +# External libraries +find_package(OpenSSL REQUIRED) +if ( OPENSSL_FOUND ) + if (${OPENSSL_VERSION} VERSION_GREATER_EQUAL 3) + add_compile_definitions(WITH_OPENSSL3) + elseif(${OPENSSL_VERSION} VERSION_LESS 1.1.1) + message(FATAL_ERROR "OpenSSL 1.1.1 or greater is required") + endif() + message(STATUS "OpenSSL Found: ${OPENSSL_VERSION}") + message(STATUS "OpenSSL Include: ${OPENSSL_INCLUDE_DIR}") + message(STATUS "OpenSSL Libraries: ${OPENSSL_LIBRARIES}") +else() + message(FATAL_ERROR "No OpenSSL library found") +endif() + # Internal libraries add_subdirectory(lib) # Third-Party libraries in tree add_subdirectory(third_party) -# External libraries -find_package(OpenSSL 1.1 REQUIRED) ### ### Library Config diff --git a/alternatives/openssl_3/vcpkg.json b/alternatives/openssl_3/vcpkg.json new file mode 100644 index 00000000..4b4d7657 --- /dev/null +++ b/alternatives/openssl_3/vcpkg.json @@ -0,0 +1,19 @@ +{ + "name": "mlspp", + "version-string": "0.1", + "description": "Cisco MLS C++ library (OpenSSL 3)", + "dependencies": [ + { + "name": "openssl", + "version>=": "3.0.7" + }, + "doctest" + ], + "builtin-baseline": "5908d702d61cea1429b223a0b7a10ab86bad4c78", + "overrides": [ + { + "name": "openssl", + "version": "3.0.7" + } + ] +} diff --git a/lib/bytes/test/bytes.cpp b/lib/bytes/test/bytes.cpp index 0f69ddcc..a28dbf9f 100644 --- a/lib/bytes/test/bytes.cpp +++ b/lib/bytes/test/bytes.cpp @@ -1,5 +1,6 @@ #include #include +#include #include using namespace bytes_ns; diff --git a/lib/hpke/src/certificate.cpp b/lib/hpke/src/certificate.cpp index 46a45189..b7ec7d02 100644 --- a/lib/hpke/src/certificate.cpp +++ b/lib/hpke/src/certificate.cpp @@ -198,8 +198,8 @@ struct Certificate::ParsedCertificate , sub_alt_names(parse_san(x509.get())) , is_ca(X509_check_ca(x509.get()) != 0) , hash(compute_digest(x509.get())) - , not_before(asn1_time_to_chrono(X509_get_notBefore(x509.get()))) - , not_after(asn1_time_to_chrono(X509_get_notAfter(x509.get()))) + , not_before(asn1_time_to_chrono(X509_get0_notBefore(x509.get()))) + , not_after(asn1_time_to_chrono(X509_get0_notAfter(x509.get()))) { } diff --git a/lib/hpke/src/digest.cpp b/lib/hpke/src/digest.cpp index 21b6b721..d2627ca7 100644 --- a/lib/hpke/src/digest.cpp +++ b/lib/hpke/src/digest.cpp @@ -2,6 +2,9 @@ #include #include +#if defined(WITH_OPENSSL3) +#include +#endif #include "openssl_common.h" @@ -25,6 +28,26 @@ openssl_digest_type(Digest::ID digest) } } +#if defined(WITH_OPENSSL3) +static std::string +openssl_digest_name(Digest::ID digest) +{ + switch (digest) { + case Digest::ID::SHA256: + return OSSL_DIGEST_NAME_SHA2_256; + + case Digest::ID::SHA384: + return OSSL_DIGEST_NAME_SHA2_384; + + case Digest::ID::SHA512: + return OSSL_DIGEST_NAME_SHA2_512; + + default: + throw std::runtime_error("Unsupported digest algorithm"); + } +} +#endif + template<> const Digest& Digest::get() @@ -91,8 +114,23 @@ Digest::hmac(const bytes& key, const bytes& data) const bytes Digest::hmac_for_hkdf_extract(const bytes& key, const bytes& data) const { +#if defined(WITH_OPENSSL3) + auto digest_name = openssl_digest_name(id); + std::array params = { + OSSL_PARAM_construct_utf8_string( + OSSL_ALG_PARAM_DIGEST, digest_name.data(), 0), + OSSL_PARAM_construct_end() + }; + const auto mac = + make_typed_unique(EVP_MAC_fetch(nullptr, OSSL_MAC_NAME_HMAC, nullptr)); + const auto ctx = make_typed_unique(EVP_MAC_CTX_new(mac.get())); +#else const auto* type = openssl_digest_type(id); auto ctx = make_typed_unique(HMAC_CTX_new()); +#endif + if (ctx == nullptr) { + throw openssl_error(); + } // Some FIPS-enabled libraries are overly conservative in their interpretation // of NIST SP 800-131A, which requires HMAC keys to be at least 112 bits long. @@ -100,11 +138,16 @@ Digest::hmac_for_hkdf_extract(const bytes& key, const bytes& data) const // enforcement for purposes of HKDF. // // https://doi.org/10.6028/NIST.SP.800-131Ar2 - static const auto fips_min_hmac_key_len = 14; auto key_size = static_cast(key.size()); + // OpenSSL 3 does not support the flag EVP_MD_CTX_FLAG_NON_FIPS_ALLOW anymore. + // However, OpenSSL 3 in FIPS mode doesn't seem to check the HMAC key size + // constraint. +#if !defined(WITH_OPENSSL3) + static const auto fips_min_hmac_key_len = 14; if (FIPS_mode() != 0 && key_size < fips_min_hmac_key_len) { HMAC_CTX_set_flags(ctx.get(), EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); } +#endif // Guard against sending nullptr to HMAC_Init_ex const auto* key_data = key.data(); @@ -113,19 +156,30 @@ Digest::hmac_for_hkdf_extract(const bytes& key, const bytes& data) const key_data = &non_null_zero_length_key; } + auto md = bytes(hash_size); +#if defined(WITH_OPENSSL3) + if (1 != EVP_MAC_init(ctx.get(), key_data, key_size, params.data())) { + throw openssl_error(); + } + if (1 != EVP_MAC_update(ctx.get(), data.data(), data.size())) { + throw openssl_error(); + } + size_t size = 0; + if (1 != EVP_MAC_final(ctx.get(), md.data(), &size, hash_size)) { + throw openssl_error(); + } +#else if (1 != HMAC_Init_ex(ctx.get(), key_data, key_size, type, nullptr)) { throw openssl_error(); } - if (1 != HMAC_Update(ctx.get(), data.data(), data.size())) { throw openssl_error(); } - - auto md = bytes(hash_size); unsigned int size = 0; if (1 != HMAC_Final(ctx.get(), md.data(), &size)) { throw openssl_error(); } +#endif return md; } diff --git a/lib/hpke/src/group.cpp b/lib/hpke/src/group.cpp index e34fcbb9..5afcd025 100644 --- a/lib/hpke/src/group.cpp +++ b/lib/hpke/src/group.cpp @@ -8,6 +8,10 @@ #include "openssl/ec.h" #include "openssl/evp.h" #include "openssl/obj_mac.h" +#if defined(WITH_OPENSSL3) +#include "openssl/core_names.h" +#include "openssl/param_build.h" +#endif namespace hpke { @@ -178,6 +182,131 @@ struct ECKeyGroup : public EVPGroup { } +#if defined(WITH_OPENSSL3) + typed_unique_ptr keypair_evp_key( + const typed_unique_ptr& priv) const + { + const auto* name = OBJ_nid2sn(curve_nid); + if (name == nullptr) { + throw std::runtime_error("Unsupported algorithm"); + } + + auto group = make_typed_unique( + EC_GROUP_new_by_curve_name_ex(nullptr, nullptr, curve_nid)); + if (group == nullptr) { + throw openssl_error(); + } + + auto pt = make_typed_unique(EC_POINT_new(group.get())); + if (pt == nullptr) { + throw openssl_error(); + } + + if (1 != EC_POINT_mul( + group.get(), pt.get(), priv.get(), nullptr, nullptr, nullptr)) { + throw openssl_error(); + } + + const auto pt_size = EC_POINT_point2oct(group.get(), + pt.get(), + POINT_CONVERSION_UNCOMPRESSED, + nullptr, + 0, + nullptr); + if (0 == pt_size) { + throw openssl_error(); + } + + bytes pub(pt_size); + if (EC_POINT_point2oct(group.get(), + pt.get(), + POINT_CONVERSION_UNCOMPRESSED, + pub.data(), + pt_size, + nullptr) != pt_size) { + throw openssl_error(); + } + + auto builder = make_typed_unique(OSSL_PARAM_BLD_new()); + if (builder == nullptr || + 1 != OSSL_PARAM_BLD_push_utf8_string( + builder.get(), OSSL_PKEY_PARAM_GROUP_NAME, name, 0) || + 1 != OSSL_PARAM_BLD_push_BN( + builder.get(), OSSL_PKEY_PARAM_PRIV_KEY, priv.get()) || + 1 != + OSSL_PARAM_BLD_push_octet_string( + builder.get(), OSSL_PKEY_PARAM_PUB_KEY, pub.data(), pub.size())) { + throw openssl_error(); + } + + auto params = make_typed_unique(OSSL_PARAM_BLD_to_param(builder.get())); + auto ctx = + make_typed_unique(EVP_PKEY_CTX_new_from_name(nullptr, "EC", nullptr)); + auto key = make_typed_unique(EVP_PKEY_new()); + auto* key_ptr = key.get(); + if (params == nullptr || ctx == nullptr || key == nullptr || + EVP_PKEY_fromdata_init(ctx.get()) <= 0 || + EVP_PKEY_fromdata( + ctx.get(), &key_ptr, EVP_PKEY_KEYPAIR, params.get()) <= 0) { + throw openssl_error(); + } + ctx.reset(); + + ctx = make_typed_unique( + EVP_PKEY_CTX_new_from_pkey(nullptr, key.get(), nullptr)); + if (EVP_PKEY_check(ctx.get()) <= 0) { + throw openssl_error(); + } + + return key; + } + + typed_unique_ptr public_evp_key(const bytes& pub) const + { + const auto* name = OBJ_nid2sn(curve_nid); + if (name == nullptr) { + throw std::runtime_error("Unsupported algorithm"); + } + + auto group = make_typed_unique( + EC_GROUP_new_by_curve_name_ex(nullptr, nullptr, curve_nid)); + if (group == nullptr) { + throw openssl_error(); + } + + auto builder = make_typed_unique(OSSL_PARAM_BLD_new()); + if (builder == nullptr || + 1 != OSSL_PARAM_BLD_push_utf8_string( + builder.get(), OSSL_PKEY_PARAM_GROUP_NAME, name, 0) || + 1 != + OSSL_PARAM_BLD_push_octet_string( + builder.get(), OSSL_PKEY_PARAM_PUB_KEY, pub.data(), pub.size())) { + throw openssl_error(); + } + + auto params = make_typed_unique(OSSL_PARAM_BLD_to_param(builder.get())); + auto ctx = + make_typed_unique(EVP_PKEY_CTX_new_from_name(nullptr, "EC", nullptr)); + auto key = make_typed_unique(EVP_PKEY_new()); + auto* key_ptr = key.get(); + if (params == nullptr || ctx == nullptr || key == nullptr || + EVP_PKEY_fromdata_init(ctx.get()) <= 0 || + EVP_PKEY_fromdata( + ctx.get(), &key_ptr, EVP_PKEY_KEYPAIR, params.get()) <= 0) { + throw openssl_error(); + } + ctx.reset(); + + ctx = make_typed_unique( + EVP_PKEY_CTX_new_from_pkey(nullptr, key.get(), nullptr)); + if (EVP_PKEY_public_check(ctx.get()) <= 0) { + throw openssl_error(); + } + + return key; + } +#endif + std::unique_ptr derive_key_pair( const bytes& suite_id, const bytes& ikm) const override @@ -188,8 +317,13 @@ struct ECKeyGroup : public EVPGroup auto dkp_prk = kdf.labeled_extract(suite_id, {}, label_dkp_prk, ikm); +#if defined(WITH_OPENSSL3) + auto* group = EC_GROUP_new_by_curve_name_ex(nullptr, nullptr, curve_nid); + auto group_ptr = make_typed_unique(group); +#else auto eckey = make_typed_unique(new_ec_key()); const auto* group = EC_KEY_get0_group(eckey.get()); +#endif auto order = make_typed_unique(BN_new()); if (1 != EC_GROUP_get_order(group, order.get(), nullptr)) { @@ -197,9 +331,7 @@ struct ECKeyGroup : public EVPGroup } auto sk = make_typed_unique(BN_new()); - if (1 != BN_zero(sk.get())) { - throw openssl_error(); - } + BN_zero(sk.get()); auto counter = int(0); while (BN_is_zero(sk.get()) != 0 || BN_cmp(sk.get(), order.get()) != -1) { @@ -216,6 +348,10 @@ struct ECKeyGroup : public EVPGroup } } +#if defined(WITH_OPENSSL3) + auto key = keypair_evp_key(sk); + return std::make_unique(key.release()); +#else auto pt = make_typed_unique(EC_POINT_new(group)); EC_POINT_mul(group, pt.get(), sk.get(), nullptr, nullptr, nullptr); @@ -223,11 +359,71 @@ struct ECKeyGroup : public EVPGroup EC_KEY_set_public_key(eckey.get(), pt.get()); return std::make_unique(to_pkey(eckey.release())); +#endif } bytes serialize(const Group::PublicKey& pk) const override { const auto& rpk = dynamic_cast(pk); +#if defined(WITH_OPENSSL3) + OSSL_PARAM* param = nullptr; + if (1 != EVP_PKEY_todata(rpk.pkey.get(), EVP_PKEY_PUBLIC_KEY, ¶m)) { + throw openssl_error(); + } + auto param_ptr = make_typed_unique(param); + + const OSSL_PARAM* pk_param = + OSSL_PARAM_locate_const(param_ptr.get(), OSSL_PKEY_PARAM_PUB_KEY); + if (pk_param == nullptr) { + return bytes({}, 0); + } + + size_t len = 0; + if (1 != OSSL_PARAM_get_octet_string(pk_param, nullptr, 0, &len)) { + return bytes({}, 0); + } + + bytes buf(len); + void* data_ptr = buf.data(); + if (1 != OSSL_PARAM_get_octet_string(pk_param, &data_ptr, len, nullptr)) { + return bytes({}, 0); + } + + // Prior to OpenSSL 3.0.8, we will always get compressed point from + // OSSL_PKEY_PARAM_PUB_KEY, so we will have to do the following conversion. + // From OpenSSL 3.0.8, we can obtain the uncompressed point value by setting + // OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT appropriately. + auto group = make_typed_unique( + EC_GROUP_new_by_curve_name_ex(nullptr, nullptr, curve_nid)); + if (group == nullptr) { + return bytes({}, 0); + } + auto point = make_typed_unique(EC_POINT_new(group.get())); + const auto* oct_ptr = static_cast(data_ptr); + if (1 != + EC_POINT_oct2point(group.get(), point.get(), oct_ptr, len, nullptr)) { + return bytes({}, 0); + } + len = EC_POINT_point2oct(group.get(), + point.get(), + POINT_CONVERSION_UNCOMPRESSED, + nullptr, + 0, + nullptr); + if (0 == len) { + return bytes({}, 0); + } + bytes out(len); + auto* data = out.data(); + if (EC_POINT_point2oct(group.get(), + point.get(), + POINT_CONVERSION_UNCOMPRESSED, + data, + len, + nullptr) != len) { + return bytes({}, 0); + } +#else auto* pub = EVP_PKEY_get0_EC_KEY(rpk.pkey.get()); auto len = i2o_ECPublicKey(pub, nullptr); @@ -240,12 +436,19 @@ struct ECKeyGroup : public EVPGroup if (i2o_ECPublicKey(pub, &data) == 0) { throw openssl_error(); } - +#endif return out; } std::unique_ptr deserialize(const bytes& enc) const override { +#if defined(WITH_OPENSSL3) + auto key = public_evp_key(enc); + if (key == nullptr) { + throw std::runtime_error("Unable to deserialize the public key"); + } + return std::make_unique(key.release()); +#else auto eckey = make_typed_unique(new_ec_key()); auto* eckey_ptr = eckey.get(); const auto* data_ptr = enc.data(); @@ -258,13 +461,34 @@ struct ECKeyGroup : public EVPGroup } return std::make_unique(to_pkey(eckey.release())); +#endif } bytes serialize_private(const Group::PrivateKey& sk) const override { const auto& rsk = dynamic_cast(sk); +#if defined(WITH_OPENSSL3) + OSSL_PARAM* param = nullptr; + if (1 != EVP_PKEY_todata(rsk.pkey.get(), EVP_PKEY_KEYPAIR, ¶m)) { + throw openssl_error(); + } + auto param_ptr = make_typed_unique(param); + + const OSSL_PARAM* sk_param = + OSSL_PARAM_locate_const(param_ptr.get(), OSSL_PKEY_PARAM_PRIV_KEY); + if (sk_param == nullptr) { + return bytes({}, 0); + } + + BIGNUM* d = nullptr; + if (1 != OSSL_PARAM_get_BN(sk_param, &d)) { + return bytes({}, 0); + } + auto d_ptr = make_typed_unique(d); +#else auto* eckey = EVP_PKEY_get0_EC_KEY(rsk.pkey.get()); const auto* d = EC_KEY_get0_private_key(eckey); +#endif auto out = bytes(BN_num_bytes(d)); if (BN_bn2bin(d, out.data()) != int(out.size())) { @@ -279,6 +503,15 @@ struct ECKeyGroup : public EVPGroup std::unique_ptr deserialize_private( const bytes& skm) const override { +#if defined(WITH_OPENSSL3) + auto priv = make_typed_unique( + BN_bin2bn(skm.data(), static_cast(skm.size()), nullptr)); + if (priv == nullptr) { + throw std::runtime_error("Unable to deserialize the private key"); + } + auto key = keypair_evp_key(priv); + return std::make_unique(key.release()); +#else auto eckey = make_typed_unique(new_ec_key()); const auto* group = EC_KEY_get0_group(eckey.get()); const auto d = make_typed_unique( @@ -290,12 +523,17 @@ struct ECKeyGroup : public EVPGroup EC_KEY_set_public_key(eckey.get(), pt.get()); return std::make_unique(to_pkey(eckey.release())); +#endif } private: int curve_nid; - EC_KEY* new_ec_key() const { return EC_KEY_new_by_curve_name(curve_nid); } +#if !defined(WITH_OPENSSL3) + EC_KEY* new_ec_key() const + { + return EC_KEY_new_by_curve_name(curve_nid); + } static EVP_PKEY* to_pkey(EC_KEY* eckey) { @@ -304,6 +542,7 @@ struct ECKeyGroup : public EVPGroup EVP_PKEY_assign_EC_KEY(pkey, eckey); return pkey; } +#endif static inline int group_to_nid(Group::ID group_id) { diff --git a/lib/hpke/src/openssl_common.cpp b/lib/hpke/src/openssl_common.cpp index b0581ba6..34d5ddb3 100644 --- a/lib/hpke/src/openssl_common.cpp +++ b/lib/hpke/src/openssl_common.cpp @@ -6,6 +6,9 @@ #include #include #include +#if defined(WITH_OPENSSL3) +#include +#endif namespace hpke { @@ -30,12 +33,14 @@ typed_delete(EVP_MD_CTX* ptr) EVP_MD_CTX_free(ptr); } +#if !defined(WITH_OPENSSL3) template<> void typed_delete(HMAC_CTX* ptr) { HMAC_CTX_free(ptr); } +#endif template<> void @@ -58,12 +63,51 @@ typed_delete(EC_POINT* ptr) EC_POINT_free(ptr); } +#if !defined(WITH_OPENSSL3) template<> void typed_delete(EC_KEY* ptr) { EC_KEY_free(ptr); } +#endif + +#if defined(WITH_OPENSSL3) +template<> +void +typed_delete(EVP_MAC* ptr) +{ + EVP_MAC_free(ptr); +} + +template<> +void +typed_delete(EVP_MAC_CTX* ptr) +{ + EVP_MAC_CTX_free(ptr); +} + +template<> +void +typed_delete(EC_GROUP* ptr) +{ + EC_GROUP_free(ptr); +} + +template<> +void +typed_delete(OSSL_PARAM_BLD* ptr) +{ + OSSL_PARAM_BLD_free(ptr); +} + +template<> +void +typed_delete(OSSL_PARAM* ptr) +{ + OSSL_PARAM_free(ptr); +} +#endif template<> void diff --git a/lib/hpke/test/aead.cpp b/lib/hpke/test/aead.cpp index 34a3f46b..93645339 100644 --- a/lib/hpke/test/aead.cpp +++ b/lib/hpke/test/aead.cpp @@ -80,6 +80,9 @@ TEST_CASE("AEAD Known-Answer") }; for (const auto& tc : cases) { + if (fips() && fips_disable(tc.id)) { + continue; + } const auto& aead = select_aead(tc.id); auto encrypted = aead.seal(tc.key, tc.nonce, tc.aad, tc.plaintext); @@ -100,6 +103,10 @@ TEST_CASE("AEAD Round-Trip") const auto aad = from_hex("04050607"); for (const auto& id : ids) { + if (fips() && fips_disable(id)) { + continue; + } + const auto& aead = select_aead(id); auto key = bytes(aead.key_size, 0xA0); auto nonce = bytes(aead.nonce_size, 0xA1); diff --git a/lib/hpke/test/common.cpp b/lib/hpke/test/common.cpp index f0fbe9fd..cfd0d930 100644 --- a/lib/hpke/test/common.cpp +++ b/lib/hpke/test/common.cpp @@ -5,20 +5,36 @@ #include #include +#if defined(WITH_OPENSSL3) +#include +#include +#endif + void ensure_fips_if_required() { // NOLINTNEXTLINE (concurrency-mt-unsafe) const auto* require = std::getenv("REQUIRE_FIPS"); +#if defined(WITH_OPENSSL3) + if (require != nullptr && OSSL_PROVIDER_available(nullptr, "fips") == 0) { + REQUIRE(OSSL_PROVIDER_load(nullptr, "fips") != nullptr); + } +#else if (require != nullptr && FIPS_mode() == 0) { REQUIRE(FIPS_mode_set(1) == 1); } +#endif } bool fips() { +#if defined(WITH_OPENSSL3) + return OSSL_PROVIDER_available(nullptr, "fips") == 1 || + EVP_default_properties_is_fips_enabled(nullptr) == 1; +#else return FIPS_mode() != 0; +#endif } bool