rust: bssl-tls: Add controls for CAs Bug: 479599893 Signed-off-by: Xiangfei Ding <xfding@google.com> Change-Id: I2b58066e499d157b7dce1560b2f161f76a6a6964 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/98791 Reviewed-by: Adam Langley <agl@google.com>
diff --git a/rust/bssl-tls/src/connection/credentials.rs b/rust/bssl-tls/src/connection/credentials.rs index 73c5d2b..cc2b0d9 100644 --- a/rust/bssl-tls/src/connection/credentials.rs +++ b/rust/bssl-tls/src/connection/credentials.rs
@@ -31,6 +31,7 @@ use super::{ Client, + Server, TlsConnection, TlsConnectionBuilder, lifecycle::{ @@ -46,6 +47,7 @@ credentials::{ CertificateType, CertificateVerificationMode, + DistinguishedName, PrivateKeyDelegate, SignatureAlgorithm, TlsCredential, @@ -495,3 +497,25 @@ Some(crate::credentials::marshal_evp_into_spki(pkey)) } } + +/// # Certificate authorities - Server +/// +/// TLS can send a list of supported certificate authorities to guide the peer in certificate +/// selection. +impl<M> TlsConnectionInHandshake<'_, Server, M> { + /// This setting advertises the list of certificate authorities names in the + /// `certificate_authorities` extension to send the client. + pub fn set_ca_names( + &mut self, + names: impl IntoIterator<Item = DistinguishedName>, + ) -> &mut Self { + unsafe { + // Safety: this call only transfers the ownership of the stack. + bssl_sys::SSL_set0_CA_names( + self.ptr(), + DistinguishedName::into_crypto_buffer_stack(names), + ) + } + self + } +}
diff --git a/rust/bssl-tls/src/context/credentials.rs b/rust/bssl-tls/src/context/credentials.rs index 8159b8a..f9f951b 100644 --- a/rust/bssl-tls/src/context/credentials.rs +++ b/rust/bssl-tls/src/context/credentials.rs
@@ -31,6 +31,7 @@ credentials::{ CertificateType, CertificateVerificationMode, + DistinguishedName, PrivateKeyDelegate, SignatureAlgorithm, TlsCredential, @@ -333,3 +334,25 @@ Ok(self) } } + +/// # Certificate authorities - Server +/// +/// TLS can send a list of supported certificate authorities to guide the peer in certificate +/// selection. +impl<M> TlsContextBuilder<M> { + /// This setting advertises the list of certificate authorities names in the + /// `certificate_authorities` extension to send the client. + pub fn set_ca_names( + &mut self, + names: impl IntoIterator<Item = DistinguishedName>, + ) -> &mut Self { + unsafe { + // Safety: this call only transfers the ownership of the stack. + bssl_sys::SSL_CTX_set0_client_CAs( + self.ptr(), + DistinguishedName::into_crypto_buffer_stack(names), + ) + } + self + } +}
diff --git a/rust/bssl-tls/src/credentials.rs b/rust/bssl-tls/src/credentials.rs index 7fe822b..2fa6181 100644 --- a/rust/bssl-tls/src/credentials.rs +++ b/rust/bssl-tls/src/credentials.rs
@@ -65,6 +65,7 @@ ffi::{ Alloc, Bio, + Stack, sanitize_slice, slice_into_ffi_raw_parts, // }, @@ -1122,5 +1123,28 @@ buffer.as_ref().to_vec() } +crypto_buffer_wrapper! { + /// A name `DistinguishedName` encoded into DER per [RFC 5280]. + /// Typically this is used to enclose a certificate authority name. + /// + /// [RFC 5280]: <https://datatracker.ietf.org/doc/html/rfc5280#appendix-A.1> + pub struct DistinguishedName +} + +impl DistinguishedName { + pub(crate) fn into_crypto_buffer_stack( + names: impl IntoIterator<Item = Self>, + ) -> *mut bssl_sys::stack_st_CRYPTO_BUFFER { + let mut sk = Stack::new(); + for name in names { + unsafe { + // Safety: `name` is owned at the moment. + sk.push(name.into_raw()); + } + } + sk.into_raw() + } +} + #[cfg(test)] mod tests;
diff --git a/rust/bssl-tls/src/ffi.rs b/rust/bssl-tls/src/ffi.rs index 2cd03f1..c462fd9 100644 --- a/rust/bssl-tls/src/ffi.rs +++ b/rust/bssl-tls/src/ffi.rs
@@ -14,7 +14,10 @@ use core::{ marker::PhantomData, - mem::MaybeUninit, + mem::{ + MaybeUninit, + forget, // + }, ptr::{ NonNull, null, @@ -271,3 +274,106 @@ self.filled() } } + +pub(crate) unsafe trait BsslStack: Sized { + type Element: StackElement; + + fn new() -> *mut Self; + + /// Safety: `this` handle must be a live `stack_st_*` handle. + unsafe fn size(this: *const Self) -> usize; + + /// Safety: both `this` and `elem` cannot be aliased. + unsafe fn push(this: *mut Self, elem: *mut Self::Element); + + const POP_FREE: unsafe extern "C" fn( + *mut Self, + Option<unsafe extern "C" fn(*mut Self::Element)>, + ); +} + +unsafe impl BsslStack for bssl_sys::stack_st_CRYPTO_BUFFER { + type Element = bssl_sys::CRYPTO_BUFFER; + + fn new() -> *mut Self { + let st = unsafe { + // Safety: this call only allocates memory + bssl_sys::sk_CRYPTO_BUFFER_new_null() + }; + if st.is_null() { + panic!("allocation failed") + } + st + } + + unsafe fn size(this: *const Self) -> usize { + unsafe { + // Safety: `this` is still live and valid. + bssl_sys::sk_CRYPTO_BUFFER_num(this) + } + } + + unsafe fn push(this: *mut Self, elem: *mut bssl_sys::CRYPTO_BUFFER) { + let rc = unsafe { + // Safety: `this` and `elem` are exclusively owned and valid. + bssl_sys::sk_CRYPTO_BUFFER_push(this, elem) + }; + if rc == 0 { + panic!("allocation failed") + } + } + + const POP_FREE: unsafe extern "C" fn( + *mut Self, + Option<unsafe extern "C" fn(*mut Self::Element)>, + ) = bssl_sys::sk_CRYPTO_BUFFER_pop_free; +} + +pub(crate) unsafe trait StackElement: Sized { + type Stack: BsslStack<Element = Self>; + + const FREE: unsafe extern "C" fn(*mut Self); +} + +unsafe impl StackElement for bssl_sys::CRYPTO_BUFFER { + type Stack = bssl_sys::stack_st_CRYPTO_BUFFER; + + const FREE: unsafe extern "C" fn(*mut Self) = bssl_sys::CRYPTO_BUFFER_free; +} + +pub(crate) struct Stack<T: StackElement> { + inner: *mut T::Stack, + _p: PhantomData<T>, +} + +impl<T: StackElement> Drop for Stack<T> { + fn drop(&mut self) { + unsafe { + // Safety: we still own the stack at this moment + T::Stack::POP_FREE(self.inner, Some(T::FREE)) + } + } +} + +impl<T: StackElement> Stack<T> { + pub fn new() -> Self { + Self { + inner: T::Stack::new(), + _p: PhantomData, + } + } + + // Safety: `elem` must not alias because its ownership will be transferred. + pub unsafe fn push(&mut self, elem: *mut T) { + unsafe { + // Safety: `this` is owned by the caller. + T::Stack::push(self.inner, elem); + } + } + + pub fn into_raw(self) -> *mut T::Stack { + let ptr = self.inner; + forget(self); + ptr + } +}