use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec::Vec;
use crate::ec::{BoxedEcdsaPrivateKey, Ed25519PrivateKey};
use crate::rsa::BoxedRsaPrivateKey;
use crate::signature_registry::SignaturePolicy;
use super::groups::NamedGroup;
use super::keylog::KeyLog;
use super::pki::{CrlStore, RootCertStore};
use super::version::ProtocolVersion;
use crate::x509::Time;
#[cfg(feature = "std")]
use super::conn::ReplayWindow;
#[allow(clippy::large_enum_variant)]
pub enum SigningKey {
Rsa(BoxedRsaPrivateKey),
Ecdsa(BoxedEcdsaPrivateKey),
Ed25519(Ed25519PrivateKey),
MlDsa44(crate::mldsa::MlDsa44PrivateKey),
MlDsa65(crate::mldsa::MlDsa65PrivateKey),
MlDsa87(crate::mldsa::MlDsa87PrivateKey),
}
#[non_exhaustive]
pub struct Identity {
pub cert_chain: Vec<Vec<u8>>,
pub key: SigningKey,
}
impl Identity {
pub fn new(cert_chain: Vec<Vec<u8>>, key: SigningKey) -> Self {
Self { cert_chain, key }
}
}
#[non_exhaustive]
pub struct ClientAuth {
pub roots: RootCertStore,
pub required: bool,
}
impl ClientAuth {
pub fn new(roots: RootCertStore, required: bool) -> Self {
Self { roots, required }
}
}
#[non_exhaustive]
pub struct Config {
pub min_version: ProtocolVersion,
pub max_version: ProtocolVersion,
pub identity: Option<Identity>,
pub roots: RootCertStore,
pub crls: CrlStore,
pub signature_policy: SignaturePolicy,
pub server_name: Option<String>,
pub verify_certificates: bool,
pub verification_time: Option<Time>,
pub client_auth: Option<ClientAuth>,
pub stapled_crl: Option<Vec<u8>>,
pub stapled_ocsp_response: Option<Vec<u8>>,
pub ticket_key: Option<[u8; 32]>,
pub max_early_data_size: u32,
#[cfg(feature = "std")]
pub replay_window: Option<ReplayWindow>,
pub alpn_protocols: Vec<Vec<u8>>,
pub record_size_limit: Option<u16>,
pub require_extended_master_secret: bool,
pub server_cert_type_preference: Vec<u8>,
pub client_cert_type_preference: Vec<u8>,
pub raw_public_key_spki: Option<Vec<u8>>,
pub expected_raw_public_keys: Vec<Vec<u8>>,
pub preferred_key_exchange_group: Option<NamedGroup>,
#[cfg(feature = "ech")]
pub ech: Option<super::ech::EchClient>,
#[cfg(feature = "ech")]
pub ech_server: Option<super::ech::EchServer>,
#[cfg(feature = "cert-compression")]
pub cert_compression_algorithms: Vec<u16>,
pub cookie_secret: Option<[u8; 32]>,
pub require_cookie: bool,
pub max_record_size: usize,
pub key_log: Option<Arc<dyn KeyLog>>,
}
impl Default for Config {
fn default() -> Self {
Config {
min_version: ProtocolVersion::TLSv1_2,
max_version: ProtocolVersion::TLSv1_3,
identity: None,
roots: RootCertStore::new(),
crls: CrlStore::new(),
signature_policy: SignaturePolicy::modern(),
server_name: None,
verify_certificates: true,
verification_time: None,
client_auth: None,
stapled_crl: None,
stapled_ocsp_response: None,
ticket_key: None,
max_early_data_size: 0,
#[cfg(feature = "std")]
replay_window: None,
alpn_protocols: Vec::new(),
record_size_limit: None,
require_extended_master_secret: true,
server_cert_type_preference: alloc::vec![0u8], client_cert_type_preference: alloc::vec![0u8],
raw_public_key_spki: None,
expected_raw_public_keys: Vec::new(),
preferred_key_exchange_group: None,
#[cfg(feature = "ech")]
ech: None,
#[cfg(feature = "ech")]
ech_server: None,
#[cfg(feature = "cert-compression")]
cert_compression_algorithms: super::cert_compression::default_algorithms(),
cookie_secret: None,
require_cookie: true,
max_record_size: 1200,
key_log: None,
}
}
}
impl Config {
pub fn builder() -> ConfigBuilder {
ConfigBuilder {
inner: Config::default(),
}
}
pub fn is_dtls(&self) -> bool {
matches!(
self.max_version,
ProtocolVersion::DTLSv1_0 | ProtocolVersion::DTLSv1_2 | ProtocolVersion::DTLSv1_3
)
}
pub(crate) fn check_versions(&self) -> Result<(), super::Error> {
let min_dtls = is_dtls(self.min_version);
let max_dtls = is_dtls(self.max_version);
if min_dtls != max_dtls {
return Err(super::Error::InappropriateState);
}
if version_rank(self.min_version) > version_rank(self.max_version) {
return Err(super::Error::InappropriateState);
}
Ok(())
}
}
fn is_dtls(v: ProtocolVersion) -> bool {
matches!(
v,
ProtocolVersion::DTLSv1_0 | ProtocolVersion::DTLSv1_2 | ProtocolVersion::DTLSv1_3
)
}
fn version_rank(v: ProtocolVersion) -> u8 {
match v {
ProtocolVersion::SSLv3 => 1,
ProtocolVersion::TLSv1_0 => 2,
ProtocolVersion::TLSv1_1 => 3,
ProtocolVersion::TLSv1_2 => 4,
ProtocolVersion::TLSv1_3 => 5,
ProtocolVersion::DTLSv1_0 => 2,
ProtocolVersion::DTLSv1_2 => 4,
ProtocolVersion::DTLSv1_3 => 5,
ProtocolVersion::Unknown(_) => 0,
}
}
pub struct ConfigBuilder {
inner: Config,
}
impl ConfigBuilder {
pub fn min_version(mut self, v: ProtocolVersion) -> Self {
self.inner.min_version = v;
self
}
pub fn max_version(mut self, v: ProtocolVersion) -> Self {
self.inner.max_version = v;
self
}
pub fn versions(mut self, min: ProtocolVersion, max: ProtocolVersion) -> Self {
self.inner.min_version = min;
self.inner.max_version = max;
self
}
pub fn dtls(mut self) -> Self {
self.inner.min_version = ProtocolVersion::DTLSv1_2;
self.inner.max_version = ProtocolVersion::DTLSv1_3;
self
}
pub fn tls_only(mut self) -> Self {
self.inner.min_version = ProtocolVersion::TLSv1_2;
self.inner.max_version = ProtocolVersion::TLSv1_3;
self
}
pub fn identity(mut self, chain: Vec<Vec<u8>>, key: SigningKey) -> Self {
self.inner.identity = Some(Identity {
cert_chain: chain,
key,
});
self
}
pub fn roots(mut self, store: RootCertStore) -> Self {
self.inner.roots = store;
self
}
pub fn server_name(mut self, sni: impl Into<String>) -> Self {
self.inner.server_name = Some(sni.into());
self
}
pub fn alpn(mut self, protocols: Vec<Vec<u8>>) -> Self {
self.inner.alpn_protocols = protocols;
self
}
pub fn verify_certificates(mut self, v: bool) -> Self {
self.inner.verify_certificates = v;
self
}
pub fn signature_policy(mut self, p: SignaturePolicy) -> Self {
self.inner.signature_policy = p;
self
}
pub fn crls(mut self, store: CrlStore) -> Self {
self.inner.crls = store;
self
}
pub fn client_auth(mut self, auth: ClientAuth) -> Self {
self.inner.client_auth = Some(auth);
self
}
pub fn cookie_secret(mut self, secret: [u8; 32]) -> Self {
self.inner.cookie_secret = Some(secret);
self.inner.require_cookie = true;
self
}
pub fn no_cookie(mut self) -> Self {
self.inner.require_cookie = false;
self
}
pub fn max_record_size(mut self, n: usize) -> Self {
self.inner.max_record_size = n;
self
}
pub fn stapled_crl(mut self, der: Vec<u8>) -> Self {
self.inner.stapled_crl = Some(der);
self
}
pub fn stapled_ocsp_response(mut self, der: Vec<u8>) -> Self {
self.inner.stapled_ocsp_response = Some(der);
self
}
pub fn ticket_key(mut self, key: [u8; 32]) -> Self {
self.inner.ticket_key = Some(key);
self
}
pub fn max_early_data(mut self, max: u32) -> Self {
self.inner.max_early_data_size = max;
self
}
#[cfg(feature = "std")]
pub fn replay_window(mut self, window: ReplayWindow) -> Self {
self.inner.replay_window = Some(window);
self
}
pub fn record_size_limit(mut self, n: u16) -> Self {
self.inner.record_size_limit = Some(n);
self
}
pub fn require_extended_master_secret(mut self, required: bool) -> Self {
self.inner.require_extended_master_secret = required;
self
}
pub fn server_cert_type_preference(mut self, prefs: Vec<u8>) -> Self {
self.inner.server_cert_type_preference = if prefs.is_empty() {
alloc::vec![0u8]
} else {
prefs
};
self
}
pub fn client_cert_type_preference(mut self, prefs: Vec<u8>) -> Self {
self.inner.client_cert_type_preference = if prefs.is_empty() {
alloc::vec![0u8]
} else {
prefs
};
self
}
pub fn raw_public_key_spki(mut self, spki_der: Vec<u8>) -> Self {
self.inner.raw_public_key_spki = Some(spki_der);
self
}
pub fn add_expected_raw_public_key(mut self, spki_der: Vec<u8>) -> Self {
self.inner.expected_raw_public_keys.push(spki_der);
self
}
pub fn verification_time(mut self, t: Time) -> Self {
self.inner.verification_time = Some(t);
self
}
pub fn preferred_key_exchange_group(mut self, group: NamedGroup) -> Self {
self.inner.preferred_key_exchange_group = Some(group);
self
}
#[cfg(feature = "ech")]
pub fn ech(mut self, ech: super::ech::EchClient) -> Self {
self.inner.ech = Some(ech);
self
}
#[cfg(feature = "ech")]
pub fn ech_server(mut self, ech: super::ech::EchServer) -> Self {
self.inner.ech_server = Some(ech);
self
}
#[cfg(feature = "cert-compression")]
pub fn cert_compression_algorithms(mut self, algorithms: Vec<u16>) -> Self {
self.inner.cert_compression_algorithms = algorithms;
self
}
pub fn key_log(mut self, sink: Arc<dyn KeyLog>) -> Self {
self.inner.key_log = Some(sink);
self
}
pub fn build(self) -> Config {
self.inner
}
}
impl SigningKey {
pub(crate) fn to_server_key_13(&self) -> super::conn::ServerKey {
match self {
SigningKey::Rsa(k) => super::conn::ServerKey::Rsa(k.clone()),
SigningKey::Ecdsa(k) => super::conn::ServerKey::Ecdsa(k.clone()),
SigningKey::Ed25519(k) => super::conn::ServerKey::Ed25519(k.clone()),
SigningKey::MlDsa44(k) => super::conn::ServerKey::MlDsa44(k.clone()),
SigningKey::MlDsa65(k) => super::conn::ServerKey::MlDsa65(k.clone()),
SigningKey::MlDsa87(k) => super::conn::ServerKey::MlDsa87(k.clone()),
}
}
pub(crate) fn try_into_server_config_12(
&self,
chain: Vec<Vec<u8>>,
) -> Option<super::conn::ServerConfig12> {
match self {
SigningKey::Rsa(k) => Some(super::conn::ServerConfig12::with_rsa(chain, k.clone())),
SigningKey::Ecdsa(k) => Some(super::conn::ServerConfig12::with_ecdsa(chain, k.clone())),
_ => None,
}
}
}