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;