blob: 006cfde709152c35c145da559a11c586a864877c [file]
// 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())
}
}
}