| // 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. | |
| use core::ffi::c_int; | |
| use bssl_crypto::FfiSlice as _; | |
| use crate::{ | |
| check_lib_error, | |
| config::ConfigurationError, | |
| context::{ | |
| SupportedMode, | |
| TlsContext, | |
| TlsContextBuilder, // | |
| }, | |
| errors::Error, | |
| sessions::TlsSession, // | |
| }; | |
| /// # Sessions | |
| impl<M> TlsContextBuilder<M> | |
| where | |
| M: SupportedMode, | |
| { | |
| /// Set Session ID Context. | |
| /// | |
| /// This method errs when the context is not a valid serialization of the context buffer. | |
| /// | |
| /// A session without a matching `sid_ctx` will not be picked. | |
| /// Also when [`crate::credentials::CertificateVerificationMode::PeerCertRequested`] is set, | |
| /// the server connection will reject all sessions unless this method is called. | |
| pub fn with_session_id_ctx(&mut self, sid_ctx: &[u8]) -> Result<&mut Self, Error> { | |
| if sid_ctx.len() > bssl_sys::SSL_MAX_SID_CTX_LENGTH as usize { | |
| return Err(Error::Configuration( | |
| ConfigurationError::SessionIdContextTooLarge, | |
| )); | |
| } | |
| check_lib_error!(unsafe { | |
| // Safety: the validity of the handle `self.0` is witnessed by `self`. | |
| bssl_sys::SSL_CTX_set_session_id_context( | |
| self.ptr(), | |
| sid_ctx.as_ffi_ptr(), | |
| sid_ctx.len(), | |
| ) | |
| }); | |
| Ok(self) | |
| } | |
| /// Set session cache | |
| pub fn with_session_cache(&mut self, mode: SessionCacheMode) -> &mut Self { | |
| unsafe { | |
| // Safety: | |
| // - the validity of the handle `self.0` is witnessed by `self`. | |
| // - the `mode` passes the right flag bits by construction. | |
| bssl_sys::SSL_CTX_set_session_cache_mode(self.ptr(), mode.bits()); | |
| } | |
| self | |
| } | |
| } | |
| bitflags::bitflags! { | |
| /// Session cache mode | |
| #[derive(Debug, Copy, Clone)] | |
| pub struct SessionCacheMode: c_int { | |
| /// No caching. | |
| const CACHE_OFF = bssl_sys::SSL_SESS_CACHE_OFF as c_int; | |
| /// Caching enabled for clients. | |
| const CACHE_CLIENT = bssl_sys::SSL_SESS_CACHE_CLIENT as c_int; | |
| /// Caching enabled for servers. | |
| const CACHE_SERVER = bssl_sys::SSL_SESS_CACHE_SERVER as c_int; | |
| /// Caching enabled for both clients and servers. | |
| const CACHE_BOTH = bssl_sys::SSL_SESS_CACHE_BOTH as c_int; | |
| /// Disable the default automatic session flushing after every 255 connections. | |
| const NO_AUTO_CLEAR = bssl_sys::SSL_SESS_CACHE_NO_AUTO_CLEAR as c_int; | |
| /// Disable session look-up from internal session cache **on a server**. | |
| const NO_INTERNAL_LOOKUP = bssl_sys::SSL_SESS_CACHE_NO_INTERNAL_LOOKUP as c_int; | |
| /// Disable session storage into the internal session cache **on a server**. | |
| const NO_INTERNAL_STORE = bssl_sys::SSL_SESS_CACHE_NO_INTERNAL_STORE as c_int; | |
| /// Disable session internal caching. | |
| const NO_INTERNAL = bssl_sys::SSL_SESS_CACHE_NO_INTERNAL as c_int; | |
| } | |
| } | |
| /// # Sessions | |
| impl<M> TlsContext<M> | |
| where | |
| M: SupportedMode, | |
| { | |
| /// Add a [`TlsSession`] to the context. | |
| /// | |
| /// This method returns `true` if the session is freshly added; | |
| /// otherwise, it is already present in the context by returning `false`. | |
| pub fn add_session(&self, session: &TlsSession) -> bool { | |
| let ret = unsafe { | |
| // Safety: | |
| // - the validity of the handle `self.0` is witnessed by `self`. | |
| // - the method is synchronised with a mutex guard. | |
| bssl_sys::SSL_CTX_add_session(self.ptr(), session.ptr()) == 1 | |
| }; | |
| unsafe { | |
| // Safety: we are only clearing the error queue in the current thread. | |
| bssl_sys::ERR_clear_error(); | |
| } | |
| ret | |
| } | |
| /// Remove a [`TlsSession`] from the context. | |
| /// | |
| /// This method returns `true` if the session is present and removed from the context; | |
| /// otherwise, it is missing by returning `false`. | |
| pub fn remove_session(&self, session: &TlsSession) -> bool { | |
| let ret = unsafe { | |
| // Safety: | |
| // - the validity of the handle `self.0` is witnessed by `self`. | |
| // - the method is synchronised with a mutex guard. | |
| bssl_sys::SSL_CTX_remove_session(self.ptr(), session.ptr()) == 1 | |
| }; | |
| unsafe { | |
| // Safety: we are only clearing the error queue in the current thread. | |
| bssl_sys::ERR_clear_error(); | |
| } | |
| ret | |
| } | |
| /// Remove all sessions that have expired past the `deadline`, which is a POSIX timestamp. | |
| pub fn flush_sessions(&self, deadline: u64) { | |
| unsafe { | |
| // Safety: | |
| // - the validity of the handle `self.0` is witnessed by `self`. | |
| // - the method is synchronised with a mutex guard. | |
| bssl_sys::SSL_CTX_flush_sessions(self.ptr(), deadline); | |
| } | |
| } | |
| /// Get the number of sessions in the context. | |
| pub fn count_sessions(&self) -> usize { | |
| unsafe { | |
| // Safety: | |
| // - the validity of the handle `self.0` is witnessed by `self`. | |
| // - the method is synchronised with a mutex guard. | |
| bssl_sys::SSL_CTX_sess_number(self.ptr()) | |
| } | |
| } | |
| } |