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 = &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 = &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 use super::*;
396 #[cfg(feature = "alloc")]
397 use crate::crl::RevocationReason;
398 use std::prelude::v1::*;
399
400 #[test]
401 fn test_serial_read() {
405 let ee = include_bytes!("../tests/misc/serial_neg_ee.der");
406 let cert = Cert::from_der(untrusted::Input::from(ee)).expect("failed to parse certificate");
407 assert_eq!(cert.serial.as_slice_less_safe(), &[255, 33, 82, 65, 17]);
408
409 let ee = include_bytes!("../tests/misc/serial_large_positive.der");
410 let cert = Cert::from_der(untrusted::Input::from(ee)).expect("failed to parse certificate");
411 assert_eq!(
412 cert.serial.as_slice_less_safe(),
413 &[
414 0, 230, 9, 254, 122, 234, 0, 104, 140, 224, 36, 180, 237, 32, 27, 31, 239, 82, 180,
415 68, 209
416 ]
417 )
418 }
419
420 #[cfg(feature = "alloc")]
421 #[test]
422 fn test_spki_read() {
423 let ee = include_bytes!("../tests/ed25519/ee.der");
424 let cert = Cert::from_der(untrusted::Input::from(ee)).expect("failed to parse certificate");
425 let expected_spki = [
430 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00, 0xfe, 0x5a,
431 0x1e, 0x36, 0x6c, 0x17, 0x27, 0x5b, 0xf1, 0x58, 0x1e, 0x3a, 0x0e, 0xe6, 0x56, 0x29,
432 0x8d, 0x9e, 0x1b, 0x3f, 0xd3, 0x3f, 0x96, 0x46, 0xef, 0xbf, 0x04, 0x6b, 0xc7, 0x3d,
433 0x47, 0x5c,
434 ];
435 assert_eq!(expected_spki, *cert.subject_public_key_info())
436 }
437
438 #[test]
439 #[cfg(feature = "alloc")]
440 fn test_crl_distribution_point_netflix() {
441 let ee = include_bytes!("../tests/netflix/ee.der");
442 let inter = include_bytes!("../tests/netflix/inter.der");
443 let ee_cert = Cert::from_der(untrusted::Input::from(ee)).expect("failed to parse EE cert");
444 let cert =
445 Cert::from_der(untrusted::Input::from(inter)).expect("failed to parse certificate");
446
447 assert!(ee_cert.crl_distribution_points.is_none());
449
450 let crl_distribution_points = cert
452 .crl_distribution_points()
453 .expect("missing distribution points extension")
454 .collect::<Result<Vec<_>, Error>>()
455 .expect("failed to parse distribution points");
456
457 assert_eq!(crl_distribution_points.len(), 1);
459 let crl_distribution_point = crl_distribution_points
460 .first()
461 .expect("missing distribution point");
462
463 assert!(crl_distribution_point.reasons.is_none());
465
466 assert!(crl_distribution_point.crl_issuer.is_none());
468
469 let distribution_point_name = crl_distribution_point
471 .names()
472 .expect("failed to parse distribution point names")
473 .expect("missing distribution point name");
474
475 let names = match distribution_point_name {
478 DistributionPointName::NameRelativeToCrlIssuer => {
479 panic!("unexpected name relative to crl issuer")
480 }
481 DistributionPointName::FullName(names) => names,
482 };
483
484 let names = names
486 .collect::<Result<Vec<_>, Error>>()
487 .expect("failed to parse general names");
488
489 assert_eq!(names.len(), 1);
491 let name = names.first().expect("missing general name");
492
493 match name {
495 GeneralName::UniformResourceIdentifier(uri) => {
496 assert_eq!(
497 uri.as_slice_less_safe(),
498 "http://s.symcb.com/pca3-g3.crl".as_bytes()
499 );
500 }
501 _ => panic!("unexpected general name type"),
502 }
503 }
504
505 #[test]
506 #[cfg(feature = "alloc")]
507 fn test_crl_distribution_point_with_reasons() {
508 let der = include_bytes!("../tests/crl_distrib_point/with_reasons.der");
509 let cert =
510 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
511
512 let crl_distribution_points = cert
514 .crl_distribution_points()
515 .expect("missing distribution points extension")
516 .collect::<Result<Vec<_>, Error>>()
517 .expect("failed to parse distribution points");
518
519 assert_eq!(crl_distribution_points.len(), 1);
521 let crl_distribution_point = crl_distribution_points
522 .first()
523 .expect("missing distribution point");
524
525 let reasons = crl_distribution_point
527 .reasons
528 .as_ref()
529 .expect("missing revocation reasons");
530 let expected = &[
531 RevocationReason::KeyCompromise,
532 RevocationReason::AffiliationChanged,
533 ];
534 for reason in RevocationReason::iter() {
535 #[allow(clippy::as_conversions)]
536 match expected.contains(&reason) {
538 true => assert!(reasons.bit_set(reason as usize)),
539 false => assert!(!reasons.bit_set(reason as usize)),
540 }
541 }
542 }
543
544 #[test]
545 #[cfg(feature = "alloc")]
546 fn test_crl_distribution_point_with_crl_issuer() {
547 let der = include_bytes!("../tests/crl_distrib_point/with_crl_issuer.der");
548 let cert =
549 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
550
551 let crl_distribution_points = cert
553 .crl_distribution_points()
554 .expect("missing distribution points extension")
555 .collect::<Result<Vec<_>, Error>>()
556 .expect("failed to parse distribution points");
557
558 assert_eq!(crl_distribution_points.len(), 1);
560 let crl_distribution_point = crl_distribution_points
561 .first()
562 .expect("missing distribution point");
563
564 assert!(crl_distribution_point.crl_issuer.is_some());
566 assert!(crl_distribution_point.distribution_point.is_none());
567 assert!(crl_distribution_point.reasons.is_none());
568 }
569
570 #[test]
571 #[cfg(feature = "alloc")]
572 fn test_crl_distribution_point_bad_der() {
573 let der = include_bytes!("../tests/crl_distrib_point/unknown_tag.der");
576 let cert =
577 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
578
579 let result = cert
582 .crl_distribution_points()
583 .expect("missing distribution points extension")
584 .collect::<Result<Vec<_>, Error>>();
585 assert!(matches!(result, Err(Error::BadDer)));
586 }
587
588 #[test]
589 #[cfg(feature = "alloc")]
590 fn test_crl_distribution_point_only_reasons() {
591 let der = include_bytes!("../tests/crl_distrib_point/only_reasons.der");
594 let cert =
595 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
596
597 let result = cert
600 .crl_distribution_points()
601 .expect("missing distribution points extension")
602 .collect::<Result<Vec<_>, Error>>();
603 assert!(matches!(result, Err(Error::MalformedExtensions)));
604 }
605
606 #[test]
607 #[cfg(feature = "alloc")]
608 fn test_crl_distribution_point_name_relative_to_issuer() {
609 let der = include_bytes!("../tests/crl_distrib_point/dp_name_relative_to_issuer.der");
610 let cert =
611 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
612
613 let crl_distribution_points = cert
615 .crl_distribution_points()
616 .expect("missing distribution points extension")
617 .collect::<Result<Vec<_>, Error>>()
618 .expect("failed to parse distribution points");
619
620 assert_eq!(crl_distribution_points.len(), 1);
622 let crl_distribution_point = crl_distribution_points
623 .first()
624 .expect("missing distribution point");
625
626 assert!(crl_distribution_point.crl_issuer.is_none());
627 assert!(crl_distribution_point.reasons.is_none());
628
629 let distribution_point_name = crl_distribution_point
631 .names()
632 .expect("failed to parse distribution point names")
633 .expect("missing distribution point name");
634
635 assert!(matches!(
637 distribution_point_name,
638 DistributionPointName::NameRelativeToCrlIssuer
639 ));
640 }
641
642 #[test]
643 #[cfg(feature = "alloc")]
644 fn test_crl_distribution_point_unknown_name_tag() {
645 let der = include_bytes!("../tests/crl_distrib_point/unknown_dp_name_tag.der");
648 let cert =
649 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
650
651 let crl_distribution_points = cert
653 .crl_distribution_points()
654 .expect("missing distribution points extension")
655 .collect::<Result<Vec<_>, Error>>()
656 .expect("failed to parse distribution points");
657
658 assert_eq!(crl_distribution_points.len(), 1);
660 let crl_distribution_point = crl_distribution_points
661 .first()
662 .expect("missing distribution point");
663
664 let result = crl_distribution_point.names();
666 assert!(matches!(result, Err(Error::BadDer)))
667 }
668
669 #[test]
670 #[cfg(feature = "alloc")]
671 fn test_crl_distribution_point_multiple() {
672 let der = include_bytes!("../tests/crl_distrib_point/multiple_distribution_points.der");
673 let cert =
674 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
675
676 let crl_distribution_points = cert
678 .crl_distribution_points()
679 .expect("missing distribution points extension")
680 .collect::<Result<Vec<_>, Error>>()
681 .expect("failed to parse distribution points");
682
683 let (point_a, point_b) = (
685 crl_distribution_points
686 .first()
687 .expect("missing first distribution point"),
688 crl_distribution_points
689 .get(1)
690 .expect("missing second distribution point"),
691 );
692
693 fn get_names<'a>(
694 point: &'a CrlDistributionPoint<'a>,
695 ) -> impl Iterator<Item = Result<GeneralName<'a>, Error>> {
696 match point
697 .names()
698 .expect("failed to parse distribution point names")
699 .expect("missing distribution point name")
700 {
701 DistributionPointName::NameRelativeToCrlIssuer => {
702 panic!("unexpected relative name")
703 }
704 DistributionPointName::FullName(names) => names,
705 }
706 }
707
708 fn uri_bytes<'a>(name: &'a GeneralName<'a>) -> &'a [u8] {
709 match name {
710 GeneralName::UniformResourceIdentifier(uri) => uri.as_slice_less_safe(),
711 _ => panic!("unexpected name type"),
712 }
713 }
714
715 let expected_names = [
717 "http://example.com/crl.1.der".as_bytes(),
718 "http://example.com/crl.2.der".as_bytes(),
719 "http://example.com/crl.3.der".as_bytes(),
720 ];
721 let all_names = get_names(point_a)
722 .chain(get_names(point_b))
723 .collect::<Result<Vec<_>, Error>>()
724 .expect("failed to parse names");
725
726 assert_eq!(
727 all_names.iter().map(uri_bytes).collect::<Vec<_>>(),
728 expected_names
729 );
730 }
731}