• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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