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::{stream::*, target::*, tls::*, BaseStream};
29pub use rustls_pki_types as pki_types;
30
31pub type RawStream = UpgradableStream<BaseStream>;
32
33#[derive(Debug, thiserror::Error)]
34pub enum ConnectionError {
35    /// I/O error encountered during connection operations.
36    #[error("I/O error: {0}")]
37    Io(#[from] std::io::Error),
38
39    /// UTF-8 decoding error.
40    #[error("UTF8 error: {0}")]
41    Utf8Error(#[from] std::str::Utf8Error),
42
43    /// SSL-related error.
44    #[error("SSL error: {0}")]
45    SslError(#[from] SslError),
46}
47
48impl From<ConnectionError> for std::io::Error {
49    fn from(err: ConnectionError) -> Self {
50        match err {
51            ConnectionError::Io(e) => e,
52            ConnectionError::Utf8Error(e) => std::io::Error::new(std::io::ErrorKind::Other, e),
53            ConnectionError::SslError(e) => e.into(),
54        }
55    }
56}
57
58#[derive(Debug, thiserror::Error)]
59pub enum SslError {
60    #[error("SSL is not supported by this client transport")]
61    SslUnsupportedByClient,
62    #[error("SSL is already upgraded or is in the process of upgrading")]
63    SslAlreadyUpgraded,
64
65    #[cfg(feature = "openssl")]
66    #[error("OpenSSL error: {0}")]
67    OpenSslError(#[from] ::openssl::ssl::Error),
68    #[cfg(feature = "openssl")]
69    #[error("OpenSSL error: {0}")]
70    OpenSslErrorStack(#[from] ::openssl::error::ErrorStack),
71    #[cfg(feature = "openssl")]
72    #[error("OpenSSL certificate verification error: {0}")]
73    OpenSslErrorVerify(#[from] ::openssl::x509::X509VerifyResult),
74
75    #[cfg(feature = "rustls")]
76    #[error("Rustls error: {0}")]
77    RustlsError(#[from] ::rustls::Error),
78
79    #[cfg(feature = "rustls")]
80    #[error("Webpki error: {0}")]
81    WebpkiError(::webpki::Error),
82
83    #[cfg(feature = "rustls")]
84    #[error("Verifier builder error: {0}")]
85    VerifierBuilderError(#[from] ::rustls::server::VerifierBuilderError),
86
87    #[error("Invalid DNS name: {0}")]
88    InvalidDnsNameError(#[from] ::rustls_pki_types::InvalidDnsNameError),
89
90    #[error("SSL I/O error: {0}")]
91    SslIoError(#[from] std::io::Error),
92}
93
94impl Into<std::io::Error> for SslError {
95    fn into(self) -> std::io::Error {
96        match self {
97            SslError::SslIoError(e) => e,
98            other => std::io::Error::new(std::io::ErrorKind::Other, other),
99        }
100    }
101}
102
103impl SslError {
104    /// Returns a common error for any time of crypto backend.
105    pub fn common_error(&self) -> Option<CommonError> {
106        match self {
107            #[cfg(feature = "rustls")]
108            SslError::RustlsError(::rustls::Error::InvalidCertificate(cert_err)) => {
109                match cert_err {
110                    ::rustls::CertificateError::NotValidForName
111                    | ::rustls::CertificateError::NotValidForNameContext { .. } => {
112                        Some(CommonError::InvalidCertificateForName)
113                    }
114                    ::rustls::CertificateError::Revoked => Some(CommonError::CertificateRevoked),
115                    ::rustls::CertificateError::Expired => Some(CommonError::CertificateExpired),
116                    ::rustls::CertificateError::UnknownIssuer => Some(CommonError::InvalidIssuer),
117                    _ => None,
118                }
119            }
120            #[cfg(feature = "rustls")]
121            SslError::RustlsError(::rustls::Error::InvalidMessage(_)) => {
122                Some(CommonError::InvalidTlsProtocolData)
123            }
124            #[cfg(feature = "openssl")]
125            SslError::OpenSslErrorVerify(e) => match e.as_raw() {
126                openssl_sys::X509_V_ERR_HOSTNAME_MISMATCH => {
127                    Some(CommonError::InvalidCertificateForName)
128                }
129                openssl_sys::X509_V_ERR_IP_ADDRESS_MISMATCH => {
130                    Some(CommonError::InvalidCertificateForName)
131                }
132                openssl_sys::X509_V_ERR_CERT_REVOKED => Some(CommonError::CertificateRevoked),
133                openssl_sys::X509_V_ERR_CERT_HAS_EXPIRED => Some(CommonError::CertificateExpired),
134                openssl_sys::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT
135                | openssl_sys::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY => {
136                    Some(CommonError::InvalidIssuer)
137                }
138                _ => None,
139            },
140            #[cfg(feature = "openssl")]
141            SslError::OpenSslErrorStack(e) => match e.errors().first().map(|err| err.code()) {
142                // SSL_R_WRONG_VERSION_NUMBER
143                Some(0xa00010b) => Some(CommonError::InvalidTlsProtocolData),
144                // SSL_R_PACKET_LENGTH_TOO_LONG
145                Some(0xa0000c6) => Some(CommonError::InvalidTlsProtocolData),
146                _ => None,
147            },
148            #[cfg(feature = "openssl")]
149            SslError::OpenSslError(e) => match e.code().as_raw() {
150                // TODO: We should probably wrap up handshake errors differently.
151                openssl_sys::SSL_ERROR_SSL => {
152                    match e
153                        .ssl_error()
154                        .and_then(|e| e.errors().first())
155                        .map(|err| err.code())
156                    {
157                        // SSL_R_WRONG_VERSION_NUMBER
158                        Some(0xa00010b) => Some(CommonError::InvalidTlsProtocolData),
159                        // SSL_R_PACKET_LENGTH_TOO_LONG
160                        Some(0xa0000c6) => Some(CommonError::InvalidTlsProtocolData),
161                        _ => None,
162                    }
163                }
164                _ => None,
165            },
166            _ => None,
167        }
168    }
169}
170
171#[derive(Debug, thiserror::Error, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
172pub enum CommonError {
173    #[error("The certificate's subject name(s) do not match the name of the host")]
174    InvalidCertificateForName,
175    #[error("The certificate has been revoked")]
176    CertificateRevoked,
177    #[error("The certificate has expired")]
178    CertificateExpired,
179    #[error("The certificate was issued by an untrusted authority")]
180    InvalidIssuer,
181    #[error("TLS protocol error")]
182    InvalidTlsProtocolData,
183}