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