bssl_crypto/lib.rs
1/* Copyright 2023 The BoringSSL Authors
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 */
15
16#![deny(
17 missing_docs,
18 unsafe_op_in_unsafe_fn,
19 clippy::indexing_slicing,
20 clippy::unwrap_used,
21 clippy::panic,
22 clippy::expect_used
23)]
24#![cfg_attr(not(any(feature = "std", test)), no_std)]
25
26//! Rust BoringSSL bindings
27
28extern crate alloc;
29extern crate core;
30
31#[cfg(feature = "mlalgs")]
32use alloc::boxed::Box;
33
34use alloc::vec::Vec;
35use core::ffi::c_void;
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;
54#[cfg(feature = "mlalgs")]
55pub mod mldsa;
56#[cfg(feature = "mlalgs")]
57pub mod mlkem;
58pub mod rsa;
59pub mod slhdsa;
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.
83trait FfiSlice {
84 fn as_ffi_ptr(&self) -> *const u8;
85 fn as_ffi_void_ptr(&self) -> *const c_void {
86 self.as_ffi_ptr() as *const c_void
87 }
88}
89
90impl FfiSlice for [u8] {
91 fn as_ffi_ptr(&self) -> *const u8 {
92 if self.is_empty() {
93 core::ptr::null()
94 } else {
95 self.as_ptr()
96 }
97 }
98}
99
100impl<const N: usize> FfiSlice for [u8; N] {
101 fn as_ffi_ptr(&self) -> *const u8 {
102 if N == 0 {
103 core::ptr::null()
104 } else {
105 self.as_ptr()
106 }
107 }
108}
109
110/// See the comment [`FfiSlice`].
111trait FfiMutSlice {
112 fn as_mut_ffi_ptr(&mut self) -> *mut u8;
113}
114
115impl FfiMutSlice for [u8] {
116 fn as_mut_ffi_ptr(&mut self) -> *mut u8 {
117 if self.is_empty() {
118 core::ptr::null_mut()
119 } else {
120 self.as_mut_ptr()
121 }
122 }
123}
124
125impl<const N: usize> FfiMutSlice for [u8; N] {
126 fn as_mut_ffi_ptr(&mut self) -> *mut u8 {
127 if N == 0 {
128 core::ptr::null_mut()
129 } else {
130 self.as_mut_ptr()
131 }
132 }
133}
134
135/// This is a helper struct which provides functions for passing slices over FFI.
136///
137/// Deprecated: use `FfiSlice` which adds less noise and lets one grep for `as_ptr`
138/// as a sign of something to check.
139struct CSlice<'a>(&'a [u8]);
140
141impl<'a> From<&'a [u8]> for CSlice<'a> {
142 fn from(value: &'a [u8]) -> Self {
143 Self(value)
144 }
145}
146
147impl CSlice<'_> {
148 /// Returns a raw pointer to the value, which is safe to pass over FFI.
149 pub fn as_ptr<T>(&self) -> *const T {
150 if self.0.is_empty() {
151 core::ptr::null()
152 } else {
153 self.0.as_ptr() as *const T
154 }
155 }
156
157 pub fn len(&self) -> usize {
158 self.0.len()
159 }
160}
161
162/// This is a helper struct which provides functions for passing mutable slices over FFI.
163///
164/// Deprecated: use `FfiMutSlice` which adds less noise and lets one grep for
165/// `as_ptr` as a sign of something to check.
166struct CSliceMut<'a>(&'a mut [u8]);
167
168impl CSliceMut<'_> {
169 /// Returns a raw pointer to the value, which is safe to pass over FFI.
170 pub fn as_mut_ptr<T>(&mut self) -> *mut T {
171 if self.0.is_empty() {
172 core::ptr::null_mut()
173 } else {
174 self.0.as_mut_ptr() as *mut T
175 }
176 }
177
178 pub fn len(&self) -> usize {
179 self.0.len()
180 }
181}
182
183impl<'a> From<&'a mut [u8]> for CSliceMut<'a> {
184 fn from(value: &'a mut [u8]) -> Self {
185 Self(value)
186 }
187}
188
189/// A helper trait implemented by types which reference borrowed foreign types.
190///
191/// # Safety
192///
193/// Implementations of `ForeignTypeRef` must guarantee the following:
194///
195/// - `Self::from_ptr(x).as_ptr() == x`
196/// - `Self::from_ptr_mut(x).as_ptr() == x`
197unsafe trait ForeignTypeRef: Sized {
198 /// The raw C type.
199 type CType;
200
201 /// Constructs a shared instance of this type from its raw type.
202 ///
203 /// # Safety
204 ///
205 /// `ptr` must be a valid, immutable, instance of the type for the `'a` lifetime.
206 #[inline]
207 unsafe fn from_ptr<'a>(ptr: *mut Self::CType) -> &'a Self {
208 debug_assert!(!ptr.is_null());
209 unsafe { &*(ptr as *mut _) }
210 }
211
212 /// Returns a raw pointer to the wrapped value.
213 #[inline]
214 fn as_ptr(&self) -> *mut Self::CType {
215 self as *const _ as *mut _
216 }
217}
218
219/// Returns a BoringSSL structure that is initialized by some function.
220/// Requires that the given function completely initializes the value.
221///
222/// (Tagged `unsafe` because a no-op argument would otherwise expose
223/// uninitialized memory.)
224unsafe fn initialized_struct<T, F>(init: F) -> T
225where
226 F: FnOnce(*mut T),
227{
228 let mut out_uninit = core::mem::MaybeUninit::<T>::uninit();
229 init(out_uninit.as_mut_ptr());
230 unsafe { out_uninit.assume_init() }
231}
232
233/// Returns a BoringSSL structure that is initialized by some function.
234/// Requires that the given function completely initializes the value or else
235/// returns false.
236///
237/// (Tagged `unsafe` because a no-op argument would otherwise expose
238/// uninitialized memory.)
239unsafe fn initialized_struct_fallible<T, F>(init: F) -> Option<T>
240where
241 F: FnOnce(*mut T) -> bool,
242{
243 let mut out_uninit = core::mem::MaybeUninit::<T>::uninit();
244 if init(out_uninit.as_mut_ptr()) {
245 Some(unsafe { out_uninit.assume_init() })
246 } else {
247 None
248 }
249}
250
251/// Returns a boxed BoringSSL structure that is initialized by some function.
252/// Requires that the given function completely initializes the value.
253///
254/// Safety: the argument must fully initialize the pointed-to `T`.
255#[cfg(feature = "mlalgs")]
256unsafe fn initialized_boxed_struct<T, F>(init: F) -> Box<T>
257where
258 F: FnOnce(*mut T),
259{
260 let mut out_uninit = Box::new(core::mem::MaybeUninit::<T>::uninit());
261 init(out_uninit.as_mut_ptr());
262 unsafe { out_uninit.assume_init() }
263}
264
265/// Returns a boxed BoringSSL structure that is initialized by some function.
266/// Requires that the given function completely initializes the value or else
267/// returns false.
268///
269/// Safety: the argument must fully initialize the pointed-to `T` if it returns
270/// true. If it returns false then there are no safety requirements.
271#[cfg(feature = "mlalgs")]
272unsafe fn initialized_boxed_struct_fallible<T, F>(init: F) -> Option<Box<T>>
273where
274 F: FnOnce(*mut T) -> bool,
275{
276 let mut out_uninit = Box::new(core::mem::MaybeUninit::<T>::uninit());
277 if init(out_uninit.as_mut_ptr()) {
278 Some(unsafe { out_uninit.assume_init() })
279 } else {
280 None
281 }
282}
283
284/// Wrap a closure that initializes an output buffer and return that buffer as
285/// an array. Requires that the closure fully initialize the given buffer.
286///
287/// Safety: the closure must fully initialize the array.
288unsafe fn with_output_array<const N: usize, F>(func: F) -> [u8; N]
289where
290 F: FnOnce(*mut u8, usize),
291{
292 let mut out_uninit = core::mem::MaybeUninit::<[u8; N]>::uninit();
293 let out_ptr = if N != 0 {
294 out_uninit.as_mut_ptr() as *mut u8
295 } else {
296 core::ptr::null_mut()
297 };
298 func(out_ptr, N);
299 // Safety: `func` promises to fill all of `out_uninit`.
300 unsafe { out_uninit.assume_init() }
301}
302
303/// Wrap a closure that initializes an output buffer and return that buffer as
304/// an array. The closure returns a [`core::ffi::c_int`] and, if the return value
305/// is not one, then the initialization is assumed to have failed and [None] is
306/// returned. Otherwise, this function requires that the closure fully
307/// initialize the given buffer.
308///
309/// Safety: the closure must fully initialize the array if it returns one.
310unsafe fn with_output_array_fallible<const N: usize, F>(func: F) -> Option<[u8; N]>
311where
312 F: FnOnce(*mut u8, usize) -> bool,
313{
314 let mut out_uninit = core::mem::MaybeUninit::<[u8; N]>::uninit();
315 let out_ptr = if N != 0 {
316 out_uninit.as_mut_ptr() as *mut u8
317 } else {
318 core::ptr::null_mut()
319 };
320 if func(out_ptr, N) {
321 // Safety: `func` promises to fill all of `out_uninit` if it returns one.
322 unsafe { Some(out_uninit.assume_init()) }
323 } else {
324 None
325 }
326}
327
328/// Wrap a closure that writes at most `max_output` bytes to fill a vector.
329/// It must return the number of bytes written.
330///
331/// Safety: `F` must not write more than `max_output` bytes and must return
332/// the number of bytes written.
333#[allow(clippy::unwrap_used)]
334unsafe fn with_output_vec<F>(max_output: usize, func: F) -> Vec<u8>
335where
336 F: FnOnce(*mut u8) -> usize,
337{
338 unsafe {
339 with_output_vec_fallible(max_output, |out_buf| Some(func(out_buf)))
340 // The closure cannot fail and thus neither can
341 // `with_output_array_fallible`.
342 .unwrap()
343 }
344}
345
346/// Wrap a closure that writes at most `max_output` bytes to fill a vector.
347/// If successful, it must return the number of bytes written.
348///
349/// Safety: `F` must not write more than `max_output` bytes and must return
350/// the number of bytes written or else return `None` to indicate failure.
351unsafe fn with_output_vec_fallible<F>(max_output: usize, func: F) -> Option<Vec<u8>>
352where
353 F: FnOnce(*mut u8) -> Option<usize>,
354{
355 let mut ret = Vec::with_capacity(max_output);
356 let out = ret.spare_capacity_mut();
357 let out_buf = out
358 .get_mut(0)
359 .map_or(core::ptr::null_mut(), |x| x.as_mut_ptr());
360
361 let num_written = func(out_buf)?;
362 assert!(num_written <= ret.capacity());
363
364 unsafe {
365 // Safety: `num_written` bytes have been written to.
366 ret.set_len(num_written);
367 }
368
369 Some(ret)
370}
371
372/// Buffer represents an owned chunk of memory on the BoringSSL heap.
373/// Call `as_ref()` to get a `&[u8]` from it.
374pub struct Buffer {
375 // This pointer is always allocated by BoringSSL and must be freed using
376 // `OPENSSL_free`.
377 ptr: *mut u8,
378 len: usize,
379}
380
381impl Buffer {
382 /// Safety: `ptr` must point to `len` bytes, allocated by BoringSSL.
383 unsafe fn new(ptr: *mut u8, len: usize) -> Buffer {
384 Buffer { ptr, len }
385 }
386}
387
388impl AsRef<[u8]> for Buffer {
389 fn as_ref(&self) -> &[u8] {
390 if self.len == 0 {
391 return &[];
392 }
393 // Safety: `ptr` and `len` describe a valid area of memory and `ptr`
394 // must be Rust-valid because `len` is non-zero.
395 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
396 }
397}
398
399impl Drop for Buffer {
400 fn drop(&mut self) {
401 // Safety: `ptr` is owned by this object and is on the BoringSSL heap.
402 unsafe {
403 bssl_sys::OPENSSL_free(self.ptr as *mut core::ffi::c_void);
404 }
405 }
406}
407
408#[cfg(feature = "mlalgs")]
409fn as_cbs(buf: &[u8]) -> bssl_sys::CBS {
410 bssl_sys::CBS {
411 data: buf.as_ffi_ptr(),
412 len: buf.len(),
413 }
414}
415
416/// Calls `parse_func` with a `CBS` structure pointing at `data`.
417/// If that returns a null pointer then it returns [None].
418/// Otherwise, if there's still data left in CBS, it calls `free_func` on the
419/// pointer and returns [None]. Otherwise it returns the pointer.
420fn parse_with_cbs<T, Parse, Free>(data: &[u8], free_func: Free, parse_func: Parse) -> Option<*mut T>
421where
422 Parse: FnOnce(*mut bssl_sys::CBS) -> *mut T,
423 Free: FnOnce(*mut T),
424{
425 // Safety: type checking ensures that `cbs` is the correct size.
426 let mut cbs =
427 unsafe { initialized_struct(|cbs| bssl_sys::CBS_init(cbs, data.as_ffi_ptr(), data.len())) };
428 let ptr = parse_func(&mut cbs);
429 if ptr.is_null() {
430 return None;
431 }
432 // Safety: `cbs` is still valid after parsing.
433 if unsafe { bssl_sys::CBS_len(&cbs) } != 0 {
434 // Safety: `ptr` is still owned by this function.
435 free_func(ptr);
436 return None;
437 }
438 Some(ptr)
439}
440
441/// Calls `func` with a `CBB` pointer and returns a [Buffer] of the ultimate
442/// contents of that CBB.
443#[allow(clippy::unwrap_used)]
444fn cbb_to_buffer<F: FnOnce(*mut bssl_sys::CBB)>(initial_capacity: usize, func: F) -> Buffer {
445 // Safety: type checking ensures that `cbb` is the correct size.
446 let mut cbb = unsafe {
447 initialized_struct_fallible(|cbb| bssl_sys::CBB_init(cbb, initial_capacity) == 1)
448 }
449 // `CBB_init` only fails if out of memory, which isn't something that this crate handles.
450 .unwrap();
451 func(&mut cbb);
452
453 let mut ptr: *mut u8 = core::ptr::null_mut();
454 let mut len: usize = 0;
455 // `CBB_finish` only fails on programming error, which we convert into a
456 // panic.
457 assert_eq!(1, unsafe {
458 bssl_sys::CBB_finish(&mut cbb, &mut ptr, &mut len)
459 });
460
461 // Safety: `ptr` is on the BoringSSL heap and ownership is returned by
462 // `CBB_finish`.
463 unsafe { Buffer::new(ptr, len) }
464}
465
466#[cfg(feature = "mlalgs")]
467/// Calls `func` with a `CBB` pointer that has been initialized to a vector
468/// of `len` bytes. That function must write exactly `len` bytes to the
469/// `CBB`. Those bytes are then returned as a vector.
470#[allow(clippy::unwrap_used)]
471fn cbb_to_vec<F: FnOnce(*mut bssl_sys::CBB)>(len: usize, func: F) -> Vec<u8> {
472 let mut boxed = Box::new_uninit_slice(len);
473 // Safety: type checking ensures that `cbb` is the correct size.
474 let mut cbb = unsafe {
475 initialized_struct_fallible(|cbb| {
476 bssl_sys::CBB_init_fixed(cbb, boxed.as_mut_ptr() as *mut u8, len) == 1
477 })
478 }
479 // `CBB_init_fixed` never fails and does not allocate.
480 .unwrap();
481
482 func(&mut cbb);
483
484 unsafe {
485 assert_eq!(bssl_sys::CBB_len(&cbb), len);
486 // `boxed` has been fully written, as checked on the previous line.
487 boxed.assume_init().into()
488 }
489}
490
491/// Used to prevent external implementations of internal traits.
492mod sealed {
493 pub struct Sealed;
494}