Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated to support OpenSSL 3 #295

Merged
merged 11 commits into from
Feb 22, 2023
68 changes: 68 additions & 0 deletions .github/workflows/build_openssl3.yml
Original file line number Diff line number Diff line change
@@ -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
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}}"
17 changes: 15 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
19 changes: 19 additions & 0 deletions alternatives/openssl_3/vcpkg.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
}
1 change: 1 addition & 0 deletions lib/bytes/test/bytes.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <bytes/bytes.h>
#include <doctest/doctest.h>
#include <memory>
#include <sstream>

using namespace bytes_ns;
Expand Down
4 changes: 2 additions & 2 deletions lib/hpke/src/certificate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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())))
{
}

Expand Down
62 changes: 58 additions & 4 deletions lib/hpke/src/digest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

#include <openssl/evp.h>
#include <openssl/hmac.h>
#if defined(WITH_OPENSSL3)
#include <openssl/core_names.h>
#endif

#include "openssl_common.h"

Expand All @@ -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<Digest::ID::SHA256>()
Expand Down Expand Up @@ -91,20 +114,40 @@ 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<OSSL_PARAM, 2> 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.
// That document does not impose that requirement on HKDF, so we disable FIPS
// 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<int>(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();
Expand All @@ -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)
bifurcation marked this conversation as resolved.
Show resolved Hide resolved
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;
}
Expand Down
Loading