Skip to content

Commit

Permalink
add opt-in post-quantum KX feature flag
Browse files Browse the repository at this point in the history
When librustls is built with the `post-quantum` feature flag, the
default `aws-lc-rs` cryptography provider will be augmented to offer
the hybrid `X25519MLKEM768` key exchange by default in addition to the
pre-existing classical KX algorithms. Similar support is added to the
`rustls_default_fips_provider()` provider when both `fips` and
`post-quantum` are enabled.

When the `post-quantum` feature is available
a `rustls_post_quantum_provider()` function is also provided to
explicitly construct the PQ-enabled provider.

Since the default provider is augmented the existing `client.c` and
`server.c` examples benefit transparently when the `-DPOST_QUANTUM=on`
CMake option is provided.

Connect-test CI is updated to test a post-QC secure key exchange with
`pq.cloudflareresearch.com` reports the correct KX on
Windows/MacOS/Linux.
  • Loading branch information
cpu committed Dec 31, 2024
1 parent f05e0dc commit 094f722
Show file tree
Hide file tree
Showing 12 changed files with 225 additions and 13 deletions.
64 changes: 64 additions & 0 deletions .github/workflows/daily-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,67 @@ jobs:
shell: bash
run: |
grep 'sni=encrypted' ech-test.log
pq:
name: "Post-quantum (${{ matrix.os }})"
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ ubuntu-latest, macos-latest, windows-latest ]

steps:
- name: Checkout sources
uses: actions/checkout@v4
with:
persist-credentials: false

- name: Install nightly toolchain
uses: dtolnay/rust-toolchain@nightly

- name: Install cargo-c (Ubuntu)
if: matrix.os == 'ubuntu-latest'
env:
LINK: https://github.com/lu-zero/cargo-c/releases/latest/download
CARGO_C_FILE: cargo-c-x86_64-unknown-linux-musl.tar.gz
run: |
curl -L $LINK/$CARGO_C_FILE | tar xz -C ~/.cargo/bin
- name: Install cargo-c (macOS)
if: matrix.os == 'macos-latest'
env:
LINK: https://github.com/lu-zero/cargo-c/releases/latest/download
CARGO_C_FILE: cargo-c-macos.zip
run: |
curl -L $LINK/$CARGO_C_FILE -o cargo-c-macos.zip
unzip cargo-c-macos.zip -d ~/.cargo/bin
- name: Install cargo-c (Windows)
if: matrix.os == 'windows-latest'
env:
LINK: https://github.com/lu-zero/cargo-c/releases/latest/download
CARGO_C_FILE: cargo-c-windows-msvc.zip
run: |
curl -L "$env:LINK/$env:CARGO_C_FILE" -o cargo-c-windows-msvc.zip
powershell -Command "Expand-Archive -Path cargo-c-windows-msvc.zip -DestinationPath $env:USERPROFILE\\.cargo\\bin -Force"
- name: Setup cmake build
run: |
cmake ${{
matrix.os != 'windows-latest' && '-DCMAKE_BUILD_TYPE=Release -DPOST_QUANTUM=on\' || '-DPOST_QUANTUM=on'
}} ${{
matrix.os == 'macos-latest' && '-DCMAKE_OSX_DEPLOYMENT_TARGET=14.5' || ''
}} -S librustls -B build
- name: Run PQ connect test
if: matrix.pq == 'on'
# NOTE: uses bash as the shell to allow for easy no-powershell tee/grep pipeline.
shell: bash
run: |
cmake --build build --target pq-test ${{
matrix.os == 'windows-latest' && '--config Release' || ''
}} | tee pq-test.log
- name: Verify PQ status
shell: bash
run: |
grep 'kex=X25519MLKEM768' pq-test.log
25 changes: 21 additions & 4 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:

