diff options
Diffstat (limited to 'vendor/der/src/asn1/set_of.rs')
-rw-r--r-- | vendor/der/src/asn1/set_of.rs | 539 |
1 files changed, 539 insertions, 0 deletions
diff --git a/vendor/der/src/asn1/set_of.rs b/vendor/der/src/asn1/set_of.rs new file mode 100644 index 0000000..ff01312 --- /dev/null +++ b/vendor/der/src/asn1/set_of.rs @@ -0,0 +1,539 @@ +//! ASN.1 `SET OF` support. +//! +//! # Ordering Notes +//! +//! Some DER serializer implementations fail to properly sort elements of a +//! `SET OF`. This is technically non-canonical, but occurs frequently +//! enough that most DER decoders tolerate it. Unfortunately because +//! of that, we must also follow suit. +//! +//! However, all types in this module sort elements of a set at decode-time, +//! ensuring they'll be in the proper order if reserialized. + +use crate::{ + arrayvec, ord::iter_cmp, ArrayVec, Decode, DecodeValue, DerOrd, Encode, EncodeValue, Error, + ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, ValueOrd, Writer, +}; +use core::cmp::Ordering; + +#[cfg(feature = "alloc")] +use {alloc::vec::Vec, core::slice}; + +/// ASN.1 `SET OF` backed by an array. +/// +/// This type implements an append-only `SET OF` type which is stack-based +/// and does not depend on `alloc` support. +// TODO(tarcieri): use `ArrayVec` when/if it's merged into `core` +// See: https://github.com/rust-lang/rfcs/pull/2990 +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct SetOf<T, const N: usize> +where + T: DerOrd, +{ + inner: ArrayVec<T, N>, +} + +impl<T, const N: usize> SetOf<T, N> +where + T: DerOrd, +{ + /// Create a new [`SetOf`]. + pub fn new() -> Self { + Self { + inner: ArrayVec::default(), + } + } + + /// Add an item to this [`SetOf`]. + /// + /// Items MUST be added in lexicographical order according to the + /// [`DerOrd`] impl on `T`. + #[deprecated(since = "0.7.6", note = "use `insert` or `insert_ordered` instead")] + pub fn add(&mut self, new_elem: T) -> Result<()> { + self.insert_ordered(new_elem) + } + + /// Insert an item into this [`SetOf`]. + pub fn insert(&mut self, item: T) -> Result<()> { + self.inner.push(item)?; + der_sort(self.inner.as_mut()) + } + + /// Insert an item into this [`SetOf`]. + /// + /// Items MUST be added in lexicographical order according to the + /// [`DerOrd`] impl on `T`. + pub fn insert_ordered(&mut self, item: T) -> Result<()> { + // Ensure set elements are lexicographically ordered + if let Some(last) = self.inner.last() { + check_der_ordering(last, &item)?; + } + + self.inner.push(item) + } + + /// Get the nth element from this [`SetOf`]. + pub fn get(&self, index: usize) -> Option<&T> { + self.inner.get(index) + } + + /// Iterate over the elements of this [`SetOf`]. + pub fn iter(&self) -> SetOfIter<'_, T> { + SetOfIter { + inner: self.inner.iter(), + } + } + + /// Is this [`SetOf`] empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + /// Number of elements in this [`SetOf`]. + pub fn len(&self) -> usize { + self.inner.len() + } +} + +impl<T, const N: usize> Default for SetOf<T, N> +where + T: DerOrd, +{ + fn default() -> Self { + Self::new() + } +} + +impl<'a, T, const N: usize> DecodeValue<'a> for SetOf<T, N> +where + T: Decode<'a> + DerOrd, +{ + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + reader.read_nested(header.length, |reader| { + let mut result = Self::new(); + + while !reader.is_finished() { + result.inner.push(T::decode(reader)?)?; + } + + der_sort(result.inner.as_mut())?; + validate(result.inner.as_ref())?; + Ok(result) + }) + } +} + +impl<'a, T, const N: usize> EncodeValue for SetOf<T, N> +where + T: 'a + Decode<'a> + Encode + DerOrd, +{ + fn value_len(&self) -> Result<Length> { + self.iter() + .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + for elem in self.iter() { + elem.encode(writer)?; + } + + Ok(()) + } +} + +impl<'a, T, const N: usize> FixedTag for SetOf<T, N> +where + T: Decode<'a> + DerOrd, +{ + const TAG: Tag = Tag::Set; +} + +impl<T, const N: usize> TryFrom<[T; N]> for SetOf<T, N> +where + T: DerOrd, +{ + type Error = Error; + + fn try_from(mut arr: [T; N]) -> Result<SetOf<T, N>> { + der_sort(&mut arr)?; + + let mut result = SetOf::new(); + + for elem in arr { + result.insert_ordered(elem)?; + } + + Ok(result) + } +} + +impl<T, const N: usize> ValueOrd for SetOf<T, N> +where + T: DerOrd, +{ + fn value_cmp(&self, other: &Self) -> Result<Ordering> { + iter_cmp(self.iter(), other.iter()) + } +} + +/// Iterator over the elements of an [`SetOf`]. +#[derive(Clone, Debug)] +pub struct SetOfIter<'a, T> { + /// Inner iterator. + inner: arrayvec::Iter<'a, T>, +} + +impl<'a, T> Iterator for SetOfIter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option<&'a T> { + self.inner.next() + } +} + +impl<'a, T> ExactSizeIterator for SetOfIter<'a, T> {} + +/// ASN.1 `SET OF` backed by a [`Vec`]. +/// +/// This type implements an append-only `SET OF` type which is heap-backed +/// and depends on `alloc` support. +#[cfg(feature = "alloc")] +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct SetOfVec<T> +where + T: DerOrd, +{ + inner: Vec<T>, +} + +#[cfg(feature = "alloc")] +impl<T: DerOrd> Default for SetOfVec<T> { + fn default() -> Self { + Self { + inner: Default::default(), + } + } +} + +#[cfg(feature = "alloc")] +impl<T> SetOfVec<T> +where + T: DerOrd, +{ + /// Create a new [`SetOfVec`]. + pub fn new() -> Self { + Self { + inner: Vec::default(), + } + } + + /// Create a new [`SetOfVec`] from the given iterator. + /// + /// Note: this is an inherent method instead of an impl of the + /// [`FromIterator`] trait in order to be fallible. + #[allow(clippy::should_implement_trait)] + pub fn from_iter<I>(iter: I) -> Result<Self> + where + I: IntoIterator<Item = T>, + { + Vec::from_iter(iter).try_into() + } + + /// Add an element to this [`SetOfVec`]. + /// + /// Items MUST be added in lexicographical order according to the + /// [`DerOrd`] impl on `T`. + #[deprecated(since = "0.7.6", note = "use `insert` or `insert_ordered` instead")] + pub fn add(&mut self, item: T) -> Result<()> { + self.insert_ordered(item) + } + + /// Extend a [`SetOfVec`] using an iterator. + /// + /// Note: this is an inherent method instead of an impl of the + /// [`Extend`] trait in order to be fallible. + pub fn extend<I>(&mut self, iter: I) -> Result<()> + where + I: IntoIterator<Item = T>, + { + self.inner.extend(iter); + der_sort(&mut self.inner) + } + + /// Insert an item into this [`SetOfVec`]. Must be unique. + pub fn insert(&mut self, item: T) -> Result<()> { + self.inner.push(item); + der_sort(&mut self.inner) + } + + /// Insert an item into this [`SetOfVec`]. Must be unique. + /// + /// Items MUST be added in lexicographical order according to the + /// [`DerOrd`] impl on `T`. + pub fn insert_ordered(&mut self, item: T) -> Result<()> { + // Ensure set elements are lexicographically ordered + if let Some(last) = self.inner.last() { + check_der_ordering(last, &item)?; + } + + self.inner.push(item); + Ok(()) + } + + /// Borrow the elements of this [`SetOfVec`] as a slice. + pub fn as_slice(&self) -> &[T] { + self.inner.as_slice() + } + + /// Get the nth element from this [`SetOfVec`]. + pub fn get(&self, index: usize) -> Option<&T> { + self.inner.get(index) + } + + /// Convert this [`SetOfVec`] into the inner [`Vec`]. + pub fn into_vec(self) -> Vec<T> { + self.inner + } + + /// Iterate over the elements of this [`SetOfVec`]. + pub fn iter(&self) -> slice::Iter<'_, T> { + self.inner.iter() + } + + /// Is this [`SetOfVec`] empty? + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + /// Number of elements in this [`SetOfVec`]. + pub fn len(&self) -> usize { + self.inner.len() + } +} + +#[cfg(feature = "alloc")] +impl<T> AsRef<[T]> for SetOfVec<T> +where + T: DerOrd, +{ + fn as_ref(&self) -> &[T] { + self.as_slice() + } +} + +#[cfg(feature = "alloc")] +impl<'a, T> DecodeValue<'a> for SetOfVec<T> +where + T: Decode<'a> + DerOrd, +{ + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> { + reader.read_nested(header.length, |reader| { + let mut inner = Vec::new(); + + while !reader.is_finished() { + inner.push(T::decode(reader)?); + } + + der_sort(inner.as_mut())?; + validate(inner.as_ref())?; + Ok(Self { inner }) + }) + } +} + +#[cfg(feature = "alloc")] +impl<'a, T> EncodeValue for SetOfVec<T> +where + T: 'a + Decode<'a> + Encode + DerOrd, +{ + fn value_len(&self) -> Result<Length> { + self.iter() + .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?) + } + + fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { + for elem in self.iter() { + elem.encode(writer)?; + } + + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl<T> FixedTag for SetOfVec<T> +where + T: DerOrd, +{ + const TAG: Tag = Tag::Set; +} + +#[cfg(feature = "alloc")] +impl<T> From<SetOfVec<T>> for Vec<T> +where + T: DerOrd, +{ + fn from(set: SetOfVec<T>) -> Vec<T> { + set.into_vec() + } +} + +#[cfg(feature = "alloc")] +impl<T> TryFrom<Vec<T>> for SetOfVec<T> +where + T: DerOrd, +{ + type Error = Error; + + fn try_from(mut vec: Vec<T>) -> Result<SetOfVec<T>> { + der_sort(vec.as_mut_slice())?; + Ok(SetOfVec { inner: vec }) + } +} + +#[cfg(feature = "alloc")] +impl<T, const N: usize> TryFrom<[T; N]> for SetOfVec<T> +where + T: DerOrd, +{ + type Error = Error; + + fn try_from(arr: [T; N]) -> Result<SetOfVec<T>> { + Vec::from(arr).try_into() + } +} + +#[cfg(feature = "alloc")] +impl<T> ValueOrd for SetOfVec<T> +where + T: DerOrd, +{ + fn value_cmp(&self, other: &Self) -> Result<Ordering> { + iter_cmp(self.iter(), other.iter()) + } +} + +// Implement by hand because the derive would create invalid values. +// Use the conversion from Vec to create a valid value. +#[cfg(feature = "arbitrary")] +impl<'a, T> arbitrary::Arbitrary<'a> for SetOfVec<T> +where + T: DerOrd + arbitrary::Arbitrary<'a>, +{ + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> { + Self::try_from( + u.arbitrary_iter()? + .collect::<std::result::Result<Vec<_>, _>>()?, + ) + .map_err(|_| arbitrary::Error::IncorrectFormat) + } + + fn size_hint(_depth: usize) -> (usize, Option<usize>) { + (0, None) + } +} + +/// Ensure set elements are lexicographically ordered using [`DerOrd`]. +fn check_der_ordering<T: DerOrd>(a: &T, b: &T) -> Result<()> { + match a.der_cmp(b)? { + Ordering::Less => Ok(()), + Ordering::Equal => Err(ErrorKind::SetDuplicate.into()), + Ordering::Greater => Err(ErrorKind::SetOrdering.into()), + } +} + +/// Sort a mut slice according to its [`DerOrd`], returning any errors which +/// might occur during the comparison. +/// +/// The algorithm is insertion sort, which should perform well when the input +/// is mostly sorted to begin with. +/// +/// This function is used rather than Rust's built-in `[T]::sort_by` in order +/// to support heapless `no_std` targets as well as to enable bubbling up +/// sorting errors. +#[allow(clippy::integer_arithmetic)] +fn der_sort<T: DerOrd>(slice: &mut [T]) -> Result<()> { + for i in 0..slice.len() { + let mut j = i; + + while j > 0 { + match slice[j - 1].der_cmp(&slice[j])? { + Ordering::Less => break, + Ordering::Equal => return Err(ErrorKind::SetDuplicate.into()), + Ordering::Greater => { + slice.swap(j - 1, j); + j -= 1; + } + } + } + } + + Ok(()) +} + +/// Validate the elements of a `SET OF`, ensuring that they are all in order +/// and that there are no duplicates. +fn validate<T: DerOrd>(slice: &[T]) -> Result<()> { + if let Some(len) = slice.len().checked_sub(1) { + for i in 0..len { + let j = i.checked_add(1).ok_or(ErrorKind::Overflow)?; + + match slice.get(i..=j) { + Some([a, b]) => { + if a.der_cmp(b)? != Ordering::Less { + return Err(ErrorKind::SetOrdering.into()); + } + } + _ => return Err(Tag::Set.value_error()), + } + } + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::SetOf; + #[cfg(feature = "alloc")] + use super::SetOfVec; + use crate::ErrorKind; + + #[test] + fn setof_tryfrom_array() { + let arr = [3u16, 2, 1, 65535, 0]; + let set = SetOf::try_from(arr).unwrap(); + assert!(set.iter().copied().eq([0, 1, 2, 3, 65535])); + } + + #[test] + fn setof_tryfrom_array_reject_duplicates() { + let arr = [1u16, 1]; + let err = SetOf::try_from(arr).err().unwrap(); + assert_eq!(err.kind(), ErrorKind::SetDuplicate); + } + + #[cfg(feature = "alloc")] + #[test] + fn setofvec_tryfrom_array() { + let arr = [3u16, 2, 1, 65535, 0]; + let set = SetOfVec::try_from(arr).unwrap(); + assert_eq!(set.as_ref(), &[0, 1, 2, 3, 65535]); + } + + #[cfg(feature = "alloc")] + #[test] + fn setofvec_tryfrom_vec() { + let vec = vec![3u16, 2, 1, 65535, 0]; + let set = SetOfVec::try_from(vec).unwrap(); + assert_eq!(set.as_ref(), &[0, 1, 2, 3, 65535]); + } + + #[cfg(feature = "alloc")] + #[test] + fn setofvec_tryfrom_vec_reject_duplicates() { + let vec = vec![1u16, 1]; + let err = SetOfVec::try_from(vec).err().unwrap(); + assert_eq!(err.kind(), ErrorKind::SetDuplicate); + } +} |