• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
from_raw(raw: c_int) -> ErrorCode41     pub fn from_raw(raw: c_int) -> ErrorCode {
42         ErrorCode(raw)
43     }
44 
45     #[allow(clippy::trivially_copy_pass_by_ref)]
as_raw(&self) -> c_int46     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 {
code(&self) -> ErrorCode65     pub fn code(&self) -> ErrorCode {
66         self.code
67     }
68 
io_error(&self) -> Option<&io::Error>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 
into_io_error(self) -> Result<io::Error, Error>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 
ssl_error(&self) -> Option<&ErrorStack>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 {
from(e: ErrorStack) -> Error92     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 {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result101     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
102         match self.code {
103             ErrorCode::ZERO_RETURN => fmt.write_str("the SSL session has been shut down"),
104             ErrorCode::WANT_READ => match self.io_error() {
105                 Some(_) => fmt.write_str("a nonblocking read call would have blocked"),
106                 None => fmt.write_str("the operation should be retried"),
107             },
108             ErrorCode::WANT_WRITE => match self.io_error() {
109                 Some(_) => fmt.write_str("a nonblocking write call would have blocked"),
110                 None => fmt.write_str("the operation should be retried"),
111             },
112             ErrorCode::SYSCALL => match self.io_error() {
113                 Some(err) => write!(fmt, "{}", err),
114                 None => fmt.write_str("unexpected EOF"),
115             },
116             ErrorCode::SSL => match self.ssl_error() {
117                 Some(e) => write!(fmt, "{}", e),
118                 None => fmt.write_str("OpenSSL error"),
119             },
120             ErrorCode(code) => write!(fmt, "unknown error code {}", code),
121         }
122     }
123 }
124 
125 impl error::Error for Error {
source(&self) -> Option<&(dyn error::Error + 'static)>126     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
127         match self.cause {
128             Some(InnerError::Io(ref e)) => Some(e),
129             Some(InnerError::Ssl(ref e)) => 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> {
source(&self) -> Option<&(dyn StdError + 'static)>150     fn source(&self) -> Option<&(dyn StdError + 'static)> {
151         match *self {
152             HandshakeError::SetupFailure(ref e) => Some(e),
153             HandshakeError::Failure(ref s) | HandshakeError::WouldBlock(ref s) => Some(s.error()),
154         }
155     }
156 }
157 
158 impl<S: fmt::Debug> fmt::Display for HandshakeError<S> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result159     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
160         match *self {
161             HandshakeError::SetupFailure(ref e) => write!(f, "stream setup failed: {}", e)?,
162             HandshakeError::Failure(ref s) => {
163                 write!(f, "the handshake failed: {}", s.error())?;
164                 let verify = s.ssl().verify_result();
165                 if verify != X509VerifyResult::OK {
166                     write!(f, ": {}", verify)?;
167                 }
168             }
169             HandshakeError::WouldBlock(ref s) => {
170                 write!(f, "the handshake was interrupted: {}", s.error())?;
171                 let verify = 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> {
from(e: ErrorStack) -> HandshakeError<S>182     fn from(e: ErrorStack) -> HandshakeError<S> {
183         HandshakeError::SetupFailure(e)
184     }
185 }
186