aws_lc_rs/
cbb.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::{CBB_cleanup, CBB_finish, CBB_init, CBB_init_fixed, CBB};
5use crate::error::Unspecified;
6use crate::ptr::LcPtr;
7use core::marker::PhantomData;
8use core::mem::MaybeUninit;
9use core::ptr::null_mut;
10
11pub(crate) struct LcCBB<'a>(CBB, PhantomData<&'a CBB>);
12
13impl LcCBB<'static> {
14    pub(crate) fn new(initial_capacity: usize) -> LcCBB<'static> {
15        let mut cbb = MaybeUninit::<CBB>::uninit();
16        let cbb = unsafe {
17            CBB_init(cbb.as_mut_ptr(), initial_capacity);
18            cbb.assume_init()
19        };
20        Self(cbb, PhantomData)
21    }
22
23    pub(crate) fn into_vec(mut self) -> Result<Vec<u8>, Unspecified> {
24        let mut out_data = null_mut::<u8>();
25        let mut out_len: usize = 0;
26
27        if 1 != unsafe { CBB_finish(self.as_mut_ptr(), &mut out_data, &mut out_len) } {
28            return Err(Unspecified);
29        }
30
31        let out_data = LcPtr::new(out_data)?;
32        let slice = unsafe { std::slice::from_raw_parts(*out_data.as_const(), out_len) };
33        // `to_vec()` copies the data into a new `Vec`
34        Ok(slice.to_vec())
35    }
36}
37
38impl<'a> LcCBB<'a> {
39    pub(crate) fn new_from_slice(buffer: &'a mut [u8]) -> LcCBB<'a> {
40        let mut cbb = MaybeUninit::<CBB>::uninit();
41        let cbb = unsafe {
42            CBB_init_fixed(cbb.as_mut_ptr(), buffer.as_mut_ptr(), buffer.len());
43            cbb.assume_init()
44        };
45        Self(cbb, PhantomData)
46    }
47
48    pub(crate) fn finish(mut self) -> Result<usize, Unspecified> {
49        let mut pkcs8_bytes_ptr = null_mut::<u8>();
50        let mut out_len: usize = 0;
51        if 1 != unsafe { CBB_finish(self.as_mut_ptr(), &mut pkcs8_bytes_ptr, &mut out_len) } {
52            return Err(Unspecified);
53        }
54        Ok(out_len)
55    }
56}
57impl LcCBB<'_> {
58    pub(crate) fn as_mut_ptr(&mut self) -> *mut CBB {
59        &mut self.0
60    }
61}
62
63impl Drop for LcCBB<'_> {
64    fn drop(&mut self) {
65        unsafe {
66            CBB_cleanup(&mut self.0);
67        }
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::LcCBB;
74    use crate::aws_lc::CBB_add_asn1_bool;
75
76    #[test]
77    fn dynamic_vec() {
78        let mut cbb = LcCBB::new(4);
79        assert_eq!(1, unsafe { CBB_add_asn1_bool(cbb.as_mut_ptr(), 1) });
80        let vec = cbb.into_vec().expect("be copied to buffer");
81        assert_eq!(vec.as_slice(), &[1, 1, 255]);
82    }
83
84    #[test]
85    fn dynamic_buffer_grows() {
86        let mut cbb = LcCBB::new(1);
87        assert_eq!(1, unsafe { CBB_add_asn1_bool(cbb.as_mut_ptr(), 1) });
88        let vec = cbb.into_vec().expect("be copied to buffer");
89        assert_eq!(vec.as_slice(), &[1, 1, 255]);
90    }
91
92    #[test]
93    fn fixed_buffer() {
94        let mut buffer = [0u8; 4];
95        let mut cbb = LcCBB::new_from_slice(&mut buffer);
96        assert_eq!(1, unsafe { CBB_add_asn1_bool(cbb.as_mut_ptr(), 1) });
97        let out_len = cbb.finish().expect("cbb finishable");
98        assert_eq!(&buffer[..out_len], &[1, 1, 255]);
99    }
100
101    #[test]
102    fn fixed_buffer_no_growth() {
103        let mut buffer = [0u8; 1];
104        let mut cbb = LcCBB::new_from_slice(&mut buffer);
105        assert_ne!(1, unsafe { CBB_add_asn1_bool(cbb.as_mut_ptr(), 1) });
106    }
107}