From 4b468274831d02f28368ad107ed514226e4f1b19 Mon Sep 17 00:00:00 2001 From: Roman Proskuryakov Date: Tue, 27 Sep 2022 13:57:37 +0300 Subject: [PATCH] Allow to specify remote peer ID we intend to connect to --- transports/tls/src/lib.rs | 12 ++++++++---- transports/tls/src/upgrade.rs | 2 +- transports/tls/src/verifier.rs | 35 +++++++++++++++++++++++++++++----- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/transports/tls/src/lib.rs b/transports/tls/src/lib.rs index 59ddc069e97..2fceea2762f 100644 --- a/transports/tls/src/lib.rs +++ b/transports/tls/src/lib.rs @@ -26,6 +26,7 @@ pub mod certificate; pub mod upgrade; mod verifier; +use libp2p_core::{identity::Keypair, PeerId}; use std::sync::Arc; use rustls::{ @@ -51,7 +52,8 @@ const P2P_ALPN: [u8; 6] = *b"libp2p"; /// Create a TLS client configuration for libp2p. pub fn make_client_config( - keypair: &libp2p_core::identity::Keypair, + keypair: &Keypair, + remote_peer_id: Option, ) -> Result { let (certificate, private_key) = certificate::generate(keypair)?; @@ -60,7 +62,9 @@ pub fn make_client_config( .with_safe_default_kx_groups() .with_protocol_versions(&[&rustls::version::TLS13]) .expect("Cipher suites and kx groups are configured; qed") - .with_custom_certificate_verifier(Arc::new(verifier::Libp2pCertificateVerifier)) + .with_custom_certificate_verifier(Arc::new( + verifier::Libp2pCertificateVerifier::with_remote_peer_id(remote_peer_id), + )) .with_single_cert(vec![certificate], private_key) .expect("Client cert key DER is valid; qed"); crypto.alpn_protocols = vec![P2P_ALPN.to_vec()]; @@ -70,7 +74,7 @@ pub fn make_client_config( /// Create a TLS server configuration for libp2p. pub fn make_server_config( - keypair: &libp2p_core::identity::Keypair, + keypair: &Keypair, ) -> Result { let (certificate, private_key) = certificate::generate(keypair)?; @@ -79,7 +83,7 @@ pub fn make_server_config( .with_safe_default_kx_groups() .with_protocol_versions(&[&rustls::version::TLS13]) .expect("Cipher suites and kx groups are configured; qed") - .with_client_cert_verifier(Arc::new(verifier::Libp2pCertificateVerifier)) + .with_client_cert_verifier(Arc::new(verifier::Libp2pCertificateVerifier::new())) .with_single_cert(vec![certificate], private_key) .expect("Server cert key DER is valid; qed"); crypto.alpn_protocols = vec![P2P_ALPN.to_vec()]; diff --git a/transports/tls/src/upgrade.rs b/transports/tls/src/upgrade.rs index a7ed538d3f2..6f7dd10dc47 100644 --- a/transports/tls/src/upgrade.rs +++ b/transports/tls/src/upgrade.rs @@ -31,7 +31,7 @@ impl Config { pub fn new(identity: &identity::Keypair) -> Result { Ok(Self { server: crate::make_server_config(identity)?, - client: crate::make_client_config(identity)?, + client: crate::make_client_config(identity, None)?, }) } } diff --git a/transports/tls/src/verifier.rs b/transports/tls/src/verifier.rs index 9af02e95298..2815b92c9a3 100644 --- a/transports/tls/src/verifier.rs +++ b/transports/tls/src/verifier.rs @@ -24,6 +24,7 @@ //! and signatures allegedly by the given certificates. use crate::certificate; +use libp2p_core::PeerId; use rustls::{ client::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier}, internal::msgs::handshake::DigitallySignedStruct, @@ -34,7 +35,10 @@ use rustls::{ /// Implementation of the `rustls` certificate verification traits for libp2p. /// /// Only TLS 1.3 is supported. TLS 1.2 should be disabled in the configuration of `rustls`. -pub struct Libp2pCertificateVerifier; +pub struct Libp2pCertificateVerifier { + /// The peer ID we intend to connect to + remote_peer_id: Option, +} /// libp2p requires the following of X.509 server certificate chains: /// @@ -43,6 +47,15 @@ pub struct Libp2pCertificateVerifier; /// - The certificate must have a valid libp2p extension that includes a /// signature of its public key. impl Libp2pCertificateVerifier { + pub fn new() -> Self { + Self { + remote_peer_id: None, + } + } + pub fn with_remote_peer_id(remote_peer_id: Option) -> Self { + Self { remote_peer_id } + } + /// Return the list of SignatureSchemes that this verifier will handle, /// in `verify_tls12_signature` and `verify_tls13_signature` calls. /// @@ -76,7 +89,19 @@ impl ServerCertVerifier for Libp2pCertificateVerifier { _ocsp_response: &[u8], _now: std::time::SystemTime, ) -> Result { - verify_presented_certs(end_entity, intermediates)?; + let peer_id = verify_presented_certs(end_entity, intermediates)?; + + if let Some(remote_peer_id) = self.remote_peer_id { + // The public host key allows the peer to calculate the peer ID of the peer + // it is connecting to. Clients MUST verify that the peer ID derived from + // the certificate matches the peer ID they intended to connect to, + // and MUST abort the connection if there is a mismatch. + if remote_peer_id != peer_id { + return Err(rustls::Error::PeerMisbehavedError( + "Wrong peer ID in p2p extension".to_string(), + )); + } + } Ok(ServerCertVerified::assertion()) } @@ -171,16 +196,16 @@ impl ClientCertVerifier for Libp2pCertificateVerifier { fn verify_presented_certs( end_entity: &Certificate, intermediates: &[Certificate], -) -> Result<(), rustls::Error> { +) -> Result { if !intermediates.is_empty() { return Err(rustls::Error::General( "libp2p-tls requires exactly one certificate".into(), )); } - certificate::parse(end_entity)?; + let cert = certificate::parse(end_entity)?; - Ok(()) + Ok(cert.peer_id()) } fn verify_tls13_signature(