snap_tun/
cert_validator.rs1use anapaya_quinn::rustls::{self, client::danger::ServerCertVerified};
17use x509_cert::{Certificate, der::Decode, spki::ObjectIdentifier};
18
19#[derive(Debug)]
29pub struct Ed25519ServerCertValidator(pub [u8; 32]);
30
31const ED25519_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.101.112");
33
34impl rustls::client::danger::ServerCertVerifier for Ed25519ServerCertValidator {
35 fn verify_server_cert(
36 &self,
37 end_entity: &rustls::pki_types::CertificateDer<'_>,
38 _intermediates: &[rustls::pki_types::CertificateDer<'_>],
39 _server_name: &rustls::pki_types::ServerName<'_>,
40 _ocsp_response: &[u8],
41 _now: rustls::pki_types::UnixTime,
42 ) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
43 verify_ed25519_public_key(&self.0, end_entity)
44 }
45
46 fn verify_tls12_signature(
47 &self,
48 _message: &[u8],
49 _cert: &rustls::pki_types::CertificateDer<'_>,
50 _dss: &rustls::DigitallySignedStruct,
51 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
52 Err(rustls::Error::PeerIncompatible(
53 rustls::PeerIncompatible::Tls12NotOffered,
54 ))
55 }
56
57 fn verify_tls13_signature(
58 &self,
59 message: &[u8],
60 cert: &rustls::pki_types::CertificateDer<'_>,
61 dss: &rustls::DigitallySignedStruct,
62 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
63 let provider = rustls::crypto::ring::default_provider();
64 let all_algs = provider.signature_verification_algorithms;
65
66 if dss.scheme != rustls::SignatureScheme::ED25519 {
67 return Err(rustls::Error::PeerIncompatible(
68 rustls::PeerIncompatible::NoSignatureSchemesInCommon,
69 ));
70 }
71
72 rustls::crypto::verify_tls13_signature(message, cert, dss, &all_algs)
73 }
74
75 fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
76 vec![rustls::SignatureScheme::ED25519]
77 }
78}
79
80fn verify_ed25519_public_key(
81 expected_pubkey: &[u8; 32],
82 end_entity: &[u8],
83) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
84 let certificate = Certificate::from_der(end_entity)
85 .map_err(|e| rustls::Error::General(format!("failed to parse certificate: {e}")))?;
86 let spki = &certificate.tbs_certificate.subject_public_key_info;
87
88 if spki.algorithm.oid != ED25519_OID {
89 return Err(rustls::Error::General(
90 "server's public key algorithm is not Ed25519.".to_string(),
91 ));
92 }
93
94 let public_key_bytes = match spki.subject_public_key.as_bytes() {
95 Some(bytes) => bytes,
96 None => {
97 return Err(rustls::Error::General(
98 "failed to extract public key bytes from certificate.".to_string(),
99 ));
100 }
101 };
102
103 if expected_pubkey.as_slice() != public_key_bytes {
104 return Err(rustls::Error::General(
105 "server's public key did not match the expected pinned public key.".to_string(),
106 ));
107 }
108 Ok(ServerCertVerified::assertion())
109}
110
111#[cfg(test)]
112mod tests {
113 use anapaya_quinn::rustls::pki_types::CertificateDer;
114 use ed25519_dalek::pkcs8::EncodePrivateKey;
115
116 use super::verify_ed25519_public_key;
117
118 #[test]
119 fn verify_ed25519_certificate_succeeds() {
120 let seed = [84u8; 32];
121 let dalek_keypair = ed25519_dalek::SigningKey::from_bytes(&seed);
122
123 let expected_pubkey = *dalek_keypair.verifying_key().as_bytes();
124
125 let kp = ed25519_dalek::pkcs8::KeypairBytes {
126 secret_key: *dalek_keypair.as_bytes(),
127 public_key: Some(ed25519_dalek::pkcs8::PublicKeyBytes(
128 *dalek_keypair.verifying_key().as_bytes(),
129 )),
130 };
131 let pkcs8 = kp.to_pkcs8_der().unwrap();
132 let pem = pem::Pem::new("PRIVATE KEY", pkcs8.as_bytes());
133 let pem_str = pem::encode(&pem);
134 let key_pair = rcgen::KeyPair::from_pem(&pem_str).unwrap();
135
136 let cert = rcgen::CertificateParams::new(vec!["test".into()])
138 .unwrap()
139 .self_signed(&key_pair)
140 .unwrap();
141
142 let cert_der = CertificateDer::from(cert.der().to_vec());
143
144 assert!(verify_ed25519_public_key(&expected_pubkey, &cert_der).is_ok());
145 }
146}