summaryrefslogtreecommitdiffstats
path: root/vendor/der/src/asn1/integer/uint.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/der/src/asn1/integer/uint.rs')
-rw-r--r--vendor/der/src/asn1/integer/uint.rs428
1 files changed, 428 insertions, 0 deletions
diff --git a/vendor/der/src/asn1/integer/uint.rs b/vendor/der/src/asn1/integer/uint.rs
new file mode 100644
index 0000000..95c6297
--- /dev/null
+++ b/vendor/der/src/asn1/integer/uint.rs
@@ -0,0 +1,428 @@
+//! Unsigned integer decoders/encoders.
+
+use super::value_cmp;
+use crate::{
+ ord::OrdIsValueOrd, AnyRef, BytesRef, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag,
+ Header, Length, Reader, Result, Tag, ValueOrd, Writer,
+};
+use core::cmp::Ordering;
+
+#[cfg(feature = "alloc")]
+pub use allocating::Uint;
+
+macro_rules! impl_encoding_traits {
+ ($($uint:ty),+) => {
+ $(
+ impl<'a> DecodeValue<'a> for $uint {
+ fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
+ // Integers always encodes as a signed value, unsigned gets a leading 0x00 that
+ // needs to be stripped off. We need to provide room for it.
+ const UNSIGNED_HEADROOM: usize = 1;
+
+ let mut buf = [0u8; (Self::BITS as usize / 8) + UNSIGNED_HEADROOM];
+ let max_length = u32::from(header.length) as usize;
+
+ if max_length > buf.len() {
+ return Err(Self::TAG.non_canonical_error());
+ }
+
+ let bytes = reader.read_into(&mut buf[..max_length])?;
+
+ let result = Self::from_be_bytes(decode_to_array(bytes)?);
+
+ // Ensure we compute the same encoded length as the original any value
+ if header.length != result.value_len()? {
+ return Err(Self::TAG.non_canonical_error());
+ }
+
+ Ok(result)
+ }
+ }
+
+ impl EncodeValue for $uint {
+ fn value_len(&self) -> Result<Length> {
+ encoded_len(&self.to_be_bytes())
+ }
+
+ fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
+ encode_bytes(writer, &self.to_be_bytes())
+ }
+ }
+
+ impl FixedTag for $uint {
+ const TAG: Tag = Tag::Integer;
+ }
+
+ impl ValueOrd for $uint {
+ fn value_cmp(&self, other: &Self) -> Result<Ordering> {
+ value_cmp(*self, *other)
+ }
+ }
+
+ impl TryFrom<AnyRef<'_>> for $uint {
+ type Error = Error;
+
+ fn try_from(any: AnyRef<'_>) -> Result<Self> {
+ any.decode_as()
+ }
+ }
+ )+
+ };
+}
+
+impl_encoding_traits!(u8, u16, u32, u64, u128);
+
+/// Unsigned arbitrary precision ASN.1 `INTEGER` reference type.
+///
+/// Provides direct access to the underlying big endian bytes which comprise an
+/// unsigned integer value.
+///
+/// Intended for use cases like very large integers that are used in
+/// cryptographic applications (e.g. keys, signatures).
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
+pub struct UintRef<'a> {
+ /// Inner value
+ inner: BytesRef<'a>,
+}
+
+impl<'a> UintRef<'a> {
+ /// Create a new [`UintRef`] from a byte slice.
+ pub fn new(bytes: &'a [u8]) -> Result<Self> {
+ let inner = BytesRef::new(strip_leading_zeroes(bytes))
+ .map_err(|_| ErrorKind::Length { tag: Self::TAG })?;
+
+ Ok(Self { inner })
+ }
+
+ /// Borrow the inner byte slice which contains the least significant bytes
+ /// of a big endian integer value with all leading zeros stripped.
+ pub fn as_bytes(&self) -> &'a [u8] {
+ self.inner.as_slice()
+ }
+
+ /// Get the length of this [`UintRef`] in bytes.
+ pub fn len(&self) -> Length {
+ self.inner.len()
+ }
+
+ /// Is the inner byte slice empty?
+ pub fn is_empty(&self) -> bool {
+ self.inner.is_empty()
+ }
+}
+
+impl_any_conversions!(UintRef<'a>, 'a);
+
+impl<'a> DecodeValue<'a> for UintRef<'a> {
+ fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
+ let bytes = BytesRef::decode_value(reader, header)?.as_slice();
+ let result = Self::new(decode_to_slice(bytes)?)?;
+
+ // Ensure we compute the same encoded length as the original any value.
+ if result.value_len()? != header.length {
+ return Err(Self::TAG.non_canonical_error());
+ }
+
+ Ok(result)
+ }
+}
+
+impl<'a> EncodeValue for UintRef<'a> {
+ fn value_len(&self) -> Result<Length> {
+ encoded_len(self.inner.as_slice())
+ }
+
+ fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
+ // Add leading `0x00` byte if required
+ if self.value_len()? > self.len() {
+ writer.write_byte(0)?;
+ }
+
+ writer.write(self.as_bytes())
+ }
+}
+
+impl<'a> From<&UintRef<'a>> for UintRef<'a> {
+ fn from(value: &UintRef<'a>) -> UintRef<'a> {
+ *value
+ }
+}
+
+impl<'a> FixedTag for UintRef<'a> {
+ const TAG: Tag = Tag::Integer;
+}
+
+impl<'a> OrdIsValueOrd for UintRef<'a> {}
+
+#[cfg(feature = "alloc")]
+mod allocating {
+ use super::{decode_to_slice, encoded_len, strip_leading_zeroes, UintRef};
+ use crate::{
+ ord::OrdIsValueOrd,
+ referenced::{OwnedToRef, RefToOwned},
+ BytesOwned, DecodeValue, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader, Result,
+ Tag, Writer,
+ };
+
+ /// Unsigned arbitrary precision ASN.1 `INTEGER` type.
+ ///
+ /// Provides heap-allocated storage for big endian bytes which comprise an
+ /// unsigned integer value.
+ ///
+ /// Intended for use cases like very large integers that are used in
+ /// cryptographic applications (e.g. keys, signatures).
+ #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
+ pub struct Uint {
+ /// Inner value
+ inner: BytesOwned,
+ }
+
+ impl Uint {
+ /// Create a new [`Uint`] from a byte slice.
+ pub fn new(bytes: &[u8]) -> Result<Self> {
+ let inner = BytesOwned::new(strip_leading_zeroes(bytes))
+ .map_err(|_| ErrorKind::Length { tag: Self::TAG })?;
+
+ Ok(Self { inner })
+ }
+
+ /// Borrow the inner byte slice which contains the least significant bytes
+ /// of a big endian integer value with all leading zeros stripped.
+ pub fn as_bytes(&self) -> &[u8] {
+ self.inner.as_slice()
+ }
+
+ /// Get the length of this [`Uint`] in bytes.
+ pub fn len(&self) -> Length {
+ self.inner.len()
+ }
+
+ /// Is the inner byte slice empty?
+ pub fn is_empty(&self) -> bool {
+ self.inner.is_empty()
+ }
+ }
+
+ impl_any_conversions!(Uint);
+
+ impl<'a> DecodeValue<'a> for Uint {
+ fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
+ let bytes = BytesOwned::decode_value(reader, header)?;
+ let result = Self::new(decode_to_slice(bytes.as_slice())?)?;
+
+ // Ensure we compute the same encoded length as the original any value.
+ if result.value_len()? != header.length {
+ return Err(Self::TAG.non_canonical_error());
+ }
+
+ Ok(result)
+ }
+ }
+
+ impl EncodeValue for Uint {
+ fn value_len(&self) -> Result<Length> {
+ encoded_len(self.inner.as_slice())
+ }
+
+ fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
+ // Add leading `0x00` byte if required
+ if self.value_len()? > self.len() {
+ writer.write_byte(0)?;
+ }
+
+ writer.write(self.as_bytes())
+ }
+ }
+
+ impl<'a> From<&UintRef<'a>> for Uint {
+ fn from(value: &UintRef<'a>) -> Uint {
+ let inner = BytesOwned::new(value.as_bytes()).expect("Invalid Uint");
+ Uint { inner }
+ }
+ }
+
+ impl FixedTag for Uint {
+ const TAG: Tag = Tag::Integer;
+ }
+
+ impl OrdIsValueOrd for Uint {}
+
+ impl<'a> RefToOwned<'a> for UintRef<'a> {
+ type Owned = Uint;
+ fn ref_to_owned(&self) -> Self::Owned {
+ let inner = self.inner.ref_to_owned();
+
+ Uint { inner }
+ }
+ }
+
+ impl OwnedToRef for Uint {
+ type Borrowed<'a> = UintRef<'a>;
+ fn owned_to_ref(&self) -> Self::Borrowed<'_> {
+ let inner = self.inner.owned_to_ref();
+
+ UintRef { inner }
+ }
+ }
+}
+
+/// Decode an unsigned integer into a big endian byte slice with all leading
+/// zeroes removed.
+///
+/// Returns a byte array of the requested size containing a big endian integer.
+pub(crate) fn decode_to_slice(bytes: &[u8]) -> Result<&[u8]> {
+ // The `INTEGER` type always encodes a signed value, so for unsigned
+ // values the leading `0x00` byte may need to be removed.
+ //
+ // We also disallow a leading byte which would overflow a signed ASN.1
+ // integer (since we're decoding an unsigned integer).
+ // We expect all such cases to have a leading `0x00` byte.
+ match bytes {
+ [] => Err(Tag::Integer.non_canonical_error()),
+ [0] => Ok(bytes),
+ [0, byte, ..] if *byte < 0x80 => Err(Tag::Integer.non_canonical_error()),
+ [0, rest @ ..] => Ok(rest),
+ [byte, ..] if *byte >= 0x80 => Err(Tag::Integer.value_error()),
+ _ => Ok(bytes),
+ }
+}
+
+/// Decode an unsigned integer into a byte array of the requested size
+/// containing a big endian integer.
+pub(super) fn decode_to_array<const N: usize>(bytes: &[u8]) -> Result<[u8; N]> {
+ let input = decode_to_slice(bytes)?;
+
+ // Compute number of leading zeroes to add
+ let num_zeroes = N
+ .checked_sub(input.len())
+ .ok_or_else(|| Tag::Integer.length_error())?;
+
+ // Copy input into `N`-sized output buffer with leading zeroes
+ let mut output = [0u8; N];
+ output[num_zeroes..].copy_from_slice(input);
+ Ok(output)
+}
+
+/// Encode the given big endian bytes representing an integer as ASN.1 DER.
+pub(crate) fn encode_bytes<W>(encoder: &mut W, bytes: &[u8]) -> Result<()>
+where
+ W: Writer + ?Sized,
+{
+ let bytes = strip_leading_zeroes(bytes);
+
+ if needs_leading_zero(bytes) {
+ encoder.write_byte(0)?;
+ }
+
+ encoder.write(bytes)
+}
+
+/// Get the encoded length for the given unsigned integer serialized as bytes.
+#[inline]
+pub(crate) fn encoded_len(bytes: &[u8]) -> Result<Length> {
+ let bytes = strip_leading_zeroes(bytes);
+ Length::try_from(bytes.len())? + u8::from(needs_leading_zero(bytes))
+}
+
+/// Strip the leading zeroes from the given byte slice
+pub(crate) fn strip_leading_zeroes(mut bytes: &[u8]) -> &[u8] {
+ while let Some((byte, rest)) = bytes.split_first() {
+ if *byte == 0 && !rest.is_empty() {
+ bytes = rest;
+ } else {
+ break;
+ }
+ }
+
+ bytes
+}
+
+/// Does the given integer need a leading zero?
+fn needs_leading_zero(bytes: &[u8]) -> bool {
+ matches!(bytes.first(), Some(byte) if *byte >= 0x80)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::{decode_to_array, UintRef};
+ use crate::{asn1::integer::tests::*, AnyRef, Decode, Encode, ErrorKind, SliceWriter, Tag};
+
+ #[test]
+ fn decode_to_array_no_leading_zero() {
+ let arr = decode_to_array::<4>(&[1, 2]).unwrap();
+ assert_eq!(arr, [0, 0, 1, 2]);
+ }
+
+ #[test]
+ fn decode_to_array_leading_zero() {
+ let arr = decode_to_array::<4>(&[0x00, 0xFF, 0xFE]).unwrap();
+ assert_eq!(arr, [0x00, 0x00, 0xFF, 0xFE]);
+ }
+
+ #[test]
+ fn decode_to_array_extra_zero() {
+ let err = decode_to_array::<4>(&[0, 1, 2]).err().unwrap();
+ assert_eq!(err.kind(), ErrorKind::Noncanonical { tag: Tag::Integer });
+ }
+
+ #[test]
+ fn decode_to_array_missing_zero() {
+ // We're decoding an unsigned integer, but this value would be signed
+ let err = decode_to_array::<4>(&[0xFF, 0xFE]).err().unwrap();
+ assert_eq!(err.kind(), ErrorKind::Value { tag: Tag::Integer });
+ }
+
+ #[test]
+ fn decode_to_array_oversized_input() {
+ let err = decode_to_array::<1>(&[1, 2, 3]).err().unwrap();
+ assert_eq!(err.kind(), ErrorKind::Length { tag: Tag::Integer });
+ }
+
+ #[test]
+ fn decode_uintref() {
+ assert_eq!(&[0], UintRef::from_der(I0_BYTES).unwrap().as_bytes());
+ assert_eq!(&[127], UintRef::from_der(I127_BYTES).unwrap().as_bytes());
+ assert_eq!(&[128], UintRef::from_der(I128_BYTES).unwrap().as_bytes());
+ assert_eq!(&[255], UintRef::from_der(I255_BYTES).unwrap().as_bytes());
+
+ assert_eq!(
+ &[0x01, 0x00],
+ UintRef::from_der(I256_BYTES).unwrap().as_bytes()
+ );
+
+ assert_eq!(
+ &[0x7F, 0xFF],
+ UintRef::from_der(I32767_BYTES).unwrap().as_bytes()
+ );
+ }
+
+ #[test]
+ fn encode_uintref() {
+ for &example in &[
+ I0_BYTES,
+ I127_BYTES,
+ I128_BYTES,
+ I255_BYTES,
+ I256_BYTES,
+ I32767_BYTES,
+ ] {
+ let uint = UintRef::from_der(example).unwrap();
+
+ let mut buf = [0u8; 128];
+ let mut encoder = SliceWriter::new(&mut buf);
+ uint.encode(&mut encoder).unwrap();
+
+ let result = encoder.finish().unwrap();
+ assert_eq!(example, result);
+ }
+ }
+
+ #[test]
+ fn reject_oversize_without_extra_zero() {
+ let err = UintRef::try_from(AnyRef::new(Tag::Integer, &[0x81]).unwrap())
+ .err()
+ .unwrap();
+
+ assert_eq!(err.kind(), ErrorKind::Value { tag: Tag::Integer });
+ }
+}