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

Enable linking against BoringSSL #349

Closed
wants to merge 12 commits into from
90 changes: 90 additions & 0 deletions .github/workflows/boring.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
name: MLSPP CI (BoringSSL Test)

on:
push:
branches:
- main
pull_request:
branches:
- main

env:
CTEST_OUTPUT_ON_FAILURE: 1
CMAKE_BUILD_BORINGSSL_DIR: ${{ github.workspace }}/build_boringssl
CMAKE_TEST_BORINGSSL_DIR: ${{ github.workspace }}/build_boringssl/test
VCPKG_BINARY_SOURCES: files,${{ github.workspace }}/build/cache,readwrite

jobs:
formatting-check:
name: Formatting Check
runs-on: ubuntu-latest
strategy:
matrix:
path:
- 'include'
- 'src'
- 'test'
- 'cmd'
- 'lib'
steps:
- uses: actions/checkout@v3

- name: Run clang-format style check for C/C++ programs
uses: jidicula/[email protected]
with:
clang-format-version: '16'
check-path: ${{ matrix.path }}
fallback-style: 'Mozilla'

platform-sanitizer-tests:
name: Build and test with BoringSSL
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"
boring-vcpkg-dir: "alternatives\\boringssl_1.1"
ctest-target: RUN_TESTS
- os: ubuntu-latest
vcpkg-cmake-file: "$VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake"
boring-vcpkg-dir: "alternatives/boringssl_1.1"
ctest-target: test
- os: macos-latest
vcpkg-cmake-file: "$VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake"
boring-vcpkg-dir: "alternatives/boringssl_1.1"
ctest-target: test

steps:
- uses: actions/checkout@v3

- 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: Dependencies (Ubuntu)
if: ${{ matrix.os == 'ubuntu-latest' }}
run: |
sudo apt-get install -y linux-headers-$(uname -r) nasm

- name: Restore cache
uses: actions/cache@v3
with:
path: ${{ github.workspace }}/build/cache
key: VCPKG-BinaryCache-${{ runner.os }}

- name: Build (BoringSSL 1.1)
run: |
cmake -B "${{ env.CMAKE_BUILD_BORINGSSL_DIR }}" -DTESTING=ON -DCLANG_TIDY=ON -DSANITIZERS=ON -DVCPKG_MANIFEST_DIR="${{ matrix.ossl3-vcpkg-dir }}" -DCMAKE_TOOLCHAIN_FILE="${{ matrix.vcpkg-cmake-file}}" -DREQUIRE_BORINGSSL=1
cmake --build "${{ env.CMAKE_BUILD_BORINGSSL_DIR }}"

- name: Unit Test (BoringSSL 1.1)
run: |
cmake --build "${{ env.CMAKE_BUILD_BORINGSSL_DIR }}" --target "${{ matrix.ctest-target}}"


25 changes: 22 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ option(TESTING "Build tests" OFF)
option(CLANG_TIDY "Perform linting with clang-tidy" OFF)
option(SANITIZERS "Enable sanitizers" OFF)
option(MLS_NAMESPACE_SUFFIX "Namespace Suffix for CXX and CMake Export")
option(REQUIRE_BORINGSSL "Require BoringSSL instead of OpenSSL" OFF)

if(MLS_NAMESPACE_SUFFIX)
set(MLS_CXX_NAMESPACE "mls_${MLS_NAMESPACE_SUFFIX}" CACHE STRING "Top-level Namespace for CXX")
Expand Down Expand Up @@ -93,16 +94,34 @@ endif()
# External libraries
find_package(OpenSSL REQUIRED)
if ( OPENSSL_FOUND )
find_path(BORINGSSL_INCLUDE_DIR openssl/is_boringssl.h HINTS ${OPENSSL_INCLUDE_DIR} NO_DEFAULT_PATH)

if (BORINGSSL_INCLUDE_DIR)
message(STATUS "Found OpenSSL includes are for BoringSSL")

add_compile_definitions(WITH_BORINGSSL)
add_compile_options(-Wno-gnu-anonymous-struct -Wno-nested-anon-types)

file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/crypto.h" boringssl_version_str
REGEX "^#[\t ]*define[\t ]+OPENSSL_VERSION_TEXT[\t ]+\"OpenSSL ([0-9])+\\.([0-9])+\\.([0-9])+ .+")

