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 
27 extern crate alloc;
28 extern crate core;
29 
30 #[cfg(feature = "mlalgs")]
31 use alloc::boxed::Box;
32 
33 use alloc::vec::Vec;
34 use core::ffi::c_void;
35 
36 #[macro_use]
37 mod macros;
38 
39 pub mod aead;
40 pub mod aes;
41 
42 /// Ciphers.
43 pub mod cipher;
44 
45 pub mod digest;
46 pub mod ec;
47 pub mod ecdh;
48 pub mod ecdsa;
49 pub mod ed25519;
50 pub mod hkdf;
51 pub mod hmac;
52 pub mod hpke;
53 #[cfg(feature = "mlalgs")]
54 pub mod mldsa;
55 #[cfg(feature = "mlalgs")]
56 pub mod mlkem;
57 pub mod rsa;
58 pub mod slhdsa;
59 pub mod x25519;
60 
61 mod scoped;
62 
63 #[cfg(test)]
64 mod test_helpers;
65 
66 mod mem;
67 pub use mem::constant_time_compare;
68 
69 mod rand;
70 pub use rand::{rand_array, rand_bytes};
71 
72 /// Error type for when a "signature" (either a public-key signature or a MAC)
73 /// is incorrect.
74 #[derive(Debug)]
75 pub struct InvalidSignatureError;
76 
77 /// FfiSlice exists to provide `as_ffi_ptr` on slices. Calling `as_ptr` on an
78 /// empty Rust slice may return the alignment of the type, rather than NULL, as
79 /// the pointer. When passing pointers into C/C++ code, that is not a valid
80 /// pointer. Thus this method should be used whenever passing a pointer to a
81 /// slice into BoringSSL code.
82 trait FfiSlice {
as_ffi_ptr(&self) -> *const u883     fn as_ffi_ptr(&self) -> *const u8;
as_ffi_void_ptr(&self) -> *const c_void84     fn as_ffi_void_ptr(&self) -> *const c_void {
85         self.as_ffi_ptr() as *const c_void
86     }
87 }
88 
89 impl FfiSlice for [u8] {
as_ffi_ptr(&self) -> *const u890     fn as_ffi_ptr(&self) -> *const u8 {
91         if self.is_empty() {
92             core::ptr::null()
93         } else {
94             self.as_ptr()
95         }
96     }
97 }
98 
99 impl<const N: usize> FfiSlice for [u8; N] {
as_ffi_ptr(&self) -> *const u8100     fn as_ffi_ptr(&self) -> *const u8 {
101         if N == 0 {
102             core::ptr::null()
103         } else {
104             self.as_ptr()
105         }
106     }
107 }
108 
109 /// See the comment [`FfiSlice`].
110 trait FfiMutSlice {
as_mut_ffi_ptr(&mut self) -> *mut u8111     fn as_mut_ffi_ptr(&mut self) -> *mut u8;
112 }
113 
114 impl FfiMutSlice for [u8] {
as_mut_ffi_ptr(&mut self) -> *mut u8115     fn as_mut_ffi_ptr(&mut self) -> *mut u8 {
116         if self.is_empty() {
117             core::ptr::null_mut()
118         } else {
119             self.as_mut_ptr()
120         }
121     }
122 }
123 
124 impl<const N: usize> FfiMutSlice for [u8; N] {
as_mut_ffi_ptr(&mut self) -> *mut u8125     fn as_mut_ffi_ptr(&mut self) -> *mut u8 {
126         if N == 0 {
127             core::ptr::null_mut()
128         } else {
129             self.as_mut_ptr()
130         }
131     }
132 }
133 
134 /// This is a helper struct which provides functions for passing slices over FFI.
135 ///
136 /// Deprecated: use `FfiSlice` which adds less noise and lets one grep for `as_ptr`
137 /// as a sign of something to check.
138 struct CSlice<'a>(&'a [u8]);
139 
140 impl<'a> From<&'a [u8]> for CSlice<'a> {
from(value: &'a [u8]) -> Self141     fn from(value: &'a [u8]) -> Self {
142         Self(value)
143     }
144 }
145 
146 impl CSlice<'_> {
147     /// Returns a raw pointer to the value, which is safe to pass over FFI.
as_ptr<T>(&self) -> *const T148     pub fn as_ptr<T>(&self) -> *const T {
149         if self.0.is_empty() {
150             core::ptr::null()
151         } else {
152             self.0.as_ptr() as *const T
153         }
154     }
155 
len(&self) -> usize156     pub fn len(&self) -> usize {
157         self.0.len()
158     }
159 }
160 
161 /// This is a helper struct which provides functions for passing mutable slices over FFI.
162 ///
163 /// Deprecated: use `FfiMutSlice` which adds less noise and lets one grep for
164 /// `as_ptr` as a sign of something to check.
165 struct CSliceMut<'a>(&'a mut [u8]);
166 
167 impl CSliceMut<'_> {
168     /// Returns a raw pointer to the value, which is safe to pass over FFI.
as_mut_ptr<T>(&mut self) -> *mut T169     pub fn as_mut_ptr<T>(&mut self) -> *mut T {
170         if self.0.is_empty() {
171             core::ptr::null_mut()
172         } else {
173             self.0.as_mut_ptr() as *mut T
174         }
175     }
176 
len(&self) -> usize177     pub fn len(&self) -> usize {
178         self.0.len()
179     }
180 }
181 
182 impl<'a> From<&'a mut [u8]> for CSliceMut<'a> {
from(value: &'a mut [u8]) -> Self183     fn from(value: &'a mut [u8]) -> Self {
184         Self(value)
185     }
186 }
187 
188 /// A helper trait implemented by types which reference borrowed foreign types.
189 ///
190 /// # Safety
191 ///
192 /// Implementations of `ForeignTypeRef` must guarantee the following:
193 ///
194 /// - `Self::from_ptr(x).as_ptr() == x`
195 /// - `Self::from_ptr_mut(x).as_ptr() == x`
196 unsafe trait ForeignTypeRef: Sized {
197     /// The raw C type.
198     type CType;
199 
200     /// Constructs a shared instance of this type from its raw type.
201     ///
202     /// # Safety
203     ///
204     /// `ptr` must be a valid, immutable, instance of the type for the `'a` lifetime.
205     #[inline]
from_ptr<'a>(ptr: *mut Self::CType) -> &'a Self206     unsafe fn from_ptr<'a>(ptr: *mut Self::CType) -> &'a Self {
207         debug_assert!(!ptr.is_null());
208         unsafe { &*(ptr as *mut _) }
209     }
210 
211     /// Returns a raw pointer to the wrapped value.
212     #[inline]
as_ptr(&self) -> *mut Self::CType213     fn as_ptr(&self) -> *mut Self::CType {
214         self as *const _ as *mut _
215     }
216 }
217 
218 /// Returns a BoringSSL structure that is initialized by some function.
219 /// Requires that the given function completely initializes the value.
220 ///
221 /// (Tagged `unsafe` because a no-op argument would otherwise expose
222 /// uninitialized memory.)
initialized_struct<T, F>(init: F) -> T where F: FnOnce(*mut T),223 unsafe fn initialized_struct<T, F>(init: F) -> T
224 where
225     F: FnOnce(*mut T),
226 {
227     let mut out_uninit = core::mem::MaybeUninit::<T>::uninit();
228     init(out_uninit.as_mut_ptr());
229     unsafe { out_uninit.assume_init() }
230 }
231 
232 /// Returns a BoringSSL structure that is initialized by some function.
233 /// Requires that the given function completely initializes the value or else
234 /// returns false.
235 ///
236 /// (Tagged `unsafe` because a no-op argument would otherwise expose
237 /// uninitialized memory.)
initialized_struct_fallible<T, F>(init: F) -> Option<T> where F: FnOnce(*mut T) -> bool,238 unsafe fn initialized_struct_fallible<T, F>(init: F) -> Option<T>
239 where
240     F: FnOnce(*mut T) -> bool,
241 {
242     let mut out_uninit = core::mem::MaybeUninit::<T>::uninit();
243     if init(out_uninit.as_mut_ptr()) {
244         Some(unsafe { out_uninit.assume_init() })
245     } else {
246         None
247     }
248 }
249 
250 /// Returns a boxed BoringSSL structure that is initialized by some function.
251 /// Requires that the given function completely initializes the value.
252 ///
253 /// Safety: the argument must fully initialize the pointed-to `T`.
254 #[cfg(feature = "mlalgs")]
initialized_boxed_struct<T, F>(init: F) -> Box<T> where F: FnOnce(*mut T),255 unsafe fn initialized_boxed_struct<T, F>(init: F) -> Box<T>
256 where
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.
270 #[cfg(feature = "mlalgs")]
initialized_boxed_struct_fallible<T, F>(init: F) -> Option<Box<T>> where F: FnOnce(*mut T) -> bool,271 unsafe fn initialized_boxed_struct_fallible<T, F>(init: F) -> Option<Box<T>>
272 where
273     F: FnOnce(*mut T) -> bool,
274 {
275     let mut out_uninit = Box::new(core::mem::MaybeUninit::<T>::uninit());
276     if init(out_uninit.as_mut_ptr()) {
277         Some(unsafe { out_uninit.assume_init() })
278     } else {
279         None
280     }
281 }
282 
283 /// Wrap a closure that initializes an output buffer and return that buffer as
284 /// an array. Requires that the closure fully initialize the given buffer.
285 ///
286 /// Safety: the closure must fully initialize the array.
with_output_array<const N: usize, F>(func: F) -> [u8; N] where F: FnOnce(*mut u8, usize),287 unsafe fn with_output_array<const N: usize, F>(func: F) -> [u8; N]
288 where
289     F: FnOnce(*mut u8, usize),
290 {
291     let mut out_uninit = core::mem::MaybeUninit::<[u8; N]>::uninit();
292     let out_ptr = if N != 0 {
293         out_uninit.as_mut_ptr() as *mut u8
294     } else {
295         core::ptr::null_mut()
296     };
297     func(out_ptr, N);
298     // Safety: `func` promises to fill all of `out_uninit`.
299     unsafe { out_uninit.assume_init() }
300 }
301 
302 /// Wrap a closure that initializes an output buffer and return that buffer as
303 /// an array. The closure returns a [`core::ffi::c_int`] and, if the return value
304 /// is not one, then the initialization is assumed to have failed and [None] is
305 /// returned. Otherwise, this function requires that the closure fully
306 /// initialize the given buffer.
307 ///
308 /// Safety: the closure must fully initialize the array if it returns one.
with_output_array_fallible<const N: usize, F>(func: F) -> Option<[u8; N]> where F: FnOnce(*mut u8, usize) -> bool,309 unsafe fn with_output_array_fallible<const N: usize, F>(func: F) -> Option<[u8; N]>
310 where
311     F: FnOnce(*mut u8, usize) -> bool,
312 {
313     let mut out_uninit = core::mem::MaybeUninit::<[u8; N]>::uninit();
314     let out_ptr = if N != 0 {
315         out_uninit.as_mut_ptr() as *mut u8
316     } else {
317         core::ptr::null_mut()
318     };
319     if func(out_ptr, N) {
320         // Safety: `func` promises to fill all of `out_uninit` if it returns one.
321         unsafe { Some(out_uninit.assume_init()) }
322     } else {
323         None
324     }
325 }
326 
327 /// Wrap a closure that writes at most `max_output` bytes to fill a vector.
328 /// It must return the number of bytes written.
329 ///
330 /// Safety: `F` must not write more than `max_output` bytes and must return
331 /// the number of bytes written.
332 #[allow(clippy::unwrap_used)]
with_output_vec<F>(max_output: usize, func: F) -> Vec<u8> where F: FnOnce(*mut u8) -> usize,333 unsafe fn with_output_vec<F>(max_output: usize, func: F) -> Vec<u8>
334 where
335     F: FnOnce(*mut u8) -> usize,
336 {
337     unsafe {
338         with_output_vec_fallible(max_output, |out_buf| Some(func(out_buf)))
339             // The closure cannot fail and thus neither can
340             // `with_output_array_fallible`.
341             .unwrap()
342     }
343 }
344 
345 /// Wrap a closure that writes at most `max_output` bytes to fill a vector.
346 /// If successful, it must return the number of bytes written.
347 ///
348 /// Safety: `F` must not write more than `max_output` bytes and must return
349 /// the number of bytes written or else return `None` to indicate failure.
with_output_vec_fallible<F>(max_output: usize, func: F) -> Option<Vec<u8>> where F: FnOnce(*mut u8) -> Option<usize>,350 unsafe fn with_output_vec_fallible<F>(max_output: usize, func: F) -> Option<Vec<u8>>
351 where
352     F: FnOnce(*mut u8) -> Option<usize>,
353 {
354     let mut ret = Vec::with_capacity(max_output);
355     let out = ret.spare_capacity_mut();
356     let out_buf = out
357         .get_mut(0)
358         .map_or(core::ptr::null_mut(), |x| x.as_mut_ptr());
359 
360     let num_written = func(out_buf)?;
361     assert!(num_written <= ret.capacity());
362 
363     unsafe {
364         // Safety: `num_written` bytes have been written to.
365         ret.set_len(num_written);
366     }
367 
368     Some(ret)
369 }
370 
371 /// Buffer represents an owned chunk of memory on the BoringSSL heap.
372 /// Call `as_ref()` to get a `&[u8]` from it.
373 pub struct Buffer {
374     // This pointer is always allocated by BoringSSL and must be freed using
375     // `OPENSSL_free`.
376     ptr: *mut u8,
377     len: usize,
378 }
379 
380 impl Buffer {
381     /// Safety: `ptr` must point to `len` bytes, allocated by BoringSSL.
new(ptr: *mut u8, len: usize) -> Buffer382     unsafe fn new(ptr: *mut u8, len: usize) -> Buffer {
383         Buffer { ptr, len }
384     }
385 }
386 
387 impl AsRef<[u8]> for Buffer {
as_ref(&self) -> &[u8]388     fn as_ref(&self) -> &[u8] {
389         if self.len == 0 {
390             return &[];
391         }
392         // Safety: `ptr` and `len` describe a valid area of memory and `ptr`
393         // must be Rust-valid because `len` is non-zero.
394         unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
395     }
396 }
397 
398 impl Drop for Buffer {
drop(&mut self)399     fn drop(&mut self) {
400         // Safety: `ptr` is owned by this object and is on the BoringSSL heap.
401         unsafe {
402             bssl_sys::OPENSSL_free(self.ptr as *mut core::ffi::c_void);
403         }
404     }
405 }
406 
407 #[cfg(feature = "mlalgs")]
as_cbs(buf: &[u8]) -> bssl_sys::CBS408 fn as_cbs(buf: &[u8]) -> bssl_sys::CBS {
409     bssl_sys::CBS {
410         data: buf.as_ffi_ptr(),
411         len: buf.len(),
412     }
413 }
414 
415 /// Calls `parse_func` with a `CBS` structure pointing at `data`.
416 /// If that returns a null pointer then it returns [None].
417 /// Otherwise, if there's still data left in CBS, it calls `free_func` on the
418 /// pointer and returns [None]. Otherwise it returns the pointer.
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),419 fn parse_with_cbs<T, Parse, Free>(data: &[u8], free_func: Free, parse_func: Parse) -> Option<*mut T>
420 where
421     Parse: FnOnce(*mut bssl_sys::CBS) -> *mut T,
422     Free: FnOnce(*mut T),
423 {
424     // Safety: type checking ensures that `cbs` is the correct size.
425     let mut cbs =
426         unsafe { initialized_struct(|cbs| bssl_sys::CBS_init(cbs, data.as_ffi_ptr(), data.len())) };
427     let ptr = parse_func(&mut cbs);
428     if ptr.is_null() {
429         return None;
430     }
431     // Safety: `cbs` is still valid after parsing.
432     if unsafe { bssl_sys::CBS_len(&cbs) } != 0 {
433         // Safety: `ptr` is still owned by this function.
434         free_func(ptr);
435         return None;
436     }
437     Some(ptr)
438 }
439 
440 /// Calls `func` with a `CBB` pointer and returns a [Buffer] of the ultimate
441 /// contents of that CBB.
442 #[allow(clippy::unwrap_used)]
cbb_to_buffer<F: FnOnce(*mut bssl_sys::CBB)>(initial_capacity: usize, func: F) -> Buffer443 fn cbb_to_buffer<F: FnOnce(*mut bssl_sys::CBB)>(initial_capacity: usize, func: F) -> Buffer {
444     // Safety: type checking ensures that `cbb` is the correct size.
445     let mut cbb = unsafe {
446         initialized_struct_fallible(|cbb| bssl_sys::CBB_init(cbb, initial_capacity) == 1)
447     }
448     // `CBB_init` only fails if out of memory, which isn't something that this crate handles.
449     .unwrap();
450     func(&mut cbb);
451 
452     let mut ptr: *mut u8 = core::ptr::null_mut();
453     let mut len: usize = 0;
454     // `CBB_finish` only fails on programming error, which we convert into a
455     // panic.
456     assert_eq!(1, unsafe {
457         bssl_sys::CBB_finish(&mut cbb, &mut ptr, &mut len)
458     });
459 
460     // Safety: `ptr` is on the BoringSSL heap and ownership is returned by
461     // `CBB_finish`.
462     unsafe { Buffer::new(ptr, len) }
463 }
464 
465 #[cfg(feature = "mlalgs")]
466 /// Calls `func` with a `CBB` pointer that has been initialized to a vector
467 /// of `len` bytes. That function must write exactly `len` bytes to the
468 /// `CBB`. Those bytes are then returned as a vector.
469 #[allow(clippy::unwrap_used)]
cbb_to_vec<F: FnOnce(*mut bssl_sys::CBB)>(len: usize, func: F) -> Vec<u8>470 fn cbb_to_vec<F: FnOnce(*mut bssl_sys::CBB)>(len: usize, func: F) -> Vec<u8> {
471     let mut boxed = Box::new_uninit_slice(len);
472     // Safety: type checking ensures that `cbb` is the correct size.
473     let mut cbb = unsafe {
474         initialized_struct_fallible(|cbb| {
475             bssl_sys::CBB_init_fixed(cbb, boxed.as_mut_ptr() as *mut u8, len) == 1
476         })
477     }
478     // `CBB_init_fixed` never fails and does not allocate.
479     .unwrap();
480 
481     func(&mut cbb);
482 
483     unsafe {
484         assert_eq!(bssl_sys::CBB_len(&cbb), len);
485         // `boxed` has been fully written, as checked on the previous line.
486         boxed.assume_init().into()
487     }
488 }
489 
490 /// Used to prevent external implementations of internal traits.
491 mod sealed {
492     pub struct Sealed;
493 }
494