structured_asn1/value.rs
1//! The contents of primitive elements, read without copying them.
2//!
3//! Tags are deliberately not checked here. Implicit tagging replaces the tag of
4//! a value with the one its position gives it, so a `[0] IMPLICIT INTEGER` is
5//! still an integer and the caller is the only one who knows that. What is
6//! checked is the encoding of the value itself, which no amount of tagging
7//! changes.
8
9use crate::error::ErrorCode;
10use crate::length::Encoding;
11use crate::memory::{Memory, MemoryError, OwnedString};
12
13mod owned;
14mod text;
15pub use owned::OwnedOid;
16
17/// An object identifier, as the arcs are encoded, without the tag or length.
18///
19/// Held encoded rather than decoded because identity is the encoding: two
20/// identifiers are the same one when their bytes match, and comparing rendered
21/// text instead would make `1.2.840.113549` and a lookalike written with an
22/// arc padded to the same digits into the same identifier.
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
24pub struct Oid<'a>(&'a [u8]);
25
26impl<'a> Oid<'a> {
27 /// An identifier from written-out bytes, validated as it is built.
28 ///
29 /// For the constants a schema names. The same rules the document reader
30 /// enforces are held here by construction, so a table entry cannot name
31 /// something no document could: a malformed constant fails the build
32 /// during constant evaluation, and a malformed runtime call panics at
33 /// the constructor rather than printing nonsense later. Document bytes
34 /// never come through here; the parser validates them.
35 ///
36 /// # Panics
37 ///
38 /// When the bytes are not a well formed object identifier: empty, a
39 /// padded arc, or a truncated continuation. Width is not among them, as
40 /// it is not for a document: the encoding bounds no subidentifier
41 /// (X.690 8.19.2).
42 #[must_use]
43 pub const fn from_bytes(bytes: &'a [u8]) -> Self {
44 assert!(
45 Self::well_formed(bytes),
46 "not a well formed object identifier"
47 );
48 Self(bytes)
49 }
50
51 /// The validation the constructor asserts, mirroring the document
52 /// reader's rules in a form constant evaluation can run.
53 const fn well_formed(bytes: &[u8]) -> bool {
54 if bytes.is_empty() {
55 return false;
56 }
57 let mut starting = true;
58 let mut at = 0;
59 while at < bytes.len() {
60 let byte = bytes[at];
61 // A leading 0x80 pads the arc with a zero seven-bit group.
62 if starting && byte == 0x80 {
63 return false;
64 }
65 starting = byte & 0x80 == 0;
66 at += 1;
67 }
68 // The last byte asked for a continuation that never came.
69 starting
70 }
71
72 /// The encoded arcs.
73 #[must_use]
74 pub fn as_bytes(self) -> &'a [u8] {
75 self.0
76 }
77
78 /// Exact dotted-decimal text, admitting conversion work and storage in
79 /// the current execution domain. The result retains its capacity charge.
80 /// Width is unrestricted by ASN.1; insufficient resources return an error.
81 pub fn text(self, execution: &Memory) -> Result<OwnedString, MemoryError> {
82 text::oid(self, execution)
83 }
84
85 /// The arcs, root first.
86 ///
87 /// Constructing the iterator is constant work. Advancing it scans the
88 /// encoded groups of one subidentifier; the caller must admit that work
89 /// when iterating untrusted input. [`Self::text`] accounts for its traversal.
90 #[must_use]
91 pub fn arcs(self) -> Arcs<'a> {
92 Arcs {
93 bytes: self.0,
94 first: true,
95 pending: None,
96 }
97 }
98}
99
100/// One arc of an [`Oid`].
101///
102/// The encoding bounds no subidentifier (X.690 8.19.2), so an arc may be
103/// wider than any integer this crate names. Such an arc keeps the base-128
104/// groups it was written in, and the joint offset the first subidentifier
105/// carries, so it still prints the number the document holds instead of
106/// reporting some other one.
107#[derive(Debug, Clone, Copy, PartialEq, Eq)]
108pub struct Arc<'a> {
109 /// The value, where it fits.
110 value: Option<u64>,
111 /// The groups it was written in, for one that does not.
112 groups: &'a [u8],
113 /// What the first subidentifier's packing adds to this arc: 0, 40 or 80
114 /// (X.690 8.19.4). Zero for every later arc.
115 offset: u64,
116}
117
118impl Arc<'_> {
119 /// Exact decimal text, with conversion and retained storage charged to
120 /// the current execution domain. No alternate-width rendering is used.
121 pub fn text(self, execution: &Memory) -> Result<OwnedString, MemoryError> {
122 text::arc(self, execution)
123 }
124
125 /// The arc where it fits sixty-four bits, and `None` where nothing that
126 /// wide could hold it. This accessor reads the already decoded value in
127 /// constant work; decoding occurred when the arcs iterator advanced.
128 #[must_use]
129 pub fn as_u64(self) -> Option<u64> {
130 self.value
131 }
132}
133
134/// The largest power of ten a remainder fits, and how many digits it writes.
135/// Dividing by this rather than by ten is what keeps the number of passes
136/// over the groups to a nineteenth of the digits.
137const DECIMAL_BLOCK: u128 = 10_000_000_000_000_000_000;
138const DECIMAL_BLOCK_DIGITS: usize = 19;
139
140/// An arc's base-128 groups with the joint offset already taken off, read
141/// where the document put them.
142///
143/// The offset comes off the least significant group, and where that group
144/// cannot pay it the borrow travels back through the zero groups above it
145/// (X.690 8.19.4). That is a suffix and nothing else, so which groups it
146/// changes is one index, found by a scan that copies nothing.
147struct Groups<'a> {
148 encoded: &'a [u8],
149 /// What the least significant group owes: 0, 40 or 80.
150 offset: u64,
151 /// The group the borrow reaches back to and stops at.
152 stop: usize,
153}
154
155impl<'a> Groups<'a> {
156 fn of(encoded: &'a [u8], offset: u64) -> Self {
157 let last = encoded.len() - 1;
158 let mut stop = last;
159 // The borrow cannot travel past the groups: an arc that is read here
160 // did not fit sixty-four bits, so it has more groups than the offset
161 // spans and the leading one is not zero.
162 while stop > 0 {
163 let owed = if stop == last { offset } else { 1 };
164 if u64::from(encoded[stop] & 0x7f) >= owed {
165 break;
166 }
167 stop -= 1;
168 }
169 Self {
170 encoded,
171 offset,
172 stop,
173 }
174 }
175
176 fn count(&self) -> usize {
177 self.encoded.len()
178 }
179
180 /// The groups from one position on, most significant first.
181 fn iter_from(&self, first: usize) -> impl ExactSizeIterator<Item = u8> + '_ {
182 (first..self.encoded.len()).map(|at| self.at(at))
183 }
184
185 /// The groups, most significant first.
186 fn iter(&self) -> impl ExactSizeIterator<Item = u8> + '_ {
187 self.iter_from(0)
188 }
189
190 /// How many groups the arc has once the leading zeros the borrow can
191 /// leave behind are dropped.
192 fn significant(&self) -> usize {
193 let leading = self.iter().take_while(|group| *group == 0).count();
194 self.encoded.len() - leading
195 }
196
197 fn at(&self, at: usize) -> u8 {
198 let last = self.encoded.len() - 1;
199 let group = u64::from(self.encoded[at] & 0x7f);
200 let owed = if at == last { self.offset } else { 1 };
201 let value = match at.cmp(&self.stop) {
202 core::cmp::Ordering::Less => group,
203 // The scan stopped here because this group can pay.
204 core::cmp::Ordering::Equal => group - owed,
205 // Above the group that pays, so this one lends and takes the
206 // base back.
207 core::cmp::Ordering::Greater => group + 128 - owed,
208 };
209 u8::try_from(value).expect("a group below the base")
210 }
211}
212
213/// The arcs of an [`Oid`], root first.
214#[derive(Debug, Clone)]
215pub struct Arcs<'a> {
216 bytes: &'a [u8],
217 first: bool,
218 pending: Option<Arc<'a>>,
219}
220
221impl<'a> Iterator for Arcs<'a> {
222 type Item = Arc<'a>;
223
224 fn next(&mut self) -> Option<Arc<'a>> {
225 if let Some(second) = self.pending.take() {
226 return Some(second);
227 }
228
229 // Accumulated wide so that a value one bit past the narrow width is
230 // still recognized as not fitting rather than wrapping. Wider than
231 // that keeps its groups: the last byte of the slice cannot ask for
232 // continuation, which was established when the identifier was read.
233 //
234 // Multiplied rather than shifted: a shift by seven is always a
235 // shift this type permits, so it reports nothing when the seven bits
236 // it drops were significant, and the arc would read as whatever
237 // survived. The multiplication answers about the value instead.
238 let mut value: Option<u128> = Some(0);
239 let mut taken = 0;
240 for byte in self.bytes {
241 taken += 1;
242 value = value
243 .and_then(|value| value.checked_mul(128)?.checked_add(u128::from(byte & 0x7f)));
244 if byte & 0x80 == 0 {
245 break;
246 }
247 }
248 let (groups, rest) = self.bytes.split_at(taken);
249 self.bytes = rest;
250 if taken == 0 {
251 return None;
252 }
253
254 let arc = |value: Option<u128>, offset: u64| Arc {
255 value: value.and_then(|value| u64::try_from(value - u128::from(offset)).ok()),
256 groups,
257 offset,
258 };
259 if self.first {
260 self.first = false;
261 // The first byte carries two arcs. Above 79 the root is 2 and the
262 // second arc continues past 39, which is how identifiers such as
263 // 2.999 are written. A value too wide to have been compared is
264 // above 79 either way: its groups reach past the root's own.
265 let root = match value {
266 Some(0..=39) => 0,
267 Some(40..=79) => 1,
268 _ => 2,
269 };
270 self.pending = Some(arc(value, root * 40));
271 return Some(Arc {
272 value: Some(root),
273 groups: &[],
274 offset: 0,
275 });
276 }
277
278 Some(arc(value, 0))
279 }
280}
281
282/// An integer, as its two's complement bytes.
283///
284/// Serial numbers reach twenty bytes and public key moduli are far larger, so
285/// this stays as it was encoded and converts on request.
286#[derive(Debug, Clone, Copy, PartialEq, Eq)]
287pub struct Integer<'a>(&'a [u8]);
288
289impl<'a> Integer<'a> {
290 /// The two's complement bytes, most significant first.
291 #[must_use]
292 pub fn as_bytes(self) -> &'a [u8] {
293 self.0
294 }
295
296 /// Whether the value is below zero.
297 #[must_use]
298 pub fn is_negative(self) -> bool {
299 self.0.first().is_some_and(|first| first & 0x80 != 0)
300 }
301
302 /// The value as an unsigned number, or `None` when it is negative or wider
303 /// than sixty-four bits.
304 #[must_use]
305 pub fn as_u64(self) -> Option<u64> {
306 if self.is_negative() {
307 return None;
308 }
309 // A leading zero is the sign byte of a value whose top bit is set, and
310 // carries no magnitude.
311 let magnitude = match self.0 {
312 [0x00, rest @ ..] => rest,
313 all => all,
314 };
315 if magnitude.len() > 8 {
316 return None;
317 }
318 Some(
319 magnitude
320 .iter()
321 .fold(0u64, |value, byte| (value << 8) | u64::from(*byte)),
322 )
323 }
324
325 /// The value as a signed number, or `None` when it is wider than
326 /// sixty-four bits.
327 #[must_use]
328 pub fn as_i64(self) -> Option<i64> {
329 if self.0.len() > 8 {
330 return None;
331 }
332 let sign = if self.is_negative() { -1i64 } else { 0 };
333 Some(
334 self.0
335 .iter()
336 .fold(sign, |value, byte| (value << 8) | i64::from(*byte)),
337 )
338 }
339
340 /// The value as a count, or `None` when it does not fit one.
341 #[must_use]
342 pub fn as_u32(self) -> Option<u32> {
343 self.as_u64().and_then(|value| u32::try_from(value).ok())
344 }
345}
346
347/// A string of bits, which is not the same as a string of bytes: the last byte
348/// may be partly padding, and a key usage of one bit occupies one of them.
349#[derive(Debug, Clone, Copy, PartialEq, Eq)]
350pub struct BitString<'a> {
351 bytes: &'a [u8],
352 unused: u8,
353}
354
355impl<'a> BitString<'a> {
356 /// The bytes holding the bits, padding included.
357 #[must_use]
358 pub fn as_bytes(self) -> &'a [u8] {
359 self.bytes
360 }
361
362 /// How many bits of the last byte are padding.
363 #[must_use]
364 pub fn unused_bits(self) -> u8 {
365 self.unused
366 }
367
368 /// How many bits the string holds.
369 #[must_use]
370 pub fn len(self) -> u64 {
371 // Every byte holds eight bits less whatever the last one pads, and the
372 // count of padding bits is below eight whenever the string is not
373 // empty, so neither the multiplication nor the subtraction can wrap.
374 (self.bytes.len() as u64) * 8 - u64::from(self.unused)
375 }
376
377 /// Whether the string holds no bits at all.
378 #[must_use]
379 pub fn is_empty(self) -> bool {
380 self.bytes.is_empty()
381 }
382
383 /// Whether the bit at `position` is set, counting from the first bit of the
384 /// first byte. Padding and anything past the end read as unset, which is
385 /// what a key usage shorter than the bit asked about means.
386 #[must_use]
387 pub fn bit(self, position: u64) -> bool {
388 if position >= self.len() {
389 return false;
390 }
391 // Below the bit count, so the byte it sits in exists and its index fits
392 // whatever a slice index is on this target.
393 let within = (position % 8) as u32;
394 usize::try_from(position / 8)
395 .ok()
396 .and_then(|byte| self.bytes.get(byte))
397 .is_some_and(|value| value & (0x80u8 >> within) != 0)
398 }
399
400 /// The bytes with the padding bits of the last one cleared, for a value
401 /// meant to be read as octets.
402 #[must_use]
403 pub fn octets(self) -> Option<&'a [u8]> {
404 (self.unused == 0).then_some(self.bytes)
405 }
406}
407
408/// Reads an object identifier's contents.
409pub(crate) fn oid(contents: &[u8]) -> Result<Oid<'_>, ErrorCode> {
410 if contents.is_empty() {
411 return Err(ErrorCode::MalformedOid);
412 }
413
414 // No arc is bounded here. The encoding bounds no subidentifier
415 // (X.690 8.19.2), so a width this reader cannot hold in an integer is
416 // still a number the document names: refusing it would abort a whole
417 // certificate over an arc that only ever gets printed. An arc past the
418 // integer keeps its groups and prints from them.
419 let mut starting = true;
420 for byte in contents {
421 // A leading 0x80 pads the arc with a zero seven-bit group, which is a
422 // second way to write a number that already has one.
423 if starting && *byte == 0x80 {
424 return Err(ErrorCode::MalformedOid);
425 }
426 starting = byte & 0x80 == 0;
427 }
428
429 // The last byte asked for a continuation that never came.
430 if !starting {
431 return Err(ErrorCode::MalformedOid);
432 }
433
434 Ok(Oid(contents))
435}
436
437/// Reads an integer's contents.
438pub(crate) fn integer(contents: &[u8]) -> Result<Integer<'_>, ErrorCode> {
439 if contents.is_empty() {
440 return Err(ErrorCode::IntegerEmpty);
441 }
442 if redundant_sign_byte(contents) {
443 return Err(ErrorCode::IntegerNotMinimal);
444 }
445 Ok(Integer(contents))
446}
447
448// X.690 ยง8.3.2 applies already to BER: only sign octets whose removal
449// preserves the next octet's sign are redundant. Strict and recovery paths
450// share this predicate; a required sign byte must never be stripped.
451// <https://www.itu.int/rec/T-REC-X.690-202102-I/en>
452fn redundant_sign_byte(contents: &[u8]) -> bool {
453 match contents {
454 [0x00, second, ..] => second & 0x80 == 0,
455 [0xff, second, ..] => second & 0x80 != 0,
456 _ => false,
457 }
458}
459
460/// The numeric view of a nonminimal primitive INTEGER, after scan admission.
461pub(crate) fn recovered_integer(mut contents: &[u8]) -> Integer<'_> {
462 debug_assert!(contents.len() >= 2);
463 while redundant_sign_byte(contents) {
464 contents = &contents[1..];
465 }
466 Integer(contents)
467}
468
469/// Reads a bit string's contents.
470pub(crate) fn bit_string(contents: &[u8], encoding: Encoding) -> Result<BitString<'_>, ErrorCode> {
471 let (unused, bytes) = contents
472 .split_first()
473 .ok_or(ErrorCode::MalformedBitString)?;
474 let unused = *unused;
475
476 if unused > 7 || (bytes.is_empty() && unused != 0) {
477 return Err(ErrorCode::MalformedBitString);
478 }
479
480 // Padding that carries data is a place to put bytes that a reader ignoring
481 // them will not report, and DER settles it by requiring zeroes. BER does
482 // not: X.690 places the zero-padding rule in clause 11.2, among the
483 // restrictions that only CER and DER add, so a BER document with set
484 // padding bits is well formed and is read as it was written. The bits
485 // never reach a value either way: the length excludes them, asking for a
486 // bit inside them answers unset, and octets() refuses a padded string.
487 if encoding.is_der()
488 && unused > 0
489 && let Some(last) = bytes.last()
490 && last & (0xffu8 >> (8 - unused)) != 0
491 {
492 return Err(ErrorCode::MalformedBitString);
493 }
494
495 Ok(BitString { bytes, unused })
496}
497
498/// Reads a boolean's contents.
499pub(crate) fn boolean(contents: &[u8], encoding: Encoding) -> Result<bool, ErrorCode> {
500 match contents {
501 [0x00] => Ok(false),
502 [0xff] => Ok(true),
503 // BER lets any non-zero byte mean true. DER settles on one spelling,
504 // and accepting the others where a signature covers the bytes would
505 // make several documents into one.
506 [_] if !encoding.is_der() => Ok(true),
507 _ => Err(ErrorCode::MalformedBoolean),
508 }
509}
510
511/// Reads a real's contents, which the encoding settles down to the last
512/// octet (X.690 8.5) and the distinguished rules settle further (11.3).
513///
514/// Nothing here reads the number: no schema this product parses has a real
515/// in it, and one arrives only inside a value preserved for somebody else.
516/// What that somebody is promised is that the octets are a value of the type
517/// they claim, which is what this decides.
518pub(crate) fn real(contents: &[u8], encoding: Encoding) -> Result<(), ErrorCode> {
519 let Some((first, rest)) = contents.split_first() else {
520 // Plus zero is written with no contents octets at all (8.5.2).
521 return Ok(());
522 };
523 match first & 0xc0 {
524 // A special value or minus zero: one octet, and one of the four
525 // (8.5.9). The rest of that range is reserved.
526 0x40 => (rest.is_empty() && matches!(first, 0x40..=0x43))
527 .then_some(())
528 .ok_or(ErrorCode::MalformedReal),
529 // Decimal (8.5.8): the form octet names an ISO 6093 representation,
530 // and the octets after it are that representation.
531 0x00 => decimal_real(*first, rest, encoding),
532 // Binary (8.5.7): a sign, a base, a scaling factor and an exponent
533 // in the first octet, then the exponent and the mantissa.
534 _ => binary_real(*first, rest, encoding),
535 }
536}
537
538/// The decimal form of a real.
539fn decimal_real(first: u8, field: &[u8], encoding: Encoding) -> Result<(), ErrorCode> {
540 let malformed = || ErrorCode::MalformedReal;
541 // NR1, NR2 and NR3 are the three the encoding names; the rest of the
542 // range is reserved (8.5.8). The distinguished rules use NR3 alone
543 // (11.3.2.1).
544 let form = first & 0x3f;
545 if !matches!(form, 1..=3) || (encoding.is_der() && form != 3) {
546 return Err(malformed());
547 }
548 if !encoding.is_der() {
549 // Outside the distinguished rules the field is ISO 6093 as the
550 // sender chose to write it, and reading it is not this crate's
551 // business: what is checkable is that there is one.
552 return (!field.is_empty()).then_some(()).ok_or_else(malformed);
553 }
554
555 // NR3 as 11.3.2 writes it: an optional minus, the mantissa's digits, a
556 // full stop, the exponent mark, and the exponent. No space anywhere
557 // (11.3.2.2), a leading minus only where the value is negative
558 // (11.3.2.3), neither the first nor the last digit of the mantissa a
559 // zero (11.3.2.4), the stop immediately after that last digit
560 // (11.3.2.5), and a zero exponent written as `+0` with no other
561 // exponent signed or led by a zero (11.3.2.6).
562 let digits = field.strip_prefix(b"-").unwrap_or(field);
563 let (mantissa, exponent) = digits
564 .iter()
565 .position(|byte| *byte == b'.')
566 .map(|stop| digits.split_at(stop))
567 .ok_or_else(malformed)?;
568 let exponent = exponent.strip_prefix(b".E").ok_or_else(malformed)?;
569
570 let sound_mantissa = mantissa.first().is_some_and(|digit| *digit != b'0')
571 && mantissa.last().is_some_and(|digit| *digit != b'0')
572 && mantissa.iter().all(u8::is_ascii_digit);
573 let sound_exponent = exponent == b"+0"
574 || exponent
575 .strip_prefix(b"-")
576 .unwrap_or(exponent)
577 .split_first()
578 .is_some_and(|(lead, rest)| {
579 lead.is_ascii_digit() && *lead != b'0' && rest.iter().all(u8::is_ascii_digit)
580 });
581 (sound_mantissa && sound_exponent)
582 .then_some(())
583 .ok_or_else(malformed)
584}
585
586/// The binary form of a real.
587fn binary_real(first: u8, rest: &[u8], encoding: Encoding) -> Result<(), ErrorCode> {
588 let malformed = || ErrorCode::MalformedReal;
589 // The distinguished rules use base two and no scaling factor, and write
590 // both parts in the fewest octets (11.3.1). Base 11 is reserved in
591 // either encoding (8.5.7.2).
592 let base = (first >> 4) & 0x03;
593 let scaling = (first >> 2) & 0x03;
594 if base == 0x03 || (encoding.is_der() && (base != 0 || scaling != 0)) {
595 return Err(malformed());
596 }
597
598 // How the exponent is written: one, two or three octets, or a count and
599 // then that many (8.5.7.4).
600 let (exponent, mantissa) = match first & 0x03 {
601 0 => rest.split_at_checked(1),
602 1 => rest.split_at_checked(2),
603 2 => rest.split_at_checked(3),
604 _ => rest.split_first().and_then(|(count, after)| {
605 // At least one octet, and the count is not part of the number.
606 // Past three the selector cannot say the length itself, which is
607 // what this form is for; at three or fewer it spends an octet
608 // saying what a selector already says, and the distinguished
609 // rules ask for the fewest octets (11.3.1).
610 let shortest = !encoding.is_der() || *count > 3;
611 (*count >= 1 && shortest).then(|| after.split_at_checked(usize::from(*count)))?
612 }),
613 }
614 .ok_or_else(malformed)?;
615
616 // The first nine bits of an exponent written in more than one octet are
617 // neither all zeros nor all ones: that is what the long form says
618 // (8.5.7.4 d), and what writing it in the fewest octets means for the
619 // shorter forms too.
620 if let [lead, next, ..] = exponent {
621 let padded = *lead == 0x00 && next & 0x80 == 0;
622 let signed = *lead == 0xff && next & 0x80 != 0;
623 if padded || signed {
624 return Err(malformed());
625 }
626 }
627
628 // The mantissa is there, written in the fewest octets, and odd: the
629 // normalization shifts it until its least significant bit is one, and a
630 // mantissa of zero is written as the value zero instead (11.3.1).
631 match mantissa {
632 // There, and without a leading octet that adds nothing.
633 [] | [0x00, ..] => Err(malformed()),
634 [.., last] if encoding.is_der() && last & 0x01 == 0 => Err(malformed()),
635 _ => Ok(()),
636 }
637}
638
639/// Reads a null's contents, which are none.
640pub(crate) fn null(contents: &[u8]) -> Result<(), ErrorCode> {
641 if contents.is_empty() {
642 Ok(())
643 } else {
644 Err(ErrorCode::MalformedNull)
645 }
646}
647
648#[cfg(test)]
649mod tests;