| // Copyright 2026 The BoringSSL Authors | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // https://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #![deny( | |
| missing_docs, | |
| unsafe_op_in_unsafe_fn, | |
| clippy::missing_safety_doc, | |
| clippy::indexing_slicing, | |
| clippy::unwrap_used, | |
| clippy::undocumented_unsafe_blocks | |
| )] | |
| #![allow(private_bounds)] | |
| #![cfg_attr(not(any(feature = "std", test)), no_std)] | |
| #![recursion_limit = "512"] | |
| //! BoringSSL TLS bindings | |
| //! | |
| //! *WARNING* this crate is still work in progress. | |
| extern crate alloc; | |
| extern crate core; | |
| use alloc::boxed::Box; | |
| use core::panic::AssertUnwindSafe; | |
| pub mod alerts; | |
| pub mod alpn; | |
| pub mod ciphers; | |
| pub mod config; | |
| pub mod connection; | |
| pub mod context; | |
| pub mod credentials; | |
| pub mod errors; | |
| mod ffi; | |
| pub mod io; | |
| mod methods; | |
| pub mod sessions; | |
| #[cfg(feature = "std")] | |
| /// Synchronous I/O high-level APIs. | |
| pub mod sync_io; | |
| #[macro_use] | |
| #[doc(hidden)] | |
| mod macros; | |
| #[cfg(test)] | |
| #[cfg(feature = "std")] | |
| mod tests; | |
| pub use ffi::ReceiveBuffer; | |
| fn has_duplicates<T: Ord + Eq>(list: &[T]) -> bool { | |
| let mut seen = alloc::collections::BTreeSet::new(); | |
| list.iter().any(|elem| !seen.insert(elem)) | |
| } | |
| /// Method table accessor for connection-level state. | |
| /// | |
| /// Returns `&'a mut Self` because connection state is exclusively owned. | |
| #[allow(unused)] // This trait will be used by certificate selection callback. | |
| pub(crate) trait Methods { | |
| /// Safety: | |
| /// - `ssl` must outlive `'a` and it must be passed in from BoringSSL | |
| /// through vtable calls. | |
| /// - the returned method table **must not** be aliased. | |
| unsafe extern "C" fn from_ssl<'a>(ssl: *mut bssl_sys::SSL) -> Option<&'a mut Self>; | |
| } | |
| /// Shared method table accessor. | |
| /// | |
| /// Returns `&'a Self` for shared (non-exclusive) access to the method table. | |
| /// Used by context, connection, and credential method tables for read-only lookups. | |
| pub(crate) trait MethodsRef { | |
| /// Safety: | |
| /// - `ssl` must outlive `'a` and it must be passed in from BoringSSL | |
| /// through vtable calls. | |
| unsafe extern "C" fn from_ssl<'a>(ssl: *mut bssl_sys::SSL) -> Option<&'a Self>; | |
| } | |
| pub(crate) trait HandshakeCompleteMethods: Methods { | |
| fn handshake_complete_methods( | |
| &mut self, | |
| ) -> Option<Box<dyn connection::lifecycle::HandshakeComplete>>; | |
| } | |
| pub(crate) trait PrivateKeyMethods: MethodsRef { | |
| fn private_key_methods(&self) -> Option<&dyn credentials::PrivateKeyDelegate>; | |
| } | |
| pub(crate) trait VerifyCertificateMethods: MethodsRef { | |
| fn verify_certificate_methods(&self) -> Option<&dyn credentials::VerifyCertificate>; | |
| } | |
| pub(crate) trait EarlyCallbackMethods<M>: MethodsRef { | |
| fn early_callback_handler(&self) -> Option<&dyn credentials::early_callback::EarlyCallback<M>>; | |
| } | |
| pub(crate) trait CertCallback<Mode>: MethodsRef { | |
| fn server_cert_cb( | |
| &self, | |
| ) -> Option<&(dyn credentials::select_cert::ServerCertificateSelector<Mode> + 'static)>; | |
| fn client_cert_cb( | |
| &self, | |
| ) -> Option<&(dyn credentials::select_cert::ClientCertificateSelector<Mode> + 'static)>; | |
| } | |
| #[inline] | |
| fn abort_on_panic<T>(work: impl FnOnce() -> T) -> T { | |
| let assert_unwind_safe = AssertUnwindSafe(work); | |
| let call = move || { | |
| let AssertUnwindSafe(work) = { assert_unwind_safe }; | |
| work() | |
| }; | |
| #[cfg(feature = "std")] | |
| let res = match std::panic::catch_unwind(call) { | |
| Ok(res) => res, | |
| Err(_) => { | |
| eprintln!("panic about to cross language boundary"); | |
| std::process::abort() | |
| } | |
| }; | |
| #[cfg(not(feature = "std"))] | |
| let res = call(); | |
| res | |
| } |