gel_stream/
lib.rs

1#![doc = include_str!("../README.md")]
2// We don't want to warn about unused code when 1) either client or server is not
3// enabled, or 2) no crypto backend is enabled.
4#![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
33/// The default TCP backlog for the server.
34pub const DEFAULT_TCP_BACKLOG: u32 = 1024;
35/// The default TLS backlog for the server.
36pub const DEFAULT_TLS_BACKLOG: u32 = 128;
37/// The default preview buffer size for the server.
38pub const DEFAULT_PREVIEW_BUFFER_SIZE: u32 = 8;
39
40#[derive(Debug, derive_more::Error, derive_more::Display, derive_more::From)]
41pub enum ConnectionError {
42    /// I/O error encountered during connection operations.
43    #[display("I/O error: {_0}")]
44    Io(#[from] std::io::Error),
45
46    /// UTF-8 decoding error.
47    #[display("UTF8 error: {_0}")]
48    Utf8Error(#[from] std::str::Utf8Error),
49
50    /// SSL-related error.
51    #[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::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::other(other),
110        }
111    }
112}
113
114impl SslError {
115    /// Returns a common error for any time of crypto backend.
116    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                // SSL_R_WRONG_VERSION_NUMBER
154                Some(0xa00010b) => Some(CommonError::InvalidTlsProtocolData),
155                // SSL_R_PACKET_LENGTH_TOO_LONG
156                Some(0xa0000c6) => Some(CommonError::InvalidTlsProtocolData),
157                _ => None,
158            },
159            #[cfg(feature = "openssl")]
160            SslError::OpenSslError(e) => match e.code().as_raw() {
161                // TODO: We should probably wrap up handshake errors differently.
162                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                        // SSL_R_WRONG_VERSION_NUMBER
169                        Some(0xa00010b) => Some(CommonError::InvalidTlsProtocolData),
170                        // SSL_R_PACKET_LENGTH_TOO_LONG
171                        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            /// Raw PEM text from the test files.
212            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}