1use std::sync::Arc;
2
3use futures::future::BoxFuture;
4use rustls::{
5 SignatureScheme,
6 pki_types::{CertificateDer, PrivateKeyDer, SubjectPublicKeyInfoDer},
7};
8use snafu::{OptionExt, ResultExt, Snafu};
9use x509_parser::prelude::FromDer;
10use x509_parser::{
11 extensions::ParsedExtension,
12 oid_registry::{
13 OID_EC_P256, OID_KEY_TYPE_EC_PUBLIC_KEY, OID_NIST_EC_P384, OID_PKCS1_RSAENCRYPTION,
14 OID_SIG_ED25519,
15 },
16 x509::SubjectPublicKeyInfo,
17};
18
19use crate::{certificate::DhttpSubjectKeyIdentifier, name::Name};
20
21const RSA_CANONICAL_SCHEME: SignatureScheme = SignatureScheme::RSA_PSS_SHA512;
22const ECDSA_CANONICAL_SCHEMES: &[SignatureScheme] = &[
23 SignatureScheme::ECDSA_NISTP256_SHA256,
24 SignatureScheme::ECDSA_NISTP384_SHA384,
25];
26const ED25519_CANONICAL_SCHEME: SignatureScheme = SignatureScheme::ED25519;
27
28#[derive(Debug, Clone, PartialEq)]
30pub struct Identity {
31 pub name: Name<'static>,
32 pub certs: Arc<Vec<CertificateDer<'static>>>,
33 pub key: Arc<PrivateKeyDer<'static>>,
34 pub ocsp: Arc<Option<Vec<u8>>>,
35}
36
37#[derive(Debug, Snafu)]
38#[snafu(module)]
39pub enum ExtractSubjectKeyIdentifierError {
40 #[snafu(display("certificate chain is empty"))]
41 EmptyCertificateChain,
42 #[snafu(display("failed to parse leaf certificate"))]
43 ParseCertificate {
44 source: x509_parser::nom::Err<x509_parser::error::X509Error>,
45 },
46 #[snafu(display("failed to parse subject key identifier extension"))]
47 ParseExtension,
48}
49
50#[derive(Debug, Snafu)]
51#[snafu(module)]
52pub enum ExtractDhttpSubjectKeyIdentifierError {
53 #[snafu(transparent)]
54 ExtractSubjectKeyIdentifier {
55 source: ExtractSubjectKeyIdentifierError,
56 },
57 #[snafu(display("leaf certificate is missing subject key identifier"))]
58 MissingSubjectKeyIdentifier,
59 #[snafu(display("subject key identifier is not a dhttp subject key identifier"))]
60 InvalidDhttpSubjectKeyIdentifier {
61 source: crate::certificate::InvalidDhttpSubjectKeyIdentifier,
62 },
63}
64
65#[derive(Debug, Snafu)]
66#[snafu(module)]
67pub enum SignError {
68 #[snafu(display("unsupported signing key type"))]
69 UnsupportedKey,
70 #[snafu(display("cryptographic operation failed"))]
71 Crypto { source: rustls::Error },
72}
73
74#[derive(Debug, Snafu)]
75#[snafu(module)]
76pub enum VerifyError {
77 #[snafu(display("unsupported public key type"))]
78 UnsupportedKey,
79}
80
81impl Identity {
82 pub fn new(
83 name: Name<'static>,
84 certs: Vec<CertificateDer<'static>>,
85 key: PrivateKeyDer<'static>,
86 ) -> Self {
87 Self {
88 name,
89 certs: Arc::new(certs),
90 key: Arc::new(key),
91 ocsp: Arc::new(None),
92 }
93 }
94
95 pub fn name(&self) -> &Name<'static> {
96 &self.name
97 }
98
99 pub fn cert_chain(&self) -> &[CertificateDer<'static>] {
100 &self.certs
101 }
102
103 pub fn certs(&self) -> &[CertificateDer<'static>] {
104 self.cert_chain()
105 }
106
107 pub fn key(&self) -> &PrivateKeyDer<'static> {
108 &self.key
109 }
110
111 pub fn public_key(&self) -> SubjectPublicKeyInfoDer<'_> {
112 match x509_parser::certificate::X509Certificate::from_der(&self.certs[0]) {
113 Ok((_remain, certificate)) => {
114 let spki = certificate.public_key().raw;
115 spki.to_owned().into()
116 }
117 Err(_) if self.certs.len() == 1 => self.certs[0].as_ref().into(),
118 Err(_) => unreachable!("rustls returned an invalid peer_certificates"),
119 }
120 }
121
122 pub fn sign(&self, data: &[u8]) -> Result<Vec<u8>, SignError> {
123 let key = rustls::crypto::ring::sign::any_supported_type(&self.key)
124 .context(sign_error::CryptoSnafu)?;
125 sign_with_key(key.as_ref(), data)
126 }
127
128 pub fn verify(&self, data: &[u8], signature: &[u8]) -> Result<bool, VerifyError> {
129 verify_signature(self.public_key(), data, signature)
130 }
131
132 pub fn subject_key_identifier(
133 &self,
134 ) -> Result<Option<&[u8]>, ExtractSubjectKeyIdentifierError> {
135 extract_subject_key_identifier(self.cert_chain())
136 }
137
138 pub fn dhttp_subject_key_identifier(
139 &self,
140 ) -> Result<DhttpSubjectKeyIdentifier, ExtractDhttpSubjectKeyIdentifierError> {
141 extract_dhttp_subject_key_identifier(self.cert_chain())
142 }
143}
144
145pub trait LocalAuthority: Send + Sync + std::fmt::Debug {
159 fn name(&self) -> &str;
160
161 fn cert_chain(&self) -> &[CertificateDer<'static>];
162
163 fn sign(&self, data: &[u8]) -> BoxFuture<'_, Result<Vec<u8>, SignError>>;
164
165 fn public_key(&self) -> SubjectPublicKeyInfoDer<'_> {
166 extract_public_key(self.cert_chain())
167 }
168
169 fn verify(&self, data: &[u8], signature: &[u8]) -> BoxFuture<'_, Result<bool, VerifyError>> {
170 let result = verify_signature(self.public_key(), data, signature);
171 Box::pin(std::future::ready(result))
172 }
173}
174
175pub trait RemoteAuthority: Send + Sync + std::fmt::Debug {
190 fn name(&self) -> &str;
191
192 fn cert_chain(&self) -> &[CertificateDer<'static>];
193
194 fn public_key(&self) -> SubjectPublicKeyInfoDer<'_> {
195 extract_public_key(self.cert_chain())
196 }
197
198 fn verify(&self, data: &[u8], signature: &[u8]) -> BoxFuture<'_, Result<bool, VerifyError>> {
199 let result = verify_signature(self.public_key(), data, signature);
200 Box::pin(std::future::ready(result))
201 }
202}
203
204pub fn extract_subject_key_identifier<'a>(
205 cert_chain: &'a [CertificateDer<'a>],
206) -> Result<Option<&'a [u8]>, ExtractSubjectKeyIdentifierError> {
207 let leaf = cert_chain
208 .first()
209 .context(extract_subject_key_identifier_error::EmptyCertificateChainSnafu)?;
210 let (_remain, certificate) = x509_parser::certificate::X509Certificate::from_der(leaf)
211 .context(extract_subject_key_identifier_error::ParseCertificateSnafu)?;
212
213 for extension in certificate.extensions() {
214 if let ParsedExtension::SubjectKeyIdentifier(identifier) = extension.parsed_extension() {
215 return Ok(Some(identifier.0));
216 }
217 if extension.oid == x509_parser::oid_registry::OID_X509_EXT_SUBJECT_KEY_IDENTIFIER {
218 return extract_subject_key_identifier_error::ParseExtensionSnafu.fail();
219 }
220 }
221
222 Ok(None)
223}
224
225pub fn extract_dhttp_subject_key_identifier(
226 cert_chain: &[CertificateDer<'_>],
227) -> Result<DhttpSubjectKeyIdentifier, ExtractDhttpSubjectKeyIdentifierError> {
228 let ski = extract_subject_key_identifier(cert_chain)?
229 .context(extract_dhttp_subject_key_identifier_error::MissingSubjectKeyIdentifierSnafu)?;
230 DhttpSubjectKeyIdentifier::try_from_subject_key_identifier_bytes(ski)
231 .context(extract_dhttp_subject_key_identifier_error::InvalidDhttpSubjectKeyIdentifierSnafu)
232}
233
234mod private {
235 pub trait Sealed {}
236
237 impl<T: ?Sized> Sealed for T {}
238}
239
240pub trait LocalAuthorityCertificateExt: private::Sealed {
241 fn subject_key_identifier(&self) -> Result<Option<&[u8]>, ExtractSubjectKeyIdentifierError>;
242
243 fn dhttp_subject_key_identifier(
244 &self,
245 ) -> Result<DhttpSubjectKeyIdentifier, ExtractDhttpSubjectKeyIdentifierError>;
246}
247
248impl<T: ?Sized + LocalAuthority> LocalAuthorityCertificateExt for T {
249 fn subject_key_identifier(&self) -> Result<Option<&[u8]>, ExtractSubjectKeyIdentifierError> {
250 extract_subject_key_identifier(self.cert_chain())
251 }
252
253 fn dhttp_subject_key_identifier(
254 &self,
255 ) -> Result<DhttpSubjectKeyIdentifier, ExtractDhttpSubjectKeyIdentifierError> {
256 extract_dhttp_subject_key_identifier(self.cert_chain())
257 }
258}
259
260pub trait RemoteAuthorityCertificateExt: private::Sealed {
261 fn subject_key_identifier(&self) -> Result<Option<&[u8]>, ExtractSubjectKeyIdentifierError>;
262
263 fn dhttp_subject_key_identifier(
264 &self,
265 ) -> Result<DhttpSubjectKeyIdentifier, ExtractDhttpSubjectKeyIdentifierError>;
266}
267
268impl<T: ?Sized + RemoteAuthority> RemoteAuthorityCertificateExt for T {
269 fn subject_key_identifier(&self) -> Result<Option<&[u8]>, ExtractSubjectKeyIdentifierError> {
270 extract_subject_key_identifier(self.cert_chain())
271 }
272
273 fn dhttp_subject_key_identifier(
274 &self,
275 ) -> Result<DhttpSubjectKeyIdentifier, ExtractDhttpSubjectKeyIdentifierError> {
276 extract_dhttp_subject_key_identifier(self.cert_chain())
277 }
278}
279
280pub fn extract_public_key<'d>(cert_chain: &'d [CertificateDer<'d>]) -> SubjectPublicKeyInfoDer<'d> {
281 match x509_parser::certificate::X509Certificate::from_der(&cert_chain[0]) {
282 Ok((_remain, certificate)) => {
283 let spki = certificate.public_key().raw;
284 spki.to_owned().into()
285 }
286 Err(_) if cert_chain.len() == 1 => cert_chain[0].as_ref().into(),
287 Err(_) => unreachable!("rustls returned an invalid peer_certificates"),
288 }
289}
290
291pub fn sign_with_key(
292 key: &(impl rustls::sign::SigningKey + ?Sized),
293 data: &[u8],
294) -> Result<Vec<u8>, SignError> {
295 for scheme in canonical_signing_schemes(key.algorithm()) {
296 if let Some(signer) = key.choose_scheme(&[*scheme]) {
297 return signer.sign(data).context(sign_error::CryptoSnafu);
298 }
299 }
300
301 sign_error::UnsupportedKeySnafu.fail()
302}
303
304pub fn verify_signature(
305 spki: SubjectPublicKeyInfoDer,
306 data: &[u8],
307 signature: &[u8],
308) -> Result<bool, VerifyError> {
309 let scheme = canonical_verification_scheme(spki.as_ref())?;
310 let algorithm: &'static dyn ring::signature::VerificationAlgorithm = match scheme {
311 SignatureScheme::ECDSA_NISTP384_SHA384 => &ring::signature::ECDSA_P384_SHA384_ASN1,
312 SignatureScheme::ECDSA_NISTP256_SHA256 => &ring::signature::ECDSA_P256_SHA256_ASN1,
313 SignatureScheme::ED25519 => &ring::signature::ED25519,
314 SignatureScheme::RSA_PSS_SHA512 => &ring::signature::RSA_PSS_2048_8192_SHA512,
315 _ => return verify_error::UnsupportedKeySnafu.fail(),
316 };
317
318 let public_key = match SubjectPublicKeyInfo::from_der(&spki) {
319 Ok((_remain, spki)) => spki.subject_public_key,
320 Err(_) => return verify_error::UnsupportedKeySnafu.fail(),
321 };
322
323 Ok(
324 ring::signature::UnparsedPublicKey::new(algorithm, public_key)
325 .verify(data, signature)
326 .is_ok(),
327 )
328}
329
330fn canonical_signing_schemes(algorithm: rustls::SignatureAlgorithm) -> &'static [SignatureScheme] {
331 match algorithm {
332 rustls::SignatureAlgorithm::RSA => &[RSA_CANONICAL_SCHEME],
333 rustls::SignatureAlgorithm::ECDSA => ECDSA_CANONICAL_SCHEMES,
334 rustls::SignatureAlgorithm::ED25519 => &[ED25519_CANONICAL_SCHEME],
335 _ => &[],
336 }
337}
338
339fn canonical_verification_scheme(spki: &[u8]) -> Result<SignatureScheme, VerifyError> {
340 let Ok((_remain, spki)) = SubjectPublicKeyInfo::from_der(spki) else {
341 return verify_error::UnsupportedKeySnafu.fail();
342 };
343
344 if spki.algorithm.algorithm == OID_SIG_ED25519 {
345 return Ok(ED25519_CANONICAL_SCHEME);
346 }
347
348 if spki.algorithm.algorithm == OID_PKCS1_RSAENCRYPTION {
349 return Ok(RSA_CANONICAL_SCHEME);
350 }
351
352 if spki.algorithm.algorithm != OID_KEY_TYPE_EC_PUBLIC_KEY {
353 return verify_error::UnsupportedKeySnafu.fail();
354 }
355
356 let Some(curve) = spki
357 .algorithm
358 .parameters
359 .as_ref()
360 .and_then(|parameters| parameters.as_oid().ok())
361 else {
362 return verify_error::UnsupportedKeySnafu.fail();
363 };
364
365 if curve == OID_EC_P256 {
366 Ok(SignatureScheme::ECDSA_NISTP256_SHA256)
367 } else if curve == OID_NIST_EC_P384 {
368 Ok(SignatureScheme::ECDSA_NISTP384_SHA384)
369 } else {
370 verify_error::UnsupportedKeySnafu.fail()
371 }
372}
373
374impl LocalAuthority for Identity {
375 fn name(&self) -> &str {
376 self.name.as_str()
377 }
378
379 fn cert_chain(&self) -> &[CertificateDer<'static>] {
380 self.cert_chain()
381 }
382
383 fn sign(&self, data: &[u8]) -> BoxFuture<'_, Result<Vec<u8>, SignError>> {
384 let result = Identity::sign(self, data);
385 Box::pin(std::future::ready(result))
386 }
387}
388
389impl RemoteAuthority for Identity {
390 fn name(&self) -> &str {
391 self.name.as_str()
392 }
393
394 fn cert_chain(&self) -> &[CertificateDer<'static>] {
395 self.cert_chain()
396 }
397}
398
399#[cfg(test)]
400mod tests {
401 use std::sync::Arc;
402
403 use ring::signature::KeyPair;
404 use rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer};
405 use rustls::sign::{Signer, SigningKey};
406 use rustls::{SignatureAlgorithm, SignatureScheme};
407
408 use crate::certificate::CertificateChainKind;
409 use crate::identity::{Identity, LocalAuthorityCertificateExt, RemoteAuthorityCertificateExt};
410 use crate::name::Name;
411
412 fn dummy_name() -> Name<'static> {
413 "test.example.com".parse().unwrap()
414 }
415
416 fn dummy_certs() -> Vec<CertificateDer<'static>> {
417 Vec::new()
418 }
419
420 fn dummy_key() -> PrivateKeyDer<'static> {
421 PrivateKeyDer::Pkcs8(b"dummy".to_vec().into())
422 }
423
424 fn fixture_identity(name: &str, der: &'static [u8]) -> Identity {
425 Identity::new(
426 name.parse().unwrap(),
427 vec![CertificateDer::from(der.to_vec())],
428 dummy_key(),
429 )
430 }
431
432 fn valid_dhttp_ski_identity() -> Identity {
433 fixture_identity(
434 "client.example.com.dhttp.net",
435 include_bytes!("../tests/fixtures/valid.der"),
436 )
437 }
438
439 fn ed25519_identity() -> Identity {
440 let rng = ring::rand::SystemRandom::new();
441 let pkcs8 = ring::signature::Ed25519KeyPair::generate_pkcs8(&rng).unwrap();
442 let keypair = ring::signature::Ed25519KeyPair::from_pkcs8(pkcs8.as_ref()).unwrap();
443
444 let mut spki = Vec::with_capacity(44);
445 spki.extend_from_slice(&[
446 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00,
447 ]);
448 spki.extend_from_slice(keypair.public_key().as_ref());
449
450 Identity::new(
451 dummy_name(),
452 vec![CertificateDer::from(spki)],
453 PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(pkcs8.as_ref().to_vec())),
454 )
455 }
456
457 #[derive(Debug)]
458 struct RsaPssSha512OnlyKey;
459
460 #[derive(Debug)]
461 struct RsaPssSha512Signer;
462
463 impl SigningKey for RsaPssSha512OnlyKey {
464 fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> {
465 offered
466 .contains(&SignatureScheme::RSA_PSS_SHA512)
467 .then(|| Box::new(RsaPssSha512Signer) as Box<dyn Signer>)
468 }
469
470 fn algorithm(&self) -> SignatureAlgorithm {
471 SignatureAlgorithm::RSA
472 }
473 }
474
475 impl Signer for RsaPssSha512Signer {
476 fn sign(&self, _message: &[u8]) -> Result<Vec<u8>, rustls::Error> {
477 Ok(b"rsa-pss-sha512".to_vec())
478 }
479
480 fn scheme(&self) -> SignatureScheme {
481 SignatureScheme::RSA_PSS_SHA512
482 }
483 }
484
485 fn rsa_subject_public_key_info() -> Vec<u8> {
486 vec![
487 0x30, 0x12, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
488 0x01, 0x05, 0x00, 0x03, 0x01, 0x00,
489 ]
490 }
491
492 #[test]
493 fn construct_identity() {
494 let id = Identity::new(dummy_name(), dummy_certs(), dummy_key());
495 assert_eq!(&id.name, &"test.example.com".parse::<Name>().unwrap());
496 assert!(id.certs.is_empty());
497 }
498
499 #[test]
500 fn clone_shares_certs_via_arc() {
501 let id = Identity::new(dummy_name(), dummy_certs(), dummy_key());
502 let cloned = id.clone();
503 assert!(Arc::ptr_eq(&id.certs, &cloned.certs));
504 }
505
506 #[test]
507 fn clone_shares_key_via_arc() {
508 let id = Identity::new(dummy_name(), dummy_certs(), dummy_key());
509 let cloned = id.clone();
510 assert!(Arc::ptr_eq(&id.key, &cloned.key));
511 }
512
513 #[test]
514 fn ocsp_defaults_to_none() {
515 let id = Identity::new(dummy_name(), dummy_certs(), dummy_key());
516 assert!(id.ocsp.is_none());
517 }
518
519 #[test]
520 fn identity_is_async_authority() {
521 fn assert_local_authority<T: crate::identity::LocalAuthority>() {}
522 fn assert_remote_authority<T: crate::identity::RemoteAuthority>() {}
523
524 assert_local_authority::<Identity>();
525 assert_remote_authority::<Identity>();
526 }
527
528 #[test]
529 fn rsa_canonical_scheme_matches_quic_tls_preference() {
530 assert_eq!(
531 super::sign_with_key(&RsaPssSha512OnlyKey, b"payload")
532 .expect("rsa canonical signature"),
533 b"rsa-pss-sha512"
534 );
535 assert_eq!(
536 super::canonical_verification_scheme(&rsa_subject_public_key_info())
537 .expect("rsa canonical verification scheme"),
538 SignatureScheme::RSA_PSS_SHA512
539 );
540 }
541
542 #[test]
543 fn identity_signs_and_verifies_with_canonical_scheme() {
544 let identity = ed25519_identity();
545 let signature = identity.sign(b"payload").expect("canonical signature");
546
547 assert!(
548 identity
549 .verify(b"payload", &signature)
550 .expect("canonical verification")
551 );
552 assert!(
553 !identity
554 .verify(b"wrong payload", &signature)
555 .expect("canonical verification")
556 );
557 }
558
559 #[test]
560 fn identity_extracts_dhttp_subject_key_identifier() {
561 let identity = valid_dhttp_ski_identity();
562 let raw = identity
563 .subject_key_identifier()
564 .expect("extract raw ski")
565 .expect("fixture has ski");
566
567 assert_eq!(
568 raw,
569 b"0:0:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
570 );
571
572 let dhttp = identity
573 .dhttp_subject_key_identifier()
574 .expect("extract dhttp ski");
575 assert_eq!(dhttp.chain().kind(), CertificateChainKind::Primary);
576 assert_eq!(dhttp.chain().sequence().get(), 0);
577 }
578
579 #[test]
580 fn identity_reports_missing_subject_key_identifier() {
581 let identity = fixture_identity(
582 "missing.example.com.dhttp.net",
583 include_bytes!("../tests/fixtures/missing.der"),
584 );
585
586 assert!(identity.subject_key_identifier().unwrap().is_none());
587 assert!(matches!(
588 identity.dhttp_subject_key_identifier().unwrap_err(),
589 super::ExtractDhttpSubjectKeyIdentifierError::MissingSubjectKeyIdentifier
590 ));
591 }
592
593 #[test]
594 fn identity_reports_malformed_dhttp_subject_key_identifier() {
595 let identity = fixture_identity(
596 "malformed.example.com.dhttp.net",
597 include_bytes!("../tests/fixtures/malformed.der"),
598 );
599
600 assert!(matches!(
601 identity.dhttp_subject_key_identifier().unwrap_err(),
602 super::ExtractDhttpSubjectKeyIdentifierError::InvalidDhttpSubjectKeyIdentifier { .. }
603 ));
604 }
605
606 #[test]
607 fn authority_extension_traits_extract_dhttp_subject_key_identifier() {
608 let identity = valid_dhttp_ski_identity();
609
610 let local = LocalAuthorityCertificateExt::dhttp_subject_key_identifier(&identity)
611 .expect("local authority dhttp ski");
612 let remote = RemoteAuthorityCertificateExt::dhttp_subject_key_identifier(&identity)
613 .expect("remote authority dhttp ski");
614
615 assert_eq!(local, remote);
616 }
617
618 #[test]
619 fn authority_traits_do_not_require_signature_scheme() {
620 let identity = ed25519_identity();
621 let signature = futures::executor::block_on(crate::identity::LocalAuthority::sign(
622 &identity, b"payload",
623 ))
624 .expect("canonical authority signature");
625
626 assert!(
627 futures::executor::block_on(crate::identity::LocalAuthority::verify(
628 &identity, b"payload", &signature,
629 ))
630 .expect("canonical local authority verification")
631 );
632 assert!(
633 futures::executor::block_on(crate::identity::RemoteAuthority::verify(
634 &identity, b"payload", &signature,
635 ))
636 .expect("canonical remote authority verification")
637 );
638 }
639}