structured_asn1/lib.rs
1//! A streaming BER/DER reader for the certificate, CMS and timestamp parsers.
2//!
3//! What this is for, and what it deliberately is not: it reads the structure of
4//! an encoding and hands back the bytes each element occupies. It does not
5//! decide what those elements mean. A schema layer above does that, and keeping
6//! the two apart is what lets a signature be checked over the bytes as they
7//! arrived rather than over a re-encoding of what somebody understood.
8//!
9//! Three things shape the design.
10//!
11//! Nothing is copied. Elements borrow from the document and carry the range
12//! they occupy in it, so a caller holding one gigabyte does not become a caller
13//! holding two.
14//!
15//! Nothing recurses. Depth is bounded by a budget the caller sets, not by the
16//! thread's stack, so a deeply nested document is refused rather than fatal.
17//!
18//! A refusal to finish is not a verdict about the document. Running out of
19//! budget reports [`ErrorCode::LimitExceeded`], which is distinct from every
20//! code that says the bytes are malformed, because telling somebody their
21//! document is broken when the truth is that this device gave up is a different
22//! statement and a worse one.
23//!
24//! ```
25//! use std::sync::Arc;
26//! use structured_asn1::{Parser, Tag, universal};
27//! use structured_asn1::memory::{Memory, MemoryAccount};
28//!
29//! // SEQUENCE { INTEGER 1 }
30//! let document = [0x30, 0x03, 0x02, 0x01, 0x01];
31//!
32//! let memory = Memory::new(Arc::new(MemoryAccount::new(1024, 1024)));
33//! let parser = Parser::der(memory);
34//! let mut reader = parser.read(&document, 0)?;
35//!
36//! let sequence = reader.expect(Tag::constructed(universal::SEQUENCE))?;
37//! let mut inside = reader.enter(&sequence)?;
38//!
39//! let integer = inside.expect(Tag::primitive(universal::INTEGER))?;
40//! assert_eq!(integer.contents(), &[0x01]);
41//!
42//! // The range the value occupies in the document, for a signature to cover.
43//! assert_eq!(integer.span().start, 2);
44//! assert_eq!(integer.span().length, 3);
45//! # Ok::<(), structured_asn1::Error>(())
46//! ```
47
48#![cfg_attr(not(feature = "std"), no_std)]
49
50extern crate alloc;
51
52pub mod error;
53pub mod length;
54pub mod limits;
55pub mod memory;
56pub mod reader;
57pub mod tag;
58pub mod value;
59
60pub use error::{Error, ErrorCode, Limit, Path, Result};
61pub use length::{Encoding, Length};
62pub use limits::Limits;
63pub use reader::{Element, IntegerReading, Parser, Reader, Span};
64pub use tag::{Class, Tag, universal};
65pub use value::{Arcs, BitString, Integer, Oid, OwnedOid};
66
67#[cfg(test)]
68pub(crate) fn test_memory() -> memory::Memory {
69 // Trusted test setup: isolate per-parser limits in existing encoding tests.
70 memory::Memory::new(alloc::sync::Arc::new(memory::MemoryAccount::new(
71 256 * 1024 * 1024,
72 1_000_000_000,
73 )))
74}