jobs:
build:
name: "Build+Test (${{ matrix.os }}, ${{ matrix.cc }}, ${{ matrix.rust }}, ${{ matrix.crypto }}${{ matrix.cert_compression == 'on' && ', cert compression' || '' }}${{ matrix.dyn_link == 'on' && ', dynamic linking' || '' }})"
name: "Build+Test (${{ matrix.os }}, ${{ matrix.cc }}, ${{ matrix.rust }}, ${{ matrix.crypto }}${{ matrix.cert_compression == 'on' && ', cert compression' || '' }}${{ matrix.pq == 'on' && ', post-quantum' || '' }}${{ matrix.dyn_link == 'on' && ', dynamic linking' || '' }})"
runs-on: ${{ matrix.os }}
strategy:
matrix:
Expand Down Expand Up @@ -42,6 +42,12 @@ jobs:
crypto: aws-lc-rs
rust: stable
cert_compression: on
# Linux pq build
- os: ubuntu-latest
cc: clang
crypto: aws-lc-rs
rust: stable
pq: on
# MacOS standard build
- os: macos-latest
cc: clang
Expand All @@ -60,6 +66,12 @@ jobs:
crypto: aws-lc-rs
rust: stable
cert_compression: on
# MacOS pq build
- os: macos-latest
cc: clang
crypto: aws-lc-rs
rust: stable
pq: on
steps:
- name: Checkout sources
uses: actions/checkout@v4
Expand Down Expand Up @@ -97,6 +109,7 @@ jobs:
cmake \
-DCRYPTO_PROVIDER=${{matrix.crypto}} \
-DCERT_COMPRESSION=${{matrix.cert_compression}} \
-DPOST_QUANTUM=${{matrix.pq}} \
-DDYN_LINK=${{matrix.dyn_link}} \
-DCMAKE_BUILD_TYPE=Debug \
${{ matrix.os == 'macos-latest' && '-DCMAKE_OSX_DEPLOYMENT_TARGET=14.5' || '' }} \
Expand All @@ -117,7 +130,7 @@ jobs:
- name: Build release binaries
run: |
cmake --build build -- clean
CC=${{matrix.cc}} CXX=${{matrix.cc}} cmake -S librustls -B build -DCRYPTO_PROVIDER=${{matrix.crypto}} -DCMAKE_BUILD_TYPE=Release
CC=${{matrix.cc}} CXX=${{matrix.cc}} cmake -S librustls -B build -DCRYPTO_PROVIDER=${{matrix.crypto}} -DPOST_QUANTUM=${{matrix.pq}} -DCMAKE_BUILD_TYPE=Release
cmake --build build
- name: Verify release builds were not using ASAN
Expand Down Expand Up @@ -189,7 +202,7 @@ jobs:
run: cmake --build build --target integration-test

test-windows:
name: "Windows (${{ matrix.crypto }}, ${{ matrix.config }}${{ matrix.cert_compression == 'on' && ', cert compression' || '' }}${{ matrix.dyn_link == 'on' && ', dynamic linking' || '' }})"
name: "Windows (${{ matrix.crypto }}, ${{ matrix.config }}${{ matrix.cert_compression == 'on' && ', cert compression' || '' }}${{ matrix.pq == 'on' && ', post-quantum' || '' }}${{ matrix.dyn_link == 'on' && ', dynamic linking' || '' }})"
runs-on: windows-latest
strategy:
matrix:
Expand All @@ -206,6 +219,10 @@ jobs:
- crypto: aws-lc-rs
config: Release
cert_compression: on
# One build with pq.
- crypto: aws-lc-rs
config: Release
pq: on
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -233,7 +250,7 @@ jobs:
powershell -Command "Expand-Archive -Path cargo-c-windows-msvc.zip -DestinationPath $env:USERPROFILE\\.cargo\\bin -Force"
- name: Configure CMake
run: cmake -DCRYPTO_PROVIDER="${{ matrix.crypto }}" -DCERT_COMPRESSION="${{ matrix.cert_compression }}" -DDYN_LINK="${{ matrix.dyn_link }}" -S librustls -B build
run: cmake -DCRYPTO_PROVIDER="${{ matrix.crypto }}" -DCERT_COMPRESSION="${{ matrix.cert_compression }}" -DPOST_QUANTUM="${{ matrix.pq }}" -DDYN_LINK="${{ matrix.dyn_link }}" -S librustls -B build

- name: Build
run: cmake --build build --config "${{ matrix.config }}"
Expand Down
13 changes: 11 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ resolver = "2"

[workspace.dependencies]
rustls = { version = "0.23", default-features = false, features = ["std", "tls12"] }
rustls-post-quantum = { version = "0.2.2" }
webpki = { package = "rustls-webpki", version = "0.102.0", default-features = false, features = ["std"] }
libc = "0.2"
log = "0.4.22"
Expand All @@ -23,3 +24,10 @@ regex = "1.9.6"
toml = { version = "0.6.0", default-features = false, features = ["parse"] }
hickory-resolver = { version = "=0.25.0-alpha.4", features = ["dns-over-https-rustls", "webpki-roots"] }
tokio = { version = "1.42.0", features = ["io-util", "macros", "net", "rt"] }

