blob: 706ed63233dee76600c5c9a157d73e399f7827d2 [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.
//! TLS Configurations
use alloc::string::String;
use core::ffi::c_int;
use bssl_macros::bssl_enum;
bssl_enum! {
/// Protocol version for TLS or DTLS
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum ProtocolVersion: u16 {
/// TLS version 1.2
Tls12 = bssl_sys::TLS1_2_VERSION as u16,
/// TLS version 1.3
Tls13 = bssl_sys::TLS1_3_VERSION as u16,
/// DTLS version 1.2
Dtls12 = bssl_sys::DTLS1_2_VERSION as u16,
/// DTLS version 1.3
Dtls13 = bssl_sys::DTLS1_3_VERSION as u16,
}
}
impl TryFrom<c_int> for ProtocolVersion {
type Error = c_int;
fn try_from(version: c_int) -> Result<Self, Self::Error> {
let Ok(val) = u16::try_from(version) else {
return Err(version);
};
if let Ok(version) = ProtocolVersion::try_from(val) {
Ok(version)
} else {
Err(version)
}
}
}
bitflags::bitflags! {
#[derive(Debug, Copy, Clone)]
pub(crate) struct ConnectionMode: u32 {
/// Deny session creation.
const MODE_NO_SESSION_CREATION = bssl_sys::SSL_MODE_NO_SESSION_CREATION as u32;
/// Allow moving write buffer.
/// This is indispensable for async I/O because the future could be freely cancelled.
const ACCEPT_MOVING_WRITE_BUFFER = bssl_sys::SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER as u32;
}
}
bssl_enum! {
/// Key exchange groups for TLS or DTLS
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum KeyExchangeGroups: u16 {
/// Key exchange using `ECDH-P256`
Secp256r1 = bssl_sys::SSL_GROUP_SECP256R1 as u16,
/// Key exchange using `ECDH-P384`
Secp384r1 = bssl_sys::SSL_GROUP_SECP384R1 as u16,
/// Key exchange using `ECDH-P521`
Secp521r1 = bssl_sys::SSL_GROUP_SECP521R1 as u16,
/// Key exchange using `X25519`
X25519 = bssl_sys::SSL_GROUP_X25519 as u16,
/// Key exchange using post-quantum hybrid scheme `X25519MLKEM768`
X25519Mlkem768 = bssl_sys::SSL_GROUP_X25519_MLKEM768 as u16,
/// Key exchange using `MLKEM-1024`
Mlkem1024 = bssl_sys::SSL_GROUP_MLKEM1024 as u16,
}
}
bitflags::bitflags! {
/// Flags to control how key exchange group could be chosen
#[repr(transparent)]
#[derive(Debug, Copy, Clone)]
pub struct KeyExchangeGroupFlag: u32 {
/// `EQUAL_PREFERENCE_WITH_NEXT` indicates that the corresponding group has equal preference
/// with the next member of the list of groups being configured.
const EQUAL_PREFERENCE_WITH_NEXT = 0x01;
}
}
/// Configuration errors
#[derive(Debug)]
pub enum ConfigurationError {
/// Some parameters are specified twice in the list.
DuplicatedParameters,
/// Some string is not acceptable.
InvalidString,
/// Session ID context data is too large.
SessionIdContextTooLarge,
/// Preshared Key is too long.
PskTooLong,
/// Value is out of range.
ValueOutOfRange,
/// Mismatching private and public key pair.
MismatchingKeyPair,
/// IP address is invalid.
/// It should either be 4 bytes for IPv4 addresses or 16 bytes for IPv6 addresses.
InvalidIp,
/// Invalid parameters.
InvalidParameters,
}
impl core::fmt::Display for ConfigurationError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
ConfigurationError::DuplicatedParameters => f.write_str("duplicated parameters"),
ConfigurationError::InvalidString => f.write_str("invalid string"),
ConfigurationError::SessionIdContextTooLarge => {
f.write_str("session ID context data is too large")
}
ConfigurationError::PskTooLong => f.write_str("preshared key is too long"),
ConfigurationError::MismatchingKeyPair => {
f.write_str("mismatching private and public key pair")
}
ConfigurationError::ValueOutOfRange => f.write_str("value is out of range"),
ConfigurationError::InvalidIp => f.write_str("invalid IP address"),
ConfigurationError::InvalidParameters => f.write_str("invalid parameters"),
}
}
}
/// Cipher information
#[derive(Clone)]
#[non_exhaustive]
pub struct CipherInfo {
/// Protocol ID as assigned by [IANA](https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4)
pub id: u32,
/// IETF Name of the cipher
pub ietf_name: String,
/// Indicates whether this cipher is an AEAD cipher
pub is_aead: bool,
/// Indicates whether this cipher is a block cipher
pub is_block_cipher: bool,
/// Cipher strength in bits
pub strength: u16,
}
/// Supported cipher suites as registered with [IANA].
///
/// The following cipher suite values are assigned by IANA and correspond to
/// both TLS 1.3 and TLS 1.2 suites.
/// TLS 1.3 suites are mentioned again in [RFC 8446].
/// TLS 1.2 suites are defined in the relevant RFCs for each algorithm family.
///
/// [IANA]: https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4
/// [RFC 8446]: https://www.rfc-editor.org/rfc/rfc8446
/// [RFC 5489]: https://www.rfc-editor.org/rfc/rfc5489
/// [RFC 8422]: https://www.rfc-editor.org/rfc/rfc8422
/// [RFC 7905]: https://www.rfc-editor.org/rfc/rfc7905
/// [RFC 5288]: https://www.rfc-editor.org/rfc/rfc5288
/// [RFC 5246]: https://www.rfc-editor.org/rfc/rfc5246
/// [RFC 4279]: https://www.rfc-editor.org/rfc/rfc4279
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct CipherSuite(pub u16);
#[allow(non_upper_case_globals)]
impl CipherSuite {
/// TLS 1.3 cipher suite `TLS_AES_128_GCM_SHA256`.
pub const Aes128GcmSha256: Self = Self(bssl_sys::SSL_CIPHER_AES_128_GCM_SHA256 as u16);
/// TLS 1.3 cipher suite `TLS_AES_256_GCM_SHA384`.
pub const Aes256GcmSha384: Self = Self(bssl_sys::SSL_CIPHER_AES_256_GCM_SHA384 as u16);
/// TLS 1.3 cipher suite `TLS_CHACHA20_POLY1305_SHA256`.
pub const Chacha20Poly1305Sha256: Self =
Self(bssl_sys::SSL_CIPHER_CHACHA20_POLY1305_SHA256 as u16);
/// TLS 1.2 cipher suite `TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256` from RFC 5288.
pub const EcdheEcdsaWithAes128GcmSha256: Self =
Self(bssl_sys::SSL_CIPHER_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 as u16);
/// TLS 1.2 cipher suite `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384` from RFC 5288.
pub const EcdheEcdsaWithAes256GcmSha384: Self =
Self(bssl_sys::SSL_CIPHER_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 as u16);
/// TLS 1.2 cipher suite `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256` from RFC 5288.
pub const EcdheRsaWithAes128GcmSha256: Self =
Self(bssl_sys::SSL_CIPHER_ECDHE_RSA_WITH_AES_128_GCM_SHA256 as u16);
/// TLS 1.2 cipher suite `TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384` from RFC 5288.
pub const EcdheRsaWithAes256GcmSha384: Self =
Self(bssl_sys::SSL_CIPHER_ECDHE_RSA_WITH_AES_256_GCM_SHA384 as u16);
/// TLS 1.2 cipher suite `TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256` from RFC 7905.
pub const EcdheRsaWithChacha20Poly1305Sha256: Self =
Self(bssl_sys::SSL_CIPHER_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 as u16);
/// TLS 1.2 cipher suite `TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256` from RFC 7905.
pub const EcdheEcdsaWithChacha20Poly1305Sha256: Self =
Self(bssl_sys::SSL_CIPHER_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 as u16);
/// TLS cipher suite `TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256` from RFC 7905.
pub const EcdhePskWithChacha20Poly1305Sha256: Self =
Self(bssl_sys::SSL_CIPHER_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 as u16);
/// TLS 1.2 cipher suite `TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA` from RFC 8422.
pub const EcdheEcdsaWithAes128CbcSha: Self =
Self(bssl_sys::SSL_CIPHER_ECDHE_ECDSA_WITH_AES_128_CBC_SHA as u16);
/// TLS 1.2 cipher suite `TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA` from RFC 8422.
pub const EcdheEcdsaWithAes256CbcSha: Self =
Self(bssl_sys::SSL_CIPHER_ECDHE_ECDSA_WITH_AES_256_CBC_SHA as u16);
/// TLS 1.2 cipher suite `TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA` from RFC 8422.
pub const EcdheRsaWithAes128CbcSha: Self =
Self(bssl_sys::SSL_CIPHER_ECDHE_RSA_WITH_AES_128_CBC_SHA as u16);
/// TLS 1.2 cipher suite `TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA` from RFC 8422.
pub const EcdheRsaWithAes256CbcSha: Self =
Self(bssl_sys::SSL_CIPHER_ECDHE_RSA_WITH_AES_256_CBC_SHA as u16);
/// TLS cipher suite `TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA` from RFC 5489.
pub const EcdhePskWithAes128CbcSha: Self =
Self(bssl_sys::SSL_CIPHER_ECDHE_PSK_WITH_AES_128_CBC_SHA as u16);
/// TLS cipher suite `TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA` from RFC 5489.
pub const EcdhePskWithAes256CbcSha: Self =
Self(bssl_sys::SSL_CIPHER_ECDHE_PSK_WITH_AES_256_CBC_SHA as u16);
/// TLS 1.2 cipher suite `TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256` from RFC 5289.
pub const EcdheEcdsaWithAes128CbcSha256: Self =
Self(bssl_sys::SSL_CIPHER_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 as u16);
/// TLS 1.2 cipher suite `TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256` from RFC 5289.
pub const EcdheRsaWithAes128CbcSha256: Self =
Self(bssl_sys::SSL_CIPHER_ECDHE_RSA_WITH_AES_128_CBC_SHA256 as u16);
/// TLS 1.2 cipher suite `TLS_RSA_WITH_AES_128_GCM_SHA256` from RFC 5288.
pub const RsaWithAes128GcmSha256: Self =
Self(bssl_sys::SSL_CIPHER_RSA_WITH_AES_128_GCM_SHA256 as u16);
/// TLS 1.2 cipher suite `TLS_RSA_WITH_AES_256_GCM_SHA384` from RFC 5288.
pub const RsaWithAes256GcmSha384: Self =
Self(bssl_sys::SSL_CIPHER_RSA_WITH_AES_256_GCM_SHA384 as u16);
/// TLS 1.2 cipher suite `TLS_RSA_WITH_AES_128_CBC_SHA` from RFC 5246.
pub const RsaWithAes128CbcSha: Self =
Self(bssl_sys::SSL_CIPHER_RSA_WITH_AES_128_CBC_SHA as u16);
/// TLS 1.2 cipher suite `TLS_RSA_WITH_AES_256_CBC_SHA` from RFC 5246.
pub const RsaWithAes256CbcSha: Self =
Self(bssl_sys::SSL_CIPHER_RSA_WITH_AES_256_CBC_SHA as u16);
/// TLS cipher suite `TLS_PSK_WITH_AES_128_CBC_SHA` from RFC 4279.
pub const PskWithAes128CbcSha: Self =
Self(bssl_sys::SSL_CIPHER_PSK_WITH_AES_128_CBC_SHA as u16);
/// TLS cipher suite `TLS_PSK_WITH_AES_256_CBC_SHA` from RFC 4279.
pub const PskWithAes256CbcSha: Self =
Self(bssl_sys::SSL_CIPHER_PSK_WITH_AES_256_CBC_SHA as u16);
/// TLS 1.2 cipher suite `TLS_RSA_WITH_3DES_EDE_CBC_SHA` from RFC 5246.
pub const RsaWith3desEdeCbcSha: Self =
Self(bssl_sys::SSL_CIPHER_RSA_WITH_3DES_EDE_CBC_SHA as u16);
}
bssl_enum! {
/// Compliance Policy.
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum CompliancePolicy: u8 {
/// FIPS 202205
///
/// This policy configures a TLS connection to use:
/// - TLS 1.2 or 1.3;
/// - For TLS 1.2, only `ECDHE_[RSA|ECDSA]_WITH_AES_*_GCM_SHA*`;
/// - For TLS 1.3, only `AES-GCM`;
/// - P-256 or P-384 for key agreement;
/// - For server signatures, only PKCS#1/PSS with SHA256/384/512,
/// or ECDSA with P-256 or P-384 and SHA256/SHA384.
Fips202205 = bssl_sys::ssl_compliance_policy_t_ssl_compliance_policy_fips_202205 as u8,
/// WPA3-192 202304
///
/// This policy configures a TLS connection to use:
/// - TLS 1.2 or 1.3.
/// - For TLS 1.2, only `TLS_ECDHE_[ECDSA|RSA]_WITH_AES_256_GCM_SHA384`.
/// - For TLS 1.3, only `AES-256-GCM`.
/// - P-384 for key agreement.
/// - For handshake signatures, only ECDSA with P-384 and SHA-384, or RSA
/// with SHA-384 or SHA-512.
///
/// No limitations on the certificate chain nor leaf public key are imposed,
/// other than by the supported signature algorithms.
/// But WPA3's "192-bit" mode requires at least P-384 or 3072-bit RSA along the chain.
/// The caller must enforce this themselves on the verified chain using functions such as
/// [`crate::credentials::TlsCredentialBuilder::with_certificate_chain`].
///
/// Note that this setting is less secure than the default.
/// The implementation risks of using a more obscure primitive like P-384 dominate other
/// considerations.
Wpa3_192_202304 = bssl_sys::ssl_compliance_policy_t_ssl_compliance_policy_wpa3_192_202304 as u8,
/// CNSA 202407
///
/// This policy configures a TLS connection to use:
/// - For TLS 1.3, AES-256-GCM over AES-128-GCM over ChaCha20-Poly1305.
///
/// I.e. it ensures that AES-GCM will be used whenever the client supports it.
/// The cipher suite configuration mini-language can be used to similarly
/// configure prior TLS versions if they are enabled.
Cnsa202407 = bssl_sys::ssl_compliance_policy_t_ssl_compliance_policy_cnsa_202407 as u8,
}
}