1use crate::ffi;
2use crate::libc_types::c_int;
3use crate::x509::X509VerifyError;
4use openssl_macros::corresponds;
5use std::error;
6use std::error::Error as StdError;
7use std::ffi::CStr;
8use std::fmt;
9use std::io;
10
11use crate::error::ErrorStack;
12use crate::ssl::MidHandshakeSslStream;
13
14#[derive(Copy, Clone, PartialEq, Eq)]
18pub struct ErrorCode(c_int);
19
20impl ErrorCode {
21 pub const NONE: ErrorCode = ErrorCode(ffi::SSL_ERROR_NONE);
23
24 pub const ZERO_RETURN: ErrorCode = ErrorCode(ffi::SSL_ERROR_ZERO_RETURN);
26
27 pub const WANT_READ: ErrorCode = ErrorCode(ffi::SSL_ERROR_WANT_READ);
31
32 pub const WANT_WRITE: ErrorCode = ErrorCode(ffi::SSL_ERROR_WANT_WRITE);
36
37 pub const WANT_X509_LOOKUP: ErrorCode = ErrorCode(ffi::SSL_ERROR_WANT_X509_LOOKUP);
38
39 pub const PENDING_SESSION: ErrorCode = ErrorCode(ffi::SSL_ERROR_PENDING_SESSION);
40
41 pub const PENDING_CERTIFICATE: ErrorCode = ErrorCode(ffi::SSL_ERROR_PENDING_CERTIFICATE);
42
43 pub const WANT_CERTIFICATE_VERIFY: ErrorCode =
44 ErrorCode(ffi::SSL_ERROR_WANT_CERTIFICATE_VERIFY);
45
46 pub const WANT_PRIVATE_KEY_OPERATION: ErrorCode =
47 ErrorCode(ffi::SSL_ERROR_WANT_PRIVATE_KEY_OPERATION);
48
49 pub const PENDING_TICKET: ErrorCode = ErrorCode(ffi::SSL_ERROR_PENDING_TICKET);
50
51 pub const SYSCALL: ErrorCode = ErrorCode(ffi::SSL_ERROR_SYSCALL);
53
54 pub const SSL: ErrorCode = ErrorCode(ffi::SSL_ERROR_SSL);
56
57 #[must_use]
61 #[inline]
62 #[cfg_attr(debug_assertions, track_caller)]
63 pub fn from_raw(raw: c_int) -> ErrorCode {
64 let code = ErrorCode(raw);
65 debug_assert!(
66 raw < 64 || code.description().is_some(),
67 "{raw} is not an SSL_ERROR_* code"
68 );
69 code
70 }
71
72 #[allow(clippy::trivially_copy_pass_by_ref)]
76 #[must_use]
77 pub fn as_raw(&self) -> c_int {
78 self.0
79 }
80
81 #[corresponds(SSL_error_description)]
82 #[must_use]
83 pub fn description(self) -> Option<&'static str> {
84 unsafe {
85 let msg = ffi::SSL_error_description(self.0);
86 if msg.is_null() {
87 return None;
88 }
89 CStr::from_ptr(msg).to_str().ok()
90 }
91 }
92}
93
94impl fmt::Display for ErrorCode {
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 write!(f, "{} ({})", self.description().unwrap_or("error"), self.0)
97 }
98}
99
100impl fmt::Debug for ErrorCode {
101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102 fmt::Display::fmt(self, f)
103 }
104}
105
106#[derive(Debug)]
107pub(crate) enum InnerError {
108 Io(io::Error),
109 Ssl(ErrorStack),
110}
111
112#[derive(Debug)]
114pub struct Error {
115 pub(crate) code: ErrorCode,
116 pub(crate) cause: Option<InnerError>,
117}
118
119impl Error {
120 #[must_use]
122 pub fn code(&self) -> ErrorCode {
123 self.code
124 }
125
126 #[must_use]
127 pub fn io_error(&self) -> Option<&io::Error> {
128 match self.cause {
129 Some(InnerError::Io(ref e)) => Some(e),
130 _ => None,
131 }
132 }
133
134 pub fn into_io_error(self) -> Result<io::Error, Error> {
135 match self.cause {
136 Some(InnerError::Io(e)) => Ok(e),
137 _ => Err(self),
138 }
139 }
140
141 #[must_use]
143 pub fn ssl_error(&self) -> Option<&ErrorStack> {
144 match self.cause {
145 Some(InnerError::Ssl(ref e)) => Some(e),
146 _ => None,
147 }
148 }
149
150 #[must_use]
151 pub fn would_block(&self) -> bool {
152 matches!(
153 self.code,
154 ErrorCode::WANT_READ
155 | ErrorCode::WANT_WRITE
156 | ErrorCode::WANT_X509_LOOKUP
157 | ErrorCode::PENDING_SESSION
158 | ErrorCode::PENDING_CERTIFICATE
159 | ErrorCode::WANT_PRIVATE_KEY_OPERATION
160 | ErrorCode::WANT_CERTIFICATE_VERIFY
161 | ErrorCode::PENDING_TICKET
162 )
163 }
164}
165
166impl From<ErrorStack> for Error {
167 fn from(e: ErrorStack) -> Error {
168 Error {
169 code: ErrorCode::SSL,
170 cause: Some(InnerError::Ssl(e)),
171 }
172 }
173}
174
175impl fmt::Display for Error {
176 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
177 let msg = match self.code {
178 ErrorCode::ZERO_RETURN => "the SSL session has been shut down",
179 ErrorCode::WANT_READ => match self.io_error() {
180 Some(_) => "a nonblocking read call would have blocked",
181 None => "the operation should be retried",
182 },
183 ErrorCode::WANT_WRITE => match self.io_error() {
184 Some(_) => "a nonblocking write call would have blocked",
185 None => "the operation should be retried",
186 },
187 ErrorCode::SYSCALL => match self.io_error() {
188 Some(err) => return err.fmt(fmt),
189 None => "unexpected EOF",
190 },
191 ErrorCode::SSL => match self.ssl_error() {
192 Some(err) => return err.fmt(fmt),
193 None => "unknown BoringSSL error",
194 },
195 ErrorCode(code) => return code.fmt(fmt),
196 };
197 fmt.write_str(msg)
198 }
199}
200
201impl error::Error for Error {
202 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
203 match self.cause {
204 Some(InnerError::Io(ref e)) => Some(e),
205 Some(InnerError::Ssl(ref e)) => Some(e),
206 None => None,
207 }
208 }
209}
210
211#[derive(Debug)]
214pub enum HandshakeError<S> {
215 SetupFailure(ErrorStack),
217 Failure(MidHandshakeSslStream<S>),
219 WouldBlock(MidHandshakeSslStream<S>),
223}
224
225impl<S: fmt::Debug> StdError for HandshakeError<S> {
226 fn source(&self) -> Option<&(dyn StdError + 'static)> {
227 match *self {
228 HandshakeError::SetupFailure(ref e) => Some(e),
229 HandshakeError::Failure(ref s) | HandshakeError::WouldBlock(ref s) => Some(s.error()),
230 }
231 }
232}
233
234impl<S> fmt::Display for HandshakeError<S> {
235 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
236 match *self {
237 HandshakeError::SetupFailure(ref e) => {
238 write!(f, "TLS stream setup failed {e}")
239 }
240 HandshakeError::Failure(ref s) => fmt_mid_handshake_error(s, f, "TLS handshake failed"),
241 HandshakeError::WouldBlock(ref s) => {
242 fmt_mid_handshake_error(s, f, "TLS handshake interrupted")
243 }
244 }
245 }
246}
247
248fn fmt_mid_handshake_error(
249 s: &MidHandshakeSslStream<impl Sized>,
250 f: &mut fmt::Formatter,
251 prefix: &str,
252) -> fmt::Result {
253 if !s.ssl().ssl_context().has_x509_support() {
254 write!(f, "{}", prefix)?;
255 return write!(f, " {}", s.error());
256 }
257
258 match s.ssl().verify_result() {
259 Ok(()) | Err(X509VerifyError::INVALID_CALL) => write!(f, "{prefix}")?,
262 Err(verify) => write!(f, "{prefix}: cert verification failed - {verify}")?,
263 }
264
265 write!(f, " {}", s.error())
266}
267
268impl<S> From<ErrorStack> for HandshakeError<S> {
269 fn from(e: ErrorStack) -> HandshakeError<S> {
270 HandshakeError::SetupFailure(e)
271 }
272}