Skip to content

Commit 7eb5a7c

Browse files
Merge pull request #30 from Spacecraft-Software/pqc-transport
feat(vault-api): post-quantum transport feature flag (X25519MLKEM768)
2 parents 653eb71 + 50f247b commit 7eb5a7c

10 files changed

Lines changed: 407 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,16 @@ range may break in any release.
1010

1111
### Added
1212

13+
- **Post-quantum transport (`pqc` feature, off by default).** A GPL-clean hybrid
14+
**X25519MLKEM768** key-exchange group is added to the rustls client config, so
15+
a TLS 1.3 handshake negotiates a post-quantum-secure secret when the server
16+
offers it (silent classical fallback otherwise). The classical half reuses
17+
ring's X25519; the PQ half is RustCrypto `ml-kem` (Apache-2.0/MIT) — *not*
18+
aws-lc-rs, whose OpenSSL-licensed AWS-LC is GPL-incompatible. Build with
19+
`cargo build -p vault-agent --features pqc`; see `docs/pqc.md`. Satisfies the
20+
PRD §12 M7 "PQC transport feature flag" item (`vault-api/src/pqc.rs`, client
21+
role only). Tests cover the ML-KEM client kx round-trip + the hybrid layout.
22+
1323
- **`EncString` parser fuzz harness.** A cargo-fuzz / libFuzzer target
1424
(`fuzz/fuzz_targets/enc_string_parse.rs`) for the security-critical Bitwarden
1525
"type 2" parser — feeds arbitrary input to `EncString::parse` and asserts the

Cargo.lock

Lines changed: 55 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ agent logs to `agent.log` beside the socket.
5050
The security-critical `EncString` parser has a cargo-fuzz harness under `fuzz/`
5151
(a standalone workspace, run on nightly) — see [`docs/fuzzing.md`](docs/fuzzing.md).
5252

53+
An optional **post-quantum transport** (`--features pqc`) prefers the hybrid
54+
X25519MLKEM768 key exchange on the HTTPS client, off by default — see
55+
[`docs/pqc.md`](docs/pqc.md).
56+
5357
## Getting started
5458

5559
```sh

crates/vault-agent/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ workspace = true
2727
# returns a clean "not compiled in" error.
2828
default = ["clipboard"]
2929
clipboard = ["dep:arboard"]
30+
# Post-quantum transport (off by default): prefer X25519MLKEM768 on the HTTPS
31+
# client. Passes through to vault-api; see `docs/pqc.md`.
32+
pqc = ["vault-api/pqc"]
3033

3134
[dependencies]
3235
anyhow = { workspace = true }

crates/vault-api/Cargo.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ readme.workspace = true
1616
[lints]
1717
workspace = true
1818

19+
[features]
20+
# Off-by-default post-quantum transport. Adds a GPL-clean X25519MLKEM768 hybrid
21+
# key-exchange group (ring X25519 + RustCrypto ML-KEM-768) to the rustls client
22+
# config. See `docs/pqc.md`.
23+
pqc = ["dep:rustls", "dep:ml-kem", "dep:kem", "dep:rand_core", "dep:webpki-roots"]
24+
1925
[dependencies]
2026
thiserror = { workspace = true }
2127
serde = { workspace = true }
@@ -28,6 +34,16 @@ time = { workspace = true }
2834
base64 = { workspace = true }
2935
vault-core = { path = "../vault-core" }
3036

37+
# PQC transport (feature = "pqc"). Pinned to the versions reqwest already pulls
38+
# so rustls unifies to one crate instance (required for `use_preconfigured_tls`).
39+
rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12"], optional = true }
40+
ml-kem = { version = "0.2", optional = true }
41+
# `kem` provides the Encapsulate/Decapsulate traits ml-kem's keys implement;
42+
# pinned to the exact pre-release ml-kem 0.2 depends on.
43+
kem = { version = "=0.3.0-pre.0", optional = true }
44+
rand_core = { version = "0.6", features = ["getrandom"], optional = true }
45+
webpki-roots = { version = "1", optional = true }
46+
3147
[dev-dependencies]
3248
tokio = { workspace = true }
3349
wiremock = { workspace = true }

crates/vault-api/src/client.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,16 @@ impl BitwardenClient {
6161
/// Returns [`Error::Transport`] if the underlying `reqwest` client fails to build.
6262
pub fn new(urls: BaseUrls, device_id: Uuid, device_name: impl Into<String>) -> Result<Self> {
6363
let user_agent = format!("vault/{} (Spacecraft-Software)", env!("CARGO_PKG_VERSION"));
64-
let http = Client::builder()
64+
let builder = Client::builder()
6565
.user_agent(&user_agent)
66-
.https_only(urls.api.scheme() == "https")
67-
.build()?;
66+
.https_only(urls.api.scheme() == "https");
67+
// With the `pqc` feature, prefer the X25519MLKEM768 hybrid key exchange
68+
// on the TLS layer (falls back to classical when the server lacks it).
69+
#[cfg(feature = "pqc")]
70+
let builder = builder.use_preconfigured_tls(
71+
crate::pqc::client_config().map_err(|e| Error::PqcTls(e.to_string()))?,
72+
);
73+
let http = builder.build()?;
6874
Ok(Self {
6975
http,
7076
urls,

crates/vault-api/src/error.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ pub enum Error {
3939
/// vault-core surfaced an error (KDF, hashing, etc.) during the API flow.
4040
#[error("crypto: {0}")]
4141
Crypto(#[from] vault_core::Error),
42+
43+
/// The post-quantum transport (feature `pqc`) could not build its rustls
44+
/// client config. Not expected in practice (safe defaults are always valid).
45+
#[cfg(feature = "pqc")]
46+
#[error("pqc tls config: {0}")]
47+
PqcTls(String),
4248
}
4349

4450
/// Convenience `Result` alias used throughout `vault-api`.

crates/vault-api/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
pub mod client;
1010
pub mod error;
1111
pub mod identity;
12+
#[cfg(feature = "pqc")]
13+
pub mod pqc;
1214
pub mod sync;
1315
pub mod urls;
1416

0 commit comments

Comments
 (0)