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 serial(&self) -> &[u8] {
181 self.serial.as_slice_less_safe()
182 }
183
184 pub fn issuer(&self) -> &[u8] {
188 self.issuer.as_slice_less_safe()
189 }
190
191 pub fn subject(&self) -> &[u8] {
195 self.subject.as_slice_less_safe()
196 }
197
198 #[cfg(feature = "alloc")]
202 pub fn subject_public_key_info(&self) -> SubjectPublicKeyInfoDer<'static> {
203 SubjectPublicKeyInfoDer::from(der::asn1_wrap(
206 Tag::Sequence,
207 self.spki.as_slice_less_safe(),
208 ))
209 }
210
211 pub(crate) fn crl_distribution_points(
213 &self,
214 ) -> Option<impl Iterator<Item = Result<CrlDistributionPoint<'a>, Error>>> {
215 self.crl_distribution_points.map(DerIterator::new)
216 }
217
218 pub fn der(&self) -> CertificateDer<'a> {
220 self.der.clone() }
222}
223
224fn version3(input: &mut untrusted::Reader<'_>) -> Result<(), Error> {
227 der::nested(
228 input,
229 der::Tag::ContextSpecificConstructed0,
230 Error::UnsupportedCertVersion,
231 |input| {
232 let version = u8::from_der(input)?;
233 if version != 2 {
234 return Err(Error::UnsupportedCertVersion);
236 }
237 Ok(())
238 },
239 )
240}
241
242pub(crate) fn lenient_certificate_serial_number<'a>(
243 input: &mut untrusted::Reader<'a>,
244) -> Result<untrusted::Input<'a>, Error> {
245 der::expect_tag(input, Tag::Integer)
256}
257
258fn remember_cert_extension<'a>(
259 cert: &mut Cert<'a>,
260 extension: &Extension<'a>,
261) -> Result<(), Error> {
262 remember_extension(extension, |id| {
267 let out = match id {
268 15 => &mut cert.key_usage,
270
271 17 => &mut cert.subject_alt_name,
273
274 19 => &mut cert.basic_constraints,
276
277 30 => &mut cert.name_constraints,
279
280 31 => &mut cert.crl_distribution_points,
282
283 37 => &mut cert.eku,
285
286 _ => return extension.unsupported(),
288 };
289
290 set_extension_once(out, || {
291 extension.value.read_all(Error::BadDer, |value| match id {
292 15 => Ok(value.read_bytes_to_end()),
295 _ => der::expect_tag(value, Tag::Sequence),
297 })
298 })
299 })
300}
301
302pub(crate) struct CrlDistributionPoint<'a> {
307 distribution_point: Option<untrusted::Input<'a>>,
309
310 pub(crate) reasons: Option<der::BitStringFlags<'a>>,
313
314 pub(crate) crl_issuer: Option<untrusted::Input<'a>>,
317}
318
319impl<'a> CrlDistributionPoint<'a> {
320 pub(crate) fn names(&self) -> Result<Option<DistributionPointName<'a>>, Error> {
322 self.distribution_point
323 .map(|input| DistributionPointName::from_der(&mut untrusted::Reader::new(input)))
324 .transpose()
325 }
326}
327
328impl<'a> FromDer<'a> for CrlDistributionPoint<'a> {
329 fn from_der(reader: &mut untrusted::Reader<'a>) -> Result<Self, Error> {
330 let mut result = CrlDistributionPoint {
334 distribution_point: None,
335 reasons: None,
336 crl_issuer: None,
337 };
338
339 der::nested(
340 reader,
341 Tag::Sequence,
342 Error::TrailingData(Self::TYPE_ID),
343 |der| {
344 const DISTRIBUTION_POINT_TAG: u8 = CONTEXT_SPECIFIC | CONSTRUCTED;
345 const REASONS_TAG: u8 = CONTEXT_SPECIFIC | 1;
346 const CRL_ISSUER_TAG: u8 = CONTEXT_SPECIFIC | CONSTRUCTED | 2;
347
348 while !der.at_end() {
349 let (tag, value) = der::read_tag_and_get_value(der)?;
350 match tag {
351 DISTRIBUTION_POINT_TAG => {
352 set_extension_once(&mut result.distribution_point, || Ok(value))?
353 }
354 REASONS_TAG => set_extension_once(&mut result.reasons, || {
355 der::bit_string_flags(value)
356 })?,
357 CRL_ISSUER_TAG => set_extension_once(&mut result.crl_issuer, || Ok(value))?,
358 _ => return Err(Error::BadDer),
359 }
360 }
361
362 match (result.distribution_point, result.crl_issuer) {
366 (None, None) => Err(Error::MalformedExtensions),
367 _ => Ok(result),
368 }
369 },
370 )
371 }
372
373 const TYPE_ID: DerTypeId = DerTypeId::CrlDistributionPoint;
374}
375
376#[cfg(test)]
377mod tests {
378 use super::*;
379 #[cfg(feature = "alloc")]
380 use crate::crl::RevocationReason;
381 use std::prelude::v1::*;
382
383 #[test]
384 fn test_serial_read() {
388 let ee = include_bytes!("../tests/misc/serial_neg_ee.der");
389 let cert = Cert::from_der(untrusted::Input::from(ee)).expect("failed to parse certificate");
390 assert_eq!(cert.serial.as_slice_less_safe(), &[255, 33, 82, 65, 17]);
391
392 let ee = include_bytes!("../tests/misc/serial_large_positive.der");
393 let cert = Cert::from_der(untrusted::Input::from(ee)).expect("failed to parse certificate");
394 assert_eq!(
395 cert.serial.as_slice_less_safe(),
396 &[
397 0, 230, 9, 254, 122, 234, 0, 104, 140, 224, 36, 180, 237, 32, 27, 31, 239, 82, 180,
398 68, 209
399 ]
400 )
401 }
402
403 #[cfg(feature = "alloc")]
404 #[test]
405 fn test_spki_read() {
406 let ee = include_bytes!("../tests/ed25519/ee.der");
407 let cert = Cert::from_der(untrusted::Input::from(ee)).expect("failed to parse certificate");
408 let expected_spki = [
413 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00, 0xfe, 0x5a,
414 0x1e, 0x36, 0x6c, 0x17, 0x27, 0x5b, 0xf1, 0x58, 0x1e, 0x3a, 0x0e, 0xe6, 0x56, 0x29,
415 0x8d, 0x9e, 0x1b, 0x3f, 0xd3, 0x3f, 0x96, 0x46, 0xef, 0xbf, 0x04, 0x6b, 0xc7, 0x3d,
416 0x47, 0x5c,
417 ];
418 assert_eq!(expected_spki, *cert.subject_public_key_info())
419 }
420
421 #[test]
422 #[cfg(feature = "alloc")]
423 fn test_crl_distribution_point_netflix() {
424 let ee = include_bytes!("../tests/netflix/ee.der");
425 let inter = include_bytes!("../tests/netflix/inter.der");
426 let ee_cert = Cert::from_der(untrusted::Input::from(ee)).expect("failed to parse EE cert");
427 let cert =
428 Cert::from_der(untrusted::Input::from(inter)).expect("failed to parse certificate");
429
430 assert!(ee_cert.crl_distribution_points.is_none());
432
433 let crl_distribution_points = cert
435 .crl_distribution_points()
436 .expect("missing distribution points extension")
437 .collect::<Result<Vec<_>, Error>>()
438 .expect("failed to parse distribution points");
439
440 assert_eq!(crl_distribution_points.len(), 1);
442 let crl_distribution_point = crl_distribution_points
443 .first()
444 .expect("missing distribution point");
445
446 assert!(crl_distribution_point.reasons.is_none());
448
449 assert!(crl_distribution_point.crl_issuer.is_none());
451
452 let distribution_point_name = crl_distribution_point
454 .names()
455 .expect("failed to parse distribution point names")
456 .expect("missing distribution point name");
457
458 let names = match distribution_point_name {
461 DistributionPointName::NameRelativeToCrlIssuer => {
462 panic!("unexpected name relative to crl issuer")
463 }
464 DistributionPointName::FullName(names) => names,
465 };
466
467 let names = names
469 .collect::<Result<Vec<_>, Error>>()
470 .expect("failed to parse general names");
471
472 assert_eq!(names.len(), 1);
474 let name = names.first().expect("missing general name");
475
476 match name {
478 GeneralName::UniformResourceIdentifier(uri) => {
479 assert_eq!(
480 uri.as_slice_less_safe(),
481 "http://s.symcb.com/pca3-g3.crl".as_bytes()
482 );
483 }
484 _ => panic!("unexpected general name type"),
485 }
486 }
487
488 #[test]
489 #[cfg(feature = "alloc")]
490 fn test_crl_distribution_point_with_reasons() {
491 let der = include_bytes!("../tests/crl_distrib_point/with_reasons.der");
492 let cert =
493 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
494
495 let crl_distribution_points = cert
497 .crl_distribution_points()
498 .expect("missing distribution points extension")
499 .collect::<Result<Vec<_>, Error>>()
500 .expect("failed to parse distribution points");
501
502 assert_eq!(crl_distribution_points.len(), 1);
504 let crl_distribution_point = crl_distribution_points
505 .first()
506 .expect("missing distribution point");
507
508 let reasons = crl_distribution_point
510 .reasons
511 .as_ref()
512 .expect("missing revocation reasons");
513 let expected = &[
514 RevocationReason::KeyCompromise,
515 RevocationReason::AffiliationChanged,
516 ];
517 for reason in RevocationReason::iter() {
518 #[allow(clippy::as_conversions)]
519 match expected.contains(&reason) {
521 true => assert!(reasons.bit_set(reason as usize)),
522 false => assert!(!reasons.bit_set(reason as usize)),
523 }
524 }
525 }
526
527 #[test]
528 #[cfg(feature = "alloc")]
529 fn test_crl_distribution_point_with_crl_issuer() {
530 let der = include_bytes!("../tests/crl_distrib_point/with_crl_issuer.der");
531 let cert =
532 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
533
534 let crl_distribution_points = cert
536 .crl_distribution_points()
537 .expect("missing distribution points extension")
538 .collect::<Result<Vec<_>, Error>>()
539 .expect("failed to parse distribution points");
540
541 assert_eq!(crl_distribution_points.len(), 1);
543 let crl_distribution_point = crl_distribution_points
544 .first()
545 .expect("missing distribution point");
546
547 assert!(crl_distribution_point.crl_issuer.is_some());
549 assert!(crl_distribution_point.distribution_point.is_none());
550 assert!(crl_distribution_point.reasons.is_none());
551 }
552
553 #[test]
554 #[cfg(feature = "alloc")]
555 fn test_crl_distribution_point_bad_der() {
556 let der = include_bytes!("../tests/crl_distrib_point/unknown_tag.der");
559 let cert =
560 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
561
562 let result = cert
565 .crl_distribution_points()
566 .expect("missing distribution points extension")
567 .collect::<Result<Vec<_>, Error>>();
568 assert!(matches!(result, Err(Error::BadDer)));
569 }
570
571 #[test]
572 #[cfg(feature = "alloc")]
573 fn test_crl_distribution_point_only_reasons() {
574 let der = include_bytes!("../tests/crl_distrib_point/only_reasons.der");
577 let cert =
578 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
579
580 let result = cert
583 .crl_distribution_points()
584 .expect("missing distribution points extension")
585 .collect::<Result<Vec<_>, Error>>();
586 assert!(matches!(result, Err(Error::MalformedExtensions)));
587 }
588
589 #[test]
590 #[cfg(feature = "alloc")]
591 fn test_crl_distribution_point_name_relative_to_issuer() {
592 let der = include_bytes!("../tests/crl_distrib_point/dp_name_relative_to_issuer.der");
593 let cert =
594 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
595
596 let crl_distribution_points = cert
598 .crl_distribution_points()
599 .expect("missing distribution points extension")
600 .collect::<Result<Vec<_>, Error>>()
601 .expect("failed to parse distribution points");
602
603 assert_eq!(crl_distribution_points.len(), 1);
605 let crl_distribution_point = crl_distribution_points
606 .first()
607 .expect("missing distribution point");
608
609 assert!(crl_distribution_point.crl_issuer.is_none());
610 assert!(crl_distribution_point.reasons.is_none());
611
612 let distribution_point_name = crl_distribution_point
614 .names()
615 .expect("failed to parse distribution point names")
616 .expect("missing distribution point name");
617
618 assert!(matches!(
620 distribution_point_name,
621 DistributionPointName::NameRelativeToCrlIssuer
622 ));
623 }
624
625 #[test]
626 #[cfg(feature = "alloc")]
627 fn test_crl_distribution_point_unknown_name_tag() {
628 let der = include_bytes!("../tests/crl_distrib_point/unknown_dp_name_tag.der");
631 let cert =
632 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
633
634 let crl_distribution_points = cert
636 .crl_distribution_points()
637 .expect("missing distribution points extension")
638 .collect::<Result<Vec<_>, Error>>()
639 .expect("failed to parse distribution points");
640
641 assert_eq!(crl_distribution_points.len(), 1);
643 let crl_distribution_point = crl_distribution_points
644 .first()
645 .expect("missing distribution point");
646
647 let result = crl_distribution_point.names();
649 assert!(matches!(result, Err(Error::BadDer)))
650 }
651
652 #[test]
653 #[cfg(feature = "alloc")]
654 fn test_crl_distribution_point_multiple() {
655 let der = include_bytes!("../tests/crl_distrib_point/multiple_distribution_points.der");
656 let cert =
657 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
658
659 let crl_distribution_points = cert
661 .crl_distribution_points()
662 .expect("missing distribution points extension")
663 .collect::<Result<Vec<_>, Error>>()
664 .expect("failed to parse distribution points");
665
666 let (point_a, point_b) = (
668 crl_distribution_points
669 .first()
670 .expect("missing first distribution point"),
671 crl_distribution_points
672 .get(1)
673 .expect("missing second distribution point"),
674 );
675
676 fn get_names<'a>(
677 point: &'a CrlDistributionPoint<'a>,
678 ) -> impl Iterator<Item = Result<GeneralName<'a>, Error>> {
679 match point
680 .names()
681 .expect("failed to parse distribution point names")
682 .expect("missing distribution point name")
683 {
684 DistributionPointName::NameRelativeToCrlIssuer => {
685 panic!("unexpected relative name")
686 }
687 DistributionPointName::FullName(names) => names,
688 }
689 }
690
691 fn uri_bytes<'a>(name: &'a GeneralName<'a>) -> &'a [u8] {
692 match name {
693 GeneralName::UniformResourceIdentifier(uri) => uri.as_slice_less_safe(),
694 _ => panic!("unexpected name type"),
695 }
696 }
697
698 let expected_names = [
700 "http://example.com/crl.1.der".as_bytes(),
701 "http://example.com/crl.2.der".as_bytes(),
702 "http://example.com/crl.3.der".as_bytes(),
703 ];
704 let all_names = get_names(point_a)
705 .chain(get_names(point_b))
706 .collect::<Result<Vec<_>, Error>>()
707 .expect("failed to parse names");
708
709 assert_eq!(
710 all_names.iter().map(uri_bytes).collect::<Vec<_>>(),
711 expected_names
712 );
713 }
714}