Skip to content

Commit 1275597

Browse files
committed
der: remove decode-time SET OF ordering checks
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. This commit builds an `ArrayVec` or `Vec` of the incoming decoded set elements, and then unconditionally sorts it retroactively, ensuring all `SET OF` types internally reflect the proper order, but out-of-order `SET OF` messages are tolerated when coming off-the-wire. The sort implementation is merge sort, which should be efficient for already-in-order or mostly-in-order sets.
1 parent 098a668 commit 1275597

File tree

4 files changed

+83
-37
lines changed

4 files changed

+83
-37
lines changed

der/src/arrayvec.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,18 @@ impl<T, const N: usize> ArrayVec<T, N> {
8585
}
8686
}
8787

88+
impl<T, const N: usize> AsRef<[Option<T>]> for ArrayVec<T, N> {
89+
fn as_ref(&self) -> &[Option<T>] {
90+
&self.elements[..self.length]
91+
}
92+
}
93+
94+
impl<T, const N: usize> AsMut<[Option<T>]> for ArrayVec<T, N> {
95+
fn as_mut(&mut self) -> &mut [Option<T>] {
96+
&mut self.elements[..self.length]
97+
}
98+
}
99+
88100
impl<T, const N: usize> Default for ArrayVec<T, N> {
89101
fn default() -> Self {
90102
Self::new()
@@ -114,11 +126,12 @@ impl<'a, T> Iterator for Iter<'a, T> {
114126
type Item = &'a T;
115127

116128
fn next(&mut self) -> Option<&'a T> {
117-
if let Some(Some(res)) = self.elements.get(self.position) {
118-
self.position = self.position.checked_add(1)?;
119-
Some(res)
120-
} else {
121-
None
129+
match self.elements.get(self.position) {
130+
Some(Some(res)) => {
131+
self.position = self.position.checked_add(1)?;
132+
Some(res)
133+
}
134+
_ => None,
122135
}
123136
}
124137

der/src/asn1/set_of.rs

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
//! ASN.1 `SET OF` support.
2+
//!
3+
//! # Ordering Notes
4+
//!
5+
//! Some DER serializer implementations fail to properly sort elements of a
6+
//! `SET OF`. This is technically non-canonical, but occurs frequently
7+
//! enough that most DER decoders tolerate it. Unfortunately because
8+
//! of that, we must also follow suit.
9+
//!
10+
//! However, all types in this module sort elements of a set at decode-time,
11+
//! ensuring they'll be in the proper order if reserialized.
212
313
use crate::{
414
arrayvec, ord::iter_cmp, ArrayVec, Decode, DecodeValue, Decoder, DerOrd, Encode, EncodeValue,
@@ -90,13 +100,15 @@ where
90100
let mut result = Self::new();
91101

92102
while decoder.position() < end_pos {
93-
result.add(decoder.decode()?)?;
103+
result.inner.add(decoder.decode()?)?;
94104
}
95105

96106
if decoder.position() != end_pos {
97107
decoder.error(ErrorKind::Length { tag: Self::TAG });
98108
}
99109

110+
der_sort(result.inner.as_mut())?;
111+
validate(result.inner.as_ref())?;
100112
Ok(result)
101113
}
102114
}
@@ -274,17 +286,19 @@ where
274286
{
275287
fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> Result<Self> {
276288
let end_pos = (decoder.position() + header.length)?;
277-
let mut result = Self::new();
289+
let mut inner = Vec::new();
278290

279291
while decoder.position() < end_pos {
280-
result.add(decoder.decode()?)?;
292+
inner.push(decoder.decode()?);
281293
}
282294

283295
if decoder.position() != end_pos {
284296
decoder.error(ErrorKind::Length { tag: Self::TAG });
285297
}
286298

287-
Ok(result)
299+
der_sort(inner.as_mut())?;
300+
validate(inner.as_ref())?;
301+
Ok(Self { inner })
288302
}
289303
}
290304

@@ -390,6 +404,27 @@ fn der_sort<T: DerOrd>(slice: &mut [T]) -> Result<()> {
390404
Ok(())
391405
}
392406

407+
/// Validate the elements of a `SET OF`, ensuring that they are all in order
408+
/// and that there are no duplicates.
409+
fn validate<T: DerOrd>(slice: &[T]) -> Result<()> {
410+
if let Some(len) = slice.len().checked_sub(1) {
411+
for i in 0..len {
412+
let j = i.checked_add(1).ok_or(ErrorKind::Overflow)?;
413+
414+
match slice.get(i..=j) {
415+
Some([a, b]) => {
416+
if a.der_cmp(b)? != Ordering::Less {
417+
return Err(ErrorKind::SetOrdering.into());
418+
}
419+
}
420+
_ => return Err(Tag::Set.value_error()),
421+
}
422+
}
423+
}
424+
425+
Ok(())
426+
}
427+
393428
#[cfg(all(test, feature = "alloc"))]
394429
mod tests {
395430
use super::{SetOf, SetOfVec};

der/tests/set_of.rs

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
//! `SetOf` tests.
22
3-
#[cfg(feature = "alloc")]
4-
use {
5-
der::{asn1::SetOfVec, DerOrd},
6-
proptest::{prelude::*, string::*},
7-
};
3+
#![cfg(feature = "alloc")]
4+
5+
use der::{asn1::SetOfVec, DerOrd};
6+
use proptest::{prelude::*, string::*};
87

9-
#[cfg(feature = "alloc")]
108
proptest! {
119
#[test]
1210
fn sort_equiv(bytes in bytes_regex(".{0,64}").unwrap()) {
@@ -18,36 +16,36 @@ proptest! {
1816
}
1917
}
2018

19+
/// Set ordering tests.
2120
#[cfg(all(feature = "derive", feature = "oid"))]
22-
mod attr_regression {
23-
#![cfg(all(feature = "derive", feature = "oid"))]
24-
25-
use core::cmp::Ordering;
21+
mod ordering {
2622
use der::{
27-
asn1::{Any, ObjectIdentifier, SetOf},
28-
Decode, Result, Sequence, ValueOrd,
23+
asn1::{Any, ObjectIdentifier, SetOf, SetOfVec},
24+
Decode, Sequence, ValueOrd,
2925
};
3026
use hex_literal::hex;
3127

32-
/// Attribute type/value pairs as defined in [RFC 5280 Section 4.1.2.4].
33-
///
34-
/// [RFC 5280 Section 4.1.2.4]: https://tools.ietf.org/html/rfc5280#section-4.1.2.4
35-
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Sequence)]
28+
/// X.501 `AttributeTypeAndValue`
29+
#[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
3630
pub struct AttributeTypeAndValue<'a> {
37-
/// OID describing the type of the attribute
3831
pub oid: ObjectIdentifier,
39-
40-
/// Value of the attribute
4132
pub value: Any<'a>,
4233
}
4334

44-
impl ValueOrd for AttributeTypeAndValue<'_> {
45-
fn value_cmp(&self, other: &Self) -> Result<Ordering> {
46-
match self.oid.value_cmp(&other.oid)? {
47-
Ordering::Equal => self.value.value_cmp(&other.value),
48-
other => Ok(other),
49-
}
50-
}
35+
const OUT_OF_ORDER_RDN_EXAMPLE: &[u8] =
36+
&hex!("311F301106035504030C0A4A4F484E20534D495448300A060355040A0C03313233");
37+
38+
/// For compatibility reasons, we allow non-canonical DER with out-of-order
39+
/// sets in order to match the behavior of other implementations.
40+
#[test]
41+
fn allow_out_of_order_setof() {
42+
assert!(SetOf::<AttributeTypeAndValue<'_>, 2>::from_der(OUT_OF_ORDER_RDN_EXAMPLE).is_ok());
43+
}
44+
45+
/// Same as above, with `SetOfVec` instead of `SetOf`.
46+
#[test]
47+
fn allow_out_of_order_setofvec() {
48+
assert!(SetOfVec::<AttributeTypeAndValue<'_>>::from_der(OUT_OF_ORDER_RDN_EXAMPLE).is_ok());
5149
}
5250

5351
/// Test to ensure ordering is handled correctly.

x509/tests/name.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,11 @@ fn decode_rdn() {
126126
// fails when caller adds items not in DER lexicographical order
127127
assert!(from_scratch2.0.add(*atav1a).is_err());
128128

129-
//parsing fails due to incorrect order
129+
// allow out-of-order RDNs (see: RustCrypto/formats#625)
130130
assert!(RelativeDistinguishedName::from_der(
131131
&hex!("311F301106035504030C0A4A4F484E20534D495448300A060355040A0C03313233")[..],
132132
)
133-
.is_err());
133+
.is_ok());
134134
}
135135

136136
// #[test]

0 commit comments

Comments
 (0)