Skip to content

Commit 35b463c

Browse files
make post quantum test run in the CI
1 parent 9eb672a commit 35b463c

File tree

5 files changed

+136
-9
lines changed

5 files changed

+136
-9
lines changed

.github/workflows/rust.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,10 @@ jobs:
133133
- uses: Swatinem/rust-cache@v2
134134
# Prevent feature unification from selecting *ring* as the crypto provider
135135
- run: RUST_BACKTRACE=1 cargo test --manifest-path quinn-proto/Cargo.toml --no-default-features --features rustls-aws-lc-rs
136-
- run: RUST_BACKTRACE=1 cargo test --manifest-path quinn/Cargo.toml --no-default-features --features rustls-aws-lc-rs,runtime-tokio
136+
- run: RUST_BACKTRACE=1 cargo test --manifest-path quinn/Cargo.toml --no-default-features --features rustls-aws-lc-rs,runtime-tokio,__rustls-post-quantum-test
137137
# FIPS
138138
- run: RUST_BACKTRACE=1 cargo test --manifest-path quinn-proto/Cargo.toml --no-default-features --features rustls-aws-lc-rs-fips
139-
- run: RUST_BACKTRACE=1 cargo test --manifest-path quinn/Cargo.toml --no-default-features --features rustls-aws-lc-rs-fips,runtime-tokio
139+
- run: RUST_BACKTRACE=1 cargo test --manifest-path quinn/Cargo.toml --no-default-features --features rustls-aws-lc-rs-fips,__rustls-post-quantum-test,runtime-tokio
140140

141141
wasm_test:
142142
name: test wasm32-unknown-unknown
@@ -283,7 +283,7 @@ jobs:
283283
env:
284284
RUSTFLAGS: -Dwarnings
285285
# skip FIPS features outside of Linux
286-
SKIP_FEATURES: ${{ matrix.os != 'ubuntu-latest' && 'rustls-aws-lc-rs-fips,aws-lc-rs-fips' || '' }}
286+
SKIP_FEATURES: ${{ matrix.os != 'ubuntu-latest' && 'rustls-aws-lc-rs-fips,aws-lc-rs-fips,__rustls-post-quantum-test' || '' }}
287287
steps:
288288
- uses: actions/checkout@v4
289289
- uses: dtolnay/rust-toolchain@stable

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ rustls = { version = "0.23.5", default-features = false, features = ["std"] }
3939
rustls-pemfile = "2"
4040
rustls-platform-verifier = "0.4"
4141
rustls-pki-types = "1.7"
42+
rustls-post-quantum = "0.1"
4243
serde = { version = "1.0", features = ["derive"] }
4344
serde_json = "1"
4445
slab = "0.4.6"

quinn/Cargo.toml

+5
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ rustc-hash = { workspace = true }
5353
pin-project-lite = { workspace = true }
5454
proto = { package = "quinn-proto", path = "../quinn-proto", version = "0.11.7", default-features = false }
5555
rustls = { workspace = true, optional = true }
56+
rustls-post-quantum = { workspace = true, optional = true }
5657
smol = { workspace = true, optional = true }
5758
socket2 = { workspace = true }
5859
thiserror = { workspace = true }
@@ -94,6 +95,10 @@ required-features = ["rustls-ring"]
9495
name = "connection"
9596
required-features = ["rustls-ring"]
9697

98+
[[test]]
99+
name = "post_quantum"
100+
required-features = ["__rustls-post-quantum-test"]
101+
97102
[[bench]]
98103
name = "bench"
99104
harness = false

