hickory_proto/openssl/
tls_client_stream.rs

1// Copyright 2015-2016 Benjamin Fry <benjaminfry@me.com>
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// https://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// https://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8use std::future::Future;
9use std::io;
10use std::net::SocketAddr;
11use std::pin::Pin;
12
13use futures_util::TryFutureExt;
14use openssl::x509::X509;
15use tokio_openssl::SslStream as TokioTlsStream;
16
17use crate::error::ProtoError;
18use crate::iocompat::AsyncIoStdAsTokio;
19use crate::iocompat::AsyncIoTokioAsStd;
20use crate::tcp::{Connect, DnsTcpStream, TcpClientStream};
21use crate::xfer::BufDnsStreamHandle;
22
23use super::TlsStreamBuilder;
24
25/// A Type definition for the TLS stream
26pub type TlsClientStream<S> =
27    TcpClientStream<AsyncIoTokioAsStd<TokioTlsStream<AsyncIoStdAsTokio<S>>>>;
28
29/// A Builder for the TlsClientStream
30pub struct TlsClientStreamBuilder<S>(TlsStreamBuilder<S>);
31
32impl<S: DnsTcpStream> TlsClientStreamBuilder<S> {
33    /// Creates a builder for the construction of a TlsClientStream.
34    pub fn new() -> Self {
35        Self(TlsStreamBuilder::new())
36    }
37
38    /// Add a custom trusted peer certificate or certificate authority.
39    ///
40    /// If this is the 'client' then the 'server' must have it associated as it's `identity`, or have had the `identity` signed by this certificate.
41    pub fn add_ca(&mut self, ca: X509) {
42        self.0.add_ca(ca);
43    }
44
45    /// Add a custom trusted peer certificate or certificate authority encoded as a (binary) DER-encoded X.509 certificate.
46    ///
47    /// If this is the 'client' then the 'server' must have it associated as it's `identity`, or have had the `identity` signed by this certificate.
48    pub fn add_ca_der(&mut self, ca_der: &[u8]) -> io::Result<()> {
49        let ca = X509::from_der(ca_der)
50            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e.to_string()))?;
51        self.add_ca(ca);
52        Ok(())
53    }
54
55    /// Sets the address to connect from.
56    pub fn bind_addr(&mut self, bind_addr: SocketAddr) {
57        self.0.bind_addr(bind_addr);
58    }
59
60    /// Creates a new TlsStream to the specified name_server with future
61    ///
62    /// # Arguments
63    ///
64    /// * `future` - future for underlying tcp stream
65    /// * `name_server` - IP and Port for the remote DNS resolver
66    /// * `dns_name` - The DNS name, Subject Public Key Info (SPKI) name, as associated to a certificate
67    #[allow(clippy::type_complexity)]
68    pub fn build_with_future<F>(
69        self,
70        future: F,
71        name_server: SocketAddr,
72        dns_name: String,
73    ) -> (
74        Pin<Box<dyn Future<Output = Result<TlsClientStream<S>, ProtoError>> + Send>>,
75        BufDnsStreamHandle,
76    )
77    where
78        F: Future<Output = io::Result<S>> + Send + Unpin + 'static,
79    {
80        let (stream_future, sender) = self.0.build_with_future(future, name_server, dns_name);
81
82        let new_future = Box::pin(
83            stream_future
84                .map_ok(TcpClientStream::from_stream)
85                .map_err(ProtoError::from),
86        );
87
88        (new_future, sender)
89    }
90}
91
92impl<S: DnsTcpStream> Default for TlsClientStreamBuilder<S> {
93    fn default() -> Self {
94        Self::new()
95    }
96}
97
98impl<S: Connect> TlsClientStreamBuilder<S> {
99    /// Creates a new TlsStream to the specified name_server
100    ///
101    /// # Arguments
102    ///
103    /// * `name_server` - IP and Port for the remote DNS resolver
104    /// * `bind_addr` - IP and port to connect from
105    /// * `dns_name` - The DNS name, Subject Public Key Info (SPKI) name, as associated to a certificate
106    #[allow(clippy::type_complexity)]
107    pub fn build(
108        self,
109        name_server: SocketAddr,
110        dns_name: String,
111    ) -> (
112        Pin<Box<dyn Future<Output = Result<TlsClientStream<S>, ProtoError>> + Send>>,
113        BufDnsStreamHandle,
114    ) {
115        let (stream_future, sender) = self.0.build(name_server, dns_name);
116
117        let new_future = Box::pin(
118            stream_future
119                .map_ok(TcpClientStream::from_stream)
120                .map_err(ProtoError::from),
121        );
122
123        (new_future, sender)
124    }
125}