Skip to main content

vector_core/tls/
mod.rs

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