//! Implementation for using `native_tls` use crate::traits::{CertifiedConn, TlsConnector, TlsProvider}; use async_trait::async_trait; use futures::{AsyncRead, AsyncWrite}; use native_tls_crate as native_tls; use std::io::{Error as IoError, Result as IoResult}; /// A [`TlsProvider`] that uses `native_tls`. /// /// It supports wrapping any reasonable stream type that implements `AsyncRead` + `AsyncWrite`. #[cfg_attr( docsrs, doc(cfg(all(feature = "native-tls", any(feature = "tokio", feature = "async-std")))) )] #[derive(Default, Clone)] #[non_exhaustive] pub struct NativeTlsProvider {} impl CertifiedConn for async_native_tls::TlsStream where S: AsyncRead + AsyncWrite + Unpin, { fn peer_certificate(&self) -> IoResult>> { let cert = self.peer_certificate(); match cert { Ok(Some(c)) => { let der = c .to_der() .map_err(|e| IoError::new(std::io::ErrorKind::Other, e))?; Ok(Some(der)) } Ok(None) => Ok(None), Err(e) => Err(IoError::new(std::io::ErrorKind::Other, e)), } } } /// An implementation of [`TlsConnector`] built with `native_tls`. pub struct NativeTlsConnector { /// The inner connector object. connector: async_native_tls::TlsConnector, /// Phantom data to ensure proper variance. _phantom: std::marker::PhantomData S>, } #[async_trait] impl TlsConnector for NativeTlsConnector where S: AsyncRead + AsyncWrite + Unpin + Send + 'static, { type Conn = async_native_tls::TlsStream; async fn negotiate_unvalidated(&self, stream: S, sni_hostname: &str) -> IoResult { let conn = self .connector .connect(sni_hostname, stream) .await .map_err(|e| IoError::new(std::io::ErrorKind::Other, e))?; Ok(conn) } } impl TlsProvider for NativeTlsProvider where S: AsyncRead + AsyncWrite + Unpin + Send + 'static, { type Connector = NativeTlsConnector; type TlsStream = async_native_tls::TlsStream; fn tls_connector(&self) -> Self::Connector { let mut builder = native_tls::TlsConnector::builder(); // These function names are scary, but they just mean that we // aren't checking whether the signer of this cert // participates in the web PKI, and we aren't checking the // hostname in the cert. builder .danger_accept_invalid_certs(true) .danger_accept_invalid_hostnames(true); let connector = builder.into(); NativeTlsConnector { connector, _phantom: std::marker::PhantomData, } } }