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