rust: hoist FFI slice converters to bssl-crypto

Signed-off-by: Xiangfei Ding <xfding@google.com>
Change-Id: I2147920ede90e01772b67e6c0a2d3e236a6a6964
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/100227
Reviewed-by: Rudolf Polzer <rpolzer@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 a2c550d..75fc7a5 100644
--- a/rust/bssl-crypto/src/lib.rs
+++ b/rust/bssl-crypto/src/lib.rs
@@ -29,7 +29,10 @@
 
 use alloc::boxed::Box;
 use alloc::vec::Vec;
-use core::ffi::c_void;
+use core::{
+    debug_assert,
+    ffi::c_void, //
+};
 
 #[macro_use]
 mod macros;
@@ -132,6 +135,89 @@
     }
 }
 
+#[doc(hidden)]
+/// The reverse of [`FfiSlice`], to re-interpret a FFI pointer back into a Rust slice.
+pub trait FromFfiSlice: Sized {
+    /// Converts an FFI pointer and length to a Rust slice. This is similar to
+    /// [core::slice::from_raw_parts] but handles a mismatch between C and Rust empty slice
+    /// conventions.
+    /// In C, empty slices may use a `NULL` pointer in C.
+    /// In Rust, they may not.
+    ///
+    /// **NOTE** This trait is set up only for BoringSSL internal use.
+    ///
+    /// # Safety
+    ///
+    /// The caller must meet the following safety pre-conditions:
+    /// - The `ptr` and `len` are from a slice returned from BoringSSL via FFI.
+    /// - The memory referenced by the returned slice must not be mutated or deallocated for the
+    ///   duration of lifetime `'a`, including by BoringSSL.
+    ///
+    /// The first condition implies the following properties:
+    ///
+    /// - `ptr` is correctly aligned for Self.
+    /// - The total bytes of the slice, in other words `size_of<Self>() * len`, is below [isize::MAX].
+    /// - If `ptr.is_null()` then `len == 0`.
+    /// - There are `len` objects of type Self at ptr.
+    /// - The entire memory range for these objects is contained in a single allocation.
+    /// - The entire memory range is not mutated within the `'a` lifetime through aliased accesses.
+    /// - Each element of the slice has a valid bit pattern as a value of `Self`.
+    unsafe fn from_ffi_ptr<'a>(ptr: *const Self, len: usize) -> &'a [Self];
+}
+
+impl<T> FromFfiSlice for T {
+    #[inline]
+    unsafe fn from_ffi_ptr<'a>(ptr: *const T, len: usize) -> &'a [T] {
+        debug_assert!(ptr.is_aligned());
+        #[cfg(debug_assertions)]
+        if let Some(len) = len.checked_mul(core::mem::size_of::<T>()) {
+            debug_assert!(len < isize::MAX.unsigned_abs());
+        } else {
+            unreachable!("length overflow");
+        };
+
+        if len == 0 {
+            &[]
+        } else {
+            debug_assert!(!ptr.is_null());
+            unsafe {
+                // Safety:
+                // - pre-condition has asserted that the pointer outlives the returned slice.
+                // - pre-condition has asserted that the memory range does not overlap with any
+                //   other allocations.
+                // - pre-condition has asserted that the bit pattern behind the pointer is valid for
+                //   the type `T`.
+                core::slice::from_raw_parts(ptr, len)
+            }
+        }
+    }
+}
+
+/// Sanitize the data pointer and length and reconstitute the mutable slice.
+///
+/// This method will **zeroize** the content.
+///
+/// This method returns an empty slice if the length is 0.
+///
+/// # Safety
+///
+/// Caller must ensure that
+/// - `ptr` outlives `'a`.
+/// - access to `out` is exclusive and strictly not aliased.
+/// - if `ptr` is NULL, `capacity == 0`.
+#[inline]
+pub unsafe fn zeroize_mut_byteslice<'a>(ptr: *mut u8, capacity: usize) -> &'a mut [u8] {
+    if capacity == 0 {
+        return &mut [];
+    }
+    debug_assert!(capacity < isize::MAX.unsigned_abs() && !ptr.is_null());
+    unsafe {
+        // Safety: `out` is 1-aligned and `0` is a valid pattern for `u8`.
+        core::ptr::write_bytes(ptr, 0, capacity);
+        core::slice::from_raw_parts_mut(ptr, capacity)
+    }
+}
+
 /// 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`
