Bump boring to v5, align FIPS to SP 800-52r2, clean up features

- Bump boring/boring-sys from v4 to v5 (zero API breaks)
- Merge fips/fips-only into a single fips feature that both enables
  FIPS-validated BoringSSL and restricts algorithms to SP 800-52r2
- Tighten FIPS KX groups to P-256 and P-384 only (aligned with
  boring's fips202205 compliance policy)
- Remove ECDSA_P521_SHA512 from FIPS signature verification set
- Simplify fips feature to forward boring/fips only (drop redundant
  boring-sys/fips)
- Add fips-precompiled as deprecated alias matching boring's naming
- Change default features to empty (TLS 1.2 now requires explicit
  tls12 feature opt-in)
- Gate TLS 1.2 code paths properly so the crate compiles and passes
  tests with default (TLS 1.3 only) features
- Update README to reflect current state: boring v5, feature docs,
  FIPS mode documentation, workspace structure
This commit is contained in:
Jan Rüth 2026-04-10 12:09:47 +02:00 committed by Jan
commit 271acbb315
11 changed files with 273 additions and 77 deletions

View file

@ -9,10 +9,9 @@ on:
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
RUSTFLAGS: -Dwarnings RUSTFLAGS: -Dwarnings
FEATURES: "logging,tls12"
jobs: jobs:
build: fmt:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@ -21,9 +20,57 @@ jobs:
run: sudo apt-get install -y cmake clang run: sudo apt-get install -y cmake clang
- name: Check fmt - name: Check fmt
run: make fmt run: make fmt
- name: Lint
run: make lint test-default:
- name: Tests usual runs-on: ubuntu-latest
run: make test
- name: Build usual steps:
run: make build - uses: actions/checkout@v3
- name: Install dependencies
run: sudo apt-get install -y cmake clang
- name: Lint (default features)
run: make lint FEATURES=""
- name: Test (default features)
run: make test FEATURES=""
- name: Build (default features)
run: make build FEATURES=""
test-tls12:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install dependencies
run: sudo apt-get install -y cmake clang
- name: Lint (tls12)
run: make lint FEATURES="tls12"
- name: Test (tls12)
run: make test FEATURES="tls12"
- name: Build (tls12)
run: make build FEATURES="tls12"
test-logging-tls12:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install dependencies
run: sudo apt-get install -y cmake clang
- name: Lint (logging,tls12)
run: make lint FEATURES="logging,tls12"
- name: Test (logging,tls12)
run: make test FEATURES="logging,tls12"
- name: Build (logging,tls12)
run: make build FEATURES="logging,tls12"
check-fips:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install dependencies
run: sudo apt-get install -y cmake clang
- name: Check (fips)
run: cargo check -p boring-rustls-provider --all-targets --features fips
- name: Check (fips-precompiled)
run: cargo check -p boring-rustls-provider --all-targets --features fips-precompiled

View file

@ -17,8 +17,8 @@ default-members = [
resolver = "2" resolver = "2"
[workspace.dependencies] [workspace.dependencies]
boring = { version = "4", default-features = false } boring = { version = "5", default-features = false }
boring-sys = { version = "4", default-features = false } boring-sys = { version = "5", default-features = false }
rustls = { version = "0.23", default-features = false } rustls = { version = "0.23", default-features = false }
rustls-pemfile = { version = "2" } rustls-pemfile = { version = "2" }
rustls-pki-types = { version = "1" } rustls-pki-types = { version = "1" }

View file

@ -1,4 +1,5 @@
FEATURES ?= logging,tls12 FEATURES ?= logging,tls12
CARGO_FEATURES := $(if $(strip $(FEATURES)),-F "$(FEATURES)",)
.PHONY: fmt .PHONY: fmt
@ -7,12 +8,16 @@ fmt:
.PHONY: lint .PHONY: lint
lint: lint:
cargo clippy --workspace --all-targets -F "$(FEATURES)" cargo clippy --workspace --all-targets $(CARGO_FEATURES)
.PHONY: check
check:
cargo check --workspace --all-targets $(CARGO_FEATURES)
.PHONY: test .PHONY: test
test: test:
cargo test --all-targets -F "$(FEATURES)" cargo test --all-targets $(CARGO_FEATURES)
.PHONY: build .PHONY: build
build: build:
cargo build --all-targets -F "$(FEATURES)" cargo build --all-targets $(CARGO_FEATURES)

View file

@ -2,55 +2,60 @@
[![Build Status](https://github.com/janrueth/boring-rustls-provider/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/janrueth/boring-rustls-provider/actions/workflows/ci.yml?query=branch%3Amain) [![Build Status](https://github.com/janrueth/boring-rustls-provider/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/janrueth/boring-rustls-provider/actions/workflows/ci.yml?query=branch%3Amain)
This is supposed to be the start to a [boringssl](https://github.com/cloudflare/boring)-based [rustls](https://github.com/rustls/rustls) crypto provider. A [BoringSSL](https://github.com/cloudflare/boring)-based [rustls](https://github.com/rustls/rustls) crypto provider.
## Status Built on `boring` v5 and `rustls` 0.23.
This is just a dump of me figuring out how to interface with boring and rustls.
It works to establish a connection and exchange data but I haven't written real tests yet, nor did I cleanup the code or made the effort to make it look nice.
There is probably some code in here that should rather live in the `boring` crate.
Further, the rustls crypto provider API is still not stable it seems. This works currently with `rustls = 0.22.0-alpha.5`. ## Features
### Supported ciphers No features are enabled by default. The provider ships with TLS 1.3 support
Currently, supports only TLS 1.3: out of the box; additional capabilities are opt-in.
| Feature | Description |
|---|---|
| `fips` | Build against FIPS-validated BoringSSL and restrict the provider to FIPS-approved algorithms only (SP 800-52r2). See [FIPS mode](#fips-mode) below. |
| `fips-precompiled` | Deprecated alias for `fips`. Matches the `boring` crate's feature name. |
| `tls12` | Enable TLS 1.2 cipher suites (`ECDHE-ECDSA` and `ECDHE-RSA` with AES-GCM and ChaCha20-Poly1305). Without this only TLS 1.3 is available. |
| `logging` | Enable debug logging of BoringSSL errors and provider internals via the `log` crate. |
## Supported Algorithms
### Cipher Suites
TLS 1.3 (always available):
``` ```
AES_128_GCM_SHA256 AES_128_GCM_SHA256
AES_256_GCM_SHA384 AES_256_GCM_SHA384
CHACHA20_POLY1305_SHA256 CHACHA20_POLY1305_SHA256
``` ```
QUIC: not yet supported TLS 1.2 (requires `tls12` feature):
TLS 1.2:
``` ```
ECDHE_ECDSA_AES128_GCM_SHA256 ECDHE_ECDSA_AES128_GCM_SHA256
ECDHE_RSA_AES128_GCM_SHA256 ECDHE_RSA_AES128_GCM_SHA256
ECDHE_ECDSA_AES256_GCM_SHA384 ECDHE_ECDSA_AES256_GCM_SHA384
ECDHE_RSA_AES256_GCM_SHA384 ECDHE_RSA_AES256_GCM_SHA384
ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
``` ```
### Key Exchange Algorithms ### Key Exchange Groups
`ECDHE` with curves: ECDHE:
``` ```
X25519 X25519
X448 X448
secp256r1 secp256r1 (P-256)
secp384r1 secp384r1 (P-384)
secp521r1 secp521r1 (P-521)
``` ```
FFDHE:
`FFDHE` with:
``` ```
ffdhe2048 ffdhe2048
``` ```
### Signature Generation / Verification ### Signature Algorithms
``` ```
RSA_PKCS1_SHA256 RSA_PKCS1_SHA256
@ -66,6 +71,30 @@ ED25519
ED448 ED448
``` ```
## FIPS Mode
When the `fips` feature is enabled the provider builds against a FIPS-validated
version of BoringSSL and restricts all algorithm selections to those approved
under [SP 800-52r2](https://doi.org/10.6028/NIST.SP.800-52r2), aligned with
boring's `fips202205` compliance policy:
- **Cipher suites**: AES-GCM only (no ChaCha20-Poly1305).
- **Key exchange groups**: P-256 and P-384 only (no X25519, X448, P-521, or FFDHE).
- **Signature algorithms**: RSA PKCS#1 / PSS and ECDSA with P-256 or P-384 only
(no P-521, Ed25519, or Ed448).
Post-quantum hybrid key exchange (`P256Kyber768Draft00`) is planned for the
FIPS group set but not yet implemented.
## Workspace Structure
| Crate | Purpose |
|---|---|
| `boring-rustls-provider` | The main rustls crypto provider. |
| `boring-additions` | Safe Rust wrappers for BoringSSL APIs not yet exposed by the `boring` crate (AEAD, EVP_PKEY_CTX, HMAC_CTX). Intended for upstreaming. |
| `boring-sys-additions` | Raw FFI binding for `CRYPTO_tls1_prf` (internal BoringSSL symbol used for FIPS-compliant TLS 1.2 PRF). Intended for upstreaming. |
| `examples` | Example client binary. |
## License ## License
MIT MIT

View file

@ -8,13 +8,30 @@ description = "Boringssl rustls provider"
publish = false publish = false
[features] [features]
default = ["tls12"] default = []
# Use a FIPS-validated version of boringssl.
fips = ["boring/fips", "boring-sys/fips"] # Build against a FIPS-validated version of BoringSSL and restrict the
logging = ["log"] # provider to FIPS-approved algorithms only. This affects:
fips-only = ["boring/fips", "boring-sys/fips"] # - Cipher suites: AES-GCM only (no ChaCha20-Poly1305).
# - Key exchange groups: P-256 and P-384 only (no X25519, X448, P-521,
# or FFDHE). P256Kyber768Draft00 will be added once implemented.
# - Signature algorithms: RSA PKCS#1 / PSS and ECDSA with P-256/P-384
# only (no P-521, Ed25519, or Ed448).
# Aligned with boring's `fips202205` compliance policy (SP 800-52r2).
fips = ["boring/fips"]
# Deprecated alias for `fips`. Matches the boring crate's feature name
# for backwards compatibility.
fips-precompiled = ["fips"]
# Enable TLS 1.2 cipher suites (ECDHE-ECDSA and ECDHE-RSA with AES-GCM
# and ChaCha20-Poly1305). Without this feature only TLS 1.3 is available.
tls12 = ["rustls/tls12"] tls12 = ["rustls/tls12"]
# Enable debug logging of BoringSSL errors and provider internals via
# the `log` crate. Useful for diagnosing handshake failures.
logging = ["log"]
[dependencies] [dependencies]
aead = {version = "0.5", default-features = false, features = ["alloc"] } aead = {version = "0.5", default-features = false, features = ["alloc"] }
boring = { workspace = true } boring = { workspace = true }

View file

@ -3,9 +3,9 @@ use std::marker::PhantomData;
use aead::{AeadCore, AeadInPlace, Buffer, Nonce, Tag}; use aead::{AeadCore, AeadInPlace, Buffer, Nonce, Tag};
use boring::error::ErrorStack; use boring::error::ErrorStack;
use boring_additions::aead::Algorithm; use boring_additions::aead::Algorithm;
use rustls::crypto::cipher::{ #[cfg(feature = "tls12")]
self, make_tls12_aad, make_tls13_aad, BorrowedPayload, Iv, PrefixedPayload, use rustls::crypto::cipher::make_tls12_aad;
}; use rustls::crypto::cipher::{self, make_tls13_aad, BorrowedPayload, Iv, PrefixedPayload};
use rustls::{ConnectionTrafficSecrets, ContentType, ProtocolVersion}; use rustls::{ConnectionTrafficSecrets, ContentType, ProtocolVersion};
use crate::helper::log_and_map; use crate::helper::log_and_map;
@ -20,6 +20,8 @@ pub(crate) trait BoringCipher {
/// The IV's fixed length (Not the full IV length, only the part that doesn't change). /// The IV's fixed length (Not the full IV length, only the part that doesn't change).
/// Together with [`BoringCipher::explicit_nonce_len`] it determines the total /// Together with [`BoringCipher::explicit_nonce_len`] it determines the total
/// lengths of the used nonce. /// lengths of the used nonce.
/// Used only by TLS 1.2 code paths.
#[cfg(feature = "tls12")]
const FIXED_IV_LEN: usize; const FIXED_IV_LEN: usize;
/// The key size in bytes /// The key size in bytes
const KEY_SIZE: usize; const KEY_SIZE: usize;
@ -569,7 +571,8 @@ impl Buffer for EncryptBufferAdapter<'_> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use hex_literal::hex; use hex_literal::hex;
use rustls::crypto::cipher::{AeadKey, Iv}; use rustls::crypto::cipher::AeadKey;
use rustls::crypto::cipher::Iv;
use crate::aead::BoringAeadCrypter; use crate::aead::BoringAeadCrypter;
use rustls::quic::PacketKey; use rustls::quic::PacketKey;
@ -611,7 +614,7 @@ mod tests {
let unprotected_header = hex!("4200bff4"); let unprotected_header = hex!("4200bff4");
let protector = BoringAeadCrypter::<ChaCha20Poly1305>::new( let protector = BoringAeadCrypter::<ChaCha20Poly1305>::new(
Iv::new(iv), Iv::from(iv),
&key, &key,
rustls::ProtocolVersion::TLSv1_3, rustls::ProtocolVersion::TLSv1_3,
) )

View file

@ -11,6 +11,7 @@ impl BoringAead for Aes128 {}
impl BoringCipher for Aes128 { impl BoringCipher for Aes128 {
const EXPLICIT_NONCE_LEN: usize = 8; const EXPLICIT_NONCE_LEN: usize = 8;
#[cfg(feature = "tls12")]
const FIXED_IV_LEN: usize = 4; const FIXED_IV_LEN: usize = 4;
const KEY_SIZE: usize = 16; const KEY_SIZE: usize = 16;
@ -55,6 +56,7 @@ impl BoringAead for Aes256 {}
impl BoringCipher for Aes256 { impl BoringCipher for Aes256 {
const EXPLICIT_NONCE_LEN: usize = 8; const EXPLICIT_NONCE_LEN: usize = 8;
#[cfg(feature = "tls12")]
const FIXED_IV_LEN: usize = 4; const FIXED_IV_LEN: usize = 4;
const KEY_SIZE: usize = 32; const KEY_SIZE: usize = 32;

View file

@ -14,6 +14,7 @@ impl BoringAead for ChaCha20Poly1305 {}
impl BoringCipher for ChaCha20Poly1305 { impl BoringCipher for ChaCha20Poly1305 {
const EXPLICIT_NONCE_LEN: usize = 0; const EXPLICIT_NONCE_LEN: usize = 0;
#[cfg(feature = "tls12")]
const FIXED_IV_LEN: usize = 12; const FIXED_IV_LEN: usize = 12;
const KEY_SIZE: usize = 32; const KEY_SIZE: usize = 32;

View file

@ -22,11 +22,11 @@ pub mod tls13;
pub mod verify; pub mod verify;
pub fn provider() -> CryptoProvider { pub fn provider() -> CryptoProvider {
#[cfg(feature = "fips-only")] #[cfg(feature = "fips")]
{ {
provider_with_ciphers(ALL_FIPS_CIPHER_SUITES.to_vec()) provider_with_ciphers(ALL_FIPS_CIPHER_SUITES.to_vec())
} }
#[cfg(not(feature = "fips-only"))] #[cfg(not(feature = "fips"))]
{ {
provider_with_ciphers(ALL_CIPHER_SUITES.to_vec()) provider_with_ciphers(ALL_CIPHER_SUITES.to_vec())
} }
@ -35,13 +35,13 @@ pub fn provider() -> CryptoProvider {
pub fn provider_with_ciphers(ciphers: Vec<rustls::SupportedCipherSuite>) -> CryptoProvider { pub fn provider_with_ciphers(ciphers: Vec<rustls::SupportedCipherSuite>) -> CryptoProvider {
CryptoProvider { CryptoProvider {
cipher_suites: ciphers, cipher_suites: ciphers,
#[cfg(feature = "fips-only")] #[cfg(feature = "fips")]
kx_groups: ALL_FIPS_KX_GROUPS.to_vec(), kx_groups: ALL_FIPS_KX_GROUPS.to_vec(),
#[cfg(not(feature = "fips-only"))] #[cfg(not(feature = "fips"))]
kx_groups: ALL_KX_GROUPS.to_vec(), kx_groups: ALL_KX_GROUPS.to_vec(),
#[cfg(feature = "fips-only")] #[cfg(feature = "fips")]
signature_verification_algorithms: verify::ALL_FIPS_ALGORITHMS, signature_verification_algorithms: verify::ALL_FIPS_ALGORITHMS,
#[cfg(not(feature = "fips-only"))] #[cfg(not(feature = "fips"))]
signature_verification_algorithms: verify::ALL_ALGORITHMS, signature_verification_algorithms: verify::ALL_ALGORITHMS,
secure_random: &Provider, secure_random: &Provider,
key_provider: &Provider, key_provider: &Provider,
@ -99,18 +99,15 @@ static ALL_CIPHER_SUITES: &[SupportedCipherSuite] = &[
SupportedCipherSuite::Tls12(&tls12::ECDHE_RSA_AES128_GCM_SHA256), SupportedCipherSuite::Tls12(&tls12::ECDHE_RSA_AES128_GCM_SHA256),
]; ];
/// Allowed KX curves for FIPS are recommended /// Allowed KX groups for FIPS per [SP 800-52r2](https://doi.org/10.6028/NIST.SP.800-52r2),
/// in [NIST SP 800-186](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-186.pdf) /// aligned with boring's `fips202205` compliance policy.
/// ///
/// See Sec. 3.1.2 Table 2 /// See Section 3.3.1 and 3.4.2.2.
/// Ordered in decending order of security strength // TODO: Add P256Kyber768Draft00 once the PQ hybrid KEM is implemented (Step 3).
#[allow(unused)] #[allow(unused)]
pub const ALL_FIPS_KX_GROUPS: &[&dyn SupportedKxGroup] = &[ pub const ALL_FIPS_KX_GROUPS: &[&dyn SupportedKxGroup] = &[
&kx::Secp521r1 as _, // P-521 in FIPS lingo &kx::Secp256r1 as _, // P-256
&kx::X448 as _, // Curve448 in FIPS lingo &kx::Secp384r1 as _, // P-384
&kx::Secp384r1 as _, // P-384 in FIPS lingo
&kx::X25519 as _, // Curve25519 in FIPS lingo
&kx::Secp256r1 as _, // P-256 in FIPS lingo
]; ];
#[allow(unused)] #[allow(unused)]

View file

@ -61,6 +61,13 @@ pub static ALL_ALGORITHMS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms
], ],
}; };
/// FIPS-approved signature verification algorithms per SP 800-52r2.
///
/// Aligned with boring's `fips202205` compliance policy:
/// - RSA: PKCS#1 v1.5 and PSS with SHA-256/384/512
/// - ECDSA: P-256 with SHA-256 and P-384 with SHA-384 only
/// (SP 800-52r2 Table 4.1: "The curve should be P-256 or P-384")
/// - No P-521, Ed25519, or Ed448
#[allow(unused)] #[allow(unused)]
pub static ALL_FIPS_ALGORITHMS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms { pub static ALL_FIPS_ALGORITHMS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms {
all: &[ all: &[
@ -72,9 +79,6 @@ pub static ALL_FIPS_ALGORITHMS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgor
&rsa::BoringRsaVerifier::RSA_PSS_SHA512, &rsa::BoringRsaVerifier::RSA_PSS_SHA512,
&ec::BoringEcVerifier::ECDSA_NISTP256_SHA256, &ec::BoringEcVerifier::ECDSA_NISTP256_SHA256,
&ec::BoringEcVerifier::ECDSA_NISTP384_SHA384, &ec::BoringEcVerifier::ECDSA_NISTP384_SHA384,
&ec::BoringEcVerifier::ECDSA_NISTP521_SHA512,
//&ed::BoringEdVerifier::ED25519, // FIPS 186-5: requires SHA512 but boring doesn't want us to set a digest, correct?
//&ed::BoringEdVerifier::ED448, // FIPS 186-5: requires SHAKE256 but boring doesn't want us to set a digest, correct?
], ],
mapping: &[ mapping: &[
( (
@ -109,11 +113,5 @@ pub static ALL_FIPS_ALGORITHMS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgor
SignatureScheme::ECDSA_NISTP384_SHA384, SignatureScheme::ECDSA_NISTP384_SHA384,
&[&ec::BoringEcVerifier::ECDSA_NISTP384_SHA384], &[&ec::BoringEcVerifier::ECDSA_NISTP384_SHA384],
), ),
(
SignatureScheme::ECDSA_NISTP521_SHA512,
&[&ec::BoringEcVerifier::ECDSA_NISTP521_SHA512],
),
// (SignatureScheme::ED25519, &[&ed::BoringEdVerifier::ED25519]),
// (SignatureScheme::ED448, &[&ed::BoringEdVerifier::ED448]),
], ],
}; };

View file

@ -5,11 +5,12 @@ use tokio::{
net::TcpStream, net::TcpStream,
}; };
use boring_rustls_provider::{tls12, tls13}; #[cfg(feature = "tls12")]
use rustls::{ use boring_rustls_provider::tls12;
version::{TLS12, TLS13}, use boring_rustls_provider::tls13;
ClientConfig, ServerConfig, SupportedCipherSuite, #[cfg(feature = "tls12")]
}; use rustls::version::TLS12;
use rustls::{version::TLS13, ClientConfig, ServerConfig, SupportedCipherSuite};
use rustls_pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer}; use rustls_pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer};
use tokio::net::TcpListener; use tokio::net::TcpListener;
use tokio_rustls::{TlsAcceptor, TlsConnector}; use tokio_rustls::{TlsAcceptor, TlsConnector};
@ -41,17 +42,107 @@ async fn test_tls13_crypto() {
} }
#[test] #[test]
#[cfg(any(feature = "fips", feature = "fips-only"))] #[cfg(feature = "fips")]
fn is_fips_enabled() { fn is_fips_enabled() {
assert!(boring::fips::enabled()); assert!(boring::fips::enabled());
} }
#[test] #[test]
#[cfg(not(any(feature = "fips", feature = "fips-only")))] #[cfg(feature = "fips")]
fn fips_provider_excludes_chacha20_cipher_suites() {
use rustls::CipherSuite;
let provider = boring_rustls_provider::provider();
let disallowed = [
CipherSuite::TLS13_CHACHA20_POLY1305_SHA256,
CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
];
for suite in provider.cipher_suites {
let selected = suite.suite();
assert!(
!disallowed.contains(&selected),
"FIPS provider exposed disallowed cipher suite: {selected:?}"
);
}
}
#[test]
#[cfg(feature = "fips")]
fn fips_provider_restricts_kx_groups() {
use rustls::NamedGroup;
let provider = boring_rustls_provider::provider();
let groups = provider
.kx_groups
.iter()
.map(|group| group.name())
.collect::<Vec<_>>();
assert!(groups.contains(&NamedGroup::secp256r1));
assert!(groups.contains(&NamedGroup::secp384r1));
for group in groups {
assert!(
matches!(group, NamedGroup::secp256r1 | NamedGroup::secp384r1),
"FIPS provider exposed disallowed KX group: {group:?}"
);
}
}
#[test]
#[cfg(feature = "fips")]
fn fips_provider_excludes_disallowed_signature_schemes() {
use rustls::SignatureScheme;
let provider = boring_rustls_provider::provider();
let schemes = provider
.signature_verification_algorithms
.mapping
.iter()
.map(|(scheme, _)| *scheme)
.collect::<Vec<_>>();
assert!(schemes.contains(&SignatureScheme::RSA_PSS_SHA256));
assert!(schemes.contains(&SignatureScheme::ECDSA_NISTP256_SHA256));
for disallowed in [
SignatureScheme::ECDSA_NISTP521_SHA512,
SignatureScheme::ED25519,
SignatureScheme::ED448,
] {
assert!(
!schemes.contains(&disallowed),
"FIPS provider exposed disallowed signature scheme: {disallowed:?}"
);
}
}
#[test]
#[cfg(not(feature = "fips"))]
fn is_fips_disabled() { fn is_fips_disabled() {
assert!(!boring::fips::enabled()); assert!(!boring::fips::enabled());
} }
#[test]
#[cfg(not(feature = "fips"))]
fn non_fips_provider_keeps_non_fips_algorithms() {
use rustls::{CipherSuite, NamedGroup};
let provider = boring_rustls_provider::provider();
assert!(provider
.cipher_suites
.iter()
.any(|suite| { suite.suite() == CipherSuite::TLS13_CHACHA20_POLY1305_SHA256 }));
assert!(provider
.kx_groups
.iter()
.any(|group| group.name() == NamedGroup::X25519));
}
#[cfg(feature = "tls12")]
#[tokio::test] #[tokio::test]
async fn test_tls12_ec_crypto() { async fn test_tls12_ec_crypto() {
let pki = TestPki::new(&rcgen::PKCS_ECDSA_P256_SHA256); let pki = TestPki::new(&rcgen::PKCS_ECDSA_P256_SHA256);
@ -78,6 +169,7 @@ async fn test_tls12_ec_crypto() {
} }
} }
#[cfg(feature = "tls12")]
#[tokio::test] #[tokio::test]
async fn test_tls12_rsa_crypto() { async fn test_tls12_rsa_crypto() {
let pki = TestPki::new(&rcgen::PKCS_RSA_SHA256); let pki = TestPki::new(&rcgen::PKCS_RSA_SHA256);
@ -188,9 +280,14 @@ impl TestPki {
} }
fn server_config(self) -> Arc<ServerConfig> { fn server_config(self) -> Arc<ServerConfig> {
#[cfg(feature = "tls12")]
let versions: &[&'static rustls::SupportedProtocolVersion] = &[&TLS12, &TLS13];
#[cfg(not(feature = "tls12"))]
let versions: &[&'static rustls::SupportedProtocolVersion] = &[&TLS13];
let mut server_config = let mut server_config =
ServerConfig::builder_with_provider(Arc::new(boring_rustls_provider::provider())) ServerConfig::builder_with_provider(Arc::new(boring_rustls_provider::provider()))
.with_protocol_versions(&[&TLS12, &TLS13]) .with_protocol_versions(versions)
.unwrap() .unwrap()
.with_no_client_auth() .with_no_client_auth()
.with_single_cert(vec![self.server_cert_der], self.server_key_der) .with_single_cert(vec![self.server_cert_der], self.server_key_der)