1use crate::ffi;
2use libc::c_int;
3use std::error;
4use std::error::Error as StdError;
5use std::fmt;
6use std::io;
7
8use crate::error::ErrorStack;
9use crate::ssl::MidHandshakeSslStream;
10
11#[derive(Debug, Copy, Clone, PartialEq, Eq)]
13pub struct ErrorCode(c_int);
14
15impl ErrorCode {
16 pub const NONE: ErrorCode = ErrorCode(ffi::SSL_ERROR_NONE);
18
19 pub const ZERO_RETURN: ErrorCode = ErrorCode(ffi::SSL_ERROR_ZERO_RETURN);
21
22 pub const WANT_READ: ErrorCode = ErrorCode(ffi::SSL_ERROR_WANT_READ);
26
27 pub const WANT_WRITE: ErrorCode = ErrorCode(ffi::SSL_ERROR_WANT_WRITE);
31
32 pub const WANT_X509_LOOKUP: ErrorCode = ErrorCode(ffi::SSL_ERROR_WANT_X509_LOOKUP);
33
34 pub const PENDING_SESSION: ErrorCode = ErrorCode(ffi::SSL_ERROR_PENDING_SESSION);
35
36 pub const PENDING_CERTIFICATE: ErrorCode = ErrorCode(ffi::SSL_ERROR_PENDING_CERTIFICATE);
37
38 pub const WANT_CERTIFICATE_VERIFY: ErrorCode =
39 ErrorCode(ffi::SSL_ERROR_WANT_CERTIFICATE_VERIFY);
40
41 pub const WANT_PRIVATE_KEY_OPERATION: ErrorCode =
42 ErrorCode(ffi::SSL_ERROR_WANT_PRIVATE_KEY_OPERATION);
43
44 pub const PENDING_TICKET: ErrorCode = ErrorCode(ffi::SSL_ERROR_PENDING_TICKET);
45
46 pub const SYSCALL: ErrorCode = ErrorCode(ffi::SSL_ERROR_SYSCALL);
48
49 pub const SSL: ErrorCode = ErrorCode(ffi::SSL_ERROR_SSL);
51
52 pub fn from_raw(raw: c_int) -> ErrorCode {
53 ErrorCode(raw)
54 }
55
56 #[allow(clippy::trivially_copy_pass_by_ref)]
57 pub fn as_raw(&self) -> c_int {
58 self.0
59 }
60}
61
62#[derive(Debug)]
63pub(crate) enum InnerError {
64 Io(io::Error),
65 Ssl(ErrorStack),
66}
67
68#[derive(Debug)]
70pub struct Error {
71 pub(crate) code: ErrorCode,
72 pub(crate) cause: Option<InnerError>,
73}
74
75impl Error {
76 pub fn code(&self) -> ErrorCode {
77 self.code
78 }
79
80 pub fn io_error(&self) -> Option<&io::Error> {
81 match self.cause {
82 Some(InnerError::Io(ref e)) => Some(e),
83 _ => None,
84 }
85 }
86
87 pub fn into_io_error(self) -> Result<io::Error, Error> {
88 match self.cause {
89 Some(InnerError::Io(e)) => Ok(e),
90 _ => Err(self),
91 }
92 }
93
94 pub fn ssl_error(&self) -> Option<&ErrorStack> {
95 match self.cause {
96 Some(InnerError::Ssl(ref e)) => Some(e),
97 _ => None,
98 }
99 }
100
101 pub fn would_block(&self) -> bool {
102 matches!(
103 self.code,
104 ErrorCode::WANT_READ
105 | ErrorCode::WANT_WRITE
106 | ErrorCode::WANT_X509_LOOKUP
107 | ErrorCode::PENDING_SESSION
108 | ErrorCode::PENDING_CERTIFICATE
109 | ErrorCode::WANT_PRIVATE_KEY_OPERATION
110 | ErrorCode::WANT_CERTIFICATE_VERIFY
111 | ErrorCode::PENDING_TICKET
112 )
113 }
114}
115
116impl From<ErrorStack> for Error {
117 fn from(e: ErrorStack) -> Error {
118 Error {
119 code: ErrorCode::SSL,
120 cause: Some(InnerError::Ssl(e)),
121 }
122 }
123}
124
125impl fmt::Display for Error {
126 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
127 match self.code {
128 ErrorCode::ZERO_RETURN => fmt.write_str("the SSL session has been shut down"),
129 ErrorCode::WANT_READ => match self.io_error() {
130 Some(_) => fmt.write_str("a nonblocking read call would have blocked"),
131 None => fmt.write_str("the operation should be retried"),
132 },
133 ErrorCode::WANT_WRITE => match self.io_error() {
134 Some(_) => fmt.write_str("a nonblocking write call would have blocked"),
135 None => fmt.write_str("the operation should be retried"),
136 },
137 ErrorCode::SYSCALL => match self.io_error() {
138 Some(err) => write!(fmt, "{}", err),
139 None => fmt.write_str("unexpected EOF"),
140 },
141 ErrorCode::SSL => match self.ssl_error() {
142 Some(e) => write!(fmt, "{}", e),
143 None => fmt.write_str("unknown BoringSSL error"),
144 },
145 ErrorCode(code) => write!(fmt, "unknown error code {}", code),
146 }
147 }
148}
149
150impl error::Error for Error {
151 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
152 match self.cause {
153 Some(InnerError::Io(ref e)) => Some(e),
154 Some(InnerError::Ssl(ref e)) => Some(e),
155 None => None,
156 }
157 }
158}
159
160#[derive(Debug)]
163pub enum HandshakeError<S> {
164 SetupFailure(ErrorStack),
166 Failure(MidHandshakeSslStream<S>),
168 WouldBlock(MidHandshakeSslStream<S>),
172}
173
174impl<S: fmt::Debug> StdError for HandshakeError<S> {
175 fn source(&self) -> Option<&(dyn StdError + 'static)> {
176 match *self {
177 HandshakeError::SetupFailure(ref e) => Some(e),
178 HandshakeError::Failure(ref s) | HandshakeError::WouldBlock(ref s) => Some(s.error()),
179 }
180 }
181}
182
183impl<S> fmt::Display for HandshakeError<S> {
184 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
185 match *self {
186 HandshakeError::SetupFailure(ref e) => {
187 write!(f, "TLS stream setup failed {}", e)
188 }
189 HandshakeError::Failure(ref s) => fmt_mid_handshake_error(s, f, "TLS handshake failed"),
190 HandshakeError::WouldBlock(ref s) => {
191 fmt_mid_handshake_error(s, f, "TLS handshake interrupted")
192 }
193 }
194 }
195}
196
197fn fmt_mid_handshake_error(
198 s: &MidHandshakeSslStream<impl Sized>,
199 f: &mut fmt::Formatter,
200 prefix: &str,
201) -> fmt::Result {
202 #[cfg(feature = "rpk")]
203 if s.ssl().ssl_context().is_rpk() {
204 write!(f, "{}", prefix)?;
205 return write!(f, " {}", s.error());
206 }
207
208 match s.ssl().verify_result() {
209 Ok(()) => write!(f, "{}", prefix)?,
210 Err(verify) => write!(f, "{}: cert verification failed - {}", prefix, verify)?,
211 }
212
213 write!(f, " {}", s.error())
214}
215
216impl<S> From<ErrorStack> for HandshakeError<S> {
217 fn from(e: ErrorStack) -> HandshakeError<S> {
218 HandshakeError::SetupFailure(e)
219 }
220}