string(REGEX REPLACE "^.*OPENSSL_VERSION_TEXT[\t ]+\"OpenSSL ([0-9]+\\.[0-9]+\\.[0-9])+ .+$"
"\\1" OPENSSL_VERSION "${boringssl_version_str}")

elseif (REQUIRE_BORINGSSL)
message(FATAL_ERROR "BoringSSL required but not found")
endif ()

if (${OPENSSL_VERSION} VERSION_GREATER_EQUAL 3)
add_compile_definitions(WITH_OPENSSL3)
add_compile_definitions(WITH_OPENSSL3)
elseif(${OPENSSL_VERSION} VERSION_LESS 1.1.1)
message(FATAL_ERROR "OpenSSL 1.1.1 or greater is required")
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")
message(FATAL_ERROR "No OpenSSL library found")
endif()

# Internal libraries
Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ MLS++
Implementation of the proposed [Messaging Layer
Security](https://github.com/mlswg/mls-protocol/blob/master/draft-ietf-mls-protocol.md)
protocol in C++. Depends on C++17, STL for data structures, and
OpenSSL for crypto.
OpenSSL or BoringSSL for crypto.

Quickstart
----------
Expand All @@ -31,3 +31,11 @@ Conventions
* Snake case for variables, functions, members (`derive_epoch_keys`)
* Private member variables start with underscore (`_`)
* In general, prefer descriptive names


OpenSSL / BoringSSL
-------------------

MLS++ requires OpenSSL of at least version 1.1.1, or BoringSSL compatible with the same requirement. MLS++ is compatible with OpenSSL >= 3.0.

Pass `OPENSSL_ROOT_DIR` to guide CMake to select a specific OpenSSL/BoringSSL installation. You may also need to specify `OPENSSL_INCLUDE_DIR`, `OPENSSL_CRYPTO_LIBRARY`, and `OPENSSL_SSL_LIBRARY` depending on the file and folder structure of your installation. When manually passing `OPENSSL_*` options one should carefully verify that both the includes and libraries match the expected installation.
21 changes: 21 additions & 0 deletions alternatives/boringssl_1.1/vcpkg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "mlspp",
"version-string": "0.1",
"description": "Cisco MLS C++ library (BoringSSL 1.1)",
"dependencies": [
{
"name": "boringssl",
"version>=": "2023-09-25"
},
"doctest",
"nlohmann-json"
],
"builtin-baseline": "5908d702d61cea1429b223a0b7a10ab86bad4c78",
"overrides": [
{
"name": "boringssl",
"version": "2023-09-25"
}
]
}

4 changes: 4 additions & 0 deletions include/mls/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,11 @@ struct CipherSuite
static const bytes& reference_label();
};

#if WITH_BORINGSSL
extern const std::array<CipherSuite::ID, 5> all_supported_suites;
#else
extern const std::array<CipherSuite::ID, 7> all_supported_suites;
#endif

// Utilities
using MLS_NAMESPACE::hpke::random_bytes;
Expand Down
7 changes: 4 additions & 3 deletions lib/hpke/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ set(CURRENT_LIB_NAME hpke)
### Dependencies
###
find_package(nlohmann_json REQUIRED)
find_package(OpenSSL 1.1 REQUIRED)

###
### Library Config
Expand All @@ -17,14 +16,16 @@ add_library(${CURRENT_LIB_NAME} ${LIB_HEADERS} ${LIB_SOURCES})
add_dependencies(${CURRENT_LIB_NAME} bytes tls_syntax)
target_link_libraries(${CURRENT_LIB_NAME}
PRIVATE
nlohmann_json::nlohmann_json OpenSSL::Crypto
OpenSSL::Crypto
PUBLIC
bytes tls_syntax)
nlohmann_json::nlohmann_json bytes tls_syntax)
target_include_directories(${CURRENT_LIB_NAME}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include/${PROJECT_NAME}>
PRIVATE
${OPENSSL_INCLUDE_DIR}
)

###
Expand Down
2 changes: 2 additions & 0 deletions lib/hpke/include/hpke/hpke.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ struct KEM
DHKEM_P384_SHA384 = 0x0011,
DHKEM_P521_SHA512 = 0x0012,
DHKEM_X25519_SHA256 = 0x0020,
#if !defined(WITH_BORINGSSL)
DHKEM_X448_SHA512 = 0x0021,
#endif
};

