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::ffi::c_void;
33
34#[macro_use]
35mod macros;
36
37pub mod aead;
38pub mod aes;
39
40/// Ciphers.
41pub mod cipher;
42
43pub mod digest;
44pub mod ec;
45pub mod ecdh;
46pub mod ecdsa;
47pub mod ed25519;
48pub mod hkdf;
49pub mod hmac;
50pub mod hpke;
51pub mod mldsa;
52pub mod mlkem;
53pub mod pkcs8;
54pub mod rsa;
55pub mod slhdsa;
56pub mod tls12_prf;
57pub mod x25519;
58
59mod scoped;
60
61#[cfg(test)]
62mod test_helpers;
63
64mod mem;
65pub use mem::constant_time_compare;
66
67mod rand;
68pub use rand::{rand_array, rand_bytes};
69
70/// Error type for when a "signature" (either a public-key signature or a MAC)
71/// is incorrect.
72#[derive(Debug)]
73pub struct InvalidSignatureError;
74
75/// FfiSlice exists to provide `as_ffi_ptr` on slices. Calling `as_ptr` on an
76/// empty Rust slice may return the alignment of the type, rather than NULL, as
77/// the pointer. When passing pointers into C/C++ code, that is not a valid
78/// pointer. Thus this method should be used whenever passing a pointer to a
79/// slice into BoringSSL code.
80pub trait FfiSlice<T> {
81 /// Cast the slice into a valid raw pointer for FFI.
82 fn as_ffi_ptr(&self) -> *const T;
83 /// Cast the slice into a valid `const void *` pointer for FFI.
84 fn as_ffi_void_ptr(&self) -> *const c_void {
85 self.as_ffi_ptr() as *const c_void
86 }
87}
88
89impl<T> FfiSlice<T> for [T] {
90 fn as_ffi_ptr(&self) -> *const T {
91 if self.is_empty() {
92 core::ptr::null()
93 } else {
94 self.as_ptr()
95 }
96 }
97}
98
99impl<T, const N: usize> FfiSlice<T> for [T; N] {
100 fn as_ffi_ptr(&self) -> *const T {
101 if N == 0 {
102 core::ptr::null()
103 } else {
104 self.as_ptr()
105 }
106 }
107}
108
109/// See the comment [`FfiSlice`].
110pub trait FfiMutSlice {
111 /// Cast the mutable slice as a valid `uint8_t*` pointer for FFI.
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`.
255unsafe fn initialized_boxed_struct<T, F>(init: F) -> Box<T>
256where
257 F: FnOnce(*mut T),
258{
259 let mut out_uninit = Box::new(core::mem::MaybeUninit::<T>::uninit());
260 init(out_uninit.as_mut_ptr());
261 unsafe { out_uninit.assume_init() }
262}
263
264/// Returns a boxed BoringSSL structure that is initialized by some function.
265/// Requires that the given function completely initializes the value or else
266/// returns false.
267///
268/// Safety: the argument must fully initialize the pointed-to `T` if it returns
269/// true. If it returns false then there are no safety requirements.
270unsafe fn initialized_boxed_struct_fallible<T, F>(init: F) -> Option<Box<T>>
271where
272 F: FnOnce(*mut T) -> bool,
273{
274 let mut out_uninit = Box::new(core::mem::MaybeUninit::<T>::uninit());
275 if init(out_uninit.as_mut_ptr()) {
276 Some(unsafe { out_uninit.assume_init() })
277 } else {
278 None
279 }
280}
281
282/// Wrap a closure that initializes an output buffer and return that buffer as
283/// an array. Requires that the closure fully initialize the given buffer.
284///
285/// Safety: the closure must fully initialize the array.
286unsafe fn with_output_array<const N: usize, F>(func: F) -> [u8; N]
287where
288 F: FnOnce(*mut u8, usize),
289{
290 let mut out_uninit = core::mem::MaybeUninit::<[u8; N]>::uninit();
291 let out_ptr = if N != 0 {
292 out_uninit.as_mut_ptr() as *mut u8
293 } else {
294 core::ptr::null_mut()
295 };
296 func(out_ptr, N);
297 // Safety: `func` promises to fill all of `out_uninit`.
298 unsafe { out_uninit.assume_init() }
299}
300
301/// Wrap a closure that initializes an output buffer and return that buffer as
302/// an array. The closure returns a [`core::ffi::c_int`] and, if the return value
303/// is not one, then the initialization is assumed to have failed and [None] is
304/// returned. Otherwise, this function requires that the closure fully
305/// initialize the given buffer.
306///
307/// Safety: the closure must fully initialize the array if it returns one.
308unsafe fn with_output_array_fallible<const N: usize, F>(func: F) -> Option<[u8; N]>
309where
310 F: FnOnce(*mut u8, usize) -> bool,
311{
312 let mut out_uninit = core::mem::MaybeUninit::<[u8; N]>::uninit();
313 let out_ptr = if N != 0 {
314 out_uninit.as_mut_ptr() as *mut u8
315 } else {
316 core::ptr::null_mut()
317 };
318 if func(out_ptr, N) {
319 // Safety: `func` promises to fill all of `out_uninit` if it returns one.
320 unsafe { Some(out_uninit.assume_init()) }
321 } else {
322 None
323 }
324}
325
326/// Wrap a closure that writes at most `max_output` bytes to fill a vector.
327/// It must return the number of bytes written.
328///
329/// Safety: `F` must not write more than `max_output` bytes and must return
330/// the number of bytes written.
331#[allow(clippy::unwrap_used)]
332unsafe fn with_output_vec<F>(max_output: usize, func: F) -> Vec<u8>
333where
334 F: FnOnce(*mut u8) -> usize,
335{
336 unsafe {
337 with_output_vec_fallible(max_output, |out_buf| Some(func(out_buf)))
338 // The closure cannot fail and thus neither can
339 // `with_output_array_fallible`.
340 .unwrap()
341 }
342}
343
344/// Wrap a closure that writes at most `max_output` bytes to fill a vector.
345/// If successful, it must return the number of bytes written.
346///
347/// Safety: `F` must not write more than `max_output` bytes and must return
348/// the number of bytes written or else return `None` to indicate failure.
349unsafe fn with_output_vec_fallible<F>(max_output: usize, func: F) -> Option<Vec<u8>>
350where
351 F: FnOnce(*mut u8) -> Option<usize>,
352{
353 let mut ret = Vec::with_capacity(max_output);
354 let out = ret.spare_capacity_mut();
355 let out_buf = out
356 .get_mut(0)
357 .map_or(core::ptr::null_mut(), |x| x.as_mut_ptr());
358
359 let num_written = func(out_buf)?;
360 assert!(num_written <= ret.capacity());
361
362 unsafe {
363 // Safety: `num_written` bytes have been written to.
364 ret.set_len(num_written);
365 }
366
367 Some(ret)
368}
369
370/// Buffer represents an owned chunk of memory on the BoringSSL heap.
371/// Call `as_ref()` to get a `&[u8]` from it.
372pub struct Buffer {
373 // This pointer is always allocated by BoringSSL and must be freed using
374 // `OPENSSL_free`.
375 ptr: *mut u8,
376 len: usize,
377}
378
379impl Buffer {
380 /// Safety: `ptr` must point to `len` bytes, allocated by BoringSSL.
381 unsafe fn new(ptr: *mut u8, len: usize) -> Buffer {
382 Buffer { ptr, len }
383 }
384}
385
386impl AsRef<[u8]> for Buffer {
387 fn as_ref(&self) -> &[u8] {
388 if self.len == 0 {
389 return &[];
390 }
391 // Safety: `ptr` and `len` describe a valid area of memory and `ptr`
392 // must be Rust-valid because `len` is non-zero.
393 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
394 }
395}
396
397impl Drop for Buffer {
398 fn drop(&mut self) {
399 // Safety: `ptr` is owned by this object and is on the BoringSSL heap.
400 unsafe {
401 bssl_sys::OPENSSL_free(self.ptr as *mut core::ffi::c_void);
402 }
403 }
404}
405
406fn as_cbs(buf: &[u8]) -> bssl_sys::CBS {
407 bssl_sys::CBS {
408 data: buf.as_ffi_ptr(),
409 len: buf.len(),
410 }
411}
412
413/// Calls `parse_func` with a `CBS` structure pointing at `data`.
414/// If that returns a null pointer then it returns [None].
415/// Otherwise, if there's still data left in CBS, it calls `free_func` on the
416/// pointer and returns [None]. Otherwise it returns the pointer.
417fn parse_with_cbs<T, Parse, Free>(data: &[u8], free_func: Free, parse_func: Parse) -> Option<*mut T>
418where
419 Parse: FnOnce(*mut bssl_sys::CBS) -> *mut T,
420 Free: FnOnce(*mut T),
421{
422 // Safety: type checking ensures that `cbs` is the correct size.
423 let mut cbs =
424 unsafe { initialized_struct(|cbs| bssl_sys::CBS_init(cbs, data.as_ffi_ptr(), data.len())) };
425 let ptr = parse_func(&mut cbs);
426 if ptr.is_null() {
427 return None;
428 }
429 // Safety: `cbs` is still valid after parsing.
430 if unsafe { bssl_sys::CBS_len(&cbs) } != 0 {
431 // Safety: `ptr` is still owned by this function.
432 free_func(ptr);
433 return None;
434 }
435 Some(ptr)
436}
437
438/// Calls `func` with a `CBB` pointer and returns a [Buffer] of the ultimate
439/// contents of that CBB.
440#[allow(clippy::unwrap_used)]
441pub fn cbb_to_buffer<F: FnOnce(*mut bssl_sys::CBB)>(initial_capacity: usize, func: F) -> Buffer {
442 // Safety: type checking ensures that `cbb` is the correct size.
443 let mut cbb = unsafe {
444 initialized_struct_fallible(|cbb| bssl_sys::CBB_init(cbb, initial_capacity) == 1)
445 }
446 // `CBB_init` only fails if out of memory, which isn't something that this crate handles.
447 .unwrap();
448 func(&mut cbb);
449
450 let mut ptr: *mut u8 = core::ptr::null_mut();
451 let mut len: usize = 0;
452 // `CBB_finish` only fails on programming error, which we convert into a
453 // panic.
454 assert_eq!(1, unsafe {
455 bssl_sys::CBB_finish(&mut cbb, &mut ptr, &mut len)
456 });
457
458 // Safety: `ptr` is on the BoringSSL heap and ownership is returned by
459 // `CBB_finish`.
460 unsafe { Buffer::new(ptr, len) }
461}
462
463/// Calls `func` with a `CBB` pointer that has been initialized to a vector
464/// of `len` bytes. That function must write exactly `len` bytes to the
465/// `CBB`. Those bytes are then returned as a vector.
466#[allow(clippy::unwrap_used)]
467fn cbb_to_vec<F: FnOnce(*mut bssl_sys::CBB)>(len: usize, func: F) -> Vec<u8> {
468 let mut boxed = Box::new_uninit_slice(len);
469 // Safety: type checking ensures that `cbb` is the correct size.
470 let mut cbb = unsafe {
471 initialized_struct_fallible(|cbb| {
472 bssl_sys::CBB_init_fixed(cbb, boxed.as_mut_ptr() as *mut u8, len) == 1
473 })
474 }
475 // `CBB_init_fixed` never fails and does not allocate.
476 .unwrap();
477
478 func(&mut cbb);
479
480 unsafe {
481 assert_eq!(bssl_sys::CBB_len(&cbb), len);
482 // `boxed` has been fully written, as checked on the previous line.
483 boxed.assume_init().into()
484 }
485}
486
487/// Used to prevent external implementations of internal traits.
488mod sealed {
489 pub struct SealedType;
490 pub trait Sealed {}
491}