tcp_stream/
native_tls_impl.rs

1use crate::{
2    HandshakeError, HandshakeResult, Identity, MidHandshakeTlsStream, StdTcpStream, TLSConfig,
3    TcpStream,
4};
5
6#[cfg(feature = "native-tls-futures")]
7use {
8    crate::AsyncTcpStream,
9    futures_io::{AsyncRead, AsyncWrite},
10};
11
12use native_tls::Certificate;
13use std::io;
14
15/// Reexport native-tls's `TlsConnector`
16pub use native_tls::TlsConnector as NativeTlsConnector;
17
18/// Reexport native-tls's `TlsConnectorBuilder`
19pub use native_tls::TlsConnectorBuilder as NativeTlsConnectorBuilder;
20
21/// A `TcpStream` wrapped by native-tls
22pub type NativeTlsStream = native_tls::TlsStream<StdTcpStream>;
23
24/// A `MidHandshakeTlsStream` from native-tls
25pub type NativeTlsMidHandshakeTlsStream = native_tls::MidHandshakeTlsStream<StdTcpStream>;
26
27/// A `HandshakeError` from native-tls
28pub type NativeTlsHandshakeError = native_tls::HandshakeError<StdTcpStream>;
29
30#[cfg(feature = "native-tls-futures")]
31/// An async `TcpStream` wrapped by native-tls
32pub type NativeTlsAsyncStream<S> = async_native_tls::TlsStream<S>;
33
34fn native_tls_connector_builder(
35    config: TLSConfig<'_, '_, '_>,
36) -> io::Result<NativeTlsConnectorBuilder> {
37    let mut builder = NativeTlsConnector::builder();
38    if let Some(identity) = config.identity {
39        let native_identity = match identity {
40            Identity::PKCS8 { pem, key } => native_tls::Identity::from_pkcs8(pem, key),
41            Identity::PKCS12 { der, password } => native_tls::Identity::from_pkcs12(der, password),
42        };
43        builder.identity(native_identity.map_err(io::Error::other)?);
44    }
45    if let Some(cert_chain) = config.cert_chain {
46        let mut cert_chain = std::io::BufReader::new(cert_chain.as_bytes());
47        for cert in rustls_pemfile::certs(&mut cert_chain).collect::<Result<Vec<_>, _>>()? {
48            builder
49                .add_root_certificate(Certificate::from_der(&cert[..]).map_err(io::Error::other)?);
50        }
51    }
52    Ok(builder)
53}
54
55fn native_tls_connector(config: TLSConfig<'_, '_, '_>) -> io::Result<NativeTlsConnector> {
56    native_tls_connector_builder(config)?
57        .build()
58        .map_err(io::Error::other)
59}
60
61#[allow(dead_code)]
62pub(crate) fn into_native_tls_impl(
63    s: TcpStream,
64    domain: &str,
65    config: TLSConfig<'_, '_, '_>,
66) -> HandshakeResult {
67    s.into_native_tls(&native_tls_connector(config)?, domain)
68}
69
70#[cfg(feature = "native-tls-futures")]
71#[allow(dead_code)]
72pub(crate) async fn into_native_tls_impl_async<
73    S: AsyncRead + AsyncWrite + Send + Unpin + 'static,
74>(
75    s: AsyncTcpStream<S>,
76    domain: &str,
77    config: TLSConfig<'_, '_, '_>,
78) -> io::Result<AsyncTcpStream<S>> {
79    s.into_native_tls(native_tls_connector_builder(config)?, domain)
80        .await
81}
82
83impl From<NativeTlsStream> for TcpStream {
84    fn from(s: NativeTlsStream) -> Self {
85        Self::NativeTls(s)
86    }
87}
88
89impl From<NativeTlsMidHandshakeTlsStream> for MidHandshakeTlsStream {
90    fn from(mid: NativeTlsMidHandshakeTlsStream) -> Self {
91        Self::NativeTls(mid)
92    }
93}
94
95impl From<NativeTlsHandshakeError> for HandshakeError {
96    fn from(error: NativeTlsHandshakeError) -> Self {
97        match error {
98            native_tls::HandshakeError::WouldBlock(mid) => Self::WouldBlock(mid.into()),
99            native_tls::HandshakeError::Failure(failure) => {
100                Self::Failure(io::Error::other(failure))
101            }
102        }
103    }
104}