| // Copyright 2023 The BoringSSL Authors | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // https://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #![deny( | |
| missing_docs, | |
| unsafe_op_in_unsafe_fn, | |
| clippy::indexing_slicing, | |
| clippy::unwrap_used, | |
| clippy::panic, | |
| clippy::expect_used | |
| )] | |
| #![cfg_attr(not(any(feature = "std", test)), no_std)] | |
| //! Rust BoringSSL bindings | |
| extern crate alloc; | |
| extern crate core; | |
| use alloc::boxed::Box; | |
| use alloc::vec::Vec; | |
| use core::ffi::c_void; | |
| #[macro_use] | |
| mod macros; | |
| pub mod aead; | |
| pub mod aes; | |
| /// Ciphers. | |
| pub mod cipher; | |
| pub mod digest; | |
| pub mod ec; | |
| pub mod ecdh; | |
| pub mod ecdsa; | |
| pub mod ed25519; | |
| pub mod hkdf; | |
| pub mod hmac; | |
| pub mod hpke; | |
| pub mod mldsa; | |
| pub mod mlkem; | |
| pub mod pkcs8; | |
| pub mod rsa; | |
| pub mod slhdsa; | |
| pub mod tls12_prf; | |
| pub mod x25519; | |
| mod scoped; | |
| #[cfg(test)] | |
| mod test_helpers; | |
| mod mem; | |
| pub use mem::constant_time_compare; | |
| mod rand; | |
| pub use rand::{rand_array, rand_bytes}; | |
| /// Error type for when a "signature" (either a public-key signature or a MAC) | |
| /// is incorrect. | |
| #[derive(Debug)] | |
| pub struct InvalidSignatureError; | |
| /// FfiSlice exists to provide `as_ffi_ptr` on slices. Calling `as_ptr` on an | |
| /// empty Rust slice may return the alignment of the type, rather than NULL, as | |
| /// the pointer. When passing pointers into C/C++ code, that is not a valid | |
| /// pointer. Thus this method should be used whenever passing a pointer to a | |
| /// slice into BoringSSL code. | |
| pub trait FfiSlice<T> { | |
| /// Cast the slice into a valid raw pointer for FFI. | |
| fn as_ffi_ptr(&self) -> *const T; | |
| /// Cast the slice into a valid `const void *` pointer for FFI. | |
| fn as_ffi_void_ptr(&self) -> *const c_void { | |
| self.as_ffi_ptr() as *const c_void | |
| } | |
| } | |
| impl<T> FfiSlice<T> for [T] { | |
| fn as_ffi_ptr(&self) -> *const T { | |
| if self.is_empty() { | |
| core::ptr::null() | |
| } else { | |
| self.as_ptr() | |
| } | |
| } | |
| } | |
| impl<T, const N: usize> FfiSlice<T> for [T; N] { | |
| fn as_ffi_ptr(&self) -> *const T { | |
| if N == 0 { | |
| core::ptr::null() | |
| } else { | |
| self.as_ptr() | |
| } | |
| } | |
| } | |
| /// See the comment [`FfiSlice`]. | |
| pub trait FfiMutSlice { | |
| /// Cast the mutable slice as a valid `uint8_t*` pointer for FFI. | |
| fn as_mut_ffi_ptr(&mut self) -> *mut u8; | |
| } | |
| impl FfiMutSlice for [u8] { | |
| fn as_mut_ffi_ptr(&mut self) -> *mut u8 { | |
| if self.is_empty() { | |
| core::ptr::null_mut() | |
| } else { | |
| self.as_mut_ptr() | |
| } | |
| } | |
| } | |
| impl<const N: usize> FfiMutSlice for [u8; N] { | |
| fn as_mut_ffi_ptr(&mut self) -> *mut u8 { | |
| if N == 0 { | |
| core::ptr::null_mut() | |
| } else { | |
| self.as_mut_ptr() | |
| } | |
| } | |
| } | |
| /// This is a helper struct which provides functions for passing slices over FFI. | |
| /// | |
| /// Deprecated: use `FfiSlice` which adds less noise and lets one grep for `as_ptr` | |
| /// as a sign of something to check. | |
| struct CSlice<'a>(&'a [u8]); | |
| impl<'a> From<&'a [u8]> for CSlice<'a> { | |
| fn from(value: &'a [u8]) -> Self { | |
| Self(value) | |
| } | |
| } | |
| impl CSlice<'_> { | |
| /// Returns a raw pointer to the value, which is safe to pass over FFI. | |
| pub fn as_ptr<T>(&self) -> *const T { | |
| if self.0.is_empty() { | |
| core::ptr::null() | |
| } else { | |
| self.0.as_ptr() as *const T | |
| } | |
| } | |
| pub fn len(&self) -> usize { | |
| self.0.len() | |
| } | |
| } | |
| /// This is a helper struct which provides functions for passing mutable slices over FFI. | |
| /// | |
| /// Deprecated: use `FfiMutSlice` which adds less noise and lets one grep for | |
| /// `as_ptr` as a sign of something to check. | |
| struct CSliceMut<'a>(&'a mut [u8]); | |
| impl CSliceMut<'_> { | |
| /// Returns a raw pointer to the value, which is safe to pass over FFI. | |
| pub fn as_mut_ptr<T>(&mut self) -> *mut T { | |
| if self.0.is_empty() { | |
| core::ptr::null_mut() | |
| } else { | |
| self.0.as_mut_ptr() as *mut T | |
| } | |
| } | |
| pub fn len(&self) -> usize { | |
| self.0.len() | |
| } | |
| } | |
| impl<'a> From<&'a mut [u8]> for CSliceMut<'a> { | |
| fn from(value: &'a mut [u8]) -> Self { | |
| Self(value) | |
| } | |
| } | |
| /// A helper trait implemented by types which reference borrowed foreign types. | |
| /// | |
| /// # Safety | |
| /// | |
| /// Implementations of `ForeignTypeRef` must guarantee the following: | |
| /// | |
| /// - `Self::from_ptr(x).as_ptr() == x` | |
| /// - `Self::from_ptr_mut(x).as_ptr() == x` | |
| unsafe trait ForeignTypeRef: Sized { | |
| /// The raw C type. | |
| type CType; | |
| /// Constructs a shared instance of this type from its raw type. | |
| /// | |
| /// # Safety | |
| /// | |
| /// `ptr` must be a valid, immutable, instance of the type for the `'a` lifetime. | |
| #[inline] | |
| unsafe fn from_ptr<'a>(ptr: *mut Self::CType) -> &'a Self { | |
| debug_assert!(!ptr.is_null()); | |
| unsafe { &*(ptr as *mut _) } | |
| } | |
| /// Returns a raw pointer to the wrapped value. | |
| #[inline] | |
| fn as_ptr(&self) -> *mut Self::CType { | |
| self as *const _ as *mut _ | |
| } | |
| } | |
| /// Returns a BoringSSL structure that is initialized by some function. | |
| /// Requires that the given function completely initializes the value. | |
| /// | |
| /// (Tagged `unsafe` because a no-op argument would otherwise expose | |
| /// uninitialized memory.) | |
| unsafe fn initialized_struct<T, F>(init: F) -> T | |
| where | |
| F: FnOnce(*mut T), | |
| { | |
| let mut out_uninit = core::mem::MaybeUninit::<T>::uninit(); | |
| init(out_uninit.as_mut_ptr()); | |
| unsafe { out_uninit.assume_init() } | |
| } | |
| /// Returns a BoringSSL structure that is initialized by some function. | |
| /// Requires that the given function completely initializes the value or else | |
| /// returns false. | |
| /// | |
| /// (Tagged `unsafe` because a no-op argument would otherwise expose | |
| /// uninitialized memory.) | |
| unsafe fn initialized_struct_fallible<T, F>(init: F) -> Option<T> | |
| where | |
| F: FnOnce(*mut T) -> bool, | |
| { | |
| let mut out_uninit = core::mem::MaybeUninit::<T>::uninit(); | |
| if init(out_uninit.as_mut_ptr()) { | |
| Some(unsafe { out_uninit.assume_init() }) | |
| } else { | |
| None | |
| } | |
| } | |
| /// Returns a boxed BoringSSL structure that is initialized by some function. | |
| /// Requires that the given function completely initializes the value. | |
| /// | |
| /// Safety: the argument must fully initialize the pointed-to `T`. | |
| unsafe fn initialized_boxed_struct<T, F>(init: F) -> Box<T> | |
| where | |
| F: FnOnce(*mut T), | |
| { | |
| let mut out_uninit = Box::new(core::mem::MaybeUninit::<T>::uninit()); | |
| init(out_uninit.as_mut_ptr()); | |
| unsafe { out_uninit.assume_init() } | |
| } | |
| /// Returns a boxed BoringSSL structure that is initialized by some function. | |
| /// Requires that the given function completely initializes the value or else | |
| /// returns false. | |
| /// | |
| /// Safety: the argument must fully initialize the pointed-to `T` if it returns | |
| /// true. If it returns false then there are no safety requirements. | |
| unsafe fn initialized_boxed_struct_fallible<T, F>(init: F) -> Option<Box<T>> | |
| where | |
| F: FnOnce(*mut T) -> bool, | |
| { | |
| let mut out_uninit = Box::new(core::mem::MaybeUninit::<T>::uninit()); | |
| if init(out_uninit.as_mut_ptr()) { | |
| Some(unsafe { out_uninit.assume_init() }) | |
| } else { | |
| None | |
| } | |
| } | |
| /// Wrap a closure that initializes an output buffer and return that buffer as | |
| /// an array. Requires that the closure fully initialize the given buffer. | |
| /// | |
| /// Safety: the closure must fully initialize the array. | |
| unsafe fn with_output_array<const N: usize, F>(func: F) -> [u8; N] | |
| where | |
| F: FnOnce(*mut u8, usize), | |
| { | |
| let mut out_uninit = core::mem::MaybeUninit::<[u8; N]>::uninit(); | |
| let out_ptr = if N != 0 { | |
| out_uninit.as_mut_ptr() as *mut u8 | |
| } else { | |
| core::ptr::null_mut() | |
| }; | |
| func(out_ptr, N); | |
| // Safety: `func` promises to fill all of `out_uninit`. | |
| unsafe { out_uninit.assume_init() } | |
| } | |
| /// Wrap a closure that initializes an output buffer and return that buffer as | |
| /// an array. The closure returns a [`core::ffi::c_int`] and, if the return value | |
| /// is not one, then the initialization is assumed to have failed and [None] is | |
| /// returned. Otherwise, this function requires that the closure fully | |
| /// initialize the given buffer. | |
| /// | |
| /// Safety: the closure must fully initialize the array if it returns one. | |
| unsafe fn with_output_array_fallible<const N: usize, F>(func: F) -> Option<[u8; N]> | |
| where | |
| F: FnOnce(*mut u8, usize) -> bool, | |
| { | |
| let mut out_uninit = core::mem::MaybeUninit::<[u8; N]>::uninit(); | |
| let out_ptr = if N != 0 { | |
| out_uninit.as_mut_ptr() as *mut u8 | |
| } else { | |
| core::ptr::null_mut() | |
| }; | |
| if func(out_ptr, N) { | |
| // Safety: `func` promises to fill all of `out_uninit` if it returns one. | |
| unsafe { Some(out_uninit.assume_init()) } | |
| } else { | |
| None | |
| } | |
| } | |
| /// Wrap a closure that writes at most `max_output` bytes to fill a vector. | |
| /// It must return the number of bytes written. | |
| /// | |
| /// Safety: `F` must not write more than `max_output` bytes and must return | |
| /// the number of bytes written. | |
| #[allow(clippy::unwrap_used)] | |
| unsafe fn with_output_vec<F>(max_output: usize, func: F) -> Vec<u8> | |
| where | |
| F: FnOnce(*mut u8) -> usize, | |
| { | |
| unsafe { | |
| with_output_vec_fallible(max_output, |out_buf| Some(func(out_buf))) | |
| // The closure cannot fail and thus neither can | |
| // `with_output_array_fallible`. | |
| .unwrap() | |
| } | |
| } | |
| /// Wrap a closure that writes at most `max_output` bytes to fill a vector. | |
| /// If successful, it must return the number of bytes written. | |
| /// | |
| /// Safety: `F` must not write more than `max_output` bytes and must return | |
| /// the number of bytes written or else return `None` to indicate failure. | |
| unsafe fn with_output_vec_fallible<F>(max_output: usize, func: F) -> Option<Vec<u8>> | |
| where | |
| F: FnOnce(*mut u8) -> Option<usize>, | |
| { | |
| let mut ret = Vec::with_capacity(max_output); | |
| let out = ret.spare_capacity_mut(); | |
| let out_buf = out | |
| .get_mut(0) | |
| .map_or(core::ptr::null_mut(), |x| x.as_mut_ptr()); | |
| let num_written = func(out_buf)?; | |
| assert!(num_written <= ret.capacity()); | |
| unsafe { | |
| // Safety: `num_written` bytes have been written to. | |
| ret.set_len(num_written); | |
| } | |
| Some(ret) | |
| } | |
| /// Buffer represents an owned chunk of memory on the BoringSSL heap. | |
| /// Call `as_ref()` to get a `&[u8]` from it. | |
| pub struct Buffer { | |
| // This pointer is always allocated by BoringSSL and must be freed using | |
| // `OPENSSL_free`. | |
| ptr: *mut u8, | |
| len: usize, | |
| } | |
| impl Buffer { | |
| /// Safety: `ptr` must point to `len` bytes, allocated by BoringSSL. | |
| unsafe fn new(ptr: *mut u8, len: usize) -> Buffer { | |
| Buffer { ptr, len } | |
| } | |
| } | |
| impl AsRef<[u8]> for Buffer { | |
| fn as_ref(&self) -> &[u8] { | |
| if self.len == 0 { | |
| return &[]; | |
| } | |
| // Safety: `ptr` and `len` describe a valid area of memory and `ptr` | |
| // must be Rust-valid because `len` is non-zero. | |
| unsafe { core::slice::from_raw_parts(self.ptr, self.len) } | |
| } | |
| } | |
| impl Drop for Buffer { | |
| fn drop(&mut self) { | |
| // Safety: `ptr` is owned by this object and is on the BoringSSL heap. | |
| unsafe { | |
| bssl_sys::OPENSSL_free(self.ptr as *mut core::ffi::c_void); | |
| } | |
| } | |
| } | |
| fn as_cbs(buf: &[u8]) -> bssl_sys::CBS { | |
| bssl_sys::CBS { | |
| data: buf.as_ffi_ptr(), | |
| len: buf.len(), | |
| } | |
| } | |
| /// Calls `parse_func` with a `CBS` structure pointing at `data`. | |
| /// If that returns a null pointer then it returns [None]. | |
| /// Otherwise, if there's still data left in CBS, it calls `free_func` on the | |
| /// pointer and returns [None]. Otherwise it returns the pointer. | |
| fn parse_with_cbs<T, Parse, Free>(data: &[u8], free_func: Free, parse_func: Parse) -> Option<*mut T> | |
| where | |
| Parse: FnOnce(*mut bssl_sys::CBS) -> *mut T, | |
| Free: FnOnce(*mut T), | |
| { | |
| // Safety: type checking ensures that `cbs` is the correct size. | |
| let mut cbs = | |
| unsafe { initialized_struct(|cbs| bssl_sys::CBS_init(cbs, data.as_ffi_ptr(), data.len())) }; | |
| let ptr = parse_func(&mut cbs); | |
| if ptr.is_null() { | |
| return None; | |
| } | |
| // Safety: `cbs` is still valid after parsing. | |
| if unsafe { bssl_sys::CBS_len(&cbs) } != 0 { | |
| // Safety: `ptr` is still owned by this function. | |
| free_func(ptr); | |
| return None; | |
| } | |
| Some(ptr) | |
| } | |
| /// Calls `func` with a `CBB` pointer and returns a [Buffer] of the ultimate | |
| /// contents of that CBB. | |
| #[allow(clippy::unwrap_used)] | |
| pub fn cbb_to_buffer<F: FnOnce(*mut bssl_sys::CBB)>(initial_capacity: usize, func: F) -> Buffer { | |
| // Safety: type checking ensures that `cbb` is the correct size. | |
| let mut cbb = unsafe { | |
| initialized_struct_fallible(|cbb| bssl_sys::CBB_init(cbb, initial_capacity) == 1) | |
| } | |
| // `CBB_init` only fails if out of memory, which isn't something that this crate handles. | |
| .unwrap(); | |
| func(&mut cbb); | |
| let mut ptr: *mut u8 = core::ptr::null_mut(); | |
| let mut len: usize = 0; | |
| // `CBB_finish` only fails on programming error, which we convert into a | |
| // panic. | |
| assert_eq!(1, unsafe { | |
| bssl_sys::CBB_finish(&mut cbb, &mut ptr, &mut len) | |
| }); | |
| // Safety: `ptr` is on the BoringSSL heap and ownership is returned by | |
| // `CBB_finish`. | |
| unsafe { Buffer::new(ptr, len) } | |
| } | |
| /// Calls `func` with a `CBB` pointer that has been initialized to a vector | |
| /// of `len` bytes. That function must write exactly `len` bytes to the | |
| /// `CBB`. Those bytes are then returned as a vector. | |
| #[allow(clippy::unwrap_used)] | |
| fn cbb_to_vec<F: FnOnce(*mut bssl_sys::CBB)>(len: usize, func: F) -> Vec<u8> { | |
| let mut boxed = Box::new_uninit_slice(len); | |
| // Safety: type checking ensures that `cbb` is the correct size. | |
| let mut cbb = unsafe { | |
| initialized_struct_fallible(|cbb| { | |
| bssl_sys::CBB_init_fixed(cbb, boxed.as_mut_ptr() as *mut u8, len) == 1 | |
| }) | |
| } | |
| // `CBB_init_fixed` never fails and does not allocate. | |
| .unwrap(); | |
| func(&mut cbb); | |
| unsafe { | |
| assert_eq!(bssl_sys::CBB_len(&cbb), len); | |
| // `boxed` has been fully written, as checked on the previous line. | |
| boxed.assume_init().into() | |
| } | |
| } | |
| /// Used to prevent external implementations of internal traits. | |
| mod sealed { | |
| pub struct SealedType; | |
| pub trait Sealed {} | |
| } |