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

add opt-in post-quantum KX feature flag #520

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .github/workflows/daily-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,66 @@ 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
# 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
Loading