Skip to main content

fkm_proxy/utils/
certs.rs

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        // All
168        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}