Skip to main content

structured_asn1/
reader.rs

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