diff --git a/client/src/lib.rs b/client/src/lib.rs index 008f77d..e764f55 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -168,7 +168,7 @@ impl MTPClient { */ pub async fn connect(config: ClientConfig) -> Result { let (sender, receiver) = - mtp_transport::connect(&config.url, config.server_cert(), Policy::default()).await?; + mtp_transport::connect(&config.url, config.server_cert(), config.policy).await?; let version_str = format!("{}", PROTOCOL_VERSION); let mut ident = CommunicationValue::new(mtp_codec::CommunicationType::Identification) diff --git a/transport/Cargo.toml b/transport/Cargo.toml index 0af879a..5ff48ac 100644 --- a/transport/Cargo.toml +++ b/transport/Cargo.toml @@ -15,9 +15,9 @@ rustls = { version = "0.23.41" } tokio = { version = "1", features = ["full"] } rustls-native-certs = "0.8.4" log = "0.4" +rcgen = "0.14" [dev-dependencies] -rcgen = "0.14" [[test]] name = "integration" diff --git a/transport/src/client.rs b/transport/src/client.rs index 115b37e..f356ea5 100644 --- a/transport/src/client.rs +++ b/transport/src/client.rs @@ -1,11 +1,65 @@ use std::sync::Arc; use mtp_common::CommunicationError; -use rustls::{ClientConfig as RustlsClientConfig, RootCertStore, pki_types::pem::PemObject}; +use rustls::{ + ClientConfig as RustlsClientConfig, RootCertStore, + client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier}, + pki_types::{ServerName, UnixTime, pem::PemObject}, + DigitallySignedStruct, SignatureScheme, +}; use wtransport::{ClientConfig, Endpoint}; use crate::{ConnectionHandle, Policy, Receiver, Sender}; +#[derive(Debug)] +struct NoopCertVerifier; + +impl ServerCertVerifier for NoopCertVerifier { + fn verify_server_cert( + &self, + _end_entity: &rustls::pki_types::CertificateDer<'_>, + _intermediates: &[rustls::pki_types::CertificateDer<'_>], + _server_name: &ServerName<'_>, + _ocsp_response: &[u8], + _now: UnixTime, + ) -> Result { + Ok(ServerCertVerified::assertion()) + } + + fn verify_tls12_signature( + &self, + _message: &[u8], + _cert: &rustls::pki_types::CertificateDer<'_>, + _dss: &DigitallySignedStruct, + ) -> Result { + Ok(HandshakeSignatureValid::assertion()) + } + + fn verify_tls13_signature( + &self, + _message: &[u8], + _cert: &rustls::pki_types::CertificateDer<'_>, + _dss: &DigitallySignedStruct, + ) -> Result { + Ok(HandshakeSignatureValid::assertion()) + } + + fn supported_verify_schemes(&self) -> Vec { + vec![ + SignatureScheme::RSA_PKCS1_SHA1, + SignatureScheme::RSA_PKCS1_SHA256, + SignatureScheme::RSA_PKCS1_SHA384, + SignatureScheme::RSA_PKCS1_SHA512, + SignatureScheme::ECDSA_NISTP256_SHA256, + SignatureScheme::ECDSA_NISTP384_SHA384, + SignatureScheme::RSA_PSS_SHA256, + SignatureScheme::RSA_PSS_SHA384, + SignatureScheme::RSA_PSS_SHA512, + SignatureScheme::ED25519, + ] + } +} + pub async fn connect( url: &str, server_cert: Option>, @@ -55,7 +109,30 @@ fn configure_client_with_cert( client_config_from_roots(root_store, policy) } +fn client_config_insecure(policy: &Policy) -> Result { + let mut tls_config = RustlsClientConfig::builder() + .dangerous() + .with_custom_certificate_verifier(Arc::new(NoopCertVerifier)) + .with_no_client_auth(); + + tls_config.alpn_protocols = vec![b"h3".to_vec()]; + + Ok(ClientConfig::builder() + .with_bind_default() + .with_custom_tls(tls_config) + .keep_alive_interval(policy.keep_alive_interval) + .max_idle_timeout(policy.max_idle_timeout) + .map_err(|e| CommunicationError::Other(e.to_string()))? + .build()) +} + fn configure_client_system_roots(policy: &Policy) -> Result { + // Check if insecure mode is enabled via env variable MTP_INSECURE + let insecure = std::env::var("MTP_INSECURE").is_ok(); + if insecure { + // Insecure mode: skip certificate verification entirely + return client_config_insecure(policy); + } let mut root_store = RootCertStore::empty(); // Load native certs diff --git a/transport/src/host.rs b/transport/src/host.rs index 0927aa0..2198770 100644 --- a/transport/src/host.rs +++ b/transport/src/host.rs @@ -5,6 +5,16 @@ use std::net::{IpAddr, SocketAddr}; use std::sync::Arc; use wtransport::{Connection as WTConnection, Endpoint, ServerConfig}; +fn generate_self_signed_cert() -> (Vec, Vec) { + let key_pair = rcgen::KeyPair::generate().unwrap(); + let params = + rcgen::CertificateParams::new(vec!["localhost".into(), "127.0.0.1".into()]).unwrap(); + let cert = params.self_signed(&key_pair).unwrap(); + let cert_pem = cert.pem(); + let key_pem = key_pair.serialize_pem(); + (cert_pem.into_bytes(), key_pem.into_bytes()) +} + pub struct Host { incoming: tokio::sync::mpsc::Receiver<(Sender, Receiver)>, local_addr: std::net::SocketAddr, @@ -46,7 +56,16 @@ pub async fn host( ) -> Result { let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); - let server_config = configure_server(ip, port, cert_pem, key_pem, &policy).await?; + // When MTP_INSECURE is set, generate a self-signed cert so the host can + // run without externally-provided TLS credentials. + let is_insecure = std::env::var("MTP_INSECURE").is_ok(); + let (use_cert_pem, use_key_pem) = if is_insecure { + generate_self_signed_cert() + } else { + (cert_pem, key_pem) + }; + + let server_config = configure_server(ip, port, use_cert_pem, use_key_pem, &policy).await?; let endpoint = Endpoint::server(server_config) .map_err(|e| CommunicationError::Other(format!("Endpoint creation failed: {}", e)))?;