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