diff --git a/rust/bssl-tls/src/credentials.rs b/rust/bssl-tls/src/credentials.rs
index 723dc7b..aa24387 100644
--- a/rust/bssl-tls/src/credentials.rs
+++ b/rust/bssl-tls/src/credentials.rs
@@ -40,6 +40,7 @@
     }, //
 };
 
+use bssl_crypto::FromFfiSlice;
 use bssl_x509::{
     errors::PemReason,
     keys::{PrivateKey, PublicKey},
@@ -68,7 +69,6 @@
         CryptoBufferWrapper,
         Stack,
         StackIterator,
-        sanitize_slice,
         slice_into_ffi_raw_parts, //
     },
     has_duplicates, //
@@ -444,7 +444,7 @@
         }
         unsafe {
             // Safety: `id_ptr` will be outlived by `self`.
-            sanitize_slice(id_ptr, id_len)
+            Some(u8::from_ffi_ptr(id_ptr, id_len))
         }
     }
 }
@@ -553,12 +553,10 @@
             if buf.to_bytes() != b"CERTIFICATE" {
                 continue;
             }
-            let Some(contents) = (unsafe {
+            let contents = unsafe {
                 // Safety: the slice is only used within the loop and we will copy the contents
                 // when constructing the certificate object.
-                sanitize_slice(data.0, len)
-            }) else {
-                return Err(Error::Io(IoError::TooLong));
+                u8::from_ffi_ptr(data.0, len)
             };
             let cert = Certificate::from_bytes(contents, cache)?;
             return Ok((cert, eof));
@@ -576,7 +574,7 @@
         };
         unsafe {
             // Safety: `data` will be outlived by `self`
-            sanitize_slice(data, len).expect("buffer is too large")
+            u8::from_ffi_ptr(data, len)
         }
     }
 }
@@ -817,7 +815,7 @@
             core::mem::transmute(call_slice_getter!(
                 bssl_sys::SSL_get0_ech_name_override,
                 self.ptr()
-            )?)
+            ))
         };
         if name.is_empty() || !name.is_ascii() {
             return None;
@@ -834,7 +832,7 @@
     /// [RFC 2560]: <https://datatracker.ietf.org/doc/html/rfc6960>
     pub fn get_ocsp_response(&self) -> Option<&[u8]> {
         // Safety: response, when it exists, is outlived by the connection.
-        let response = call_slice_getter!(bssl_sys::SSL_get0_ocsp_response, self.ptr())?;
+        let response = call_slice_getter!(bssl_sys::SSL_get0_ocsp_response, self.ptr());
         (!response.is_empty()).then_some(response)
     }
 
@@ -843,7 +841,7 @@
     /// [RFC 6962]: <https://datatracker.ietf.org/doc/html/rfc6962#section-3.2>
     pub fn get_signed_cert_timestamp_list(&self) -> Option<&[u8]> {
         // Safety: list, when it exists, is outlived by the connection.
-        let list = call_slice_getter!(bssl_sys::SSL_get0_signed_cert_timestamp_list, self.ptr())?;
+        let list = call_slice_getter!(bssl_sys::SSL_get0_signed_cert_timestamp_list, self.ptr());
         (!list.is_empty()).then_some(list)
     }
 
diff --git a/rust/bssl-tls/src/credentials/early_callback.rs b/rust/bssl-tls/src/credentials/early_callback.rs
index fd498c9..5fc9198c 100644
--- a/rust/bssl-tls/src/credentials/early_callback.rs
+++ b/rust/bssl-tls/src/credentials/early_callback.rs
@@ -23,6 +23,8 @@
     }, //
 };
 
+use bssl_crypto::FromFfiSlice;
+
 use crate::{
     EarlyCallbackMethods,
     abort_on_panic,
@@ -30,8 +32,7 @@
     connection::{
         Server,
         lifecycle::TlsConnectionInHandshake, //
-    },
-    ffi::sanitize_slice, //
+    }, //
 };
 
 bssl_macros::bssl_enum! {
@@ -158,7 +159,7 @@
     ($client_hello:expr, $data:ident, $len:ident) => {
         unsafe {
             // Safety: `$client_hello` is a valid pointer
-            sanitize_slice($client_hello.$data, $client_hello.$len)?
+            u8::from_ffi_ptr($client_hello.$data, $client_hello.$len)
         }
     };
 }
