Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libp2p-tls: Allow to specify remote peer ID we intend to connect to #2947

Merged
merged 1 commit into from
Sep 28, 2022
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
12 changes: 8 additions & 4 deletions transports/tls/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub mod certificate;
pub mod upgrade;
mod verifier;

use libp2p_core::{identity::Keypair, PeerId};
use std::sync::Arc;

use rustls::{
Expand All @@ -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<PeerId>,
) -> Result<rustls::ClientConfig, certificate::GenError> {
let (certificate, private_key) = certificate::generate(keypair)?;

Expand All @@ -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()];
Expand All @@ -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<rustls::ServerConfig, certificate::GenError> {
let (certificate, private_key) = certificate::generate(keypair)?;

Expand All @@ -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()];
Expand Down
2 changes: 1 addition & 1 deletion transports/tls/src/upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl Config {
pub fn new(identity: &identity::Keypair) -> Result<Self, certificate::GenError> {
Ok(Self {
server: crate::make_server_config(identity)?,
client: crate::make_client_config(identity)?,
client: crate::make_client_config(identity, None)?,
})
}
}
Expand Down
35 changes: 30 additions & 5 deletions transports/tls/src/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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<PeerId>,
}

/// libp2p requires the following of X.509 server certificate chains:
///
Expand All @@ -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<PeerId>) -> Self {
Self { remote_peer_id }
}

/// Return the list of SignatureSchemes that this verifier will handle,
/// in `verify_tls12_signature` and `verify_tls13_signature` calls.
///
Expand Down Expand Up @@ -76,7 +89,19 @@ impl ServerCertVerifier for Libp2pCertificateVerifier {
_ocsp_response: &[u8],
_now: std::time::SystemTime,
) -> Result<ServerCertVerified, rustls::Error> {
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())
}
Expand Down Expand Up @@ -171,16 +196,16 @@ impl ClientCertVerifier for Libp2pCertificateVerifier {
fn verify_presented_certs(
end_entity: &Certificate,
intermediates: &[Certificate],
) -> Result<(), rustls::Error> {
) -> Result<PeerId, rustls::Error> {
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(
Expand Down