boring_imp/ssl/
error.rs

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/// An error code returned from SSL functions.
12#[derive(Debug, Copy, Clone, PartialEq, Eq)]
13pub struct ErrorCode(c_int);
14
15impl ErrorCode {
16    /// No error.
17    pub const NONE: ErrorCode = ErrorCode(ffi::SSL_ERROR_NONE);
18
19    /// The SSL session has been closed.
20    pub const ZERO_RETURN: ErrorCode = ErrorCode(ffi::SSL_ERROR_ZERO_RETURN);
21
22    /// An attempt to read data from the underlying socket returned `WouldBlock`.
23    ///
24    /// Wait for read readiness and retry the operation.
25    pub const WANT_READ: ErrorCode = ErrorCode(ffi::SSL_ERROR_WANT_READ);
26
27    /// An attempt to write data to the underlying socket returned `WouldBlock`.
28    ///
29    /// Wait for write readiness and retry the operation.
30    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    /// A non-recoverable IO error occurred.
47    pub const SYSCALL: ErrorCode = ErrorCode(ffi::SSL_ERROR_SYSCALL);
48
49    /// An error occurred in the SSL library.
50    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/// An SSL error.
69#[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/// An error or intermediate state after a TLS handshake attempt.
161// FIXME overhaul
162#[derive(Debug)]
163pub enum HandshakeError<S> {
164    /// Setup failed.
165    SetupFailure(ErrorStack),
166    /// The handshake failed.
167    Failure(MidHandshakeSslStream<S>),
168    /// The handshake encountered a `WouldBlock` error midway through.
169    ///
170    /// This error will never be returned for blocking streams.
171    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}