sacp_cbor/limits.rs
1use crate::{CborError, ErrorCode};
2
3/// Default maximum nesting depth limit.
4pub const DEFAULT_MAX_DEPTH: usize = 256;
5
6/// Default maximum container length limit for arrays/maps.
7///
8/// This is a safety limit; adjust explicitly for your deployment.
9pub const DEFAULT_MAX_CONTAINER_LEN: usize = 1 << 16;
10
11/// Decode-time resource limits for validation and decoding.
12///
13/// Limits are enforced deterministically and must not depend on background timers.
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub struct DecodeLimits {
16 /// Maximum total input length in bytes.
17 pub max_input_bytes: usize,
18 /// Maximum nesting depth.
19 pub max_depth: usize,
20 /// Maximum total count of container items:
21 /// `sum(array_len) + sum(2 * map_pairs)` across the entire decoded item
22 /// (maps count both keys and values).
23 pub max_total_items: usize,
24 /// Maximum array length.
25 pub max_array_len: usize,
26 /// Maximum map length (pairs).
27 pub max_map_len: usize,
28 /// Maximum byte-string length (also applies to bignum magnitudes).
29 pub max_bytes_len: usize,
30 /// Maximum text-string length in UTF-8 bytes.
31 pub max_text_len: usize,
32}
33
34impl DecodeLimits {
35 /// Construct conservative limits derived from a maximum message size.
36 ///
37 /// The defaults are:
38 /// - `max_input_bytes = max_message_bytes`
39 /// - `max_total_items = max_message_bytes`
40 /// - `max_bytes_len = max_message_bytes`
41 /// - `max_text_len = max_message_bytes`
42 /// - `max_array_len` and `max_map_len` are capped by `DEFAULT_MAX_CONTAINER_LEN`
43 ///
44 /// This is a pragmatic baseline. Production deployments should tune these explicitly.
45 #[must_use]
46 pub fn for_bytes(max_message_bytes: usize) -> Self {
47 let max_container_len = max_message_bytes.min(DEFAULT_MAX_CONTAINER_LEN);
48 Self {
49 max_input_bytes: max_message_bytes,
50 max_depth: DEFAULT_MAX_DEPTH,
51 max_total_items: max_message_bytes,
52 max_array_len: max_container_len,
53 max_map_len: max_container_len,
54 max_bytes_len: max_message_bytes,
55 max_text_len: max_message_bytes,
56 }
57 }
58}
59
60/// End-to-end limits used by SACP implementations.
61///
62/// SACP commonly distinguishes between:
63/// - maximum message size on the wire, and
64/// - maximum size of canonical CBOR stored durably as state.
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66pub struct CborLimits {
67 /// Maximum bytes per message.
68 pub max_message_bytes: usize,
69 /// Maximum bytes per state blob (must be <= `max_message_bytes`).
70 pub max_state_bytes: usize,
71}
72
73impl CborLimits {
74 /// Construct new limits.
75 ///
76 /// # Errors
77 ///
78 /// Returns `InvalidLimits` if `max_state_bytes > max_message_bytes`.
79 pub const fn new(max_message_bytes: usize, max_state_bytes: usize) -> Result<Self, CborError> {
80 if max_state_bytes > max_message_bytes {
81 return Err(CborError::new(ErrorCode::InvalidLimits, 0));
82 }
83 Ok(Self {
84 max_message_bytes,
85 max_state_bytes,
86 })
87 }
88
89 /// Decode limits appropriate for validating incoming messages.
90 #[must_use]
91 pub fn message_limits(self) -> DecodeLimits {
92 DecodeLimits::for_bytes(self.max_message_bytes)
93 }
94
95 /// Decode limits appropriate for validating stored canonical state.
96 #[must_use]
97 pub fn state_limits(self) -> DecodeLimits {
98 DecodeLimits::for_bytes(self.max_state_bytes)
99 }
100}