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, BudgetView, 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    /// Borrows this session's cumulative work ceiling and a current account.
63    ///
64    /// This creates no reader, allocation or owning account clone. It allows
65    /// schema scratch to keep the same local ceiling while a reader cursor
66    /// advances. Selecting an aggregate account does not reset earlier work;
67    /// existing retained capacity stays with its original storage owner.
68    #[must_use]
69    pub fn execution_in<'work>(
70        &'work self,
71        memory: &'work Memory,
72    ) -> crate::memory::Execution<'work> {
73        crate::memory::Execution::new(memory, BudgetView::root(&self.budget))
74    }
75
76    /// A reader over `data`, whose first byte sits at `base` in the document.
77    ///
78    /// `base` is what makes an error's offset and an element's span mean
79    /// something to a caller holding a whole document while handing this parser
80    /// a window into it.
81    ///
82    /// Refused when the end of `data` would not fit an offset. Checking that
83    /// here is what lets every offset computed while reading be ordinary
84    /// arithmetic: each is at most `base + data.len()`.
85    pub fn read<'a>(&'a self, data: &'a [u8], base: u64) -> Result<Reader<'a>> {
86        self.read_as(data, base, self.encoding)
87    }
88
89    /// A reader over `data` under a chosen encoding, sharing this parser's
90    /// budget.
91    ///
92    /// For a window whose schema fixes its encoding regardless of what this
93    /// parser was built for: the value of a certificate extension is DER even
94    /// when the parser was made lenient for the envelope the certificate
95    /// arrived in.
96    pub fn read_as<'a>(
97        &'a self,
98        data: &'a [u8],
99        base: u64,
100        encoding: Encoding,
101    ) -> Result<Reader<'a>> {
102        self.read_as_in(data, base, encoding, self.memory())
103    }
104
105    fn read_as_in<'a>(
106        &'a self,
107        data: &'a [u8],
108        base: u64,
109        encoding: Encoding,
110        execution: &Memory,
111    ) -> Result<Reader<'a>> {
112        u64::try_from(data.len())
113            .ok()
114            .and_then(|length| base.checked_add(length))
115            .ok_or_else(|| Error::new(ErrorCode::OffsetTooLarge, base, Path::default()))?;
116
117        Ok(Reader {
118            data,
119            pos: 0,
120            base,
121            depth: 0,
122            next_index: 0,
123            path: Path::default(),
124            encoding,
125            parser: self,
126            execution: execution.clone(),
127            query: None,
128        })
129    }
130
131    /// A reader over bytes another element carries as its value, one level
132    /// below the reader that element was found in.
133    ///
134    /// For an encoding wrapped in a primitive, an octet string above all: a
135    /// certificate extension's value, a signed message's content. `outer` is
136    /// [`Reader::depth`] of the reader the carrying element came from. A
137    /// reader made with [`Parser::read_as`] would count the wrapped structure
138    /// from the top again, and a caller's depth ceiling would bound each
139    /// wrapping rather than the document.
140    ///
141    /// # Errors
142    ///
143    /// [`ErrorCode::LimitExceeded`] where the level is past the depth
144    /// ceiling, and what [`Parser::read_as`] refuses.
145    pub fn read_nested<'a>(
146        &'a self,
147        data: &'a [u8],
148        base: u64,
149        encoding: Encoding,
150        outer: u32,
151    ) -> Result<Reader<'a>> {
152        self.read_nested_in(data, base, encoding, outer, self.memory())
153    }
154
155    /// Nested lazy reader using the current execution domain from creation.
156    ///
157    /// Original offsets, depth and this parser session's cumulative ceilings
158    /// remain in force. New storage and deferred work use `execution`.
159    pub fn read_nested_in<'a>(
160        &'a self,
161        data: &'a [u8],
162        base: u64,
163        encoding: Encoding,
164        outer: u32,
165        execution: &Memory,
166    ) -> Result<Reader<'a>> {
167        self.read_depth_in(data, base, encoding, outer.checked_add(1), execution)
168    }
169
170    pub(crate) fn read_source_in<'a>(
171        &'a self,
172        data: &'a [u8],
173        base: u64,
174        encoding: Encoding,
175        depth: u32,
176        execution: &Memory,
177    ) -> Result<Reader<'a>> {
178        self.read_depth_in(data, base, encoding, Some(depth), execution)
179    }
180
181    fn read_depth_in<'a>(
182        &'a self,
183        data: &'a [u8],
184        base: u64,
185        encoding: Encoding,
186        depth: Option<u32>,
187        execution: &Memory,
188    ) -> Result<Reader<'a>> {
189        let mut reader = self.read_as_in(data, base, encoding, execution)?;
190        let depth = depth.ok_or_else(|| {
191            Error::new(
192                ErrorCode::LimitExceeded(Limit::Depth),
193                base,
194                Path::default(),
195            )
196        })?;
197        self.budget
198            .depth(depth)
199            .map_err(|limit| Error::new(ErrorCode::LimitExceeded(limit), base, Path::default()))?;
200        reader.depth = depth;
201        Ok(reader)
202    }
203
204    /// Reads an original source window under the current query's ceilings.
205    ///
206    /// The original parser, encoding, offsets and inherited depth remain the
207    /// source's. Its cumulative limits and the query operation's limits both
208    /// apply before work; the current aggregate account is charged once.
209    /// Further foreign-source transitions retain the same operation owner,
210    /// rather than accumulating a chain of unrelated source budgets.
211    pub fn read_nested_query_in<'a>(
212        &'a self,
213        query: &Reader<'a>,
214        data: &'a [u8],
215        base: u64,
216        encoding: Encoding,
217        outer: u32,
218    ) -> Result<Reader<'a>> {
219        self.read_nested_operation_in(
220            data,
221            base,
222            encoding,
223            outer,
224            query.budget().operation(),
225            query.memory(),
226        )
227    }
228
229    /// Reads an original source window at its actual depth under a current query.
230    ///
231    /// A fresh ASN.1 document carried by another format, such as XML base64,
232    /// starts at depth zero: that carrier is not an ASN.1 enclosing element.
233    /// Existing nested windows retain their actual inherited depth instead.
234    /// Source and current-operation cumulative work/depth ceilings both apply;
235    /// storage and new work use the current account, charged once. This does
236    /// not create a parser or reset either session's prior work. The caller
237    /// supplies the original source provenance, as for `read_nested_query_in`.
238    pub fn read_query_in<'a>(
239        &'a self,
240        query: &Reader<'a>,
241        data: &'a [u8],
242        base: u64,
243        encoding: Encoding,
244        depth: u32,
245    ) -> Result<Reader<'a>> {
246        self.read_query_budget_in(
247            data,
248            base,
249            encoding,
250            depth,
251            query.budget().operation(),
252            query.memory(),
253        )
254    }
255
256    pub(crate) fn read_nested_operation_in<'a>(
257        &'a self,
258        data: &'a [u8],
259        base: u64,
260        encoding: Encoding,
261        outer: u32,
262        operation: &'a Budget,
263        execution: &Memory,
264    ) -> Result<Reader<'a>> {
265        let depth = nested_depth(outer, base)?;
266        self.read_query_budget_in(data, base, encoding, depth, operation, execution)
267    }
268
269    pub(crate) fn read_query_budget_in<'a>(
270        &'a self,
271        data: &'a [u8],
272        base: u64,
273        encoding: Encoding,
274        depth: u32,
275        operation: &'a Budget,
276        execution: &Memory,
277    ) -> Result<Reader<'a>> {
278        self.read_scoped_source_in(data, base, encoding, depth, Some(operation), execution)
279    }
280
281    pub(crate) fn read_scoped_source_in<'source: 'operation, 'operation>(
282        &'source self,
283        data: &'source [u8],
284        base: u64,
285        encoding: Encoding,
286        depth: u32,
287        operation: Option<&'operation Budget>,
288        execution: &Memory,
289    ) -> Result<ScopedReader<'source, 'operation>> {
290        let Some(operation) = operation else {
291            return self.read_depth_in(data, base, encoding, Some(depth), execution);
292        };
293        let budget = BudgetView::query(&self.budget, operation);
294        budget
295            .depth(depth)
296            .map_err(|limit| Error::new(ErrorCode::LimitExceeded(limit), base, Path::default()))?;
297        budget
298            .work_in(1, execution)
299            .map_err(|limit| Error::new(ErrorCode::LimitExceeded(limit), base, Path::default()))?;
300        let reader = self.read_as_in(data, base, encoding, execution)?;
301        Ok(ScopedReader {
302            data: reader.data,
303            pos: reader.pos,
304            base: reader.base,
305            depth,
306            next_index: reader.next_index,
307            path: reader.path,
308            encoding: reader.encoding,
309            parser: reader.parser,
310            execution: reader.execution,
311            query: Some(operation),
312        })
313    }
314}
315
316fn nested_depth(outer: u32, base: u64) -> Result<u32> {
317    outer.checked_add(1).ok_or_else(|| {
318        Error::new(
319            ErrorCode::LimitExceeded(Limit::Depth),
320            base,
321            Path::default(),
322        )
323    })
324}
325
326/// Where in a document one run of bytes sits.
327#[derive(Debug, Clone, Copy, PartialEq, Eq)]
328pub struct Span {
329    /// Offset of the first byte, counted in the whole document.
330    pub start: u64,
331    /// How many bytes.
332    pub length: u64,
333}
334
335impl Span {
336    /// The offset just past the last byte.
337    ///
338    /// Ordinary arithmetic: a span is only ever built by a reader, which
339    /// refuses a window whose end does not fit an offset, so `start + length`
340    /// has already been shown to fit.
341    #[must_use]
342    pub fn end(self) -> u64 {
343        self.start + self.length
344    }
345}
346
347/// One element, as it was found.
348#[derive(Debug, Clone, Copy)]
349pub struct Element<'a> {
350    tag: Tag,
351    contents: &'a [u8],
352    bytes: &'a [u8],
353    contents_span: Span,
354    whole: Span,
355    indefinite: bool,
356    index: u32,
357}
358
359impl<'a> Element<'a> {
360    /// What kind of element this is.
361    #[must_use]
362    pub fn tag(self) -> Tag {
363        self.tag
364    }
365
366    /// The contents, borrowed from the document.
367    ///
368    /// For an indefinite-length element this is everything up to but not
369    /// including the end-of-contents marker.
370    #[must_use]
371    pub fn contents(self) -> &'a [u8] {
372        self.contents
373    }
374
375    /// The whole element as it arrived, header included.
376    ///
377    /// What a signature is computed over wherever a schema says the signature
378    /// covers an element as encoded, and what identity is compared on wherever
379    /// a schema says two structures are the same one when their bytes are.
380    /// Handing these back rather than re-encoding what was understood is the
381    /// difference between checking a signature over the document somebody was
382    /// sent and checking it over this parser's opinion of that document.
383    #[must_use]
384    pub fn as_bytes(self) -> &'a [u8] {
385        self.bytes
386    }
387
388    /// Where the contents sit in the document.
389    #[must_use]
390    pub fn contents_span(self) -> Span {
391        self.contents_span
392    }
393
394    /// Where the whole element sits, header included.
395    ///
396    /// This is the range a signature is computed over wherever a schema says
397    /// the signature covers an element as encoded.
398    #[must_use]
399    pub fn span(self) -> Span {
400        self.whole
401    }
402
403    /// Whether the length was written in the indefinite form.
404    #[must_use]
405    pub fn is_indefinite(self) -> bool {
406        self.indefinite
407    }
408
409    /// Its position among the elements of the container it was read from.
410    #[must_use]
411    pub fn index(self) -> u32 {
412        self.index
413    }
414}
415
416/// Reads the elements of one container, in order.
417///
418/// Cloning one keeps where it is and how deep it sits, so a caller that has to
419/// come back to a container later can put the reader aside rather than start
420/// again from the document and count the nesting as one.
421#[derive(Debug)]
422pub struct ScopedReader<'a: 'operation, 'operation> {
423    data: &'a [u8],
424    pos: usize,
425    base: u64,
426    depth: u32,
427    next_index: u32,
428    path: Path,
429    encoding: Encoding,
430    parser: &'a Parser,
431    execution: Memory,
432    query: Option<&'operation Budget>,
433}
434
435/// Source reader whose input and operation have the same lifetime.
436/// Scoped schema processing can instead use [`ScopedReader`] to return input
437/// views independently of the current operation's borrowed budget.
438pub type Reader<'a> = ScopedReader<'a, 'a>;
439
440impl<'a: 'operation, 'operation> ScopedReader<'a, 'operation> {
441    /// Current domain for deferred work, copies and new storage.
442    #[must_use]
443    pub fn memory(&self) -> &Memory {
444        &self.execution
445    }
446
447    /// Borrows both the current account and original cumulative work ceiling.
448    ///
449    /// Schema scratch must use this boundary when work belongs to the parse:
450    /// allocator growth, copying and sorting then retain the session ceiling
451    /// as well as the aggregate account. Independently retained results use
452    /// [`Self::memory`] instead.
453    ///
454    /// # Examples
455    ///
456    /// ```
457    /// use std::sync::Arc;
458    /// use structured_asn1::{Parser, memory::{Memory, MemoryAccount, Work}};
459    /// let parser = Parser::ber(Memory::new(Arc::new(MemoryAccount::new(1024, 1024))));
460    /// let reader = parser.read(&[], 900).unwrap();
461    /// let mut scratch = reader.execution().vector();
462    /// scratch.try_push(7_u8)?;
463    /// assert_eq!(&*scratch, &[7]);
464    /// # Ok::<(), structured_asn1::memory::MemoryError>(())
465    /// ```
466    #[must_use]
467    pub fn execution(&self) -> crate::memory::Execution<'_> {
468        crate::memory::Execution::new(self.memory(), self.budget())
469    }
470
471    /// Borrows the source/query budgets independently of this reader cursor.
472    ///
473    /// Supply the operation account explicitly so scratch can keep the same
474    /// admission while the cursor advances. This creates no allocation or
475    /// owning account clone and cannot discard an inherited query ceiling.
476    #[must_use]
477    pub fn execution_in<'work>(&self, memory: &'work Memory) -> crate::memory::Execution<'work>
478    where
479        'a: 'work,
480        'operation: 'work,
481    {
482        crate::memory::Execution::new(memory, self.budget())
483    }
484
485    /// Borrows original-source and current root-operation work ceilings for
486    /// metadata queries that do not enter a payload or advance a cursor.
487    ///
488    /// Construction allocates nothing, copies no diagnostic path and does not
489    /// inspect bytes or require an additional ASN.1 nesting level. Work and
490    /// collection admission still checks both cumulative ceilings, charging
491    /// the current query's aggregate account once. A prior foreign source is
492    /// replaced by this source, never by a wider ancestor operation.
493    #[must_use]
494    pub fn execution_query<'query>(
495        &self,
496        query: &'query Reader<'_>,
497    ) -> crate::memory::Execution<'query>
498    where
499        'a: 'query,
500    {
501        crate::memory::Execution::new(
502            query.memory(),
503            BudgetView::query(&self.parser.budget, query.budget().operation()),
504        )
505    }
506
507    /// Selects the domain for subsequent execution without moving existing
508    /// storage charges. Offsets, depth and parser-session cumulative limits
509    /// remain unchanged; a new domain does not reset that session ceiling.
510    #[must_use]
511    pub fn with_execution(mut self, execution: &Memory) -> Self {
512        self.execution = execution.clone();
513        self
514    }
515
516    /// Moves this cursor into a current query without copying its retained path.
517    /// Original parser, data, offsets and depth remain unchanged. Both source
518    /// and operation admission apply before changing execution; existing path
519    /// capacity keeps its original owner until actually freed.
520    pub fn with_query<'query>(self, query: &Reader<'query>) -> Result<Reader<'query>>
521    where
522        'a: 'query,
523    {
524        let operation = query.budget().operation();
525        let budget = BudgetView::query(&self.parser.budget, operation);
526        budget.depth(self.depth).map_err(|limit| {
527            Error::new(
528                ErrorCode::LimitExceeded(limit),
529                self.offset(),
530                Path::default(),
531            )
532        })?;
533        budget.work_in(1, query.memory()).map_err(|limit| {
534            Error::new(
535                ErrorCode::LimitExceeded(limit),
536                self.offset(),
537                Path::default(),
538            )
539        })?;
540        Ok(ScopedReader {
541            data: self.data,
542            pos: self.pos,
543            base: self.base,
544            depth: self.depth,
545            next_index: self.next_index,
546            path: self.path,
547            encoding: self.encoding,
548            parser: self.parser,
549            execution: query.memory().clone(),
550            query: Some(operation),
551        })
552    }
553
554    /// Copies the reader position and diagnostic path fallibly in the same domain.
555    pub fn try_clone(&self) -> Result<Self> {
556        self.admit_path(0)
557            .map_err(|reason| Error::resource(reason, self.offset()))?;
558        Ok(Self {
559            data: self.data,
560            pos: self.pos,
561            base: self.base,
562            depth: self.depth,
563            next_index: self.next_index,
564            path: self
565                .path
566                .try_copy_in(self.memory())
567                .map_err(|reason| Error::resource(reason, self.offset()))?,
568            encoding: self.encoding,
569            parser: self.parser,
570            execution: self.execution.clone(),
571            query: self.query,
572        })
573    }
574    /// Whether every element here has been read.
575    #[must_use]
576    pub fn is_empty(&self) -> bool {
577        self.pos >= self.data.len()
578    }
579
580    /// Original parser, whose session ceilings remain cumulative across
581    /// deferred reads. Use [`Self::memory`] for the current execution domain;
582    /// the parser's storage domain may belong to an earlier operation.
583    #[must_use]
584    pub fn parser(&self) -> &'a Parser {
585        self.parser
586    }
587
588    /// The shared budget, by way of the parser.
589    fn budget(&self) -> BudgetView<'operation> {
590        match self.query {
591            Some(operation) => BudgetView::query(&self.parser.budget, operation),
592            None => BudgetView::root(&self.parser.budget),
593        }
594    }
595
596    /// Charges caller-side scanning to the shared work budget.
597    ///
598    /// For a schema layer that walks an element's contents itself, text
599    /// validation and named-bit walks among them: the walk costs what the
600    /// bytes cost, and a caller bounding work must see that cost on the
601    /// same meter the reads use.
602    pub fn charge(&self, amount: u64) -> Result<()> {
603        self.budget()
604            .work_in(amount, self.memory())
605            .map_err(|limit| self.fail_at(ErrorCode::LimitExceeded(limit), self.offset()))
606    }
607
608    /// How many containers deep this reader sits, counted as the depth
609    /// ceiling counts it. What [`Parser::read_nested`] is given for a value
610    /// found here.
611    #[must_use]
612    pub fn depth(&self) -> u32 {
613        self.depth
614    }
615
616    /// The offset of the next unread byte, in the document.
617    ///
618    /// Ordinary arithmetic, because `pos` never exceeds the length of `data`
619    /// and `base` plus that length was shown to fit when this reader was made.
620    #[must_use]
621    pub fn offset(&self) -> u64 {
622        self.base + self.pos as u64
623    }
624
625    /// The bytes not yet read.
626    #[must_use]
627    pub fn remaining(&self) -> &'a [u8] {
628        &self.data[self.pos.min(self.data.len())..]
629    }
630
631    /// The path to this container, for a caller building its own diagnostics.
632    #[must_use]
633    pub fn path(&self) -> &Path {
634        &self.path
635    }
636
637    /// Which encoding this reader accepts, for a schema whose own rules
638    /// differ between the two, such as the ordering DER requires of a set.
639    #[must_use]
640    pub fn encoding(&self) -> Encoding {
641        self.encoding
642    }
643
644    /// A reader over an element's own bytes, header included, under a chosen
645    /// encoding.
646    ///
647    /// For a structure whose schema fixes its encoding regardless of the
648    /// container's: a certificate is DER even when the envelope carrying it
649    /// is BER, and reading it with the container's leniency would let
650    /// spellings survive that the certificate's own rules refuse. The
651    /// element's header is read again under the chosen rules, so a header
652    /// only the lenient encoding accepts is refused too. Offsets stay offsets
653    /// in the document and the budget stays the shared one.
654    pub fn reread(&self, element: &Element<'a>, encoding: Encoding) -> Result<Self> {
655        self.admit_path(0)
656            .map_err(|reason| Error::resource(reason, element.whole.start))?;
657        Ok(Self {
658            data: element.bytes,
659            pos: 0,
660            base: element.whole.start,
661            depth: self.depth,
662            next_index: 0,
663            path: self
664                .path
665                .try_copy_in(self.memory())
666                .map_err(|reason| Error::resource(reason, element.whole.start))?,
667            encoding,
668            parser: self.parser,
669            execution: self.execution.clone(),
670            query: self.query,
671        })
672    }
673
674    /// Reads the next element, or `None` at the end of this container.
675    pub fn next_element(&mut self) -> Result<Option<Element<'a>>> {
676        if self.is_empty() {
677            return Ok(None);
678        }
679
680        let header = self.read_header()?;
681
682        // An end-of-contents marker belongs to whichever reader opened the
683        // indefinite element, and that reader stops before handing it out.
684        // Meeting one here means it closes something never opened.
685        if header.tag.is_end_of_contents() {
686            return Err(self.fail_at(ErrorCode::MalformedEndOfContents, header.start));
687        }
688
689        self.finish(header).map(Some)
690    }
691
692    /// Reads the next element and requires it to carry `tag`.
693    pub fn expect(&mut self, tag: Tag) -> Result<Element<'a>> {
694        let offset = self.offset();
695        match self.next_element()? {
696            Some(element) if element.tag == tag => Ok(element),
697            // Named under the element that carried the wrong tag: it was read,
698            // so it has an index, and the fault is that element rather than
699            // the container holding it. Nothing was read in the other arm, so
700            // there is no element to name and the container is the answer.
701            Some(element) => Err(self.fail_under(ErrorCode::UnexpectedTag, &element)),
702            None => Err(self.fail_at(ErrorCode::UnexpectedEnd, offset)),
703        }
704    }
705
706    /// Reads and discards the next element, whatever it is.
707    ///
708    /// This is how a schema layer steps over an extension it does not know: the
709    /// element is skipped within its declared length, so an unknown tag costs
710    /// what a known one costs and cannot make the reader wander.
711    pub fn skip(&mut self) -> Result<bool> {
712        Ok(self.next_element()?.is_some())
713    }
714
715    /// A reader over the contents of a constructed element read from here.
716    ///
717    /// Refused for a primitive element: its contents are a value rather than
718    /// further elements, and reading them as elements is how a parser is
719    /// talked into finding structure inside an octet string that nobody put
720    /// there.
721    pub fn enter(&self, element: &Element<'a>) -> Result<Self> {
722        if !element.tag.is_constructed() {
723            return Err(self.fail_under(ErrorCode::WrongConstruction, element));
724        }
725
726        // Check depth before copying/growing a path: a rejected descent must
727        // not perform the allocation it was supposed to prevent.
728        let depth = self.depth.checked_add(1).ok_or_else(|| {
729            self.fail_under_at(
730                ErrorCode::LimitExceeded(Limit::Depth),
731                element,
732                element.contents_span.start,
733            )
734        })?;
735        self.budget().depth(depth).map_err(|limit| {
736            self.fail_under_at(
737                ErrorCode::LimitExceeded(limit),
738                element,
739                element.contents_span.start,
740            )
741        })?;
742        self.admit_path(1)
743            .map_err(|reason| Error::resource(reason, element.contents_span.start))?;
744        let mut path = self
745            .path
746            .try_copy_in(self.memory())
747            .map_err(|reason| Error::resource(reason, element.contents_span.start))?;
748        path.push(self.memory(), element.index)
749            .map_err(|reason| Error::resource(reason, element.contents_span.start))?;
750
751        Ok(Self {
752            data: element.contents,
753            pos: 0,
754            base: element.contents_span.start,
755            depth,
756            next_index: 0,
757            path,
758            encoding: self.encoding,
759            parser: self.parser,
760            execution: self.execution.clone(),
761            query: self.query,
762        })
763    }
764
765    /// Reads an element's contents as an object identifier.
766    pub fn oid(&self, element: &Element<'a>) -> Result<Oid<'a>> {
767        self.primitive(element)?;
768        // The arcs are scanned byte by byte, so the scan is charged to the
769        // shared work budget like the headers are: one long identifier must
770        // not cost time the caller's limits never metered.
771        self.budget()
772            .work_in(element.contents.len() as u64, self.memory())
773            .map_err(|limit| self.fail_under(ErrorCode::LimitExceeded(limit), element))?;
774        value::oid(element.contents).map_err(|code| self.fail_under(code, element))
775    }
776
777    /// Reads an element's contents as an integer.
778    pub fn integer(&self, element: &Element<'a>) -> Result<Integer<'a>> {
779        self.primitive(element)?;
780        value::integer(element.contents).map_err(|code| self.fail_under(code, element))
781    }
782
783    /// Reads an element's contents as a bit string.
784    ///
785    /// The segmented form BER allows for a constructed bit string is refused:
786    /// every bit string this product reads is covered by a signature computed
787    /// over the bytes, where one value with two spellings is one value too
788    /// many.
789    pub fn bit_string(&self, element: &Element<'a>) -> Result<BitString<'a>> {
790        self.primitive(element)?;
791        value::bit_string(element.contents, self.encoding)
792            .map_err(|code| self.fail_under(code, element))
793    }
794
795    /// Reads an element's contents as a boolean.
796    pub fn boolean(&self, element: &Element<'a>) -> Result<bool> {
797        self.primitive(element)?;
798        value::boolean(element.contents, self.encoding)
799            .map_err(|code| self.fail_under(code, element))
800    }
801
802    /// Reads an element's contents as a null, which has none.
803    pub fn null(&self, element: &Element<'a>) -> Result<()> {
804        self.primitive(element)?;
805        value::null(element.contents).map_err(|code| self.fail_under(code, element))
806    }
807
808    /// Reads an element's contents as a real, and answers only whether they
809    /// are a value of the type.
810    ///
811    /// The number itself is not read: no schema this product parses has a
812    /// real in it, and one arrives only inside a value preserved for
813    /// somebody else, who is promised octets that are what they claim.
814    pub fn real(&self, element: &Element<'a>) -> Result<()> {
815        self.primitive(element)?;
816        // The decimal form's field is walked digit by digit, so the scan is
817        // charged to the shared work budget like the headers are: one long
818        // value must not cost time the caller's limits never metered.
819        self.budget()
820            .work_in(element.contents.len() as u64, self.memory())
821            .map_err(|limit| self.fail_under(ErrorCode::LimitExceeded(limit), element))?;
822        value::real(element.contents, self.encoding).map_err(|code| self.fail_under(code, element))
823    }
824
825    /// Reads the next element as an object identifier.
826    pub fn read_oid(&mut self) -> Result<Oid<'a>> {
827        let element = self.expect(Tag::primitive(universal::OID))?;
828        self.oid(&element)
829    }
830
831    /// Reads the next element as an integer.
832    pub fn read_integer(&mut self) -> Result<Integer<'a>> {
833        let element = self.expect(Tag::primitive(universal::INTEGER))?;
834        self.integer(&element)
835    }
836
837    /// Reads the next element as a bit string.
838    pub fn read_bit_string(&mut self) -> Result<BitString<'a>> {
839        let element = self.expect(Tag::primitive(universal::BIT_STRING))?;
840        self.bit_string(&element)
841    }
842
843    /// Reads the next element as a boolean.
844    pub fn read_boolean(&mut self) -> Result<bool> {
845        let element = self.expect(Tag::primitive(universal::BOOLEAN))?;
846        self.boolean(&element)
847    }
848
849    fn primitive(&self, element: &Element<'a>) -> Result<()> {
850        if element.tag.is_constructed() {
851            return Err(self.fail_under(ErrorCode::WrongConstruction, element));
852        }
853        Ok(())
854    }
855
856    /// An error naming an element read from this container.
857    #[must_use]
858    pub fn fail_under(&self, code: ErrorCode, element: &Element<'a>) -> Error {
859        self.fail_under_at(code, element, element.whole.start)
860    }
861
862    fn fail_under_at(&self, code: ErrorCode, element: &Element<'a>, offset: u64) -> Error {
863        match self.path_into(element.index, &[]) {
864            Ok(path) => Error::new(code, offset, path),
865            Err(reason) => Error::resource(reason, offset),
866        }
867    }
868
869    fn fail_at(&self, code: ErrorCode, offset: u64) -> Error {
870        if let Err(reason) = self.admit_path(0) {
871            return Error::resource(reason, offset);
872        }
873        match self.path.try_copy_in(self.memory()) {
874            Ok(path) => Error::new(code, offset, path),
875            Err(reason) => Error::resource(reason, offset),
876        }
877    }
878
879    fn read_header(&mut self) -> Result<Header> {
880        let start = self.offset();
881        self.budget()
882            .element()
883            .map_err(|limit| self.fail_at(ErrorCode::LimitExceeded(limit), start))?;
884
885        let rest = &self.data[self.pos..];
886        header_at(rest, self.encoding, start, self.budget(), self.memory())
887            .map_err(|(code, at)| self.fail_at(code, at))
888    }
889
890    fn finish(&mut self, header: Header) -> Result<Element<'a>> {
891        let contents_at = self.pos + header.len;
892        let contents_start = header.start + header.len as u64;
893
894        let (contents_len, total_len, indefinite) = match header.length {
895            Length::Definite(length) => {
896                self.budget()
897                    .length(length)
898                    .map_err(|limit| self.fail_at(ErrorCode::LimitExceeded(limit), header.start))?;
899
900                let length = usize::try_from(length)
901                    .map_err(|_| self.fail_at(ErrorCode::LengthTooLarge, header.start))?;
902
903                let end = contents_at
904                    .checked_add(length)
905                    .ok_or_else(|| self.fail_at(ErrorCode::LengthTooLarge, header.start))?;
906
907                if end > self.data.len() {
908                    return Err(self.fail_at(ErrorCode::UnexpectedEnd, header.start));
909                }
910
911                (length, header.len + length, false)
912            }
913            Length::Indefinite => {
914                if !header.tag.is_constructed() {
915                    return Err(self.fail_at(ErrorCode::WrongConstruction, header.start));
916                }
917                let contents_len =
918                    self.scan_to_end_of_contents(contents_at, contents_start, self.next_index)?;
919
920                // An indefinite element declares no length, so nothing has held
921                // it to one yet. Its size is what the scan just measured, and a
922                // container assembled from many small children would otherwise
923                // pass a budget its declared-length siblings could not.
924                self.budget()
925                    .length(contents_len as u64)
926                    .map_err(|limit| self.fail_at(ErrorCode::LimitExceeded(limit), header.start))?;
927
928                // Two further bytes for the end-of-contents marker, which is
929                // exactly two: the scan refuses any other spelling of it.
930                (contents_len, header.len + contents_len + 2, true)
931            }
932        };
933
934        let contents = &self.data[contents_at..contents_at + contents_len];
935        // The element as it arrived, header and any end-of-contents marker
936        // included. Both bounds were established above, so the slice exists.
937        let bytes = &self.data[self.pos..self.pos + total_len];
938        let index = self.next_index;
939
940        self.pos += total_len;
941        self.next_index = self
942            .next_index
943            .checked_add(1)
944            .ok_or_else(|| self.fail_at(ErrorCode::LimitExceeded(Limit::Elements), header.start))?;
945
946        Ok(Element {
947            tag: header.tag,
948            contents,
949            bytes,
950            contents_span: Span {
951                start: contents_start,
952                length: contents_len as u64,
953            },
954            whole: Span {
955                start: header.start,
956                length: total_len as u64,
957            },
958            indefinite,
959            index,
960        })
961    }
962
963    /// Finds where an indefinite-length element's contents end.
964    ///
965    /// Walks the elements inside it with an explicit stack rather than by
966    /// recursing, so a document nested a million deep is refused by the depth
967    /// budget instead of ending the process.
968    ///
969    /// A measurement, not a reading: the elements it steps over are charged to
970    /// the element budget later, where they are actually read. This costs
971    /// work.
972    fn scan_to_end_of_contents(
973        &self,
974        from: usize,
975        from_offset: u64,
976        own_index: u32,
977    ) -> Result<usize> {
978        let mut cursor = from;
979        let mut offset = from_offset;
980
981        // The index of the next element at each level entered so far, so an
982        // error inside nested contents names where it is rather than naming the
983        // container the scan started from.
984        let mut trail = self.execution().vector::<u32>();
985        let mut index: u32 = 0;
986
987        // Assembled only where an error is returned: building it per header is
988        // work proportional to depth times children, which the work budget
989        // does not count.
990        let fail = |code: ErrorCode, at: u64, trail: &[u32]| match self.path_into(own_index, trail)
991        {
992            Ok(path) => Error::new(code, at, path),
993            Err(reason) => Error::resource(reason, at),
994        };
995        let spent =
996            |limit: Limit, at: u64, trail: &[u32]| fail(ErrorCode::LimitExceeded(limit), at, trail);
997
998        loop {
999            let depth = u32::try_from(trail.len())
1000                .ok()
1001                .and_then(|nested| self.depth.checked_add(nested))
1002                .and_then(|depth| depth.checked_add(1))
1003                .ok_or_else(|| spent(Limit::Depth, offset, &trail))?;
1004            self.budget()
1005                .depth(depth)
1006                .map_err(|limit| spent(limit, offset, &trail))?;
1007
1008            let rest = self
1009                .data
1010                .get(cursor..)
1011                .filter(|rest| !rest.is_empty())
1012                .ok_or_else(|| fail(ErrorCode::UnterminatedContents, from_offset, &trail))?;
1013
1014            let header = header_at(rest, self.encoding, offset, self.budget(), self.memory())
1015                .map_err(|(code, at)| fail(code, at, &trail))?;
1016            let inner_tag = header.tag;
1017            let inner_length = header.length;
1018            let header_len = header.len;
1019
1020            if inner_tag.is_end_of_contents() {
1021                // Exactly two octets. A zero length written the long way reads
1022                // as a zero length, and taking it for the marker would end the
1023                // element short and leave the rest of the marker to be read as
1024                // another element.
1025                if header_len != 2 || !matches!(inner_length, Length::Definite(0)) {
1026                    return Err(fail(ErrorCode::MalformedEndOfContents, offset, &trail));
1027                }
1028                match trail.pop() {
1029                    // This one closes the element the scan was opened for.
1030                    None => return Ok(cursor - from),
1031                    // Back at the level that container sat on, with it read.
1032                    Some(outer) => {
1033                        index = outer
1034                            .checked_add(1)
1035                            .ok_or_else(|| spent(Limit::Elements, offset, &trail))?;
1036                    }
1037                }
1038                cursor += header_len;
1039                offset += header_len as u64;
1040                continue;
1041            }
1042
1043            let step = match inner_length {
1044                Length::Indefinite => {
1045                    if !inner_tag.is_constructed() {
1046                        return Err(fail(ErrorCode::WrongConstruction, offset, &trail));
1047                    }
1048                    // The index this container itself sits at, so a fault
1049                    // inside it is reported under it rather than beside it.
1050                    trail
1051                        .try_push(index)
1052                        .map_err(|reason| Error::resource(reason, offset))?;
1053                    index = 0;
1054                    header_len
1055                }
1056                Length::Definite(length) => {
1057                    self.budget()
1058                        .length(length)
1059                        .map_err(|limit| spent(limit, offset, &trail))?;
1060                    let length = usize::try_from(length)
1061                        .map_err(|_| fail(ErrorCode::LengthTooLarge, offset, &trail))?;
1062                    index = index
1063                        .checked_add(1)
1064                        .ok_or_else(|| spent(Limit::Elements, offset, &trail))?;
1065                    header_len
1066                        .checked_add(length)
1067                        .ok_or_else(|| fail(ErrorCode::LengthTooLarge, offset, &trail))?
1068                }
1069            };
1070
1071            cursor = cursor
1072                .checked_add(step)
1073                .ok_or_else(|| fail(ErrorCode::LengthTooLarge, offset, &trail))?;
1074            if cursor > self.data.len() {
1075                return Err(fail(ErrorCode::UnexpectedEnd, offset, &trail));
1076            }
1077            offset += step as u64;
1078        }
1079    }
1080
1081    /// The path to a point inside an element of this container: this
1082    /// container's path, the element's own index, then the index of each
1083    /// nested container entered on the way.
1084    fn path_into(
1085        &self,
1086        own_index: u32,
1087        trail: &[u32],
1088    ) -> core::result::Result<Path, crate::memory::MemoryError> {
1089        let additional = trail
1090            .len()
1091            .checked_add(1)
1092            .ok_or(crate::memory::MemoryError::WorkExceeded)?;
1093        self.admit_path(additional)?;
1094        let mut path = self.path.try_copy_in(self.memory())?;
1095        path.push(self.memory(), own_index)?;
1096        for index in trail {
1097            path.push(self.memory(), *index)?;
1098        }
1099        Ok(path)
1100    }
1101
1102    fn admit_path(
1103        &self,
1104        additional: usize,
1105    ) -> core::result::Result<(), crate::memory::MemoryError> {
1106        let work = self.path.copy_work(additional)?;
1107        self.budget()
1108            .local_work(work)
1109            .map_err(|_| crate::memory::MemoryError::WorkExceeded)
1110    }
1111}
1112
1113#[derive(Clone, Copy)]
1114struct Header {
1115    tag: Tag,
1116    length: Length,
1117    start: u64,
1118    len: usize,
1119}
1120
1121/// Both ordinary parsing and indefinite scans use the same pre-admission path.
1122fn header_at(
1123    input: &[u8],
1124    encoding: Encoding,
1125    start: u64,
1126    budget: BudgetView<'_>,
1127    execution: &Memory,
1128) -> core::result::Result<Header, (ErrorCode, u64)> {
1129    // Common short headers use one aggregate atomic admission for both bytes.
1130    // Extra high-tag octets and long lengths spend only before they are examined.
1131    budget
1132        .work_in(2, execution)
1133        .map_err(|limit| (ErrorCode::LimitExceeded(limit), start))?;
1134    let mut credit = 2;
1135    let mut charge = |amount: u64| {
1136        if amount <= credit {
1137            credit -= amount;
1138            return Ok(());
1139        }
1140        let additional = amount - credit;
1141        credit = 0;
1142        budget
1143            .work_in(additional, execution)
1144            .map_err(ErrorCode::LimitExceeded)
1145    };
1146    let (tag, tag_len) = tag::read_accounted(input, start, &mut charge)?;
1147    let (length, length_len) = length::read_accounted(
1148        &input[tag_len..],
1149        encoding,
1150        start + tag_len as u64,
1151        &mut charge,
1152    )?;
1153    Ok(Header {
1154        tag,
1155        length,
1156        start,
1157        len: tag_len + length_len,
1158    })
1159}
1160
1161#[cfg(test)]
1162mod tests;