Skip to main content

der/asn1/integer/
uint.rs

1//! Unsigned integer decoders/encoders.
2
3use super::value_cmp;
4use crate::{
5    AnyRef, BytesRef, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader,
6    Result, Tag, ValueOrd, Writer, ord::OrdIsValueOrd,
7};
8use core::cmp::Ordering;
9
10#[cfg(feature = "alloc")]
11pub use allocating::Uint;
12
13macro_rules! impl_encoding_traits {
14    ($($uint:ty),+) => {
15        $(
16            impl<'a> DecodeValue<'a> for $uint {
17                type Error = $crate::Error;
18
19                fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
20                    // Integers always encodes as a signed value, unsigned gets a leading 0x00 that
21                    // needs to be stripped off. We need to provide room for it.
22                    const UNSIGNED_HEADROOM: usize = 1;
23
24                    let mut buf = [0u8; (Self::BITS as usize / 8) + UNSIGNED_HEADROOM];
25                    let max_length = u32::from(header.length()) as usize;
26
27                    if max_length == 0 {
28                        return Err(reader.error(Tag::Integer.length_error()));
29                    }
30
31                    if max_length > buf.len() {
32                        return Err(reader.error(Self::TAG.non_canonical_error()));
33                    }
34
35                    let bytes = reader.read_into(&mut buf[..max_length])?;
36                    let result = Self::from_be_bytes(
37                        decode_to_array(bytes).map_err(|err| reader.error(err.kind()))?
38                    );
39
40                    // Ensure we compute the same encoded length as the original any value
41                    if header.length() != result.value_len()? {
42                        return Err(reader.error(Self::TAG.non_canonical_error()));
43                    }
44
45                    Ok(result)
46                }
47            }
48
49            impl EncodeValue for $uint {
50                fn value_len(&self) -> Result<Length> {
51                    encoded_len(&self.to_be_bytes())
52                }
53
54                fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
55                    encode_bytes(writer, &self.to_be_bytes())
56                }
57            }
58
59            impl FixedTag for $uint {
60                const TAG: Tag = Tag::Integer;
61            }
62
63            impl ValueOrd for $uint {
64                fn value_cmp(&self, other: &Self) -> Result<Ordering> {
65                    value_cmp(*self, *other)
66                }
67            }
68
69            impl TryFrom<AnyRef<'_>> for $uint {
70                type Error = Error;
71
72                fn try_from(any: AnyRef<'_>) -> Result<Self> {
73                    any.decode_as()
74                }
75            }
76        )+
77    };
78}
79
80impl_encoding_traits!(u8, u16, u32, u64, u128);
81
82/// Unsigned arbitrary precision ASN.1 `INTEGER` reference type.
83///
84/// Provides direct access to the underlying big endian bytes which comprise an
85/// unsigned integer value.
86///
87/// Intended for use cases like very large integers that are used in
88/// cryptographic applications (e.g. keys, signatures).
89#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
90pub struct UintRef<'a> {
91    /// Inner value
92    inner: &'a BytesRef,
93}
94
95impl<'a> UintRef<'a> {
96    /// Create a new [`UintRef`] from a byte slice.
97    ///
98    /// # Errors
99    /// Returns [`Error`] in the event `bytes` is too long.
100    pub fn new(bytes: &'a [u8]) -> Result<Self> {
101        let inner = BytesRef::new(strip_leading_zeroes(bytes))
102            .map_err(|_| ErrorKind::Length { tag: Self::TAG })?;
103
104        Ok(Self { inner })
105    }
106
107    /// Borrow the inner byte slice which contains the least significant bytes
108    /// of a big endian integer value with all leading zeros stripped.
109    #[must_use]
110    pub fn as_bytes(&self) -> &'a [u8] {
111        self.inner.as_slice()
112    }
113
114    /// Get the length of this [`UintRef`] in bytes.
115    #[must_use]
116    pub fn len(&self) -> Length {
117        self.inner.len()
118    }
119
120    /// Is the inner byte slice empty?
121    #[must_use]
122    pub fn is_empty(&self) -> bool {
123        self.inner.is_empty()
124    }
125}
126
127impl_any_conversions!(UintRef<'a>, 'a);
128
129impl<'a> DecodeValue<'a> for UintRef<'a> {
130    type Error = Error;
131
132    fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
133        let bytes = <&'a BytesRef>::decode_value(reader, header)?.as_slice();
134        let result = Self::new(decode_to_slice(bytes).map_err(|err| reader.error(err.kind()))?)?;
135
136        // Ensure we compute the same encoded length as the original any value.
137        if result.value_len()? != header.length() {
138            return Err(reader.error(Self::TAG.non_canonical_error()));
139        }
140
141        Ok(result)
142    }
143}
144
145impl EncodeValue for UintRef<'_> {
146    fn value_len(&self) -> Result<Length> {
147        encoded_len(self.inner.as_slice())
148    }
149
150    fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
151        // Add leading `0x00` byte if required
152        if self.value_len()? > self.len() {
153            writer.write_byte(0)?;
154        }
155
156        writer.write(self.as_bytes())
157    }
158}
159
160impl<'a> From<&UintRef<'a>> for UintRef<'a> {
161    fn from(value: &UintRef<'a>) -> UintRef<'a> {
162        *value
163    }
164}
165
166impl FixedTag for UintRef<'_> {
167    const TAG: Tag = Tag::Integer;
168}
169
170impl OrdIsValueOrd for UintRef<'_> {}
171
172#[cfg(feature = "alloc")]
173mod allocating {
174    use super::{UintRef, decode_to_slice, encoded_len, strip_leading_zeroes};
175    use crate::{
176        BytesOwned, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader,
177        Result, Tag, Writer,
178        ord::OrdIsValueOrd,
179        referenced::{OwnedToRef, RefToOwned},
180    };
181    use alloc::borrow::ToOwned;
182
183    /// Unsigned arbitrary precision ASN.1 `INTEGER` type.
184    ///
185    /// Provides heap-allocated storage for big endian bytes which comprise an
186    /// unsigned integer value.
187    ///
188    /// Intended for use cases like very large integers that are used in
189    /// cryptographic applications (e.g. keys, signatures).
190    #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
191    pub struct Uint {
192        /// Inner value
193        inner: BytesOwned,
194    }
195
196    impl Uint {
197        /// Create a new [`Uint`] from a byte slice.
198        ///
199        /// # Errors
200        /// If `bytes` is too long.
201        pub fn new(bytes: &[u8]) -> Result<Self> {
202            let inner = BytesOwned::new(strip_leading_zeroes(bytes))
203                .map_err(|_| ErrorKind::Length { tag: Self::TAG })?;
204
205            Ok(Self { inner })
206        }
207
208        /// Borrow the inner byte slice which contains the least significant bytes
209        /// of a big endian integer value with all leading zeros stripped.
210        #[must_use]
211        pub fn as_bytes(&self) -> &[u8] {
212            self.inner.as_slice()
213        }
214
215        /// Get the length of this [`Uint`] in bytes.
216        #[must_use]
217        pub fn len(&self) -> Length {
218            self.inner.len()
219        }
220
221        /// Is the inner byte slice empty?
222        #[must_use]
223        pub fn is_empty(&self) -> bool {
224            self.inner.is_empty()
225        }
226    }
227
228    impl_any_conversions!(Uint);
229
230    impl<'a> DecodeValue<'a> for Uint {
231        type Error = Error;
232
233        fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
234            let bytes = BytesOwned::decode_value_parts(reader, header, Self::TAG)?;
235            let result = Self::new(decode_to_slice(bytes.as_slice())?)?;
236
237            // Ensure we compute the same encoded length as the original any value.
238            if result.value_len()? != header.length() {
239                return Err(reader.error(Self::TAG.non_canonical_error()));
240            }
241
242            Ok(result)
243        }
244    }
245
246    impl EncodeValue for Uint {
247        fn value_len(&self) -> Result<Length> {
248            encoded_len(self.inner.as_slice())
249        }
250
251        fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
252            // Add leading `0x00` byte if required
253            if self.value_len()? > self.len() {
254                writer.write_byte(0)?;
255            }
256
257            writer.write(self.as_bytes())
258        }
259    }
260
261    impl<'a> From<&UintRef<'a>> for Uint {
262        fn from(value: &UintRef<'a>) -> Uint {
263            Uint {
264                inner: value.inner.into(),
265            }
266        }
267    }
268
269    impl FixedTag for Uint {
270        const TAG: Tag = Tag::Integer;
271    }
272
273    impl OrdIsValueOrd for Uint {}
274
275    impl<'a> RefToOwned<'a> for UintRef<'a> {
276        type Owned = Uint;
277        fn ref_to_owned(&self) -> Self::Owned {
278            let inner = self.inner.to_owned();
279
280            Uint { inner }
281        }
282    }
283
284    impl OwnedToRef for Uint {
285        type Borrowed<'a> = UintRef<'a>;
286        fn owned_to_ref(&self) -> Self::Borrowed<'_> {
287            let inner = self.inner.as_ref();
288
289            UintRef { inner }
290        }
291    }
292
293    macro_rules! impl_from_traits {
294        ($($uint:ty),+) => {
295            $(
296                impl TryFrom<$uint> for Uint {
297                    type Error = $crate::Error;
298
299                    fn try_from(value: $uint) -> $crate::Result<Self> {
300                        let mut buf  = [0u8; 17];
301                        let buf = $crate::encode::encode_value_to_slice(&mut buf, &value)?;
302                        Uint::new(buf)
303                    }
304                }
305            )+
306        };
307    }
308
309    impl_from_traits!(u8, u16, u32, u64, u128);
310
311    #[cfg(test)]
312    #[allow(clippy::unwrap_used)]
313    mod tests {
314        use super::Uint;
315
316        #[test]
317        fn from_uint() {
318            assert_eq!(Uint::try_from(u8::MIN).unwrap().as_bytes(), &[0]);
319            assert_eq!(Uint::try_from(u8::MAX).unwrap().as_bytes(), &[0xFF]);
320            assert_eq!(Uint::try_from(u16::MIN).unwrap().as_bytes(), &[0]);
321            assert_eq!(Uint::try_from(u16::MAX).unwrap().as_bytes(), &[0xFF; 2]);
322            assert_eq!(Uint::try_from(u32::MIN).unwrap().as_bytes(), &[0]);
323            assert_eq!(Uint::try_from(u32::MAX).unwrap().as_bytes(), &[0xFF; 4]);
324            assert_eq!(Uint::try_from(u64::MIN).unwrap().as_bytes(), &[0]);
325            assert_eq!(Uint::try_from(u64::MAX).unwrap().as_bytes(), &[0xFF; 8]);
326            assert_eq!(Uint::try_from(u128::MIN).unwrap().as_bytes(), &[0]);
327            assert_eq!(Uint::try_from(u128::MAX).unwrap().as_bytes(), &[0xFF; 16]);
328        }
329    }
330}
331
332/// Decode an unsigned integer into a big endian byte slice with all leading
333/// zeroes removed.
334///
335/// Returns a byte array of the requested size containing a big endian integer.
336pub(crate) fn decode_to_slice(bytes: &[u8]) -> Result<&[u8]> {
337    // The `INTEGER` type always encodes a signed value, so for unsigned
338    // values the leading `0x00` byte may need to be removed.
339    //
340    // We also disallow a leading byte which would overflow a signed ASN.1
341    // integer (since we're decoding an unsigned integer).
342    // We expect all such cases to have a leading `0x00` byte.
343    match bytes {
344        [] => Err(Tag::Integer.non_canonical_error().into()),
345        [0] => Ok(bytes),
346        [0, byte, ..] if *byte < 0x80 => Err(Tag::Integer.non_canonical_error().into()),
347        [0, rest @ ..] => Ok(rest),
348        [byte, ..] if *byte >= 0x80 => Err(Tag::Integer.value_error().into()),
349        _ => Ok(bytes),
350    }
351}
352
353/// Decode an unsigned integer into a byte array of the requested size
354/// containing a big endian integer.
355pub(super) fn decode_to_array<const N: usize>(bytes: &[u8]) -> Result<[u8; N]> {
356    let input = decode_to_slice(bytes)?;
357
358    // Compute number of leading zeroes to add
359    let num_zeroes = N
360        .checked_sub(input.len())
361        .ok_or_else(|| Tag::Integer.length_error())?;
362
363    // Copy input into `N`-sized output buffer with leading zeroes
364    let mut output = [0u8; N];
365    output[num_zeroes..].copy_from_slice(input);
366    Ok(output)
367}
368
369/// Encode the given big endian bytes representing an integer as ASN.1 DER.
370pub(crate) fn encode_bytes<W>(writer: &mut W, bytes: &[u8]) -> Result<()>
371where
372    W: Writer + ?Sized,
373{
374    let bytes = strip_leading_zeroes(bytes);
375
376    if needs_leading_zero(bytes) {
377        writer.write_byte(0)?;
378    }
379
380    writer.write(bytes)
381}
382
383/// Get the encoded length for the given unsigned integer serialized as bytes.
384#[inline]
385pub(crate) fn encoded_len(bytes: &[u8]) -> Result<Length> {
386    let bytes = strip_leading_zeroes(bytes);
387    Length::try_from(bytes.len())? + u8::from(needs_leading_zero(bytes))
388}
389
390/// Strip the leading zeroes from the given byte slice
391pub(crate) fn strip_leading_zeroes(mut bytes: &[u8]) -> &[u8] {
392    while let Some((byte, rest)) = bytes.split_first() {
393        if *byte == 0 && !rest.is_empty() {
394            bytes = rest;
395        } else {
396            break;
397        }
398    }
399
400    bytes
401}
402
403/// Does the given integer need a leading zero?
404fn needs_leading_zero(bytes: &[u8]) -> bool {
405    matches!(bytes.first(), Some(byte) if *byte >= 0x80)
406}
407
408#[cfg(test)]
409#[allow(clippy::unwrap_used)]
410mod tests {
411    use super::{UintRef, decode_to_array};
412    use crate::{AnyRef, Decode, Encode, ErrorKind, SliceWriter, Tag, asn1::integer::tests::*};
413
414    #[test]
415    fn decode_to_array_no_leading_zero() {
416        let arr = decode_to_array::<4>(&[1, 2]).unwrap();
417        assert_eq!(arr, [0, 0, 1, 2]);
418    }
419
420    #[test]
421    fn decode_to_array_leading_zero() {
422        let arr = decode_to_array::<4>(&[0x00, 0xFF, 0xFE]).unwrap();
423        assert_eq!(arr, [0x00, 0x00, 0xFF, 0xFE]);
424    }
425
426    #[test]
427    fn decode_to_array_extra_zero() {
428        let err = decode_to_array::<4>(&[0, 1, 2]).err().unwrap();
429        assert_eq!(err.kind(), ErrorKind::Noncanonical { tag: Tag::Integer });
430    }
431
432    #[test]
433    fn decode_to_array_missing_zero() {
434        // We're decoding an unsigned integer, but this value would be signed
435        let err = decode_to_array::<4>(&[0xFF, 0xFE]).err().unwrap();
436        assert_eq!(err.kind(), ErrorKind::Value { tag: Tag::Integer });
437    }
438
439    #[test]
440    fn decode_to_array_oversized_input() {
441        let err = decode_to_array::<1>(&[1, 2, 3]).err().unwrap();
442        assert_eq!(err.kind(), ErrorKind::Length { tag: Tag::Integer });
443    }
444
445    #[test]
446    fn decode_uintref() {
447        assert_eq!(&[0], UintRef::from_der(I0_BYTES).unwrap().as_bytes());
448        assert_eq!(&[127], UintRef::from_der(I127_BYTES).unwrap().as_bytes());
449        assert_eq!(&[128], UintRef::from_der(I128_BYTES).unwrap().as_bytes());
450        assert_eq!(&[255], UintRef::from_der(I255_BYTES).unwrap().as_bytes());
451
452        assert_eq!(
453            &[0x01, 0x00],
454            UintRef::from_der(I256_BYTES).unwrap().as_bytes()
455        );
456
457        assert_eq!(
458            &[0x7F, 0xFF],
459            UintRef::from_der(I32767_BYTES).unwrap().as_bytes()
460        );
461    }
462
463    #[test]
464    fn encode_uintref() {
465        for &example in &[
466            I0_BYTES,
467            I127_BYTES,
468            I128_BYTES,
469            I255_BYTES,
470            I256_BYTES,
471            I32767_BYTES,
472        ] {
473            let uint = UintRef::from_der(example).unwrap();
474
475            let mut buf = [0u8; 128];
476            let mut writer = SliceWriter::new(&mut buf);
477            uint.encode(&mut writer).unwrap();
478
479            let result = writer.finish().unwrap();
480            assert_eq!(example, result);
481        }
482    }
483
484    #[test]
485    fn reject_oversize_without_extra_zero() {
486        let err = UintRef::try_from(AnyRef::new(Tag::Integer, &[0x81]).unwrap())
487            .err()
488            .unwrap();
489
490        assert_eq!(err.kind(), ErrorKind::Value { tag: Tag::Integer });
491    }
492}