1 | use libc::c_int; |
2 | use std::error; |
3 | use std::error::Error as StdError; |
4 | use std::fmt; |
5 | use std::io; |
6 | |
7 | use crate::error::ErrorStack; |
8 | use crate::ssl::MidHandshakeSslStream; |
9 | use crate::x509::X509VerifyResult; |
10 | |
11 | /// An error code returned from SSL functions. |
12 | #[derive (Debug, Copy, Clone, PartialEq, Eq)] |
13 | pub struct ErrorCode(c_int); |
14 | |
15 | impl ErrorCode { |
16 | /// The SSL session has been closed. |
17 | pub const ZERO_RETURN: ErrorCode = ErrorCode(ffi::SSL_ERROR_ZERO_RETURN); |
18 | |
19 | /// An attempt to read data from the underlying socket returned `WouldBlock`. |
20 | /// |
21 | /// Wait for read readiness and retry the operation. |
22 | pub const WANT_READ: ErrorCode = ErrorCode(ffi::SSL_ERROR_WANT_READ); |
23 | |
24 | /// An attempt to write data to the underlying socket returned `WouldBlock`. |
25 | /// |
26 | /// Wait for write readiness and retry the operation. |
27 | pub const WANT_WRITE: ErrorCode = ErrorCode(ffi::SSL_ERROR_WANT_WRITE); |
28 | |
29 | /// A non-recoverable IO error occurred. |
30 | pub const SYSCALL: ErrorCode = ErrorCode(ffi::SSL_ERROR_SYSCALL); |
31 | |
32 | /// An error occurred in the SSL library. |
33 | pub const SSL: ErrorCode = ErrorCode(ffi::SSL_ERROR_SSL); |
34 | |
35 | /// The client hello callback indicated that it needed to be retried. |
36 | /// |
37 | /// Requires OpenSSL 1.1.1 or newer. |
38 | #[cfg (ossl111)] |
39 | pub const WANT_CLIENT_HELLO_CB: ErrorCode = ErrorCode(ffi::SSL_ERROR_WANT_CLIENT_HELLO_CB); |
40 | |
41 | pub fn from_raw(raw: c_int) -> ErrorCode { |
42 | ErrorCode(raw) |
43 | } |
44 | |
45 | #[allow (clippy::trivially_copy_pass_by_ref)] |
46 | pub fn as_raw(&self) -> c_int { |
47 | self.0 |
48 | } |
49 | } |
50 | |
51 | #[derive (Debug)] |
52 | pub(crate) enum InnerError { |
53 | Io(io::Error), |
54 | Ssl(ErrorStack), |
55 | } |
56 | |
57 | /// An SSL error. |
58 | #[derive (Debug)] |
59 | pub struct Error { |
60 | pub(crate) code: ErrorCode, |
61 | pub(crate) cause: Option<InnerError>, |
62 | } |
63 | |
64 | impl Error { |
65 | pub fn code(&self) -> ErrorCode { |
66 | self.code |
67 | } |
68 | |
69 | pub fn io_error(&self) -> Option<&io::Error> { |
70 | match self.cause { |
71 | Some(InnerError::Io(ref e)) => Some(e), |
72 | _ => None, |
73 | } |
74 | } |
75 | |
76 | pub fn into_io_error(self) -> Result<io::Error, Error> { |
77 | match self.cause { |
78 | Some(InnerError::Io(e)) => Ok(e), |
79 | _ => Err(self), |
80 | } |
81 | } |
82 | |
83 | pub fn ssl_error(&self) -> Option<&ErrorStack> { |
84 | match self.cause { |
85 | Some(InnerError::Ssl(ref e)) => Some(e), |
86 | _ => None, |
87 | } |
88 | } |
89 | } |
90 | |
91 | impl From<ErrorStack> for Error { |
92 | fn from(e: ErrorStack) -> Error { |
93 | Error { |
94 | code: ErrorCode::SSL, |
95 | cause: Some(InnerError::Ssl(e)), |
96 | } |
97 | } |
98 | } |
99 | |
100 | impl fmt::Display for Error { |
101 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
102 | match self.code { |
103 | ErrorCode::ZERO_RETURN => fmt.write_str(data:"the SSL session has been shut down" ), |
104 | ErrorCode::WANT_READ => match self.io_error() { |
105 | Some(_) => fmt.write_str(data:"a nonblocking read call would have blocked" ), |
106 | None => fmt.write_str(data:"the operation should be retried" ), |
107 | }, |
108 | ErrorCode::WANT_WRITE => match self.io_error() { |
109 | Some(_) => fmt.write_str(data:"a nonblocking write call would have blocked" ), |
110 | None => fmt.write_str(data:"the operation should be retried" ), |
111 | }, |
112 | ErrorCode::SYSCALL => match self.io_error() { |
113 | Some(err: &Error) => write!(fmt, " {}" , err), |
114 | None => fmt.write_str(data:"unexpected EOF" ), |
115 | }, |
116 | ErrorCode::SSL => match self.ssl_error() { |
117 | Some(e: &ErrorStack) => write!(fmt, " {}" , e), |
118 | None => fmt.write_str(data:"OpenSSL error" ), |
119 | }, |
120 | ErrorCode(code: i32) => write!(fmt, "unknown error code {}" , code), |
121 | } |
122 | } |
123 | } |
124 | |
125 | impl error::Error for Error { |
126 | fn source(&self) -> Option<&(dyn error::Error + 'static)> { |
127 | match self.cause { |
128 | Some(InnerError::Io(ref e: &Error)) => Some(e), |
129 | Some(InnerError::Ssl(ref e: &ErrorStack)) => Some(e), |
130 | None => None, |
131 | } |
132 | } |
133 | } |
134 | |
135 | /// An error or intermediate state after a TLS handshake attempt. |
136 | // FIXME overhaul |
137 | #[derive (Debug)] |
138 | pub enum HandshakeError<S> { |
139 | /// Setup failed. |
140 | SetupFailure(ErrorStack), |
141 | /// The handshake failed. |
142 | Failure(MidHandshakeSslStream<S>), |
143 | /// The handshake encountered a `WouldBlock` error midway through. |
144 | /// |
145 | /// This error will never be returned for blocking streams. |
146 | WouldBlock(MidHandshakeSslStream<S>), |
147 | } |
148 | |
149 | impl<S: fmt::Debug> StdError for HandshakeError<S> { |
150 | fn source(&self) -> Option<&(dyn StdError + 'static)> { |
151 | match *self { |
152 | HandshakeError::SetupFailure(ref e: &ErrorStack) => Some(e), |
153 | HandshakeError::Failure(ref s: &MidHandshakeSslStream) | HandshakeError::WouldBlock(ref s: &MidHandshakeSslStream) => Some(s.error()), |
154 | } |
155 | } |
156 | } |
157 | |
158 | impl<S: fmt::Debug> fmt::Display for HandshakeError<S> { |
159 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
160 | match *self { |
161 | HandshakeError::SetupFailure(ref e: &ErrorStack) => write!(f, "stream setup failed: {}" , e)?, |
162 | HandshakeError::Failure(ref s: &MidHandshakeSslStream) => { |
163 | write!(f, "the handshake failed: {}" , s.error())?; |
164 | let verify: X509VerifyResult = s.ssl().verify_result(); |
165 | if verify != X509VerifyResult::OK { |
166 | write!(f, ": {}" , verify)?; |
167 | } |
168 | } |
169 | HandshakeError::WouldBlock(ref s: &MidHandshakeSslStream) => { |
170 | write!(f, "the handshake was interrupted: {}" , s.error())?; |
171 | let verify: X509VerifyResult = s.ssl().verify_result(); |
172 | if verify != X509VerifyResult::OK { |
173 | write!(f, ": {}" , verify)?; |
174 | } |
175 | } |
176 | } |
177 | Ok(()) |
178 | } |
179 | } |
180 | |
181 | impl<S> From<ErrorStack> for HandshakeError<S> { |
182 | fn from(e: ErrorStack) -> HandshakeError<S> { |
183 | HandshakeError::SetupFailure(e) |
184 | } |
185 | } |
186 | |