Skip to main content

Crate ferritls_rustls

Crate ferritls_rustls 

Source
Expand description

§ferritls-rustls

A rustls 0.23 CryptoProvider backed by ferritls_core: a pure-Rust cryptographic core with no C, no assembly and no unsafe code, organized as a FIPS 140-3 module boundary.

This crate sits outside the FIPS boundary: it only assembles rustls traits from core primitives and contains no cryptography itself, which isolates rustls version churn to this layer.

§Getting started

Install the provider once per process, then use rustls as usual:

ferritls_rustls::default_provider()
    .install_default()
    .expect("ferritls is the first CryptoProvider installed");

// `ClientConfig::builder()` / `ServerConfig::builder()` now pick up
// the process-default provider:
let config = rustls::ClientConfig::builder()
    .with_root_certificates(rustls::RootCertStore::empty())
    .with_no_client_auth();

install_default() fails if another provider has already claimed the process default (for example a ring/aws-lc-rs default pulled in by another dependency — see the reqwest notes below).

To avoid process-global state, pass the provider explicitly:

use std::sync::Arc;

let provider = Arc::new(ferritls_rustls::default_provider());

let client_config = rustls::ClientConfig::builder_with_provider(provider.clone())
    .with_safe_default_protocol_versions()
    .expect("rustls defaults")
    .with_root_certificates(rustls::RootCertStore::empty())
    .with_no_client_auth();

