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 if !tbs.at_end() {
108 der::nested(
109 tbs,
110 der::Tag::ContextSpecificConstructed3,
111 Error::TrailingData(DerTypeId::CertificateExtensions),
112 |tagged| {
113 der::nested_of_mut(
114 tagged,
115 der::Tag::Sequence,
116 der::Tag::Sequence,
117 Error::TrailingData(DerTypeId::Extension),
118 |extension| {
119 remember_cert_extension(
120 &mut cert,
121 &Extension::from_der(extension)?,
122 )
123 },
124 )
125 },
126 )?;
127 }
128
129 Ok(cert)
130 },
131 )
132 }
133
134 pub fn valid_dns_names(&self) -> impl Iterator<Item = &str> {
142 NameIterator::new(self.subject_alt_name).filter_map(|result| {
143 let presented_id = match result.ok()? {
144 GeneralName::DnsName(presented) => presented,
145 _ => return None,
146 };
147
148 let dns_str = core::str::from_utf8(presented_id.as_slice_less_safe()).ok()?;
151 match DnsName::try_from(dns_str) {
152 Ok(_) => Some(dns_str),
153 Err(_) => {
154 match WildcardDnsNameRef::try_from_ascii(presented_id.as_slice_less_safe()) {
155 Ok(wildcard_dns_name) => Some(wildcard_dns_name.as_str()),
156 Err(_) => None,
157 }
158 }
159 }
160 })
161 }
162
163 pub fn serial(&self) -> &[u8] {
165 self.serial.as_slice_less_safe()
166 }
167
168 pub fn issuer(&self) -> &[u8] {
170 self.issuer.as_slice_less_safe()
171 }
172
173 pub fn subject(&self) -> &[u8] {
175 self.subject.as_slice_less_safe()
176 }
177
178 #[cfg(feature = "alloc")]
180 pub fn subject_public_key_info(&self) -> SubjectPublicKeyInfoDer<'static> {
181 SubjectPublicKeyInfoDer::from(der::asn1_wrap(
184 Tag::Sequence,
185 self.spki.as_slice_less_safe(),
186 ))
187 }
188
189 pub(crate) fn crl_distribution_points(
191 &self,
192 ) -> Option<impl Iterator<Item = Result<CrlDistributionPoint<'a>, Error>>> {
193 self.crl_distribution_points.map(DerIterator::new)
194 }
195
196 pub fn der(&self) -> CertificateDer<'a> {
198 self.der.clone() }
200}
201
202fn version3(input: &mut untrusted::Reader<'_>) -> Result<(), Error> {
205 der::nested(
206 input,
207 der::Tag::ContextSpecificConstructed0,
208 Error::UnsupportedCertVersion,
209 |input| {
210 let version = u8::from_der(input)?;
211 if version != 2 {
212 return Err(Error::UnsupportedCertVersion);
214 }
215 Ok(())
216 },
217 )
218}
219
220pub(crate) fn lenient_certificate_serial_number<'a>(
221 input: &mut untrusted::Reader<'a>,
222) -> Result<untrusted::Input<'a>, Error> {
223 der::expect_tag(input, Tag::Integer)
234}
235
236fn remember_cert_extension<'a>(
237 cert: &mut Cert<'a>,
238 extension: &Extension<'a>,
239) -> Result<(), Error> {
240 remember_extension(extension, |id| {
245 let out = match id {
246 15 => &mut cert.key_usage,
248
249 17 => &mut cert.subject_alt_name,
251
252 19 => &mut cert.basic_constraints,
254
255 30 => &mut cert.name_constraints,
257
258 31 => &mut cert.crl_distribution_points,
260
261 37 => &mut cert.eku,
263
264 _ => return extension.unsupported(),
266 };
267
268 set_extension_once(out, || {
269 extension.value.read_all(Error::BadDer, |value| match id {
270 15 => Ok(value.read_bytes_to_end()),
273 _ => der::expect_tag(value, Tag::Sequence),
275 })
276 })
277 })
278}
279
280pub(crate) struct CrlDistributionPoint<'a> {
285 distribution_point: Option<untrusted::Input<'a>>,
287
288 pub(crate) reasons: Option<der::BitStringFlags<'a>>,
291
292 pub(crate) crl_issuer: Option<untrusted::Input<'a>>,
295}
296
297impl<'a> CrlDistributionPoint<'a> {
298 pub(crate) fn names(&self) -> Result<Option<DistributionPointName<'a>>, Error> {
300 self.distribution_point
301 .map(|input| DistributionPointName::from_der(&mut untrusted::Reader::new(input)))
302 .transpose()
303 }
304}
305
306impl<'a> FromDer<'a> for CrlDistributionPoint<'a> {
307 fn from_der(reader: &mut untrusted::Reader<'a>) -> Result<Self, Error> {
308 let mut result = CrlDistributionPoint {
312 distribution_point: None,
313 reasons: None,
314 crl_issuer: None,
315 };
316
317 der::nested(
318 reader,
319 Tag::Sequence,
320 Error::TrailingData(Self::TYPE_ID),
321 |der| {
322 const DISTRIBUTION_POINT_TAG: u8 = CONTEXT_SPECIFIC | CONSTRUCTED;
323 const REASONS_TAG: u8 = CONTEXT_SPECIFIC | 1;
324 const CRL_ISSUER_TAG: u8 = CONTEXT_SPECIFIC | CONSTRUCTED | 2;
325
326 while !der.at_end() {
327 let (tag, value) = der::read_tag_and_get_value(der)?;
328 match tag {
329 DISTRIBUTION_POINT_TAG => {
330 set_extension_once(&mut result.distribution_point, || Ok(value))?
331 }
332 REASONS_TAG => set_extension_once(&mut result.reasons, || {
333 der::bit_string_flags(value)
334 })?,
335 CRL_ISSUER_TAG => set_extension_once(&mut result.crl_issuer, || Ok(value))?,
336 _ => return Err(Error::BadDer),
337 }
338 }
339
340 match (result.distribution_point, result.crl_issuer) {
344 (None, None) => Err(Error::MalformedExtensions),
345 _ => Ok(result),
346 }
347 },
348 )
349 }
350
351 const TYPE_ID: DerTypeId = DerTypeId::CrlDistributionPoint;
352}
353
354#[cfg(test)]
355mod tests {
356 use super::*;
357 #[cfg(feature = "alloc")]
358 use crate::crl::RevocationReason;
359 use std::prelude::v1::*;
360
361 #[test]
362 fn test_serial_read() {
366 let ee = include_bytes!("../tests/misc/serial_neg_ee.der");
367 let cert = Cert::from_der(untrusted::Input::from(ee)).expect("failed to parse certificate");
368 assert_eq!(cert.serial.as_slice_less_safe(), &[255, 33, 82, 65, 17]);
369
370 let ee = include_bytes!("../tests/misc/serial_large_positive.der");
371 let cert = Cert::from_der(untrusted::Input::from(ee)).expect("failed to parse certificate");
372 assert_eq!(
373 cert.serial.as_slice_less_safe(),
374 &[
375 0, 230, 9, 254, 122, 234, 0, 104, 140, 224, 36, 180, 237, 32, 27, 31, 239, 82, 180,
376 68, 209
377 ]
378 )
379 }
380
381 #[cfg(feature = "alloc")]
382 #[test]
383 fn test_spki_read() {
384 let ee = include_bytes!("../tests/ed25519/ee.der");
385 let cert = Cert::from_der(untrusted::Input::from(ee)).expect("failed to parse certificate");
386 let expected_spki = [
391 0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00, 0xfe, 0x5a,
392 0x1e, 0x36, 0x6c, 0x17, 0x27, 0x5b, 0xf1, 0x58, 0x1e, 0x3a, 0x0e, 0xe6, 0x56, 0x29,
393 0x8d, 0x9e, 0x1b, 0x3f, 0xd3, 0x3f, 0x96, 0x46, 0xef, 0xbf, 0x04, 0x6b, 0xc7, 0x3d,
394 0x47, 0x5c,
395 ];
396 assert_eq!(expected_spki, *cert.subject_public_key_info())
397 }
398
399 #[test]
400 #[cfg(feature = "alloc")]
401 fn test_crl_distribution_point_netflix() {
402 let ee = include_bytes!("../tests/netflix/ee.der");
403 let inter = include_bytes!("../tests/netflix/inter.der");
404 let ee_cert = Cert::from_der(untrusted::Input::from(ee)).expect("failed to parse EE cert");
405 let cert =
406 Cert::from_der(untrusted::Input::from(inter)).expect("failed to parse certificate");
407
408 assert!(ee_cert.crl_distribution_points.is_none());
410
411 let crl_distribution_points = cert
413 .crl_distribution_points()
414 .expect("missing distribution points extension")
415 .collect::<Result<Vec<_>, Error>>()
416 .expect("failed to parse distribution points");
417
418 assert_eq!(crl_distribution_points.len(), 1);
420 let crl_distribution_point = crl_distribution_points
421 .first()
422 .expect("missing distribution point");
423
424 assert!(crl_distribution_point.reasons.is_none());
426
427 assert!(crl_distribution_point.crl_issuer.is_none());
429
430 let distribution_point_name = crl_distribution_point
432 .names()
433 .expect("failed to parse distribution point names")
434 .expect("missing distribution point name");
435
436 let names = match distribution_point_name {
439 DistributionPointName::NameRelativeToCrlIssuer => {
440 panic!("unexpected name relative to crl issuer")
441 }
442 DistributionPointName::FullName(names) => names,
443 };
444
445 let names = names
447 .collect::<Result<Vec<_>, Error>>()
448 .expect("failed to parse general names");
449
450 assert_eq!(names.len(), 1);
452 let name = names.first().expect("missing general name");
453
454 match name {
456 GeneralName::UniformResourceIdentifier(uri) => {
457 assert_eq!(
458 uri.as_slice_less_safe(),
459 "http://s.symcb.com/pca3-g3.crl".as_bytes()
460 );
461 }
462 _ => panic!("unexpected general name type"),
463 }
464 }
465
466 #[test]
467 #[cfg(feature = "alloc")]
468 fn test_crl_distribution_point_with_reasons() {
469 let der = include_bytes!("../tests/crl_distrib_point/with_reasons.der");
470 let cert =
471 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
472
473 let crl_distribution_points = cert
475 .crl_distribution_points()
476 .expect("missing distribution points extension")
477 .collect::<Result<Vec<_>, Error>>()
478 .expect("failed to parse distribution points");
479
480 assert_eq!(crl_distribution_points.len(), 1);
482 let crl_distribution_point = crl_distribution_points
483 .first()
484 .expect("missing distribution point");
485
486 let reasons = crl_distribution_point
488 .reasons
489 .as_ref()
490 .expect("missing revocation reasons");
491 let expected = &[
492 RevocationReason::KeyCompromise,
493 RevocationReason::AffiliationChanged,
494 ];
495 for reason in RevocationReason::iter() {
496 #[allow(clippy::as_conversions)]
497 match expected.contains(&reason) {
499 true => assert!(reasons.bit_set(reason as usize)),
500 false => assert!(!reasons.bit_set(reason as usize)),
501 }
502 }
503 }
504
505 #[test]
506 #[cfg(feature = "alloc")]
507 fn test_crl_distribution_point_with_crl_issuer() {
508 let der = include_bytes!("../tests/crl_distrib_point/with_crl_issuer.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 assert!(crl_distribution_point.crl_issuer.is_some());
527 assert!(crl_distribution_point.distribution_point.is_none());
528 assert!(crl_distribution_point.reasons.is_none());
529 }
530
531 #[test]
532 #[cfg(feature = "alloc")]
533 fn test_crl_distribution_point_bad_der() {
534 let der = include_bytes!("../tests/crl_distrib_point/unknown_tag.der");
537 let cert =
538 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
539
540 let result = cert
543 .crl_distribution_points()
544 .expect("missing distribution points extension")
545 .collect::<Result<Vec<_>, Error>>();
546 assert!(matches!(result, Err(Error::BadDer)));
547 }
548
549 #[test]
550 #[cfg(feature = "alloc")]
551 fn test_crl_distribution_point_only_reasons() {
552 let der = include_bytes!("../tests/crl_distrib_point/only_reasons.der");
555 let cert =
556 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
557
558 let result = cert
561 .crl_distribution_points()
562 .expect("missing distribution points extension")
563 .collect::<Result<Vec<_>, Error>>();
564 assert!(matches!(result, Err(Error::MalformedExtensions)));
565 }
566
567 #[test]
568 #[cfg(feature = "alloc")]
569 fn test_crl_distribution_point_name_relative_to_issuer() {
570 let der = include_bytes!("../tests/crl_distrib_point/dp_name_relative_to_issuer.der");
571 let cert =
572 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
573
574 let crl_distribution_points = cert
576 .crl_distribution_points()
577 .expect("missing distribution points extension")
578 .collect::<Result<Vec<_>, Error>>()
579 .expect("failed to parse distribution points");
580
581 assert_eq!(crl_distribution_points.len(), 1);
583 let crl_distribution_point = crl_distribution_points
584 .first()
585 .expect("missing distribution point");
586
587 assert!(crl_distribution_point.crl_issuer.is_none());
588 assert!(crl_distribution_point.reasons.is_none());
589
590 let distribution_point_name = crl_distribution_point
592 .names()
593 .expect("failed to parse distribution point names")
594 .expect("missing distribution point name");
595
596 assert!(matches!(
598 distribution_point_name,
599 DistributionPointName::NameRelativeToCrlIssuer
600 ));
601 }
602
603 #[test]
604 #[cfg(feature = "alloc")]
605 fn test_crl_distribution_point_unknown_name_tag() {
606 let der = include_bytes!("../tests/crl_distrib_point/unknown_dp_name_tag.der");
609 let cert =
610 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
611
612 let crl_distribution_points = cert
614 .crl_distribution_points()
615 .expect("missing distribution points extension")
616 .collect::<Result<Vec<_>, Error>>()
617 .expect("failed to parse distribution points");
618
619 assert_eq!(crl_distribution_points.len(), 1);
621 let crl_distribution_point = crl_distribution_points
622 .first()
623 .expect("missing distribution point");
624
625 let result = crl_distribution_point.names();
627 assert!(matches!(result, Err(Error::BadDer)))
628 }
629
630 #[test]
631 #[cfg(feature = "alloc")]
632 fn test_crl_distribution_point_multiple() {
633 let der = include_bytes!("../tests/crl_distrib_point/multiple_distribution_points.der");
634 let cert =
635 Cert::from_der(untrusted::Input::from(der)).expect("failed to parse certificate");
636
637 let crl_distribution_points = cert
639 .crl_distribution_points()
640 .expect("missing distribution points extension")
641 .collect::<Result<Vec<_>, Error>>()
642 .expect("failed to parse distribution points");
643
644 let (point_a, point_b) = (
646 crl_distribution_points
647 .first()
648 .expect("missing first distribution point"),
649 crl_distribution_points
650 .get(1)
651 .expect("missing second distribution point"),
652 );
653
654 fn get_names<'a>(
655 point: &'a CrlDistributionPoint<'a>,
656 ) -> impl Iterator<Item = Result<GeneralName<'a>, Error>> {
657 match point
658 .names()
659 .expect("failed to parse distribution point names")
660 .expect("missing distribution point name")
661 {
662 DistributionPointName::NameRelativeToCrlIssuer => {
663 panic!("unexpected relative name")
664 }
665 DistributionPointName::FullName(names) => names,
666 }
667 }
668
669 fn uri_bytes<'a>(name: &'a GeneralName<'a>) -> &'a [u8] {
670 match name {
671 GeneralName::UniformResourceIdentifier(uri) => uri.as_slice_less_safe(),
672 _ => panic!("unexpected name type"),
673 }
674 }
675
676 let expected_names = [
678 "http://example.com/crl.1.der".as_bytes(),
679 "http://example.com/crl.2.der".as_bytes(),
680 "http://example.com/crl.3.der".as_bytes(),
681 ];
682 let all_names = get_names(point_a)
683 .chain(get_names(point_b))
684 .collect::<Result<Vec<_>, Error>>()
685 .expect("failed to parse names");
686
687 assert_eq!(
688 all_names.iter().map(uri_bytes).collect::<Vec<_>>(),
689 expected_names
690 );
691 }
692}