Reworking bssl_crypto: x25519
Change-Id: Ib9fc874e1c5d540dda91a454681dad809e8d6d14
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/65167
Reviewed-by: Bob Beck <bbe@google.com>
Reviewed-by: Maurice Lam <yukl@google.com>
Reviewed-by: Nabil Wadih <nwadih@google.com>
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/rust/bssl-crypto/src/lib.rs b/rust/bssl-crypto/src/lib.rs
index e53469d..022f5a3 100644
--- a/rust/bssl-crypto/src/lib.rs
+++ b/rust/bssl-crypto/src/lib.rs
@@ -28,6 +28,8 @@
extern crate core;
+use core::ffi::c_void;
+
/// Authenticated Encryption with Additional Data algorithms.
pub mod aead;
@@ -52,7 +54,6 @@
/// Random number generation.
pub mod rand;
-/// X25519 elliptic curve operations.
pub mod x25519;
/// Memory-manipulation operations.
@@ -68,7 +69,70 @@
#[cfg(test)]
mod test_helpers;
+/// FfiSlice exists to provide `as_ffi_ptr` on slices. Calling `as_ptr` on an
+/// empty Rust slice may return the alignment of the type, rather than NULL, as
+/// the pointer. When passing pointers into C/C++ code, that is not a valid
+/// pointer. Thus this method should be used whenever passing a pointer to a
+/// slice into BoringSSL code.
+trait FfiSlice {
+ fn as_ffi_ptr(&self) -> *const u8;
+ fn as_ffi_void_ptr(&self) -> *const c_void {
+ self.as_ffi_ptr() as *const c_void
+ }
+}
+
+impl FfiSlice for [u8] {
+ fn as_ffi_ptr(&self) -> *const u8 {
+ if self.is_empty() {
+ core::ptr::null()
+ } else {
+ self.as_ptr()
+ }
+ }
+}
+
+impl<const N: usize> FfiSlice for [u8; N] {
+ fn as_ffi_ptr(&self) -> *const u8 {
+ if N == 0 {
+ core::ptr::null()
+ } else {
+ self.as_ptr()
+ }
+ }
+}
+
+/// See the comment [`FfiSlice`].
+trait FfiMutSlice {
+ fn as_mut_ffi_ptr(&mut self) -> *mut u8;
+ fn as_ffi_void_ptr(&mut self) -> *mut c_void {
+ self.as_mut_ffi_ptr() as *mut c_void
+ }
+}
+
+impl FfiMutSlice for [u8] {
+ fn as_mut_ffi_ptr(&mut self) -> *mut u8 {
+ if self.is_empty() {
+ core::ptr::null_mut()
+ } else {
+ self.as_mut_ptr()
+ }
+ }
+}
+
+impl<const N: usize> FfiMutSlice for [u8; N] {
+ fn as_mut_ffi_ptr(&mut self) -> *mut u8 {
+ if N == 0 {
+ core::ptr::null_mut()
+ } else {
+ self.as_mut_ptr()
+ }
+ }
+}
+
/// This is a helper struct which provides functions for passing slices over FFI.
+///
+/// Deprecated: use `FfiSlice` which adds less noise and lets one grep for `as_ptr`
+/// as a sign of something to check.
struct CSlice<'a>(&'a [u8]);
impl<'a> From<&'a [u8]> for CSlice<'a> {
@@ -93,6 +157,9 @@
}
/// This is a helper struct which provides functions for passing mutable slices over FFI.
+///
+/// Deprecated: use `FfiMutSlice` which adds less noise and lets one grep for
+/// `as_ptr` as a sign of something to check.
struct CSliceMut<'a>(&'a mut [u8]);
impl CSliceMut<'_> {
@@ -179,3 +246,47 @@
/// Returns a raw pointer to the wrapped value.
fn as_ptr(&self) -> *mut Self::CType;
}
+
+/// Wrap a closure that initializes an output buffer and return that buffer as
+/// an array. Requires that the closure fully initialize the given buffer.
+///
+/// Safety: the closure must fully initialize the array.
+unsafe fn with_output_array<const N: usize, F>(func: F) -> [u8; N]
+where
+ F: FnOnce(*mut u8, usize),
+{
+ let mut out_uninit = core::mem::MaybeUninit::<[u8; N]>::uninit();
+ let out_ptr = if N != 0 {
+ out_uninit.as_mut_ptr() as *mut u8
+ } else {
+ core::ptr::null_mut()
+ };
+ func(out_ptr, N);
+ // Safety: `func` promises to fill all of `out_uninit`.
+ unsafe { out_uninit.assume_init() }
+}
+
+/// Wrap a closure that initializes an output buffer and return that buffer as
+/// an array. The closure returns a [`core::ffi::c_int`] and, if the return value
+/// is not one, then the initialization is assumed to have failed and [None] is
+/// returned. Otherwise, this function requires that the closure fully
+/// initialize the given buffer.
+///
+/// Safety: the closure must fully initialize the array if it returns one.
+unsafe fn with_output_array_fallible<const N: usize, F>(func: F) -> Option<[u8; N]>
+where
+ F: FnOnce(*mut u8, usize) -> core::ffi::c_int,
+{
+ let mut out_uninit = core::mem::MaybeUninit::<[u8; N]>::uninit();
+ let out_ptr = if N != 0 {
+ out_uninit.as_mut_ptr() as *mut u8
+ } else {
+ core::ptr::null_mut()
+ };
+ if func(out_ptr, N) == 1 {
+ // Safety: `func` promises to fill all of `out_uninit` if it returns one.
+ unsafe { Some(out_uninit.assume_init()) }
+ } else {
+ None
+ }
+}