Skip to main content

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;