feat(vault-api): post-quantum transport feature flag (X25519MLKEM768)#30
Merged
Conversation
Adds an off-by-default `pqc` cargo feature that prefers the hybrid X25519MLKEM768 key exchange on the HTTPS/TLS layer — the PRD §12 M7 PQC transport item. Built from GPL-compatible parts only: the classical half reuses ring's audited X25519, the post-quantum half is RustCrypto `ml-kem` (Apache-2.0/MIT). We deliberately avoid aws-lc-rs (the only rustls provider shipping X25519MLKEM768) because its bundled AWS-LC carries OpenSSL-licensed code, which is GPL-incompatible. - crates/vault-api/src/pqc.rs: ML-KEM-768 as a rustls SupportedKxGroup (client/KEM-initiator role), composed with ring's X25519 into the X25519MLKEM768 hybrid (post-quantum-first wire layout per draft-ietf-tls-ecdhe-mlkem); `client_config()` builds a rustls ClientConfig that lists the hybrid first with classical fallback, injected into reqwest via `use_preconfigured_tls`. No unsafe (stays under forbid(unsafe_code)). - BitwardenClient::new wires it behind `#[cfg(feature = "pqc")]`; a gated Error::PqcTls variant carries config errors. vault-agent gains a `pqc` passthrough feature. - Off by default: the default dep tree, tests, deny, and headless builds are unchanged. Tests (run with `--features pqc`) cover the ML-KEM client kx round-trip + hybrid layout + that the config prefers PQC. - docs/pqc.md (construction + licensing rationale), README pointer, CHANGELOG. TLS 1.3 only; silent classical fallback when the server lacks PQC. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds an off-by-default
pqccargo feature that prefers the hybrid X25519MLKEM768 key exchange on the HTTPS/TLS layer — the PRD §12 M7 "PQC transport feature flag" item. With PQC enabled, a TLS 1.3 handshake negotiates a post-quantum-secure shared secret when the server offers it, and silently falls back to a classical group otherwise.GPL-clean by construction
rustls only ships X25519MLKEM768 via its aws-lc-rs provider, whose bundled AWS-LC carries OpenSSL-licensed code — GPL-incompatible, so off the table for a GPL-3.0-or-later project (Standard §4). Instead the hybrid is built from GPL-compatible parts:
rustls::crypto::ring::kx_group::X25519), reused as-is;ml-kem(MlKem768), Apache-2.0/MIT.cargo deny checkpasses with the new optional deps in the graph (no allow-list change).How
crates/vault-api/src/pqc.rs— ML-KEM-768 as arustls::crypto::SupportedKxGroup(client/KEM-initiator role: generate keypair, send the encapsulation key, decapsulate the server's ciphertext), composed with ring's X25519 into the X25519MLKEM768 hybrid. Post-quantum-first wire layout perdraft-ietf-tls-ecdhe-mlkem(client shareek(1184)‖x25519(32), server sharect(1088)‖x25519(32), secretss_mlkem(32)‖ss_x25519(32)), mirroring rustls's own crate-private layout.client_config()builds a rustlsClientConfiglisting the hybrid first (classical fallback), injected into reqwest viause_preconfigured_tls. Nounsafe(stays under#![forbid(unsafe_code)]).client.rs—BitwardenClient::newwires it behind#[cfg(feature = "pqc")]; a gatedError::PqcTlscarries config errors.vault-agentgains apqcpassthrough feature.Off by default → existing gates unchanged
The default dep tree,
cargo test --workspace,cargo deny, and both headless builds are untouched (PQC off). Clippy is--all-featuresso it builds + lints the module. The feature's own tests run withcargo test -p vault-api --features pqc(CI's test job doesn't pass--all-features) and cover: the ML-KEM client kx round-trip (encapsulate→decapsulate secrets match), the hybrid pub-key layout, wrong-length rejection, and that the config prefers PQC.Verification
fmt --check, fresh-isolatedclippy --all-features -D warnings,cargo test --workspace --all-targets,cargo test -p vault-api --features pqc(4/4),cargo deny check, both headless builds — all green.Out of scope (still pending for the v0.1 tag)
A live PQC-handshake test against a real server; making PQC the default. The ≥24h fuzz soak, the broader hardening pass, and the §11.2 two-week daily-driver attestation remain; then a slice cuts
v0.1.0.🤖 Generated with Claude Code