summaryrefslogtreecommitdiffstats
path: root/vendor/der/src/asn1/integer
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/der/src/asn1/integer')
-rw-r--r--vendor/der/src/asn1/integer/bigint.rs152
-rw-r--r--vendor/der/src/asn1/integer/int.rs55
-rw-r--r--vendor/der/src/asn1/integer/uint.rs116
3 files changed, 323 insertions, 0 deletions
diff --git a/vendor/der/src/asn1/integer/bigint.rs b/vendor/der/src/asn1/integer/bigint.rs
new file mode 100644
index 000000000..f896406a6
--- /dev/null
+++ b/vendor/der/src/asn1/integer/bigint.rs
@@ -0,0 +1,152 @@
+//! "Big" ASN.1 `INTEGER` types.
+
+use super::uint;
+use crate::{
+ asn1::AnyRef, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, ErrorKind,
+ FixedTag, Header, Length, Reader, Result, Tag, Writer,
+};
+
+/// "Big" unsigned ASN.1 `INTEGER` 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: ByteSlice<'a>,
+}
+
+impl<'a> UIntRef<'a> {
+ /// Create a new [`UIntRef`] from a byte slice.
+ pub fn new(bytes: &'a [u8]) -> Result<Self> {
+ let inner = ByteSlice::new(uint::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<'a> DecodeValue<'a> for UIntRef<'a> {
+ fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
+ let bytes = ByteSlice::decode_value(reader, header)?.as_slice();
+ let result = Self::new(uint::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> {
+ uint::encoded_len(self.inner.as_slice())
+ }
+
+ fn encode_value(&self, writer: &mut dyn 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> TryFrom<AnyRef<'a>> for UIntRef<'a> {
+ type Error = Error;
+
+ fn try_from(any: AnyRef<'a>) -> Result<UIntRef<'a>> {
+ any.decode_into()
+ }
+}
+
+impl<'a> FixedTag for UIntRef<'a> {
+ const TAG: Tag = Tag::Integer;
+}
+
+impl<'a> OrdIsValueOrd for UIntRef<'a> {}
+
+#[cfg(test)]
+mod tests {
+ use super::UIntRef;
+ use crate::{
+ asn1::{integer::tests::*, AnyRef},
+ Decode, Encode, ErrorKind, SliceWriter, Tag,
+ };
+
+ #[test]
+ fn decode_uint_bytes() {
+ 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_uint_bytes() {
+ 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 });
+ }
+}
diff --git a/vendor/der/src/asn1/integer/int.rs b/vendor/der/src/asn1/integer/int.rs
new file mode 100644
index 000000000..a9fe43890
--- /dev/null
+++ b/vendor/der/src/asn1/integer/int.rs
@@ -0,0 +1,55 @@
+//! Support for encoding negative integers
+
+use super::is_highest_bit_set;
+use crate::{ErrorKind, Length, Result, Writer};
+
+/// Decode an unsigned integer of the specified size.
+///
+/// Returns 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]> {
+ match N.checked_sub(bytes.len()) {
+ Some(offset) => {
+ let mut output = [0xFFu8; N];
+ output[offset..].copy_from_slice(bytes);
+ Ok(output)
+ }
+ None => {
+ let expected_len = Length::try_from(N)?;
+ let actual_len = Length::try_from(bytes.len())?;
+
+ Err(ErrorKind::Incomplete {
+ expected_len,
+ actual_len,
+ }
+ .into())
+ }
+ }
+}
+
+/// Encode the given big endian bytes representing an integer as ASN.1 DER.
+pub(super) fn encode_bytes<W>(writer: &mut W, bytes: &[u8]) -> Result<()>
+where
+ W: Writer + ?Sized,
+{
+ writer.write(strip_leading_ones(bytes))
+}
+
+/// Get the encoded length for the given unsigned integer serialized as bytes.
+#[inline]
+pub(super) fn encoded_len(bytes: &[u8]) -> Result<Length> {
+ Length::try_from(strip_leading_ones(bytes).len())
+}
+
+/// Strip the leading all-ones bytes from the given byte slice.
+fn strip_leading_ones(mut bytes: &[u8]) -> &[u8] {
+ while let Some((byte, rest)) = bytes.split_first() {
+ if *byte == 0xFF && is_highest_bit_set(rest) {
+ bytes = rest;
+ continue;
+ }
+
+ break;
+ }
+
+ bytes
+}
diff --git a/vendor/der/src/asn1/integer/uint.rs b/vendor/der/src/asn1/integer/uint.rs
new file mode 100644
index 000000000..e45a72f2a
--- /dev/null
+++ b/vendor/der/src/asn1/integer/uint.rs
@@ -0,0 +1,116 @@
+//! Unsigned integer decoders/encoders.
+
+use crate::{Length, Result, Tag, Writer};
+
+/// 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.get(0), Some(byte) if *byte >= 0x80)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::decode_to_array;
+ use crate::{ErrorKind, 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 });
+ }
+}