1#[cfg(feature = "alloc")]
16use pki_types::SubjectPublicKeyInfoDer;
17use pki_types::{CertificateDer, DnsName};
18
19use crate::der::{self, CONSTRUCTED, CONTEXT_SPECIFIC, DerIterator, FromDer, Tag};
20use crate::error::{DerTypeId, Error};
21use crate::public_values_eq;
22use crate::signed_data::SignedData;
23use crate::subject_name::{GeneralName, NameIterator, WildcardDnsNameRef};
24use crate::x509::{DistributionPointName, Extension, remember_extension, set_extension_once};
25
26pub struct Cert<'a> {
28 pub(crate) serial: untrusted::Input<'a>,
29 pub(crate) signed_data: SignedData<'a>,
30 pub(crate) issuer: untrusted::Input<'a>,
31 pub(crate) validity: untrusted::Input<'a>,
32 pub(crate) subject: untrusted::Input<'a>,
33 pub(crate) spki: untrusted::Input<'a>,
34
35 pub(crate) basic_constraints: Option<untrusted::Input<'a>>,
36 pub(crate) key_usage: Option<untrusted::Input<'a>>,
41 pub(crate) eku: Option<untrusted::Input<'a>>,
42 pub(crate) name_constraints: Option<untrusted::Input<'a>>,
43 pub(crate) subject_alt_name: Option<untrusted::Input<'a>>,
44 pub(crate) crl_distribution_points: Option<untrusted::Input<'a>>,
45
46 der: CertificateDer<'a>,
47}
48
49impl<'a> Cert<'a> {
50 pub(crate) fn from_der(cert_der: untrusted::Input<'a>) -> Result<Self, Error> {
51 let (tbs, signed_data) =
52 cert_der.read_all(Error::TrailingData(DerTypeId::Certificate), |cert_der| {
53 der::nested(
54 cert_der,
55 der::Tag::Sequence,
56 Error::TrailingData(DerTypeId::SignedData),
57 |der| {
58 SignedData::from_der(der, der::TWO_BYTE_DER_SIZE)
60 },
61 )
62 })?;
63
64 tbs.read_all(
65 Error::TrailingData(DerTypeId::CertificateTbsCertificate),
66 |tbs| {
67 version3(tbs)?;
68
69 let serial = lenient_certificate_serial_number(tbs)?;
70
71 let signature = der::expect_tag(tbs, der::Tag::Sequence)?;
72 if !public_values_eq(signature, signed_data.algorithm) {
76 return Err(Error::SignatureAlgorithmMismatch);
77 }
78
79 let issuer = der::expect_tag(tbs, der::Tag::Sequence)?;
80 let validity = der::expect_tag(tbs, der::Tag::Sequence)?;
81 let subject = der::expect_tag(tbs, der::Tag::Sequence)?;
82 let spki = der::expect_tag(tbs, der::Tag::Sequence)?;
83
84 let mut cert = Cert {
90 signed_data,
91 serial,
92 issuer,
93 validity,
94 subject,
95 spki,
96
97 basic_constraints: None,
98 key_usage: None,
99 eku: None,
100 name_constraints: None,
101 subject_alt_name: None,
102 crl_distribution_points: None,
103
104 der: CertificateDer::from(cert_der.as_slice_less_safe()),
105 };
106
107 const ALLOW_EMPTY: bool = true;
116
117 if !tbs.at_end() {
118 der::nested(
119 tbs,
120 der::Tag::ContextSpecificConstructed3,
121 Error::TrailingData(DerTypeId::CertificateExtensions),
122 |tagged| {
123 der::nested_of_mut(
124 tagged,
125 der::Tag::Sequence,
126 der::Tag::Sequence,
127 Error::TrailingData(DerTypeId::Extension),
128 ALLOW_EMPTY,
129 |extension| {
130 remember_cert_extension(
131 &mut cert,
132 &Extension::from_der(extension)?,
133 )
134 },
135 )
136 },
137 )?;
138 }
139
140 Ok(cert)
141 },
142 )
143 }
144
145 pub fn valid_dns_names(&self) -> impl Iterator<Item = &'a str> {
153 NameIterator::new(self.subject_alt_name).filter_map(|result| {
154 let presented_id = match result.ok()? {
155 GeneralName::DnsName(presented) => presented,
156 _ => return None,
157 };
158
159 let dns_str = core::str::from_utf8(presented_id.as_slice_less_safe()).ok()?;
162 match DnsName::try_from(dns_str) {
163 Ok(_) => Some(dns_str),
164 Err(_) => {
165 match WildcardDnsNameRef::try_from_ascii(presented_id.as_slice_less_safe()) {
166 Ok(wildcard_dns_name) => Some(wildcard_dns_name.as_str()),
167 Err(_) => None,
168 }
169 }
170 }
171 })
172 }
173
174 pub fn valid_uri_names(&self) -> impl Iterator<Item = &'a str> {
179 NameIterator::new(self.subject_alt_name).filter_map(|result| {
180 let presented_id = match result.ok()? {
181 GeneralName::UniformResourceIdentifier(presented) => presented,
182 _ => return None,
183 };
184
185 core::str::from_utf8(presented_id.as_slice_less_safe()).ok()
188 })
189 }
190
191 pub fn serial(&self) -> &[u8] {
198 self.serial.as_slice_less_safe()
199 }
200
201 pub fn issuer(&self) -> &[u8] {
205 self.issuer.as_slice_less_safe()
206 }
207
208 pub fn subject(&self) -> &[u8] {
212 self.subject.as_slice_less_safe()
213 }
214
215 #[cfg(feature = "alloc")]
219 pub fn subject_public_key_info(&self) -> SubjectPublicKeyInfoDer<'static> {
220 SubjectPublicKeyInfoDer::from(der::asn1_wrap(
223 Tag::Sequence,
224 self.spki.as_slice_less_safe(),
225 ))
226 }
227
228 pub(crate) fn crl_distribution_points(
230 &self,
231 ) -> Option<impl Iterator<Item = Result<CrlDistributionPoint<'a>, Error>>> {
232 self.crl_distribution_points.map(DerIterator::new)
233 }
234
235 pub fn der(&self) -> CertificateDer<'a> {
237 self.der.clone() }
239}
240
241fn version3(input: &mut untrusted::Reader<'_>) -> Result<(), Error> {
244 der::nested(
245 input,
246 der::Tag::ContextSpecificConstructed0,
247 Error::UnsupportedCertVersion,
248 |input| {
249 let version = u8::from_der(input)?;
250 if version != 2 {
251 return Err(Error::UnsupportedCertVersion);
253 }
254 Ok(())
255 },
256 )
257}
258
259pub(crate) fn lenient_certificate_serial_number<'a>(
260 input: &mut untrusted::Reader<'a>,
261) -> Result<untrusted::Input<'a>, Error> {
262 der::expect_tag(input, Tag::Integer)
273}
274
275fn remember_cert_extension<'a>(
276 cert: &mut Cert<'a>,
277 extension: &Extension<'a>,
278) -> Result<(), Error> {
279 remember_extension(extension, |id| {
284 let out = match id {
285 15 => &mut cert.key_usage,
287
288 17 => &mut cert.subject_alt_name,
290
291 19 => &mut cert.basic_constraints,
293
294 30 => &mut cert.name_constraints,
296
297 31 => &mut cert.crl_distribution_points,
299
300 37 => &mut cert.eku,
302
303 _ => return extension.unsupported(),
305 };
306
307 set_extension_once(out, || {
308 extension.value.read_all(Error::BadDer, |value| match id {
309 15 => Ok(value.read_bytes_to_end()),
312 _ => der::expect_tag(value, Tag::Sequence),
314 })
315 })
316 })
317}
318
319pub(crate) struct CrlDistributionPoint<'a> {
324 distribution_point: Option<untrusted::Input<'a>>,
326
327 pub(crate) reasons: Option<der::BitStringFlags<'a>>,
330
331 pub(crate) crl_issuer: Option<untrusted::Input<'a>>,
334}
335
336impl<'a> CrlDistributionPoint<'a> {
337 pub(crate) fn names(&self) -> Result<Option<DistributionPointName<'a>>, Error> {
339 self.distribution_point
340 .map(|input| DistributionPointName::from_der(&mut untrusted::Reader::new(input)))
341 .transpose()
342 }
343}
344
345impl<'a> FromDer<'a> for CrlDistributionPoint<'a> {
346 fn from_der(reader: &mut untrusted::Reader<'a>) -> Result<Self, Error> {
347 let mut result = CrlDistributionPoint {
351 distribution_point: None,
352 reasons: None,
353 crl_issuer: None,
354 };
355
356 der::nested(
357 reader,
358 Tag::Sequence,
359 Error::TrailingData(Self::TYPE_ID),
360 |der| {
361 const DISTRIBUTION_POINT_TAG: u8 = CONTEXT_SPECIFIC | CONSTRUCTED;
362 const REASONS_TAG: u8 = CONTEXT_SPECIFIC | 1;
363 const CRL_ISSUER_TAG: u8 = CONTEXT_SPECIFIC | CONSTRUCTED | 2;
364
365 while !der.at_end() {
366 let (tag, value) = der::read_tag_and_get_value(der)?;
367 match tag {
368 DISTRIBUTION_POINT_TAG => {
369 set_extension_once(&mut result.distribution_point, || Ok(value))?
370 }
371 REASONS_TAG => set_extension_once(&mut result.reasons, || {
372 der::bit_string_flags(value)
373 })?,
374 CRL_ISSUER_TAG => set_extension_once(&mut result.crl_issuer, || Ok(value))?,
375 _ => return Err(Error::BadDer),
376 }
377 }
378
379 match (result.distribution_point, result.crl_issuer) {
383 (None, None) => Err(Error::MalformedExtensions),
384 _ => Ok(result),
385 }
386 },
387 )
388 }
389
390 const TYPE_ID: DerTypeId = DerTypeId::CrlDistributionPoint;
391}
392
393#[cfg(test)]
394mod tests {
395 #[cfg(feature = "alloc")]
396 use alloc::vec::Vec;
397
398 use super::*;
399 #[cfg(feature = "alloc")]
400 use crate::crl::RevocationReason;
401
402 #[test]
403 fn test_serial_read() {
407 let ee = include_bytes!("../tests/misc/serial_neg_ee.der");
408 let cert = Cert::from_der(untrusted::Input::from(ee)).expect("failed to parse certificate");
409 assert_eq!(cert.serial.as_slice_less_safe(), &[255, 33, 82, 65, 17]);
410
411 let ee = include_bytes!("../tests/misc/serial_large_positive.der");
412 let cert = Cert::from_der(untrusted::Input::from(ee)).expect("failed to parse certificate");
413 assert_eq!(
414 cert.serial.as_slice_less_safe(),
415 &[
416 0, 230, 9, 254, 122, 234, 0, 104, 140, 224, 36, 180, 237, 32, 27, 31, 239, 82, 180,
417 68, 209
418 ]
419 )
420 }
421
422 #[cfg(feature = "alloc")]
423 #[test]
424 fn test_spki_read() {
425 let ee = include_bytes!("../tests/ed25519/ee.der");
426 let cert = Cert::from_der(untrusted::Input::from(ee)).expect("failed to parse certificate");
427 let expected_spki = [
432 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00, 0xfe, 0x5a,
433 0x1e, 0x36, 0x6c, 0x17, 0x27, 0x5b, 0xf1, 0x58, 0x1e, 0x3a, 0x0e, 0xe6, 0x56, 0x29,
434 0x8d, 0x9e, 0x1b, 0x3f, 0xd3, 0x3f, 0x96, 0x46, 0xef, 0xbf, 0x04, 0x6b, 0xc7, 0x3d,
435 0x47, 0x5c,
436 ];
437 assert_eq!(expected_spki, *cert.subject_public_key_info())
438 }
439
440 #[test]
441 #[cfg(feature = "alloc")]
442 fn test_crl_distribution_point_netflix() {
443 let ee = include_bytes!("../tests/netflix/ee.der");
444 let inter = include_bytes!("../tests/netflix/inter.der");
445 let ee_cert = Cert::from_der(untrusted::Input::from(ee)).expect("failed to parse EE cert");
446 let cert =
447 Cert::from_der(untrusted::Input::from(inter)).expect("failed to parse certificate");
448
449 assert!(ee_cert.crl_distribution_points.is_none());
451
452 let crl_distribution_points = cert
454 .crl_distribution_points()
455 .expect("missing distribution points extension")
456 .collect::<Result<Vec<_>, Error>>()
457 .expect("failed to parse distribution points");
458
459 assert_eq!(crl_distribution_points.len(), 1);
461 let crl_distribution_point = crl_distribution_points
462 .first()
463 .expect("missing distribution point");
464
465 assert!(crl_distribution_point.reasons.is_none());
467
468 assert!(crl_distribution_point.crl_issuer.is_none());
470
471 let distribution_point_name = crl_distribution_point
473 .names()
474 .expect("failed to parse distribution point names")
475 .expect("missing distribution point name");
476
477 let names = match distribution_point_name {
480 DistributionPointName::NameRelativeToCrlIssuer => {
481 panic!("unexpected name relative to crl issuer")
482 }
483 DistributionPointName::FullName(names) => names,
484 };
485
486 let names = names
488 .collect::<Result<Vec<_>, Error>>()
489 .expect("failed to parse general names");
490
491 assert_eq!(names.len(), 1);
493 let name = names.first().expect("missing general name");
494
495 match name {
497 GeneralName::UniformResourceIdentifier(uri) => {
498 assert_eq!(
499 uri.as_slice_less_safe(),
500 "http://s.symcb.com/pca3-g3.crl".as_bytes()
501 );
502 }
503 _ => panic!("unexpected general name type"),
504 }
505 }
506
507 #[test]
508 #[cfg(feature = "alloc")]
509 fn test_crl_distribution_point_with_reasons() {
510 let der = include_bytes!("../tests/crl_distrib_point/with_reasons.der");
511 let cert =
512 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
513
514 let crl_distribution_points = cert
516 .crl_distribution_points()
517 .expect("missing distribution points extension")
518 .collect::<Result<Vec<_>, Error>>()
519 .expect("failed to parse distribution points");
520
521 assert_eq!(crl_distribution_points.len(), 1);
523 let crl_distribution_point = crl_distribution_points
524 .first()
525 .expect("missing distribution point");
526
527 let reasons = crl_distribution_point
529 .reasons
530 .as_ref()
531 .expect("missing revocation reasons");
532 let expected = &[
533 RevocationReason::KeyCompromise,
534 RevocationReason::AffiliationChanged,
535 ];
536 for reason in RevocationReason::iter() {
537 #[allow(clippy::as_conversions)]
538 match expected.contains(&reason) {
540 true => assert!(reasons.bit_set(reason as usize)),
541 false => assert!(!reasons.bit_set(reason as usize)),
542 }
543 }
544 }
545
546 #[test]
547 #[cfg(feature = "alloc")]
548 fn test_crl_distribution_point_with_crl_issuer() {
549 let der = include_bytes!("../tests/crl_distrib_point/with_crl_issuer.der");
550 let cert =
551 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
552
553 let crl_distribution_points = cert
555 .crl_distribution_points()
556 .expect("missing distribution points extension")
557 .collect::<Result<Vec<_>, Error>>()
558 .expect("failed to parse distribution points");
559
560 assert_eq!(crl_distribution_points.len(), 1);
562 let crl_distribution_point = crl_distribution_points
563 .first()
564 .expect("missing distribution point");
565
566 assert!(crl_distribution_point.crl_issuer.is_some());
568 assert!(crl_distribution_point.distribution_point.is_none());
569 assert!(crl_distribution_point.reasons.is_none());
570 }
571
572 #[test]
573 #[cfg(feature = "alloc")]
574 fn test_crl_distribution_point_bad_der() {
575 let der = include_bytes!("../tests/crl_distrib_point/unknown_tag.der");
578 let cert =
579 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
580
581 let result = cert
584 .crl_distribution_points()
585 .expect("missing distribution points extension")
586 .collect::<Result<Vec<_>, Error>>();
587 assert!(matches!(result, Err(Error::BadDer)));
588 }
589
590 #[test]
591 #[cfg(feature = "alloc")]
592 fn test_crl_distribution_point_only_reasons() {
593 let der = include_bytes!("../tests/crl_distrib_point/only_reasons.der");
596 let cert =
597 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
598
599 let result = cert
602 .crl_distribution_points()
603 .expect("missing distribution points extension")
604 .collect::<Result<Vec<_>, Error>>();
605 assert!(matches!(result, Err(Error::MalformedExtensions)));
606 }
607
608 #[test]
609 #[cfg(feature = "alloc")]
610 fn test_crl_distribution_point_name_relative_to_issuer() {
611 let der = include_bytes!("../tests/crl_distrib_point/dp_name_relative_to_issuer.der");
612 let cert =
613 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
614
615 let crl_distribution_points = cert
617 .crl_distribution_points()
618 .expect("missing distribution points extension")
619 .collect::<Result<Vec<_>, Error>>()
620 .expect("failed to parse distribution points");
621
622 assert_eq!(crl_distribution_points.len(), 1);
624 let crl_distribution_point = crl_distribution_points
625 .first()
626 .expect("missing distribution point");
627
628 assert!(crl_distribution_point.crl_issuer.is_none());
629 assert!(crl_distribution_point.reasons.is_none());
630
631 let distribution_point_name = crl_distribution_point
633 .names()
634 .expect("failed to parse distribution point names")
635 .expect("missing distribution point name");
636
637 assert!(matches!(
639 distribution_point_name,
640 DistributionPointName::NameRelativeToCrlIssuer
641 ));
642 }
643
644 #[test]
645 #[cfg(feature = "alloc")]
646 fn test_crl_distribution_point_unknown_name_tag() {
647 let der = include_bytes!("../tests/crl_distrib_point/unknown_dp_name_tag.der");
650 let cert =
651 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
652
653 let crl_distribution_points = cert
655 .crl_distribution_points()
656 .expect("missing distribution points extension")
657 .collect::<Result<Vec<_>, Error>>()
658 .expect("failed to parse distribution points");
659
660 assert_eq!(crl_distribution_points.len(), 1);
662 let crl_distribution_point = crl_distribution_points
663 .first()
664 .expect("missing distribution point");
665
666 let result = crl_distribution_point.names();
668 assert!(matches!(result, Err(Error::BadDer)))
669 }
670
671 #[test]
672 #[cfg(feature = "alloc")]
673 fn test_crl_distribution_point_multiple() {
674 let der = include_bytes!("../tests/crl_distrib_point/multiple_distribution_points.der");
675 let cert =
676 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
677
678 let crl_distribution_points = cert
680 .crl_distribution_points()
681 .expect("missing distribution points extension")
682 .collect::<Result<Vec<_>, Error>>()
683 .expect("failed to parse distribution points");
684
685 let (point_a, point_b) = (
687 crl_distribution_points
688 .first()
689 .expect("missing first distribution point"),
690 crl_distribution_points
691 .get(1)
692 .expect("missing second distribution point"),
693 );
694
695 fn get_names<'a>(
696 point: &'a CrlDistributionPoint<'a>,
697 ) -> impl Iterator<Item = Result<GeneralName<'a>, Error>> {
698 match point
699 .names()
700 .expect("failed to parse distribution point names")
701 .expect("missing distribution point name")
702 {
703 DistributionPointName::NameRelativeToCrlIssuer => {
704 panic!("unexpected relative name")
705 }
706 DistributionPointName::FullName(names) => names,
707 }
708 }
709
710 fn uri_bytes<'a>(name: &'a GeneralName<'a>) -> &'a [u8] {
711 match name {
712 GeneralName::UniformResourceIdentifier(uri) => uri.as_slice_less_safe(),
713 _ => panic!("unexpected name type"),
714 }
715 }
716
717 let expected_names = [
719 "http://example.com/crl.1.der".as_bytes(),
720 "http://example.com/crl.2.der".as_bytes(),
721 "http://example.com/crl.3.der".as_bytes(),
722 ];
723 let all_names = get_names(point_a)
724 .chain(get_names(point_b))
725 .collect::<Result<Vec<_>, Error>>()
726 .expect("failed to parse names");
727
728 assert_eq!(
729 all_names.iter().map(uri_bytes).collect::<Vec<_>>(),
730 expected_names
731 );
732 }
733}