Skip to content

Commit 57b6ca5

Browse files
authored
der: fix handling of non-unique items in SetOf(Vec) (#1066)
The `TryFrom` constructors were not properly tested for the handling of duplicate items and allowed them to be inserted. This commit fixes the handling and adds tests. In the event there are duplicates in a set, a newly added `ErrorKind::SetDuplicate` variant is returned with the error type.
1 parent b0be47a commit 57b6ca5

File tree

3 files changed

+49
-17
lines changed

3 files changed

+49
-17
lines changed

der/src/asn1/set_of.rs

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,10 @@ where
5151
pub fn add(&mut self, new_elem: T) -> Result<()> {
5252
// Ensure set elements are lexicographically ordered
5353
if let Some(last_elem) = self.inner.last() {
54-
if new_elem.der_cmp(last_elem)? != Ordering::Greater {
55-
return Err(ErrorKind::SetOrdering.into());
54+
match new_elem.der_cmp(last_elem)? {
55+
Ordering::Less => return Err(ErrorKind::SetOrdering.into()),
56+
Ordering::Equal => return Err(ErrorKind::SetDuplicate.into()),
57+
Ordering::Greater => (),
5658
}
5759
}
5860

@@ -360,7 +362,6 @@ where
360362
type Error = Error;
361363

362364
fn try_from(mut vec: Vec<T>) -> Result<SetOfVec<T>> {
363-
// TODO(tarcieri): use `[T]::sort_by` here?
364365
der_sort(vec.as_mut_slice())?;
365366
Ok(SetOfVec { inner: vec })
366367
}
@@ -422,9 +423,15 @@ fn der_sort<T: DerOrd>(slice: &mut [T]) -> Result<()> {
422423
for i in 0..slice.len() {
423424
let mut j = i;
424425

425-
while j > 0 && slice[j - 1].der_cmp(&slice[j])? == Ordering::Greater {
426-
slice.swap(j - 1, j);
427-
j -= 1;
426+
while j > 0 {
427+
match slice[j - 1].der_cmp(&slice[j])? {
428+
Ordering::Less => break,
429+
Ordering::Equal => return Err(ErrorKind::SetDuplicate.into()),
430+
Ordering::Greater => {
431+
slice.swap(j - 1, j);
432+
j -= 1;
433+
}
434+
}
428435
}
429436
}
430437

@@ -452,21 +459,28 @@ fn validate<T: DerOrd>(slice: &[T]) -> Result<()> {
452459
Ok(())
453460
}
454461

455-
#[cfg(all(test, feature = "alloc"))]
462+
#[cfg(test)]
456463
mod tests {
457-
use super::{SetOf, SetOfVec};
458-
use alloc::vec::Vec;
464+
use super::SetOf;
465+
#[cfg(feature = "alloc")]
466+
use super::SetOfVec;
467+
use crate::ErrorKind;
459468

460469
#[test]
461470
fn setof_tryfrom_array() {
462471
let arr = [3u16, 2, 1, 65535, 0];
463472
let set = SetOf::try_from(arr).unwrap();
464-
assert_eq!(
465-
set.iter().cloned().collect::<Vec<u16>>(),
466-
&[0, 1, 2, 3, 65535]
467-
);
473+
assert!(set.iter().copied().eq([0, 1, 2, 3, 65535]));
468474
}
469475

476+
#[test]
477+
fn setof_tryfrom_array_reject_duplicates() {
478+
let arr = [1u16, 1];
479+
let err = SetOf::try_from(arr).err().unwrap();
480+
assert_eq!(err.kind(), ErrorKind::SetDuplicate);
481+
}
482+
483+
#[cfg(feature = "alloc")]
470484
#[test]
471485
fn setofvec_tryfrom_array() {
472486
let arr = [3u16, 2, 1, 65535, 0];
@@ -481,4 +495,12 @@ mod tests {
481495
let set = SetOfVec::try_from(vec).unwrap();
482496
assert_eq!(set.as_ref(), &[0, 1, 2, 3, 65535]);
483497
}
498+
499+
#[cfg(feature = "alloc")]
500+
#[test]
501+
fn setofvec_tryfrom_vec_reject_duplicates() {
502+
let vec = vec![1u16, 1];
503+
let err = SetOfVec::try_from(vec).err().unwrap();
504+
assert_eq!(err.kind(), ErrorKind::SetDuplicate);
505+
}
484506
}

der/src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,9 @@ pub enum ErrorKind {
227227
oid: ObjectIdentifier,
228228
},
229229

230+
/// `SET` cannot contain duplicates.
231+
SetDuplicate,
232+
230233
/// `SET` ordering error: items not in canonical order.
231234
SetOrdering,
232235

@@ -329,6 +332,7 @@ impl fmt::Display for ErrorKind {
329332
ErrorKind::OidUnknown { oid } => {
330333
write!(f, "unknown/unsupported OID: {}", oid)
331334
}
335+
ErrorKind::SetDuplicate => write!(f, "SET OF contains duplicate"),
332336
ErrorKind::SetOrdering => write!(f, "SET OF ordering error"),
333337
ErrorKind::Overflow => write!(f, "integer overflow"),
334338
ErrorKind::Overlength => write!(f, "ASN.1 DER message is too long"),

der/tests/set_of.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,21 @@
44

55
use der::{asn1::SetOfVec, DerOrd};
66
use proptest::{prelude::*, string::*};
7+
use std::collections::BTreeSet;
78

89
proptest! {
910
#[test]
1011
fn sort_equiv(bytes in bytes_regex(".{0,64}").unwrap()) {
11-
let mut expected = bytes.clone();
12-
expected.sort_by(|a, b| a.der_cmp(b).unwrap());
12+
let mut uniq = BTreeSet::new();
1313

14-
let set = SetOfVec::try_from(bytes).unwrap();
15-
prop_assert_eq!(expected.as_slice(), set.as_slice());
14+
// Ensure there are no duplicates
15+
if bytes.iter().copied().all(move |x| uniq.insert(x)) {
16+
let mut expected = bytes.clone();
17+
expected.sort_by(|a, b| a.der_cmp(b).unwrap());
18+
19+
let set = SetOfVec::try_from(bytes).unwrap();
20+
prop_assert_eq!(expected.as_slice(), set.as_slice());
21+
}
1622
}
1723
}
1824

0 commit comments

Comments
 (0)