1use crate::{Error, ErrorCode, Result};
4use structured_asn1::memory::{OwnedVec, Work};
5use structured_asn1::{Element, Parser, Reader, Span, Tag, universal};
6
7#[derive(Debug, Clone, Copy)]
9pub struct Piece<'a> {
10 bytes: &'a [u8],
11 span: Span,
12}
13
14impl<'a> Piece<'a> {
15 #[must_use]
17 pub fn as_bytes(self) -> &'a [u8] {
18 self.bytes
19 }
20
21 #[must_use]
23 pub fn span(self) -> Span {
24 self.span
25 }
26}
27
28#[derive(Debug)]
29enum Storage<'a> {
30 One([Piece<'a>; 1]),
31 Many(OwnedVec<Piece<'a>>),
32}
33
34#[derive(Debug)]
40pub struct Octets<'a> {
41 parser: &'a Parser,
42 outer_depth: u32,
43 carrier: Span,
44 contents: Span,
45 storage: Storage<'a>,
46 length: usize,
47 field: &'static str,
48}
49
50impl<'a> Octets<'a> {
51 pub fn read_ia5(
57 parent: &Reader<'a>,
58 element: &Element<'a>,
59 field: &'static str,
60 ) -> Result<Self> {
61 parent
62 .charge(1)
63 .map_err(|cause| Error::encoding(cause, field))?;
64 let value = Self::read_tagged(parent, element, universal::IA5_STRING, false, field)?;
65 let execution = parent.execution();
66 for piece in value.pieces() {
67 execution
68 .charge_work(1 + piece.as_bytes().len() as u64)
69 .map_err(|cause| Error::resource(cause, field, piece.span().start))?;
70 if !piece.as_bytes().is_ascii() {
71 return Err(Error::schema(
72 ErrorCode::MalformedValue,
73 field,
74 piece.span().start,
75 ));
76 }
77 }
78 Ok(value)
79 }
80
81 pub fn read(parent: &Reader<'a>, element: &Element<'a>, field: &'static str) -> Result<Self> {
89 Self::read_tagged(parent, element, universal::OCTET_STRING, false, field)
90 }
91
92 pub(crate) fn read_identifier(
97 parent: &Reader<'a>,
98 element: &Element<'a>,
99 field: &'static str,
100 ) -> Result<Self> {
101 Self::read_tagged(parent, element, 0, true, field)
102 }
103
104 pub(crate) fn projection_string(
108 parent: &structured_asn1::ScopedReader<'a, '_>,
109 element: &Element<'a>,
110 number: u32,
111 context: bool,
112 field: &'static str,
113 ) -> Result<Self> {
114 if !context {
115 structured_pkix::der::conforms(parent, element, field).map_err(Error::pkix)?;
116 }
117 Self::read_tagged(parent, element, number, context, field)
118 }
119
120 fn read_tagged(
121 parent: &structured_asn1::ScopedReader<'a, '_>,
122 element: &Element<'a>,
123 outer_number: u32,
124 context: bool,
125 field: &'static str,
126 ) -> Result<Self> {
127 let primitive = if context {
128 Tag::context(false, outer_number)
129 } else {
130 Tag::primitive(outer_number)
131 };
132 let constructed = if context {
133 Tag::context(true, outer_number)
134 } else {
135 Tag::constructed(outer_number)
136 };
137 if element.tag() == primitive {
138 return Ok(Self {
139 parser: parent.parser(),
140 outer_depth: parent.depth(),
141 carrier: element.span(),
142 contents: element.contents_span(),
143 storage: Storage::One([Piece {
144 bytes: element.contents(),
145 span: element.contents_span(),
146 }]),
147 length: element.contents().len(),
148 field,
149 });
150 }
151 if element.tag() != constructed {
152 return Err(Error::schema(
153 ErrorCode::UnexpectedTag,
154 field,
155 element.span().start,
156 ));
157 }
158 if parent.encoding().is_der() {
159 return Err(Error::schema(
160 ErrorCode::UnexpectedTag,
161 field,
162 element.span().start,
163 ));
164 }
165 let execution = parent.execution();
166 let mut pieces = execution.vector();
167 let mut frames = execution.vector();
168 frames
169 .try_push(
170 parent
171 .enter(element)
172 .map_err(|error| Error::encoding(error, field))?,
173 )
174 .map_err(|reason| Error::resource(reason, field, element.span().start))?;
175 let mut length = 0_usize;
176 while let Some(reader) = frames.last_mut() {
177 let Some(child) = reader
178 .next_element()
179 .map_err(|error| Error::encoding(error, field))?
180 else {
181 frames.pop();
182 continue;
183 };
184 if child.tag() == Tag::primitive(universal::OCTET_STRING) {
191 length = length.checked_add(child.contents().len()).ok_or_else(|| {
192 Error::schema(ErrorCode::LengthOverflow, field, child.span().start)
193 })?;
194 pieces
195 .try_push(Piece {
196 bytes: child.contents(),
197 span: child.contents_span(),
198 })
199 .map_err(|reason| Error::resource(reason, field, child.span().start))?;
200 } else if child.tag() == Tag::constructed(universal::OCTET_STRING) {
201 let nested = reader
202 .enter(&child)
203 .map_err(|error| Error::encoding(error, field))?;
204 frames
205 .try_push(nested)
206 .map_err(|reason| Error::resource(reason, field, child.span().start))?;
207 } else {
208 return Err(Error::schema(
209 ErrorCode::UnexpectedTag,
210 field,
211 child.span().start,
212 ));
213 }
214 }
215 Ok(Self {
216 parser: parent.parser(),
217 outer_depth: parent.depth(),
218 carrier: element.span(),
219 contents: element.contents_span(),
220 storage: Storage::Many(pieces.into_owned()),
221 length,
222 field,
223 })
224 }
225
226 #[must_use]
228 pub fn pieces(&self) -> &[Piece<'a>] {
229 match &self.storage {
230 Storage::One(piece) => piece,
231 Storage::Many(pieces) => pieces,
232 }
233 }
234
235 #[must_use]
237 pub fn len(&self) -> usize {
238 self.length
239 }
240
241 #[must_use]
243 pub fn is_empty(&self) -> bool {
244 self.length == 0
245 }
246
247 #[must_use]
249 pub fn span(&self) -> Span {
250 self.carrier
251 }
252
253 pub(crate) fn content_span(&self) -> Span {
254 self.contents
255 }
256
257 pub(crate) fn outer_depth(&self) -> u32 {
258 self.outer_depth
259 }
260
261 pub(crate) fn parser(&self) -> &'a Parser {
262 self.parser
263 }
264
265 #[must_use]
267 pub fn as_one(&self) -> Option<&'a [u8]> {
268 match self.pieces() {
269 [piece] => Some(piece.bytes),
270 _ => None,
271 }
272 }
273
274 pub fn copy_in(
284 &self,
285 parent: &Reader<'_>,
286 field: &'static str,
287 at: u64,
288 ) -> Result<OwnedVec<u8>> {
289 if !core::ptr::eq(self.parser, parent.parser()) {
290 return Err(Error::pkix(structured_pkix::Error::new(
291 structured_pkix::ErrorCode::ForeignReader,
292 field,
293 at,
294 )));
295 }
296 let execution = parent.execution();
297 let refusal = |reason| Error::resource(reason, field, at);
298 execution
299 .charge_work(self.pieces().len() as u64)
300 .map_err(refusal)?;
301 let mut output = execution.vector();
302 output.try_reserve_exact(self.length).map_err(refusal)?;
304 for piece in self.pieces() {
305 output.try_extend_from_slice(piece.bytes).map_err(refusal)?;
306 }
307 Ok(output.into_owned())
308 }
309
310 pub(crate) fn same_value(
311 &self,
312 other: &Octets<'_>,
313 parent: &Reader<'_>,
314 field: &'static str,
315 at: u64,
316 ) -> Result<bool> {
317 let execution = parent.execution();
318 execution
319 .charge_work(1)
320 .map_err(|reason| Error::resource(reason, field, at))?;
321 if self.length != other.length {
322 return Ok(false);
323 }
324 for amount in [self.pieces().len(), other.pieces().len(), self.length] {
325 execution
326 .charge_work(amount as u64)
327 .map_err(|reason| Error::resource(reason, field, at))?;
328 }
329 Ok(self
330 .pieces()
331 .iter()
332 .flat_map(|piece| piece.bytes.iter())
333 .eq(other.pieces().iter().flat_map(|piece| piece.bytes.iter())))
334 }
335}
336
337#[derive(Debug)]
339pub enum SourceError {
340 Processing(Error),
342 Receiver(crate::stream::Refused),
344}
345
346impl crate::stream::Source for &Octets<'_> {
347 type Error = SourceError;
348
349 fn stream<W: Work>(
350 &mut self,
351 receiver: &mut impl crate::stream::Receiver,
352 execution: &W,
353 ) -> core::result::Result<(), Self::Error> {
354 for piece in self.pieces() {
355 execution.charge_work(1).map_err(|reason| {
356 SourceError::Processing(Error::resource(reason, self.field, piece.span.start))
357 })?;
358 receiver.write(piece.bytes).map_err(SourceError::Receiver)?;
359 }
360 Ok(())
361 }
362}