template<KEM::ID>
Expand Down
2 changes: 2 additions & 0 deletions lib/hpke/include/hpke/signature.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ struct Signature
P384_SHA384,
P521_SHA512,
Ed25519,
#if !defined(WITH_BORINGSSL)
Ed448,
#endif
RSA_SHA256,
RSA_SHA384,
RSA_SHA512,
Expand Down
74 changes: 74 additions & 0 deletions lib/hpke/src/aead_cipher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
#include <namespace.h>
#include <openssl/evp.h>

#if WITH_BORINGSSL
#include <openssl/aead.h>
#endif

namespace MLS_NAMESPACE::hpke {

///
Expand Down Expand Up @@ -109,6 +113,25 @@ cipher_tag_size(AEAD::ID cipher)
}
}

#if WITH_BORINGSSL
static const EVP_AEAD*
boringssl_cipher(AEAD::ID cipher)
{
switch (cipher) {
case AEAD::ID::AES_128_GCM:
return EVP_aead_aes_128_gcm();

case AEAD::ID::AES_256_GCM:
return EVP_aead_aes_256_gcm();

case AEAD::ID::CHACHA20_POLY1305:
return EVP_aead_chacha20_poly1305();

default:
throw std::runtime_error("Unsupported algorithm");
}
}
#else
static const EVP_CIPHER*
openssl_cipher(AEAD::ID cipher)
{
Expand All @@ -126,6 +149,7 @@ openssl_cipher(AEAD::ID cipher)
throw std::runtime_error("Unsupported algorithm");
}
}
#endif // WITH_BORINGSSL

AEADCipher::AEADCipher(AEAD::ID id_in)
: AEAD(id_in, cipher_key_size(id_in), cipher_nonce_size(id_in))
Expand All @@ -139,6 +163,30 @@ AEADCipher::seal(const bytes& key,
const bytes& aad,
const bytes& pt) const
{
#if WITH_BORINGSSL
auto ctx = make_typed_unique(
EVP_AEAD_CTX_new(boringssl_cipher(id), key.data(), key.size(), tag_size));
if (ctx == nullptr) {
throw openssl_error();
}

auto ct = bytes(pt.size() + tag_size);
auto out_len = ct.size();
if (1 != EVP_AEAD_CTX_seal(ctx.get(),
ct.data(),
&out_len,
ct.size(),
nonce.data(),
nonce.size(),
pt.data(),
pt.size(),
aad.data(),
aad.size())) {
throw openssl_error();
}

return ct;
#else
auto ctx = make_typed_unique(EVP_CIPHER_CTX_new());
if (ctx == nullptr) {
throw openssl_error();
Expand Down Expand Up @@ -185,6 +233,7 @@ AEADCipher::seal(const bytes& key,

ct += tag;
return ct;
#endif // WITH_BORINGSSL
}

std::optional<bytes>
Expand All @@ -197,6 +246,30 @@ AEADCipher::open(const bytes& key,
throw std::runtime_error("AEAD ciphertext smaller than tag size");
}

#if WITH_BORINGSSL
auto ctx = make_typed_unique(EVP_AEAD_CTX_new(
boringssl_cipher(id), key.data(), key.size(), cipher_tag_size(id)));
if (ctx == nullptr) {
throw openssl_error();
}

auto pt = bytes(ct.size() - tag_size);
auto out_len = pt.size();
if (1 != EVP_AEAD_CTX_open(ctx.get(),
pt.data(),
&out_len,
pt.size(),
nonce.data(),
nonce.size(),
ct.data(),
ct.size(),
aad.data(),
aad.size())) {
throw openssl_error();
}

return pt;
#else
auto ctx = make_typed_unique(EVP_CIPHER_CTX_new());
if (ctx == nullptr) {
throw openssl_error();
Expand Down Expand Up @@ -243,6 +316,7 @@ AEADCipher::open(const bytes& key,
}

return pt;
#endif // WITH_BORINGSSL
}

} // namespace MLS_NAMESPACE::hpke
4 changes: 4 additions & 0 deletions lib/hpke/src/base64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ to_base64(const bytes& data)
return "";
}

#if WITH_BORINGSSL
const auto data_size = data.size();
#else
const auto data_size = static_cast<int>(data.size());
#endif

// base64 encoding produces 4 characters for every 3 input bytes (rounded up)
const auto out_size = (data_size + 2) / 3 * 4;
Expand Down
Loading
Loading