1#![doc = include_str!("../README.md")]
2#![cfg_attr(
5 not(all(
6 all(feature = "client", feature = "server"),
7 any(feature = "rustls", feature = "openssl")
8 )),
9 allow(unused)
10)]
11
12#[cfg(feature = "client")]
13mod client;
14#[cfg(feature = "server")]
15mod server;
16
17#[cfg(feature = "client")]
18pub use client::Connector;
19
20#[cfg(feature = "server")]
21pub use server::Acceptor;
22
23mod common;
24#[cfg(feature = "openssl")]
25pub use common::openssl::OpensslDriver;
26#[cfg(feature = "rustls")]
27pub use common::rustls::RustlsDriver;
28pub use common::{resolver::*, stream::*, target::*, tls::*, BaseStream};
29pub use rustls_pki_types as pki_types;
30
31pub type RawStream = UpgradableStream<BaseStream>;
32
33pub const DEFAULT_TCP_BACKLOG: u32 = 1024;
35pub const DEFAULT_TLS_BACKLOG: u32 = 128;
37pub const DEFAULT_PREVIEW_BUFFER_SIZE: u32 = 8;
39
40#[derive(Debug, derive_more::Error, derive_more::Display, derive_more::From)]
41pub enum ConnectionError {
42 #[display("I/O error: {_0}")]
44 Io(#[from] std::io::Error),
45
46 #[display("UTF8 error: {_0}")]
48 Utf8Error(#[from] std::str::Utf8Error),
49
50 #[display("SSL error: {_0}")]
52 SslError(#[from] SslError),
53}
54
55impl From<ConnectionError> for std::io::Error {
56 fn from(err: ConnectionError) -> Self {
57 match err {
58 ConnectionError::Io(e) => e,
59 ConnectionError::Utf8Error(e) => std::io::Error::new(std::io::ErrorKind::Other, e),
60 ConnectionError::SslError(e) => e.into(),
61 }
62 }
63}
64
65#[derive(Debug, derive_more::Error, derive_more::Display, derive_more::From)]
66pub enum SslError {
67 #[display("SSL is not supported by this transport")]
68 SslUnsupported,
69 #[display("SSL is already upgraded or is in the process of upgrading")]
70 SslAlreadyUpgraded,
71
72 #[cfg(feature = "openssl")]
73 #[display("OpenSSL error: {_0}")]
74 OpenSslError(#[from] ::openssl::ssl::Error),
75 #[cfg(feature = "openssl")]
76 #[display("OpenSSL error: {_0}")]
77 OpenSslErrorStack(#[from] ::openssl::error::ErrorStack),
78 #[cfg(feature = "openssl")]
79 #[display("OpenSSL certificate verification error: {_0}")]
80 OpenSslErrorVerify(#[from] ::openssl::x509::X509VerifyResult),
81
82 #[cfg(feature = "rustls")]
83 #[display("Rustls error: {_0}")]
84 RustlsError(#[from] ::rustls::Error),
85
86 #[cfg(feature = "rustls")]
87 #[display("Webpki error: {_0}")]
88 WebpkiError(
89 #[from]
90 #[error(not(source))]
91 ::webpki::Error,
92 ),
93
94 #[cfg(feature = "rustls")]
95 #[display("Verifier builder error: {_0}")]
96 VerifierBuilderError(#[from] ::rustls::server::VerifierBuilderError),
97
98 #[display("Invalid DNS name: {_0}")]
99 InvalidDnsNameError(#[from] ::rustls_pki_types::InvalidDnsNameError),
100
101 #[display("SSL I/O error: {_0}")]
102 SslIoError(#[from] std::io::Error),
103}
104
105impl From<SslError> for std::io::Error {
106 fn from(err: SslError) -> Self {
107 match err {
108 SslError::SslIoError(e) => e,
109 other => std::io::Error::new(std::io::ErrorKind::Other, other),
110 }
111 }
112}
113
114impl SslError {
115 pub fn common_error(&self) -> Option<CommonError> {
117 match self {
118 #[cfg(feature = "rustls")]
119 SslError::RustlsError(::rustls::Error::InvalidCertificate(cert_err)) => {
120 match cert_err {
121 ::rustls::CertificateError::NotValidForName
122 | ::rustls::CertificateError::NotValidForNameContext { .. } => {
123 Some(CommonError::InvalidCertificateForName)
124 }
125 ::rustls::CertificateError::Revoked => Some(CommonError::CertificateRevoked),
126 ::rustls::CertificateError::Expired => Some(CommonError::CertificateExpired),
127 ::rustls::CertificateError::UnknownIssuer => Some(CommonError::InvalidIssuer),
128 _ => None,
129 }
130 }
131 #[cfg(feature = "rustls")]
132 SslError::RustlsError(::rustls::Error::InvalidMessage(_)) => {
133 Some(CommonError::InvalidTlsProtocolData)
134 }
135 #[cfg(feature = "openssl")]
136 SslError::OpenSslErrorVerify(e) => match e.as_raw() {
137 openssl_sys::X509_V_ERR_HOSTNAME_MISMATCH => {
138 Some(CommonError::InvalidCertificateForName)
139 }
140 openssl_sys::X509_V_ERR_IP_ADDRESS_MISMATCH => {
141 Some(CommonError::InvalidCertificateForName)
142 }
143 openssl_sys::X509_V_ERR_CERT_REVOKED => Some(CommonError::CertificateRevoked),
144 openssl_sys::X509_V_ERR_CERT_HAS_EXPIRED => Some(CommonError::CertificateExpired),
145 openssl_sys::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT
146 | openssl_sys::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY => {
147 Some(CommonError::InvalidIssuer)
148 }
149 _ => None,
150 },
151 #[cfg(feature = "openssl")]
152 SslError::OpenSslErrorStack(e) => match e.errors().first().map(|err| err.code()) {
153 Some(0xa00010b) => Some(CommonError::InvalidTlsProtocolData),
155 Some(0xa0000c6) => Some(CommonError::InvalidTlsProtocolData),
157 _ => None,
158 },
159 #[cfg(feature = "openssl")]
160 SslError::OpenSslError(e) => match e.code().as_raw() {
161 openssl_sys::SSL_ERROR_SSL => {
163 match e
164 .ssl_error()
165 .and_then(|e| e.errors().first())
166 .map(|err| err.code())
167 {
168 Some(0xa00010b) => Some(CommonError::InvalidTlsProtocolData),
170 Some(0xa0000c6) => Some(CommonError::InvalidTlsProtocolData),
172 _ => None,
173 }
174 }
175 _ => None,
176 },
177 _ => None,
178 }
179 }
180}
181
182#[derive(
183 Debug,
184 derive_more::Error,
185 derive_more::Display,
186 PartialEq,
187 Eq,
188 PartialOrd,
189 Ord,
190 Clone,
191 Copy,
192 Hash,
193)]
194pub enum CommonError {
195 #[display("The certificate's subject name(s) do not match the name of the host")]
196 InvalidCertificateForName,
197 #[display("The certificate has been revoked")]
198 CertificateRevoked,
199 #[display("The certificate has expired")]
200 CertificateExpired,
201 #[display("The certificate was issued by an untrusted authority")]
202 InvalidIssuer,
203 #[display("TLS protocol error")]
204 InvalidTlsProtocolData,
205}
206
207#[cfg(feature = "__test_keys")]
208pub mod test_keys {
209 macro_rules! include_files {
210 ($($name:ident : $type:path => $path:literal),*) => {
211 pub mod raw {
213 $(
214 #[doc = concat!("Test key: ", $path)]
215 pub static $name: &str = include_str!(concat!("../tests/", $path));
216 )*
217 }
218
219 #[cfg(feature = "pem")]
220 pub mod binary {
221 use std::sync::LazyLock;
222 $(
223 #[doc = concat!("Test key: ", $path)]
224 pub static $name: LazyLock<$type> = LazyLock::new(
225 || rustls_pki_types::pem::PemObject::from_pem_slice($crate::test_keys::raw::$name.as_bytes()).unwrap()
226 );
227 )*
228 }
229 }
230 }
231
232 include_files!(
233 SERVER_KEY: rustls_pki_types::PrivateKeyDer => "certs/server.key.pem",
234 SERVER_CERT: rustls_pki_types::CertificateDer => "certs/server.cert.pem",
235 SERVER_ALT_KEY: rustls_pki_types::PrivateKeyDer => "certs/server-alt.key.pem",
236 SERVER_ALT_CERT: rustls_pki_types::CertificateDer => "certs/server-alt.cert.pem",
237 CLIENT_KEY_PROTECTED: rustls_pki_types::PrivateKeyDer => "certs/client.key.protected.pem",
238 CLIENT_KEY: rustls_pki_types::PrivateKeyDer => "certs/client.key.pem",
239 CLIENT_CERT: rustls_pki_types::CertificateDer => "certs/client.cert.pem",
240 CLIENT_CA_KEY: rustls_pki_types::PrivateKeyDer => "certs/client_ca.key.pem",
241 CLIENT_CA_CERT: rustls_pki_types::CertificateDer => "certs/client_ca.cert.pem",
242 CA_KEY: rustls_pki_types::PrivateKeyDer => "certs/ca.key.pem",
243 CA_CRL: rustls_pki_types::CertificateRevocationListDer => "certs/ca.crl.pem",
244 CA_CERT: rustls_pki_types::CertificateDer => "certs/ca.cert.pem"
245 );
246
247 use std::sync::LazyLock;
248
249 #[cfg(feature = "pem")]
250 pub static SERVER_KEY: LazyLock<crate::TlsKey> = LazyLock::new(|| {
251 crate::TlsKey::new(binary::SERVER_KEY.clone_key(), binary::SERVER_CERT.clone())
252 });
253
254 #[cfg(feature = "pem")]
255 pub static SERVER_ALT_KEY: LazyLock<crate::TlsKey> = LazyLock::new(|| {
256 crate::TlsKey::new(
257 binary::SERVER_ALT_KEY.clone_key(),
258 binary::SERVER_ALT_CERT.clone(),
259 )
260 });
261
262 #[cfg(feature = "pem")]
263 pub static CLIENT_KEY: LazyLock<crate::TlsKey> = LazyLock::new(|| {
264 crate::TlsKey::new(binary::CLIENT_KEY.clone_key(), binary::CLIENT_CERT.clone())
265 });
266}