use std::sync::Arc;
use foctet_core::id::NodeId;
use rustls::{
client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
crypto::ring::cipher_suite::{
TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384, TLS13_CHACHA20_POLY1305_SHA256,
},
pki_types::{CertificateDer, ServerName, UnixTime},
server::danger::{ClientCertVerified, ClientCertVerifier},
CertificateError, DigitallySignedStruct, DistinguishedName, OtherError, SignatureScheme,
SupportedCipherSuite, SupportedProtocolVersion,
};
use crate::tls::cert;
pub(crate) static PROTOCOL_VERSIONS: &[&SupportedProtocolVersion] = &[&rustls::version::TLS13];
pub(crate) static CIPHERSUITES: &[SupportedCipherSuite] = &[
TLS13_CHACHA20_POLY1305_SHA256,
TLS13_AES_256_GCM_SHA384,
TLS13_AES_128_GCM_SHA256,
];
#[derive(Debug)]
pub(crate) struct FoctetCertificateVerifier {
remote_node_id: Option<NodeId>,
}
impl FoctetCertificateVerifier {
pub(crate) fn new() -> Self {
Self {
remote_node_id: None,
}
}
pub(crate) fn with_remote_node_id(remote_node_id: Option<NodeId>) -> Self {
Self { remote_node_id }
}
fn verification_schemes() -> Vec<SignatureScheme> {
vec![
SignatureScheme::ECDSA_NISTP384_SHA384,
SignatureScheme::ECDSA_NISTP256_SHA256,
SignatureScheme::ED25519,
SignatureScheme::RSA_PSS_SHA512,
SignatureScheme::RSA_PSS_SHA384,
SignatureScheme::RSA_PSS_SHA256,
SignatureScheme::RSA_PKCS1_SHA512,
SignatureScheme::RSA_PKCS1_SHA384,
SignatureScheme::RSA_PKCS1_SHA256,
]
}
}
impl ServerCertVerifier for FoctetCertificateVerifier {
fn verify_server_cert(
&self,
end_entity: &CertificateDer,
intermediates: &[CertificateDer],
_server_name: &rustls::pki_types::ServerName,
_ocsp_response: &[u8],
_now: rustls::pki_types::UnixTime,
) -> Result<ServerCertVerified, rustls::Error> {
let node_id = verify_presented_certs(end_entity, intermediates)?;
if let Some(remote_node_id) = self.remote_node_id {
if remote_node_id != node_id {
return Err(rustls::Error::InvalidCertificate(
CertificateError::ApplicationVerificationFailure,
));
}
}
Ok(ServerCertVerified::assertion())
}
fn verify_tls12_signature(
&self,
_message: &[u8],
_cert: &CertificateDer,
_dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, rustls::Error> {
unreachable!("`PROTOCOL_VERSIONS` only allows TLS 1.3")
}
fn verify_tls13_signature(
&self,
message: &[u8],
cert: &CertificateDer,
dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, rustls::Error> {
verify_tls13_signature(cert, dss.scheme, message, dss.signature())
}
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
Self::verification_schemes()
}
}
impl ClientCertVerifier for FoctetCertificateVerifier {
fn offer_client_auth(&self) -> bool {
true
}
fn root_hint_subjects(&self) -> &[DistinguishedName] {
&[]
}
fn verify_client_cert(
&self,
end_entity: &CertificateDer,
intermediates: &[CertificateDer],
_now: rustls::pki_types::UnixTime,
) -> Result<ClientCertVerified, rustls::Error> {
verify_presented_certs(end_entity, intermediates)?;
Ok(ClientCertVerified::assertion())
}
fn verify_tls12_signature(
&self,
_message: &[u8],
_cert: &CertificateDer,
_dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, rustls::Error> {
unreachable!("`PROTOCOL_VERSIONS` only allows TLS 1.3")
}
fn verify_tls13_signature(
&self,
message: &[u8],
cert: &CertificateDer,
dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, rustls::Error> {
verify_tls13_signature(cert, dss.scheme, message, dss.signature())
}
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
Self::verification_schemes()
}
}
fn verify_presented_certs(
end_entity: &CertificateDer,
intermediates: &[CertificateDer],
) -> Result<NodeId, rustls::Error> {
if !intermediates.is_empty() {
return Err(rustls::Error::General(
"foctet-tls requires exactly one certificate".into(),
));
}
let cert = match cert::parse(end_entity) {
Ok(cert) => cert,
Err(_) => {
return Err(rustls::Error::InvalidCertificate(
CertificateError::BadEncoding,
))
}
};
Ok(cert.node_id())
}
fn verify_tls13_signature(
cert: &CertificateDer,
signature_scheme: SignatureScheme,
message: &[u8],
signature: &[u8],
) -> Result<HandshakeSignatureValid, rustls::Error> {
match cert::parse(cert)?.verify_signature(signature_scheme, message, signature) {
Ok(()) => {}
Err(_) => {
return Err(rustls::Error::InvalidCertificate(
CertificateError::BadSignature,
))
}
}
Ok(HandshakeSignatureValid::assertion())
}
impl From<cert::ParseError> for rustls::Error {
fn from(cert::ParseError(e): cert::ParseError) -> Self {
use webpki::Error::*;
match e {
BadDer => rustls::Error::InvalidCertificate(CertificateError::BadEncoding),
e => {
rustls::Error::InvalidCertificate(CertificateError::Other(OtherError(Arc::new(e))))
}
}
}
}
impl From<cert::VerificationError> for rustls::Error {
fn from(cert::VerificationError(e): cert::VerificationError) -> Self {
use webpki::Error::*;
match e {
InvalidSignatureForPublicKey => {
rustls::Error::InvalidCertificate(CertificateError::BadSignature)
}
other => rustls::Error::InvalidCertificate(CertificateError::Other(OtherError(
Arc::new(other),
))),
}
}
}
#[derive(Debug)]
pub struct SkipServerVerification(Arc<rustls::crypto::CryptoProvider>);
impl SkipServerVerification {
#[allow(dead_code)]
pub fn new() -> Arc<Self> {
Arc::new(Self(Arc::new(rustls::crypto::ring::default_provider())))
}
}
impl ServerCertVerifier for SkipServerVerification {
fn verify_server_cert(
&self,
_end_entity: &CertificateDer<'_>,
_intermediates: &[CertificateDer<'_>],
_server_name: &ServerName<'_>,
_ocsp: &[u8],
_now: UnixTime,
) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
Ok(rustls::client::danger::ServerCertVerified::assertion())
}
fn verify_tls12_signature(
&self,
message: &[u8],
cert: &CertificateDer<'_>,
dss: &rustls::DigitallySignedStruct,
) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
rustls::crypto::verify_tls12_signature(
message,
cert,
dss,
&self.0.signature_verification_algorithms,
)
}
fn verify_tls13_signature(
&self,
message: &[u8],
cert: &CertificateDer<'_>,
dss: &rustls::DigitallySignedStruct,
) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
rustls::crypto::verify_tls13_signature(
message,
cert,
dss,
&self.0.signature_verification_algorithms,
)
}
fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
self.0.signature_verification_algorithms.supported_schemes()
}
}