Reworking bssl_crypto: ECDH
This change also adds scoped.rs, which contains scoped objects for
`EVP_PKEY` and `EC_KEY`, for when we're holding temporary objects of
those types.
Due to an accident with git rebase, it also renames `crypto_memcmp` to
`constant_time_compare` and promotes it to the top-level of the crate.
Change-Id: I629c051a244e3f9dcf64d8a36846528f10a31f50
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/65174
Reviewed-by: Bob Beck <bbe@google.com>
diff --git a/rust/bssl-crypto/src/lib.rs b/rust/bssl-crypto/src/lib.rs
index 38096c3..61a8dbc 100644
--- a/rust/bssl-crypto/src/lib.rs
+++ b/rust/bssl-crypto/src/lib.rs
@@ -55,15 +55,13 @@
pub mod x25519;
-/// Memory-manipulation operations.
-pub mod mem;
-
-/// Elliptic curve diffie-hellman operations.
+pub mod ec;
pub mod ecdh;
-pub(crate) mod bn;
-pub(crate) mod ec;
-pub(crate) mod pkey;
+mod scoped;
+
+mod mem;
+pub use mem::constant_time_compare;
#[cfg(test)]
mod test_helpers;
@@ -365,6 +363,85 @@
Some(ret)
}
+/// Buffer represents an owned chunk of memory on the BoringSSL heap.
+/// Call `as_ref()` to get a `&[u8]` from it.
+pub struct Buffer {
+ // This pointer is always allocated by BoringSSL and must be freed using
+ // `OPENSSL_free`.
+ pub(crate) ptr: *mut u8,
+ pub(crate) len: usize,
+}
+
+impl AsRef<[u8]> for Buffer {
+ fn as_ref(&self) -> &[u8] {
+ if self.len == 0 {
+ return &[];
+ }
+ // Safety: `ptr` and `len` describe a valid area of memory and `ptr`
+ // must be Rust-valid because `len` is non-zero.
+ unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
+ }
+}
+
+impl Drop for Buffer {
+ fn drop(&mut self) {
+ // Safety: `ptr` is owned by this object and is on the BoringSSL heap.
+ unsafe {
+ bssl_sys::OPENSSL_free(self.ptr as *mut core::ffi::c_void);
+ }
+ }
+}
+
+/// Calls `parse_func` with a `CBS` structure pointing at `data`.
+/// If that returns a null pointer then it returns [None].
+/// Otherwise, if there's still data left in CBS, it calls `free_func` on the
+/// pointer and returns [None]. Otherwise it returns the pointer.
+fn 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),
+{
+ // Safety: type checking ensures that `cbs` is the correct size.
+ let mut cbs =
+ unsafe { initialized_struct(|cbs| bssl_sys::CBS_init(cbs, data.as_ffi_ptr(), data.len())) };
+ let ptr = parse_func(&mut cbs);
+ if ptr.is_null() {
+ return None;
+ }
+ // Safety: `cbs` is still valid after parsing.
+ if unsafe { bssl_sys::CBS_len(&cbs) } != 0 {
+ // Safety: `ptr` is still owned by this function.
+ free_func(ptr);
+ return None;
+ }
+ Some(ptr)
+}
+
+/// Calls `func` with a `CBB` pointer and returns a [Buffer] of the ultimate
+/// contents of that CBB.
+#[allow(clippy::unwrap_used)]
+fn cbb_to_buffer<F: FnOnce(*mut bssl_sys::CBB)>(initial_capacity: usize, func: F) -> Buffer {
+ // Safety: type checking ensures that `cbb` is the correct size.
+ let mut cbb = unsafe {
+ initialized_struct_fallible(|cbb| bssl_sys::CBB_init(cbb, initial_capacity) == 1)
+ }
+ // `CBB_init` only fails if out of memory, which isn't something that this crate handles.
+ .unwrap();
+ func(&mut cbb);
+
+ let mut ptr: *mut u8 = core::ptr::null_mut();
+ let mut len: usize = 0;
+ // `CBB_finish` only fails on programming error, which we convert into a
+ // panic.
+ assert_eq!(1, unsafe {
+ bssl_sys::CBB_finish(&mut cbb, &mut ptr, &mut len)
+ });
+
+ // Safety: `ptr` is on the BoringSSL heap and ownership is returned by
+ // `CBB_finish`.
+ Buffer { ptr, len }
+}
+
/// Used to prevent external implementations of internal traits.
mod sealed {
pub struct Sealed;