use cfg_if::cfg_if;
use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};
use rustls::crypto::ring::cipher_suite::{
TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384, TLS13_CHACHA20_POLY1305_SHA256,
};
use rustls::crypto::{
WebPkiSupportedAlgorithms, ring as provider, verify_tls13_signature_with_raw_key,
};
use rustls::server::danger::{ClientCertVerified, ClientCertVerifier};
use rustls::{
CertificateError, DigitallySignedStruct, DistinguishedName, Error, PeerIncompatible,
SignatureScheme, SupportedCipherSuite,
};
use rustls_pki_types::{CertificateDer, ServerName, SubjectPublicKeyInfoDer, UnixTime};
use tracing::debug;
#[derive(Debug)]
pub(crate) struct SimpleRpkClientCertVerifier {
trusted_spki: Vec<SubjectPublicKeyInfoDer<'static>>,
supported_algs: WebPkiSupportedAlgorithms,
}
impl SimpleRpkClientCertVerifier {
pub(crate) fn new(trusted_spki: Vec<SubjectPublicKeyInfoDer<'static>>) -> Self {
Self {
trusted_spki,
supported_algs: provider::default_provider().signature_verification_algorithms,
}
}
}
impl ClientCertVerifier for SimpleRpkClientCertVerifier {
fn root_hint_subjects(&self) -> &[DistinguishedName] {
&[]
}
fn verify_client_cert(
&self,
end_entity: &CertificateDer<'_>,
_intermediates: &[CertificateDer<'_>],
_now: UnixTime,
) -> Result<ClientCertVerified, Error> {
let end_entity_as_spki = SubjectPublicKeyInfoDer::from(end_entity.as_ref());
if self.trusted_spki.contains(&end_entity_as_spki) {
Ok(ClientCertVerified::assertion())
} else {
Err(Error::InvalidCertificate(CertificateError::UnknownIssuer))
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
fn verify_tls12_signature(
&self,
_message: &[u8],
_cert: &CertificateDer<'_>,
_dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, Error> {
Err(Error::PeerIncompatible(PeerIncompatible::Tls12NotOffered))
}
fn verify_tls13_signature(
&self,
message: &[u8],
cert: &CertificateDer<'_>,
dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, Error> {
verify_tls13_signature_with_raw_key(
message,
&SubjectPublicKeyInfoDer::from(cert.as_ref()),
dss,
&self.supported_algs,
)
}
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
self.supported_algs.supported_schemes()
}
fn requires_raw_public_keys(&self) -> bool {
true
}
}
#[derive(Debug)]
pub(crate) struct SimpleRpkServerCertVerifier {
trusted_spki: Vec<SubjectPublicKeyInfoDer<'static>>,
supported_algs: WebPkiSupportedAlgorithms,
}
impl SimpleRpkServerCertVerifier {
pub(crate) fn new(trusted_spki: Vec<SubjectPublicKeyInfoDer<'static>>) -> Self {
Self {
trusted_spki,
supported_algs: provider::default_provider().signature_verification_algorithms,
}
}
}
impl ServerCertVerifier for SimpleRpkServerCertVerifier {
fn verify_server_cert(
&self,
end_entity: &CertificateDer<'_>,
_intermediates: &[CertificateDer<'_>],
_server_name: &ServerName<'_>,
_ocsp_response: &[u8],
_now: UnixTime,
) -> Result<ServerCertVerified, Error> {
let end_entity_as_spki = SubjectPublicKeyInfoDer::from(end_entity.as_ref());
if self.trusted_spki.contains(&end_entity_as_spki) {
Ok(ServerCertVerified::assertion())
} else {
Err(Error::InvalidCertificate(CertificateError::UnknownIssuer))
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
fn verify_tls12_signature(
&self,
_message: &[u8],
_cert: &CertificateDer<'_>,
_dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, Error> {
Err(Error::PeerIncompatible(PeerIncompatible::Tls12NotOffered))
}
fn verify_tls13_signature(
&self,
message: &[u8],
cert: &CertificateDer<'_>,
dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, Error> {
verify_tls13_signature_with_raw_key(
message,
&SubjectPublicKeyInfoDer::from(cert.as_ref()),
dss,
&self.supported_algs,
)
}
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
self.supported_algs.supported_schemes()
}
fn requires_raw_public_keys(&self) -> bool {
true
}
}
pub const CIPHER_SUITES_FORCE_AES256: &[SupportedCipherSuite] =
&[TLS13_AES_256_GCM_SHA384, TLS13_AES_128_GCM_SHA256];
pub const CIPHER_SUITES_DEFAULT: &[SupportedCipherSuite] = &[
TLS13_AES_128_GCM_SHA256,
TLS13_AES_256_GCM_SHA384,
TLS13_CHACHA20_POLY1305_SHA256,
];
pub const CIPHER_SUITES_NO_AES_HW: &[SupportedCipherSuite] = &[
TLS13_CHACHA20_POLY1305_SHA256,
TLS13_AES_128_GCM_SHA256,
TLS13_AES_256_GCM_SHA384,
];
pub fn select_cipher_suites(force_aes256: bool) -> &'static [SupportedCipherSuite] {
if force_aes256 {
debug!(
"AES256 cipher suite mode selected: using suites {:?}",
CIPHER_SUITES_FORCE_AES256
);
CIPHER_SUITES_FORCE_AES256
} else if cpu_supports_aes() {
debug!(
"AES hardware support detected, using default TLS1.3 cipher suites {:?}",
CIPHER_SUITES_DEFAULT
);
CIPHER_SUITES_DEFAULT
} else {
debug!(
"No AES support detected on CPU. Selecting alternate TLS1.3 cipher suites {:?}",
CIPHER_SUITES_NO_AES_HW
);
CIPHER_SUITES_NO_AES_HW
}
}
#[must_use]
pub fn ignore_client_order(force_aes256: bool) -> bool {
force_aes256 || !cpu_supports_aes()
}
#[must_use]
pub fn cpu_supports_aes() -> bool {
cfg_if! {
if #[cfg(target_arch = "x86_64")] {
std::arch::is_x86_feature_detected!("aes") && std::arch::is_x86_feature_detected!("pclmulqdq")
} else if #[cfg(target_arch = "aarch64")] {
std::arch::is_aarch64_feature_detected!("aes") && std::arch::is_aarch64_feature_detected!("pmull")
} else {
debug!("target arch feature autodetection is not supported on {}; assuming no AES support", std::env::consts::ARCH);
false
}
}
}