//! This example demonstrates how to make a QUIC connection that ignores the server certificate. //! //! Checkout the `README.md` for guidance. use std::{ error::Error, net::{IpAddr, Ipv4Addr, SocketAddr}, sync::Arc, }; use proto::crypto::rustls::QuicClientConfig; use quinn::{ClientConfig, Endpoint}; use rustls::pki_types::{CertificateDer, ServerName, UnixTime}; mod common; use common::make_server_endpoint; #[tokio::main] async fn main() -> Result<(), Box> { // server and client are running on the same thread asynchronously let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080); tokio::spawn(run_server(addr)); run_client(addr).await?; Ok(()) } /// Runs a QUIC server bound to given address. async fn run_server(addr: SocketAddr) { let (endpoint, _server_cert) = make_server_endpoint(addr).unwrap(); // accept a single connection let incoming_conn = endpoint.accept().await.unwrap(); let conn = incoming_conn.await.unwrap(); println!( "[server] connection accepted: addr={}", conn.remote_address() ); } async fn run_client(server_addr: SocketAddr) -> Result<(), Box> { let mut endpoint = Endpoint::client(SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 0))?; endpoint.set_default_client_config(ClientConfig::new(Arc::new(QuicClientConfig::try_from( rustls::ClientConfig::builder() .dangerous() .with_custom_certificate_verifier(SkipServerVerification::new()) .with_no_client_auth(), )?))); // connect to server let connection = endpoint .connect(server_addr, "localhost") .unwrap() .await .unwrap(); println!("[client] connected: addr={}", connection.remote_address()); // Dropping handles allows the corresponding objects to automatically shut down drop(connection); // Make sure the server has a chance to clean up endpoint.wait_idle().await; Ok(()) } /// Dummy certificate verifier that treats any certificate as valid. /// NOTE, such verification is vulnerable to MITM attacks, but convenient for testing. #[derive(Debug)] struct SkipServerVerification(Arc); impl SkipServerVerification { fn new() -> Arc { Arc::new(Self(Arc::new(rustls::crypto::ring::default_provider()))) } } impl rustls::client::danger::ServerCertVerifier for SkipServerVerification { fn verify_server_cert( &self, _end_entity: &CertificateDer<'_>, _intermediates: &[CertificateDer<'_>], _server_name: &ServerName<'_>, _ocsp: &[u8], _now: UnixTime, ) -> Result { Ok(rustls::client::danger::ServerCertVerified::assertion()) } fn verify_tls12_signature( &self, message: &[u8], cert: &CertificateDer<'_>, dss: &rustls::DigitallySignedStruct, ) -> Result { rustls::crypto::verify_tls12_signature( message, cert, dss, &self.0.signature_verification_algorithms, ) } fn verify_tls13_signature( &self, message: &[u8], cert: &CertificateDer<'_>, dss: &rustls::DigitallySignedStruct, ) -> Result { rustls::crypto::verify_tls13_signature( message, cert, dss, &self.0.signature_verification_algorithms, ) } fn supported_verify_schemes(&self) -> Vec { self.0.signature_verification_algorithms.supported_schemes() } }