# TODO(@cpu): remove this once Rustls 0.23.21 w/ built-in post-quantum support (rustls/rustls#2288) is published.
# we want to avoid rustls-post-quantum 0.2.1 because it activates aws-lc-rs/non-fips
# and so conflicts with our fips feature when running cbindgen with everything activated.
[patch.crates-io]
rustls = { git = 'https://github.com/cpu/rustls.git', rev = '2008a03eff1f608467a70915109dc100129143d0' }
rustls-post-quantum = { git = 'https://github.com/cpu/rustls.git', rev = '2008a03eff1f608467a70915109dc100129143d0' }
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,22 @@ platforms see the upstream documentation:
[`*ring*`]: https://crates.io/crates/ring
[`*ring*` supported platforms]: https://github.com/briansmith/ring/blob/2e8363b433fa3b3962c877d9ed2e9145612f3160/include/ring-core/target.h#L18-L64

#### Post-Quantum X25519MLKEM768 Key Exchange

You can optionally enable use of a hybrid post-quantum secure key exchange ([X25519MLKEM768][]) with the
`--features=x25519mlkem768` flag.

This feature is **disabled** by default. Enabling this feature will implicitly select `aws-lc-rs` as the
cryptography provider since `*ring*` has no equivalent support at this time.

When enabled the default provider will include support for the `X25519MLKEM768` key exchange.
A `rustls_crypto_provider` with support can also be constructed with `rustls_post_quantum_provider()`.

