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