1use anyhow::Result;
2use rustls::{
3 client::danger::{ServerCertVerified, ServerCertVerifier},
4 pki_types::{CertificateDer, PrivateKeyDer, ServerName, UnixTime},
5};
6use std::{fs::File, io::BufReader, path::Path, sync::Arc};
7
8pub fn load_certs(path: &Path) -> Result<Vec<CertificateDer<'static>>> {
9 if !path.exists() {
10 return Err(anyhow::anyhow!("Cert not found in path: {path:?}"));
11 }
12
13 rustls_pemfile::certs(&mut BufReader::new(File::open(path)?))
14 .collect::<std::io::Result<_>>()
15 .map_err(anyhow::Error::from)
16}
17
18pub fn load_keys(path: &Path) -> Result<PrivateKeyDer<'static>> {
19 if !path.exists() {
20 return Err(anyhow::anyhow!("Private key not found in path: {path:?}"));
21 }
22
23 rustls_pemfile::private_key(&mut BufReader::new(File::open(path)?))?
24 .ok_or_else(|| anyhow::anyhow!("Private key returned None"))
25}
26
27pub fn cert_from_str(cert: &str) -> Result<Vec<CertificateDer<'static>>> {
28 rustls_pemfile::certs(&mut cert.as_bytes())
29 .collect::<std::io::Result<_>>()
30 .map_err(anyhow::Error::from)
31}
32
33pub fn key_from_str(key: &str) -> Result<PrivateKeyDer<'static>> {
34 rustls_pemfile::private_key(&mut key.as_bytes())?
35 .ok_or_else(|| anyhow::anyhow!("Private ket returned None"))
36}
37
38pub fn compute_fingerprint(cert: &CertificateDer<'_>) -> String {
39 let hash = ring::digest::digest(&ring::digest::SHA256, cert.as_ref());
40 hash.as_ref().iter().map(|b| format!("{b:02x}")).collect()
41}
42
43#[derive(Debug)]
44pub struct FingerprintVerifier {
45 expected: String,
46 provider: Arc<rustls::crypto::CryptoProvider>,
47}
48
49impl FingerprintVerifier {
50 pub fn new(fingerprint: &str) -> Result<Arc<Self>> {
51 let normalized = fingerprint.to_lowercase().replace([':', ' '], "");
52
53 if normalized.len() != 64 || !normalized.chars().all(|c| c.is_ascii_hexdigit()) {
54 return Err(anyhow::anyhow!(
55 "Invalid server fingerprint: must be a 64-character hex SHA-256 digest \
56 (colons/spaces are accepted). Got {normalized:?}"
57 ));
58 }
59
60 Ok(Arc::new(Self {
61 expected: normalized,
62 provider: Arc::new(rustls::crypto::ring::default_provider()),
63 }))
64 }
65
66 fn check(&self, cert: &CertificateDer<'_>) -> Result<(), rustls::Error> {
67 let got = compute_fingerprint(cert);
68 if got == self.expected {
69 Ok(())
70 } else {
71 Err(rustls::Error::General(format!(
72 "TLS certificate fingerprint mismatch: expected {}, got {got}",
73 self.expected,
74 )))
75 }
76 }
77}
78
79impl rustls::client::danger::ServerCertVerifier for FingerprintVerifier {
80 fn verify_server_cert(
81 &self,
82 end_entity: &CertificateDer<'_>,
83 _intermediates: &[CertificateDer<'_>],
84 _server_name: &ServerName<'_>,
85 _ocsp_response: &[u8],
86 _now: UnixTime,
87 ) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
88 self.check(end_entity)?;
89 Ok(rustls::client::danger::ServerCertVerified::assertion())
90 }
91
92 fn verify_tls12_signature(
93 &self,
94 message: &[u8],
95 cert: &CertificateDer<'_>,
96 dss: &rustls::DigitallySignedStruct,
97 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
98 rustls::crypto::verify_tls12_signature(
99 message,
100 cert,
101 dss,
102 &self.provider.signature_verification_algorithms,
103 )
104 }
105
106 fn verify_tls13_signature(
107 &self,
108 message: &[u8],
109 cert: &CertificateDer<'_>,
110 dss: &rustls::DigitallySignedStruct,
111 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
112 rustls::crypto::verify_tls13_signature(
113 message,
114 cert,
115 dss,
116 &self.provider.signature_verification_algorithms,
117 )
118 }
119
120 fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
121 self.provider
122 .signature_verification_algorithms
123 .supported_schemes()
124 }
125}
126
127#[derive(Debug)]
128pub struct NoCertVerification;
129impl ServerCertVerifier for NoCertVerification {
130 fn verify_server_cert(
131 &self,
132 _end_entity: &tokio_rustls::rustls::pki_types::CertificateDer<'_>,
133 _intermediates: &[tokio_rustls::rustls::pki_types::CertificateDer<'_>],
134 _server_name: &tokio_rustls::rustls::pki_types::ServerName<'_>,
135 _ocsp_response: &[u8],
136 _now: tokio_rustls::rustls::pki_types::UnixTime,
137 ) -> Result<tokio_rustls::rustls::client::danger::ServerCertVerified, tokio_rustls::rustls::Error>
138 {
139 Ok(ServerCertVerified::assertion())
140 }
141
142 fn verify_tls12_signature(
143 &self,
144 _message: &[u8],
145 _cert: &tokio_rustls::rustls::pki_types::CertificateDer<'_>,
146 _dss: &tokio_rustls::rustls::DigitallySignedStruct,
147 ) -> Result<
148 tokio_rustls::rustls::client::danger::HandshakeSignatureValid,
149 tokio_rustls::rustls::Error,
150 > {
151 Ok(tokio_rustls::rustls::client::danger::HandshakeSignatureValid::assertion())
152 }
153
154 fn verify_tls13_signature(
155 &self,
156 _message: &[u8],
157 _cert: &tokio_rustls::rustls::pki_types::CertificateDer<'_>,
158 _dss: &tokio_rustls::rustls::DigitallySignedStruct,
159 ) -> Result<
160 tokio_rustls::rustls::client::danger::HandshakeSignatureValid,
161 tokio_rustls::rustls::Error,
162 > {
163 Ok(tokio_rustls::rustls::client::danger::HandshakeSignatureValid::assertion())
164 }
165
166 fn supported_verify_schemes(&self) -> Vec<tokio_rustls::rustls::SignatureScheme> {
167 vec![
169 tokio_rustls::rustls::SignatureScheme::RSA_PKCS1_SHA1,
170 tokio_rustls::rustls::SignatureScheme::RSA_PKCS1_SHA256,
171 tokio_rustls::rustls::SignatureScheme::ECDSA_NISTP256_SHA256,
172 tokio_rustls::rustls::SignatureScheme::RSA_PKCS1_SHA384,
173 tokio_rustls::rustls::SignatureScheme::ECDSA_NISTP384_SHA384,
174 tokio_rustls::rustls::SignatureScheme::RSA_PKCS1_SHA512,
175 tokio_rustls::rustls::SignatureScheme::ECDSA_NISTP521_SHA512,
176 tokio_rustls::rustls::SignatureScheme::RSA_PSS_SHA256,
177 tokio_rustls::rustls::SignatureScheme::RSA_PSS_SHA384,
178 tokio_rustls::rustls::SignatureScheme::RSA_PSS_SHA512,
179 tokio_rustls::rustls::SignatureScheme::ED25519,
180 tokio_rustls::rustls::SignatureScheme::ED448,
181 ]
182 }
183}
184
185#[derive(Debug)]
186pub struct SkipQuicServerVerification(Arc<rustls::crypto::CryptoProvider>);
187impl SkipQuicServerVerification {
188 pub fn new() -> Arc<Self> {
189 Arc::new(Self(Arc::new(rustls::crypto::ring::default_provider())))
190 }
191}
192
193impl rustls::client::danger::ServerCertVerifier for SkipQuicServerVerification {
194 fn verify_server_cert(
195 &self,
196 _end_entity: &CertificateDer<'_>,
197 _intermediates: &[CertificateDer<'_>],
198 _server_name: &ServerName<'_>,
199 _ocsp: &[u8],
200 _now: UnixTime,
201 ) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
202 Ok(rustls::client::danger::ServerCertVerified::assertion())
203 }
204
205 fn verify_tls12_signature(
206 &self,
207 message: &[u8],
208 cert: &CertificateDer<'_>,
209 dss: &rustls::DigitallySignedStruct,
210 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
211 rustls::crypto::verify_tls12_signature(
212 message,
213 cert,
214 dss,
215 &self.0.signature_verification_algorithms,
216 )
217 }
218
219 fn verify_tls13_signature(
220 &self,
221 message: &[u8],
222 cert: &CertificateDer<'_>,
223 dss: &rustls::DigitallySignedStruct,
224 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
225 rustls::crypto::verify_tls13_signature(
226 message,
227 cert,
228 dss,
229 &self.0.signature_verification_algorithms,
230 )
231 }
232
233 fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
234 self.0.signature_verification_algorithms.supported_schemes()
235 }
236}