Skip to main content

der/asn1/integer/
int.rs

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