1 /* 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,
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
28 extern crate alloc;
29 extern crate core;
30
31 use alloc::vec::Vec;
32 use core::ffi::c_void;
33
34 #[macro_use]
35 mod macros;
36
37 pub mod aead;
38 pub mod aes;
39
40 /// Ciphers.
41 pub mod cipher;
42
43 pub mod digest;
44 pub mod ec;
45 pub mod ecdh;
46 pub mod ecdsa;
47 pub mod ed25519;
48 pub mod hkdf;
49 pub mod hmac;
50 pub mod hpke;
51 pub mod rsa;
52 pub mod x25519;
53
54 mod scoped;
55
56 #[cfg(test)]
57 mod test_helpers;
58
59 mod mem;
60 pub use mem::constant_time_compare;
61
62 mod rand;
63 pub use rand::{rand_array, rand_bytes};
64
65 /// Error type for when a "signature" (either a public-key signature or a MAC)
66 /// is incorrect.
67 #[derive(Debug)]
68 pub struct InvalidSignatureError;
69
70 /// FfiSlice exists to provide `as_ffi_ptr` on slices. Calling `as_ptr` on an
71 /// empty Rust slice may return the alignment of the type, rather than NULL, as
72 /// the pointer. When passing pointers into C/C++ code, that is not a valid
73 /// pointer. Thus this method should be used whenever passing a pointer to a
74 /// slice into BoringSSL code.
75 trait FfiSlice {
as_ffi_ptr(&self) -> *const u876 fn as_ffi_ptr(&self) -> *const u8;
as_ffi_void_ptr(&self) -> *const c_void77 fn as_ffi_void_ptr(&self) -> *const c_void {
78 self.as_ffi_ptr() as *const c_void
79 }
80 }
81
82 impl FfiSlice for [u8] {
as_ffi_ptr(&self) -> *const u883 fn as_ffi_ptr(&self) -> *const u8 {
84 if self.is_empty() {
85 core::ptr::null()
86 } else {
87 self.as_ptr()
88 }
89 }
90 }
91
92 impl<const N: usize> FfiSlice for [u8; N] {
as_ffi_ptr(&self) -> *const u893 fn as_ffi_ptr(&self) -> *const u8 {
94 if N == 0 {
95 core::ptr::null()
96 } else {
97 self.as_ptr()
98 }
99 }
100 }
101
102 /// See the comment [`FfiSlice`].
103 trait FfiMutSlice {
as_mut_ffi_ptr(&mut self) -> *mut u8104 fn as_mut_ffi_ptr(&mut self) -> *mut u8;
105 }
106
107 impl FfiMutSlice for [u8] {
as_mut_ffi_ptr(&mut self) -> *mut u8108 fn as_mut_ffi_ptr(&mut self) -> *mut u8 {
109 if self.is_empty() {
110 core::ptr::null_mut()
111 } else {
112 self.as_mut_ptr()
113 }
114 }
115 }
116
117 impl<const N: usize> FfiMutSlice for [u8; N] {
as_mut_ffi_ptr(&mut self) -> *mut u8118 fn as_mut_ffi_ptr(&mut self) -> *mut u8 {
119 if N == 0 {
120 core::ptr::null_mut()
121 } else {
122 self.as_mut_ptr()
123 }
124 }
125 }
126
127 /// This is a helper struct which provides functions for passing slices over FFI.
128 ///
129 /// Deprecated: use `FfiSlice` which adds less noise and lets one grep for `as_ptr`
130 /// as a sign of something to check.
131 struct CSlice<'a>(&'a [u8]);
132
133 impl<'a> From<&'a [u8]> for CSlice<'a> {
from(value: &'a [u8]) -> Self134 fn from(value: &'a [u8]) -> Self {
135 Self(value)
136 }
137 }
138
139 impl CSlice<'_> {
140 /// Returns a raw pointer to the value, which is safe to pass over FFI.
as_ptr<T>(&self) -> *const T141 pub fn as_ptr<T>(&self) -> *const T {
142 if self.0.is_empty() {
143 core::ptr::null()
144 } else {
145 self.0.as_ptr() as *const T
146 }
147 }
148
len(&self) -> usize149 pub fn len(&self) -> usize {
150 self.0.len()
151 }
152 }
153
154 /// This is a helper struct which provides functions for passing mutable slices over FFI.
155 ///
156 /// Deprecated: use `FfiMutSlice` which adds less noise and lets one grep for
157 /// `as_ptr` as a sign of something to check.
158 struct CSliceMut<'a>(&'a mut [u8]);
159
160 impl CSliceMut<'_> {
161 /// Returns a raw pointer to the value, which is safe to pass over FFI.
as_mut_ptr<T>(&mut self) -> *mut T162 pub fn as_mut_ptr<T>(&mut self) -> *mut T {
163 if self.0.is_empty() {
164 core::ptr::null_mut()
165 } else {
166 self.0.as_mut_ptr() as *mut T
167 }
168 }
169
len(&self) -> usize170 pub fn len(&self) -> usize {
171 self.0.len()
172 }
173 }
174
175 impl<'a> From<&'a mut [u8]> for CSliceMut<'a> {
from(value: &'a mut [u8]) -> Self176 fn from(value: &'a mut [u8]) -> Self {
177 Self(value)
178 }
179 }
180
181 /// A helper trait implemented by types which reference borrowed foreign types.
182 ///
183 /// # Safety
184 ///
185 /// Implementations of `ForeignTypeRef` must guarantee the following:
186 ///
187 /// - `Self::from_ptr(x).as_ptr() == x`
188 /// - `Self::from_ptr_mut(x).as_ptr() == x`
189 unsafe trait ForeignTypeRef: Sized {
190 /// The raw C type.
191 type CType;
192
193 /// Constructs a shared instance of this type from its raw type.
194 ///
195 /// # Safety
196 ///
197 /// `ptr` must be a valid, immutable, instance of the type for the `'a` lifetime.
198 #[inline]
from_ptr<'a>(ptr: *mut Self::CType) -> &'a Self199 unsafe fn from_ptr<'a>(ptr: *mut Self::CType) -> &'a Self {
200 debug_assert!(!ptr.is_null());
201 unsafe { &*(ptr as *mut _) }
202 }
203
204 /// Returns a raw pointer to the wrapped value.
205 #[inline]
as_ptr(&self) -> *mut Self::CType206 fn as_ptr(&self) -> *mut Self::CType {
207 self as *const _ as *mut _
208 }
209 }
210
211 /// Returns a BoringSSL structure that is initialized by some function.
212 /// Requires that the given function completely initializes the value.
213 ///
214 /// (Tagged `unsafe` because a no-op argument would otherwise expose
215 /// uninitialized memory.)
initialized_struct<T, F>(init: F) -> T where F: FnOnce(*mut T),216 unsafe fn initialized_struct<T, F>(init: F) -> T
217 where
218 F: FnOnce(*mut T),
219 {
220 let mut out_uninit = core::mem::MaybeUninit::<T>::uninit();
221 init(out_uninit.as_mut_ptr());
222 unsafe { out_uninit.assume_init() }
223 }
224
225 /// Returns a BoringSSL structure that is initialized by some function.
226 /// Requires that the given function completely initializes the value or else
227 /// returns false.
228 ///
229 /// (Tagged `unsafe` because a no-op argument would otherwise expose
230 /// uninitialized memory.)
initialized_struct_fallible<T, F>(init: F) -> Option<T> where F: FnOnce(*mut T) -> bool,231 unsafe fn initialized_struct_fallible<T, F>(init: F) -> Option<T>
232 where
233 F: FnOnce(*mut T) -> bool,
234 {
235 let mut out_uninit = core::mem::MaybeUninit::<T>::uninit();
236 if init(out_uninit.as_mut_ptr()) {
237 Some(unsafe { out_uninit.assume_init() })
238 } else {
239 None
240 }
241 }
242
243 /// Wrap a closure that initializes an output buffer and return that buffer as
244 /// an array. Requires that the closure fully initialize the given buffer.
245 ///
246 /// 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),247 unsafe fn with_output_array<const N: usize, F>(func: F) -> [u8; N]
248 where
249 F: FnOnce(*mut u8, usize),
250 {
251 let mut out_uninit = core::mem::MaybeUninit::<[u8; N]>::uninit();
252 let out_ptr = if N != 0 {
253 out_uninit.as_mut_ptr() as *mut u8
254 } else {
255 core::ptr::null_mut()
256 };
257 func(out_ptr, N);
258 // Safety: `func` promises to fill all of `out_uninit`.
259 unsafe { out_uninit.assume_init() }
260 }
261
262 /// Wrap a closure that initializes an output buffer and return that buffer as
263 /// an array. The closure returns a [`core::ffi::c_int`] and, if the return value
264 /// is not one, then the initialization is assumed to have failed and [None] is
265 /// returned. Otherwise, this function requires that the closure fully
266 /// initialize the given buffer.
267 ///
268 /// 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,269 unsafe fn with_output_array_fallible<const N: usize, F>(func: F) -> Option<[u8; N]>
270 where
271 F: FnOnce(*mut u8, usize) -> bool,
272 {
273 let mut out_uninit = core::mem::MaybeUninit::<[u8; N]>::uninit();
274 let out_ptr = if N != 0 {
275 out_uninit.as_mut_ptr() as *mut u8
276 } else {
277 core::ptr::null_mut()
278 };
279 if func(out_ptr, N) {
280 // Safety: `func` promises to fill all of `out_uninit` if it returns one.
281 unsafe { Some(out_uninit.assume_init()) }
282 } else {
283 None
284 }
285 }
286
287 /// Wrap a closure that writes at most `max_output` bytes to fill a vector.
288 /// It must return the number of bytes written.
289 #[allow(clippy::unwrap_used)]
with_output_vec<F>(max_output: usize, func: F) -> Vec<u8> where F: FnOnce(*mut u8) -> usize,290 unsafe fn with_output_vec<F>(max_output: usize, func: F) -> Vec<u8>
291 where
292 F: FnOnce(*mut u8) -> usize,
293 {
294 unsafe {
295 with_output_vec_fallible(max_output, |out_buf| Some(func(out_buf)))
296 // The closure cannot fail and thus neither can
297 // `with_output_array_fallible`.
298 .unwrap()
299 }
300 }
301
302 /// Wrap a closure that writes at most `max_output` bytes to fill a vector.
303 /// If successful, it must return the number of bytes written.
with_output_vec_fallible<F>(max_output: usize, func: F) -> Option<Vec<u8>> where F: FnOnce(*mut u8) -> Option<usize>,304 unsafe fn with_output_vec_fallible<F>(max_output: usize, func: F) -> Option<Vec<u8>>
305 where
306 F: FnOnce(*mut u8) -> Option<usize>,
307 {
308 let mut ret = Vec::with_capacity(max_output);
309 let out = ret.spare_capacity_mut();
310 let out_buf = out
311 .get_mut(0)
312 .map_or(core::ptr::null_mut(), |x| x.as_mut_ptr());
313
314 let num_written = func(out_buf)?;
315 assert!(num_written <= ret.capacity());
316
317 unsafe {
318 // Safety: `num_written` bytes have been written to.
319 ret.set_len(num_written);
320 }
321
322 Some(ret)
323 }
324
325 /// Buffer represents an owned chunk of memory on the BoringSSL heap.
326 /// Call `as_ref()` to get a `&[u8]` from it.
327 pub struct Buffer {
328 // This pointer is always allocated by BoringSSL and must be freed using
329 // `OPENSSL_free`.
330 pub(crate) ptr: *mut u8,
331 pub(crate) len: usize,
332 }
333
334 impl AsRef<[u8]> for Buffer {
as_ref(&self) -> &[u8]335 fn as_ref(&self) -> &[u8] {
336 if self.len == 0 {
337 return &[];
338 }
339 // Safety: `ptr` and `len` describe a valid area of memory and `ptr`
340 // must be Rust-valid because `len` is non-zero.
341 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
342 }
343 }
344
345 impl Drop for Buffer {
drop(&mut self)346 fn drop(&mut self) {
347 // Safety: `ptr` is owned by this object and is on the BoringSSL heap.
348 unsafe {
349 bssl_sys::OPENSSL_free(self.ptr as *mut core::ffi::c_void);
350 }
351 }
352 }
353
354 /// Calls `parse_func` with a `CBS` structure pointing at `data`.
355 /// If that returns a null pointer then it returns [None].
356 /// Otherwise, if there's still data left in CBS, it calls `free_func` on the
357 /// 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),358 fn parse_with_cbs<T, Parse, Free>(data: &[u8], free_func: Free, parse_func: Parse) -> Option<*mut T>
359 where
360 Parse: FnOnce(*mut bssl_sys::CBS) -> *mut T,
361 Free: FnOnce(*mut T),
362 {
363 // Safety: type checking ensures that `cbs` is the correct size.
364 let mut cbs =
365 unsafe { initialized_struct(|cbs| bssl_sys::CBS_init(cbs, data.as_ffi_ptr(), data.len())) };
366 let ptr = parse_func(&mut cbs);
367 if ptr.is_null() {
368 return None;
369 }
370 // Safety: `cbs` is still valid after parsing.
371 if unsafe { bssl_sys::CBS_len(&cbs) } != 0 {
372 // Safety: `ptr` is still owned by this function.
373 free_func(ptr);
374 return None;
375 }
376 Some(ptr)
377 }
378
379 /// Calls `func` with a `CBB` pointer and returns a [Buffer] of the ultimate
380 /// contents of that CBB.
381 #[allow(clippy::unwrap_used)]
cbb_to_buffer<F: FnOnce(*mut bssl_sys::CBB)>(initial_capacity: usize, func: F) -> Buffer382 fn cbb_to_buffer<F: FnOnce(*mut bssl_sys::CBB)>(initial_capacity: usize, func: F) -> Buffer {
383 // Safety: type checking ensures that `cbb` is the correct size.
384 let mut cbb = unsafe {
385 initialized_struct_fallible(|cbb| bssl_sys::CBB_init(cbb, initial_capacity) == 1)
386 }
387 // `CBB_init` only fails if out of memory, which isn't something that this crate handles.
388 .unwrap();
389 func(&mut cbb);
390
391 let mut ptr: *mut u8 = core::ptr::null_mut();
392 let mut len: usize = 0;
393 // `CBB_finish` only fails on programming error, which we convert into a
394 // panic.
395 assert_eq!(1, unsafe {
396 bssl_sys::CBB_finish(&mut cbb, &mut ptr, &mut len)
397 });
398
399 // Safety: `ptr` is on the BoringSSL heap and ownership is returned by
400 // `CBB_finish`.
401 Buffer { ptr, len }
402 }
403
404 /// Used to prevent external implementations of internal traits.
405 mod sealed {
406 pub struct Sealed;
407 }
408