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