From 4d052a93ce2ec8cdd939de4071f1b319eaec7da9 Mon Sep 17 00:00:00 2001 From: CJ Date: Wed, 18 Jan 2023 16:55:39 +0000 Subject: [PATCH 1/8] Updated to support OpenSSL 3 --- lib/hpke/CMakeLists.txt | 14 ++- lib/hpke/src/certificate.cpp | 4 +- lib/hpke/src/digest.cpp | 62 ++++++++++ lib/hpke/src/group.cpp | 193 +++++++++++++++++++++++++++++++- lib/hpke/src/openssl_common.cpp | 44 ++++++++ 5 files changed, 309 insertions(+), 8 deletions(-) diff --git a/lib/hpke/CMakeLists.txt b/lib/hpke/CMakeLists.txt index 3a1bb340..71f17295 100644 --- a/lib/hpke/CMakeLists.txt +++ b/lib/hpke/CMakeLists.txt @@ -3,7 +3,19 @@ set(CURRENT_LIB_NAME hpke) ### ### Dependencies ### -find_package(OpenSSL 1.1 REQUIRED) +find_package(OpenSSL REQUIRED) +if ( OPENSSL_FOUND ) + if (${OPENSSL_VERSION} VERSION_GREATER 1.1.1) + 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() ### ### Library Config diff --git a/lib/hpke/src/certificate.cpp b/lib/hpke/src/certificate.cpp index 148e8068..0a7cabf4 100644 --- a/lib/hpke/src/certificate.cpp +++ b/lib/hpke/src/certificate.cpp @@ -199,8 +199,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_getm_notBefore(x509.get()))) + , not_after(asn1_time_to_chrono(X509_getm_notAfter(x509.get()))) { } diff --git a/lib/hpke/src/digest.cpp b/lib/hpke/src/digest.cpp index 21b6b721..12f0716c 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,22 @@ 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 mac = + make_typed_unique(EVP_MAC_fetch(nullptr, OSSL_MAC_NAME_HMAC, nullptr)); + auto ctx = make_typed_unique(EVP_MAC_CTX_new(mac.get())); + OSSL_PARAM params[2] = { + OSSL_PARAM_construct_utf8_string( + OSSL_ALG_PARAM_DIGEST, openssl_digest_name(id).data(), 0), + OSSL_PARAM_construct_end() + }; +#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. @@ -102,9 +139,21 @@ Digest::hmac_for_hkdf_extract(const bytes& key, const bytes& data) const // 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()); +#if defined(WITH_OPENSSL3) + if (EVP_default_properties_is_fips_enabled(nullptr) && + key_size < fips_min_hmac_key_len) { + // Currently OpenSSL's EVP_PKEY_new_mac_key API cannot deal with an empty + // key, see: https://github.com/openssl/openssl/issues/13089 As such, we + // have to use EVP_MAC API to do the HMAC operations. I am not sure if it's + // possible to do the following (or the equivalent) with EVP_MAC APIs: + // EVP_MD_CTX_set_flags(context, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW) + throw std::runtime_error("key size violates FIPS constraint"); + } +#else 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,17 +162,30 @@ Digest::hmac_for_hkdf_extract(const bytes& key, const bytes& data) const key_data = &non_null_zero_length_key; } +#if defined(WITH_OPENSSL3) + if (!EVP_MAC_init(ctx.get(), key_data, key_size, params)) { +#else if (1 != HMAC_Init_ex(ctx.get(), key_data, key_size, type, nullptr)) { +#endif throw openssl_error(); } +#if defined(WITH_OPENSSL3) + if (1 != EVP_MAC_update(ctx.get(), data.data(), data.size())) { +#else if (1 != HMAC_Update(ctx.get(), data.data(), data.size())) { +#endif throw openssl_error(); } auto md = bytes(hash_size); +#if defined(WITH_OPENSSL3) + size_t size = 0; + if (1 != EVP_MAC_final(ctx.get(), md.data(), &size, hash_size)) { +#else unsigned int size = 0; if (1 != HMAC_Final(ctx.get(), md.data(), &size)) { +#endif throw openssl_error(); } diff --git a/lib/hpke/src/group.cpp b/lib/hpke/src/group.cpp index 6b56fbdb..aace6372 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 { @@ -152,6 +156,91 @@ struct ECKeyGroup : public EVPGroup { } +#if defined(WITH_OPENSSL3) + int EVP_PKEY_set_keys(EVP_PKEY* key, const bytes& sk, const bytes& pk) const + { + auto d = make_typed_unique(BN_bin2bn(sk.data(), sk.size(), nullptr)); + if (d == nullptr) { + throw openssl_error(); + } + + auto group = make_typed_unique( + EC_GROUP_new_by_curve_name_ex(nullptr, nullptr, curve_nid)); + if (group == nullptr) { + throw openssl_error(); + } + + bytes pub(pk); + if (pk.size() == 0) { + 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(), d.get(), nullptr, nullptr, nullptr)) { + throw openssl_error(); + } + + size_t pt_size = EC_POINT_point2oct(group.get(), + pt.get(), + POINT_CONVERSION_UNCOMPRESSED, + nullptr, + 0, + nullptr); + if (!pt_size) { + return 0; + } + + pub.resize(pt_size); + if (EC_POINT_point2oct(group.get(), + pt.get(), + POINT_CONVERSION_UNCOMPRESSED, + pub.data(), + pt_size, + nullptr) != pt_size) { + return 0; + } + } + + auto bld = make_typed_unique(OSSL_PARAM_BLD_new()); + if (bld == nullptr || + !OSSL_PARAM_BLD_push_utf8_string( + bld.get(), OSSL_PKEY_PARAM_GROUP_NAME, OBJ_nid2sn(curve_nid), 0) || + !OSSL_PARAM_BLD_push_octet_string( + bld.get(), OSSL_PKEY_PARAM_PUB_KEY, pub.data(), pub.size())) { + throw openssl_error(); + } + + if (sk.size() > 0 && + !OSSL_PARAM_BLD_push_BN(bld.get(), OSSL_PKEY_PARAM_PRIV_KEY, d.get())) { + throw openssl_error(); + } + + auto params = make_typed_unique(OSSL_PARAM_BLD_to_param(bld.get())); + auto ctx = + make_typed_unique(EVP_PKEY_CTX_new_from_name(nullptr, "EC", nullptr)); + if (params == nullptr || ctx == nullptr || + EVP_PKEY_fromdata_init(ctx.get()) <= 0 || + EVP_PKEY_fromdata(ctx.get(), &key, EVP_PKEY_KEYPAIR, params.get()) <= 0) + throw openssl_error(); + ctx.reset(); + + ctx = make_typed_unique(EVP_PKEY_CTX_new_from_pkey(nullptr, key, nullptr)); + if (sk.size() > 0) { + if (EVP_PKEY_check(ctx.get()) <= 0) { + throw openssl_error(); + } + } else { + if (EVP_PKEY_public_check(ctx.get()) <= 0) { + throw openssl_error(); + } + } + + return 1; + } +#endif + std::unique_ptr derive_key_pair( const bytes& suite_id, const bytes& ikm) const override @@ -162,8 +251,14 @@ struct ECKeyGroup : public EVPGroup auto dkp_prk = kdf.labeled_extract(suite_id, {}, label_dkp_prk, ikm); +#if defined(WITH_OPENSSL3) + EC_GROUP* 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)) { @@ -171,9 +266,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) { @@ -190,6 +283,20 @@ struct ECKeyGroup : public EVPGroup } } +#if defined(WITH_OPENSSL3) + auto sk_buf = bytes(BN_num_bytes(sk.get())); + auto* data = sk_buf.data(); + if (BN_bn2bin(sk.get(), data) != int(sk_buf.size())) { + throw openssl_error(); + } + + auto* key = new_pkey(); + if (!EVP_PKEY_set_keys(key, sk_buf, {})) { + throw std::runtime_error("DeriveKeyPair fails to create key-pair"); + } + + return std::make_unique(key); +#else auto pt = make_typed_unique(EC_POINT_new(group)); EC_POINT_mul(group, pt.get(), sk.get(), nullptr, nullptr, nullptr); @@ -197,11 +304,37 @@ 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 (!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 (!OSSL_PARAM_get_octet_string(pk_param, nullptr, 0, &len)) { + return bytes({}, 0); + } + + bytes out(len); + auto* data = out.data(); + if (!OSSL_PARAM_get_octet_string( + pk_param, reinterpret_cast(&data), len, nullptr)) { + return bytes({}, 0); + } +#else auto* pub = EVP_PKEY_get0_EC_KEY(rpk.pkey.get()); auto len = i2o_ECPublicKey(pub, nullptr); @@ -214,12 +347,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 = new_pkey(); + if (!EVP_PKEY_set_keys(key, {}, enc)) { + throw std::runtime_error("Unable to deserialize the public key"); + } + return std::make_unique(key); +#else auto eckey = make_typed_unique(new_ec_key()); auto* eckey_ptr = eckey.get(); const auto* data_ptr = enc.data(); @@ -232,13 +372,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 (!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 (!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())) { @@ -253,6 +414,13 @@ struct ECKeyGroup : public EVPGroup std::unique_ptr deserialize_private( const bytes& skm) const override { +#if defined(WITH_OPENSSL3) + auto* key = new_pkey(); + if (!EVP_PKEY_set_keys(key, skm, {})) { + throw std::runtime_error("Unable to deserialize the private key"); + } + return std::make_unique(key); +#else auto eckey = make_typed_unique(new_ec_key()); const auto* group = EC_KEY_get0_group(eckey.get()); const auto d = make_typed_unique( @@ -264,12 +432,26 @@ 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) + EVP_PKEY* new_pkey() const + { + auto name = OBJ_nid2sn(curve_nid); + if (name == nullptr) { + throw std::runtime_error("Unsupported algorithm"); + } + return EVP_EC_gen(name); + } +#else + EC_KEY* new_ec_key() const + { + return EC_KEY_new_by_curve_name(curve_nid); + } static EVP_PKEY* to_pkey(EC_KEY* eckey) { @@ -278,6 +460,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 From 54ffe0be50bb0294002b2eb6cbe95b336d49db7e Mon Sep 17 00:00:00 2001 From: CJ Date: Fri, 27 Jan 2023 23:28:26 +0000 Subject: [PATCH 2/8] Addressed reviewer's comments * Refactored group.cpp * Added Github actions for OpenSSL 3 * Added OpenSSL vcpkg.json for MLS library and interop binary --- .github/workflows/build_openssl3.yml | 72 ++++++ .github/workflows/compat_openssl3.yml | 43 ++++ .github/workflows/interop_openssl3.yml | 42 ++++ alternatives/openssl_3/vcpkg.json | 19 ++ cmd/interop/alternatives/openssl_3/vcpkg.json | 22 ++ lib/bytes/test/bytes.cpp | 1 + lib/hpke/src/certificate.cpp | 4 +- lib/hpke/src/digest.cpp | 26 +-- lib/hpke/src/group.cpp | 218 +++++++++++------- lib/hpke/test/common.cpp | 28 +++ 10 files changed, 373 insertions(+), 102 deletions(-) create mode 100644 .github/workflows/build_openssl3.yml create mode 100644 .github/workflows/compat_openssl3.yml create mode 100644 .github/workflows/interop_openssl3.yml create mode 100644 alternatives/openssl_3/vcpkg.json create mode 100644 cmd/interop/alternatives/openssl_3/vcpkg.json diff --git a/.github/workflows/build_openssl3.yml b/.github/workflows/build_openssl3.yml new file mode 100644 index 00000000..48f45d70 --- /dev/null +++ b/.github/workflows/build_openssl3.yml @@ -0,0 +1,72 @@ +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 + 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: Cleanup + run: | + rm -rf "${{ env.CMAKE_BUILD_DIR }}" + + - 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/.github/workflows/compat_openssl3.yml b/.github/workflows/compat_openssl3.yml new file mode 100644 index 00000000..3c630506 --- /dev/null +++ b/.github/workflows/compat_openssl3.yml @@ -0,0 +1,43 @@ +name: Build for older MacOS + +on: + push: + branches: + - main + pull_request: + branches: + - main + +env: + CTEST_OUTPUT_ON_FAILURE: 1 + MACOSX_DEPLOYMENT_TARGET: 10.11 + +jobs: + build: + runs-on: macos-latest + + env: + CMAKE_BUILD_DIR: ${{ github.workspace }}/build + TOOLCHAIN_FILE: $VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake + OSSL3_VCPKG_DIR: ${{ github.workspace }}/alternatives/openssl_3 + + steps: + - uses: actions/checkout@v2 + + - name: dependencies + run: | + brew install llvm + 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: build the library + run: | + cmake -B "${{ env.CMAKE_BUILD_DIR }}" -DVCPKG_MANIFEST_DIR="${{ env.OSSL3_VCPKG_DIR }}" -DCMAKE_TOOLCHAIN_FILE="${{ env.TOOLCHAIN_FILE }}" . + cmake --build "${{ env.CMAKE_BUILD_DIR }}" --target mlspp diff --git a/.github/workflows/interop_openssl3.yml b/.github/workflows/interop_openssl3.yml new file mode 100644 index 00000000..70790027 --- /dev/null +++ b/.github/workflows/interop_openssl3.yml @@ -0,0 +1,42 @@ +name: Build the interop harness (OpenSSL 3) + +on: + push: + branches: + - main + pull_request: + branches: + - main + +env: + CTEST_OUTPUT_ON_FAILURE: 1 + +jobs: + build: + runs-on: ubuntu-latest + + env: + CMAKE_BUILD_DIR: ${{ github.workspace }}/build + TOOLCHAIN_FILE: $VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake + OSSL3_VCPKG_DIR: ${{ github.workspace }}/cmd/interop/alternatives/openssl_3 + + steps: + - uses: actions/checkout@v2 + + - name: Restore cache + uses: actions/cache@v2 + with: + path: | + ${{ env.CMAKE_BUILD_DIR }}/vcpkg_installed + key: ${{ runner.os }}-${{ hashFiles( '**/vcpkg.json' ) }} + + - name: Build the library + run: | + cmake -B build -DVCPKG_MANIFEST_DIR="${{ env.OSSL3_VCPKG_DIR }}" -DCMAKE_TOOLCHAIN_FILE="${{ env.TOOLCHAIN_FILE }}" . + cmake --build build + + - name: Build interop harness + run: | + cd cmd/interop + cmake -B build -DSANITIZERS=ON -DVCPKG_MANIFEST_DIR="${{ env.OSSL3_VCPKG_DIR }}" -DCMAKE_TOOLCHAIN_FILE="${{ env.TOOLCHAIN_FILE }}" . + cmake --build build diff --git a/alternatives/openssl_3/vcpkg.json b/alternatives/openssl_3/vcpkg.json new file mode 100644 index 00000000..c26fb807 --- /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": "3b3bd424827a1f7f4813216f6b32b6c61e386b2e", + "overrides": [ + { + "name": "openssl", + "version": "3.0.7" + } + ] +} diff --git a/cmd/interop/alternatives/openssl_3/vcpkg.json b/cmd/interop/alternatives/openssl_3/vcpkg.json new file mode 100644 index 00000000..bc4e7a6b --- /dev/null +++ b/cmd/interop/alternatives/openssl_3/vcpkg.json @@ -0,0 +1,22 @@ +{ + "name": "mlspp-interop", + "version-string": "0.1", + "description": "Interop harness for Cisco MLS C++ library (OpenSSL 3)", + "dependencies": [ + { + "name": "openssl", + "version>=": "3.0.7" + }, + "protobuf", + "grpc", + "gflags", + "nlohmann-json" + ], + "builtin-baseline": "3b3bd424827a1f7f4813216f6b32b6c61e386b2e", + "overrides": [ + { + "name": "openssl", + "version-string": "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 d9011302..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_getm_notBefore(x509.get()))) - , not_after(asn1_time_to_chrono(X509_getm_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 12f0716c..1499a83f 100644 --- a/lib/hpke/src/digest.cpp +++ b/lib/hpke/src/digest.cpp @@ -118,11 +118,10 @@ Digest::hmac_for_hkdf_extract(const bytes& key, const bytes& data) const auto mac = make_typed_unique(EVP_MAC_fetch(nullptr, OSSL_MAC_NAME_HMAC, nullptr)); auto ctx = make_typed_unique(EVP_MAC_CTX_new(mac.get())); - OSSL_PARAM params[2] = { - OSSL_PARAM_construct_utf8_string( - OSSL_ALG_PARAM_DIGEST, openssl_digest_name(id).data(), 0), - OSSL_PARAM_construct_end() - }; + auto digest_name = openssl_digest_name(id); + OSSL_PARAM params[2] = { OSSL_PARAM_construct_utf8_string( + OSSL_ALG_PARAM_DIGEST, digest_name.data(), 0), + OSSL_PARAM_construct_end() }; #else const auto* type = openssl_digest_type(id); auto ctx = make_typed_unique(HMAC_CTX_new()); @@ -137,19 +136,12 @@ 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()); -#if defined(WITH_OPENSSL3) - if (EVP_default_properties_is_fips_enabled(nullptr) && - key_size < fips_min_hmac_key_len) { - // Currently OpenSSL's EVP_PKEY_new_mac_key API cannot deal with an empty - // key, see: https://github.com/openssl/openssl/issues/13089 As such, we - // have to use EVP_MAC API to do the HMAC operations. I am not sure if it's - // possible to do the following (or the equivalent) with EVP_MAC APIs: - // EVP_MD_CTX_set_flags(context, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW) - throw std::runtime_error("key size violates FIPS constraint"); - } -#else + // 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); } diff --git a/lib/hpke/src/group.cpp b/lib/hpke/src/group.cpp index 42e2fc6a..f8ec291f 100644 --- a/lib/hpke/src/group.cpp +++ b/lib/hpke/src/group.cpp @@ -155,11 +155,12 @@ struct ECKeyGroup : public EVPGroup } #if defined(WITH_OPENSSL3) - int EVP_PKEY_set_keys(EVP_PKEY* key, const bytes& sk, const bytes& pk) const + typed_unique_ptr keypair_evp_key( + const typed_unique_ptr& priv) const { - auto d = make_typed_unique(BN_bin2bn(sk.data(), sk.size(), nullptr)); - if (d == nullptr) { - throw openssl_error(); + auto name = OBJ_nid2sn(curve_nid); + if (name == nullptr) { + throw std::runtime_error("Unsupported algorithm"); } auto group = make_typed_unique( @@ -168,74 +169,111 @@ struct ECKeyGroup : public EVPGroup throw openssl_error(); } - bytes pub(pk); - if (pk.size() == 0) { - auto pt = make_typed_unique(EC_POINT_new(group.get())); - if (pt == 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(), d.get(), nullptr, nullptr, nullptr)) { - throw openssl_error(); - } + if (1 != EC_POINT_mul( + group.get(), pt.get(), priv.get(), nullptr, nullptr, nullptr)) { + throw openssl_error(); + } - size_t pt_size = EC_POINT_point2oct(group.get(), - pt.get(), - POINT_CONVERSION_UNCOMPRESSED, - nullptr, - 0, - nullptr); - if (!pt_size) { - return 0; - } + size_t pt_size = EC_POINT_point2oct(group.get(), + pt.get(), + POINT_CONVERSION_UNCOMPRESSED, + nullptr, + 0, + nullptr); + if (!pt_size) { + throw openssl_error(); + } - pub.resize(pt_size); - if (EC_POINT_point2oct(group.get(), - pt.get(), - POINT_CONVERSION_UNCOMPRESSED, - pub.data(), - pt_size, - nullptr) != pt_size) { - return 0; - } + 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 bld = make_typed_unique(OSSL_PARAM_BLD_new()); - if (bld == nullptr || + auto builder = make_typed_unique(OSSL_PARAM_BLD_new()); + if (builder == nullptr || !OSSL_PARAM_BLD_push_utf8_string( - bld.get(), OSSL_PKEY_PARAM_GROUP_NAME, OBJ_nid2sn(curve_nid), 0) || + builder.get(), OSSL_PKEY_PARAM_GROUP_NAME, name, 0) || + !OSSL_PARAM_BLD_push_BN( + builder.get(), OSSL_PKEY_PARAM_PRIV_KEY, priv.get()) || !OSSL_PARAM_BLD_push_octet_string( - bld.get(), OSSL_PKEY_PARAM_PUB_KEY, pub.data(), pub.size())) { + 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 + { + 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(); } - if (sk.size() > 0 && - !OSSL_PARAM_BLD_push_BN(bld.get(), OSSL_PKEY_PARAM_PRIV_KEY, d.get())) { + auto builder = make_typed_unique(OSSL_PARAM_BLD_new()); + if (builder == nullptr || + !OSSL_PARAM_BLD_push_utf8_string( + builder.get(), OSSL_PKEY_PARAM_GROUP_NAME, name, 0) || + !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(bld.get())); + 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)); - if (params == nullptr || ctx == 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, EVP_PKEY_KEYPAIR, params.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, nullptr)); - if (sk.size() > 0) { - if (EVP_PKEY_check(ctx.get()) <= 0) { - throw openssl_error(); - } - } else { - if (EVP_PKEY_public_check(ctx.get()) <= 0) { - throw openssl_error(); - } + 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 1; + return key; } #endif @@ -250,8 +288,7 @@ struct ECKeyGroup : public EVPGroup auto dkp_prk = kdf.labeled_extract(suite_id, {}, label_dkp_prk, ikm); #if defined(WITH_OPENSSL3) - EC_GROUP* group = - EC_GROUP_new_by_curve_name_ex(nullptr, nullptr, curve_nid); + 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()); @@ -282,18 +319,8 @@ struct ECKeyGroup : public EVPGroup } #if defined(WITH_OPENSSL3) - auto sk_buf = bytes(BN_num_bytes(sk.get())); - auto* data = sk_buf.data(); - if (BN_bn2bin(sk.get(), data) != int(sk_buf.size())) { - throw openssl_error(); - } - - auto* key = new_pkey(); - if (!EVP_PKEY_set_keys(key, sk_buf, {})) { - throw std::runtime_error("DeriveKeyPair fails to create key-pair"); - } - - return std::make_unique(key); + 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); @@ -326,10 +353,43 @@ struct ECKeyGroup : public EVPGroup return bytes({}, 0); } + bytes buf(len); + auto* buf_ptr = buf.data(); + if (!OSSL_PARAM_get_octet_string( + pk_param, reinterpret_cast(&buf_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())); + if (!EC_POINT_oct2point(group.get(), point.get(), buf_ptr, len, nullptr)) { + return bytes({}, 0); + } + len = EC_POINT_point2oct(group.get(), + point.get(), + POINT_CONVERSION_UNCOMPRESSED, + nullptr, + 0, + nullptr); + if (!len) { + return bytes({}, 0); + } bytes out(len); auto* data = out.data(); - if (!OSSL_PARAM_get_octet_string( - pk_param, reinterpret_cast(&data), len, nullptr)) { + if (EC_POINT_point2oct(group.get(), + point.get(), + POINT_CONVERSION_UNCOMPRESSED, + data, + len, + nullptr) != len) { return bytes({}, 0); } #else @@ -352,11 +412,11 @@ struct ECKeyGroup : public EVPGroup std::unique_ptr deserialize(const bytes& enc) const override { #if defined(WITH_OPENSSL3) - auto* key = new_pkey(); - if (!EVP_PKEY_set_keys(key, {}, enc)) { + auto key = public_evp_key(enc); + if (key == nullptr) { throw std::runtime_error("Unable to deserialize the public key"); } - return std::make_unique(key); + return std::make_unique(key.release()); #else auto eckey = make_typed_unique(new_ec_key()); auto* eckey_ptr = eckey.get(); @@ -413,11 +473,12 @@ struct ECKeyGroup : public EVPGroup const bytes& skm) const override { #if defined(WITH_OPENSSL3) - auto* key = new_pkey(); - if (!EVP_PKEY_set_keys(key, skm, {})) { + auto priv = make_typed_unique(BN_bin2bn(skm.data(), skm.size(), nullptr)); + if (priv == nullptr) { throw std::runtime_error("Unable to deserialize the private key"); } - return std::make_unique(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()); @@ -436,16 +497,7 @@ struct ECKeyGroup : public EVPGroup private: int curve_nid; -#if defined(WITH_OPENSSL3) - EVP_PKEY* new_pkey() const - { - auto name = OBJ_nid2sn(curve_nid); - if (name == nullptr) { - throw std::runtime_error("Unsupported algorithm"); - } - return EVP_EC_gen(name); - } -#else +#if !defined(WITH_OPENSSL3) EC_KEY* new_ec_key() const { return EC_KEY_new_by_curve_name(curve_nid); diff --git a/lib/hpke/test/common.cpp b/lib/hpke/test/common.cpp index f0fbe9fd..611c758c 100644 --- a/lib/hpke/test/common.cpp +++ b/lib/hpke/test/common.cpp @@ -5,6 +5,34 @@ #include #include +#if defined(WITH_OPENSSL3) +#include +#include + +static OSSL_PROVIDER* fips_prov = nullptr; + +static int +FIPS_mode() +{ + if (OSSL_PROVIDER_available(nullptr, "fips") == 1) { + return 1; + } + return EVP_default_properties_is_fips_enabled(nullptr); +} + +static int +FIPS_mode_set(int enable) +{ + if (enable && fips_prov == nullptr) { + fips_prov = OSSL_PROVIDER_load(nullptr, "fips"); + return fips_prov != nullptr; + } else if (!enable && fips_prov != nullptr) { + return OSSL_PROVIDER_unload(fips_prov); + } + return 0; +} +#endif + void ensure_fips_if_required() { From 5d5ea5bffbf03f60c74240b561fc0d2b57aec71a Mon Sep 17 00:00:00 2001 From: CJ Date: Mon, 23 Jan 2023 04:52:09 -0500 Subject: [PATCH 3/8] clang-tidy conformance and updated tests for FIPS mode --- lib/hpke/src/digest.cpp | 10 +++--- lib/hpke/src/group.cpp | 50 +++++++++++++++------------- lib/hpke/test/aead.cpp | 7 ++++ lib/hpke/test/common.cpp | 11 +++--- lib/mls_vectors/test/fips.cpp | 23 +++++++++++++ lib/mls_vectors/test/fips.h | 7 ++++ lib/mls_vectors/test/mls_vectors.cpp | 9 +++++ test/crypto.cpp | 5 +++ test/fips.cpp | 23 +++++++++++++ test/fips.h | 7 ++++ test/key_schedule.cpp | 5 +++ test/treekem.cpp | 5 +++ 12 files changed, 130 insertions(+), 32 deletions(-) create mode 100644 lib/mls_vectors/test/fips.cpp create mode 100644 lib/mls_vectors/test/fips.h create mode 100644 test/fips.cpp create mode 100644 test/fips.h diff --git a/lib/hpke/src/digest.cpp b/lib/hpke/src/digest.cpp index 1499a83f..b8bbd621 100644 --- a/lib/hpke/src/digest.cpp +++ b/lib/hpke/src/digest.cpp @@ -119,9 +119,11 @@ Digest::hmac_for_hkdf_extract(const bytes& key, const bytes& data) const make_typed_unique(EVP_MAC_fetch(nullptr, OSSL_MAC_NAME_HMAC, nullptr)); auto ctx = make_typed_unique(EVP_MAC_CTX_new(mac.get())); auto digest_name = openssl_digest_name(id); - OSSL_PARAM params[2] = { OSSL_PARAM_construct_utf8_string( - OSSL_ALG_PARAM_DIGEST, digest_name.data(), 0), - OSSL_PARAM_construct_end() }; + std::array params = { + OSSL_PARAM_construct_utf8_string( + OSSL_ALG_PARAM_DIGEST, digest_name.data(), 0), + OSSL_PARAM_construct_end() + }; #else const auto* type = openssl_digest_type(id); auto ctx = make_typed_unique(HMAC_CTX_new()); @@ -155,7 +157,7 @@ Digest::hmac_for_hkdf_extract(const bytes& key, const bytes& data) const } #if defined(WITH_OPENSSL3) - if (!EVP_MAC_init(ctx.get(), key_data, key_size, params)) { + if (1 != EVP_MAC_init(ctx.get(), key_data, key_size, params.data())) { #else if (1 != HMAC_Init_ex(ctx.get(), key_data, key_size, type, nullptr)) { #endif diff --git a/lib/hpke/src/group.cpp b/lib/hpke/src/group.cpp index f8ec291f..a30193e6 100644 --- a/lib/hpke/src/group.cpp +++ b/lib/hpke/src/group.cpp @@ -158,7 +158,7 @@ struct ECKeyGroup : public EVPGroup typed_unique_ptr keypair_evp_key( const typed_unique_ptr& priv) const { - auto name = OBJ_nid2sn(curve_nid); + const auto* name = OBJ_nid2sn(curve_nid); if (name == nullptr) { throw std::runtime_error("Unsupported algorithm"); } @@ -185,7 +185,7 @@ struct ECKeyGroup : public EVPGroup nullptr, 0, nullptr); - if (!pt_size) { + if (0 == pt_size) { throw openssl_error(); } @@ -201,12 +201,13 @@ struct ECKeyGroup : public EVPGroup auto builder = make_typed_unique(OSSL_PARAM_BLD_new()); if (builder == nullptr || - !OSSL_PARAM_BLD_push_utf8_string( - builder.get(), OSSL_PKEY_PARAM_GROUP_NAME, name, 0) || - !OSSL_PARAM_BLD_push_BN( - builder.get(), OSSL_PKEY_PARAM_PRIV_KEY, priv.get()) || - !OSSL_PARAM_BLD_push_octet_string( - builder.get(), OSSL_PKEY_PARAM_PUB_KEY, pub.data(), pub.size())) { + 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(); } @@ -234,7 +235,7 @@ struct ECKeyGroup : public EVPGroup typed_unique_ptr public_evp_key(const bytes& pub) const { - auto name = OBJ_nid2sn(curve_nid); + const auto* name = OBJ_nid2sn(curve_nid); if (name == nullptr) { throw std::runtime_error("Unsupported algorithm"); } @@ -247,10 +248,11 @@ struct ECKeyGroup : public EVPGroup auto builder = make_typed_unique(OSSL_PARAM_BLD_new()); if (builder == nullptr || - !OSSL_PARAM_BLD_push_utf8_string( - builder.get(), OSSL_PKEY_PARAM_GROUP_NAME, name, 0) || - !OSSL_PARAM_BLD_push_octet_string( - builder.get(), OSSL_PKEY_PARAM_PUB_KEY, pub.data(), pub.size())) { + 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(); } @@ -337,7 +339,7 @@ struct ECKeyGroup : public EVPGroup const auto& rpk = dynamic_cast(pk); #if defined(WITH_OPENSSL3) OSSL_PARAM* param = nullptr; - if (!EVP_PKEY_todata(rpk.pkey.get(), EVP_PKEY_PUBLIC_KEY, ¶m)) { + if (1 != EVP_PKEY_todata(rpk.pkey.get(), EVP_PKEY_PUBLIC_KEY, ¶m)) { throw openssl_error(); } auto param_ptr = make_typed_unique(param); @@ -349,14 +351,13 @@ struct ECKeyGroup : public EVPGroup } size_t len = 0; - if (!OSSL_PARAM_get_octet_string(pk_param, nullptr, 0, &len)) { + if (1 != OSSL_PARAM_get_octet_string(pk_param, nullptr, 0, &len)) { return bytes({}, 0); } bytes buf(len); - auto* buf_ptr = buf.data(); - if (!OSSL_PARAM_get_octet_string( - pk_param, reinterpret_cast(&buf_ptr), len, nullptr)) { + void* data_ptr = buf.data(); + if (1 != OSSL_PARAM_get_octet_string(pk_param, &data_ptr, len, nullptr)) { return bytes({}, 0); } @@ -370,7 +371,9 @@ struct ECKeyGroup : public EVPGroup return bytes({}, 0); } auto point = make_typed_unique(EC_POINT_new(group.get())); - if (!EC_POINT_oct2point(group.get(), point.get(), buf_ptr, len, nullptr)) { + 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(), @@ -379,7 +382,7 @@ struct ECKeyGroup : public EVPGroup nullptr, 0, nullptr); - if (!len) { + if (0 == len) { return bytes({}, 0); } bytes out(len); @@ -438,7 +441,7 @@ struct ECKeyGroup : public EVPGroup const auto& rsk = dynamic_cast(sk); #if defined(WITH_OPENSSL3) OSSL_PARAM* param = nullptr; - if (!EVP_PKEY_todata(rsk.pkey.get(), EVP_PKEY_KEYPAIR, ¶m)) { + if (1 != EVP_PKEY_todata(rsk.pkey.get(), EVP_PKEY_KEYPAIR, ¶m)) { throw openssl_error(); } auto param_ptr = make_typed_unique(param); @@ -450,7 +453,7 @@ struct ECKeyGroup : public EVPGroup } BIGNUM* d = nullptr; - if (!OSSL_PARAM_get_BN(sk_param, &d)) { + if (1 != OSSL_PARAM_get_BN(sk_param, &d)) { return bytes({}, 0); } auto d_ptr = make_typed_unique(d); @@ -473,7 +476,8 @@ struct ECKeyGroup : public EVPGroup const bytes& skm) const override { #if defined(WITH_OPENSSL3) - auto priv = make_typed_unique(BN_bin2bn(skm.data(), skm.size(), nullptr)); + 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"); } 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 611c758c..c3131fc0 100644 --- a/lib/hpke/test/common.cpp +++ b/lib/hpke/test/common.cpp @@ -23,13 +23,14 @@ FIPS_mode() static int FIPS_mode_set(int enable) { - if (enable && fips_prov == nullptr) { + auto retval = 0; + if (enable != 0 && fips_prov == nullptr) { fips_prov = OSSL_PROVIDER_load(nullptr, "fips"); - return fips_prov != nullptr; - } else if (!enable && fips_prov != nullptr) { - return OSSL_PROVIDER_unload(fips_prov); + retval = (fips_prov != nullptr) ? 1 : 0; + } else if (enable == 0 && fips_prov != nullptr) { + retval = OSSL_PROVIDER_unload(fips_prov); } - return 0; + return retval; } #endif diff --git a/lib/mls_vectors/test/fips.cpp b/lib/mls_vectors/test/fips.cpp new file mode 100644 index 00000000..4121a706 --- /dev/null +++ b/lib/mls_vectors/test/fips.cpp @@ -0,0 +1,23 @@ +#include "fips.h" +#include +#include +#include + +using namespace mls; + +bool +fips() +{ + return OSSL_PROVIDER_available(nullptr, "fips") == 1 || + EVP_default_properties_is_fips_enabled(nullptr) == 1; +} + +bool +is_fips_approved(CipherSuite::ID id) +{ + static const auto disallowed = std::set{ + CipherSuite::ID::X25519_CHACHA20POLY1305_SHA256_Ed25519, + CipherSuite::ID::X448_CHACHA20POLY1305_SHA512_Ed448, + }; + return disallowed.count(id) == 0; +} diff --git a/lib/mls_vectors/test/fips.h b/lib/mls_vectors/test/fips.h new file mode 100644 index 00000000..a7428e5b --- /dev/null +++ b/lib/mls_vectors/test/fips.h @@ -0,0 +1,7 @@ +#include + +bool +fips(); + +bool +is_fips_approved(mls::CipherSuite::ID id); diff --git a/lib/mls_vectors/test/mls_vectors.cpp b/lib/mls_vectors/test/mls_vectors.cpp index 745b7ccd..f91b74d4 100644 --- a/lib/mls_vectors/test/mls_vectors.cpp +++ b/lib/mls_vectors/test/mls_vectors.cpp @@ -1,3 +1,4 @@ +#include "fips.h" #include #include #include @@ -22,6 +23,10 @@ TEST_CASE("Tree Math") TEST_CASE("Encryption Keys") { for (auto suite : supported_suites) { + if (fips() && !is_fips_approved(suite.cipher_suite())) { + continue; + } + const auto tv = EncryptionTestVector::create(suite, 15, 10); REQUIRE(tv.verify() == std::nullopt); } @@ -46,6 +51,10 @@ TEST_CASE("Transcript") TEST_CASE("TreeKEM") { for (auto suite : supported_suites) { + if (fips() && !is_fips_approved(suite.cipher_suite())) { + continue; + } + const auto tv = TreeKEMTestVector::create(suite, 10); REQUIRE(tv.verify() == std::nullopt); } diff --git a/test/crypto.cpp b/test/crypto.cpp index 7c84276c..aac61b72 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -1,3 +1,4 @@ +#include "fips.h" #include #include @@ -12,6 +13,10 @@ TEST_CASE("Basic HPKE") auto original = random_bytes(100); for (auto suite_id : all_supported_suites) { + if (fips() && !is_fips_approved(suite_id)) { + continue; + } + auto suite = CipherSuite{ suite_id }; auto s = bytes{ 0, 1, 2, 3 }; diff --git a/test/fips.cpp b/test/fips.cpp new file mode 100644 index 00000000..4121a706 --- /dev/null +++ b/test/fips.cpp @@ -0,0 +1,23 @@ +#include "fips.h" +#include +#include +#include + +using namespace mls; + +bool +fips() +{ + return OSSL_PROVIDER_available(nullptr, "fips") == 1 || + EVP_default_properties_is_fips_enabled(nullptr) == 1; +} + +bool +is_fips_approved(CipherSuite::ID id) +{ + static const auto disallowed = std::set{ + CipherSuite::ID::X25519_CHACHA20POLY1305_SHA256_Ed25519, + CipherSuite::ID::X448_CHACHA20POLY1305_SHA512_Ed448, + }; + return disallowed.count(id) == 0; +} diff --git a/test/fips.h b/test/fips.h new file mode 100644 index 00000000..a7428e5b --- /dev/null +++ b/test/fips.h @@ -0,0 +1,7 @@ +#include + +bool +fips(); + +bool +is_fips_approved(mls::CipherSuite::ID id); diff --git a/test/key_schedule.cpp b/test/key_schedule.cpp index 4863578b..c36423ef 100644 --- a/test/key_schedule.cpp +++ b/test/key_schedule.cpp @@ -1,3 +1,4 @@ +#include "fips.h" #include #include #include @@ -8,6 +9,10 @@ using namespace mls_vectors; TEST_CASE("Encryption Keys Interop") { for (auto suite : all_supported_suites) { + if (fips() && !is_fips_approved(suite)) { + continue; + } + const auto tv = EncryptionTestVector::create(suite, 15, 10); REQUIRE(tv.verify() == std::nullopt); } diff --git a/test/treekem.cpp b/test/treekem.cpp index a1cdef21..c79039cd 100644 --- a/test/treekem.cpp +++ b/test/treekem.cpp @@ -1,3 +1,4 @@ +#include "fips.h" #include #include #include @@ -266,6 +267,10 @@ TEST_CASE_FIXTURE(TreeKEMTest, "TreeKEM encap/decap") TEST_CASE("TreeKEM Interop") { for (auto suite : all_supported_suites) { + if (fips() && !is_fips_approved(suite)) { + continue; + } + auto tv = TreeKEMTestVector::create(suite, 10); tv.initialize_trees(); REQUIRE(tv.verify() == std::nullopt); From 07642097d88d787d752b4810605038cc0bd94b70 Mon Sep 17 00:00:00 2001 From: CJ Date: Tue, 31 Jan 2023 11:27:52 +0000 Subject: [PATCH 4/8] Fixed broken GitHub actions --- .github/workflows/build_openssl3.yml | 4 ---- CMakeLists.txt | 17 +++++++++++++++-- lib/hpke/CMakeLists.txt | 14 +------------- lib/hpke/src/group.cpp | 12 ++++++------ lib/mls_vectors/test/fips.cpp | 8 ++++++++ test/fips.cpp | 8 ++++++++ 6 files changed, 38 insertions(+), 25 deletions(-) diff --git a/.github/workflows/build_openssl3.yml b/.github/workflows/build_openssl3.yml index 48f45d70..9500bc57 100644 --- a/.github/workflows/build_openssl3.yml +++ b/.github/workflows/build_openssl3.yml @@ -48,10 +48,6 @@ jobs: 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: Cleanup - run: | - rm -rf "${{ env.CMAKE_BUILD_DIR }}" - - name: Restore cache uses: actions/cache@v2 with: diff --git a/CMakeLists.txt b/CMakeLists.txt index f9181691..8cecb101 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 1.1.1) + 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/lib/hpke/CMakeLists.txt b/lib/hpke/CMakeLists.txt index 71f17295..3a1bb340 100644 --- a/lib/hpke/CMakeLists.txt +++ b/lib/hpke/CMakeLists.txt @@ -3,19 +3,7 @@ set(CURRENT_LIB_NAME hpke) ### ### Dependencies ### -find_package(OpenSSL REQUIRED) -if ( OPENSSL_FOUND ) - if (${OPENSSL_VERSION} VERSION_GREATER 1.1.1) - 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() +find_package(OpenSSL 1.1 REQUIRED) ### ### Library Config diff --git a/lib/hpke/src/group.cpp b/lib/hpke/src/group.cpp index a30193e6..b8fd785c 100644 --- a/lib/hpke/src/group.cpp +++ b/lib/hpke/src/group.cpp @@ -179,12 +179,12 @@ struct ECKeyGroup : public EVPGroup throw openssl_error(); } - size_t pt_size = EC_POINT_point2oct(group.get(), - pt.get(), - POINT_CONVERSION_UNCOMPRESSED, - nullptr, - 0, - nullptr); + const auto pt_size = EC_POINT_point2oct(group.get(), + pt.get(), + POINT_CONVERSION_UNCOMPRESSED, + nullptr, + 0, + nullptr); if (0 == pt_size) { throw openssl_error(); } diff --git a/lib/mls_vectors/test/fips.cpp b/lib/mls_vectors/test/fips.cpp index 4121a706..ebb2b034 100644 --- a/lib/mls_vectors/test/fips.cpp +++ b/lib/mls_vectors/test/fips.cpp @@ -1,6 +1,10 @@ #include "fips.h" +#if defined(WITH_OPENSSL3) #include #include +#else +#include +#endif #include using namespace mls; @@ -8,8 +12,12 @@ using namespace mls; 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() == 1; +#endif } bool diff --git a/test/fips.cpp b/test/fips.cpp index 4121a706..ebb2b034 100644 --- a/test/fips.cpp +++ b/test/fips.cpp @@ -1,6 +1,10 @@ #include "fips.h" +#if defined(WITH_OPENSSL3) #include #include +#else +#include +#endif #include using namespace mls; @@ -8,8 +12,12 @@ using namespace mls; 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() == 1; +#endif } bool From f933250dcb7c3550b8450ae2615183462d98dac5 Mon Sep 17 00:00:00 2001 From: CJ Date: Tue, 31 Jan 2023 06:31:10 -0500 Subject: [PATCH 5/8] Updated built-baseline to allow Windows to find OpenSSL 3.0.7 --- .github/workflows/compat_openssl3.yml | 2 +- alternatives/openssl_3/vcpkg.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/compat_openssl3.yml b/.github/workflows/compat_openssl3.yml index 3c630506..236f4663 100644 --- a/.github/workflows/compat_openssl3.yml +++ b/.github/workflows/compat_openssl3.yml @@ -1,4 +1,4 @@ -name: Build for older MacOS +name: Build for older MacOS (OpenSSL 3) on: push: diff --git a/alternatives/openssl_3/vcpkg.json b/alternatives/openssl_3/vcpkg.json index c26fb807..4b4d7657 100644 --- a/alternatives/openssl_3/vcpkg.json +++ b/alternatives/openssl_3/vcpkg.json @@ -9,7 +9,7 @@ }, "doctest" ], - "builtin-baseline": "3b3bd424827a1f7f4813216f6b32b6c61e386b2e", + "builtin-baseline": "5908d702d61cea1429b223a0b7a10ab86bad4c78", "overrides": [ { "name": "openssl", From 9df638a2a87ea00850e768d13f68d423a853b52a Mon Sep 17 00:00:00 2001 From: CJ Date: Thu, 9 Feb 2023 15:07:47 +0000 Subject: [PATCH 6/8] Addressed reviewer's comments --- .github/workflows/compat_openssl3.yml | 43 -------------------------- .github/workflows/interop_openssl3.yml | 42 ------------------------- CMakeLists.txt | 2 +- lib/hpke/src/digest.cpp | 28 ++++++++--------- lib/hpke/test/common.cpp | 35 +++++++-------------- lib/mls_vectors/test/fips.cpp | 31 ------------------- lib/mls_vectors/test/fips.h | 7 ----- lib/mls_vectors/test/mls_vectors.cpp | 5 --- test/crypto.cpp | 5 --- test/fips.cpp | 31 ------------------- test/fips.h | 7 ----- test/key_schedule.cpp | 1 - test/treekem.cpp | 5 --- 13 files changed, 25 insertions(+), 217 deletions(-) delete mode 100644 .github/workflows/compat_openssl3.yml delete mode 100644 .github/workflows/interop_openssl3.yml delete mode 100644 lib/mls_vectors/test/fips.cpp delete mode 100644 lib/mls_vectors/test/fips.h delete mode 100644 test/fips.cpp delete mode 100644 test/fips.h diff --git a/.github/workflows/compat_openssl3.yml b/.github/workflows/compat_openssl3.yml deleted file mode 100644 index 236f4663..00000000 --- a/.github/workflows/compat_openssl3.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: Build for older MacOS (OpenSSL 3) - -on: - push: - branches: - - main - pull_request: - branches: - - main - -env: - CTEST_OUTPUT_ON_FAILURE: 1 - MACOSX_DEPLOYMENT_TARGET: 10.11 - -jobs: - build: - runs-on: macos-latest - - env: - CMAKE_BUILD_DIR: ${{ github.workspace }}/build - TOOLCHAIN_FILE: $VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake - OSSL3_VCPKG_DIR: ${{ github.workspace }}/alternatives/openssl_3 - - steps: - - uses: actions/checkout@v2 - - - name: dependencies - run: | - brew install llvm - 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: build the library - run: | - cmake -B "${{ env.CMAKE_BUILD_DIR }}" -DVCPKG_MANIFEST_DIR="${{ env.OSSL3_VCPKG_DIR }}" -DCMAKE_TOOLCHAIN_FILE="${{ env.TOOLCHAIN_FILE }}" . - cmake --build "${{ env.CMAKE_BUILD_DIR }}" --target mlspp diff --git a/.github/workflows/interop_openssl3.yml b/.github/workflows/interop_openssl3.yml deleted file mode 100644 index 70790027..00000000 --- a/.github/workflows/interop_openssl3.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: Build the interop harness (OpenSSL 3) - -on: - push: - branches: - - main - pull_request: - branches: - - main - -env: - CTEST_OUTPUT_ON_FAILURE: 1 - -jobs: - build: - runs-on: ubuntu-latest - - env: - CMAKE_BUILD_DIR: ${{ github.workspace }}/build - TOOLCHAIN_FILE: $VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake - OSSL3_VCPKG_DIR: ${{ github.workspace }}/cmd/interop/alternatives/openssl_3 - - steps: - - uses: actions/checkout@v2 - - - name: Restore cache - uses: actions/cache@v2 - with: - path: | - ${{ env.CMAKE_BUILD_DIR }}/vcpkg_installed - key: ${{ runner.os }}-${{ hashFiles( '**/vcpkg.json' ) }} - - - name: Build the library - run: | - cmake -B build -DVCPKG_MANIFEST_DIR="${{ env.OSSL3_VCPKG_DIR }}" -DCMAKE_TOOLCHAIN_FILE="${{ env.TOOLCHAIN_FILE }}" . - cmake --build build - - - name: Build interop harness - run: | - cd cmd/interop - cmake -B build -DSANITIZERS=ON -DVCPKG_MANIFEST_DIR="${{ env.OSSL3_VCPKG_DIR }}" -DCMAKE_TOOLCHAIN_FILE="${{ env.TOOLCHAIN_FILE }}" . - cmake --build build diff --git a/CMakeLists.txt b/CMakeLists.txt index 8cecb101..6bf7f0de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,7 +73,7 @@ endif() # External libraries find_package(OpenSSL REQUIRED) if ( OPENSSL_FOUND ) - if (${OPENSSL_VERSION} VERSION_GREATER 1.1.1) + 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") diff --git a/lib/hpke/src/digest.cpp b/lib/hpke/src/digest.cpp index b8bbd621..d2627ca7 100644 --- a/lib/hpke/src/digest.cpp +++ b/lib/hpke/src/digest.cpp @@ -115,15 +115,15 @@ bytes Digest::hmac_for_hkdf_extract(const bytes& key, const bytes& data) const { #if defined(WITH_OPENSSL3) - auto mac = - make_typed_unique(EVP_MAC_fetch(nullptr, OSSL_MAC_NAME_HMAC, nullptr)); - auto ctx = make_typed_unique(EVP_MAC_CTX_new(mac.get())); 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()); @@ -156,32 +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())) { -#else - if (1 != HMAC_Init_ex(ctx.get(), key_data, key_size, type, nullptr)) { -#endif throw openssl_error(); } - -#if defined(WITH_OPENSSL3) if (1 != EVP_MAC_update(ctx.get(), data.data(), data.size())) { -#else - if (1 != HMAC_Update(ctx.get(), data.data(), data.size())) { -#endif throw openssl_error(); } - - auto md = bytes(hash_size); -#if defined(WITH_OPENSSL3) 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(); + } unsigned int size = 0; if (1 != HMAC_Final(ctx.get(), md.data(), &size)) { -#endif throw openssl_error(); } +#endif return md; } diff --git a/lib/hpke/test/common.cpp b/lib/hpke/test/common.cpp index c3131fc0..cfd0d930 100644 --- a/lib/hpke/test/common.cpp +++ b/lib/hpke/test/common.cpp @@ -8,30 +8,6 @@ #if defined(WITH_OPENSSL3) #include #include - -static OSSL_PROVIDER* fips_prov = nullptr; - -static int -FIPS_mode() -{ - if (OSSL_PROVIDER_available(nullptr, "fips") == 1) { - return 1; - } - return EVP_default_properties_is_fips_enabled(nullptr); -} - -static int -FIPS_mode_set(int enable) -{ - auto retval = 0; - if (enable != 0 && fips_prov == nullptr) { - fips_prov = OSSL_PROVIDER_load(nullptr, "fips"); - retval = (fips_prov != nullptr) ? 1 : 0; - } else if (enable == 0 && fips_prov != nullptr) { - retval = OSSL_PROVIDER_unload(fips_prov); - } - return retval; -} #endif void @@ -39,15 +15,26 @@ 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 diff --git a/lib/mls_vectors/test/fips.cpp b/lib/mls_vectors/test/fips.cpp deleted file mode 100644 index ebb2b034..00000000 --- a/lib/mls_vectors/test/fips.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "fips.h" -#if defined(WITH_OPENSSL3) -#include -#include -#else -#include -#endif -#include - -using namespace mls; - -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() == 1; -#endif -} - -bool -is_fips_approved(CipherSuite::ID id) -{ - static const auto disallowed = std::set{ - CipherSuite::ID::X25519_CHACHA20POLY1305_SHA256_Ed25519, - CipherSuite::ID::X448_CHACHA20POLY1305_SHA512_Ed448, - }; - return disallowed.count(id) == 0; -} diff --git a/lib/mls_vectors/test/fips.h b/lib/mls_vectors/test/fips.h deleted file mode 100644 index a7428e5b..00000000 --- a/lib/mls_vectors/test/fips.h +++ /dev/null @@ -1,7 +0,0 @@ -#include - -bool -fips(); - -bool -is_fips_approved(mls::CipherSuite::ID id); diff --git a/lib/mls_vectors/test/mls_vectors.cpp b/lib/mls_vectors/test/mls_vectors.cpp index 4c67e235..26902cf3 100644 --- a/lib/mls_vectors/test/mls_vectors.cpp +++ b/lib/mls_vectors/test/mls_vectors.cpp @@ -1,4 +1,3 @@ -#include "fips.h" #include #include #include @@ -63,10 +62,6 @@ TEST_CASE("Transcript") TEST_CASE("TreeKEM") { for (auto suite : supported_suites) { - if (fips() && !is_fips_approved(suite.cipher_suite())) { - continue; - } - const auto tv = TreeKEMTestVector::create(suite, 10); REQUIRE(tv.verify() == std::nullopt); } diff --git a/test/crypto.cpp b/test/crypto.cpp index 8438d912..8dd930c2 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -1,4 +1,3 @@ -#include "fips.h" #include #include #include @@ -15,10 +14,6 @@ TEST_CASE("Basic HPKE") auto original = random_bytes(100); for (auto suite_id : all_supported_suites) { - if (fips() && !is_fips_approved(suite_id)) { - continue; - } - auto suite = CipherSuite{ suite_id }; auto s = bytes{ 0, 1, 2, 3 }; diff --git a/test/fips.cpp b/test/fips.cpp deleted file mode 100644 index ebb2b034..00000000 --- a/test/fips.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "fips.h" -#if defined(WITH_OPENSSL3) -#include -#include -#else -#include -#endif -#include - -using namespace mls; - -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() == 1; -#endif -} - -bool -is_fips_approved(CipherSuite::ID id) -{ - static const auto disallowed = std::set{ - CipherSuite::ID::X25519_CHACHA20POLY1305_SHA256_Ed25519, - CipherSuite::ID::X448_CHACHA20POLY1305_SHA512_Ed448, - }; - return disallowed.count(id) == 0; -} diff --git a/test/fips.h b/test/fips.h deleted file mode 100644 index a7428e5b..00000000 --- a/test/fips.h +++ /dev/null @@ -1,7 +0,0 @@ -#include - -bool -fips(); - -bool -is_fips_approved(mls::CipherSuite::ID id); diff --git a/test/key_schedule.cpp b/test/key_schedule.cpp index f0615808..7c0bc6b0 100644 --- a/test/key_schedule.cpp +++ b/test/key_schedule.cpp @@ -1,4 +1,3 @@ -#include "fips.h" #include #include #include diff --git a/test/treekem.cpp b/test/treekem.cpp index c79039cd..a1cdef21 100644 --- a/test/treekem.cpp +++ b/test/treekem.cpp @@ -1,4 +1,3 @@ -#include "fips.h" #include #include #include @@ -267,10 +266,6 @@ TEST_CASE_FIXTURE(TreeKEMTest, "TreeKEM encap/decap") TEST_CASE("TreeKEM Interop") { for (auto suite : all_supported_suites) { - if (fips() && !is_fips_approved(suite)) { - continue; - } - auto tv = TreeKEMTestVector::create(suite, 10); tv.initialize_trees(); REQUIRE(tv.verify() == std::nullopt); From 101ac70b085c77e9bc06d9a5365bdee8fbdd4ad7 Mon Sep 17 00:00:00 2001 From: CJ Date: Fri, 10 Feb 2023 17:30:40 +0000 Subject: [PATCH 7/8] Removed unused OpenSSL 3 vcpkg.json for interop --- cmd/interop/alternatives/openssl_3/vcpkg.json | 22 ------------------- 1 file changed, 22 deletions(-) delete mode 100644 cmd/interop/alternatives/openssl_3/vcpkg.json diff --git a/cmd/interop/alternatives/openssl_3/vcpkg.json b/cmd/interop/alternatives/openssl_3/vcpkg.json deleted file mode 100644 index bc4e7a6b..00000000 --- a/cmd/interop/alternatives/openssl_3/vcpkg.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "mlspp-interop", - "version-string": "0.1", - "description": "Interop harness for Cisco MLS C++ library (OpenSSL 3)", - "dependencies": [ - { - "name": "openssl", - "version>=": "3.0.7" - }, - "protobuf", - "grpc", - "gflags", - "nlohmann-json" - ], - "builtin-baseline": "3b3bd424827a1f7f4813216f6b32b6c61e386b2e", - "overrides": [ - { - "name": "openssl", - "version-string": "3.0.7" - } - ] - } From dbcdb86b81a62a338a9aa1313ad22d2206b716fa Mon Sep 17 00:00:00 2001 From: CJ Date: Tue, 21 Feb 2023 23:26:30 +0000 Subject: [PATCH 8/8] Added missing pkg-config to OpenSSL 3 CI build --- .github/workflows/build_openssl3.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_openssl3.yml b/.github/workflows/build_openssl3.yml index 9500bc57..9899ec44 100644 --- a/.github/workflows/build_openssl3.yml +++ b/.github/workflows/build_openssl3.yml @@ -44,7 +44,7 @@ jobs: - name: dependencies (macos) if: ${{ matrix.os == 'macos-latest' }} run: | - brew install llvm + 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"