use ed25519_dalek::pkcs8::EncodePublicKey;
use iroh_base::PublicKey;
use rustls::{
CertificateError, DigitallySignedStruct, DistinguishedName, SignatureScheme,
SupportedProtocolVersion,
client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
crypto::{WebPkiSupportedAlgorithms, verify_tls13_signature_with_raw_key},
pki_types::CertificateDer as Certificate,
server::danger::{ClientCertVerified, ClientCertVerifier},
};
use webpki::ring as webpki_algs;
use webpki_types::SubjectPublicKeyInfoDer;
pub(super) static PROTOCOL_VERSIONS: &[&SupportedProtocolVersion] = &[&rustls::version::TLS13];
static SUPPORTED_SIG_ALGS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms {
all: &[
webpki_algs::ECDSA_P256_SHA256,
webpki_algs::ECDSA_P256_SHA384,
webpki_algs::ECDSA_P384_SHA256,
webpki_algs::ECDSA_P384_SHA384,
webpki_algs::ED25519,
],
mapping: &[
(
SignatureScheme::ECDSA_NISTP384_SHA384,
&[
webpki_algs::ECDSA_P384_SHA384,
webpki_algs::ECDSA_P256_SHA384,
],
),
(
SignatureScheme::ECDSA_NISTP256_SHA256,
&[
webpki_algs::ECDSA_P256_SHA256,
webpki_algs::ECDSA_P384_SHA256,
],
),
(SignatureScheme::ED25519, &[webpki_algs::ED25519]),
],
};
#[derive(Default, Debug)]
pub(super) struct ServerCertificateVerifier;
fn public_key_to_spki(remote_peer_id: &PublicKey) -> SubjectPublicKeyInfoDer<'static> {
let der_key = remote_peer_id
.as_verifying_key()
.to_public_key_der()
.expect("valid key");
SubjectPublicKeyInfoDer::from(der_key.into_vec())
}
impl ServerCertVerifier for ServerCertificateVerifier {
fn verify_server_cert(
&self,
end_entity: &Certificate,
intermediates: &[Certificate],
server_name: &rustls::pki_types::ServerName,
_ocsp_response: &[u8],
_now: rustls::pki_types::UnixTime,
) -> Result<ServerCertVerified, rustls::Error> {
let rustls::pki_types::ServerName::DnsName(dns_name) = server_name else {
return Err(rustls::Error::UnsupportedNameType);
};
let Some(remote_peer_id) = super::name::decode(dns_name.as_ref()) else {
return Err(rustls::Error::InvalidCertificate(
CertificateError::NotValidForName,
));
};
if !intermediates.is_empty() {
return Err(rustls::Error::InvalidCertificate(
CertificateError::UnknownIssuer,
));
}
let end_entity_as_spki = SubjectPublicKeyInfoDer::from(end_entity.as_ref());
if public_key_to_spki(&remote_peer_id) != end_entity_as_spki {
return Err(rustls::Error::InvalidCertificate(
CertificateError::UnknownIssuer,
));
}
Ok(ServerCertVerified::assertion())
}
fn verify_tls12_signature(
&self,
_message: &[u8],
_cert: &Certificate,
_dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, rustls::Error> {
Err(rustls::Error::PeerIncompatible(
rustls::PeerIncompatible::Tls12NotOffered,
))
}
fn verify_tls13_signature(
&self,
message: &[u8],
cert: &Certificate,
dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, rustls::Error> {
verify_tls13_signature_with_raw_key(
message,
&SubjectPublicKeyInfoDer::from(cert.as_ref()),
dss,
&SUPPORTED_SIG_ALGS,
)
}
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
SUPPORTED_SIG_ALGS.supported_schemes()
}
fn requires_raw_public_keys(&self) -> bool {
true
}
}
#[derive(Default, Debug)]
pub(super) struct ClientCertificateVerifier;
impl ClientCertVerifier for ClientCertificateVerifier {
fn offer_client_auth(&self) -> bool {
true
}
fn verify_client_cert(
&self,
_end_entity: &Certificate,
intermediates: &[Certificate],
_now: rustls::pki_types::UnixTime,
) -> Result<ClientCertVerified, rustls::Error> {
if !intermediates.is_empty() {
return Err(rustls::Error::InvalidCertificate(
CertificateError::UnknownIssuer,
));
}
Ok(ClientCertVerified::assertion())
}
fn verify_tls12_signature(
&self,
_message: &[u8],
_cert: &Certificate,
_dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, rustls::Error> {
Err(rustls::Error::PeerIncompatible(
rustls::PeerIncompatible::Tls12NotOffered,
))
}
fn verify_tls13_signature(
&self,
message: &[u8],
cert: &Certificate,
dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, rustls::Error> {
verify_tls13_signature_with_raw_key(
message,
&SubjectPublicKeyInfoDer::from(cert.as_ref()),
dss,
&SUPPORTED_SIG_ALGS,
)
}
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
SUPPORTED_SIG_ALGS.supported_schemes()
}
fn root_hint_subjects(&self) -> &[DistinguishedName] {
&[][..]
}
fn requires_raw_public_keys(&self) -> bool {
true
}
}