diff --git a/transports/quic/CHANGELOG.md b/transports/quic/CHANGELOG.md index 00898299001..1d0472a65a0 100644 --- a/transports/quic/CHANGELOG.md +++ b/transports/quic/CHANGELOG.md @@ -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). diff --git a/transports/quic/src/config.rs b/transports/quic/src/config.rs index 0d514db5751..71fb578391c 100644 --- a/transports/quic/src/config.rs +++ b/transports/quic/src/config.rs @@ -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, + ) -> 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, diff --git a/transports/tls/CHANGELOG.md b/transports/tls/CHANGELOG.md index 94848e243b2..fa91d130ff1 100644 --- a/transports/tls/CHANGELOG.md +++ b/transports/tls/CHANGELOG.md @@ -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). diff --git a/transports/tls/src/lib.rs b/transports/tls/src/lib.rs index 8cf5b06a53f..7c53b2ed7b7 100644 --- a/transports/tls/src/lib.rs +++ b/transports/tls/src/lib.rs @@ -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, +) -> Result { + 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, + custom_provider: Option, ) -> Result { 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) @@ -70,11 +96,21 @@ pub fn make_client_config( /// Create a TLS server configuration for libp2p. pub fn make_server_config( keypair: &Keypair, +) -> Result { + 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, ) -> Result { 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) diff --git a/transports/tls/src/upgrade.rs b/transports/tls/src/upgrade.rs index 2563f636dac..43055ef5560 100644 --- a/transports/tls/src/upgrade.rs +++ b/transports/tls/src/upgrade.rs @@ -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 { + 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 {