• 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 
bwrite<S: Write>(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int232 unsafe extern "C" fn bwrite<S: Write>(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int {
233     BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_RWS);
234 
235     let state = get_state::<S>(bio);
236     if len < 0 {
237         state.error = Some(io::Error::from(io::ErrorKind::InvalidInput));
238         return -1;
239     }
240 
241     let buf = slice::from_raw_parts(buf as *const _, len as usize);
242 
243     match catch_unwind(AssertUnwindSafe(|| state.stream.write(buf))) {
244         Ok(Err(err)) => {
245             if retry_error(&err) {
246                 BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_WRITE)
247             }
248             state.error = Some(err);
249             -1
250         }
251         Ok(Ok(len)) => len as c_int,
252         Err(err) => {
253             state.panic = Some(err);
254             -1
255         }
256     }
257 }
258 
bread<S: Read>(bio: *mut BIO, buf: *mut c_char, len: c_int) -> c_int259 unsafe extern "C" fn bread<S: Read>(bio: *mut BIO, buf: *mut c_char, len: c_int) -> c_int {
260     BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_RWS);
261 
262     let state = get_state::<S>(bio);
263     let buf = slice::from_raw_parts_mut(buf as *mut _, len as usize);
264 
265     match catch_unwind(AssertUnwindSafe(|| state.stream.read(buf))) {
266         Ok(Err(err)) => {
267             if retry_error(&err) {
268                 BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_READ)
269             }
270             state.error = Some(err);
271             -1
272         }
273         Ok(Ok(len)) => len as c_int,
274         Err(err) => {
275             state.panic = Some(err);
276             -1
277         }
278     }
279 }
280 
bputs<S: Write>(bio: *mut BIO, buf: *const c_char) -> c_int281 unsafe extern "C" fn bputs<S: Write>(bio: *mut BIO, buf: *const c_char) -> c_int {
282     bwrite::<S>(bio, buf, strlen(buf) as c_int)
283 }
284