1use std::{collections::BTreeSet, sync::Arc};
6
7use arc_swap::ArcSwap;
8use fastcrypto::{ed25519::Ed25519PublicKey, traits::ToFromBytes};
9use rustls::{
10 crypto::WebPkiSupportedAlgorithms,
11 pki_types::{
12 CertificateDer, PrivateKeyDer, ServerName, SignatureVerificationAlgorithm, TrustAnchor,
13 UnixTime,
14 },
15};
16
17static SUPPORTED_SIG_ALGS: &[&dyn SignatureVerificationAlgorithm] = &[webpki::ring::ED25519];
18
19static SUPPORTED_ALGORITHMS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms {
20 all: SUPPORTED_SIG_ALGS,
21 mapping: &[(rustls::SignatureScheme::ED25519, SUPPORTED_SIG_ALGS)],
22};
23
24pub trait Allower: std::fmt::Debug + Send + Sync {
30 fn allowed(&self, key: &Ed25519PublicKey) -> bool;
32}
33
34#[derive(Debug, Clone, Default)]
36pub struct AllowAll;
37
38impl Allower for AllowAll {
39 fn allowed(&self, _: &Ed25519PublicKey) -> bool {
40 true
41 }
42}
43
44#[derive(Debug, Clone, Default)]
47pub struct AllowPublicKeys {
48 inner: Arc<ArcSwap<BTreeSet<Ed25519PublicKey>>>,
49}
50
51impl AllowPublicKeys {
52 pub fn new(allowed: BTreeSet<Ed25519PublicKey>) -> Self {
53 Self {
54 inner: Arc::new(ArcSwap::from_pointee(allowed)),
55 }
56 }
57
58 pub fn update(&self, new_allowed: BTreeSet<Ed25519PublicKey>) {
59 self.inner.store(Arc::new(new_allowed));
60 }
61}
62
63impl Allower for AllowPublicKeys {
64 fn allowed(&self, key: &Ed25519PublicKey) -> bool {
65 self.inner.load().contains(key)
66 }
67}
68
69#[derive(Clone, Debug)]
73pub struct ClientCertVerifier<A> {
74 allower: A,
75 name: String,
76}
77
78impl<A> ClientCertVerifier<A> {
79 pub fn new(allower: A, name: String) -> Self {
80 Self { allower, name }
81 }
82}
83
84impl<A: Allower + 'static> ClientCertVerifier<A> {
85 pub fn rustls_server_config(
86 self,
87 certificates: Vec<CertificateDer<'static>>,
88 private_key: PrivateKeyDer<'static>,
89 ) -> Result<rustls::ServerConfig, rustls::Error> {
90 let mut config = rustls::ServerConfig::builder_with_provider(Arc::new(
91 rustls::crypto::ring::default_provider(),
92 ))
93 .with_safe_default_protocol_versions()?
94 .with_client_cert_verifier(std::sync::Arc::new(self))
95 .with_single_cert(certificates, private_key)?;
96 config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
97
98 Ok(config)
99 }
100}
101
102impl<A: Allower> rustls::server::danger::ClientCertVerifier for ClientCertVerifier<A> {
103 fn offer_client_auth(&self) -> bool {
104 true
105 }
106
107 fn client_auth_mandatory(&self) -> bool {
108 true
109 }
110
111 fn root_hint_subjects(&self) -> &[rustls::DistinguishedName] {
112 &[]
115 }
116
117 fn verify_client_cert(
123 &self,
124 end_entity: &CertificateDer,
125 intermediates: &[CertificateDer],
126 now: UnixTime,
127 ) -> Result<rustls::server::danger::ClientCertVerified, rustls::Error> {
128 let public_key = public_key_from_certificate(end_entity)?;
130
131 if !self.allower.allowed(&public_key) {
132 return Err(rustls::Error::General(format!(
133 "invalid certificate: {public_key:?} is not in the validator set",
134 )));
135 }
136
137 verify_self_signed_cert(
139 end_entity,
140 intermediates,
141 webpki::KeyUsage::client_auth(),
142 &self.name,
143 now,
144 )
145 .map(|_| rustls::server::danger::ClientCertVerified::assertion())
146 }
147
148 fn verify_tls12_signature(
149 &self,
150 message: &[u8],
151 cert: &CertificateDer<'_>,
152 dss: &rustls::DigitallySignedStruct,
153 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
154 rustls::crypto::verify_tls12_signature(message, cert, dss, &SUPPORTED_ALGORITHMS)
155 }
156
157 fn verify_tls13_signature(
158 &self,
159 message: &[u8],
160 cert: &CertificateDer<'_>,
161 dss: &rustls::DigitallySignedStruct,
162 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
163 rustls::crypto::verify_tls13_signature(message, cert, dss, &SUPPORTED_ALGORITHMS)
164 }
165
166 fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
167 SUPPORTED_ALGORITHMS.supported_schemes()
168 }
169}
170
171#[derive(Clone, Debug)]
174pub struct ServerCertVerifier {
175 public_key: Ed25519PublicKey,
176 name: String,
177}
178
179impl ServerCertVerifier {
180 pub fn new(public_key: Ed25519PublicKey, name: String) -> Self {
181 Self { public_key, name }
182 }
183
184 pub fn rustls_client_config_with_client_auth(
185 self,
186 certificates: Vec<CertificateDer<'static>>,
187 private_key: PrivateKeyDer<'static>,
188 ) -> Result<rustls::ClientConfig, rustls::Error> {
189 rustls::ClientConfig::builder_with_provider(Arc::new(
190 rustls::crypto::ring::default_provider(),
191 ))
192 .with_safe_default_protocol_versions()?
193 .dangerous()
194 .with_custom_certificate_verifier(std::sync::Arc::new(self))
195 .with_client_auth_cert(certificates, private_key)
196 }
197
198 pub fn rustls_client_config_with_no_client_auth(
199 self,
200 ) -> Result<rustls::ClientConfig, rustls::Error> {
201 Ok(rustls::ClientConfig::builder_with_provider(Arc::new(
202 rustls::crypto::ring::default_provider(),
203 ))
204 .with_safe_default_protocol_versions()?
205 .dangerous()
206 .with_custom_certificate_verifier(std::sync::Arc::new(self))
207 .with_no_client_auth())
208 }
209}
210
211impl rustls::client::danger::ServerCertVerifier for ServerCertVerifier {
212 fn verify_server_cert(
213 &self,
214 end_entity: &CertificateDer<'_>,
215 intermediates: &[CertificateDer<'_>],
216 _server_name: &ServerName,
217 _ocsp_response: &[u8],
218 now: UnixTime,
219 ) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
220 let public_key = public_key_from_certificate(end_entity)?;
221 if public_key != self.public_key {
222 return Err(rustls::Error::General(format!(
223 "invalid certificate: {public_key:?} is not the expected server public key",
224 )));
225 }
226
227 verify_self_signed_cert(
228 end_entity,
229 intermediates,
230 webpki::KeyUsage::server_auth(),
231 &self.name,
232 now,
233 )
234 .map(|_| rustls::client::danger::ServerCertVerified::assertion())
235 }
236
237 fn verify_tls12_signature(
238 &self,
239 message: &[u8],
240 cert: &CertificateDer<'_>,
241 dss: &rustls::DigitallySignedStruct,
242 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
243 rustls::crypto::verify_tls12_signature(message, cert, dss, &SUPPORTED_ALGORITHMS)
244 }
245
246 fn verify_tls13_signature(
247 &self,
248 message: &[u8],
249 cert: &CertificateDer<'_>,
250 dss: &rustls::DigitallySignedStruct,
251 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
252 rustls::crypto::verify_tls13_signature(message, cert, dss, &SUPPORTED_ALGORITHMS)
253 }
254
255 fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
256 SUPPORTED_ALGORITHMS.supported_schemes()
257 }
258}
259
260fn verify_self_signed_cert(
266 end_entity: &CertificateDer,
267 intermediates: &[CertificateDer],
268 usage: webpki::KeyUsage,
269 name: &str,
270 now: UnixTime,
271) -> Result<(), rustls::Error> {
272 let (cert, chain, trustroots) = prepare_for_self_signed(end_entity, intermediates)?;
275
276 let verified_cert = cert
278 .verify_for_usage(
279 SUPPORTED_SIG_ALGS,
280 &trustroots,
281 chain,
282 now,
283 usage,
284 None,
285 None,
286 )
287 .map_err(pki_error)?;
288
289 let subject_name =
291 ServerName::try_from(name).map_err(|_| rustls::Error::UnsupportedNameType)?;
292 verified_cert
293 .end_entity()
294 .verify_is_valid_for_subject_name(&subject_name)
295 .map_err(pki_error)
296}
297
298type CertChainAndRoots<'a> = (
299 webpki::EndEntityCert<'a>,
300 &'a [CertificateDer<'a>],
301 Vec<TrustAnchor<'a>>,
302);
303
304fn prepare_for_self_signed<'a>(
308 end_entity: &'a CertificateDer,
309 intermediates: &'a [CertificateDer],
310) -> Result<CertChainAndRoots<'a>, rustls::Error> {
311 let cert = webpki::EndEntityCert::try_from(end_entity).map_err(pki_error)?;
313
314 let root = webpki::anchor_from_trusted_cert(end_entity).map_err(pki_error)?;
316
317 Ok((cert, intermediates, vec![root]))
318}
319
320fn pki_error(error: webpki::Error) -> rustls::Error {
321 use webpki::Error::*;
322 match error {
323 BadDer | BadDerTime => {
324 rustls::Error::InvalidCertificate(rustls::CertificateError::BadEncoding)
325 }
326 InvalidSignatureForPublicKey
327 | UnsupportedSignatureAlgorithm
328 | UnsupportedSignatureAlgorithmForPublicKey => {
329 rustls::Error::InvalidCertificate(rustls::CertificateError::BadSignature)
330 }
331 CertNotValidForName(_) => {
332 rustls::Error::InvalidCertificate(rustls::CertificateError::NotValidForName)
333 }
334 e => rustls::Error::General(format!("invalid peer certificate: {e}")),
335 }
336}
337
338pub fn public_key_from_certificate(
340 certificate: &CertificateDer,
341) -> Result<Ed25519PublicKey, rustls::Error> {
342 use x509_parser::{certificate::X509Certificate, prelude::FromDer};
343
344 let cert = X509Certificate::from_der(certificate.as_ref())
345 .map_err(|e| rustls::Error::General(e.to_string()))?;
346 let spki = cert.1.public_key();
347 let public_key_bytes =
348 <ed25519::pkcs8::PublicKeyBytes as pkcs8::DecodePublicKey>::from_public_key_der(spki.raw)
349 .map_err(|e| rustls::Error::General(format!("invalid ed25519 public key: {e}")))?;
350
351 let public_key = Ed25519PublicKey::from_bytes(public_key_bytes.as_ref())
352 .map_err(|e| rustls::Error::General(format!("invalid ed25519 public key: {e}")))?;
353 Ok(public_key)
354}