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