structured_asn1/reader.rs
1//! Reading elements in sequence, and descending into the constructed ones.
2//!
3//! Three invariants hold throughout. Nothing copies the document: elements
4//! borrow it and carry the range they occupy. Nothing recurses: depth is
5//! bounded by the caller's budget rather than by the stack. An element carries
6//! no path; the path belongs to the reader that produced it.
7
8use crate::error::{Error, ErrorCode, Limit, Path, Result};
9use crate::length::{self, Encoding, Length};
10use crate::limits::{Budget, Limits};
11use crate::memory::{Memory, Work};
12use crate::tag::{self, Tag, universal};
13use crate::value::{self, BitString, Integer, Oid};
14
15mod integer;
16pub use integer::IntegerReading;
17
18/// Holds the budget for one parse and hands out readers that share it.
19#[derive(Debug)]
20pub struct Parser {
21 budget: Budget,
22 encoding: Encoding,
23}
24
25impl Parser {
26 /// A parser for one document, in one encoding, with one budget.
27 #[must_use]
28 pub fn new(encoding: Encoding, limits: Limits, memory: Memory) -> Self {
29 Self {
30 budget: Budget::new(limits, memory),
31 encoding,
32 }
33 }
34
35 /// A parser for DER, with the default budget.
36 #[must_use]
37 pub fn der(memory: Memory) -> Self {
38 Self::new(Encoding::Der, Limits::default(), memory)
39 }
40
41 /// A parser that also accepts the BER forms CMS permits.
42 #[must_use]
43 pub fn ber(memory: Memory) -> Self {
44 Self::new(Encoding::Ber, Limits::default(), memory)
45 }
46
47 /// The limits this parser was given.
48 #[must_use]
49 pub fn limits(&self) -> Limits {
50 self.budget.limits()
51 }
52
53 /// The aggregate account shared with other parsers and retained results.
54 ///
55 /// `Limits.max_work` additionally bounds this parser's scanning, not later
56 /// owned-result processing. Memory's cumulative work bounds the whole domain.
57 #[must_use]
58 pub fn memory(&self) -> &Memory {
59 self.budget.memory()
60 }
61
62 /// A reader over `data`, whose first byte sits at `base` in the document.
63 ///
64 /// `base` is what makes an error's offset and an element's span mean
65 /// something to a caller holding a whole document while handing this parser
66 /// a window into it.
67 ///
68 /// Refused when the end of `data` would not fit an offset. Checking that
69 /// here is what lets every offset computed while reading be ordinary
70 /// arithmetic: each is at most `base + data.len()`.
71 pub fn read<'a>(&'a self, data: &'a [u8], base: u64) -> Result<Reader<'a>> {
72 self.read_as(data, base, self.encoding)
73 }
74
75 /// A reader over `data` under a chosen encoding, sharing this parser's
76 /// budget.
77 ///
78 /// For a window whose schema fixes its encoding regardless of what this
79 /// parser was built for: the value of a certificate extension is DER even
80 /// when the parser was made lenient for the envelope the certificate
81 /// arrived in.
82 pub fn read_as<'a>(
83 &'a self,
84 data: &'a [u8],
85 base: u64,
86 encoding: Encoding,
87 ) -> Result<Reader<'a>> {
88 self.read_as_in(data, base, encoding, self.memory())
89 }
90
91 fn read_as_in<'a>(
92 &'a self,
93 data: &'a [u8],
94 base: u64,
95 encoding: Encoding,
96 execution: &Memory,
97 ) -> Result<Reader<'a>> {
98 u64::try_from(data.len())
99 .ok()
100 .and_then(|length| base.checked_add(length))
101 .ok_or_else(|| Error::new(ErrorCode::OffsetTooLarge, base, Path::default()))?;
102
103 Ok(Reader {
104 data,
105 pos: 0,
106 base,
107 depth: 0,
108 next_index: 0,
109 path: Path::default(),
110 encoding,
111 parser: self,
112 execution: execution.clone(),
113 })
114 }
115
116 /// A reader over bytes another element carries as its value, one level
117 /// below the reader that element was found in.
118 ///
119 /// For an encoding wrapped in a primitive, an octet string above all: a
120 /// certificate extension's value, a signed message's content. `outer` is
121 /// [`Reader::depth`] of the reader the carrying element came from. A
122 /// reader made with [`Parser::read_as`] would count the wrapped structure
123 /// from the top again, and a caller's depth ceiling would bound each
124 /// wrapping rather than the document.
125 ///
126 /// # Errors
127 ///
128 /// [`ErrorCode::LimitExceeded`] where the level is past the depth
129 /// ceiling, and what [`Parser::read_as`] refuses.
130 pub fn read_nested<'a>(
131 &'a self,
132 data: &'a [u8],
133 base: u64,
134 encoding: Encoding,
135 outer: u32,
136 ) -> Result<Reader<'a>> {
137 self.read_nested_in(data, base, encoding, outer, self.memory())
138 }
139
140 /// Nested lazy reader using the current execution domain from creation.
141 ///
142 /// Original offsets, depth and this parser session's cumulative ceilings
143 /// remain in force. New storage and deferred work use `execution`.
144 pub fn read_nested_in<'a>(
145 &'a self,
146 data: &'a [u8],
147 base: u64,
148 encoding: Encoding,
149 outer: u32,
150 execution: &Memory,
151 ) -> Result<Reader<'a>> {
152 let mut reader = self.read_as_in(data, base, encoding, execution)?;
153 let depth = outer.checked_add(1).ok_or_else(|| {
154 Error::new(
155 ErrorCode::LimitExceeded(Limit::Depth),
156 base,
157 Path::default(),
158 )
159 })?;
160 self.budget
161 .depth(depth)
162 .map_err(|limit| Error::new(ErrorCode::LimitExceeded(limit), base, Path::default()))?;
163 reader.depth = depth;
164 Ok(reader)
165 }
166}
167
168/// Where in a document one run of bytes sits.
169#[derive(Debug, Clone, Copy, PartialEq, Eq)]
170pub struct Span {
171 /// Offset of the first byte, counted in the whole document.
172 pub start: u64,
173 /// How many bytes.
174 pub length: u64,
175}
176
177impl Span {
178 /// The offset just past the last byte.
179 ///
180 /// Ordinary arithmetic: a span is only ever built by a reader, which
181 /// refuses a window whose end does not fit an offset, so `start + length`
182 /// has already been shown to fit.
183 #[must_use]
184 pub fn end(self) -> u64 {
185 self.start + self.length
186 }
187}
188
189/// One element, as it was found.
190#[derive(Debug, Clone, Copy)]
191pub struct Element<'a> {
192 tag: Tag,
193 contents: &'a [u8],
194 bytes: &'a [u8],
195 contents_span: Span,
196 whole: Span,
197 indefinite: bool,
198 index: u32,
199}
200
201impl<'a> Element<'a> {
202 /// What kind of element this is.
203 #[must_use]
204 pub fn tag(self) -> Tag {
205 self.tag
206 }
207
208 /// The contents, borrowed from the document.
209 ///
210 /// For an indefinite-length element this is everything up to but not
211 /// including the end-of-contents marker.
212 #[must_use]
213 pub fn contents(self) -> &'a [u8] {
214 self.contents
215 }
216
217 /// The whole element as it arrived, header included.
218 ///
219 /// What a signature is computed over wherever a schema says the signature
220 /// covers an element as encoded, and what identity is compared on wherever
221 /// a schema says two structures are the same one when their bytes are.
222 /// Handing these back rather than re-encoding what was understood is the
223 /// difference between checking a signature over the document somebody was
224 /// sent and checking it over this parser's opinion of that document.
225 #[must_use]
226 pub fn as_bytes(self) -> &'a [u8] {
227 self.bytes
228 }
229
230 /// Where the contents sit in the document.
231 #[must_use]
232 pub fn contents_span(self) -> Span {
233 self.contents_span
234 }
235
236 /// Where the whole element sits, header included.
237 ///
238 /// This is the range a signature is computed over wherever a schema says
239 /// the signature covers an element as encoded.
240 #[must_use]
241 pub fn span(self) -> Span {
242 self.whole
243 }
244
245 /// Whether the length was written in the indefinite form.
246 #[must_use]
247 pub fn is_indefinite(self) -> bool {
248 self.indefinite
249 }
250
251 /// Its position among the elements of the container it was read from.
252 #[must_use]
253 pub fn index(self) -> u32 {
254 self.index
255 }
256}
257
258/// Reads the elements of one container, in order.
259///
260/// Cloning one keeps where it is and how deep it sits, so a caller that has to
261/// come back to a container later can put the reader aside rather than start
262/// again from the document and count the nesting as one.
263#[derive(Debug)]
264pub struct Reader<'a> {
265 data: &'a [u8],
266 pos: usize,
267 base: u64,
268 depth: u32,
269 next_index: u32,
270 path: Path,
271 encoding: Encoding,
272 parser: &'a Parser,
273 execution: Memory,
274}
275
276impl<'a> Reader<'a> {
277 /// Current domain for deferred work, copies and new storage.
278 #[must_use]
279 pub fn memory(&self) -> &Memory {
280 &self.execution
281 }
282
283 /// Borrows both the current account and original cumulative work ceiling.
284 ///
285 /// Schema scratch must use this boundary when work belongs to the parse:
286 /// allocator growth, copying and sorting then retain the session ceiling
287 /// as well as the aggregate account. Independently retained results use
288 /// [`Self::memory`] instead.
289 ///
290 /// # Examples
291 ///
292 /// ```
293 /// use std::sync::Arc;
294 /// use structured_asn1::{Parser, memory::{Memory, MemoryAccount, Work}};
295 /// let parser = Parser::ber(Memory::new(Arc::new(MemoryAccount::new(1024, 1024))));
296 /// let reader = parser.read(&[], 900).unwrap();
297 /// let mut scratch = reader.execution().vector();
298 /// scratch.try_push(7_u8)?;
299 /// assert_eq!(&*scratch, &[7]);
300 /// # Ok::<(), structured_asn1::memory::MemoryError>(())
301 /// ```
302 #[must_use]
303 pub fn execution(&self) -> crate::memory::Execution<'_> {
304 crate::memory::Execution::new(self.memory(), self.budget())
305 }
306
307 /// Selects the domain for subsequent execution without moving existing
308 /// storage charges. Offsets, depth and parser-session cumulative limits
309 /// remain unchanged; a new domain does not reset that session ceiling.
310 #[must_use]
311 pub fn with_execution(mut self, execution: &Memory) -> Self {
312 self.execution = execution.clone();
313 self
314 }
315
316 /// Copies the reader position and diagnostic path fallibly in the same domain.
317 pub fn try_clone(&self) -> Result<Self> {
318 self.admit_path(0)
319 .map_err(|reason| Error::resource(reason, self.offset()))?;
320 Ok(Self {
321 data: self.data,
322 pos: self.pos,
323 base: self.base,
324 depth: self.depth,
325 next_index: self.next_index,
326 path: self
327 .path
328 .try_copy_in(self.memory())
329 .map_err(|reason| Error::resource(reason, self.offset()))?,
330 encoding: self.encoding,
331 parser: self.parser,
332 execution: self.execution.clone(),
333 })
334 }
335 /// Whether every element here has been read.
336 #[must_use]
337 pub fn is_empty(&self) -> bool {
338 self.pos >= self.data.len()
339 }
340
341 /// Original parser, whose session ceilings remain cumulative across
342 /// deferred reads. Use [`Self::memory`] for the current execution domain;
343 /// the parser's storage domain may belong to an earlier operation.
344 #[must_use]
345 pub fn parser(&self) -> &'a Parser {
346 self.parser
347 }
348
349 /// The shared budget, by way of the parser.
350 fn budget(&self) -> &'a Budget {
351 &self.parser.budget
352 }
353
354 /// Charges caller-side scanning to the shared work budget.
355 ///
356 /// For a schema layer that walks an element's contents itself, text
357 /// validation and named-bit walks among them: the walk costs what the
358 /// bytes cost, and a caller bounding work must see that cost on the
359 /// same meter the reads use.
360 pub fn charge(&self, amount: u64) -> Result<()> {
361 self.budget()
362 .work_in(amount, self.memory())
363 .map_err(|limit| self.fail_at(ErrorCode::LimitExceeded(limit), self.offset()))
364 }
365
366 /// How many containers deep this reader sits, counted as the depth
367 /// ceiling counts it. What [`Parser::read_nested`] is given for a value
368 /// found here.
369 #[must_use]
370 pub fn depth(&self) -> u32 {
371 self.depth
372 }
373
374 /// The offset of the next unread byte, in the document.
375 ///
376 /// Ordinary arithmetic, because `pos` never exceeds the length of `data`
377 /// and `base` plus that length was shown to fit when this reader was made.
378 #[must_use]
379 pub fn offset(&self) -> u64 {
380 self.base + self.pos as u64
381 }
382
383 /// The bytes not yet read.
384 #[must_use]
385 pub fn remaining(&self) -> &'a [u8] {
386 &self.data[self.pos.min(self.data.len())..]
387 }
388
389 /// The path to this container, for a caller building its own diagnostics.
390 #[must_use]
391 pub fn path(&self) -> &Path {
392 &self.path
393 }
394
395 /// Which encoding this reader accepts, for a schema whose own rules
396 /// differ between the two, such as the ordering DER requires of a set.
397 #[must_use]
398 pub fn encoding(&self) -> Encoding {
399 self.encoding
400 }
401
402 /// A reader over an element's own bytes, header included, under a chosen
403 /// encoding.
404 ///
405 /// For a structure whose schema fixes its encoding regardless of the
406 /// container's: a certificate is DER even when the envelope carrying it
407 /// is BER, and reading it with the container's leniency would let
408 /// spellings survive that the certificate's own rules refuse. The
409 /// element's header is read again under the chosen rules, so a header
410 /// only the lenient encoding accepts is refused too. Offsets stay offsets
411 /// in the document and the budget stays the shared one.
412 pub fn reread(&self, element: &Element<'a>, encoding: Encoding) -> Result<Reader<'a>> {
413 self.admit_path(0)
414 .map_err(|reason| Error::resource(reason, element.whole.start))?;
415 Ok(Reader {
416 data: element.bytes,
417 pos: 0,
418 base: element.whole.start,
419 depth: self.depth,
420 next_index: 0,
421 path: self
422 .path
423 .try_copy_in(self.memory())
424 .map_err(|reason| Error::resource(reason, element.whole.start))?,
425 encoding,
426 parser: self.parser,
427 execution: self.execution.clone(),
428 })
429 }
430
431 /// Reads the next element, or `None` at the end of this container.
432 pub fn next_element(&mut self) -> Result<Option<Element<'a>>> {
433 if self.is_empty() {
434 return Ok(None);
435 }
436
437 let header = self.read_header()?;
438
439 // An end-of-contents marker belongs to whichever reader opened the
440 // indefinite element, and that reader stops before handing it out.
441 // Meeting one here means it closes something never opened.
442 if header.tag.is_end_of_contents() {
443 return Err(self.fail_at(ErrorCode::MalformedEndOfContents, header.start));
444 }
445
446 self.finish(header).map(Some)
447 }
448
449 /// Reads the next element and requires it to carry `tag`.
450 pub fn expect(&mut self, tag: Tag) -> Result<Element<'a>> {
451 let offset = self.offset();
452 match self.next_element()? {
453 Some(element) if element.tag == tag => Ok(element),
454 // Named under the element that carried the wrong tag: it was read,
455 // so it has an index, and the fault is that element rather than
456 // the container holding it. Nothing was read in the other arm, so
457 // there is no element to name and the container is the answer.
458 Some(element) => Err(self.fail_under(ErrorCode::UnexpectedTag, &element)),
459 None => Err(self.fail_at(ErrorCode::UnexpectedEnd, offset)),
460 }
461 }
462
463 /// Reads and discards the next element, whatever it is.
464 ///
465 /// This is how a schema layer steps over an extension it does not know: the
466 /// element is skipped within its declared length, so an unknown tag costs
467 /// what a known one costs and cannot make the reader wander.
468 pub fn skip(&mut self) -> Result<bool> {
469 Ok(self.next_element()?.is_some())
470 }
471
472 /// A reader over the contents of a constructed element read from here.
473 ///
474 /// Refused for a primitive element: its contents are a value rather than
475 /// further elements, and reading them as elements is how a parser is
476 /// talked into finding structure inside an octet string that nobody put
477 /// there.
478 pub fn enter(&self, element: &Element<'a>) -> Result<Reader<'a>> {
479 if !element.tag.is_constructed() {
480 return Err(self.fail_under(ErrorCode::WrongConstruction, element));
481 }
482
483 // Check depth before copying/growing a path: a rejected descent must
484 // not perform the allocation it was supposed to prevent.
485 let depth = self.depth.checked_add(1).ok_or_else(|| {
486 self.fail_under_at(
487 ErrorCode::LimitExceeded(Limit::Depth),
488 element,
489 element.contents_span.start,
490 )
491 })?;
492 self.budget().depth(depth).map_err(|limit| {
493 self.fail_under_at(
494 ErrorCode::LimitExceeded(limit),
495 element,
496 element.contents_span.start,
497 )
498 })?;
499 self.admit_path(1)
500 .map_err(|reason| Error::resource(reason, element.contents_span.start))?;
501 let mut path = self
502 .path
503 .try_copy_in(self.memory())
504 .map_err(|reason| Error::resource(reason, element.contents_span.start))?;
505 path.push(self.memory(), element.index)
506 .map_err(|reason| Error::resource(reason, element.contents_span.start))?;
507
508 Ok(Reader {
509 data: element.contents,
510 pos: 0,
511 base: element.contents_span.start,
512 depth,
513 next_index: 0,
514 path,
515 encoding: self.encoding,
516 parser: self.parser,
517 execution: self.execution.clone(),
518 })
519 }
520
521 /// Reads an element's contents as an object identifier.
522 pub fn oid(&self, element: &Element<'a>) -> Result<Oid<'a>> {
523 self.primitive(element)?;
524 // The arcs are scanned byte by byte, so the scan is charged to the
525 // shared work budget like the headers are: one long identifier must
526 // not cost time the caller's limits never metered.
527 self.budget()
528 .work_in(element.contents.len() as u64, self.memory())
529 .map_err(|limit| self.fail_under(ErrorCode::LimitExceeded(limit), element))?;
530 value::oid(element.contents).map_err(|code| self.fail_under(code, element))
531 }
532
533 /// Reads an element's contents as an integer.
534 pub fn integer(&self, element: &Element<'a>) -> Result<Integer<'a>> {
535 self.primitive(element)?;
536 value::integer(element.contents).map_err(|code| self.fail_under(code, element))
537 }
538
539 /// Reads an element's contents as a bit string.
540 ///
541 /// The segmented form BER allows for a constructed bit string is refused:
542 /// every bit string this product reads is covered by a signature computed
543 /// over the bytes, where one value with two spellings is one value too
544 /// many.
545 pub fn bit_string(&self, element: &Element<'a>) -> Result<BitString<'a>> {
546 self.primitive(element)?;
547 value::bit_string(element.contents, self.encoding)
548 .map_err(|code| self.fail_under(code, element))
549 }
550
551 /// Reads an element's contents as a boolean.
552 pub fn boolean(&self, element: &Element<'a>) -> Result<bool> {
553 self.primitive(element)?;
554 value::boolean(element.contents, self.encoding)
555 .map_err(|code| self.fail_under(code, element))
556 }
557
558 /// Reads an element's contents as a null, which has none.
559 pub fn null(&self, element: &Element<'a>) -> Result<()> {
560 self.primitive(element)?;
561 value::null(element.contents).map_err(|code| self.fail_under(code, element))
562 }
563
564 /// Reads an element's contents as a real, and answers only whether they
565 /// are a value of the type.
566 ///
567 /// The number itself is not read: no schema this product parses has a
568 /// real in it, and one arrives only inside a value preserved for
569 /// somebody else, who is promised octets that are what they claim.
570 pub fn real(&self, element: &Element<'a>) -> Result<()> {
571 self.primitive(element)?;
572 // The decimal form's field is walked digit by digit, so the scan is
573 // charged to the shared work budget like the headers are: one long
574 // value must not cost time the caller's limits never metered.
575 self.budget()
576 .work_in(element.contents.len() as u64, self.memory())
577 .map_err(|limit| self.fail_under(ErrorCode::LimitExceeded(limit), element))?;
578 value::real(element.contents, self.encoding).map_err(|code| self.fail_under(code, element))
579 }
580
581 /// Reads the next element as an object identifier.
582 pub fn read_oid(&mut self) -> Result<Oid<'a>> {
583 let element = self.expect(Tag::primitive(universal::OID))?;
584 self.oid(&element)
585 }
586
587 /// Reads the next element as an integer.
588 pub fn read_integer(&mut self) -> Result<Integer<'a>> {
589 let element = self.expect(Tag::primitive(universal::INTEGER))?;
590 self.integer(&element)
591 }
592
593 /// Reads the next element as a bit string.
594 pub fn read_bit_string(&mut self) -> Result<BitString<'a>> {
595 let element = self.expect(Tag::primitive(universal::BIT_STRING))?;
596 self.bit_string(&element)
597 }
598
599 /// Reads the next element as a boolean.
600 pub fn read_boolean(&mut self) -> Result<bool> {
601 let element = self.expect(Tag::primitive(universal::BOOLEAN))?;
602 self.boolean(&element)
603 }
604
605 fn primitive(&self, element: &Element<'a>) -> Result<()> {
606 if element.tag.is_constructed() {
607 return Err(self.fail_under(ErrorCode::WrongConstruction, element));
608 }
609 Ok(())
610 }
611
612 /// An error naming an element read from this container.
613 #[must_use]
614 pub fn fail_under(&self, code: ErrorCode, element: &Element<'a>) -> Error {
615 self.fail_under_at(code, element, element.whole.start)
616 }
617
618 fn fail_under_at(&self, code: ErrorCode, element: &Element<'a>, offset: u64) -> Error {
619 match self.path_into(element.index, &[]) {
620 Ok(path) => Error::new(code, offset, path),
621 Err(reason) => Error::resource(reason, offset),
622 }
623 }
624
625 fn fail_at(&self, code: ErrorCode, offset: u64) -> Error {
626 if let Err(reason) = self.admit_path(0) {
627 return Error::resource(reason, offset);
628 }
629 match self.path.try_copy_in(self.memory()) {
630 Ok(path) => Error::new(code, offset, path),
631 Err(reason) => Error::resource(reason, offset),
632 }
633 }
634
635 fn read_header(&mut self) -> Result<Header> {
636 let start = self.offset();
637 self.budget()
638 .element()
639 .map_err(|limit| self.fail_at(ErrorCode::LimitExceeded(limit), start))?;
640
641 let rest = &self.data[self.pos..];
642 header_at(rest, self.encoding, start, self.budget(), self.memory())
643 .map_err(|(code, at)| self.fail_at(code, at))
644 }
645
646 fn finish(&mut self, header: Header) -> Result<Element<'a>> {
647 let contents_at = self.pos + header.len;
648 let contents_start = header.start + header.len as u64;
649
650 let (contents_len, total_len, indefinite) = match header.length {
651 Length::Definite(length) => {
652 self.budget()
653 .length(length)
654 .map_err(|limit| self.fail_at(ErrorCode::LimitExceeded(limit), header.start))?;
655
656 let length = usize::try_from(length)
657 .map_err(|_| self.fail_at(ErrorCode::LengthTooLarge, header.start))?;
658
659 let end = contents_at
660 .checked_add(length)
661 .ok_or_else(|| self.fail_at(ErrorCode::LengthTooLarge, header.start))?;
662
663 if end > self.data.len() {
664 return Err(self.fail_at(ErrorCode::UnexpectedEnd, header.start));
665 }
666
667 (length, header.len + length, false)
668 }
669 Length::Indefinite => {
670 if !header.tag.is_constructed() {
671 return Err(self.fail_at(ErrorCode::WrongConstruction, header.start));
672 }
673 let contents_len =
674 self.scan_to_end_of_contents(contents_at, contents_start, self.next_index)?;
675
676 // An indefinite element declares no length, so nothing has held
677 // it to one yet. Its size is what the scan just measured, and a
678 // container assembled from many small children would otherwise
679 // pass a budget its declared-length siblings could not.
680 self.budget()
681 .length(contents_len as u64)
682 .map_err(|limit| self.fail_at(ErrorCode::LimitExceeded(limit), header.start))?;
683
684 // Two further bytes for the end-of-contents marker, which is
685 // exactly two: the scan refuses any other spelling of it.
686 (contents_len, header.len + contents_len + 2, true)
687 }
688 };
689
690 let contents = &self.data[contents_at..contents_at + contents_len];
691 // The element as it arrived, header and any end-of-contents marker
692 // included. Both bounds were established above, so the slice exists.
693 let bytes = &self.data[self.pos..self.pos + total_len];
694 let index = self.next_index;
695
696 self.pos += total_len;
697 self.next_index = self
698 .next_index
699 .checked_add(1)
700 .ok_or_else(|| self.fail_at(ErrorCode::LimitExceeded(Limit::Elements), header.start))?;
701
702 Ok(Element {
703 tag: header.tag,
704 contents,
705 bytes,
706 contents_span: Span {
707 start: contents_start,
708 length: contents_len as u64,
709 },
710 whole: Span {
711 start: header.start,
712 length: total_len as u64,
713 },
714 indefinite,
715 index,
716 })
717 }
718
719 /// Finds where an indefinite-length element's contents end.
720 ///
721 /// Walks the elements inside it with an explicit stack rather than by
722 /// recursing, so a document nested a million deep is refused by the depth
723 /// budget instead of ending the process.
724 ///
725 /// A measurement, not a reading: the elements it steps over are charged to
726 /// the element budget later, where they are actually read. This costs
727 /// work.
728 fn scan_to_end_of_contents(
729 &self,
730 from: usize,
731 from_offset: u64,
732 own_index: u32,
733 ) -> Result<usize> {
734 let mut cursor = from;
735 let mut offset = from_offset;
736
737 // The index of the next element at each level entered so far, so an
738 // error inside nested contents names where it is rather than naming the
739 // container the scan started from.
740 let mut trail = self.execution().vector::<u32>();
741 let mut index: u32 = 0;
742
743 // Assembled only where an error is returned: building it per header is
744 // work proportional to depth times children, which the work budget
745 // does not count.
746 let fail = |code: ErrorCode, at: u64, trail: &[u32]| match self.path_into(own_index, trail)
747 {
748 Ok(path) => Error::new(code, at, path),
749 Err(reason) => Error::resource(reason, at),
750 };
751 let spent =
752 |limit: Limit, at: u64, trail: &[u32]| fail(ErrorCode::LimitExceeded(limit), at, trail);
753
754 loop {
755 let depth = u32::try_from(trail.len())
756 .ok()
757 .and_then(|nested| self.depth.checked_add(nested))
758 .and_then(|depth| depth.checked_add(1))
759 .ok_or_else(|| spent(Limit::Depth, offset, &trail))?;
760 self.budget()
761 .depth(depth)
762 .map_err(|limit| spent(limit, offset, &trail))?;
763
764 let rest = self
765 .data
766 .get(cursor..)
767 .filter(|rest| !rest.is_empty())
768 .ok_or_else(|| fail(ErrorCode::UnterminatedContents, from_offset, &trail))?;
769
770 let header = header_at(rest, self.encoding, offset, self.budget(), self.memory())
771 .map_err(|(code, at)| fail(code, at, &trail))?;
772 let inner_tag = header.tag;
773 let inner_length = header.length;
774 let header_len = header.len;
775
776 if inner_tag.is_end_of_contents() {
777 // Exactly two octets. A zero length written the long way reads
778 // as a zero length, and taking it for the marker would end the
779 // element short and leave the rest of the marker to be read as
780 // another element.
781 if header_len != 2 || !matches!(inner_length, Length::Definite(0)) {
782 return Err(fail(ErrorCode::MalformedEndOfContents, offset, &trail));
783 }
784 match trail.pop() {
785 // This one closes the element the scan was opened for.
786 None => return Ok(cursor - from),
787 // Back at the level that container sat on, with it read.
788 Some(outer) => {
789 index = outer
790 .checked_add(1)
791 .ok_or_else(|| spent(Limit::Elements, offset, &trail))?;
792 }
793 }
794 cursor += header_len;
795 offset += header_len as u64;
796 continue;
797 }
798
799 let step = match inner_length {
800 Length::Indefinite => {
801 if !inner_tag.is_constructed() {
802 return Err(fail(ErrorCode::WrongConstruction, offset, &trail));
803 }
804 // The index this container itself sits at, so a fault
805 // inside it is reported under it rather than beside it.
806 trail
807 .try_push(index)
808 .map_err(|reason| Error::resource(reason, offset))?;
809 index = 0;
810 header_len
811 }
812 Length::Definite(length) => {
813 self.budget()
814 .length(length)
815 .map_err(|limit| spent(limit, offset, &trail))?;
816 let length = usize::try_from(length)
817 .map_err(|_| fail(ErrorCode::LengthTooLarge, offset, &trail))?;
818 index = index
819 .checked_add(1)
820 .ok_or_else(|| spent(Limit::Elements, offset, &trail))?;
821 header_len
822 .checked_add(length)
823 .ok_or_else(|| fail(ErrorCode::LengthTooLarge, offset, &trail))?
824 }
825 };
826
827 cursor = cursor
828 .checked_add(step)
829 .ok_or_else(|| fail(ErrorCode::LengthTooLarge, offset, &trail))?;
830 if cursor > self.data.len() {
831 return Err(fail(ErrorCode::UnexpectedEnd, offset, &trail));
832 }
833 offset += step as u64;
834 }
835 }
836
837 /// The path to a point inside an element of this container: this
838 /// container's path, the element's own index, then the index of each
839 /// nested container entered on the way.
840 fn path_into(
841 &self,
842 own_index: u32,
843 trail: &[u32],
844 ) -> core::result::Result<Path, crate::memory::MemoryError> {
845 let additional = trail
846 .len()
847 .checked_add(1)
848 .ok_or(crate::memory::MemoryError::WorkExceeded)?;
849 self.admit_path(additional)?;
850 let mut path = self.path.try_copy_in(self.memory())?;
851 path.push(self.memory(), own_index)?;
852 for index in trail {
853 path.push(self.memory(), *index)?;
854 }
855 Ok(path)
856 }
857
858 fn admit_path(
859 &self,
860 additional: usize,
861 ) -> core::result::Result<(), crate::memory::MemoryError> {
862 let work = self.path.copy_work(additional)?;
863 self.budget()
864 .local_work(work)
865 .map_err(|_| crate::memory::MemoryError::WorkExceeded)
866 }
867}
868
869#[derive(Clone, Copy)]
870struct Header {
871 tag: Tag,
872 length: Length,
873 start: u64,
874 len: usize,
875}
876
877/// Both ordinary parsing and indefinite scans use the same pre-admission path.
878fn header_at(
879 input: &[u8],
880 encoding: Encoding,
881 start: u64,
882 budget: &Budget,
883 execution: &Memory,
884) -> core::result::Result<Header, (ErrorCode, u64)> {
885 // Common short headers use one aggregate atomic admission for both bytes.
886 // Extra high-tag octets and long lengths spend only before they are examined.
887 budget
888 .work_in(2, execution)
889 .map_err(|limit| (ErrorCode::LimitExceeded(limit), start))?;
890 let mut credit = 2;
891 let mut charge = |amount: u64| {
892 if amount <= credit {
893 credit -= amount;
894 return Ok(());
895 }
896 let additional = amount - credit;
897 credit = 0;
898 budget
899 .work_in(additional, execution)
900 .map_err(ErrorCode::LimitExceeded)
901 };
902 let (tag, tag_len) = tag::read_accounted(input, start, &mut charge)?;
903 let (length, length_len) = length::read_accounted(
904 &input[tag_len..],
905 encoding,
906 start + tag_len as u64,
907 &mut charge,
908 )?;
909 Ok(Header {
910 tag,
911 length,
912 start,
913 len: tag_len + length_len,
914 })
915}
916
917#[cfg(test)]
918mod tests;