quinn/tests/many_connections.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,10 @@ struct Shared {
1919
#[test]
2020
#[ignore]
2121
fn connect_n_nodes_to_1_and_send_1mb_data() {
22-
tracing::subscriber::set_global_default(
23-
tracing_subscriber::FmtSubscriber::builder()
24-
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
25-
.finish(),
26-
)
27-
.unwrap();
22+
let _ = tracing_subscriber::FmtSubscriber::builder()
23+
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
24+
.with_test_writer()
25+
.try_init();
2826

2927
let runtime = Builder::new_current_thread().enable_all().build().unwrap();
3028
let _guard = runtime.enter();

quinn/tests/post_quantum.rs

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
#![cfg(feature = "rustls-aws-lc-rs")]
2+
3+
use std::{
4+
error::Error,
5+
net::{Ipv4Addr, SocketAddr},
6+
sync::Arc,
7+
};
8+
9+
use rustls::{
10+
pki_types::{CertificateDer, PrivatePkcs8KeyDer},
11+
NamedGroup,
12+
};
13+
use tracing::info;
14+
15+
use quinn::{
16+
crypto::rustls::{HandshakeData, QuicClientConfig, QuicServerConfig},
17+
Endpoint,
18+
};
19+
20+
#[tokio::test]
21+
async fn post_quantum_key_worst_case_header() {
22+
check_post_quantum_key_exchange(1274, 8081).await;
23+
}
24+
25+
#[tokio::test]
26+
async fn post_quantum_key_exchange_large_mtu() {
27+
check_post_quantum_key_exchange(1433, 8082).await;
28+
}
29+
30+
async fn check_post_quantum_key_exchange(min_mtu: u16, server_port: u16) {
31+
let _ = tracing_subscriber::FmtSubscriber::builder()
32+
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
33+
.with_test_writer()
34+
.try_init();
35+
36+
let server_addr = SocketAddr::from((Ipv4Addr::LOCALHOST, server_port));
37+
38+
let (endpoint, server_cert) = make_server_endpoint(server_addr, min_mtu).unwrap();
39+
// accept a single connection
40+
tokio::spawn(async move {
41+
let incoming_conn = endpoint.accept().await.unwrap();
42+
let conn = incoming_conn.await.unwrap();
43+
info!(
44+
"[server] connection accepted: addr={}",
45+
conn.remote_address()
46+
);
47+
assert_eq!(
48+
conn.handshake_data()
49+
.unwrap()
50+
.downcast::<HandshakeData>()
51+
.unwrap()
52+
.negotiated_key_exchange_group,
53+
X25519_KYBER768_DRAFT00
54+
)
55+
// Dropping all handles associated with a connection implicitly closes it
56+
});
57+
58+
let endpoint =
59+
make_client_endpoint(SocketAddr::from((Ipv4Addr::UNSPECIFIED, 0)), server_cert).unwrap();
60+
// connect to server
61+
let connection = endpoint
62+
.connect(server_addr, "localhost")
63+
.unwrap()
64+
.await
65+
.unwrap();
66+
info!("[client] connected: addr={}", connection.remote_address());
67+
68+
// Waiting for a stream will complete with an error when the server closes the connection
69+
let _ = connection.accept_uni().await;
70+
71+
// Make sure the server has a chance to clean up
72+
endpoint.wait_idle().await;
73+
}
74+
75+
fn make_client_endpoint(
76+
bind_addr: SocketAddr,
77+
server_cert: CertificateDer<'static>,
78+
) -> Result<Endpoint, Box<dyn Error + Send + Sync + 'static>> {
79+
let mut certs = rustls::RootCertStore::empty();
80+
certs.add(server_cert)?;
81+
let rustls_config =
82+
rustls::ClientConfig::builder_with_provider(Arc::new(rustls_post_quantum::provider()))
83+
.with_safe_default_protocol_versions()
84+
.unwrap()
85+
.with_root_certificates(certs)
86+
.with_no_client_auth();
87+
88+
let client_cfg =
89+
quinn::ClientConfig::new(Arc::new(QuicClientConfig::try_from(rustls_config).unwrap()));
90+
let mut endpoint = Endpoint::client(bind_addr)?;
91+
endpoint.set_default_client_config(client_cfg);
92+
Ok(endpoint)
93+
}
94+
95+
fn make_server_endpoint(
96+
bind_addr: SocketAddr,
97+
min_mtu: u16,
98+
) -> Result<(Endpoint, CertificateDer<'static>), Box<dyn Error + Send + Sync + 'static>> {
99+
let cert = rcgen::generate_simple_self_signed(vec!["localhost".into()]).unwrap();
100+
let server_cert = CertificateDer::from(cert.cert);
101+
let priv_key = PrivatePkcs8KeyDer::from(cert.key_pair.serialize_der());
102+
let mut server_config = quinn::ServerConfig::with_crypto(Arc::new(
103+
QuicServerConfig::try_from(
104+
rustls::ServerConfig::builder_with_provider(Arc::new(rustls_post_quantum::provider()))
105+
.with_safe_default_protocol_versions()
106+
.unwrap()
107+
.with_no_client_auth()
108+
.with_single_cert(vec![server_cert.clone()], priv_key.into())
109+
.unwrap(),
110+
)
111+
.unwrap(),
112+
));
113+
114+
let transport_config = Arc::get_mut(&mut server_config.transport).unwrap();
115+
transport_config.max_concurrent_uni_streams(0_u8.into());
116+
transport_config.min_mtu(min_mtu);
117+
118+
let endpoint = Endpoint::server(server_config, bind_addr)?;
119+
Ok((endpoint, server_cert))
120+
}
121+
122+
/// <https://datatracker.ietf.org/doc/html/draft-tls-westerbaan-xyber768d00-02#name-iana-considerations-23>
123+
const X25519_KYBER768_DRAFT00: NamedGroup = NamedGroup::Unknown(0x06399);

0 commit comments

Comments
 (0)