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::{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 #[error("I/O error: {0}")]
37 Io(#[from] std::io::Error),
38
39 #[error("UTF8 error: {0}")]
41 Utf8Error(#[from] std::str::Utf8Error),
42
43 #[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 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 Some(0xa00010b) => Some(CommonError::InvalidTlsProtocolData),
144 Some(0xa0000c6) => Some(CommonError::InvalidTlsProtocolData),
146 _ => None,
147 },
148 #[cfg(feature = "openssl")]
149 SslError::OpenSslError(e) => match e.code().as_raw() {
150 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 Some(0xa00010b) => Some(CommonError::InvalidTlsProtocolData),
159 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}