@@ -215,22 +216,12 @@
 
     /// Get the legacy compression methods bytes.
     pub fn legacy_compression_methods(&self) -> &'a [u8] {
-        unsafe {
-            // Safety: `self.ptr` is a valid pointer to `SSL_CLIENT_HELLO` provided by BoringSSL.
-            sanitize_slice(
-                (*self.ptr).compression_methods,
-                (*self.ptr).compression_methods_len,
-            )
-            .unwrap_or(&[])
-        }
+        client_hello_getter!(*self.ptr, compression_methods, compression_methods_len)
     }
 
     /// Get the extensions bytes.
     pub fn extensions(&self) -> &'a [u8] {
-        unsafe {
-            // Safety: `self.ptr` is a valid pointer to `SSL_CLIENT_HELLO` provided by BoringSSL.
-            sanitize_slice((*self.ptr).extensions, (*self.ptr).extensions_len).unwrap_or(&[])
-        }
+        client_hello_getter!(*self.ptr, extensions, extensions_len)
     }
 
     /// Extract a specific extension from the client hello.
@@ -253,7 +244,7 @@
         if ret == 1 {
             unsafe {
                 // Safety: `out_data` and `out_len` are valid if the function returns 1.
-                sanitize_slice(out_data, out_len)
+                Some(u8::from_ffi_ptr(out_data, out_len))
             }
         } else {
             None
diff --git a/rust/bssl-tls/src/credentials/methods.rs b/rust/bssl-tls/src/credentials/methods.rs
index 2a40cba..f5a34da 100644
--- a/rust/bssl-tls/src/credentials/methods.rs
+++ b/rust/bssl-tls/src/credentials/methods.rs
@@ -22,6 +22,7 @@
     }, //
 };
 
+use bssl_crypto::FromFfiSlice;
 use once_cell::sync::Lazy;
 
 use crate::{
@@ -36,10 +37,6 @@
         SignatureOperation,
         waker_data_from_ssl, //
     },
-    ffi::{
-        sanitise_mut_byteslice,
-        sanitize_slice, //
-    },
     methods::drop_box_rust_methods, //
 };
 
@@ -144,20 +141,16 @@
         // TODO(@xfding) maybe we should log this error?
         Err(_) => return bssl_sys::ssl_private_key_result_t_ssl_private_key_failure,
     };
