Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/daily-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ jobs:
- name: Check rustls-post-quantum client
run: cargo run --locked -p rustls-post-quantum --example client | grep 'kex=X25519MLKEM768'

- name: Smoke test for secp256r1mlkem768 interop
run: cargo run --locked -p rustls-examples --bin tlsclient-mio -- --http --key-exchange secp256r1mlkem768 --verbose openquantumsafe.org

feature-powerset:
name: Feature Powerset
Expand Down
28 changes: 27 additions & 1 deletion examples/src/bin/tlsclient-mio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use std::{process, str};
use clap::Parser;
use mio::net::TcpStream;
use rustls::RootCertStore;
use rustls::crypto::{CryptoProvider, aws_lc_rs as provider};
use rustls::crypto::{CryptoProvider, SupportedKxGroup, aws_lc_rs as provider};
use rustls::pki_types::pem::PemObject;
use rustls::pki_types::{CertificateDer, PrivateKeyDer, ServerName};

Expand Down Expand Up @@ -232,6 +232,10 @@ struct Args {
#[clap(long)]
suite: Vec<String>,

/// Disable default key exchange list, and use KX instead. Maybe be used multiple times.
#[clap(long)]
key_exchange: Vec<String>,

/// Send ALPN extension containing PROTOCOL.
/// May be used multiple times to offer several protocols.
#[clap(long)]
Expand Down Expand Up @@ -283,6 +287,19 @@ fn find_suite(name: &str) -> Option<rustls::SupportedCipherSuite> {
None
}

/// Find a key exchange with the given name
fn find_key_exchange(name: &str) -> &'static dyn SupportedKxGroup {
for kx_group in provider::ALL_KX_GROUPS {
let kx_name = format!("{:?}", kx_group.name()).to_lowercase();

if kx_name == name.to_string().to_lowercase() {
return *kx_group;
}
}

panic!("cannot find key exchange with name '{name}'");
}

/// Make a vector of ciphersuites named in `suites`
fn lookup_suites(suites: &[String]) -> Vec<rustls::SupportedCipherSuite> {
let mut out = Vec::new();
Expand Down Expand Up @@ -412,6 +429,14 @@ fn make_config(args: &Args) -> Arc<rustls::ClientConfig> {
provider::DEFAULT_CIPHER_SUITES.to_vec()
};

let kx_groups = match args.key_exchange.as_slice() {
[] => provider::DEFAULT_KX_GROUPS.to_vec(),
items => items
.iter()
.map(|kx| find_key_exchange(kx))
.collect::<Vec<&'static dyn SupportedKxGroup>>(),
};

let versions = if !args.protover.is_empty() {
lookup_versions(&args.protover)
} else {
Expand All @@ -421,6 +446,7 @@ fn make_config(args: &Args) -> Arc<rustls::ClientConfig> {
let config = rustls::ClientConfig::builder_with_provider(
CryptoProvider {
cipher_suites: suites,
kx_groups,
..provider::default_provider()
}
.into(),
Expand Down
6 changes: 5 additions & 1 deletion rustls/src/crypto/aws_lc_rs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ static SUPPORTED_SIG_ALGS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms
/// [`DEFAULT_KX_GROUPS`] is provided as an array of this provider's defaults.
pub mod kx_group {
pub use super::kx::{SECP256R1, SECP384R1, X25519};
pub use super::pq::{MLKEM768, X25519MLKEM768};
pub use super::pq::{MLKEM768, SECP256R1MLKEM768, X25519MLKEM768};
}

/// A list of the default key exchange groups supported by this provider.
Expand All @@ -250,11 +250,15 @@ pub static DEFAULT_KX_GROUPS: &[&dyn SupportedKxGroup] = &[
pub static ALL_KX_GROUPS: &[&dyn SupportedKxGroup] = &[
#[cfg(feature = "prefer-post-quantum")]
kx_group::X25519MLKEM768,
#[cfg(feature = "prefer-post-quantum")]
kx_group::SECP256R1MLKEM768,
kx_group::X25519,
kx_group::SECP256R1,
kx_group::SECP384R1,
#[cfg(not(feature = "prefer-post-quantum"))]
kx_group::X25519MLKEM768,
#[cfg(not(feature = "prefer-post-quantum"))]
kx_group::SECP256R1MLKEM768,
kx_group::MLKEM768,
];

Expand Down
16 changes: 16 additions & 0 deletions rustls/src/crypto/aws_lc_rs/pq/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,21 @@ pub static X25519MLKEM768: &dyn SupportedKxGroup = &hybrid::Hybrid {
},
};

/// This is the [SECP256R1MLKEM768] key exchange.
///
/// [SECP256R1MLKEM768]: <https://datatracker.ietf.org/doc/draft-ietf-tls-ecdhe-mlkem/>
pub static SECP256R1MLKEM768: &dyn SupportedKxGroup = &hybrid::Hybrid {
classical: kx_group::SECP256R1,
post_quantum: MLKEM768,
name: NamedGroup::secp256r1MLKEM768,
layout: hybrid::Layout {
classical_share_len: SECP256R1_LEN,
post_quantum_client_share_len: MLKEM768_ENCAP_LEN,
post_quantum_server_share_len: MLKEM768_CIPHERTEXT_LEN,
post_quantum_first: false,
},
};

/// This is the [MLKEM] key exchange.
///
/// [MLKEM]: https://datatracker.ietf.org/doc/draft-connolly-tls-mlkem-key-agreement
Expand All @@ -28,5 +43,6 @@ pub static MLKEM768: &dyn SupportedKxGroup = &mlkem::MlKem768;
const INVALID_KEY_SHARE: Error = Error::PeerMisbehaved(PeerMisbehaved::InvalidKeyShare);

const X25519_LEN: usize = 32;
const SECP256R1_LEN: usize = 65;
const MLKEM768_CIPHERTEXT_LEN: usize = 1088;
const MLKEM768_ENCAP_LEN: usize = 1184;
20 changes: 20 additions & 0 deletions rustls/tests/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5871,6 +5871,26 @@ fn test_client_config_keyshare_mismatch() {
assert!(do_handshake_until_error(&mut client, &mut server).is_err());
}

#[test]
fn exercise_all_key_exchange_methods() {
for version in rustls::ALL_VERSIONS {
for kx_group in provider::ALL_KX_GROUPS {
if !kx_group.usable_for_version(version.version) {
continue;
}

let provider = provider::default_provider();
let client_config =
make_client_config_with_kx_groups(KeyType::Rsa2048, vec![*kx_group], &provider);
let server_config =
make_server_config_with_kx_groups(KeyType::Rsa2048, vec![*kx_group], &provider);
let (mut client, mut server) = make_pair_for_configs(client_config, server_config);
assert!(do_handshake_until_error(&mut client, &mut server).is_ok());
println!("kx_group {:?} is self-consistent", kx_group.name());
}
}
}

#[cfg(feature = "tls12")]
#[test]
fn test_client_sends_helloretryrequest() {
Expand Down
Loading