structured_pkix/extension/
entry.rs1use crate::error::{CallbackError, CallbackResult, Error, ErrorCode, Located, Result};
4use structured_asn1::{Element, Oid, Reader, Span, Tag, universal};
5
6#[derive(Debug, Clone, Copy)]
14pub struct ExtensionHeader<'a> {
15 kind: Oid<'a>,
16 critical: bool,
17 critical_span: Option<Span>,
18 span: Span,
19}
20
21impl<'a> ExtensionHeader<'a> {
22 #[must_use]
24 pub fn kind(self) -> Oid<'a> {
25 self.kind
26 }
27
28 #[must_use]
30 pub fn is_critical(self) -> bool {
31 self.critical
32 }
33
34 #[must_use]
36 pub fn critical_span(self) -> Option<Span> {
37 self.critical_span
38 }
39
40 #[must_use]
42 pub fn span(self) -> Span {
43 self.span
44 }
45
46 #[must_use]
48 pub fn default_written(self) -> bool {
49 self.critical_span.is_some() && !self.critical
50 }
51}
52
53#[derive(Debug)]
55pub struct ExtensionValue<'a, V> {
56 header: ExtensionHeader<'a>,
57 value: V,
58 trailing_span: Option<Span>,
59}
60
61impl<'a, V> ExtensionValue<'a, V> {
62 #[must_use]
64 pub fn header(&self) -> ExtensionHeader<'a> {
65 self.header
66 }
67
68 #[must_use]
70 pub fn value(&self) -> &V {
71 &self.value
72 }
73
74 #[must_use]
76 pub fn trailing_span(&self) -> Option<Span> {
77 self.trailing_span
78 }
79
80 #[must_use]
82 pub fn into_value(self) -> V {
83 self.value
84 }
85}
86
87pub fn read_with<'a, V, E>(
103 parent: &Reader<'a>,
104 element: &Element<'a>,
105 field: &'static str,
106 read_value: impl FnOnce(
107 &ExtensionHeader<'a>,
108 &Reader<'a>,
109 &Element<'a>,
110 ) -> core::result::Result<V, E>,
111) -> CallbackResult<ExtensionValue<'a, V>, E> {
112 open(parent, element, field)?.read_with(read_value)
113}
114
115pub struct ExtensionFields<'a> {
121 header: ExtensionHeader<'a>,
122 inside: Reader<'a>,
123 pending: ValueState<'a>,
124 field: &'static str,
125}
126
127enum ValueState<'a> {
128 Read(Option<Element<'a>>),
129 Deferred,
130}
131
132impl<'a> ExtensionFields<'a> {
133 #[must_use]
135 pub fn header(&self) -> ExtensionHeader<'a> {
136 self.header
137 }
138
139 #[must_use]
141 pub fn reader(&self) -> &Reader<'a> {
142 &self.inside
143 }
144
145 pub fn read_with<V, E>(
150 mut self,
151 read_value: impl FnOnce(
152 &ExtensionHeader<'a>,
153 &Reader<'a>,
154 &Element<'a>,
155 ) -> core::result::Result<V, E>,
156 ) -> CallbackResult<ExtensionValue<'a, V>, E> {
157 let value = match self.pending {
158 ValueState::Read(value) => value,
159 ValueState::Deferred => self.inside.next_element().field(self.field)?,
160 }
161 .ok_or_else(|| Error::new(ErrorCode::MissingField, self.field, self.header.span.start))?;
162 if value.tag() != Tag::primitive(universal::OCTET_STRING)
163 && value.tag() != Tag::constructed(universal::OCTET_STRING)
164 {
165 return Err(Error::new(
166 ErrorCode::Encoding(structured_asn1::ErrorCode::UnexpectedTag),
167 self.field,
168 value.span().start,
169 )
170 .into());
171 }
172 let trailing_span = if self.inside.is_empty() {
173 None
174 } else {
175 Some(Span {
176 start: self.inside.offset(),
177 length: self.inside.remaining().len() as u64,
178 })
179 };
180 let decoded =
181 read_value(&self.header, &self.inside, &value).map_err(CallbackError::Callback)?;
182 Ok(ExtensionValue {
183 header: self.header,
184 value: decoded,
185 trailing_span,
186 })
187 }
188}
189
190pub fn open<'a>(
194 parent: &Reader<'a>,
195 element: &Element<'a>,
196 field: &'static str,
197) -> Result<ExtensionFields<'a>> {
198 let fail = |code, offset| Error::new(code, field, offset);
199 if element.tag() != Tag::constructed(universal::SEQUENCE) {
200 return Err(fail(
201 ErrorCode::Encoding(structured_asn1::ErrorCode::UnexpectedTag),
202 element.span().start,
203 ));
204 }
205 let mut inside = parent.enter(element).field(field)?;
206 let kind = inside.read_oid().field(field)?;
207 let value = inside.next_element().field(field)?;
208 let mut pending = ValueState::Read(value);
209 let mut critical_span = None;
210 let mut critical = false;
211 if let Some(flag) = value
212 && flag.tag() == Tag::primitive(universal::BOOLEAN)
213 {
214 critical = inside.boolean(&flag).field(field)?;
215 critical_span = Some(flag.span());
216 pending = ValueState::Deferred;
219 }
220 Ok(ExtensionFields {
221 header: ExtensionHeader {
222 kind,
223 critical,
224 critical_span,
225 span: element.span(),
226 },
227 inside,
228 pending,
229 field,
230 })
231}