bssl_crypto/lib.rs
1// Copyright 2023 The BoringSSL Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#![deny(
16 missing_docs,
17 unsafe_op_in_unsafe_fn,
18 clippy::indexing_slicing,
19 clippy::unwrap_used,
20 clippy::panic,
21 clippy::expect_used
22)]
23#![cfg_attr(not(any(feature = "std", test)), no_std)]
24
25//! Rust BoringSSL bindings
26
27extern crate alloc;
28extern crate core;
29
30use alloc::boxed::Box;
31use alloc::vec::Vec;
32use core::{
33 debug_assert,
34 ffi::c_void, //
35};
36
37#[macro_use]
38mod macros;
39
40pub mod aead;
41pub mod aes;
42
43/// Ciphers.
44pub mod cipher;
45
46pub mod digest;
47pub mod ec;
48pub mod ecdh;
49pub mod ecdsa;
50pub mod ed25519;
51pub mod hkdf;
52pub mod hmac;
53pub mod hpke;
54pub mod mldsa;
55pub mod mlkem;
56pub mod pkcs8;
57pub mod rsa;
58pub mod slhdsa;
59pub mod tls12_prf;
60pub mod x25519;
61
62mod scoped;
63
64#[cfg(test)]
65mod test_helpers;
66
67mod mem;
68pub use mem::constant_time_compare;
69
70mod rand;
71pub use rand::{rand_array, rand_bytes};
72
73/// Error type for when a "signature" (either a public-key signature or a MAC)
74/// is incorrect.
75#[derive(Debug)]
76pub struct InvalidSignatureError;
77
78/// FfiSlice exists to provide `as_ffi_ptr` on slices. Calling `as_ptr` on an
79/// empty Rust slice may return the alignment of the type, rather than NULL, as
80/// the pointer. When passing pointers into C/C++ code, that is not a valid
81/// pointer. Thus this method should be used whenever passing a pointer to a
82/// slice into BoringSSL code.
83pub trait FfiSlice<T> {
84 /// Cast the slice into a valid raw pointer for FFI.
85 fn as_ffi_ptr(&self) -> *const T;
86 /// Cast the slice into a valid `const void *` pointer for FFI.
87 fn as_ffi_void_ptr(&self) -> *const c_void {
88 self.as_ffi_ptr() as *const c_void
89 }
90}
91
92impl<T> FfiSlice<T> for [T] {
93 fn as_ffi_ptr(&self) -> *const T {
94 if self.is_empty() {
95 core::ptr::null()
96 } else {
97 self.as_ptr()
98 }
99 }
100}
101
102impl<T, const N: usize> FfiSlice<T> for [T; N] {
103 fn as_ffi_ptr(&self) -> *const T {
104 if N == 0 {
105 core::ptr::null()
106 } else {
107 self.as_ptr()
108 }
109 }
110}
111
112/// See the comment [`FfiSlice`].
113pub trait FfiMutSlice {
114 /// Cast the mutable slice as a valid `uint8_t*` pointer for FFI.
115 fn as_mut_ffi_ptr(&mut self) -> *mut u8;
116}
117
118impl FfiMutSlice for [u8] {
119 fn as_mut_ffi_ptr(&mut self) -> *mut u8 {
120 if self.is_empty() {
121 core::ptr::null_mut()
122 } else {
123 self.as_mut_ptr()
124 }
125 }
126}
127
128impl<const N: usize> FfiMutSlice for [u8; N] {
129 fn as_mut_ffi_ptr(&mut self) -> *mut u8 {
130 if N == 0 {
131 core::ptr::null_mut()
132 } else {
133 self.as_mut_ptr()
134 }
135 }
136}
137
138#[doc(hidden)]
139/// The reverse of [`FfiSlice`], to re-interpret a FFI pointer back into a Rust slice.
140pub trait FromFfiSlice: Sized {
141 /// Converts an FFI pointer and length to a Rust slice. This is similar to
142 /// [core::slice::from_raw_parts] but handles a mismatch between C and Rust empty slice
143 /// conventions.
144 /// In C, empty slices may use a `NULL` pointer in C.
145 /// In Rust, they may not.
146 ///
147 /// **NOTE** This trait is set up only for BoringSSL internal use.
148 ///
149 /// # Safety
150 ///
151 /// The caller must meet the following safety pre-conditions:
152 /// - The `ptr` and `len` are from a slice returned from BoringSSL via FFI.
153 /// - The memory referenced by the returned slice must not be mutated or deallocated for the
154 /// duration of lifetime `'a`, including by BoringSSL.
155 ///
156 /// The first condition implies the following properties:
157 ///
158 /// - `ptr` is correctly aligned for Self.
159 /// - The total bytes of the slice, in other words `size_of<Self>() * len`, is below [isize::MAX].
160 /// - If `ptr.is_null()` then `len == 0`.
161 /// - There are `len` objects of type Self at ptr.
162 /// - The entire memory range for these objects is contained in a single allocation.
163 /// - The entire memory range is not mutated within the `'a` lifetime through aliased accesses.
164 /// - Each element of the slice has a valid bit pattern as a value of `Self`.
165 unsafe fn from_ffi_ptr<'a>(ptr: *const Self, len: usize) -> &'a [Self];
166}
167
168impl<T> FromFfiSlice for T {
169 #[inline]
170 unsafe fn from_ffi_ptr<'a>(ptr: *const T, len: usize) -> &'a [T] {
171 debug_assert!(ptr.is_aligned());
172 #[cfg(debug_assertions)]
173 if let Some(len) = len.checked_mul(core::mem::size_of::<T>()) {
174 debug_assert!(len < isize::MAX.unsigned_abs());
175 } else {
176 unreachable!("length overflow");
177 };
178
179 if len == 0 {
180 &[]
181 } else {
182 debug_assert!(!ptr.is_null());
183 unsafe {
184 // Safety:
185 // - pre-condition has asserted that the pointer outlives the returned slice.
186 // - pre-condition has asserted that the memory range does not overlap with any
187 // other allocations.
188 // - pre-condition has asserted that the bit pattern behind the pointer is valid for
189 // the type `T`.
190 core::slice::from_raw_parts(ptr, len)
191 }
192 }
193 }
194}
195
196/// Sanitize the data pointer and length and reconstitute the mutable slice.
197///
198/// This method will **zeroize** the content.
199///
200/// This method returns an empty slice if the length is 0.
201///
202/// # Safety
203///
204/// Caller must ensure that
205/// - `ptr` outlives `'a`.
206/// - access to `out` is exclusive and strictly not aliased.
207/// - if `ptr` is NULL, `capacity == 0`.
208#[inline]
209pub unsafe fn zeroize_mut_byteslice<'a>(ptr: *mut u8, capacity: usize) -> &'a mut [u8] {
210 if capacity == 0 {
211 return &mut [];
212 }
213 debug_assert!(capacity < isize::MAX.unsigned_abs() && !ptr.is_null());
214 unsafe {
215 // Safety: `out` is 1-aligned and `0` is a valid pattern for `u8`.
216 core::ptr::write_bytes(ptr, 0, capacity);
217 core::slice::from_raw_parts_mut(ptr, capacity)
218 }
219}
220
221/// This is a helper struct which provides functions for passing slices over FFI.
222///
223/// Deprecated: use `FfiSlice` which adds less noise and lets one grep for `as_ptr`
224/// as a sign of something to check.
225struct CSlice<'a>(&'a [u8]);
226
227impl<'a> From<&'a [u8]> for CSlice<'a> {
228 fn from(value: &'a [u8]) -> Self {
229 Self(value)
230 }
231}
232
233impl CSlice<'_> {
234 /// Returns a raw pointer to the value, which is safe to pass over FFI.
235 pub fn as_ptr<T>(&self) -> *const T {
236 if self.0.is_empty() {
237 core::ptr::null()
238 } else {
239 self.0.as_ptr() as *const T
240 }
241 }
242
243 pub fn len(&self) -> usize {
244 self.0.len()
245 }
246}
247
248/// This is a helper struct which provides functions for passing mutable slices over FFI.
249///
250/// Deprecated: use `FfiMutSlice` which adds less noise and lets one grep for
251/// `as_ptr` as a sign of something to check.
252struct CSliceMut<'a>(&'a mut [u8]);
253
254impl CSliceMut<'_> {
255 /// Returns a raw pointer to the value, which is safe to pass over FFI.
256 pub fn as_mut_ptr<T>(&mut self) -> *mut T {
257 if self.0.is_empty() {
258 core::ptr::null_mut()
259 } else {
260 self.0.as_mut_ptr() as *mut T
261 }
262 }
263
264 pub fn len(&self) -> usize {
265 self.0.len()
266 }
267}
268
269impl<'a> From<&'a mut [u8]> for CSliceMut<'a> {
270 fn from(value: &'a mut [u8]) -> Self {
271 Self(value)
272 }
273}
274
275/// A helper trait implemented by types which reference borrowed foreign types.
276///
277/// # Safety
278///
279/// Implementations of `ForeignTypeRef` must guarantee the following:
280///
281/// - `Self::from_ptr(x).as_ptr() == x`
282/// - `Self::from_ptr_mut(x).as_ptr() == x`
283unsafe trait ForeignTypeRef: Sized {
284 /// The raw C type.
285 type CType;
286
287 /// Constructs a shared instance of this type from its raw type.
288 ///
289 /// # Safety
290 ///
291 /// `ptr` must be a valid, immutable, instance of the type for the `'a` lifetime.
292 #[inline]
293 unsafe fn from_ptr<'a>(ptr: *mut Self::CType) -> &'a Self {
294 debug_assert!(!ptr.is_null());
295 unsafe { &*(ptr as *mut _) }
296 }
297
298 /// Returns a raw pointer to the wrapped value.
299 #[inline]
300 fn as_ptr(&self) -> *mut Self::CType {
301 self as *const _ as *mut _
302 }
303}
304
305/// Returns a BoringSSL structure that is initialized by some function.
306/// Requires that the given function completely initializes the value.
307///
308/// (Tagged `unsafe` because a no-op argument would otherwise expose
309/// uninitialized memory.)
310unsafe fn initialized_struct<T, F>(init: F) -> T
311where
312 F: FnOnce(*mut T),
313{
314 let mut out_uninit = core::mem::MaybeUninit::<T>::uninit();
315 init(out_uninit.as_mut_ptr());
316 unsafe { out_uninit.assume_init() }
317}
318
319/// Returns a BoringSSL structure that is initialized by some function.
320/// Requires that the given function completely initializes the value or else
321/// returns false.
322///
323/// (Tagged `unsafe` because a no-op argument would otherwise expose
324/// uninitialized memory.)
325unsafe fn initialized_struct_fallible<T, F>(init: F) -> Option<T>
326where
327 F: FnOnce(*mut T) -> bool,
328{
329 let mut out_uninit = core::mem::MaybeUninit::<T>::uninit();
330 if init(out_uninit.as_mut_ptr()) {
331 Some(unsafe { out_uninit.assume_init() })
332 } else {
333 None
334 }
335}
336
337/// Returns a boxed BoringSSL structure that is initialized by some function.
338/// Requires that the given function completely initializes the value.
339///
340/// Safety: the argument must fully initialize the pointed-to `T`.
341unsafe fn initialized_boxed_struct<T, F>(init: F) -> Box<T>
342where
343 F: FnOnce(*mut T),
344{
345 let mut out_uninit = Box::new(core::mem::MaybeUninit::<T>::uninit());
346 init(out_uninit.as_mut_ptr());
347 unsafe { out_uninit.assume_init() }
348}
349
350/// Returns a boxed BoringSSL structure that is initialized by some function.
351/// Requires that the given function completely initializes the value or else
352/// returns false.
353///
354/// Safety: the argument must fully initialize the pointed-to `T` if it returns
355/// true. If it returns false then there are no safety requirements.
356unsafe fn initialized_boxed_struct_fallible<T, F>(init: F) -> Option<Box<T>>
357where
358 F: FnOnce(*mut T) -> bool,
359{
360 let mut out_uninit = Box::new(core::mem::MaybeUninit::<T>::uninit());
361 if init(out_uninit.as_mut_ptr()) {
362 Some(unsafe { out_uninit.assume_init() })
363 } else {
364 None
365 }
366}
367
368/// Wrap a closure that initializes an output buffer and return that buffer as
369/// an array. Requires that the closure fully initialize the given buffer.
370///
371/// Safety: the closure must fully initialize the array.
372unsafe fn with_output_array<const N: usize, F>(func: F) -> [u8; N]
373where
374 F: FnOnce(*mut u8, usize),
375{
376 let mut out_uninit = core::mem::MaybeUninit::<[u8; N]>::uninit();
377 let out_ptr = if N != 0 {
378 out_uninit.as_mut_ptr() as *mut u8
379 } else {
380 core::ptr::null_mut()
381 };
382 func(out_ptr, N);
383 // Safety: `func` promises to fill all of `out_uninit`.
384 unsafe { out_uninit.assume_init() }
385}
386
387/// Wrap a closure that initializes an output buffer and return that buffer as
388/// an array. The closure returns a [`core::ffi::c_int`] and, if the return value
389/// is not one, then the initialization is assumed to have failed and [None] is
390/// returned. Otherwise, this function requires that the closure fully
391/// initialize the given buffer.
392///
393/// Safety: the closure must fully initialize the array if it returns one.
394unsafe fn with_output_array_fallible<const N: usize, F>(func: F) -> Option<[u8; N]>
395where
396 F: FnOnce(*mut u8, usize) -> bool,
397{
398 let mut out_uninit = core::mem::MaybeUninit::<[u8; N]>::uninit();
399 let out_ptr = if N != 0 {
400 out_uninit.as_mut_ptr() as *mut u8
401 } else {
402 core::ptr::null_mut()
403 };
404 if func(out_ptr, N) {
405 // Safety: `func` promises to fill all of `out_uninit` if it returns one.
406 unsafe { Some(out_uninit.assume_init()) }
407 } else {
408 None
409 }
410}
411
412/// Wrap a closure that writes at most `max_output` bytes to fill a vector.
413/// It must return the number of bytes written.
414///
415/// Safety: `F` must not write more than `max_output` bytes and must return
416/// the number of bytes written.
417#[allow(clippy::unwrap_used)]
418unsafe fn with_output_vec<F>(max_output: usize, func: F) -> Vec<u8>
419where
420 F: FnOnce(*mut u8) -> usize,
421{
422 unsafe {
423 with_output_vec_fallible(max_output, |out_buf| Some(func(out_buf)))
424 // The closure cannot fail and thus neither can
425 // `with_output_array_fallible`.
426 .unwrap()
427 }
428}
429
430/// Wrap a closure that writes at most `max_output` bytes to fill a vector.
431/// If successful, it must return the number of bytes written.
432///
433/// Safety: `F` must not write more than `max_output` bytes and must return
434/// the number of bytes written or else return `None` to indicate failure.
435unsafe fn with_output_vec_fallible<F>(max_output: usize, func: F) -> Option<Vec<u8>>
436where
437 F: FnOnce(*mut u8) -> Option<usize>,
438{
439 let mut ret = Vec::with_capacity(max_output);
440 let out = ret.spare_capacity_mut();
441 let out_buf = out
442 .get_mut(0)
443 .map_or(core::ptr::null_mut(), |x| x.as_mut_ptr());
444
445 let num_written = func(out_buf)?;
446 assert!(num_written <= ret.capacity());
447
448 unsafe {
449 // Safety: `num_written` bytes have been written to.
450 ret.set_len(num_written);
451 }
452
453 Some(ret)
454}
455
456/// Buffer represents an owned chunk of memory on the BoringSSL heap.
457/// Call `as_ref()` to get a `&[u8]` from it.
458pub struct Buffer {
459 // This pointer is always allocated by BoringSSL and must be freed using
460 // `OPENSSL_free`.
461 ptr: *mut u8,
462 len: usize,
463}
464
465impl Buffer {
466 /// Safety: `ptr` must point to `len` bytes, allocated by BoringSSL.
467 unsafe fn new(ptr: *mut u8, len: usize) -> Buffer {
468 Buffer { ptr, len }
469 }
470}
471
472impl AsRef<[u8]> for Buffer {
473 fn as_ref(&self) -> &[u8] {
474 if self.len == 0 {
475 return &[];
476 }
477 // Safety: `ptr` and `len` describe a valid area of memory and `ptr`
478 // must be Rust-valid because `len` is non-zero.
479 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
480 }
481}
482
483impl Drop for Buffer {
484 fn drop(&mut self) {
485 // Safety: `ptr` is owned by this object and is on the BoringSSL heap.
486 unsafe {
487 bssl_sys::OPENSSL_free(self.ptr as *mut core::ffi::c_void);
488 }
489 }
490}
491
492fn as_cbs(buf: &[u8]) -> bssl_sys::CBS {
493 bssl_sys::CBS {
494 data: buf.as_ffi_ptr(),
495 len: buf.len(),
496 }
497}
498
499/// Calls `parse_func` with a `CBS` structure pointing at `data`.
500/// If that returns a null pointer then it returns [None].
501/// Otherwise, if there's still data left in CBS, it calls `free_func` on the
502/// pointer and returns [None]. Otherwise it returns the pointer.
503fn parse_with_cbs<T, Parse, Free>(data: &[u8], free_func: Free, parse_func: Parse) -> Option<*mut T>
504where
505 Parse: FnOnce(*mut bssl_sys::CBS) -> *mut T,
506 Free: FnOnce(*mut T),
507{
508 // Safety: type checking ensures that `cbs` is the correct size.
509 let mut cbs =
510 unsafe { initialized_struct(|cbs| bssl_sys::CBS_init(cbs, data.as_ffi_ptr(), data.len())) };
511 let ptr = parse_func(&mut cbs);
512 if ptr.is_null() {
513 return None;
514 }
515 // Safety: `cbs` is still valid after parsing.
516 if unsafe { bssl_sys::CBS_len(&cbs) } != 0 {
517 // Safety: `ptr` is still owned by this function.
518 free_func(ptr);
519 return None;
520 }
521 Some(ptr)
522}
523
524/// Calls `func` with a `CBB` pointer and returns a [Buffer] of the ultimate
525/// contents of that CBB.
526#[allow(clippy::unwrap_used)]
527pub fn cbb_to_buffer<F: FnOnce(*mut bssl_sys::CBB)>(initial_capacity: usize, func: F) -> Buffer {
528 // Safety: type checking ensures that `cbb` is the correct size.
529 let mut cbb = unsafe {
530 initialized_struct_fallible(|cbb| bssl_sys::CBB_init(cbb, initial_capacity) == 1)
531 }
532 // `CBB_init` only fails if out of memory, which isn't something that this crate handles.
533 .unwrap();
534 func(&mut cbb);
535
536 let mut ptr: *mut u8 = core::ptr::null_mut();
537 let mut len: usize = 0;
538 // `CBB_finish` only fails on programming error, which we convert into a
539 // panic.
540 assert_eq!(1, unsafe {
541 bssl_sys::CBB_finish(&mut cbb, &mut ptr, &mut len)
542 });
543
544 // Safety: `ptr` is on the BoringSSL heap and ownership is returned by
545 // `CBB_finish`.
546 unsafe { Buffer::new(ptr, len) }
547}
548
549/// Calls `func` with a `CBB` pointer that has been initialized to a vector
550/// of `len` bytes. That function must write exactly `len` bytes to the
551/// `CBB`. Those bytes are then returned as a vector.
552#[allow(clippy::unwrap_used)]
553fn cbb_to_vec<F: FnOnce(*mut bssl_sys::CBB)>(len: usize, func: F) -> Vec<u8> {
554 let mut boxed = Box::new_uninit_slice(len);
555 // Safety: type checking ensures that `cbb` is the correct size.
556 let mut cbb = unsafe {
557 initialized_struct_fallible(|cbb| {
558 bssl_sys::CBB_init_fixed(cbb, boxed.as_mut_ptr() as *mut u8, len) == 1
559 })
560 }
561 // `CBB_init_fixed` never fails and does not allocate.
562 .unwrap();
563
564 func(&mut cbb);
565
566 unsafe {
567 assert_eq!(bssl_sys::CBB_len(&cbb), len);
568 // `boxed` has been fully written, as checked on the previous line.
569 boxed.assume_init().into()
570 }
571}
572
573/// Used to prevent external implementations of internal traits.
574mod sealed {
575 pub struct SealedType;
576 pub trait Sealed {}
577}