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