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