If used with the [`fips`](#fips-140-3) feature, the `rustls_default_fips_provider()` function will
also return a FIPS-enabled provider with support for `X25519MLKEM768`.

[X25519MLKEM768]: https://datatracker.ietf.org/doc/draft-kwiatkowski-tls-ecdhe-mlkem

#### Certificate Compression

You can optionally enable [RFC 8879](https://www.rfc-editor.org/rfc/rfc8879)
Expand All @@ -117,7 +133,8 @@ cargo capi install --features=cert_compression # With cert compression.

You can optionally enable FIPS support via `--features=fips`. This implicitly
enables the `aws-lc-rs` cryptography provider since `ring` does not have FIPS
140-3 support at this time.
140-3 support at this time. This feature can also be combined with the
[`post-quantum`](#post-quantum-x25519mlkem768-key-exchange) feature.

Enabling FIPS mode adds several new build requirements depending on your
platform. For example, all platforms will require `cmake` and `go`. Windows will
Expand Down Expand Up @@ -218,6 +235,8 @@ cmake --build build
Use `-DCRYPTO_PROVIDER=ring` to select the cryptography provider for the
examples explicitly.

Use `-DPOST_QUANTUM=on` to enable post-quantum X25519MLKEM768 key exchange.

Use `-DCERT_COMPRESSION=on` to enable certificate compression.

Use `-DFIPS=on` to enable FIPS mode.
Expand Down
4 changes: 3 additions & 1 deletion librustls/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ ring = ["rustls/ring", "webpki/ring"]
aws-lc-rs = ["rustls/aws-lc-rs", "webpki/aws_lc_rs"]
cert_compression = ["rustls/brotli", "rustls/zlib"]
fips = ["aws-lc-rs", "rustls/fips"]
post-quantum = ["aws-lc-rs", "rustls-post-quantum"]

[dependencies]
# Keep in sync with RUSTLS_CRATE_VERSION in build.rs
rustls = { version = "0.23.18", default-features = false, features = ["std", "tls12"] }
rustls = { version = "0.23.20", default-features = false, features = ["std", "tls12"] }
rustls-post-quantum = { workspace = true, optional = true }
webpki = { workspace = true }
libc = { workspace = true }
log = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion librustls/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::{env, fs, path::PathBuf};
// because doing so would require a heavy-weight deserialization lib dependency
// (and it couldn't be a _dev_ dep for use in a build script) or doing brittle
// by-hand parsing.
const RUSTLS_CRATE_VERSION: &str = "0.23.18";
const RUSTLS_CRATE_VERSION: &str = "0.23.20";

fn main() {
let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
Expand Down
3 changes: 2 additions & 1 deletion librustls/cbindgen.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ include = ["rustls_tls_version"]
"feature = aws-lc-rs" = "DEFINE_AWS_LC_RS"
"feature = ring" = "DEFINE_RING"
"feature = fips" = "DEFINE_FIPS"
"feature = post-quantum" = "DEFINE_POST_QUANTUM"

[parse.expand]
crates = ["rustls-ffi"]
features = ["read_buf", "aws-lc-rs", "ring", "fips"]
features = ["read_buf", "aws-lc-rs", "ring", "fips", "post-quantum"]
9 changes: 9 additions & 0 deletions librustls/cmake/options.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ option(

option(FIPS "Whether to enable aws-lc-rs and FIPS support")

option(
POST_QUANTUM
"Whether to enable aws-lc-rs and post-quantum key exchange support"
)

option(DYN_LINK "Use dynamic linking for rustls library" OFF)

if(DYN_LINK AND FIPS AND (APPLE OR WIN32))
Expand All @@ -45,6 +50,10 @@ if(FIPS)
list(APPEND CARGO_FEATURES --features=fips)
endif()

if(POST_QUANTUM)
list(APPEND CARGO_FEATURES --features=post-quantum)
endif()

# By default w/ Makefile or Ninja generators (e.g. Linux/MacOS CLI)
# the `CMAKE_BUILD_TYPE` is "" when using the C/C++ project tooling.
#
Expand Down
21 changes: 21 additions & 0 deletions librustls/cmake/rust.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,24 @@ add_custom_command(
$<TARGET_FILE:client> cloudflare-ech.com 443 /cdn-cgi/trace
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
)

add_custom_target(pq-test DEPENDS client)

if(WIN32 AND DYN_LINK)
add_custom_command(
TARGET pq-test
PRE_BUILD
COMMAND
${CMAKE_COMMAND} -E copy "${CMAKE_BINARY_DIR}/rust/bin/rustls.dll"
"${CMAKE_BINARY_DIR}\\tests\\$<CONFIG>\\"
)
endif()

add_custom_command(
TARGET pq-test
POST_BUILD
COMMAND
${CMAKE_COMMAND} -E env RUSTLS_PLATFORM_VERIFIER=1 $<TARGET_FILE:client>
pq.cloudflareresearch.com 443 /cdn-cgi/trace
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
)
48 changes: 45 additions & 3 deletions librustls/src/crypto_provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,9 @@ pub extern "C" fn rustls_aws_lc_rs_crypto_provider() -> *const rustls_crypto_pro
///
/// See the upstream [rustls FIPS documentation][FIPS] for more information.
///
/// If the `post-quantum` feature is also enabled, this function will return a provider
/// that includes the FIPS approved post-quantum X25519MLKEM768 key exchange group.
///
/// The caller owns the returned `rustls_crypto_provider` and must free it using
/// `rustls_crypto_provider_free`.
///
Expand All @@ -264,8 +267,38 @@ pub extern "C" fn rustls_aws_lc_rs_crypto_provider() -> *const rustls_crypto_pro
#[cfg(feature = "fips")]
pub extern "C" fn rustls_default_fips_provider() -> *const rustls_crypto_provider {
ffi_panic_boundary! {
Arc::into_raw(Arc::new(rustls::crypto::default_fips_provider()))
as *const rustls_crypto_provider
#[cfg(not(feature = "post-quantum"))]
{
Arc::into_raw(Arc::new(rustls::crypto::default_fips_provider()))
as *const rustls_crypto_provider
}
#[cfg(feature = "post-quantum")]
{
let mut fips_provider = rustls::crypto::default_fips_provider();
fips_provider
.kx_groups
.splice(0..0, vec![rustls_post_quantum::X25519MLKEM768]);
Arc::into_raw(Arc::new(fips_provider)) as *const rustls_crypto_provider
}
}
}

/// Return a post-quantum enabled `rustls_crypto_provider` backed by the `aws-lc-rs` cryptography
/// library.
///
/// This `rustls_crypto_provider` is the same as the one returned from
/// `rustls_aws_lc_rs_crypto_provider()`, but includes the post-quantum X25519MLKEM768 key exchange
/// algorithm.
///
/// Requires the `post-quantum` feature be enabled.
///
/// The caller owns the returned `rustls_crypto_provider` and must free it using
/// `rustls_crypto_provider_free`.
#[no_mangle]
#[cfg(feature = "post-quantum")]
pub extern "C" fn rustls_post_quantum_provider() -> *const rustls_crypto_provider {
ffi_panic_boundary! {
Arc::into_raw(Arc::new(rustls_post_quantum::provider())) as *const rustls_crypto_provider
}
}

Expand Down Expand Up @@ -559,10 +592,19 @@ pub(crate) fn get_default_or_install_from_crate_features() -> Option<Arc<CryptoP

fn provider_from_crate_features() -> Option<CryptoProvider> {
// Provider default is unambiguously aws-lc-rs
#[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))]
#[cfg(all(
feature = "aws-lc-rs",
not(feature = "ring"),
not(feature = "post-quantum")
))]
{
return Some(aws_lc_rs::default_provider());
}
// Provider default is unambiguously post-qc aws-lc-rs
#[cfg(all(feature = "aws-lc-rs", not(feature = "ring"), feature = "post-quantum"))]
{
return Some(rustls_post_quantum::provider());
}

// Provider default is unambiguously ring
#[cfg(all(feature = "ring", not(feature = "aws-lc-rs")))]
Expand Down
Loading

0 comments on commit 094f722

Please sign in to comment.