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] {
176 self.serial.as_slice_less_safe()
177 }
178
179 pub fn issuer(&self) -> &[u8] {
181 self.issuer.as_slice_less_safe()
182 }
183
184 pub fn subject(&self) -> &[u8] {
186 self.subject.as_slice_less_safe()
187 }
188
189 #[cfg(feature = "alloc")]
191 pub fn subject_public_key_info(&self) -> SubjectPublicKeyInfoDer<'static> {
192 SubjectPublicKeyInfoDer::from(der::asn1_wrap(
195 Tag::Sequence,
196 self.spki.as_slice_less_safe(),
197 ))
198 }
199
200 pub(crate) fn crl_distribution_points(
202 &self,
203 ) -> Option<impl Iterator<Item = Result<CrlDistributionPoint<'a>, Error>>> {
204 self.crl_distribution_points.map(DerIterator::new)
205 }
206
207 pub fn der(&self) -> CertificateDer<'a> {
209 self.der.clone() }
211}
212
213fn version3(input: &mut untrusted::Reader<'_>) -> Result<(), Error> {
216 der::nested(
217 input,
218 der::Tag::ContextSpecificConstructed0,
219 Error::UnsupportedCertVersion,
220 |input| {
221 let version = u8::from_der(input)?;
222 if version != 2 {
223 return Err(Error::UnsupportedCertVersion);
225 }
226 Ok(())
227 },
228 )
229}
230
231pub(crate) fn lenient_certificate_serial_number<'a>(
232 input: &mut untrusted::Reader<'a>,
233) -> Result<untrusted::Input<'a>, Error> {
234 der::expect_tag(input, Tag::Integer)
245}
246
247fn remember_cert_extension<'a>(
248 cert: &mut Cert<'a>,
249 extension: &Extension<'a>,
250) -> Result<(), Error> {
251 remember_extension(extension, |id| {
256 let out = match id {
257 15 => &mut cert.key_usage,
259
260 17 => &mut cert.subject_alt_name,
262
263 19 => &mut cert.basic_constraints,
265
266 30 => &mut cert.name_constraints,
268
269 31 => &mut cert.crl_distribution_points,
271
272 37 => &mut cert.eku,
274
275 _ => return extension.unsupported(),
277 };
278
279 set_extension_once(out, || {
280 extension.value.read_all(Error::BadDer, |value| match id {
281 15 => Ok(value.read_bytes_to_end()),
284 _ => der::expect_tag(value, Tag::Sequence),
286 })
287 })
288 })
289}
290
291pub(crate) struct CrlDistributionPoint<'a> {
296 distribution_point: Option<untrusted::Input<'a>>,
298
299 pub(crate) reasons: Option<der::BitStringFlags<'a>>,
302
303 pub(crate) crl_issuer: Option<untrusted::Input<'a>>,
306}
307
308impl<'a> CrlDistributionPoint<'a> {
309 pub(crate) fn names(&self) -> Result<Option<DistributionPointName<'a>>, Error> {
311 self.distribution_point
312 .map(|input| DistributionPointName::from_der(&mut untrusted::Reader::new(input)))
313 .transpose()
314 }
315}
316
317impl<'a> FromDer<'a> for CrlDistributionPoint<'a> {
318 fn from_der(reader: &mut untrusted::Reader<'a>) -> Result<Self, Error> {
319 let mut result = CrlDistributionPoint {
323 distribution_point: None,
324 reasons: None,
325 crl_issuer: None,
326 };
327
328 der::nested(
329 reader,
330 Tag::Sequence,
331 Error::TrailingData(Self::TYPE_ID),
332 |der| {
333 const DISTRIBUTION_POINT_TAG: u8 = CONTEXT_SPECIFIC | CONSTRUCTED;
334 const REASONS_TAG: u8 = CONTEXT_SPECIFIC | 1;
335 const CRL_ISSUER_TAG: u8 = CONTEXT_SPECIFIC | CONSTRUCTED | 2;
336
337 while !der.at_end() {
338 let (tag, value) = der::read_tag_and_get_value(der)?;
339 match tag {
340 DISTRIBUTION_POINT_TAG => {
341 set_extension_once(&mut result.distribution_point, || Ok(value))?
342 }
343 REASONS_TAG => set_extension_once(&mut result.reasons, || {
344 der::bit_string_flags(value)
345 })?,
346 CRL_ISSUER_TAG => set_extension_once(&mut result.crl_issuer, || Ok(value))?,
347 _ => return Err(Error::BadDer),
348 }
349 }
350
351 match (result.distribution_point, result.crl_issuer) {
355 (None, None) => Err(Error::MalformedExtensions),
356 _ => Ok(result),
357 }
358 },
359 )
360 }
361
362 const TYPE_ID: DerTypeId = DerTypeId::CrlDistributionPoint;
363}
364
365#[cfg(test)]
366mod tests {
367 use super::*;
368 #[cfg(feature = "alloc")]
369 use crate::crl::RevocationReason;
370 use std::prelude::v1::*;
371
372 #[test]
373 fn test_serial_read() {
377 let ee = include_bytes!("../tests/misc/serial_neg_ee.der");
378 let cert = Cert::from_der(untrusted::Input::from(ee)).expect("failed to parse certificate");
379 assert_eq!(cert.serial.as_slice_less_safe(), &[255, 33, 82, 65, 17]);
380
381 let ee = include_bytes!("../tests/misc/serial_large_positive.der");
382 let cert = Cert::from_der(untrusted::Input::from(ee)).expect("failed to parse certificate");
383 assert_eq!(
384 cert.serial.as_slice_less_safe(),
385 &[
386 0, 230, 9, 254, 122, 234, 0, 104, 140, 224, 36, 180, 237, 32, 27, 31, 239, 82, 180,
387 68, 209
388 ]
389 )
390 }
391
392 #[cfg(feature = "alloc")]
393 #[test]
394 fn test_spki_read() {
395 let ee = include_bytes!("../tests/ed25519/ee.der");
396 let cert = Cert::from_der(untrusted::Input::from(ee)).expect("failed to parse certificate");
397 let expected_spki = [
402 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00, 0xfe, 0x5a,
403 0x1e, 0x36, 0x6c, 0x17, 0x27, 0x5b, 0xf1, 0x58, 0x1e, 0x3a, 0x0e, 0xe6, 0x56, 0x29,
404 0x8d, 0x9e, 0x1b, 0x3f, 0xd3, 0x3f, 0x96, 0x46, 0xef, 0xbf, 0x04, 0x6b, 0xc7, 0x3d,
405 0x47, 0x5c,
406 ];
407 assert_eq!(expected_spki, *cert.subject_public_key_info())
408 }
409
410 #[test]
411 #[cfg(feature = "alloc")]
412 fn test_crl_distribution_point_netflix() {
413 let ee = include_bytes!("../tests/netflix/ee.der");
414 let inter = include_bytes!("../tests/netflix/inter.der");
415 let ee_cert = Cert::from_der(untrusted::Input::from(ee)).expect("failed to parse EE cert");
416 let cert =
417 Cert::from_der(untrusted::Input::from(inter)).expect("failed to parse certificate");
418
419 assert!(ee_cert.crl_distribution_points.is_none());
421
422 let crl_distribution_points = cert
424 .crl_distribution_points()
425 .expect("missing distribution points extension")
426 .collect::<Result<Vec<_>, Error>>()
427 .expect("failed to parse distribution points");
428
429 assert_eq!(crl_distribution_points.len(), 1);
431 let crl_distribution_point = crl_distribution_points
432 .first()
433 .expect("missing distribution point");
434
435 assert!(crl_distribution_point.reasons.is_none());
437
438 assert!(crl_distribution_point.crl_issuer.is_none());
440
441 let distribution_point_name = crl_distribution_point
443 .names()
444 .expect("failed to parse distribution point names")
445 .expect("missing distribution point name");
446
447 let names = match distribution_point_name {
450 DistributionPointName::NameRelativeToCrlIssuer => {
451 panic!("unexpected name relative to crl issuer")
452 }
453 DistributionPointName::FullName(names) => names,
454 };
455
456 let names = names
458 .collect::<Result<Vec<_>, Error>>()
459 .expect("failed to parse general names");
460
461 assert_eq!(names.len(), 1);
463 let name = names.first().expect("missing general name");
464
465 match name {
467 GeneralName::UniformResourceIdentifier(uri) => {
468 assert_eq!(
469 uri.as_slice_less_safe(),
470 "http://s.symcb.com/pca3-g3.crl".as_bytes()
471 );
472 }
473 _ => panic!("unexpected general name type"),
474 }
475 }
476
477 #[test]
478 #[cfg(feature = "alloc")]
479 fn test_crl_distribution_point_with_reasons() {
480 let der = include_bytes!("../tests/crl_distrib_point/with_reasons.der");
481 let cert =
482 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
483
484 let crl_distribution_points = cert
486 .crl_distribution_points()
487 .expect("missing distribution points extension")
488 .collect::<Result<Vec<_>, Error>>()
489 .expect("failed to parse distribution points");
490
491 assert_eq!(crl_distribution_points.len(), 1);
493 let crl_distribution_point = crl_distribution_points
494 .first()
495 .expect("missing distribution point");
496
497 let reasons = crl_distribution_point
499 .reasons
500 .as_ref()
501 .expect("missing revocation reasons");
502 let expected = &[
503 RevocationReason::KeyCompromise,
504 RevocationReason::AffiliationChanged,
505 ];
506 for reason in RevocationReason::iter() {
507 #[allow(clippy::as_conversions)]
508 match expected.contains(&reason) {
510 true => assert!(reasons.bit_set(reason as usize)),
511 false => assert!(!reasons.bit_set(reason as usize)),
512 }
513 }
514 }
515
516 #[test]
517 #[cfg(feature = "alloc")]
518 fn test_crl_distribution_point_with_crl_issuer() {
519 let der = include_bytes!("../tests/crl_distrib_point/with_crl_issuer.der");
520 let cert =
521 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
522
523 let crl_distribution_points = cert
525 .crl_distribution_points()
526 .expect("missing distribution points extension")
527 .collect::<Result<Vec<_>, Error>>()
528 .expect("failed to parse distribution points");
529
530 assert_eq!(crl_distribution_points.len(), 1);
532 let crl_distribution_point = crl_distribution_points
533 .first()
534 .expect("missing distribution point");
535
536 assert!(crl_distribution_point.crl_issuer.is_some());
538 assert!(crl_distribution_point.distribution_point.is_none());
539 assert!(crl_distribution_point.reasons.is_none());
540 }
541
542 #[test]
543 #[cfg(feature = "alloc")]
544 fn test_crl_distribution_point_bad_der() {
545 let der = include_bytes!("../tests/crl_distrib_point/unknown_tag.der");
548 let cert =
549 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
550
551 let result = cert
554 .crl_distribution_points()
555 .expect("missing distribution points extension")
556 .collect::<Result<Vec<_>, Error>>();
557 assert!(matches!(result, Err(Error::BadDer)));
558 }
559
560 #[test]
561 #[cfg(feature = "alloc")]
562 fn test_crl_distribution_point_only_reasons() {
563 let der = include_bytes!("../tests/crl_distrib_point/only_reasons.der");
566 let cert =
567 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
568
569 let result = cert
572 .crl_distribution_points()
573 .expect("missing distribution points extension")
574 .collect::<Result<Vec<_>, Error>>();
575 assert!(matches!(result, Err(Error::MalformedExtensions)));
576 }
577
578 #[test]
579 #[cfg(feature = "alloc")]
580 fn test_crl_distribution_point_name_relative_to_issuer() {
581 let der = include_bytes!("../tests/crl_distrib_point/dp_name_relative_to_issuer.der");
582 let cert =
583 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
584
585 let crl_distribution_points = cert
587 .crl_distribution_points()
588 .expect("missing distribution points extension")
589 .collect::<Result<Vec<_>, Error>>()
590 .expect("failed to parse distribution points");
591
592 assert_eq!(crl_distribution_points.len(), 1);
594 let crl_distribution_point = crl_distribution_points
595 .first()
596 .expect("missing distribution point");
597
598 assert!(crl_distribution_point.crl_issuer.is_none());
599 assert!(crl_distribution_point.reasons.is_none());
600
601 let distribution_point_name = crl_distribution_point
603 .names()
604 .expect("failed to parse distribution point names")
605 .expect("missing distribution point name");
606
607 assert!(matches!(
609 distribution_point_name,
610 DistributionPointName::NameRelativeToCrlIssuer
611 ));
612 }
613
614 #[test]
615 #[cfg(feature = "alloc")]
616 fn test_crl_distribution_point_unknown_name_tag() {
617 let der = include_bytes!("../tests/crl_distrib_point/unknown_dp_name_tag.der");
620 let cert =
621 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
622
623 let crl_distribution_points = cert
625 .crl_distribution_points()
626 .expect("missing distribution points extension")
627 .collect::<Result<Vec<_>, Error>>()
628 .expect("failed to parse distribution points");
629
630 assert_eq!(crl_distribution_points.len(), 1);
632 let crl_distribution_point = crl_distribution_points
633 .first()
634 .expect("missing distribution point");
635
636 let result = crl_distribution_point.names();
638 assert!(matches!(result, Err(Error::BadDer)))
639 }
640
641 #[test]
642 #[cfg(feature = "alloc")]
643 fn test_crl_distribution_point_multiple() {
644 let der = include_bytes!("../tests/crl_distrib_point/multiple_distribution_points.der");
645 let cert =
646 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
647
648 let crl_distribution_points = cert
650 .crl_distribution_points()
651 .expect("missing distribution points extension")
652 .collect::<Result<Vec<_>, Error>>()
653 .expect("failed to parse distribution points");
654
655 let (point_a, point_b) = (
657 crl_distribution_points
658 .first()
659 .expect("missing first distribution point"),
660 crl_distribution_points
661 .get(1)
662 .expect("missing second distribution point"),
663 );
664
665 fn get_names<'a>(
666 point: &'a CrlDistributionPoint<'a>,
667 ) -> impl Iterator<Item = Result<GeneralName<'a>, Error>> {
668 match point
669 .names()
670 .expect("failed to parse distribution point names")
671 .expect("missing distribution point name")
672 {
673 DistributionPointName::NameRelativeToCrlIssuer => {
674 panic!("unexpected relative name")
675 }
676 DistributionPointName::FullName(names) => names,
677 }
678 }
679
680 fn uri_bytes<'a>(name: &'a GeneralName<'a>) -> &'a [u8] {
681 match name {
682 GeneralName::UniformResourceIdentifier(uri) => uri.as_slice_less_safe(),
683 _ => panic!("unexpected name type"),
684 }
685 }
686
687 let expected_names = [
689 "http://example.com/crl.1.der".as_bytes(),
690 "http://example.com/crl.2.der".as_bytes(),
691 "http://example.com/crl.3.der".as_bytes(),
692 ];
693 let all_names = get_names(point_a)
694 .chain(get_names(point_b))
695 .collect::<Result<Vec<_>, Error>>()
696 .expect("failed to parse names");
697
698 assert_eq!(
699 all_names.iter().map(uri_bytes).collect::<Vec<_>>(),
700 expected_names
701 );
702 }
703}