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