Skip to content
Open
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
6 changes: 6 additions & 0 deletions transports/quic/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
## 0.14.0

- Add `Config::new_with_provider(keypair, provider)` accepting a custom
`rustls::crypto::CryptoProvider` that is threaded into both the
client- and server-side TLS configs underneath QUIC. Pairs with the
matching libp2p-tls addition. Lets consumers enable the X25519MLKEM768
hybrid PQ key-exchange group via `rustls-post-quantum`. Closes
[issue 6236](https://github.com/libp2p/rust-libp2p/issues/6236).
- Raise MSRV to 1.88.0.
See [PR 6273](https://github.com/libp2p/rust-libp2p/pull/6273).

Expand Down
38 changes: 36 additions & 2 deletions transports/quic/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,46 @@ pub struct Config {
impl Config {
/// Creates a new configuration object with default values.
pub fn new(keypair: &libp2p_identity::Keypair) -> Self {
Self::new_inner(keypair, None)
}

/// Build a libp2p-quic config with a custom rustls
/// [`CryptoProvider`](rustls::crypto::CryptoProvider) used for both the
/// client- and server-side TLS configs underneath QUIC.
///
/// Pass e.g. `rustls_post_quantum::provider().clone()` to enable the
/// X25519MLKEM768 hybrid post-quantum key-exchange group on the QUIC
/// handshake. When you don't need to override the default, keep using
/// [`Config::new`] — semantically identical.
pub fn new_with_provider(
keypair: &libp2p_identity::Keypair,
provider: rustls::crypto::CryptoProvider,
) -> Self {
Self::new_inner(keypair, Some(provider))
}

/// Internal helper shared by [`Self::new`] and [`Self::new_with_provider`]
/// so the two public constructors stay one-liners.
fn new_inner(
keypair: &libp2p_identity::Keypair,
custom_provider: Option<rustls::crypto::CryptoProvider>,
) -> Self {
let client_tls_config = Arc::new(
QuicClientConfig::try_from(libp2p_tls::make_client_config(keypair, None).unwrap())
QuicClientConfig::try_from(
libp2p_tls::make_client_config_with_provider(
keypair,
None,
custom_provider.clone(),
)
.unwrap(),
)
.unwrap(),
);
let server_tls_config = Arc::new(
QuicServerConfig::try_from(libp2p_tls::make_server_config(keypair).unwrap()).unwrap(),
QuicServerConfig::try_from(
libp2p_tls::make_server_config_with_provider(keypair, custom_provider).unwrap(),
)
.unwrap(),
);
Self {
client_tls_config,
Expand Down
8 changes: 8 additions & 0 deletions transports/tls/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
## 0.7.0

- Add `make_client_config_with_provider` / `make_server_config_with_provider`
free functions and `Config::new_with_provider` constructor that accept
an optional `rustls::crypto::CryptoProvider`. Lets consumers plug in
alternative providers — notably `rustls-post-quantum` for the
X25519MLKEM768 hybrid PQ key-exchange group (IANA codepoint `0x11EC`,
draft-ietf-tls-ecdhe-mlkem). Behaviour-preserving: existing
`make_*_config` and `Config::new` delegate to the new variants with
`None`. Closes [issue 6236](https://github.com/libp2p/rust-libp2p/issues/6236).
- Raise MSRV to 1.88.0.
See [PR 6273](https://github.com/libp2p/rust-libp2p/pull/6273).

Expand Down
44 changes: 40 additions & 4 deletions transports/tls/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,41 @@ pub use upgrade::{Config, UpgradeError};

const P2P_ALPN: [u8; 6] = *b"libp2p";

/// Build a `CryptoProvider` from `ring` with libp2p-tls's required cipher suites.
///
/// Used as the default-provider fallback by both the unmodified API
/// (`make_client_config`, `make_server_config`) and the new `_with_provider`
/// variants when the caller passes `None`.
fn default_libp2p_provider() -> rustls::crypto::CryptoProvider {
let mut provider = rustls::crypto::ring::default_provider();
provider.cipher_suites = verifier::CIPHERSUITES.to_vec();
provider
}

/// Create a TLS client configuration for libp2p.
pub fn make_client_config(
keypair: &Keypair,
remote_peer_id: Option<PeerId>,
) -> Result<rustls::ClientConfig, certificate::GenError> {
make_client_config_with_provider(keypair, remote_peer_id, None)
}

/// Create a TLS client configuration for libp2p with an optional custom
/// `rustls::crypto::CryptoProvider`.
///
/// Pass `Some(provider)` to enable a non-default provider (for example,
/// `rustls_post_quantum::provider().clone()` to add the X25519MLKEM768
/// hybrid post-quantum kx group). When `None`, the default `ring`-based
/// provider with libp2p's cipher-suite list is used — semantically
/// identical to `make_client_config`.
pub fn make_client_config_with_provider(
keypair: &Keypair,
remote_peer_id: Option<PeerId>,
custom_provider: Option<rustls::crypto::CryptoProvider>,
) -> Result<rustls::ClientConfig, certificate::GenError> {
let (certificate, private_key) = certificate::generate(keypair)?;

let mut provider = rustls::crypto::ring::default_provider();
provider.cipher_suites = verifier::CIPHERSUITES.to_vec();
let provider = custom_provider.unwrap_or_else(default_libp2p_provider);

let cert_resolver = Arc::new(
AlwaysResolvesCert::new(certificate, &private_key)
Expand All @@ -70,11 +96,21 @@ pub fn make_client_config(
/// Create a TLS server configuration for libp2p.
pub fn make_server_config(
keypair: &Keypair,
) -> Result<rustls::ServerConfig, certificate::GenError> {
make_server_config_with_provider(keypair, None)
}

/// Create a TLS server configuration for libp2p with an optional custom
/// `rustls::crypto::CryptoProvider`.
///
/// See [`make_client_config_with_provider`] for the rationale.
pub fn make_server_config_with_provider(
keypair: &Keypair,
custom_provider: Option<rustls::crypto::CryptoProvider>,
) -> Result<rustls::ServerConfig, certificate::GenError> {
let (certificate, private_key) = certificate::generate(keypair)?;

let mut provider = rustls::crypto::ring::default_provider();
provider.cipher_suites = verifier::CIPHERSUITES.to_vec();
let provider = custom_provider.unwrap_or_else(default_libp2p_provider);

let cert_resolver = Arc::new(
AlwaysResolvesCert::new(certificate, &private_key)
Expand Down
23 changes: 23 additions & 0 deletions transports/tls/src/upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,29 @@ impl Config {
client: crate::make_client_config(identity, None)?,
})
}

/// Build a libp2p TLS upgrade config with a custom rustls
/// [`CryptoProvider`](rustls::crypto::CryptoProvider) injected on both
/// the server and client sides.
///
/// Pass e.g. `rustls_post_quantum::provider().clone()` to enable the
/// X25519MLKEM768 hybrid post-quantum key-exchange group on the
/// libp2p TLS handshake. When you don't need to override the default,
/// keep using [`Config::new`] — semantically identical.
///
/// The same provider is used for both server- and client-side configs
/// because the libp2p TLS upgrade negotiates symmetrically (every node
/// is both a TLS server and a TLS client). Cloning a `CryptoProvider`
/// is cheap.
pub fn new_with_provider(
identity: &identity::Keypair,
provider: rustls::crypto::CryptoProvider,
) -> Result<Self, certificate::GenError> {
Ok(Self {
server: crate::make_server_config_with_provider(identity, Some(provider.clone()))?,
client: crate::make_client_config_with_provider(identity, None, Some(provider))?,
})
}
}

impl UpgradeInfo for Config {
Expand Down