-    let Some(output) = (unsafe {
-        // Safety: the slice will only be used within this callback.
-        sanitise_mut_byteslice(out, max_out)
-    }) else {
-        return bssl_sys::ssl_private_key_result_t_ssl_private_key_failure;
+    let output = unsafe {
+        // Safety: the slice comes from BoringSSL and it will only be used within this callback.
+        bssl_crypto::zeroize_mut_byteslice(out, max_out)
     };
     if output.is_empty() {
         return bssl_sys::ssl_private_key_result_t_ssl_private_key_failure;
     }
-    let Some(message) = (unsafe {
+    let message = unsafe {
         // Safety: `msg` outlives `message` because it is owned by BoringSSL.
-        sanitize_slice(msg, msg_len)
-    }) else {
-        return bssl_sys::ssl_private_key_result_t_ssl_private_key_failure;
+        u8::from_ffi_ptr(msg, msg_len)
     };
     // Unwind-safety: when panic happens, we will not inspect the `output` buffer.
     abort_on_panic(move || {
@@ -204,20 +197,16 @@
 
     // Unwind-safety: later when panic happens, we detach the poisoned private key method
     // without calling destructor.
-    let Some(output) = (unsafe {
-        // Safety: the slice will only be used within this callback.
-        sanitise_mut_byteslice(out, max_out)
-    }) else {
-        return bssl_sys::ssl_private_key_result_t_ssl_private_key_failure;
+    let output = unsafe {
+        // Safety: the slice comes from BoringSSL and it will only be used within this callback.
+        bssl_crypto::zeroize_mut_byteslice(out, max_out)
     };
     if output.is_empty() {
         return bssl_sys::ssl_private_key_result_t_ssl_private_key_failure;
     }
-    let Some(ciphertext) = (unsafe {
+    let ciphertext = unsafe {
         // Safety: `ciphertext` is now owned by BoringSSL and outlives the slice.
-        sanitize_slice(ciphertext, ciphertext_len)
-    }) else {
-        return bssl_sys::ssl_private_key_result_t_ssl_private_key_failure;
+        u8::from_ffi_ptr(ciphertext, ciphertext_len)
     };
     // Unwind-safety: when panic happens, we will not inspect the `output` buffer.
     abort_on_panic(move || {
@@ -252,11 +241,9 @@
 
     // Unwind-safety: later when panic happens, we detach the poisoned private key method
     // without calling destructor.
-    let Some(output) = (unsafe {
-        // Safety: the slice will only be used within this callback.
-        sanitise_mut_byteslice(out, max_out)
-    }) else {
-        return bssl_sys::ssl_private_key_result_t_ssl_private_key_failure;
+    let output = unsafe {
+        // Safety: the slice comes from BoringSSL and it will only be used within this callback.
+        bssl_crypto::zeroize_mut_byteslice(out, max_out)
     };
     if output.is_empty() {
         return bssl_sys::ssl_private_key_result_t_ssl_private_key_failure;
diff --git a/rust/bssl-tls/src/credentials/select_cert.rs b/rust/bssl-tls/src/credentials/select_cert.rs
index a5f5a83..675cc7e 100644
--- a/rust/bssl-tls/src/credentials/select_cert.rs
+++ b/rust/bssl-tls/src/credentials/select_cert.rs
@@ -14,29 +14,35 @@
 
 //! TLS certificate selection hook.
 
-use alloc::{vec, vec::Vec};
+use alloc::vec::Vec;
 use core::{
-    ffi::{c_int, c_void},
+    ffi::{
+        c_int,
+        c_void, //
+    },
     marker::PhantomData,
-    ptr::{NonNull, null},
+    ptr::{
+        NonNull,
+        null, //
+    },
     task::Context,
 };
 
+use bssl_crypto::FromFfiSlice;
+
 use super::{
     CryptoBufferIterator,
-    DistinguishedName, //
+    DistinguishedName,
     SignatureAlgorithm,
     get_peer_certificate_type,
-    get_peer_raw_public_key,
+    get_peer_raw_public_key, //
 };
-
 use crate::{
     CertCallback,
     abort_on_panic,
     config::ProtocolVersion,
     connection::methods::waker_data_from_ssl,
-    context::TlsContext,
-    ffi::sanitize_slice, //
+    context::TlsContext, //
 };
 
 /// Result of certificate selection.
@@ -233,18 +239,17 @@
             // Safety: `self.0` is still valid by BoringSSL invariant.
             bssl_sys::SSL_get0_peer_verify_algorithms(self.ptr(), &raw mut algs)
         };
-        if let Some(slice) = unsafe {
-            // Safety: `algs` is only live within this call.
-            sanitize_slice(algs, len)
-        } {
-            slice
-                .iter()
-                .copied()
-                .map(SignatureAlgorithm::try_from)
-                .collect()
-        } else {
-            vec![]
-        }
+        let slice = unsafe {
+            // Safety:
+            // - `slice` is only live within this call.
+            // - `slice` is generated by BoringSSL.
+            u16::from_ffi_ptr(algs, len)
+        };
+        slice
+            .iter()
+            .copied()
+            .map(SignatureAlgorithm::try_from)
+            .collect()
     }
 
     /// Get TLS 1.2 certificate types.
@@ -257,18 +262,17 @@
             // Safety: `self.0` is still valid by BoringSSL invariant.
             bssl_sys::SSL_get0_certificate_types(self.ptr(), &raw mut types)
         };
-        if let Some(slice) = unsafe {
-            // Safety: `types` is only live within this call.
-            sanitize_slice(types, len)
-        } {
-            slice
-                .iter()
-                .copied()
-                .map(RequestedCertificateType::try_from)
-                .collect()
-        } else {
-            vec![]
-        }
+        let slice = unsafe {
+            // Safety:
+            // - `types` is only live within this call.
+            // - `types` is generated by BoringSSL.
+            u8::from_ffi_ptr(types, len)
+        };
+        slice
+            .iter()
+            .copied()
+            .map(RequestedCertificateType::try_from)
+            .collect()
     }
 
     /// Get server requested CAs for client authentication.
diff --git a/rust/bssl-tls/src/ffi.rs b/rust/bssl-tls/src/ffi.rs
index 55d4b02..d27ce62 100644
--- a/rust/bssl-tls/src/ffi.rs
+++ b/rust/bssl-tls/src/ffi.rs
@@ -23,14 +23,13 @@
         NonNull,
         null,
         null_mut, //
-    },
-    slice::{
-        from_raw_parts,
-        from_raw_parts_mut, //
     }, //
 };
 
-use bssl_crypto::FfiSlice;
+use bssl_crypto::{
+    FfiSlice,
+    FromFfiSlice, //
+};
 
 use crate::{
     context::CertificateCache,
@@ -69,50 +68,6 @@
     }
 }
 
-/// Sanitize the data pointer and length and reconstitute the slice.
-///
-/// This method returns an empty slice if the length is 0 or the pointer is NULL.
-/// # Safety
-/// Caller must ensure that `'a` outlives `input`.
-#[inline]
-pub(crate) unsafe fn sanitize_slice<'a, T>(input: *const T, len: usize) -> Option<&'a [T]> {
-    if len == 0 || input.is_null() {
-        return Some(&[]);
-    }
-    if !input.is_aligned() || len.checked_mul(size_of::<T>())? > isize::MAX as usize {
-        return None;
-    }
-    unsafe {
-        // Safety: the pointer and the size has been sanitised.
-        Some(from_raw_parts(input, len))
-    }
-}
-
-/// Sanitize the data pointer and length and reconstitute the mutable slice.
-///
-/// `capacity` counts the number of `T`s that `out` can hold, **not number of bytes**.
-///
-/// This method returns an empty slice if the length is 0 or the pointer is NULL.
-/// # Safety
-/// Caller must ensure that `'a` outlives `input`.
-#[inline]
-pub(crate) unsafe fn sanitise_mut_byteslice<'a>(
-    out: *mut u8,
-    capacity: usize,
-) -> Option<&'a mut [u8]> {
-    if capacity == 0 || out.is_null() {
-        return Some(&mut []);
-    }
-    if capacity > isize::MAX as usize {
-        return None;
-    }
-    unsafe {
-        // Safety: `out` is 1-aligned and `0` is a valid pattern for `u8`.
-        core::ptr::write_bytes(out, 0, capacity);
-        Some(from_raw_parts_mut(out, capacity))
-    }
-}
-
 pub(crate) fn crypto_buffer_from_buf(
     buf: &[u8],
     pool: Option<&CertificateCache>,
@@ -253,7 +208,7 @@
         unsafe {
             // Safety: `self` still exclusively owns the buffer region and the range of bytes
             // is known to be initialised by us. See `advance`.
-            sanitize_slice(self.ptr, self.cursor).unwrap_or(&[])
+            u8::from_ffi_ptr(self.ptr, self.cursor)
         }
     }
 
diff --git a/rust/bssl-tls/src/io.rs b/rust/bssl-tls/src/io.rs
index 756aab3..240765f 100644
--- a/rust/bssl-tls/src/io.rs
+++ b/rust/bssl-tls/src/io.rs
@@ -31,6 +31,7 @@
     },
 };
 
