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_protocol_versions(&[&rustls::version::TLS13])?
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 if !intermediates.is_empty() {
130 return Err(rustls::Error::General(format!(
131 "invalid certificate chain: expected one certificate, got {}",
132 intermediates.len() + 1
133 )));
134 }
135
136 let public_key = public_key_from_certificate(end_entity)?;
138
139 if !self.allower.allowed(&public_key) {
140 return Err(rustls::Error::General(format!(
141 "invalid certificate: {public_key:?} is not in the validator set",
142 )));
143 }
144
145 verify_self_signed_cert(
147 end_entity,
148 intermediates,
149 webpki::KeyUsage::client_auth(),
150 &self.name,
151 now,
152 )
153 .map(|_| rustls::server::danger::ClientCertVerified::assertion())
154 }
155
156 fn verify_tls12_signature(
157 &self,
158 message: &[u8],
159 cert: &CertificateDer<'_>,
160 dss: &rustls::DigitallySignedStruct,
161 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
162 rustls::crypto::verify_tls12_signature(message, cert, dss, &SUPPORTED_ALGORITHMS)
163 }
164
165 fn verify_tls13_signature(
166 &self,
167 message: &[u8],
168 cert: &CertificateDer<'_>,
169 dss: &rustls::DigitallySignedStruct,
170 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
171 rustls::crypto::verify_tls13_signature(message, cert, dss, &SUPPORTED_ALGORITHMS)
172 }
173
174 fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
175 SUPPORTED_ALGORITHMS.supported_schemes()
176 }
177}
178
179#[derive(Clone, Debug)]
182pub struct ServerCertVerifier {
183 public_key: Ed25519PublicKey,
184 name: String,
185}
186
187impl ServerCertVerifier {
188 pub fn new(public_key: Ed25519PublicKey, name: String) -> Self {
189 Self { public_key, name }
190 }
191
192 pub fn rustls_client_config_with_client_auth(
193 self,
194 certificates: Vec<CertificateDer<'static>>,
195 private_key: PrivateKeyDer<'static>,
196 ) -> Result<rustls::ClientConfig, rustls::Error> {
197 rustls::ClientConfig::builder_with_provider(Arc::new(
198 rustls::crypto::ring::default_provider(),
199 ))
200 .with_protocol_versions(&[&rustls::version::TLS13])?
201 .dangerous()
202 .with_custom_certificate_verifier(std::sync::Arc::new(self))
203 .with_client_auth_cert(certificates, private_key)
204 }
205
206 pub fn rustls_client_config_with_no_client_auth(
207 self,
208 ) -> Result<rustls::ClientConfig, rustls::Error> {
209 Ok(rustls::ClientConfig::builder_with_provider(Arc::new(
210 rustls::crypto::ring::default_provider(),
211 ))
212 .with_protocol_versions(&[&rustls::version::TLS13])?
213 .dangerous()
214 .with_custom_certificate_verifier(std::sync::Arc::new(self))
215 .with_no_client_auth())
216 }
217}
218
219impl rustls::client::danger::ServerCertVerifier for ServerCertVerifier {
220 fn verify_server_cert(
221 &self,
222 end_entity: &CertificateDer<'_>,
223 intermediates: &[CertificateDer<'_>],
224 _server_name: &ServerName,
225 _ocsp_response: &[u8],
226 now: UnixTime,
227 ) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
228 let public_key = public_key_from_certificate(end_entity)?;
229 if public_key != self.public_key {
230 return Err(rustls::Error::General(format!(
231 "invalid certificate: {public_key:?} is not the expected server public key",
232 )));
233 }
234
235 verify_self_signed_cert(
236 end_entity,
237 intermediates,
238 webpki::KeyUsage::server_auth(),
239 &self.name,
240 now,
241 )
242 .map(|_| rustls::client::danger::ServerCertVerified::assertion())
243 }
244
245 fn verify_tls12_signature(
246 &self,
247 message: &[u8],
248 cert: &CertificateDer<'_>,
249 dss: &rustls::DigitallySignedStruct,
250 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
251 rustls::crypto::verify_tls12_signature(message, cert, dss, &SUPPORTED_ALGORITHMS)
252 }
253
254 fn verify_tls13_signature(
255 &self,
256 message: &[u8],
257 cert: &CertificateDer<'_>,
258 dss: &rustls::DigitallySignedStruct,
259 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
260 rustls::crypto::verify_tls13_signature(message, cert, dss, &SUPPORTED_ALGORITHMS)
261 }
262
263 fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
264 SUPPORTED_ALGORITHMS.supported_schemes()
265 }
266}
267
268fn verify_self_signed_cert(
274 end_entity: &CertificateDer,
275 intermediates: &[CertificateDer],
276 usage: webpki::KeyUsage,
277 name: &str,
278 now: UnixTime,
279) -> Result<(), rustls::Error> {
280 let (cert, chain, trustroots) = prepare_for_self_signed(end_entity, intermediates)?;
283
284 let verified_cert = cert
286 .verify_for_usage(
287 SUPPORTED_SIG_ALGS,
288 &trustroots,
289 chain,
290 now,
291 usage,
292 None,
293 None,
294 )
295 .map_err(pki_error)?;
296
297 let subject_name =
299 ServerName::try_from(name).map_err(|_| rustls::Error::UnsupportedNameType)?;
300 verified_cert
301 .end_entity()
302 .verify_is_valid_for_subject_name(&subject_name)
303 .map_err(pki_error)
304}
305
306type CertChainAndRoots<'a> = (
307 webpki::EndEntityCert<'a>,
308 &'a [CertificateDer<'a>],
309 Vec<TrustAnchor<'a>>,
310);
311
312fn prepare_for_self_signed<'a>(
316 end_entity: &'a CertificateDer,
317 intermediates: &'a [CertificateDer],
318) -> Result<CertChainAndRoots<'a>, rustls::Error> {
319 let cert = webpki::EndEntityCert::try_from(end_entity).map_err(pki_error)?;
321
322 let root = webpki::anchor_from_trusted_cert(end_entity).map_err(pki_error)?;
324
325 Ok((cert, intermediates, vec![root]))
326}
327
328fn pki_error(error: webpki::Error) -> rustls::Error {
329 use webpki::Error::*;
330 match error {
331 BadDer | BadDerTime => {
332 rustls::Error::InvalidCertificate(rustls::CertificateError::BadEncoding)
333 }
334 InvalidSignatureForPublicKey
335 | UnsupportedSignatureAlgorithmContext(_)
336 | UnsupportedSignatureAlgorithmForPublicKeyContext(_) => {
337 rustls::Error::InvalidCertificate(rustls::CertificateError::BadSignature)
338 }
339 CertNotValidForName(_) => {
340 rustls::Error::InvalidCertificate(rustls::CertificateError::NotValidForName)
341 }
342 e => rustls::Error::General(format!("invalid peer certificate: {e}")),
343 }
344}
345
346pub fn public_key_from_certificate(
348 certificate: &CertificateDer,
349) -> Result<Ed25519PublicKey, rustls::Error> {
350 use x509_parser::{certificate::X509Certificate, prelude::FromDer};
351
352 let cert = X509Certificate::from_der(certificate.as_ref())
353 .map_err(|e| rustls::Error::General(e.to_string()))?;
354 let spki = cert.1.public_key();
355 let public_key_bytes =
356 <ed25519::pkcs8::PublicKeyBytes as pkcs8::DecodePublicKey>::from_public_key_der(spki.raw)
357 .map_err(|e| rustls::Error::General(format!("invalid ed25519 public key: {e}")))?;
358
359 let public_key = Ed25519PublicKey::from_bytes(public_key_bytes.as_ref())
360 .map_err(|e| rustls::Error::General(format!("invalid ed25519 public key: {e}")))?;
361 Ok(public_key)
362}