Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 28 additions & 5 deletions der/src/asn1/utc_time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

use crate::{
DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag,
Writer,
ValueOrd, Writer,
datetime::{self, DateTime},
ord::OrdIsValueOrd,
encode::encode_value_to_slice,
};
use core::time::Duration;
use core::{cmp::Ordering, time::Duration};

#[cfg(feature = "std")]
use std::time::SystemTime;
Expand Down Expand Up @@ -173,7 +173,18 @@ impl FixedTag for UtcTime {
const TAG: Tag = Tag::UtcTime;
}

impl OrdIsValueOrd for UtcTime {}
/// Compares the `YYMMDDHHMMSSZ` encodings (X.690 11.6 orders `SET OF` components by their
/// encodings), which differs from [`Ord`] (chronological) across 2000: `000101000000Z`
/// (2000) sorts before `991231235959Z` (1999).
impl ValueOrd for UtcTime {
fn value_cmp(&self, other: &Self) -> Result<Ordering> {
let mut buf1 = [0u8; Self::LENGTH];
let mut buf2 = [0u8; Self::LENGTH];
let a = encode_value_to_slice(&mut buf1, self)?;
let b = encode_value_to_slice(&mut buf2, other)?;
Ok(a.cmp(b))
Comment thread
tarcieri marked this conversation as resolved.
Outdated
}
}

impl From<&UtcTime> for UtcTime {
fn from(value: &UtcTime) -> UtcTime {
Expand Down Expand Up @@ -255,9 +266,21 @@ impl<'a> arbitrary::Arbitrary<'a> for UtcTime {
#[allow(clippy::unwrap_used)]
mod tests {
use super::UtcTime;
use crate::{Decode, Encode, SliceWriter};
use crate::{Decode, DerOrd, Encode, SliceWriter, ValueOrd};
use core::cmp::Ordering;
use hex_literal::hex;

#[test]
fn value_ord_is_encoding_order() {
// 1999-12-31 encodes as "99...", 2000-01-01 as "00...": X.690 11.6 puts 2000 first.
let y1999 = UtcTime::from_der(&hex!("170d 3939313233313233353935395a")).unwrap();
let y2000 = UtcTime::from_der(&hex!("170d 3030303130313030303030305a")).unwrap();
assert!(y1999 < y2000); // `Ord` stays chronological
assert_eq!(y2000.value_cmp(&y1999), Ok(Ordering::Less));
assert_eq!(y2000.der_cmp(&y1999), Ok(Ordering::Less));
assert_eq!(y1999.value_cmp(&y1999), Ok(Ordering::Equal));
}

#[test]
fn round_trip_vector() {
let example_bytes = hex!("17 0d 39 31 30 35 30 36 32 33 34 35 34 30 5a");
Expand Down
24 changes: 24 additions & 0 deletions der/tests/set_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,27 @@ mod ordering {
assert_eq!(ObjectIdentifier::new("2.5.4.3").unwrap(), attr1.oid);
}
}

/// X.690 11.6: `SET OF UTCTime` is ordered by the `YYMMDDHHMMSSZ` encodings, so a 20xx time
/// (`00..49`) sorts before a 19xx time (`50..99`).
mod utctime_order {
use der::{
Decode, Encode,
asn1::{SetOfVec, UtcTime},
};
use hex_literal::hex;

const Y1999: [u8; 15] = hex!("170d 3939313233313233353935395a");
const Y2000: [u8; 15] = hex!("170d 3030303130313030303030305a");

#[test]
fn setofvec_utctime_encodes_in_octet_order() {
let mut set = SetOfVec::new();
set.insert(UtcTime::from_der(&Y1999).unwrap()).unwrap();
set.insert(UtcTime::from_der(&Y2000).unwrap()).unwrap();
let mut want = hex!("311e").to_vec();
want.extend_from_slice(&Y2000);
want.extend_from_slice(&Y1999);
assert_eq!(set.to_der().unwrap(), want);
}
}
Loading