+use bssl_crypto::FromFfiSlice;
 use once_cell::sync::Lazy;
 
 use crate::{
@@ -38,11 +39,7 @@
     errors::{
         Error,
         TlsRetryReason, //
-    },
-    ffi::{
-        sanitise_mut_byteslice,
-        sanitize_slice, //
-    },
+    }, //
 };
 
 #[cfg(feature = "std")]
@@ -369,11 +366,9 @@
     };
     // Zero the buffer now.
     // TODO(@xfding): maybe we want to have a buffer wrapper that tracks initialised region.
-    let Some(buf) = (unsafe {
+    let buf = unsafe {
         // Safety: `buffer` and `len` are sanitised and initialised for the right memory region.
-        sanitise_mut_byteslice(buffer as *mut u8, len)
-    }) else {
-        return -1;
+        bssl_crypto::zeroize_mut_byteslice(buffer as *mut u8, len)
     };
     let work = {
         let Some(reader) = rust_bio.get_reader() else {
@@ -429,11 +424,11 @@
     } else {
         None
     };
-    let Some(buf) = (unsafe {
-        // Safety: `buffer` and `len` are sanitised and initialised for the right memory region.
-        sanitize_slice(buffer as *mut u8, len)
-    }) else {
-        return -1;
+    let buf = unsafe {
+        // Safety:
+        // - `buffer` and `len` are sanitised and initialised for the right memory region.
+        // - in `libssl` context, `buffer` is an allocation generated by BoringSSL.
+        u8::from_ffi_ptr(buffer as *const u8, len)
     };
     let work = {
         let Some(writer) = rust_bio.get_writer() else {
diff --git a/rust/bssl-tls/src/macros.rs b/rust/bssl-tls/src/macros.rs
index 3b6a19a..93bf11c 100644
--- a/rust/bssl-tls/src/macros.rs
+++ b/rust/bssl-tls/src/macros.rs
@@ -93,14 +93,12 @@
                         ::bssl_sys::CRYPTO_BUFFER_len(self.ptr()),
                     )
                 };
-                if data.is_null() || len == 0 || len > isize::MAX as usize {
-                    return &[]
-                }
                 unsafe {
                     // Safety:
                     // - `data` is 1-size and 1-align and `len` is valid by BoringSSL invariant.
                     // - `len` is sanitised to be within bound.
-                    $crate::ffi::sanitize_slice(data, len).unwrap_or(&[])
+                    // - `data` is sourced from BoringSSL.
+                    ::bssl_crypto::FromFfiSlice::from_ffi_ptr(data, len)
                 }
             }
         }
@@ -153,7 +151,7 @@
         #[allow(unused_unsafe)]
         unsafe {
             // Safety: data and len are returned by BoringSSL and are valid.
-            $crate::ffi::sanitize_slice(data, len)
+            ::bssl_crypto::FromFfiSlice::from_ffi_ptr(data, len)
         }
     }};
 }