Server side (certificate chain and private key loaded from your own storage; PKCS#8 / SEC1 DER and PEM via rustls::pki_types):

let provider = Arc::new(ferritls_rustls::default_provider());

let server_config = rustls::ServerConfig::builder_with_provider(provider)
    .with_safe_default_protocol_versions()
    .expect("rustls defaults")
    .with_no_client_auth()
    .with_single_cert(certs, key)
    .expect("valid server certificate chain");

Signing keys are loaded through the provider’s key_provider; the supported private-key formats are ECDSA (SEC1/PKCS#8), RSA (PKCS#8) and Ed25519 (PKCS#8).

§Capabilities

Cipher suites (TLS 1.3 only) — order equals preference:

SuiteDefault modeApproved modeQUIC
TLS_AES_128_GCM_SHA256yesyesyes
TLS_AES_256_GCM_SHA384yesyesyes
TLS_CHACHA20_POLY1305_SHA256yesno (not NIST-approved)yes
TLS_AES_128_CCM_SHA256yesyesno
TLS_AES_128_CCM_8_SHA256yesno (8-byte tag outside SP 800-52r2)no

Key exchange groups: X25519, secp256r1, secp384r1, the X25519MLKEM768 hybrid (0x11EC, draft-ietf-tls-ecdhe-mlkem) and the pure ML-KEM groups MLKEM512/768/1024 (0x0200–0x0202, draft-ietf-tls-mlkem-key-agreement). Approved mode offers the SP 800-52r2 approved subset (P-256/384 + X25519MLKEM768 + ML-KEM).

Signature verification: ECDSA P-256/384 (SHA-256/384/512), RSA-PSS and RSA PKCS#1 v1.5 (SHA-256/384/512), Ed25519 (default mode only — EdDSA is not a FIPS-approved signature algorithm).

§Approved (“FIPS”) mode

fips_mode_provider() returns a provider restricted to NIST-approved algorithms: AES-GCM/CCM suites, P-256/384 + ML-KEM key exchange, ECDSA/RSA verification, an SP 800-90A CTR-DRBG random source (reseeded with OS entropy on every generate) and power-on self-test KATs. The same restriction is available at compile time via the fips cargo feature.

let provider = ferritls_rustls::fips_mode_provider();

fips() semantics (important): ferritls is not yet CMVP-validated, so every fips() hook on this provider returns false. fips_mode_provider() means “runs in the approved algorithm mode”, not a certification claim. Once validation lands, a separate fips-validated feature on a locked source snapshot will flip that semantics (see docs/FIPS.md, phase C).

§QUIC

The AES-128-GCM, AES-256-GCM and ChaCha20-Poly1305 suites implement rustls::quic::Algorithm (RFC 9001 packet protection: packet keys, header protection and multipath for_path), so they can be used with QUIC stacks such as quinn:

let provider = std::sync::Arc::new(ferritls_rustls::default_provider());
let mut config = rustls::ClientConfig::builder_with_provider(provider)
    .with_safe_default_protocol_versions()
    .expect("rustls defaults")
    .with_root_certificates(rustls::RootCertStore::empty())
    .with_no_client_auth();
config.alpn_protocols = vec![b"h3".to_vec()];
// Feed `config` to your QUIC stack (e.g. quinn::crypto::rustls).

The CCM suites report quic: None (RFC 9001 §5.1 mandates AES-GCM as the baseline; rustls has no CCM traffic-secrets variant either).

§Using with reqwest

reqwest 0.12 and 0.13 both depend on rustls ^0.23 — the same version line as ferritls — so Cargo unifies everything into a single rustls instance and both generations work out of the box. Pick the no-provider feature variants; otherwise reqwest compiles in ring/aws-lc, which may claim the process default provider first (after which install_default() fails):

# reqwest 0.13 (rustls is the default TLS backend; system roots via
# rustls-platform-verifier)
reqwest = { version = "0.13", default-features = false,
            features = ["rustls-no-provider", "http2", "charset"] }

# reqwest 0.12 (rustls is opt-in; bundled webpki root store)
reqwest = { version = "0.12", default-features = false,
            features = ["rustls-tls-webpki-roots-no-provider", "http2", "charset"] }
# For system root stores use rustls-tls-native-roots-no-provider.
ⓘ
// Install before creating the first Client:
ferritls_rustls::default_provider().install_default()?;
let client = reqwest::Client::new();

To avoid process-global state, build a ClientConfig explicitly and inject it via use_preconfigured_tls (supported in both 0.12 and 0.13). The trust roots and ALPN must then be set on the ClientConfig yourself: reqwest does not modify a preconfigured config, and a missing ALPN list silently disables HTTP/2. Note that ferritls currently ships TLS 1.3 suites only.

§Build requirements (simd default feature)

The default simd feature of ferritls-core uses the standard library’s core::simd (portable_simd) for explicit vectorization of the AES and ChaCha20 hot paths. It is safe code from std (no new dependencies), but on the stable toolchain it requires the RUSTC_BOOTSTRAP=1 environment variable to compile the feature gate:

export RUSTC_BOOTSTRAP=1                                     # (a) keep simd
# or, in your Cargo.toml:                                    # (b) scalar fallback
# ferritls-core = { version = "0.9", default-features = false }

Vector width follows the compile target (SSE2/NEON baseline; build with RUSTFLAGS="-C target-feature=+avx2" or -C target-cpu=native to widen to AVX2/AVX-512). Nightly toolchains need no variable, and the requirement disappears once portable_simd stabilizes.

§Hardware acceleration (optional)

ferritls-backend-x86_64 is a separate, out-of-boundary crate (x86_64 only) providing AES-NI + CLMUL whole-message AES-GCM kernels and SHA-NI SHA-256, with runtime CPU detection and install-time KATs. It is opt-in from the application side via ferritls_core::ops::install(); nothing changes if it is not installed, and approved mode always stays on the software path.

§Crate layout

ModuleContents
providerdefault_provider / fips_mode_provider assembly
cipherTLS 1.3 suite adapters (AEAD, hash, HKDF, QUIC wiring)
kxSupportedKxGroup adapters (ECDH, ML-KEM, hybrid)
verifywebpki signature-verification algorithms
signSigningKey/Signer adapters and the rustls key provider
randomSecureRandom implementations (OS entropy / CTR-DRBG)
quicrustls::quic::Algorithm packet/header protection

Re-exports§

pub use provider::default_provider;
pub use provider::fips_mode_provider;

Modules§

cipher
TLS 1.3 密码套件装配(M6;QUIC 接线 M8.5)。
kx
密钥交换组:SupportedKxGroup / ActiveKeyExchange 适配。
provider
CryptoProvider 装配(M6)。
quic
QUIC 包保护(RFC 9001,M8.5)。
random
SecureRandom 适配:rustls 的握手随机数需求桥接到 ferritls-core。
sign
签名适配:SigningKey / Signer / KeyProvider。
verify
证书/握手签名验证算法(rustls-webpki 经由 rustls::crypto::WebPkiSupportedAlgorithms 消费)。