Skip to main content

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