diff --git a/rust/bssl-tls/src/sessions.rs b/rust/bssl-tls/src/sessions.rs
index aee4f83..eada1b0 100644
--- a/rust/bssl-tls/src/sessions.rs
+++ b/rust/bssl-tls/src/sessions.rs
@@ -17,6 +17,8 @@
 use alloc::vec::Vec;
 use core::ptr::NonNull;
 
+use bssl_crypto::FromFfiSlice;
+
 use crate::{
     call_slice_getter,
     config::ProtocolVersion,
@@ -24,7 +26,6 @@
     errors::Error,
     ffi::{
         Alloc,
-        sanitize_slice,
         slice_into_ffi_raw_parts, //
     }, //
 };
@@ -76,7 +77,7 @@
         let out_data = Alloc(out_data);
         let slice = unsafe {
             // Safety: out_data.0 and out_len are returned by BoringSSL and are valid.
-            sanitize_slice(out_data.0, out_len).unwrap()
+            u8::from_ffi_ptr(out_data.0, out_len)
         };
         Ok(slice.to_vec())
     }
@@ -95,7 +96,7 @@
         let out_data = Alloc(out_data);
         let slice = unsafe {
             // Safety: out_data.0 and out_len are returned by BoringSSL and are valid.
-            sanitize_slice(out_data.0, out_len).unwrap()
+            u8::from_ffi_ptr(out_data.0, out_len)
         };
         Ok(slice.to_vec())
     }
@@ -165,11 +166,9 @@
                     bssl_sys::CRYPTO_BUFFER_len(buf),
                 )
             };
-            let Some(slice) = (unsafe {
+            let slice = unsafe {
                 // Safety: data and len are valid.
-                sanitize_slice(data, len)
-            }) else {
-                continue;
+                u8::from_ffi_ptr(data, len)
             };
             res.push(slice.to_vec());
         }
@@ -178,17 +177,19 @@
 
     /// Get the signed certificate timestamp list, if any.
     pub fn get_signed_cert_timestamp_list(&self) -> Option<&[u8]> {
-        call_slice_getter!(
+        let sct = call_slice_getter!(
             bssl_sys::SSL_SESSION_get0_signed_cert_timestamp_list,
             self.ptr()
-        )
+        );
+        (!sct.is_empty()).then_some(sct)
     }
 
     /// Get the OCSP response, if any.
     ///
     /// See [RFC 8446 §4.4.2.1](https://datatracker.ietf.org/doc/html/rfc8446#section-4.4.2.1).
     pub fn get_ocsp_response(&self) -> Option<&[u8]> {
-        call_slice_getter!(bssl_sys::SSL_SESSION_get0_ocsp_response, self.ptr())
+        let ocsp = call_slice_getter!(bssl_sys::SSL_SESSION_get0_ocsp_response, self.ptr());
+        (!ocsp.is_empty()).then_some(ocsp)
     }
 
     /// Check if the session should be single use.
