From 7e5d7eea9c580ef4b41a765bde624af431942b96 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 4 May 2024 14:41:35 +0200 Subject: Merging upstream version 1.70.0+dfsg2. Signed-off-by: Daniel Baumann --- vendor/der/tests/datetime.proptest-regressions | 8 + vendor/der/tests/datetime.rs | 64 ++++ vendor/der/tests/derive.rs | 459 +++++++++++++++++++++++++ vendor/der/tests/examples/spki.der | Bin 0 -> 44 bytes vendor/der/tests/examples/spki.pem | 3 + vendor/der/tests/pem.rs | 67 ++++ vendor/der/tests/set_of.rs | 59 ++++ 7 files changed, 660 insertions(+) create mode 100644 vendor/der/tests/datetime.proptest-regressions create mode 100644 vendor/der/tests/datetime.rs create mode 100644 vendor/der/tests/derive.rs create mode 100644 vendor/der/tests/examples/spki.der create mode 100644 vendor/der/tests/examples/spki.pem create mode 100644 vendor/der/tests/pem.rs create mode 100644 vendor/der/tests/set_of.rs (limited to 'vendor/der/tests') diff --git a/vendor/der/tests/datetime.proptest-regressions b/vendor/der/tests/datetime.proptest-regressions new file mode 100644 index 000000000..f280ac46a --- /dev/null +++ b/vendor/der/tests/datetime.proptest-regressions @@ -0,0 +1,8 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc 00dbea7e90761c16aa20e2fbf7ffad420da0c84d4ed4e6df123de03c9b4567e5 # shrinks to year = 1970, month = 1, day = 1, hour = 0, min = 60, sec = 0 +cc 3b0bd01ef4cad6bea0a287f9cdcd56bad186125ec388d204f6afcd193ca12c39 # shrinks to year = 1970, month = 1, day = 1, hour = 0, min = 0, sec = 60 diff --git a/vendor/der/tests/datetime.rs b/vendor/der/tests/datetime.rs new file mode 100644 index 000000000..454c1f0e4 --- /dev/null +++ b/vendor/der/tests/datetime.rs @@ -0,0 +1,64 @@ +//! Tests for the [`DateTime`] type. + +use der::{asn1::UtcTime, DateTime, Decode, Encode}; +use proptest::prelude::*; + +proptest! { + #[test] + fn roundtrip_datetime( + year in 1970u16..=9999, + month in 1u8..=12, + day in 1u8..=31, + hour in 0u8..=23, + min in 0u8..=59, + sec in 0u8..=59, + ) { + let datetime1 = make_datetime(year, month, day, hour, min, sec); + let datetime2 = DateTime::from_unix_duration(datetime1.unix_duration()).unwrap(); + prop_assert_eq!(datetime1, datetime2); + } + + #[test] + fn roundtrip_utctime( + year in 1970u16..=2049, + month in 1u8..=12, + day in 1u8..=31, + hour in 0u8..=23, + min in 0u8..=59, + sec in 0u8..=59, + ) { + let datetime = make_datetime(year, month, day, hour, min, sec); + let utc_time1 = UtcTime::try_from(datetime).unwrap(); + + let mut buf = [0u8; 128]; + let mut encoder = der::SliceWriter::new(&mut buf); + utc_time1.encode(&mut encoder).unwrap(); + let der_bytes = encoder.finish().unwrap(); + + let utc_time2 = UtcTime::from_der(der_bytes).unwrap(); + prop_assert_eq!(utc_time1, utc_time2); + } +} + +fn make_datetime(year: u16, month: u8, day: u8, hour: u8, min: u8, sec: u8) -> DateTime { + let max_day = if month == 2 { + let is_leap_year = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); + + if is_leap_year { + 29 + } else { + 28 + } + } else { + 30 + }; + + let day = if day > max_day { max_day } else { day }; + + DateTime::new(year, month, day, hour, min, sec).unwrap_or_else(|e| { + panic!( + "invalid DateTime: {:02}-{:02}-{:02}T{:02}:{:02}:{:02}: {}", + year, month, day, hour, min, sec, e + ); + }) +} diff --git a/vendor/der/tests/derive.rs b/vendor/der/tests/derive.rs new file mode 100644 index 000000000..dac14f816 --- /dev/null +++ b/vendor/der/tests/derive.rs @@ -0,0 +1,459 @@ +//! Tests for custom derive support. +//! +//! # Debugging with `cargo expand` +//! +//! To expand the Rust code generated by the proc macro when debugging +//! issues related to these tests, run: +//! +//! $ cargo expand --test derive --all-features + +#![cfg(all(feature = "derive", feature = "alloc"))] + +/// Custom derive test cases for the `Choice` macro. +mod choice { + /// `Choice` with `EXPLICIT` tagging. + mod explicit { + use der::{ + asn1::{GeneralizedTime, UtcTime}, + Choice, Decode, Encode, SliceWriter, + }; + use hex_literal::hex; + use std::time::Duration; + + /// Custom derive test case for the `Choice` macro. + /// + /// Based on `Time` as defined in RFC 5280: + /// + /// + /// ```text + /// Time ::= CHOICE { + /// utcTime UTCTime, + /// generalTime GeneralizedTime } + /// ``` + #[derive(Choice)] + pub enum Time { + #[asn1(type = "UTCTime")] + UtcTime(UtcTime), + + #[asn1(type = "GeneralizedTime")] + GeneralTime(GeneralizedTime), + } + + impl Time { + fn to_unix_duration(self) -> Duration { + match self { + Time::UtcTime(t) => t.to_unix_duration(), + Time::GeneralTime(t) => t.to_unix_duration(), + } + } + } + + const UTC_TIMESTAMP_DER: &'static [u8] = + &hex!("17 0d 39 31 30 35 30 36 32 33 34 35 34 30 5a"); + const GENERAL_TIMESTAMP_DER: &'static [u8] = + &hex!("18 0f 31 39 39 31 30 35 30 36 32 33 34 35 34 30 5a"); + + #[test] + fn decode() { + let utc_time = Time::from_der(UTC_TIMESTAMP_DER).unwrap(); + assert_eq!(utc_time.to_unix_duration().as_secs(), 673573540); + + let general_time = Time::from_der(GENERAL_TIMESTAMP_DER).unwrap(); + assert_eq!(general_time.to_unix_duration().as_secs(), 673573540); + } + + #[test] + fn encode() { + let mut buf = [0u8; 128]; + + let utc_time = Time::from_der(UTC_TIMESTAMP_DER).unwrap(); + let mut encoder = SliceWriter::new(&mut buf); + utc_time.encode(&mut encoder).unwrap(); + assert_eq!(UTC_TIMESTAMP_DER, encoder.finish().unwrap()); + + let general_time = Time::from_der(GENERAL_TIMESTAMP_DER).unwrap(); + let mut encoder = SliceWriter::new(&mut buf); + general_time.encode(&mut encoder).unwrap(); + assert_eq!(GENERAL_TIMESTAMP_DER, encoder.finish().unwrap()); + } + } + + /// `Choice` with `IMPLICIT` tagging. + mod implicit { + use der::{ + asn1::{BitStringRef, GeneralizedTime}, + Choice, Decode, Encode, SliceWriter, + }; + use hex_literal::hex; + + /// `Choice` macro test case for `IMPLICIT` tagging. + #[derive(Choice, Debug, Eq, PartialEq)] + #[asn1(tag_mode = "IMPLICIT")] + pub enum ImplicitChoice<'a> { + #[asn1(context_specific = "0", type = "BIT STRING")] + BitString(BitStringRef<'a>), + + #[asn1(context_specific = "1", type = "GeneralizedTime")] + Time(GeneralizedTime), + + #[asn1(context_specific = "2", type = "UTF8String")] + Utf8String(String), + } + + impl<'a> ImplicitChoice<'a> { + pub fn bit_string(&self) -> Option> { + match self { + Self::BitString(bs) => Some(*bs), + _ => None, + } + } + + pub fn time(&self) -> Option { + match self { + Self::Time(time) => Some(*time), + _ => None, + } + } + } + + const BITSTRING_DER: &'static [u8] = &hex!("80 04 00 01 02 03"); + const TIME_DER: &'static [u8] = &hex!("81 0f 31 39 39 31 30 35 30 36 32 33 34 35 34 30 5a"); + + #[test] + fn decode() { + let cs_bit_string = ImplicitChoice::from_der(BITSTRING_DER).unwrap(); + assert_eq!( + cs_bit_string.bit_string().unwrap().as_bytes().unwrap(), + &[1, 2, 3] + ); + + let cs_time = ImplicitChoice::from_der(TIME_DER).unwrap(); + assert_eq!( + cs_time.time().unwrap().to_unix_duration().as_secs(), + 673573540 + ); + } + + #[test] + fn encode() { + let mut buf = [0u8; 128]; + + let cs_bit_string = ImplicitChoice::from_der(BITSTRING_DER).unwrap(); + let mut encoder = SliceWriter::new(&mut buf); + cs_bit_string.encode(&mut encoder).unwrap(); + assert_eq!(BITSTRING_DER, encoder.finish().unwrap()); + + let cs_time = ImplicitChoice::from_der(TIME_DER).unwrap(); + let mut encoder = SliceWriter::new(&mut buf); + cs_time.encode(&mut encoder).unwrap(); + assert_eq!(TIME_DER, encoder.finish().unwrap()); + } + } +} + +/// Custom derive test cases for the `Enumerated` macro. +mod enumerated { + use der::{Decode, Encode, Enumerated, SliceWriter}; + use hex_literal::hex; + + /// X.509 `CRLReason`. + #[derive(Enumerated, Copy, Clone, Debug, Eq, PartialEq)] + #[repr(u32)] + pub enum CrlReason { + Unspecified = 0, + KeyCompromise = 1, + CaCompromise = 2, + AffiliationChanged = 3, + Superseded = 4, + CessationOfOperation = 5, + CertificateHold = 6, + RemoveFromCrl = 8, + PrivilegeWithdrawn = 9, + AaCompromised = 10, + } + + const UNSPECIFIED_DER: &[u8] = &hex!("0a 01 00"); + const KEY_COMPROMISE_DER: &[u8] = &hex!("0a 01 01"); + + #[test] + fn decode() { + let unspecified = CrlReason::from_der(UNSPECIFIED_DER).unwrap(); + assert_eq!(CrlReason::Unspecified, unspecified); + + let key_compromise = CrlReason::from_der(KEY_COMPROMISE_DER).unwrap(); + assert_eq!(CrlReason::KeyCompromise, key_compromise); + } + + #[test] + fn encode() { + let mut buf = [0u8; 128]; + + let mut encoder = SliceWriter::new(&mut buf); + CrlReason::Unspecified.encode(&mut encoder).unwrap(); + assert_eq!(UNSPECIFIED_DER, encoder.finish().unwrap()); + + let mut encoder = SliceWriter::new(&mut buf); + CrlReason::KeyCompromise.encode(&mut encoder).unwrap(); + assert_eq!(KEY_COMPROMISE_DER, encoder.finish().unwrap()); + } +} + +/// Custom derive test cases for the `Sequence` macro. +#[cfg(feature = "oid")] +mod sequence { + use der::{ + asn1::{AnyRef, ObjectIdentifier, SetOf}, + Decode, Encode, Sequence, ValueOrd, + }; + use hex_literal::hex; + + pub fn default_false_example() -> bool { + false + } + + // Issuing distribution point extension as defined in [RFC 5280 Section 5.2.5] and as identified by the [`PKIX_PE_SUBJECTINFOACCESS`](constant.PKIX_PE_SUBJECTINFOACCESS.html) OID. + // + // ```text + // IssuingDistributionPoint ::= SEQUENCE { + // distributionPoint [0] DistributionPointName OPTIONAL, + // onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE, + // onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE, + // onlySomeReasons [3] ReasonFlags OPTIONAL, + // indirectCRL [4] BOOLEAN DEFAULT FALSE, + // onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE } + // -- at most one of onlyContainsUserCerts, onlyContainsCACerts, + // -- and onlyContainsAttributeCerts may be set to TRUE. + // ``` + // + // [RFC 5280 Section 5.2.5]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.2.5 + #[derive(Sequence)] + pub struct IssuingDistributionPointExample { + // Omit distributionPoint and only_some_reasons because corresponding structs are not + // available here and are not germane to the example + // distributionPoint [0] DistributionPointName OPTIONAL, + //#[asn1(context_specific="0", optional="true", tag_mode="IMPLICIT")] + //pub distribution_point: Option>, + /// onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE, + #[asn1( + context_specific = "1", + default = "default_false_example", + tag_mode = "IMPLICIT" + )] + pub only_contains_user_certs: bool, + + /// onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE, + #[asn1( + context_specific = "2", + default = "default_false_example", + tag_mode = "IMPLICIT" + )] + pub only_contains_cacerts: bool, + + // onlySomeReasons [3] ReasonFlags OPTIONAL, + //#[asn1(context_specific="3", optional="true", tag_mode="IMPLICIT")] + //pub only_some_reasons: Option>, + /// indirectCRL [4] BOOLEAN DEFAULT FALSE, + #[asn1( + context_specific = "4", + default = "default_false_example", + tag_mode = "IMPLICIT" + )] + pub indirect_crl: bool, + + /// onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE + #[asn1( + context_specific = "5", + default = "default_false_example", + tag_mode = "IMPLICIT" + )] + pub only_contains_attribute_certs: bool, + } + + // Extension as defined in [RFC 5280 Section 4.1.2.9]. + // + // The ASN.1 definition for Extension objects is below. The extnValue type may be further parsed using a decoder corresponding to the extnID value. + // + // ```text + // Extension ::= SEQUENCE { + // extnID OBJECT IDENTIFIER, + // critical BOOLEAN DEFAULT FALSE, + // extnValue OCTET STRING + // -- contains the DER encoding of an ASN.1 value + // -- corresponding to the extension type identified + // -- by extnID + // } + // ``` + // + // [RFC 5280 Section 4.1.2.9]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.9 + #[derive(Clone, Debug, Eq, PartialEq, Sequence)] + pub struct ExtensionExample<'a> { + /// extnID OBJECT IDENTIFIER, + pub extn_id: ObjectIdentifier, + + /// critical BOOLEAN DEFAULT FALSE, + #[asn1(default = "default_false_example")] + pub critical: bool, + + /// extnValue OCTET STRING + #[asn1(type = "OCTET STRING")] + pub extn_value: &'a [u8], + } + + /// X.509 `AlgorithmIdentifier` + #[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)] + pub struct AlgorithmIdentifier<'a> { + pub algorithm: ObjectIdentifier, + pub parameters: Option>, + } + + /// X.509 `SubjectPublicKeyInfo` (SPKI) + #[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)] + pub struct SubjectPublicKeyInfo<'a> { + pub algorithm: AlgorithmIdentifier<'a>, + #[asn1(type = "BIT STRING")] + pub subject_public_key: &'a [u8], + } + + /// PKCS#8v2 `OneAsymmetricKey` + #[derive(Sequence)] + pub struct OneAsymmetricKey<'a> { + pub version: u8, + pub private_key_algorithm: AlgorithmIdentifier<'a>, + #[asn1(type = "OCTET STRING")] + pub private_key: &'a [u8], + #[asn1(context_specific = "0", extensible = "true", optional = "true")] + pub attributes: Option, 1>>, + #[asn1( + context_specific = "1", + extensible = "true", + optional = "true", + type = "BIT STRING" + )] + pub public_key: Option<&'a [u8]>, + } + + /// X.509 extension + // TODO(tarcieri): tests for code derived with the `default` attribute + #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)] + pub struct Extension<'a> { + extn_id: ObjectIdentifier, + #[asn1(default = "critical_default")] + critical: bool, + #[asn1(type = "OCTET STRING")] + extn_value: &'a [u8], + } + + /// Default value of the `critical` bit + fn critical_default() -> bool { + false + } + + const ID_EC_PUBLIC_KEY_OID: ObjectIdentifier = + ObjectIdentifier::new_unwrap("1.2.840.10045.2.1"); + + const PRIME256V1_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.3.1.7"); + + const ALGORITHM_IDENTIFIER_DER: &[u8] = + &hex!("30 13 06 07 2a 86 48 ce 3d 02 01 06 08 2a 86 48 ce 3d 03 01 07"); + + #[derive(Sequence)] + #[asn1(tag_mode = "IMPLICIT")] + pub struct TypeCheckExpandedSequenceFieldAttributeCombinations<'a> { + pub simple: bool, + #[asn1(type = "BIT STRING")] + pub typed: &'a [u8], + #[asn1(context_specific = "0")] + pub context_specific: bool, + #[asn1(optional = "true")] + pub optional: Option, + #[asn1(default = "default_false_example")] + pub default: bool, + #[asn1(type = "BIT STRING", context_specific = "1")] + pub typed_context_specific: &'a [u8], + #[asn1(context_specific = "2", optional = "true")] + pub context_specific_optional: Option, + #[asn1(context_specific = "3", default = "default_false_example")] + pub context_specific_default: bool, + #[asn1(type = "BIT STRING", context_specific = "4", optional = "true")] + pub typed_context_specific_optional: Option<&'a [u8]>, + } + + #[test] + fn idp_test() { + let idp = IssuingDistributionPointExample::from_der(&hex!("30038101FF")).unwrap(); + assert_eq!(idp.only_contains_user_certs, true); + assert_eq!(idp.only_contains_cacerts, false); + assert_eq!(idp.indirect_crl, false); + assert_eq!(idp.only_contains_attribute_certs, false); + + let idp = IssuingDistributionPointExample::from_der(&hex!("30038201FF")).unwrap(); + assert_eq!(idp.only_contains_user_certs, false); + assert_eq!(idp.only_contains_cacerts, true); + assert_eq!(idp.indirect_crl, false); + assert_eq!(idp.only_contains_attribute_certs, false); + + let idp = IssuingDistributionPointExample::from_der(&hex!("30038401FF")).unwrap(); + assert_eq!(idp.only_contains_user_certs, false); + assert_eq!(idp.only_contains_cacerts, false); + assert_eq!(idp.indirect_crl, true); + assert_eq!(idp.only_contains_attribute_certs, false); + + let idp = IssuingDistributionPointExample::from_der(&hex!("30038501FF")).unwrap(); + assert_eq!(idp.only_contains_user_certs, false); + assert_eq!(idp.only_contains_cacerts, false); + assert_eq!(idp.indirect_crl, false); + assert_eq!(idp.only_contains_attribute_certs, true); + } + + // demonstrates default field that is not context specific + #[test] + fn extension_test() { + let ext1 = ExtensionExample::from_der(&hex!( + "300F" // 0 15: SEQUENCE { + "0603551D13" // 2 3: OBJECT IDENTIFIER basicConstraints (2 5 29 19) + "0101FF" // 7 1: BOOLEAN TRUE + "0405" // 10 5: OCTET STRING, encapsulates { + "3003" // 12 3: SEQUENCE { + "0101FF" // 14 1: BOOLEAN TRUE + )) + .unwrap(); + assert_eq!(ext1.critical, true); + + let ext2 = ExtensionExample::from_der(&hex!( + "301F" // 0 31: SEQUENCE { + "0603551D23" // 2 3: OBJECT IDENTIFIER authorityKeyIdentifier (2 5 29 35) + "0418" // 7 24: OCTET STRING, encapsulates { + "3016" // 9 22: SEQUENCE { + "8014E47D5FD15C9586082C05AEBE75B665A7D95DA866" // 11 20: [0] E4 7D 5F D1 5C 95 86 08 2C 05 AE BE 75 B6 65 A7 D9 5D A8 66 + )) + .unwrap(); + assert_eq!(ext2.critical, false); + } + + #[test] + fn decode() { + let algorithm_identifier = + AlgorithmIdentifier::from_der(&ALGORITHM_IDENTIFIER_DER).unwrap(); + + assert_eq!(ID_EC_PUBLIC_KEY_OID, algorithm_identifier.algorithm); + assert_eq!( + PRIME256V1_OID, + ObjectIdentifier::try_from(algorithm_identifier.parameters.unwrap()).unwrap() + ); + } + + #[test] + fn encode() { + let parameters_oid = PRIME256V1_OID; + + let algorithm_identifier = AlgorithmIdentifier { + algorithm: ID_EC_PUBLIC_KEY_OID, + parameters: Some(AnyRef::from(¶meters_oid)), + }; + + assert_eq!( + ALGORITHM_IDENTIFIER_DER, + algorithm_identifier.to_vec().unwrap() + ); + } +} diff --git a/vendor/der/tests/examples/spki.der b/vendor/der/tests/examples/spki.der new file mode 100644 index 000000000..1b602ee1f Binary files /dev/null and b/vendor/der/tests/examples/spki.der differ diff --git a/vendor/der/tests/examples/spki.pem b/vendor/der/tests/examples/spki.pem new file mode 100644 index 000000000..6891701f7 --- /dev/null +++ b/vendor/der/tests/examples/spki.pem @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEATSkWfz8ZEqb3rfopOgUaFcBexnuPFyZ7HFVQ3OhTvQ0= +-----END PUBLIC KEY----- diff --git a/vendor/der/tests/pem.rs b/vendor/der/tests/pem.rs new file mode 100644 index 000000000..d2c865463 --- /dev/null +++ b/vendor/der/tests/pem.rs @@ -0,0 +1,67 @@ +//! PEM decoding and encoding tests. + +#![cfg(all(feature = "derive", feature = "oid", feature = "pem"))] + +use der::{ + asn1::{BitString, ObjectIdentifier}, + pem::{LineEnding, PemLabel}, + Decode, DecodePem, EncodePem, Sequence, +}; + +/// Example SPKI document encoded as DER. +const SPKI_DER: &[u8] = include_bytes!("examples/spki.der"); + +/// Example SPKI document encoded as PEM. +const SPKI_PEM: &str = include_str!("examples/spki.pem"); + +/// X.509 `AlgorithmIdentifier` +#[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence)] +pub struct AlgorithmIdentifier { + pub algorithm: ObjectIdentifier, + // pub parameters: ... (not used in spki.pem) +} + +/// X.509 `SubjectPublicKeyInfo` (SPKI) in borrowed form +#[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence)] +pub struct SpkiBorrowed<'a> { + pub algorithm: AlgorithmIdentifier, + #[asn1(type = "BIT STRING")] + pub subject_public_key: &'a [u8], +} + +impl PemLabel for SpkiBorrowed<'_> { + const PEM_LABEL: &'static str = "PUBLIC KEY"; +} + +/// X.509 `SubjectPublicKeyInfo` (SPKI) in owned form +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +pub struct SpkiOwned { + pub algorithm: AlgorithmIdentifier, + pub subject_public_key: BitString, +} + +impl PemLabel for SpkiOwned { + const PEM_LABEL: &'static str = "PUBLIC KEY"; +} + +#[test] +fn from_pem() { + // Decode PEM to owned form. + let pem_spki = SpkiOwned::from_pem(SPKI_PEM).unwrap(); + + // Decode DER to borrowed form. + let der_spki = SpkiBorrowed::from_der(SPKI_DER).unwrap(); + + assert_eq!(pem_spki.algorithm, der_spki.algorithm); + assert_eq!( + pem_spki.subject_public_key.raw_bytes(), + der_spki.subject_public_key + ); +} + +#[test] +fn to_pem() { + let spki = SpkiBorrowed::from_der(SPKI_DER).unwrap(); + let pem = spki.to_pem(LineEnding::LF).unwrap(); + assert_eq!(&pem, SPKI_PEM); +} diff --git a/vendor/der/tests/set_of.rs b/vendor/der/tests/set_of.rs new file mode 100644 index 000000000..ba43d80a2 --- /dev/null +++ b/vendor/der/tests/set_of.rs @@ -0,0 +1,59 @@ +//! `SetOf` tests. + +#![cfg(feature = "alloc")] + +use der::{asn1::SetOfVec, DerOrd}; +use proptest::{prelude::*, string::*}; + +proptest! { + #[test] + fn sort_equiv(bytes in bytes_regex(".{0,64}").unwrap()) { + let mut expected = bytes.clone(); + expected.sort_by(|a, b| a.der_cmp(b).unwrap()); + + let set = SetOfVec::try_from(bytes).unwrap(); + prop_assert_eq!(expected.as_slice(), set.as_slice()); + } +} + +/// Set ordering tests. +#[cfg(all(feature = "derive", feature = "oid"))] +mod ordering { + use der::{ + asn1::{AnyRef, ObjectIdentifier, SetOf, SetOfVec}, + Decode, Sequence, ValueOrd, + }; + use hex_literal::hex; + + /// X.501 `AttributeTypeAndValue` + #[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)] + pub struct AttributeTypeAndValue<'a> { + pub oid: ObjectIdentifier, + pub value: AnyRef<'a>, + } + + const OUT_OF_ORDER_RDN_EXAMPLE: &[u8] = + &hex!("311F301106035504030C0A4A4F484E20534D495448300A060355040A0C03313233"); + + /// For compatibility reasons, we allow non-canonical DER with out-of-order + /// sets in order to match the behavior of other implementations. + #[test] + fn allow_out_of_order_setof() { + assert!(SetOf::, 2>::from_der(OUT_OF_ORDER_RDN_EXAMPLE).is_ok()); + } + + /// Same as above, with `SetOfVec` instead of `SetOf`. + #[test] + fn allow_out_of_order_setofvec() { + assert!(SetOfVec::>::from_der(OUT_OF_ORDER_RDN_EXAMPLE).is_ok()); + } + + /// Test to ensure ordering is handled correctly. + #[test] + fn ordering_regression() { + let der_bytes = hex!("3139301906035504030C12546573742055736572393031353734333830301C060A0992268993F22C640101130E3437303031303030303134373333"); + let set = SetOf::, 3>::from_der(&der_bytes).unwrap(); + let attr1 = set.get(0).unwrap(); + assert_eq!(ObjectIdentifier::new("2.5.4.3").unwrap(), attr1.oid); + } +} -- cgit v1.2.3