• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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::any::Any;
15 use core::marker::PhantomData;
16 use core::panic::AssertUnwindSafe;
17 use core::{ptr, slice};
18 use std::io::{self, Read, Write};
19 use std::panic::catch_unwind;
20 
21 use libc::{c_char, c_int, c_long, c_void, strlen};
22 
23 use super::error::ErrorStack;
24 use super::ffi::bio::{
25     BIO_clear_flags, BIO_free_all, BIO_get_data, BIO_meth_free, BIO_meth_new, BIO_meth_set_create,
26     BIO_meth_set_ctrl, BIO_meth_set_destroy, BIO_meth_set_puts, BIO_meth_set_read,
27     BIO_meth_set_write, BIO_new, BIO_new_mem_buf, BIO_set_data, BIO_set_flags, BIO_set_init, BIO,
28     BIO_METHOD,
29 };
30 use super::{check_ptr, ssl_init};
31 
32 #[derive(Debug)]
33 pub struct Bio(*mut BIO);
34 
35 impl Drop for Bio {
drop(&mut self)36     fn drop(&mut self) {
37         unsafe {
38             BIO_free_all(self.0);
39         }
40     }
41 }
42 
43 #[derive(Debug)]
44 pub struct BioSlice<'a>(*mut BIO, PhantomData<&'a [u8]>);
45 
46 impl<'a> BioSlice<'a> {
from_byte(buf: &'a [u8]) -> Result<BioSlice<'a>, ErrorStack>47     pub(crate) fn from_byte(buf: &'a [u8]) -> Result<BioSlice<'a>, ErrorStack> {
48         unsafe {
49             ssl_init();
50             let bio = check_ptr(BIO_new_mem_buf(
51                 buf.as_ptr() as *const _,
52                 buf.len() as c_int,
53             ))?;
54             Ok(BioSlice(bio, PhantomData))
55         }
56     }
57 
as_ptr(&self) -> *mut BIO58     pub(crate) fn as_ptr(&self) -> *mut BIO {
59         self.0
60     }
61 }
62 
63 impl<'a> Drop for BioSlice<'a> {
drop(&mut self)64     fn drop(&mut self) {
65         unsafe { BIO_free_all(self.0) }
66     }
67 }
68 
69 const BIO_TYPE_NONE: c_int = 0;
70 
71 const BIO_CTRL_FLUSH: c_int = 11;
72 const BIO_CTRL_DGRAM_QUERY: c_int = 40;
73 
74 const BIO_FLAGS_READ: c_int = 0x01;
75 const BIO_FLAGS_WRITE: c_int = 0x02;
76 const BIO_FLAGS_IO_SPECIAL: c_int = 0x04;
77 const BIO_FLAGS_SHOULD_RETRY: c_int = 0x08;
78 const BIO_FLAGS_RWS: c_int = BIO_FLAGS_READ | BIO_FLAGS_WRITE | BIO_FLAGS_IO_SPECIAL;
79 
80 #[derive(Debug)]
81 pub struct BioMethodInner(*mut BIO_METHOD);
82 
83 impl BioMethodInner {
new<S: Read + Write>() -> Result<BioMethodInner, ErrorStack>84     fn new<S: Read + Write>() -> Result<BioMethodInner, ErrorStack> {
85         unsafe {
86             let ptr = check_ptr(BIO_meth_new(BIO_TYPE_NONE, b"rust\0".as_ptr() as *const _))?;
87             let bio_method = BioMethodInner(ptr);
88 
89             BIO_meth_set_write(ptr, bwrite::<S>);
90             BIO_meth_set_read(ptr, bread::<S>);
91             BIO_meth_set_puts(ptr, bputs::<S>);
92             BIO_meth_set_ctrl(ptr, ctrl::<S>);
93             BIO_meth_set_create(ptr, create);
94             BIO_meth_set_destroy(ptr, destroy::<S>);
95 
96             Ok(bio_method)
97         }
98     }
99 
get(&self) -> *mut BIO_METHOD100     fn get(&self) -> *mut BIO_METHOD {
101         self.0
102     }
103 }
104 
105 unsafe impl Sync for BioMethod {}
106 unsafe impl Send for BioMethod {}
107 
108 impl Drop for BioMethodInner {
drop(&mut self)109     fn drop(&mut self) {
110         unsafe { BIO_meth_free(self.0) }
111     }
112 }
113 
114 #[derive(Debug)]
115 pub struct BioMethod(BioMethodInner);
116 
117 impl BioMethod {
new<S: Read + Write>() -> Result<BioMethod, ErrorStack>118     fn new<S: Read + Write>() -> Result<BioMethod, ErrorStack> {
119         let method = BioMethodInner::new::<S>()?;
120         Ok(BioMethod(method))
121     }
122 
get(&self) -> *mut BIO_METHOD123     fn get(&self) -> *mut BIO_METHOD {
124         self.0.get()
125     }
126 }
127 
128 pub(crate) struct StreamState<S> {
129     pub(crate) stream: S,
130     pub(crate) error: Option<io::Error>,
131     pub(crate) panic: Option<Box<dyn Any + Send>>,
132     pub(crate) dtls_mtu_size: c_long,
133 }
get_state<'a, S: 'a>(bio: *mut BIO) -> &'a mut StreamState<S>134 unsafe fn get_state<'a, S: 'a>(bio: *mut BIO) -> &'a mut StreamState<S> {
135     &mut *(BIO_get_data(bio) as *mut _)
136 }
137 
get_error<S>(bio: *mut BIO) -> Option<io::Error>138 pub(crate) unsafe fn get_error<S>(bio: *mut BIO) -> Option<io::Error> {
139     let state = get_state::<S>(bio);
140     state.error.take()
141 }
142 
get_panic<S>(bio: *mut BIO) -> Option<Box<dyn Any + Send>>143 pub(crate) unsafe fn get_panic<S>(bio: *mut BIO) -> Option<Box<dyn Any + Send>> {
144     let state = get_state::<S>(bio);
145     state.panic.take()
146 }
147 
get_stream_ref<'a, S: 'a>(bio: *mut BIO) -> &'a S148 pub(crate) unsafe fn get_stream_ref<'a, S: 'a>(bio: *mut BIO) -> &'a S {
149     let state: &'a StreamState<S> = &*(BIO_get_data(bio) as *const StreamState<S>);
150     &state.stream
151 }
152 
get_stream_mut<'a, S: 'a>(bio: *mut BIO) -> &'a mut S153 pub(crate) unsafe fn get_stream_mut<'a, S: 'a>(bio: *mut BIO) -> &'a mut S {
154     &mut get_state(bio).stream
155 }
156 
new<S: Read + Write>(stream: S) -> Result<(*mut BIO, BioMethod), ErrorStack>157 pub(crate) fn new<S: Read + Write>(stream: S) -> Result<(*mut BIO, BioMethod), ErrorStack> {
158     let bio_method = BioMethod::new::<S>()?;
159 
160     let stream_state = Box::new(StreamState {
161         stream,
162         error: None,
163         panic: None,
164         dtls_mtu_size: 0,
165     });
166 
167     unsafe {
168         let bio = check_ptr(BIO_new(bio_method.get()))?;
169         BIO_set_data(bio, Box::into_raw(stream_state) as *mut _);
170         BIO_set_init(bio, 1);
171 
172         Ok((bio, bio_method))
173     }
174 }
175 
retry_error(err: &io::Error) -> bool176 fn retry_error(err: &io::Error) -> bool {
177     matches!(
178         err.kind(),
179         io::ErrorKind::WouldBlock | io::ErrorKind::NotConnected
180     )
181 }
182 
ctrl<S: Write>( bio: *mut BIO, ctrl_cmd: c_int, _num: c_long, _ptr: *mut c_void, ) -> c_long183 unsafe extern "C" fn ctrl<S: Write>(
184     bio: *mut BIO,
185     ctrl_cmd: c_int,
186     _num: c_long,
187     _ptr: *mut c_void,
188 ) -> c_long {
189     let state = get_state::<S>(bio);
190 
191     if ctrl_cmd == BIO_CTRL_FLUSH {
192         match catch_unwind(AssertUnwindSafe(|| state.stream.flush())) {
193             Ok(Err(err)) => {
194                 state.error = Some(err);
195                 0
196             }
197             Ok(Ok(())) => 1,
198             Err(err) => {
199                 state.panic = Some(err);
200                 0
201             }
202         }
203     } else if ctrl_cmd == BIO_CTRL_DGRAM_QUERY {
204         state.dtls_mtu_size
205     } else {
206         0
207     }
208 }
209 
210 #[allow(non_snake_case)]
BIO_set_num(_bio: *mut BIO, _num: c_int)211 unsafe fn BIO_set_num(_bio: *mut BIO, _num: c_int) {}
212 
create(bio: *mut BIO) -> c_int213 unsafe extern "C" fn create(bio: *mut BIO) -> c_int {
214     BIO_set_init(bio, 0);
215     BIO_set_flags(bio, 0);
216     BIO_set_num(bio, 0);
217     BIO_set_data(bio, ptr::null_mut());
218     1
219 }
220 
destroy<S>(bio: *mut BIO) -> c_int221 unsafe extern "C" fn destroy<S>(bio: *mut BIO) -> c_int {
222     if bio.is_null() {
223         return 0;
224     }
225     let data = BIO_get_data(bio);
226     drop(Box::<StreamState<S>>::from_raw(data as *mut _));
227     BIO_set_init(bio, 0);
228     BIO_set_data(bio, ptr::null_mut());
229     1
230 }
231 
232 macro_rules! catch_unwind_bio {
233     ($io: expr, $flag: expr, $bio: expr, $state: expr) => {
234         match catch_unwind(AssertUnwindSafe(|| $io)) {
235             Ok(Err(err)) => {
236                 if retry_error(&err) {
237                     BIO_set_flags($bio, BIO_FLAGS_SHOULD_RETRY | $flag)
238                 }
239                 $state.error = Some(err);
240                 -1
241             }
242             Ok(Ok(len)) => len as c_int,
243             Err(err) => {
244                 $state.panic = Some(err);
245                 -1
246             }
247         }
248     };
249 }
250 
bwrite<S: Write>(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int251 unsafe extern "C" fn bwrite<S: Write>(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int {
252     BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_RWS);
253 
254     let state = get_state::<S>(bio);
255     if len < 0 {
256         state.error = Some(io::Error::from(io::ErrorKind::InvalidInput));
257         return -1;
258     }
259 
260     let buf = slice::from_raw_parts(buf as *const _, len as usize);
261     catch_unwind_bio!(state.stream.write(buf), BIO_FLAGS_WRITE, bio, state)
262 }
263 
bread<S: Read>(bio: *mut BIO, buf: *mut c_char, len: c_int) -> c_int264 unsafe extern "C" fn bread<S: Read>(bio: *mut BIO, buf: *mut c_char, len: c_int) -> c_int {
265     BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_RWS);
266 
267     let state = get_state::<S>(bio);
268     let buf = slice::from_raw_parts_mut(buf as *mut _, len as usize);
269 
270     catch_unwind_bio!(state.stream.read(buf), BIO_FLAGS_READ, bio, state)
271 }
272 
bputs<S: Write>(bio: *mut BIO, buf: *const c_char) -> c_int273 unsafe extern "C" fn bputs<S: Write>(bio: *mut BIO, buf: *const c_char) -> c_int {
274     bwrite::<S>(bio, buf, strlen(buf) as c_int)
275 }
276 
277 #[cfg(test)]
278 mod ut_bio_slice {
279     use super::*;
280 
281     /// UT test case for `BioSlice::from_byte`.
282     ///
283     /// # Brief
284     /// 1. Calls `BioSlice::from_byte` with a byte slice.
285     /// 2. Verifies if the slice is created successfully.
286     /// 3. Retrieves the pointer.
287     /// 4. Checks if the pointer is not null;
288     #[test]
ut_from_byte()289     fn ut_from_byte() {
290         let data = b"TEST";
291         let slice = BioSlice::from_byte(data);
292         assert!(slice.is_ok());
293         let ptr = slice.unwrap().as_ptr();
294         assert!(!ptr.is_null());
295     }
296 }
297 
298 #[cfg(test)]
299 mod ut_bio_method_inner {
300     use std::io::Cursor;
301 
302     use super::*;
303 
304     /// UT test case for `BioMethodInner::new` and `BioMethodInner::get`.
305     ///
306     /// # Brief
307     /// 1. Creates a new `BioMethodInner` and check it successfully.
308     /// 2. Checks if the internal pointer is not null.
309     #[test]
ut_new_get()310     fn ut_new_get() {
311         let inner = BioMethodInner::new::<Cursor<Vec<u8>>>();
312         assert!(inner.is_ok());
313         let inner = inner.unwrap();
314         assert!(!inner.get().is_null());
315         drop(inner);
316     }
317 }
318 
319 #[cfg(test)]
320 mod ut_bio_method {
321     use std::io::Cursor;
322 
323     use super::*;
324 
325     /// UT test case for `BioMethod::new` and `BioMethod::get`.
326     ///
327     /// # Brief
328     /// 1. Creates a new `BioMethod` and check it successfully.
329     /// 2. Checks if the internal pointer is not null.
330     #[test]
ut_new_get()331     fn ut_new_get() {
332         let method = BioMethod::new::<Cursor<Vec<u8>>>();
333         assert!(method.is_ok());
334         let method = method.unwrap();
335         assert!(!method.get().is_null());
336     }
337 }
338 
339 #[cfg(test)]
340 mod ut_bio {
341     use std::io::Cursor;
342 
343     use super::*;
344 
345     /// UT test case for `Bio::new`.
346     ///
347     /// # Brief
348     /// 1. Create a BIO with a cursor stream.
349     /// 2. Verify if the BIO is created successfully.
350     #[test]
ut_new()351     fn ut_new() {
352         let stream = Cursor::new(vec![0u8; 10]);
353         let bio = new(stream);
354         assert!(bio.is_ok());
355         let (bio, _bio_method) = bio.unwrap();
356         unsafe {
357             BIO_free_all(bio);
358         }
359     }
360 
361     /// UT test case for `Bio::get_state`.
362     ///
363     /// # Brief
364     /// 1. Create a BIO and retrieve the BIO state.
365     /// 2. Check if the stream length matches the expected value.
366     #[test]
ut_get_state()367     fn ut_get_state() {
368         let stream = Cursor::new(vec![0u8; 10]);
369         let (bio, _method) = new(stream).unwrap();
370         unsafe {
371             let state = get_state::<Cursor<Vec<u8>>>(bio);
372             assert_eq!(state.stream.get_ref().len(), 10);
373             BIO_free_all(bio);
374         }
375     }
376 
377     /// UT test case for `BIO::get_error`.
378     ///
379     /// # Brief
380     /// 1. Calls `get_error` to retrieve the error state.
381     /// 2. Verify that errors is as expected.
382     #[test]
ut_get_error()383     fn ut_get_error() {
384         let stream = Cursor::new(vec![0u8; 10]);
385         let (bio, _method) = new(stream).unwrap();
386         unsafe {
387             let error = get_error::<Cursor<Vec<u8>>>(bio);
388             assert!(error.is_none());
389             let state = get_state::<Cursor<Vec<u8>>>(bio);
390             state.error = Some(io::Error::new(io::ErrorKind::Other, "ERROR TEST"));
391             let error = get_error::<Cursor<Vec<u8>>>(bio);
392             assert!(error.is_some());
393             let msg = error.unwrap().to_string();
394             assert_eq!(msg, "ERROR TEST");
395             BIO_free_all(bio);
396         }
397     }
398 
399     /// UT test case for `BIO::get_panic`.
400     ///
401     /// # Brief
402     /// 1. Calls `get_panic` to retrieve the panic state.
403     /// 2. Verify that the panic is as expected.
404     #[test]
ut_get_panic()405     fn ut_get_panic() {
406         let stream = Cursor::new(vec![0u8; 10]);
407         let (bio, _method) = new(stream).unwrap();
408         unsafe {
409             let panic = get_panic::<Cursor<Vec<u8>>>(bio);
410             assert!(panic.is_none());
411             let state = get_state::<Cursor<Vec<u8>>>(bio);
412             state.panic = Some(Box::new("PANIC TEST"));
413             let panic = get_panic::<Cursor<Vec<u8>>>(bio);
414             assert!(panic.is_some());
415             assert_eq!(panic.unwrap().downcast_ref::<&str>(), Some(&"PANIC TEST"));
416             BIO_free_all(bio);
417         }
418     }
419 
420     /// UT test case for `BIO::get_panic`.
421     ///
422     /// # Brief
423     /// 1. Calls `get_stream_ref` and `get_stream_mut` to retrieve the stream
424     ///    references.
425     /// 2. Verify that the stream length matches expected.
426     #[test]
ut_get_stream()427     fn ut_get_stream() {
428         let stream = Cursor::new(vec![0u8; 10]);
429         let (bio, _method) = new(stream).unwrap();
430         unsafe {
431             let stream_ref = get_stream_ref::<Cursor<Vec<u8>>>(bio);
432             assert_eq!(stream_ref.get_ref().len(), 10);
433             let stream_mut = get_stream_mut::<Cursor<Vec<u8>>>(bio);
434             assert_eq!(stream_mut.get_mut().len(), 10);
435             BIO_free_all(bio);
436         }
437     }
438 
439     /// UT test case for `BIO::retry_error`.
440     ///
441     /// # Brief
442     /// 1. Calls `retry_error` with some IO errors.
443     /// 2. Verify that the result matches the error kind.
444     #[test]
ut_try_error()445     fn ut_try_error() {
446         let error = io::Error::new(io::ErrorKind::WouldBlock, "operation would back");
447         assert!(retry_error(&error));
448         let error = io::Error::new(io::ErrorKind::NotConnected, "not connected");
449         assert!(retry_error(&error));
450         let error = io::Error::new(io::ErrorKind::Other, "some other error");
451         assert!(!retry_error(&error));
452     }
453 
454     /// UT test case for `ctrl` with `BIO_CTRL_FLUSH`.
455     ///
456     /// # Brief
457     /// 1. Calls `ctrl` with `BIO_CTRL_FLUSH.
458     /// 2. Verify that the flush operation returns the expected result.
459     #[test]
ut_ctrl_flush()460     fn ut_ctrl_flush() {
461         let stream = Cursor::new(vec![0u8; 10]);
462         let (bio, _method) = new(stream).unwrap();
463         unsafe {
464             let res = ctrl::<Cursor<Vec<u8>>>(bio, BIO_CTRL_FLUSH, 0, std::ptr::null_mut());
465             assert_eq!(res, 1);
466             BIO_free_all(bio);
467         }
468     }
469 
470     /// UT test case for `ctrl` with `BIO_CTRL_DGRAM_QUERY`.
471     ///
472     /// # Brief
473     /// 1. Injects an MTU size into the BIO state.
474     /// 2. Calls `ctrl` with `BIO_CTRL_DGRAM_QUERY`.
475     /// 3. Verify that the MTU size is returned correctly.
476     #[test]
ut_ctrl_dgram_query()477     fn ut_ctrl_dgram_query() {
478         let stream = Cursor::new(vec![0u8; 10]);
479         let (bio, _method) = new(stream).unwrap();
480         unsafe {
481             let state = get_state::<Cursor<Vec<u8>>>(bio);
482             state.dtls_mtu_size = 100;
483             let res = ctrl::<Cursor<Vec<u8>>>(bio, BIO_CTRL_DGRAM_QUERY, 0, std::ptr::null_mut());
484             assert_eq!(res, 100);
485             BIO_free_all(bio);
486         }
487     }
488 
489     /// UT test case for `ctrl` with unknow command.
490     ///
491     /// # Brief
492     /// 1. Calls `ctrl` with an unknown command.
493     /// 2. Verify that the default result is returned.
494     #[test]
ut_ctrl_default()495     fn ut_ctrl_default() {
496         let stream = Cursor::new(vec![0u8; 10]);
497         let (bio, _method) = new(stream).unwrap();
498         unsafe {
499             let res = ctrl::<Cursor<Vec<u8>>>(bio, 99, 0, std::ptr::null_mut());
500             assert_eq!(res, 0);
501             BIO_free_all(bio);
502         }
503     }
504 
505     /// UT test case for `bwrite`.
506     ///
507     /// # Brief
508     /// 1. Write data to the BIO.
509     /// 2. Verify that the data is written correctly.
510     #[test]
ut_bwrite()511     fn ut_bwrite() {
512         let stream = Cursor::new(vec![0u8; 10]);
513         let (bio, _method) = new(stream).unwrap();
514         let data = b"TEST TEST";
515         let len = data.len() as c_int;
516         unsafe {
517             let res = bwrite::<Cursor<Vec<u8>>>(bio, data.as_ptr() as *const c_char, len);
518             assert_eq!(res, len);
519             let state = get_stream_ref::<Cursor<Vec<u8>>>(bio);
520             let write_data = state.get_ref();
521             assert_eq!(&write_data[..len as usize], b"TEST TEST");
522             BIO_free_all(bio);
523         }
524     }
525 
526     /// UT test case for `bread`.
527     ///
528     /// # Brief
529     /// 1. Read data to the BIO.
530     /// 2. Verify that the data is read correctly.
531     #[test]
ut_bread()532     fn ut_bread() {
533         let data = b"TEST TEST".to_vec();
534         let stream = Cursor::new(data.clone());
535         let (bio, _method) = new(stream).unwrap();
536         let mut buf = vec![0u8; data.len()];
537         let len = data.len() as c_int;
538         unsafe {
539             let res = bread::<Cursor<Vec<u8>>>(bio, buf.as_mut_ptr() as *mut c_char, len);
540             assert_eq!(res, len);
541             assert_eq!(buf, data);
542             BIO_free_all(bio);
543         }
544     }
545 
546     /// UT test case for `bputs`.
547     ///
548     /// # Brief
549     /// 1. Write a null-terminated string to the BIO.
550     /// 2. Verify that the string is written correctly.
551     #[test]
ut_bput()552     fn ut_bput() {
553         let stream = Cursor::new(vec![0u8; 10]);
554         let (bio, _method) = new(stream).unwrap();
555         let data = "TEST TEST\0";
556         unsafe {
557             let res = bputs::<Cursor<Vec<u8>>>(bio, data.as_ptr() as *const c_char);
558             assert_eq!(res, strlen(data.as_ptr() as *const c_char) as c_int);
559             let state = get_stream_ref::<Cursor<Vec<u8>>>(bio);
560             let write_data = state.get_ref();
561             assert_eq!(
562                 &write_data[..data.len() - 1],
563                 data.as_bytes().strip_suffix(&[0]).unwrap()
564             );
565             BIO_free_all(bio);
566         }
567     }
568 }
569