aws_lc_rs/
ptr.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0 OR ISC
3
4use crate::aws_lc::{
5    BN_free, ECDSA_SIG_free, EC_GROUP_free, EC_KEY_free, EC_POINT_free, EVP_AEAD_CTX_free,
6    EVP_CIPHER_CTX_free, EVP_PKEY_CTX_free, EVP_PKEY_free, OPENSSL_free, RSA_free, BIGNUM,
7    ECDSA_SIG, EC_GROUP, EC_KEY, EC_POINT, EVP_AEAD_CTX, EVP_CIPHER_CTX, EVP_PKEY, EVP_PKEY_CTX,
8    RSA,
9};
10use core::ops::Deref;
11use std::marker::PhantomData;
12
13pub(crate) type LcPtr<T> = ManagedPointer<*mut T>;
14pub(crate) type DetachableLcPtr<T> = DetachablePointer<*mut T>;
15
16#[derive(Debug)]
17pub(crate) struct ManagedPointer<P: Pointer> {
18    pointer: P,
19}
20
21impl<P: Pointer> ManagedPointer<P> {
22    #[inline]
23    pub fn new<T: IntoPointer<P>>(value: T) -> Result<Self, ()> {
24        if let Some(pointer) = value.into_pointer() {
25            Ok(Self { pointer })
26        } else {
27            Err(())
28        }
29    }
30
31    pub unsafe fn as_slice(&self, len: usize) -> &[P::T] {
32        core::slice::from_raw_parts(self.pointer.as_const_ptr(), len)
33    }
34}
35
36impl<P: Pointer> Drop for ManagedPointer<P> {
37    #[inline]
38    fn drop(&mut self) {
39        self.pointer.free();
40    }
41}
42
43impl<'a, P: Pointer> From<&'a ManagedPointer<P>> for ConstPointer<'a, P::T> {
44    fn from(ptr: &'a ManagedPointer<P>) -> ConstPointer<'a, P::T> {
45        ConstPointer {
46            ptr: ptr.pointer.as_const_ptr(),
47            _lifetime: PhantomData,
48        }
49    }
50}
51
52impl<P: Pointer> ManagedPointer<P> {
53    #[inline]
54    pub fn as_const(&self) -> ConstPointer<'_, P::T> {
55        self.into()
56    }
57
58    pub fn project_const_lifetime<'a, C>(
59        &'a self,
60        f: unsafe fn(&'a Self) -> *const C,
61    ) -> Result<ConstPointer<'a, C>, ()> {
62        let ptr = unsafe { f(self) };
63        if ptr.is_null() {
64            return Err(());
65        }
66        Ok(ConstPointer {
67            ptr,
68            _lifetime: PhantomData,
69        })
70    }
71
72    #[inline]
73    pub unsafe fn as_mut_unsafe(&self) -> MutPointer<P::T> {
74        MutPointer {
75            ptr: self.pointer.as_const_ptr() as *mut P::T,
76        }
77    }
78
79    #[inline]
80    pub fn as_mut(&mut self) -> MutPointer<P::T> {
81        MutPointer {
82            ptr: self.pointer.as_mut_ptr(),
83        }
84    }
85}
86
87impl<P: Pointer> DetachablePointer<P> {
88    #[inline]
89    pub fn as_mut(&mut self) -> MutPointer<P::T> {
90        MutPointer {
91            ptr: self.pointer.as_mut().unwrap().as_mut_ptr(),
92        }
93    }
94}
95
96#[derive(Debug)]
97#[allow(clippy::module_name_repetitions)]
98pub(crate) struct DetachablePointer<P: Pointer> {
99    pointer: Option<P>,
100}
101
102impl<P: Pointer> Deref for DetachablePointer<P> {
103    type Target = P;
104    #[inline]
105    fn deref(&self) -> &Self::Target {
106        match &self.pointer {
107            Some(pointer) => pointer,
108            None => {
109                // Safety: pointer is only None when DetachableLcPtr is detached or dropped
110                unreachable!()
111            }
112        }
113    }
114}
115
116impl<P: Pointer> DetachablePointer<P> {
117    #[inline]
118    pub fn new<T: IntoPointer<P>>(value: T) -> Result<Self, ()> {
119        if let Some(pointer) = value.into_pointer() {
120            Ok(Self {
121                pointer: Some(pointer),
122            })
123        } else {
124            Err(())
125        }
126    }
127
128    #[inline]
129    pub fn detach(mut self) -> P {
130        self.pointer.take().unwrap()
131    }
132}
133
134impl<P: Pointer> From<DetachablePointer<P>> for ManagedPointer<P> {
135    #[inline]
136    fn from(mut dptr: DetachablePointer<P>) -> Self {
137        match dptr.pointer.take() {
138            Some(pointer) => ManagedPointer { pointer },
139            None => {
140                // Safety: pointer is only None when DetachableLcPtr is detached or dropped
141                unreachable!()
142            }
143        }
144    }
145}
146
147impl<P: Pointer> Drop for DetachablePointer<P> {
148    #[inline]
149    fn drop(&mut self) {
150        if let Some(mut pointer) = self.pointer.take() {
151            pointer.free();
152        }
153    }
154}
155
156#[derive(Debug)]
157pub(crate) struct ConstPointer<'a, T> {
158    ptr: *const T,
159    _lifetime: PhantomData<&'a T>,
160}
161
162impl<T> ConstPointer<'static, T> {
163    pub unsafe fn new_static(ptr: *const T) -> Result<Self, ()> {
164        if ptr.is_null() {
165            return Err(());
166        }
167        Ok(ConstPointer {
168            ptr,
169            _lifetime: PhantomData,
170        })
171    }
172}
173
174impl<T> ConstPointer<'_, T> {
175    pub fn project_const_lifetime<'a, C>(
176        &'a self,
177        f: unsafe fn(&'a Self) -> *const C,
178    ) -> Result<ConstPointer<'a, C>, ()> {
179        let ptr = unsafe { f(self) };
180        if ptr.is_null() {
181            return Err(());
182        }
183        Ok(ConstPointer {
184            ptr,
185            _lifetime: PhantomData,
186        })
187    }
188}
189
190impl<T> Deref for ConstPointer<'_, T> {
191    type Target = *const T;
192
193    fn deref(&self) -> &Self::Target {
194        &self.ptr
195    }
196}
197
198#[derive(Debug)]
199pub(crate) struct MutPointer<T> {
200    ptr: *mut T,
201}
202
203impl<T> Deref for MutPointer<T> {
204    type Target = *mut T;
205
206    fn deref(&self) -> &Self::Target {
207        &self.ptr
208    }
209}
210
211pub(crate) trait Pointer {
212    type T;
213
214    fn free(&mut self);
215    fn as_const_ptr(&self) -> *const Self::T;
216    fn as_mut_ptr(&mut self) -> *mut Self::T;
217}
218
219pub(crate) trait IntoPointer<P> {
220    fn into_pointer(self) -> Option<P>;
221}
222
223impl<T> IntoPointer<*mut T> for *mut T {
224    #[inline]
225    fn into_pointer(self) -> Option<*mut T> {
226        if self.is_null() {
227            None
228        } else {
229            Some(self)
230        }
231    }
232}
233
234macro_rules! create_pointer {
235    ($ty:ty, $free:path) => {
236        impl Pointer for *mut $ty {
237            type T = $ty;
238
239            #[inline]
240            fn free(&mut self) {
241                unsafe {
242                    let ptr = *self;
243                    $free(ptr.cast());
244                }
245            }
246
247            #[inline]
248            fn as_const_ptr(&self) -> *const Self::T {
249                self.cast()
250            }
251
252            #[inline]
253            fn as_mut_ptr(&mut self) -> *mut Self::T {
254                *self
255            }
256        }
257    };
258}
259
260// `OPENSSL_free` and the other `XXX_free` functions perform a zeroization of the memory when it's
261// freed. This is different than functions of the same name in OpenSSL which generally do not zero
262// memory.
263create_pointer!(u8, OPENSSL_free);
264create_pointer!(EC_GROUP, EC_GROUP_free);
265create_pointer!(EC_POINT, EC_POINT_free);
266create_pointer!(EC_KEY, EC_KEY_free);
267create_pointer!(ECDSA_SIG, ECDSA_SIG_free);
268create_pointer!(BIGNUM, BN_free);
269create_pointer!(EVP_PKEY, EVP_PKEY_free);
270create_pointer!(EVP_PKEY_CTX, EVP_PKEY_CTX_free);
271create_pointer!(RSA, RSA_free);
272create_pointer!(EVP_AEAD_CTX, EVP_AEAD_CTX_free);
273create_pointer!(EVP_CIPHER_CTX, EVP_CIPHER_CTX_free);
274
275#[cfg(test)]
276mod tests {
277    use crate::aws_lc::BIGNUM;
278    use crate::ptr::{DetachablePointer, ManagedPointer};
279
280    #[test]
281    fn test_debug() {
282        let num = 100u64;
283        let detachable_ptr: DetachablePointer<*mut BIGNUM> =
284            DetachablePointer::try_from(num).unwrap();
285        let debug = format!("{detachable_ptr:?}");
286        assert!(debug.contains("DetachablePointer { pointer: Some("));
287
288        let lc_ptr = ManagedPointer::new(detachable_ptr.detach()).unwrap();
289        let debug = format!("{lc_ptr:?}");
290        assert!(debug.contains("ManagedPointer { pointer:"));
291    }
292}