@@ -217,7 +218,8 @@
 
     /// Get the ticket, if any.
     pub fn get_ticket(&self) -> Option<&[u8]> {
-        call_slice_getter!(bssl_sys::SSL_SESSION_get0_ticket, self.ptr())
+        let ticket = call_slice_getter!(bssl_sys::SSL_SESSION_get0_ticket, self.ptr());
+        (!ticket.is_empty()).then_some(ticket)
     }
 
     /// Check if the session has a peer SHA256.
@@ -230,7 +232,8 @@
 
     /// Get the peer SHA256, if any.
     pub fn get_peer_sha256(&self) -> Option<&[u8]> {
-        call_slice_getter!(bssl_sys::SSL_SESSION_get0_peer_sha256, self.ptr())
+        let sha256 = call_slice_getter!(bssl_sys::SSL_SESSION_get0_peer_sha256, self.ptr());
+        (!sha256.is_empty()).then_some(sha256)
     }
 
     /// Check if the session is resumable across names.
diff --git a/rust/bssl-x509/src/certificates.rs b/rust/bssl-x509/src/certificates.rs
index ece3a6d..7156d8a 100644
--- a/rust/bssl-x509/src/certificates.rs
+++ b/rust/bssl-x509/src/certificates.rs
@@ -72,10 +72,22 @@
     ptr::{NonNull, null_mut},
 };
 
+use bssl_crypto::FromFfiSlice;
+
 use crate::{
-    errors::{PemReason, PkiError, X509Error},
-    ffi::{Bio, sanitize_slice, slice_into_ffi_raw_parts},
-    keys::{PrivateKey, PublicKey},
+    errors::{
+        PemReason,
+        PkiError,
+        X509Error, //
+    },
+    ffi::{
+        Bio,
+        slice_into_ffi_raw_parts, //
+    },
+    keys::{
+        PrivateKey,
+        PublicKey, //
+    },
 };
 
 bssl_macros::bssl_enum! {
@@ -175,8 +187,10 @@
         return None;
     }
     let bytes = unsafe {
-        // Safety: `'a` will still outlive the input buffer and this byte slice.
-        sanitize_slice(ptr, str_len)?
+        // Safety:
+        // - `'a` will still outlive the input buffer and this byte slice.
+        // - `ptr` is sourced from BoringSSL.
+        u8::from_ffi_ptr(ptr, str_len)
     };
     core::str::from_utf8(bytes).ok()
 }
@@ -249,8 +263,10 @@
                                 continue;
                             }
                             let bytes = unsafe {
-                                // Safety: `self` will outlive the input buffer and this byte slice.
-                                sanitize_slice(ptr, len as usize)?
+                                // Safety:
+                                // - `self` will outlive the input buffer and this byte slice.
+                                // - `ptr` is sourced from BoringSSL.
+                                u8::from_ffi_ptr(ptr, len as usize)
                             };
                             return Some(GeneralName::Ip(bytes));
                         }
diff --git a/rust/bssl-x509/src/ffi.rs b/rust/bssl-x509/src/ffi.rs
index 3137423..11f186f 100644
--- a/rust/bssl-x509/src/ffi.rs
+++ b/rust/bssl-x509/src/ffi.rs
@@ -14,8 +14,10 @@
 
 use core::{
     marker::PhantomData,
-    ptr::{NonNull, null},
-    slice::from_raw_parts,
+    ptr::{
+        NonNull,
+        null, //
+    },//
 };
 
 use bssl_crypto::FfiSlice;
@@ -50,25 +52,6 @@
     }
 }
 
-/// Sanitize the data pointer and length and reconstitute the slice.
-///
-/// This method returns an empty slice if the length is 0 or the pointer is NULL.
-/// # Safety
-/// Caller must ensure that `'a` outlives `input`.
-#[inline]
-pub(crate) unsafe fn sanitize_slice<'a, T>(input: *const T, len: usize) -> Option<&'a [T]> {
-    if len == 0 || input.is_null() {
-        return Some(&[]);
-    }
-    if !input.is_aligned() || len.checked_mul(size_of::<T>())? > isize::MAX as usize {
-        return None;
-    }
-    unsafe {
-        // Safety: the pointer and the size has been sanitised.
-        Some(from_raw_parts(input, len))
-    }
-}
-
 /// BIO wrapper only for internal use.
 pub(crate) struct Bio<'a>(NonNull<bssl_sys::BIO>, PhantomData<&'a ()>);