1use crate::der::{self, CONSTRUCTED, CONTEXT_SPECIFIC, DerIterator, FromDer};
16use crate::error::{DerTypeId, Error};
17use crate::subject_name::GeneralName;
18
19pub(crate) struct Extension<'a> {
20 pub(crate) critical: bool,
21 pub(crate) id: untrusted::Input<'a>,
22 pub(crate) value: untrusted::Input<'a>,
23}
24
25impl Extension<'_> {
26 pub(crate) fn unsupported(&self, policy: UnknownExtensionPolicy) -> Result<(), Error> {
27 match (policy, self.critical) {
28 (UnknownExtensionPolicy::Strict, true) => Err(Error::UnsupportedCriticalExtension),
29 _ => Ok(()),
30 }
31 }
32}
33
34impl<'a> FromDer<'a> for Extension<'a> {
35 fn from_der(reader: &mut untrusted::Reader<'a>) -> Result<Self, Error> {
36 let id = der::expect_tag(reader, der::Tag::OID)?;
37 let critical = bool::from_der(reader)?;
38 let value = der::expect_tag(reader, der::Tag::OctetString)?;
39 Ok(Extension {
40 id,
41 critical,
42 value,
43 })
44 }
45
46 const TYPE_ID: DerTypeId = DerTypeId::Extension;
47}
48
49pub(crate) fn set_extension_once<T>(
50 destination: &mut Option<T>,
51 parser: impl Fn() -> Result<T, Error>,
52) -> Result<(), Error> {
53 match destination {
54 Some(..) => Err(Error::ExtensionValueInvalid),
57 None => {
58 *destination = Some(parser()?);
59 Ok(())
60 }
61 }
62}
63
64pub(crate) fn remember_extension(
65 extension: &Extension<'_>,
66 ext_policy: UnknownExtensionPolicy,
67 mut handler: impl FnMut(u8) -> Result<(), Error>,
68) -> Result<(), Error> {
69 static ID_CE: [u8; 2] = oid![2, 5, 29];
72
73 if extension.id.len() != ID_CE.len() + 1
74 || !extension.id.as_slice_less_safe().starts_with(&ID_CE)
75 {
76 return extension.unsupported(ext_policy);
77 }
78
79 let last_octet = *extension.id.as_slice_less_safe().last().unwrap();
81 handler(last_octet)
82}
83
84#[derive(Clone, Copy, Debug, Default)]
85pub(crate) enum UnknownExtensionPolicy {
86 #[default]
87 Strict,
88 IgnoreCritical,
89}
90
91pub(crate) enum DistributionPointName<'a> {
96 NameRelativeToCrlIssuer,
98 FullName(DerIterator<'a, GeneralName<'a>>),
100}
101
102impl<'a> FromDer<'a> for DistributionPointName<'a> {
103 fn from_der(reader: &mut untrusted::Reader<'a>) -> Result<Self, Error> {
104 const FULL_NAME_TAG: u8 = CONTEXT_SPECIFIC | CONSTRUCTED;
108 const NAME_RELATIVE_TO_CRL_ISSUER_TAG: u8 = CONTEXT_SPECIFIC | CONSTRUCTED | 1;
109
110 let (tag, value) = der::read_tag_and_get_value(reader)?;
111 match tag {
112 FULL_NAME_TAG => Ok(DistributionPointName::FullName(DerIterator::new(value))),
113 NAME_RELATIVE_TO_CRL_ISSUER_TAG => Ok(DistributionPointName::NameRelativeToCrlIssuer),
114 _ => Err(Error::BadDer),
115 }
116 }
117
118 const TYPE_ID: DerTypeId = DerTypeId::DistributionPointName;
119}