use std::sync::{Arc, Mutex};
use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};
use rustls::pki_types::{CertificateDer, ServerName, UnixTime};
use rustls::{DigitallySignedStruct, Error as TlsError, SignatureScheme};
use crate::identity::{peer_id_from_leaf_cert_der, PeerId};
#[derive(Debug, Default, Clone)]
pub struct CapturedPeerId(pub Arc<Mutex<Option<PeerId>>>);
impl CapturedPeerId {
pub fn get(&self) -> Option<PeerId> {
*self.0.lock().unwrap()
}
}
#[derive(Debug)]
pub struct PeerIdPinningVerifier {
expected: Option<PeerId>,
captured: CapturedPeerId,
defaults: Vec<SignatureScheme>,
}
impl PeerIdPinningVerifier {
pub fn new(expected: Option<PeerId>, captured: CapturedPeerId) -> Self {
PeerIdPinningVerifier {
expected,
captured,
defaults: default_signature_schemes(),
}
}
}
impl ServerCertVerifier for PeerIdPinningVerifier {
fn verify_server_cert(
&self,
end_entity: &CertificateDer<'_>,
_intermediates: &[CertificateDer<'_>],
_server_name: &ServerName<'_>,
_ocsp_response: &[u8],
_now: UnixTime,
) -> Result<ServerCertVerified, TlsError> {
let derived = peer_id_from_leaf_cert_der(end_entity.as_ref()).ok_or_else(|| {
TlsError::General("peer leaf certificate could not be parsed as X.509".to_string())
})?;
*self.captured.0.lock().unwrap() = Some(derived);
if let Some(expected) = self.expected {
if derived != expected {
return Err(TlsError::General(format!(
"peer_id mismatch: expected {expected}, got {derived}"
)));
}
}
Ok(ServerCertVerified::assertion())
}
fn verify_tls12_signature(
&self,
message: &[u8],
cert: &CertificateDer<'_>,
dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, TlsError> {
rustls::crypto::verify_tls12_signature(
message,
cert,
dss,
&rustls::crypto::ring::default_provider().signature_verification_algorithms,
)
}
fn verify_tls13_signature(
&self,
message: &[u8],
cert: &CertificateDer<'_>,
dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, TlsError> {
rustls::crypto::verify_tls13_signature(
message,
cert,
dss,
&rustls::crypto::ring::default_provider().signature_verification_algorithms,
)
}
fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
self.defaults.clone()
}
}
fn default_signature_schemes() -> Vec<SignatureScheme> {
rustls::crypto::ring::default_provider()
.signature_verification_algorithms
.supported_schemes()
}