1 // Copyright (c) 2023 Huawei Device Co., Ltd. 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 use core::fmt; 15 use std::error::Error; 16 use std::io; 17 18 use libc::c_int; 19 20 use super::MidHandshakeSslStream; 21 use crate::c_openssl::error::ErrorStack; 22 use crate::util::c_openssl::error::VerifyError; 23 24 #[derive(Debug)] 25 pub(crate) struct SslError { 26 pub(crate) code: SslErrorCode, 27 pub(crate) internal: Option<InternalError>, 28 } 29 30 #[derive(Debug)] 31 pub(crate) enum InternalError { 32 Io(io::Error), 33 Ssl(ErrorStack), 34 User(VerifyError), 35 } 36 37 impl SslError { code(&self) -> SslErrorCode38 pub(crate) fn code(&self) -> SslErrorCode { 39 self.code 40 } 41 into_io_error(self) -> Result<io::Error, SslError>42 pub(crate) fn into_io_error(self) -> Result<io::Error, SslError> { 43 match self.internal { 44 Some(InternalError::Io(e)) => Ok(e), 45 _ => Err(self), 46 } 47 } 48 get_io_error(&self) -> Option<&io::Error>49 pub(crate) fn get_io_error(&self) -> Option<&io::Error> { 50 match self.internal { 51 Some(InternalError::Io(ref e)) => Some(e), 52 _ => None, 53 } 54 } 55 } 56 57 impl Error for SslError { source(&self) -> Option<&(dyn Error + 'static)>58 fn source(&self) -> Option<&(dyn Error + 'static)> { 59 match self.internal { 60 Some(InternalError::Io(ref e)) => Some(e), 61 Some(InternalError::Ssl(ref e)) => Some(e), 62 Some(InternalError::User(ref e)) => Some(e), 63 None => None, 64 } 65 } 66 } 67 68 impl fmt::Display for SslError { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 70 match self.code { 71 SslErrorCode::ZERO_RETURN => write!(f, "SSL session has been closed"), 72 SslErrorCode::SYSCALL => { 73 if let Some(InternalError::Io(e)) = &self.internal { 74 write!(f, "SslCode[{}], IO Error: {}", self.code, e) 75 } else { 76 write!(f, "SslCode[{}], Unexpected EOF", self.code) 77 } 78 } 79 SslErrorCode::SSL => { 80 if let Some(InternalError::Ssl(e)) = &self.internal { 81 write!(f, "ErrorStack: {e}") 82 } else { 83 write!(f, "SslCode: [{}]", self.code) 84 } 85 } 86 SslErrorCode::WANT_READ => { 87 if let Some(InternalError::Io(e)) = &self.internal { 88 write!(f, "SslCode[{}], IO Error: {}", self.code, e) 89 } else { 90 write!( 91 f, 92 "SslCode[{}], Read operation should be retried", 93 self.code 94 ) 95 } 96 } 97 SslErrorCode::WANT_WRITE => { 98 if let Some(InternalError::Io(e)) = &self.internal { 99 write!(f, "SslCode[{}], IO Error: {}", self.code, e) 100 } else { 101 write!( 102 f, 103 "SslCode[{}], Write operation should be retried", 104 self.code 105 ) 106 } 107 } 108 _ => { 109 write!(f, "Unknown SslCode[{}]", self.code) 110 } 111 } 112 } 113 } 114 115 const SSL_ERROR_SSL: c_int = 1; 116 const SSL_ERROR_SYSCALL: c_int = 5; 117 const SSL_ERROR_WANT_READ: c_int = 2; 118 const SSL_ERROR_WANT_WRITE: c_int = 3; 119 const SSL_ERROR_ZERO_RETURN: c_int = 6; 120 121 #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] 122 pub(crate) struct SslErrorCode(c_int); 123 124 impl SslErrorCode { 125 pub(crate) const ZERO_RETURN: SslErrorCode = SslErrorCode(SSL_ERROR_ZERO_RETURN); 126 pub(crate) const WANT_READ: SslErrorCode = SslErrorCode(SSL_ERROR_WANT_READ); 127 pub(crate) const WANT_WRITE: SslErrorCode = SslErrorCode(SSL_ERROR_WANT_WRITE); 128 pub(crate) const SYSCALL: SslErrorCode = SslErrorCode(SSL_ERROR_SYSCALL); 129 pub(crate) const SSL: SslErrorCode = SslErrorCode(SSL_ERROR_SSL); 130 from_int(err: c_int) -> SslErrorCode131 pub(crate) fn from_int(err: c_int) -> SslErrorCode { 132 SslErrorCode(err) 133 } 134 } 135 136 impl fmt::Display for SslErrorCode { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 138 write!(f, "{}", self.0) 139 } 140 } 141 142 #[derive(Debug)] 143 pub(crate) enum HandshakeError<S> { 144 SetupFailure(ErrorStack), 145 #[allow(dead_code)] 146 Failure(MidHandshakeSslStream<S>), 147 #[allow(dead_code)] 148 WouldBlock(MidHandshakeSslStream<S>), 149 } 150 151 impl<S> From<ErrorStack> for HandshakeError<S> { from(e: ErrorStack) -> HandshakeError<S>152 fn from(e: ErrorStack) -> HandshakeError<S> { 153 HandshakeError::SetupFailure(e) 154 } 155 } 156 157 impl<S: fmt::Debug> Error for HandshakeError<S> { source(&self) -> Option<&(dyn Error + 'static)>158 fn source(&self) -> Option<&(dyn Error + 'static)> { 159 match *self { 160 HandshakeError::SetupFailure(ref e) => Some(e), 161 HandshakeError::Failure(ref s) | HandshakeError::WouldBlock(ref s) => Some(s.error()), 162 } 163 } 164 } 165 166 impl<S: fmt::Debug> fmt::Display for HandshakeError<S> { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result167 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 168 match *self { 169 HandshakeError::SetupFailure(ref e) => write!(f, "Stream setup failed: {e}")?, 170 HandshakeError::Failure(ref s) => { 171 write!(f, "Handshake failed: {}", s.error())?; 172 } 173 HandshakeError::WouldBlock(ref s) => { 174 write!(f, "Handshake was interrupted: {}", s.error())?; 175 } 176 } 177 Ok(()) 178 } 179 } 180 181 #[cfg(test)] 182 mod ut_ssl_error { 183 use std::error::Error; 184 use std::io; 185 186 use crate::util::c_openssl::error::VerifyKind::PubKeyPinning; 187 use crate::util::c_openssl::error::{ErrorStack, VerifyError}; 188 use crate::util::c_openssl::ssl::{InternalError, SslError, SslErrorCode}; 189 190 /// UT test cases for `SslErrorCode::from_int`. 191 /// 192 /// # Brief 193 /// 1. Creates a `SslErrorCode` by calling `Redirect::from_int`. 194 /// 2. Checks if the results are correct. 195 #[test] ut_ssl_error_code_from_int()196 fn ut_ssl_error_code_from_int() { 197 let v_6 = SslErrorCode::from_int(6); 198 assert_eq!(v_6, SslErrorCode::ZERO_RETURN); 199 assert!(v_6 > SslErrorCode::WANT_READ); 200 assert_eq!(v_6.clone(), v_6); 201 assert_eq!(format!("{v_6}"), "6"); 202 } 203 204 /// UT test cases for `SslError::into_io_error`. 205 /// 206 /// # Brief 207 /// 1. Creates a `SslErrorCode`. 208 /// 2. Checks if the results are correct. 209 #[test] ut_ssl_error_into_io_error()210 fn ut_ssl_error_into_io_error() { 211 let ssl_error = SslError { 212 code: SslErrorCode::ZERO_RETURN, 213 internal: Some(InternalError::Io(io::Error::from( 214 io::ErrorKind::BrokenPipe, 215 ))), 216 }; 217 assert!(ssl_error.get_io_error().is_some()); 218 assert!(ssl_error.into_io_error().is_ok()); 219 let ssl_error = SslError { 220 code: SslErrorCode::ZERO_RETURN, 221 internal: None, 222 }; 223 assert!(ssl_error.get_io_error().is_none()); 224 assert!(ssl_error.into_io_error().is_err()); 225 } 226 227 /// UT test cases for `SslError::source`. 228 /// 229 /// # Brief 230 /// 1. Creates a `SslErrorCode`. 231 /// 2. Checks if the results are correct. 232 #[test] ut_ssl_error_source()233 fn ut_ssl_error_source() { 234 let ssl_error = SslError { 235 code: SslErrorCode::ZERO_RETURN, 236 internal: Some(InternalError::Io(io::Error::from( 237 io::ErrorKind::BrokenPipe, 238 ))), 239 }; 240 assert!(ssl_error.source().is_some()); 241 let ssl_error = SslError { 242 code: SslErrorCode::ZERO_RETURN, 243 internal: Some(InternalError::Ssl(ErrorStack::get())), 244 }; 245 assert!(ssl_error.source().is_some()); 246 let ssl_error = SslError { 247 code: SslErrorCode::ZERO_RETURN, 248 internal: None, 249 }; 250 assert!(ssl_error.source().is_none()); 251 let ssl_error = SslError { 252 code: SslErrorCode::ZERO_RETURN, 253 internal: Some(InternalError::User(VerifyError::from_msg( 254 PubKeyPinning, 255 "error", 256 ))), 257 }; 258 assert!(ssl_error.source().is_some()); 259 } 260 261 /// UT test cases for `SslError::fmt`. 262 /// 263 /// # Brief 264 /// 1. Creates a `SslErrorCode`. 265 /// 2. Checks if the results are correct. 266 #[test] ut_ssl_error_fmt()267 fn ut_ssl_error_fmt() { 268 let ssl_error = SslError { 269 code: SslErrorCode::ZERO_RETURN, 270 internal: Some(InternalError::Io(io::Error::from( 271 io::ErrorKind::BrokenPipe, 272 ))), 273 }; 274 assert_eq!(format!("{}", ssl_error), "SSL session has been closed"); 275 276 let ssl_error = SslError { 277 code: SslErrorCode::SYSCALL, 278 internal: Some(InternalError::Io(io::Error::from( 279 io::ErrorKind::BrokenPipe, 280 ))), 281 }; 282 assert_eq!( 283 format!("{}", ssl_error), 284 format!( 285 "SslCode[5], IO Error: {}", 286 io::Error::from(io::ErrorKind::BrokenPipe) 287 ) 288 ); 289 290 let ssl_error = SslError { 291 code: SslErrorCode::SYSCALL, 292 internal: None, 293 }; 294 assert_eq!( 295 format!("{}", ssl_error), 296 "SslCode[5], Unexpected EOF".to_string() 297 ); 298 299 let ssl_error = SslError { 300 code: SslErrorCode::SSL, 301 internal: None, 302 }; 303 assert_eq!(format!("{}", ssl_error), "SslCode: [1]".to_string()); 304 305 let error_stack = ErrorStack::get(); 306 let ssl_error = SslError { 307 code: SslErrorCode::SSL, 308 internal: Some(InternalError::Ssl(error_stack.clone())), 309 }; 310 let error_stack = format!("{error_stack}"); 311 assert_eq!( 312 format!("{}", ssl_error), 313 format!("ErrorStack: {}", error_stack) 314 ); 315 316 let ssl_error = SslError { 317 code: SslErrorCode::WANT_READ, 318 internal: Some(InternalError::Io(io::Error::from( 319 io::ErrorKind::BrokenPipe, 320 ))), 321 }; 322 assert_eq!( 323 format!("{}", ssl_error), 324 format!( 325 "SslCode[2], IO Error: {}", 326 io::Error::from(io::ErrorKind::BrokenPipe) 327 ) 328 ); 329 330 let ssl_error = SslError { 331 code: SslErrorCode::WANT_READ, 332 internal: None, 333 }; 334 assert_eq!( 335 format!("{}", ssl_error), 336 "SslCode[2], Read operation should be retried".to_string() 337 ); 338 339 let ssl_error = SslError { 340 code: SslErrorCode::WANT_WRITE, 341 internal: Some(InternalError::Io(io::Error::from( 342 io::ErrorKind::BrokenPipe, 343 ))), 344 }; 345 assert_eq!( 346 format!("{}", ssl_error), 347 format!( 348 "SslCode[3], IO Error: {}", 349 io::Error::from(io::ErrorKind::BrokenPipe) 350 ) 351 ); 352 353 let ssl_error = SslError { 354 code: SslErrorCode::WANT_WRITE, 355 internal: None, 356 }; 357 assert_eq!( 358 format!("{}", ssl_error), 359 "SslCode[3], Write operation should be retried".to_string() 360 ); 361 362 let ssl_error = SslError { 363 code: SslErrorCode::from_int(15), 364 internal: None, 365 }; 366 assert_eq!(format!("{}", ssl_error), "Unknown SslCode[15]".to_string()); 367 } 368 369 /// UT test cases for `Debug` of `SslError`. 370 /// 371 /// # Brief 372 /// 1. Creates a `SslErrorCode`. 373 /// 2. Checks if the results are correct. 374 #[test] ut_ssl_error_debug()375 fn ut_ssl_error_debug() { 376 let ssl_error = SslError { 377 code: SslErrorCode::from_int(15), 378 internal: None, 379 }; 380 assert_eq!( 381 format!("{:?}", ssl_error), 382 "SslError { code: SslErrorCode(15), internal: None }".to_string() 383 ); 384 } 385 386 /// UT test cases for `Debug` of `InternalError`. 387 /// 388 /// # Brief 389 /// 1. Creates a `InternalError`. 390 /// 2. Checks if the results are correct. 391 #[test] ut_internal_error_debug()392 fn ut_internal_error_debug() { 393 let internal_error = InternalError::Ssl(ErrorStack::get()); 394 assert_eq!( 395 format!("{:?}", internal_error), 396 "Ssl(ErrorStack([]))".to_string() 397 ); 398 } 399 } 400