From 3b1ff348999da1543b7c394f4db9f7364e061508 Mon Sep 17 00:00:00 2001 From: Roman Proskuryakov Date: Thu, 11 Nov 2021 21:26:24 +0300 Subject: [PATCH] Don't require remote PK to dial a peer --- transports/quic/src/crypto.rs | 7 +- transports/quic/src/endpoint.rs | 23 +----- transports/quic/src/tls/mod.rs | 6 +- transports/quic/src/tls/verifier.rs | 23 ++---- transports/quic/src/transport.rs | 114 +++++++++++----------------- transports/quic/tests/smoke.rs | 28 ++----- 6 files changed, 67 insertions(+), 134 deletions(-) diff --git a/transports/quic/src/crypto.rs b/transports/quic/src/crypto.rs index ad9fdbe2c16..145990c7973 100644 --- a/transports/quic/src/crypto.rs +++ b/transports/quic/src/crypto.rs @@ -18,7 +18,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -use libp2p_core::identity::{Keypair, PublicKey}; +use libp2p_core::identity::Keypair; use quinn_proto::crypto::Session; use quinn_proto::TransportConfig; use std::sync::Arc; @@ -45,11 +45,8 @@ impl TlsCrypto { pub fn new_client_config( config: &CryptoConfig, - remote_public: PublicKey, ) -> ::ClientConfig { - let mut client = - crate::tls::make_client_config(&config.keypair, remote_public.to_peer_id()) - .expect("invalid config"); + let mut client = crate::tls::make_client_config(&config.keypair).expect("invalid config"); if let Some(key_log) = config.keylogger.clone() { client.key_log = key_log; } diff --git a/transports/quic/src/endpoint.rs b/transports/quic/src/endpoint.rs index 2ec239e518a..728bb11948e 100644 --- a/transports/quic/src/endpoint.rs +++ b/transports/quic/src/endpoint.rs @@ -23,7 +23,6 @@ use crate::muxer::QuicMuxer; use crate::{QuicConfig, QuicError}; use futures::channel::{mpsc, oneshot}; use futures::prelude::*; -use libp2p_core::identity::PublicKey; use quinn_proto::generic::ClientConfig as QuinnClientConfig; use quinn_proto::ServerConfig as QuinnServerConfig; use quinn_proto::{ @@ -46,8 +45,6 @@ enum ToEndpoint { Dial { /// UDP address to connect to. addr: SocketAddr, - /// The remotes public key. - public_key: PublicKey, /// Channel to return the result of the dialing to. tx: oneshot::Sender>, }, @@ -70,17 +67,9 @@ pub struct TransportChannel { } impl TransportChannel { - pub fn dial( - &mut self, - addr: SocketAddr, - public_key: PublicKey, - ) -> oneshot::Receiver> { + pub fn dial(&mut self, addr: SocketAddr) -> oneshot::Receiver> { let (tx, rx) = oneshot::channel(); - let msg = ToEndpoint::Dial { - addr, - public_key, - tx, - }; + let msg = ToEndpoint::Dial { addr, tx }; self.tx.unbounded_send(msg).expect("endpoint has crashed"); rx } @@ -351,12 +340,8 @@ impl Future for Endpoint { if me.event_slot.is_none() { while let Poll::Ready(event) = me.channel.poll_next_event(cx) { match event { - Some(ToEndpoint::Dial { - addr, - public_key, - tx, - }) => { - let crypto = TlsCrypto::new_client_config(&me.crypto_config, public_key); + Some(ToEndpoint::Dial { addr, tx }) => { + let crypto = TlsCrypto::new_client_config(&me.crypto_config); let client_config = QuinnClientConfig { transport: me.crypto_config.transport.clone(), crypto, diff --git a/transports/quic/src/tls/mod.rs b/transports/quic/src/tls/mod.rs index 1cf8f3571b6..9241c527b9f 100644 --- a/transports/quic/src/tls/mod.rs +++ b/transports/quic/src/tls/mod.rs @@ -23,7 +23,6 @@ mod certificate; mod verifier; -use libp2p_core::PeerId; use std::sync::Arc; use thiserror::Error; @@ -50,13 +49,12 @@ pub enum ConfigError { pub fn make_client_config( keypair: &libp2p_core::identity::Keypair, - remote_peer_id: PeerId, ) -> Result { let cert = certificate::make_cert(keypair)?; let private_key = cert.serialize_private_key_der(); let cert = rustls::Certificate(cert.serialize_der()?); let key = rustls::PrivateKey(private_key); - let verifier = verifier::Libp2pServerCertificateVerifier(remote_peer_id); + let verifier = verifier::Libp2pCertificateVerifier; let mut crypto = rustls::ClientConfig::new(); crypto.versions = vec![rustls::ProtocolVersion::TLSv1_3]; @@ -76,7 +74,7 @@ pub fn make_server_config( let private_key = cert.serialize_private_key_der(); let cert = rustls::Certificate(cert.serialize_der()?); let key = rustls::PrivateKey(private_key); - let verifier = verifier::Libp2pClientCertificateVerifier; + let verifier = verifier::Libp2pCertificateVerifier; let mut crypto = rustls::ServerConfig::new(Arc::new(verifier)); crypto.versions = vec![rustls::ProtocolVersion::TLSv1_3]; diff --git a/transports/quic/src/tls/verifier.rs b/transports/quic/src/tls/verifier.rs index 3427aa4275a..793d8a91455 100644 --- a/transports/quic/src/tls/verifier.rs +++ b/transports/quic/src/tls/verifier.rs @@ -31,7 +31,7 @@ use webpki::Error; /// 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(crate) struct Libp2pServerCertificateVerifier(pub(crate) PeerId); +pub(crate) struct Libp2pCertificateVerifier; /// libp2p requires the following of X.509 server certificate chains: /// @@ -39,7 +39,7 @@ pub(crate) struct Libp2pServerCertificateVerifier(pub(crate) PeerId); /// - The certificate must be self-signed. /// - The certificate must have a valid libp2p extension that includes a /// signature of its public key. -impl rustls::ServerCertVerifier for Libp2pServerCertificateVerifier { +impl rustls::ServerCertVerifier for Libp2pCertificateVerifier { fn verify_server_cert( &self, _roots: &rustls::RootCertStore, @@ -47,13 +47,7 @@ impl rustls::ServerCertVerifier for Libp2pServerCertificateVerifier { _dns_name: webpki::DNSNameRef<'_>, _ocsp_response: &[u8], ) -> Result { - let peer_id = verify_presented_certs(presented_certs)?; - if peer_id != self.0 { - return Err(TLSError::PeerIncompatibleError( - "Unexpected peer id".to_string(), - )); - } - Ok(ServerCertVerified::assertion()) + verify_presented_certs(presented_certs).map(|_| ServerCertVerified::assertion()) } fn verify_tls12_signature( @@ -77,11 +71,6 @@ impl rustls::ServerCertVerifier for Libp2pServerCertificateVerifier { } } -/// 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(crate) struct Libp2pClientCertificateVerifier; - /// libp2p requires the following of X.509 client certificate chains: /// /// - Exactly one certificate must be presented. In particular, client @@ -89,7 +78,7 @@ pub(crate) struct Libp2pClientCertificateVerifier; /// - The certificate must be self-signed. /// - The certificate must have a valid libp2p extension that includes a /// signature of its public key. -impl rustls::ClientCertVerifier for Libp2pClientCertificateVerifier { +impl rustls::ClientCertVerifier for Libp2pCertificateVerifier { fn offer_client_auth(&self) -> bool { true } @@ -186,7 +175,7 @@ fn parse_certificate( Ok((parsed, libp2p_extension)) } -fn verify_presented_certs(presented_certs: &[Certificate]) -> Result { +fn verify_presented_certs(presented_certs: &[Certificate]) -> Result<(), TLSError> { if presented_certs.len() != 1 { return Err(TLSError::NoCertificatesPresented); } @@ -198,7 +187,7 @@ fn verify_presented_certs(presented_certs: &[Certificate]) -> Result { diff --git a/transports/quic/src/transport.rs b/transports/quic/src/transport.rs index d1ec1fd0b28..c3ffd428c64 100644 --- a/transports/quic/src/transport.rs +++ b/transports/quic/src/transport.rs @@ -24,7 +24,6 @@ use crate::{QuicConfig, QuicError}; use futures::channel::oneshot; use futures::prelude::*; use if_watch::{IfEvent, IfWatcher}; -use libp2p_core::identity::PublicKey; use libp2p_core::multiaddr::{Multiaddr, Protocol}; use libp2p_core::muxing::{StreamMuxer, StreamMuxerBox}; use libp2p_core::transport::{Boxed, ListenerEvent, Transport, TransportError}; @@ -48,8 +47,7 @@ impl QuicTransport { addr: Multiaddr, ) -> Result> { let socket_addr = multiaddr_to_socketaddr(&addr) - .map_err(|_| TransportError::MultiaddrNotSupported(addr.clone()))? - .0; + .ok_or_else(|| TransportError::MultiaddrNotSupported(addr.clone()))?; let addresses = if socket_addr.ip().is_unspecified() { let watcher = IfWatcher::new() .await @@ -100,24 +98,22 @@ impl Transport for QuicTransport { type Dial = QuicDial; fn listen_on(self, addr: Multiaddr) -> Result> { - multiaddr_to_socketaddr(&addr).map_err(|_| TransportError::MultiaddrNotSupported(addr))?; + multiaddr_to_socketaddr(&addr) + .ok_or_else(|| TransportError::MultiaddrNotSupported(addr))?; Ok(self) } fn dial(self, addr: Multiaddr) -> Result> { - let (socket_addr, public_key) = - if let Ok((socket_addr, Some(public_key))) = multiaddr_to_socketaddr(&addr) { - (socket_addr, public_key) - } else { - tracing::debug!("invalid multiaddr"); - return Err(TransportError::MultiaddrNotSupported(addr.clone())); - }; + let socket_addr = multiaddr_to_socketaddr(&addr).ok_or_else(|| { + tracing::debug!("invalid multiaddr"); + TransportError::MultiaddrNotSupported(addr.clone()) + })?; if socket_addr.port() == 0 || socket_addr.ip().is_unspecified() { tracing::debug!("invalid multiaddr"); return Err(TransportError::MultiaddrNotSupported(addr)); } tracing::debug!("dialing {}", socket_addr); - let rx = self.inner.lock().channel.dial(socket_addr, public_key); + let rx = self.inner.lock().channel.dial(socket_addr); Ok(QuicDial::Dialing(rx)) } @@ -240,38 +236,29 @@ impl Future for QuicUpgrade { } } -/// Tries to turn a QUIC multiaddress into a UDP [`SocketAddr`]. Returns an error if the format +/// Tries to turn a QUIC multiaddress into a UDP [`SocketAddr`]. Returns None if the format /// of the multiaddr is wrong. -fn multiaddr_to_socketaddr(addr: &Multiaddr) -> Result<(SocketAddr, Option), ()> { - let mut iter = addr.iter().peekable(); - let proto1 = iter.next().ok_or(())?; - let proto2 = iter.next().ok_or(())?; - let proto3 = iter.next().ok_or(())?; +fn multiaddr_to_socketaddr(addr: &Multiaddr) -> Option { + let mut iter = addr.iter(); + let proto1 = iter.next()?; + let proto2 = iter.next()?; + let proto3 = iter.next()?; - let peer_id = if let Some(Protocol::P2p(peer_id)) = iter.peek() { - if peer_id.code() != multihash::Code::Identity.into() { - return Err(()); + while let Some(proto) = iter.next() { + match proto { + Protocol::P2p(_) => {} // Ignore a `/p2p/...` prefix of possibly outer protocols, if present. + _ => return None, } - let public_key = - libp2p_core::PublicKey::from_protobuf_encoding(peer_id.digest()).map_err(|_| ())?; - iter.next(); - Some(public_key) - } else { - None - }; - - if iter.next().is_some() { - return Err(()); } match (proto1, proto2, proto3) { (Protocol::Ip4(ip), Protocol::Udp(port), Protocol::Quic) => { - Ok((SocketAddr::new(ip.into(), port), peer_id)) + Some(SocketAddr::new(ip.into(), port)) } (Protocol::Ip6(ip), Protocol::Udp(port), Protocol::Quic) => { - Ok((SocketAddr::new(ip.into(), port), peer_id)) + Some(SocketAddr::new(ip.into(), port)) } - _ => Err(()), + _ => None, } } @@ -288,12 +275,12 @@ mod tests { use super::*; #[test] - fn multiaddr_to_udp_conversion() { + fn multiaddr_to_socketaddr_conversion() { use std::net::{Ipv4Addr, Ipv6Addr}; assert!( multiaddr_to_socketaddr(&"/ip4/127.0.0.1/udp/1234".parse::().unwrap()) - .is_err() + .is_none() ); assert_eq!( @@ -302,27 +289,35 @@ mod tests { .parse::() .unwrap() ), - Ok(( - SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 12345,), - None + Some(SocketAddr::new( + IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), + 12345, )) ); + + assert!(multiaddr_to_socketaddr( + &"/ip4/127.0.0.1/udp/12345/quic/tcp/12345" + .parse::() + .unwrap() + ) + .is_none()); + assert_eq!( multiaddr_to_socketaddr( &"/ip4/255.255.255.255/udp/8080/quic" .parse::() .unwrap() ), - Ok(( - SocketAddr::new(IpAddr::V4(Ipv4Addr::new(255, 255, 255, 255)), 8080,), - None + Some(SocketAddr::new( + IpAddr::V4(Ipv4Addr::new(255, 255, 255, 255)), + 8080, )) ); assert_eq!( multiaddr_to_socketaddr(&"/ip6/::1/udp/12345/quic".parse::().unwrap()), - Ok(( - SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), 12345,), - None + Some(SocketAddr::new( + IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), + 12345, )) ); assert_eq!( @@ -331,30 +326,11 @@ mod tests { .parse::() .unwrap() ), - Ok(( - SocketAddr::new( - IpAddr::V6(Ipv6Addr::new( - 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - )), - 8080, - ), - None - )) - ); - } - - #[test] - fn multiaddr_to_pk_conversion() { - use std::net::Ipv4Addr; - - let keypair = libp2p_core::identity::Keypair::generate_ed25519(); - let peer_id = keypair.public().to_peer_id(); - let addr = String::from("/ip4/127.0.0.1/udp/12345/quic/p2p/") + &peer_id.to_base58(); - assert_eq!( - multiaddr_to_socketaddr(&addr.parse::().unwrap()), - Ok(( - SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 12345,), - Some(keypair.public()) + Some(SocketAddr::new( + IpAddr::V6(Ipv6Addr::new( + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + )), + 8080, )) ); } diff --git a/transports/quic/tests/smoke.rs b/transports/quic/tests/smoke.rs index 7336b66b7d1..4135a08bbf6 100644 --- a/transports/quic/tests/smoke.rs +++ b/transports/quic/tests/smoke.rs @@ -4,7 +4,6 @@ use futures::future::FutureExt; use futures::io::{AsyncRead, AsyncWrite, AsyncWriteExt}; use futures::stream::StreamExt; use libp2p::core::upgrade; -use libp2p::multiaddr::Protocol; use libp2p::request_response::{ ProtocolName, ProtocolSupport, RequestResponse, RequestResponseCodec, RequestResponseConfig, RequestResponseEvent, RequestResponseMessage, @@ -51,11 +50,10 @@ async fn smoke() -> Result<()> { Swarm::listen_on(&mut a, "/ip4/127.0.0.1/udp/0/quic".parse()?)?; - let mut addr = match a.next().await { + let addr = match a.next().await { Some(SwarmEvent::NewListenAddr { address, .. }) => address, e => panic!("{:?}", e), }; - addr.push(Protocol::P2p((*a.local_peer_id()).into())); let mut data = vec![0; 4096 * 10]; rng.fill_bytes(&mut data); @@ -252,34 +250,27 @@ async fn dial_failure() -> Result<()> { .ok(); log_panics::init(); - let mut a = create_swarm(true).await?; - let mut b = create_swarm(false).await?; + let mut a = create_swarm(false).await?; + let mut b = create_swarm(true).await?; Swarm::listen_on(&mut a, "/ip4/127.0.0.1/udp/0/quic".parse()?)?; - let keypair = generate_tls_keypair(); - let fake_peer_id = keypair.public().to_peer_id(); - - let mut addr = match a.next().await { + let addr = match a.next().await { Some(SwarmEvent::NewListenAddr { address, .. }) => address, e => panic!("{:?}", e), }; - addr.push(Protocol::P2p(fake_peer_id.into())); + let a_peer_id = &Swarm::local_peer_id(&a).clone(); + drop(a); // stop a swarm so b can never reach it - b.behaviour_mut().add_address(&fake_peer_id, addr); + b.behaviour_mut().add_address(a_peer_id, addr); b.behaviour_mut() - .send_request(&fake_peer_id, Ping(b"hello world".to_vec())); + .send_request(a_peer_id, Ping(b"hello world".to_vec())); match b.next().await { Some(SwarmEvent::Dialing(_)) => {} e => panic!("{:?}", e), } - match a.next().await { - Some(SwarmEvent::IncomingConnection { .. }) => {} - e => panic!("{:?}", e), - } - match b.next().await { Some(SwarmEvent::OutgoingConnectionError { .. }) => {} e => panic!("{:?}", e), @@ -290,8 +281,5 @@ async fn dial_failure() -> Result<()> { e => panic!("{:?}", e), }; - assert!(a.next().await.is_some()); // ConnectionClosed - assert!(a.next().now_or_never().is_none()); - Ok(()) }