structured_pkix/extension/
entry.rs1use crate::error::{CallbackError, CallbackResult, Error, ErrorCode, Located, Result};
4use structured_asn1::{Element, Oid, ScopedReader, 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: 'operation, 'operation, V, E>(
103 parent: &ScopedReader<'a, 'operation>,
104 element: &Element<'a>,
105 field: &'static str,
106 read_value: impl FnOnce(
107 &ExtensionHeader<'a>,
108 &ScopedReader<'a, 'operation>,
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 ScopedExtensionFields<'a: 'operation, 'operation> {
121 header: ExtensionHeader<'a>,
122 inside: ScopedReader<'a, 'operation>,
123 pending: ValueState<'a>,
124 field: &'static str,
125}
126
127pub type ExtensionFields<'a> = ScopedExtensionFields<'a, 'a>;
129
130enum ValueState<'a> {
131 Read(Option<Element<'a>>),
132 Deferred,
133}
134
135impl<'a: 'operation, 'operation> ScopedExtensionFields<'a, 'operation> {
136 #[must_use]
138 pub fn header(&self) -> ExtensionHeader<'a> {
139 self.header
140 }
141
142 #[must_use]
144 pub fn reader(&self) -> &ScopedReader<'a, 'operation> {
145 &self.inside
146 }
147
148 pub fn read_with<V, E>(
153 mut self,
154 read_value: impl FnOnce(
155 &ExtensionHeader<'a>,
156 &ScopedReader<'a, 'operation>,
157 &Element<'a>,
158 ) -> core::result::Result<V, E>,
159 ) -> CallbackResult<ExtensionValue<'a, V>, E> {
160 let value = match self.pending {
161 ValueState::Read(value) => value,
162 ValueState::Deferred => self.inside.next_element().field(self.field)?,
163 }
164 .ok_or_else(|| Error::new(ErrorCode::MissingField, self.field, self.header.span.start))?;
165 if value.tag() != Tag::primitive(universal::OCTET_STRING)
166 && value.tag() != Tag::constructed(universal::OCTET_STRING)
167 {
168 return Err(Error::new(
169 ErrorCode::Encoding(structured_asn1::ErrorCode::UnexpectedTag),
170 self.field,
171 value.span().start,
172 )
173 .into());
174 }
175 let trailing_span = if self.inside.is_empty() {
176 None
177 } else {
178 Some(Span {
179 start: self.inside.offset(),
180 length: self.inside.remaining().len() as u64,
181 })
182 };
183 let decoded =
184 read_value(&self.header, &self.inside, &value).map_err(CallbackError::Callback)?;
185 Ok(ExtensionValue {
186 header: self.header,
187 value: decoded,
188 trailing_span,
189 })
190 }
191}
192
193pub fn open<'a: 'operation, 'operation>(
197 parent: &ScopedReader<'a, 'operation>,
198 element: &Element<'a>,
199 field: &'static str,
200) -> Result<ScopedExtensionFields<'a, 'operation>> {
201 let fail = |code, offset| Error::new(code, field, offset);
202 if element.tag() != Tag::constructed(universal::SEQUENCE) {
203 return Err(fail(
204 ErrorCode::Encoding(structured_asn1::ErrorCode::UnexpectedTag),
205 element.span().start,
206 ));
207 }
208 let mut inside = parent.enter(element).field(field)?;
209 let kind = inside.read_oid().field(field)?;
210 let value = inside.next_element().field(field)?;
211 let mut pending = ValueState::Read(value);
212 let mut critical_span = None;
213 let mut critical = false;
214 if let Some(flag) = value
215 && flag.tag() == Tag::primitive(universal::BOOLEAN)
216 {
217 critical = inside.boolean(&flag).field(field)?;
218 critical_span = Some(flag.span());
219 pending = ValueState::Deferred;
222 }
223 Ok(ScopedExtensionFields {
224 header: ExtensionHeader {
225 kind,
226 critical,
227 critical_span,
228 span: element.span(),
229 },
230 inside,
231 pending,
232 field,
233 })
234}