blob: 4263be5e103d40383d18399dfd541bccc9ef66ce [file] [log] [blame]
Nabil Wadihbe792832023-02-14 11:46:37 -08001/* Copyright (c) 2023, Google Inc.
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,
Nabil Wadihfa7afff2023-04-14 13:21:48 -070018 unsafe_op_in_unsafe_fn,
Nabil Wadihbe792832023-02-14 11:46:37 -080019 clippy::indexing_slicing,
20 clippy::unwrap_used,
21 clippy::panic,
22 clippy::expect_used
23)]
Alice Wangcfcb9542023-09-21 14:02:07 +000024#![cfg_attr(not(any(feature = "std", test)), no_std)]
Nabil Wadihbe792832023-02-14 11:46:37 -080025
David Benjamin2a72f972023-06-07 12:21:18 -040026//! Rust BoringSSL bindings
Alice Wangcfcb9542023-09-21 14:02:07 +000027extern crate alloc;
Nabil Wadihbe792832023-02-14 11:46:37 -080028
29extern crate core;
Nabil Wadihbe792832023-02-14 11:46:37 -080030
Adam Langley6a4c7172024-01-06 15:47:00 -080031use alloc::vec::Vec;
Adam Langleyec6a4052024-01-05 14:55:24 -080032use core::ffi::c_void;
33
Adam Langley677414b2024-01-05 15:50:16 -080034#[macro_use]
35mod macros;
36
Nabil Wadih79916922023-05-19 09:04:11 -070037pub mod aead;
38
Nabil Wadih39da68f2023-02-16 18:07:41 -080039pub mod aes;
40
Nabil Wadihc6c9c382023-06-05 17:55:37 -070041/// Ciphers.
42pub mod cipher;
43
Nabil Wadihbe792832023-02-14 11:46:37 -080044pub mod digest;
45
David Benjamin2a72f972023-06-07 12:21:18 -040046/// Ed25519, a signature scheme.
Nabil Wadihb0a026f2023-05-12 09:30:10 -070047pub mod ed25519;
48
Nabil Wadihcc575422023-02-22 17:50:58 -080049pub mod hkdf;
Nabil Wadihbe792832023-02-14 11:46:37 -080050
Nabil Wadihcc575422023-02-22 17:50:58 -080051pub mod hmac;
Nabil Wadihbe792832023-02-14 11:46:37 -080052
Maurice Lamf7629e12023-06-01 02:07:47 +000053pub mod x25519;
54
Adam Langleya8e5e342024-01-06 16:28:22 -080055pub mod ec;
Maurice Lam37be47b2023-06-01 02:07:35 +000056pub mod ecdh;
Adam Langley169128d2024-01-07 17:47:37 -080057pub mod ecdsa;
Maurice Lam37be47b2023-06-01 02:07:35 +000058
Adam Langleya8e5e342024-01-06 16:28:22 -080059mod scoped;
60
61mod mem;
62pub use mem::constant_time_compare;
Maurice Lam37be47b2023-06-01 02:07:35 +000063
Adam Langley929518a2024-01-08 12:22:26 -080064mod rand;
65pub use rand::{rand_array, rand_bytes};
66
Nabil Wadih92de1952023-03-20 09:58:31 -070067#[cfg(test)]
68mod test_helpers;
69
Adam Langley518172c2024-01-06 10:41:48 -080070/// Error type for when a "signature" (either a public-key signature or a MAC)
71/// is incorrect.
72#[derive(Debug)]
73pub struct InvalidSignatureError;
74
Adam Langleyec6a4052024-01-05 14:55:24 -080075/// 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.
80trait FfiSlice {
81 fn as_ffi_ptr(&self) -> *const u8;
82 fn as_ffi_void_ptr(&self) -> *const c_void {
83 self.as_ffi_ptr() as *const c_void
84 }
85}
86
87impl FfiSlice for [u8] {
88 fn as_ffi_ptr(&self) -> *const u8 {
89 if self.is_empty() {
90 core::ptr::null()
91 } else {
92 self.as_ptr()
93 }
94 }
95}
96
97impl<const N: usize> FfiSlice for [u8; N] {
98 fn as_ffi_ptr(&self) -> *const u8 {
99 if N == 0 {
100 core::ptr::null()
101 } else {
102 self.as_ptr()
103 }
104 }
105}
106
107/// See the comment [`FfiSlice`].
108trait FfiMutSlice {
109 fn as_mut_ffi_ptr(&mut self) -> *mut u8;
110 fn as_ffi_void_ptr(&mut self) -> *mut c_void {
111 self.as_mut_ffi_ptr() as *mut c_void
112 }
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
Nabil Wadihcc575422023-02-22 17:50:58 -0800135/// This is a helper struct which provides functions for passing slices over FFI.
Adam Langleyec6a4052024-01-05 14:55:24 -0800136///
137/// Deprecated: use `FfiSlice` which adds less noise and lets one grep for `as_ptr`
138/// as a sign of something to check.
Nabil Wadihbe792832023-02-14 11:46:37 -0800139struct CSlice<'a>(&'a [u8]);
140
Nabil Wadihcc575422023-02-22 17:50:58 -0800141impl<'a> From<&'a [u8]> for CSlice<'a> {
142 fn from(value: &'a [u8]) -> Self {
143 Self(value)
144 }
145}
146
Nabil Wadihbe792832023-02-14 11:46:37 -0800147impl CSlice<'_> {
Nabil Wadihcc575422023-02-22 17:50:58 -0800148 /// Returns a raw pointer to the value, which is safe to pass over FFI.
Nabil Wadihbe792832023-02-14 11:46:37 -0800149 pub fn as_ptr<T>(&self) -> *const T {
150 if self.0.is_empty() {
Alice Wangcfcb9542023-09-21 14:02:07 +0000151 core::ptr::null()
Nabil Wadihbe792832023-02-14 11:46:37 -0800152 } else {
153 self.0.as_ptr() as *const T
154 }
155 }
Nabil Wadihb0a026f2023-05-12 09:30:10 -0700156
157 pub fn len(&self) -> usize {
158 self.0.len()
159 }
Nabil Wadihbe792832023-02-14 11:46:37 -0800160}
161
Nabil Wadihcc575422023-02-22 17:50:58 -0800162/// This is a helper struct which provides functions for passing mutable slices over FFI.
Adam Langleyec6a4052024-01-05 14:55:24 -0800163///
164/// Deprecated: use `FfiMutSlice` which adds less noise and lets one grep for
165/// `as_ptr` as a sign of something to check.
Nabil Wadihcc575422023-02-22 17:50:58 -0800166struct 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() {
Alice Wangcfcb9542023-09-21 14:02:07 +0000172 core::ptr::null_mut()
Nabil Wadihcc575422023-02-22 17:50:58 -0800173 } 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 {
Nabil Wadihbe792832023-02-14 11:46:37 -0800185 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`
Maurice Lam37be47b2023-06-01 02:07:35 +0000196/// - `Self::from_ptr_mut(x).as_ptr() == x`
Nabil Wadihbe792832023-02-14 11:46:37 -0800197unsafe 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());
Nabil Wadihfa7afff2023-04-14 13:21:48 -0700209 unsafe { &*(ptr as *mut _) }
Nabil Wadihbe792832023-02-14 11:46:37 -0800210 }
211
212 /// Constructs a mutable reference of this type from its raw type.
213 ///
214 /// # Safety
215 ///
216 /// `ptr` must be a valid, unique, instance of the type for the `'a` lifetime.
217 #[inline]
218 unsafe fn from_ptr_mut<'a>(ptr: *mut Self::CType) -> &'a mut Self {
219 debug_assert!(!ptr.is_null());
Nabil Wadihfa7afff2023-04-14 13:21:48 -0700220 unsafe { &mut *(ptr as *mut _) }
Nabil Wadihbe792832023-02-14 11:46:37 -0800221 }
222
223 /// Returns a raw pointer to the wrapped value.
224 #[inline]
225 fn as_ptr(&self) -> *mut Self::CType {
226 self as *const _ as *mut _
227 }
228}
Maurice Lam37be47b2023-06-01 02:07:35 +0000229
230/// A helper trait implemented by types which has an owned reference to foreign types.
231///
232/// # Safety
233///
234/// Implementations of `ForeignType` must guarantee the following:
235///
236/// - `Self::from_ptr(x).as_ptr() == x`
237unsafe trait ForeignType {
238 /// The raw C type.
239 type CType;
240
241 /// Constructs an instance of this type from its raw type.
242 ///
243 /// # Safety
244 ///
245 /// - `ptr` must be a valid, immutable, instance of `CType`.
246 /// - Ownership of `ptr` is passed to the implementation, and will free `ptr` when dropped.
247 unsafe fn from_ptr(ptr: *mut Self::CType) -> Self;
248
249 /// Returns a raw pointer to the wrapped value.
250 fn as_ptr(&self) -> *mut Self::CType;
251}
Adam Langleyec6a4052024-01-05 14:55:24 -0800252
Adam Langley677414b2024-01-05 15:50:16 -0800253/// Returns a BoringSSL structure that is initialized by some function.
254/// Requires that the given function completely initializes the value.
255///
256/// (Tagged `unsafe` because a no-op argument would otherwise expose
257/// uninitialized memory.)
258unsafe fn initialized_struct<T, F>(init: F) -> T
259where
260 F: FnOnce(*mut T),
261{
262 let mut out_uninit = core::mem::MaybeUninit::<T>::uninit();
263 init(out_uninit.as_mut_ptr());
264 unsafe { out_uninit.assume_init() }
265}
266
Adam Langley6a4c7172024-01-06 15:47:00 -0800267/// Returns a BoringSSL structure that is initialized by some function.
268/// Requires that the given function completely initializes the value or else
Adam Langley470b9cb2024-01-06 16:26:19 -0800269/// returns false.
Adam Langley6a4c7172024-01-06 15:47:00 -0800270///
271/// (Tagged `unsafe` because a no-op argument would otherwise expose
272/// uninitialized memory.)
273unsafe fn initialized_struct_fallible<T, F>(init: F) -> Option<T>
274where
Adam Langley470b9cb2024-01-06 16:26:19 -0800275 F: FnOnce(*mut T) -> bool,
Adam Langley6a4c7172024-01-06 15:47:00 -0800276{
277 let mut out_uninit = core::mem::MaybeUninit::<T>::uninit();
Adam Langley470b9cb2024-01-06 16:26:19 -0800278 if init(out_uninit.as_mut_ptr()) {
Adam Langley6a4c7172024-01-06 15:47:00 -0800279 Some(unsafe { out_uninit.assume_init() })
280 } else {
281 None
282 }
283}
284
Adam Langleyec6a4052024-01-05 14:55:24 -0800285/// Wrap a closure that initializes an output buffer and return that buffer as
286/// an array. Requires that the closure fully initialize the given buffer.
287///
288/// Safety: the closure must fully initialize the array.
289unsafe fn with_output_array<const N: usize, F>(func: F) -> [u8; N]
290where
291 F: FnOnce(*mut u8, usize),
292{
293 let mut out_uninit = core::mem::MaybeUninit::<[u8; N]>::uninit();
294 let out_ptr = if N != 0 {
295 out_uninit.as_mut_ptr() as *mut u8
296 } else {
297 core::ptr::null_mut()
298 };
299 func(out_ptr, N);
300 // Safety: `func` promises to fill all of `out_uninit`.
301 unsafe { out_uninit.assume_init() }
302}
303
304/// Wrap a closure that initializes an output buffer and return that buffer as
305/// an array. The closure returns a [`core::ffi::c_int`] and, if the return value
306/// is not one, then the initialization is assumed to have failed and [None] is
307/// returned. Otherwise, this function requires that the closure fully
308/// initialize the given buffer.
309///
310/// Safety: the closure must fully initialize the array if it returns one.
311unsafe fn with_output_array_fallible<const N: usize, F>(func: F) -> Option<[u8; N]>
312where
Adam Langley0eac3482024-01-18 12:43:33 -0800313 F: FnOnce(*mut u8, usize) -> bool,
Adam Langleyec6a4052024-01-05 14:55:24 -0800314{
315 let mut out_uninit = core::mem::MaybeUninit::<[u8; N]>::uninit();
316 let out_ptr = if N != 0 {
317 out_uninit.as_mut_ptr() as *mut u8
318 } else {
319 core::ptr::null_mut()
320 };
Adam Langley0eac3482024-01-18 12:43:33 -0800321 if func(out_ptr, N) {
Adam Langleyec6a4052024-01-05 14:55:24 -0800322 // Safety: `func` promises to fill all of `out_uninit` if it returns one.
323 unsafe { Some(out_uninit.assume_init()) }
324 } else {
325 None
326 }
327}
Adam Langley677414b2024-01-05 15:50:16 -0800328
Adam Langley6a4c7172024-01-06 15:47:00 -0800329/// Wrap a closure that writes at most `max_output` bytes to fill a vector.
330/// It must return 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.
346unsafe fn with_output_vec_fallible<F>(max_output: usize, func: F) -> Option<Vec<u8>>
347where
348 F: FnOnce(*mut u8) -> Option<usize>,
349{
350 let mut ret = Vec::with_capacity(max_output);
351 let out = ret.spare_capacity_mut();
352 let out_buf = out
353 .get_mut(0)
354 .map_or(core::ptr::null_mut(), |x| x.as_mut_ptr());
355
356 let num_written = func(out_buf)?;
357 assert!(num_written <= ret.capacity());
358
359 unsafe {
360 // Safety: `num_written` bytes have been written to.
361 ret.set_len(num_written);
362 }
363
364 Some(ret)
365}
366
Adam Langleya8e5e342024-01-06 16:28:22 -0800367/// Buffer represents an owned chunk of memory on the BoringSSL heap.
368/// Call `as_ref()` to get a `&[u8]` from it.
369pub struct Buffer {
370 // This pointer is always allocated by BoringSSL and must be freed using
371 // `OPENSSL_free`.
372 pub(crate) ptr: *mut u8,
373 pub(crate) len: usize,
374}
375
376impl AsRef<[u8]> for Buffer {
377 fn as_ref(&self) -> &[u8] {
378 if self.len == 0 {
379 return &[];
380 }
381 // Safety: `ptr` and `len` describe a valid area of memory and `ptr`
382 // must be Rust-valid because `len` is non-zero.
383 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
384 }
385}
386
387impl Drop for Buffer {
388 fn drop(&mut self) {
389 // Safety: `ptr` is owned by this object and is on the BoringSSL heap.
390 unsafe {
391 bssl_sys::OPENSSL_free(self.ptr as *mut core::ffi::c_void);
392 }
393 }
394}
395
396/// Calls `parse_func` with a `CBS` structure pointing at `data`.
397/// If that returns a null pointer then it returns [None].
398/// Otherwise, if there's still data left in CBS, it calls `free_func` on the
399/// pointer and returns [None]. Otherwise it returns the pointer.
400fn parse_with_cbs<T, Parse, Free>(data: &[u8], free_func: Free, parse_func: Parse) -> Option<*mut T>
401where
402 Parse: FnOnce(*mut bssl_sys::CBS) -> *mut T,
403 Free: FnOnce(*mut T),
404{
405 // Safety: type checking ensures that `cbs` is the correct size.
406 let mut cbs =
407 unsafe { initialized_struct(|cbs| bssl_sys::CBS_init(cbs, data.as_ffi_ptr(), data.len())) };
408 let ptr = parse_func(&mut cbs);
409 if ptr.is_null() {
410 return None;
411 }
412 // Safety: `cbs` is still valid after parsing.
413 if unsafe { bssl_sys::CBS_len(&cbs) } != 0 {
414 // Safety: `ptr` is still owned by this function.
415 free_func(ptr);
416 return None;
417 }
418 Some(ptr)
419}
420
421/// Calls `func` with a `CBB` pointer and returns a [Buffer] of the ultimate
422/// contents of that CBB.
423#[allow(clippy::unwrap_used)]
424fn cbb_to_buffer<F: FnOnce(*mut bssl_sys::CBB)>(initial_capacity: usize, func: F) -> Buffer {
425 // Safety: type checking ensures that `cbb` is the correct size.
426 let mut cbb = unsafe {
427 initialized_struct_fallible(|cbb| bssl_sys::CBB_init(cbb, initial_capacity) == 1)
428 }
429 // `CBB_init` only fails if out of memory, which isn't something that this crate handles.
430 .unwrap();
431 func(&mut cbb);
432
433 let mut ptr: *mut u8 = core::ptr::null_mut();
434 let mut len: usize = 0;
435 // `CBB_finish` only fails on programming error, which we convert into a
436 // panic.
437 assert_eq!(1, unsafe {
438 bssl_sys::CBB_finish(&mut cbb, &mut ptr, &mut len)
439 });
440
441 // Safety: `ptr` is on the BoringSSL heap and ownership is returned by
442 // `CBB_finish`.
443 Buffer { ptr, len }
444}
445
Adam Langley677414b2024-01-05 15:50:16 -0800446/// Used to prevent external implementations of internal traits.
447mod sealed {
448 pub struct Sealed;
449}