vector_core/tls/
mod.rs

1#![allow(clippy::missing_errors_doc)]
2
3use std::{fmt::Debug, net::SocketAddr, path::PathBuf, time::Duration};
4
5use openssl::{
6    error::ErrorStack,
7    ssl::{ConnectConfiguration, SslConnector, SslConnectorBuilder, SslMethod},
8};
9use snafu::{ResultExt, Snafu};
10use std::num::TryFromIntError;
11use tokio::net::TcpStream;
12use tokio_openssl::SslStream;
13
14use crate::tcp::{self, TcpKeepaliveConfig};
15
16mod incoming;
17mod maybe_tls;
18mod outgoing;
19mod settings;
20
21pub use incoming::{CertificateMetadata, MaybeTlsIncomingStream, MaybeTlsListener};
22pub use maybe_tls::MaybeTls;
23pub use settings::{
24    MaybeTlsSettings, TlsConfig, TlsEnableableConfig, TlsSettings, TlsSourceConfig,
25    PEM_START_MARKER, TEST_PEM_CA_PATH, TEST_PEM_CLIENT_CRT_PATH, TEST_PEM_CLIENT_KEY_PATH,
26    TEST_PEM_CRT_PATH, TEST_PEM_INTERMEDIATE_CA_PATH, TEST_PEM_KEY_PATH,
27};
28
29pub type Result<T> = std::result::Result<T, TlsError>;
30
31pub type MaybeTlsStream<S> = MaybeTls<S, SslStream<S>>;
32
33#[derive(Debug, Snafu)]
34pub enum TlsError {
35    #[snafu(display("Could not open {} file {:?}: {}", note, filename, source))]
36    FileOpenFailed {
37        note: &'static str,
38        filename: PathBuf,
39        source: std::io::Error,
40    },
41    #[snafu(display("Could not read {} file {:?}: {}", note, filename, source))]
42    FileReadFailed {
43        note: &'static str,
44        filename: PathBuf,
45        source: std::io::Error,
46    },
47    #[snafu(display("Could not build TLS connector: {}", source))]
48    TlsBuildConnector { source: ErrorStack },
49    #[snafu(display("Could not set TCP TLS identity: {}", source))]
50    TlsIdentityError { source: ErrorStack },
51    #[snafu(display("Could not export identity to DER: {}", source))]
52    DerExportError { source: ErrorStack },
53    #[snafu(display("Identity certificate is missing a key"))]
54    MissingKey,
55    #[snafu(display("Certificate file contains no certificates"))]
56    MissingCertificate,
57    #[snafu(display("Could not parse certificate in {:?}: {}", filename, source))]
58    CertificateParseError {
59        filename: PathBuf,
60        source: ErrorStack,
61    },
62    #[snafu(display("Must specify both TLS key_file and crt_file"))]
63    MissingCrtKeyFile,
64    #[snafu(display("Could not parse X509 certificate in {:?}: {}", filename, source))]
65    X509ParseError {
66        filename: PathBuf,
67        source: ErrorStack,
68    },
69    #[snafu(display("Could not parse private key in {:?}: {}", filename, source))]
70    PrivateKeyParseError {
71        filename: PathBuf,
72        source: ErrorStack,
73    },
74    #[snafu(display("Could not build PKCS#12 archive for identity: {}", source))]
75    Pkcs12Error { source: ErrorStack },
76    #[snafu(display("Could not parse identity in {:?}: {}", filename, source))]
77    IdentityParseError {
78        filename: PathBuf,
79        source: ErrorStack,
80    },
81    #[snafu(display("TLS configuration requires a certificate when enabled"))]
82    MissingRequiredIdentity,
83    #[snafu(display("TLS handshake failed: {}", source))]
84    Handshake { source: openssl::ssl::Error },
85    #[snafu(display("Incoming listener failed: {}", source))]
86    IncomingListener { source: tokio::io::Error },
87    #[snafu(display("Creating the TLS acceptor failed: {}", source))]
88    CreateAcceptor { source: ErrorStack },
89    #[snafu(display("Error building SSL context: {}", source))]
90    SslBuildError { source: openssl::error::ErrorStack },
91    #[snafu(display("Error setting up the TLS certificate: {}", source))]
92    SetCertificate { source: ErrorStack },
93    #[snafu(display("Error setting up the TLS private key: {}", source))]
94    SetPrivateKey { source: ErrorStack },
95    #[snafu(display("Error setting up the TLS chain certificates: {}", source))]
96    AddExtraChainCert { source: ErrorStack },
97    #[snafu(display("Error creating a certificate store: {}", source))]
98    NewStoreBuilder { source: ErrorStack },
99    #[snafu(display("Error adding a certificate to a store: {}", source))]
100    AddCertToStore { source: ErrorStack },
101    #[snafu(display("Error setting up the verification certificate: {}", source))]
102    SetVerifyCert { source: ErrorStack },
103    #[snafu(display("Error setting SNI: {}", source))]
104    SetSni { source: ErrorStack },
105    #[snafu(display("Error setting ALPN protocols: {}", source))]
106    SetAlpnProtocols { source: ErrorStack },
107    #[snafu(display(
108        "Error encoding ALPN protocols, could not encode length as u8: {}",
109        source
110    ))]
111    EncodeAlpnProtocols { source: TryFromIntError },
112    #[snafu(display("PKCS#12 parse failed: {}", source))]
113    ParsePkcs12 { source: ErrorStack },
114    #[snafu(display("TCP bind failed: {}", source))]
115    TcpBind { source: tokio::io::Error },
116    #[snafu(display("{}", source))]
117    Connect { source: tokio::io::Error },
118    #[snafu(display("Could not get peer address: {}", source))]
119    PeerAddress { source: std::io::Error },
120    #[snafu(display("Security Framework Error: {}", source))]
121    #[cfg(target_os = "macos")]
122    SecurityFramework {
123        source: security_framework::base::Error,
124    },
125    #[snafu(display("Schannel Error: {}", source))]
126    #[cfg(windows)]
127    Schannel { source: std::io::Error },
128    #[cfg(any(windows, target_os = "macos"))]
129    #[snafu(display("Unable to parse X509 from system cert: {}", source))]
130    X509SystemParseError { source: ErrorStack },
131    #[snafu(display("Creating an empty CA stack failed"))]
132    NewCaStack { source: ErrorStack },
133    #[snafu(display("Could not push intermediate certificate onto stack"))]
134    CaStackPush { source: ErrorStack },
135}
136
137impl MaybeTlsStream<TcpStream> {
138    pub fn peer_addr(&self) -> std::result::Result<SocketAddr, std::io::Error> {
139        match self {
140            Self::Raw(raw) => raw.peer_addr(),
141            Self::Tls(tls) => tls.get_ref().peer_addr(),
142        }
143    }
144
145    pub fn set_keepalive(&mut self, keepalive: TcpKeepaliveConfig) -> std::io::Result<()> {
146        let stream = match self {
147            Self::Raw(raw) => raw,
148            Self::Tls(tls) => tls.get_ref(),
149        };
150
151        if let Some(time_secs) = keepalive.time_secs {
152            let config = socket2::TcpKeepalive::new().with_time(Duration::from_secs(time_secs));
153
154            tcp::set_keepalive(stream, &config)?;
155        }
156
157        Ok(())
158    }
159
160    pub fn set_send_buffer_bytes(&mut self, bytes: usize) -> std::io::Result<()> {
161        let stream = match self {
162            Self::Raw(raw) => raw,
163            Self::Tls(tls) => tls.get_ref(),
164        };
165
166        tcp::set_send_buffer_size(stream, bytes)
167    }
168
169    pub fn set_receive_buffer_bytes(&mut self, bytes: usize) -> std::io::Result<()> {
170        let stream = match self {
171            Self::Raw(raw) => raw,
172            Self::Tls(tls) => tls.get_ref(),
173        };
174
175        tcp::set_receive_buffer_size(stream, bytes)
176    }
177}
178
179pub fn tls_connector_builder(settings: &MaybeTlsSettings) -> Result<SslConnectorBuilder> {
180    let mut builder = SslConnector::builder(SslMethod::tls()).context(TlsBuildConnectorSnafu)?;
181    if let Some(settings) = settings.tls() {
182        settings.apply_context(&mut builder)?;
183    }
184    Ok(builder)
185}
186
187fn tls_connector(settings: &MaybeTlsSettings) -> Result<ConnectConfiguration> {
188    let mut configure = tls_connector_builder(settings)?
189        .build()
190        .configure()
191        .context(TlsBuildConnectorSnafu)?;
192    let tls_setting = settings.tls().cloned();
193    if let Some(tls_setting) = &tls_setting {
194        tls_setting
195            .apply_connect_configuration(&mut configure)
196            .context(SetSniSnafu)?;
197    }
198    Ok(configure)
199}