From 14e4bec260fad061b201ff4b3c1b14346f0d0a85 Mon Sep 17 00:00:00 2001 From: Carl Wallace Date: Thu, 27 Jan 2022 18:51:56 -0500 Subject: [PATCH 1/3] add support for RFC5914 structs. make adjusts to some prior structure definitions to work around macro-related issues. Notes on non-use of macros In trust_anchor_format.rs - Choice was not used on TrustAnchorChoice owing to types not available in Asn1Type enum - Sequence was not used on TrustAnchorInfo owing to lack of DecodeValue required by context_specific error[E0277]: the trait bound `TrustAnchorInfo<'a>: DecodeValue<'_>` is not satisfied --> x509/src/trust_anchor_format.rs:295:22 | 295 | .context_specific::>(TAC_TA_INFO_TAG, TagMode::Explicit)?; | ^^^^^^^^^^^^^^^^ the trait `DecodeValue<'_>` is not implemented for `TrustAnchorInfo<'a>` | note: required by a bound in `Decoder::<'a>::context_specific` --> der/src/decoder.rs:172:12 | 172 | T: DecodeValue<'a> + FixedTag, | ^^^^^^^^^^^^^^^ required by this bound in `Decoder::<'a>::context_specific` - Sequence was not used on CertPathControls to use decode_implicit for each field (trailing bits were left using the default decoder even with mods to Certificate and NameConstraints) In certificate.rs - Sequence was not used on Certificate due to same issue as described above for TrustAnchorInfo (i.e., tension between use of DecodeValue and Decodable) - Sequence was not used on NameConstraints for the same DecodeValue vs Decodable issue. --- x509/src/certificate.rs | 31 +- x509/src/lib.rs | 1 + x509/src/pkix_extensions.rs | 25 +- x509/src/trust_anchor_format.rs | 343 +++++++++++++++ x509/tests/examples/eca.der | Bin 0 -> 859 bytes x509/tests/examples/eca_policies.ta | Bin 0 -> 1954 bytes x509/tests/examples/entrust.der | Bin 0 -> 936 bytes x509/tests/examples/entrust_dnConstraint.ta | Bin 0 -> 1443 bytes x509/tests/examples/exostar.der | Bin 0 -> 972 bytes x509/tests/examples/exostar_policyFlags.ta | Bin 0 -> 1495 bytes x509/tests/examples/raytheon.der | Bin 0 -> 907 bytes .../examples/raytheon_pathLenConstraint.ta | Bin 0 -> 1324 bytes x509/tests/trust_anchor_format.rs | 410 ++++++++++++++++++ 13 files changed, 795 insertions(+), 15 deletions(-) create mode 100644 x509/src/trust_anchor_format.rs create mode 100644 x509/tests/examples/eca.der create mode 100755 x509/tests/examples/eca_policies.ta create mode 100644 x509/tests/examples/entrust.der create mode 100755 x509/tests/examples/entrust_dnConstraint.ta create mode 100644 x509/tests/examples/exostar.der create mode 100755 x509/tests/examples/exostar_policyFlags.ta create mode 100644 x509/tests/examples/raytheon.der create mode 100644 x509/tests/examples/raytheon_pathLenConstraint.ta create mode 100644 x509/tests/trust_anchor_format.rs diff --git a/x509/src/certificate.rs b/x509/src/certificate.rs index 85ac1cfc4..57528c6a3 100644 --- a/x509/src/certificate.rs +++ b/x509/src/certificate.rs @@ -2,7 +2,7 @@ use crate::{Name, Validity}; use der::asn1::{BitString, ContextSpecific, ObjectIdentifier, UIntBytes}; -use der::{Sequence, TagMode, TagNumber}; +use der::{DecodeValue, Decoder, Length, Sequence, TagMode, TagNumber}; use spki::{AlgorithmIdentifier, SubjectPublicKeyInfo}; /// returns false in support of integer DEFAULT fields set to 0 @@ -192,7 +192,7 @@ impl<'a> ::core::fmt::Debug for TBSCertificate<'a> { /// ``` /// /// [RFC 5280 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1 -#[derive(Clone, Debug, Eq, PartialEq, Sequence)] +#[derive(Clone, Debug, Eq, PartialEq)] pub struct Certificate<'a> { /// tbsCertificate TBSCertificate, pub tbs_certificate: TBSCertificate<'a>, @@ -202,6 +202,33 @@ pub struct Certificate<'a> { pub signature: BitString<'a>, } +impl<'a> DecodeValue<'a> for Certificate<'a> { + fn decode_value(decoder: &mut Decoder<'a>, _length: Length) -> der::Result { + let tbs_certificate = decoder.decode()?; + let signature_algorithm = decoder.decode()?; + let signature = decoder.decode()?; + Ok(Self { + tbs_certificate, + signature_algorithm, + signature, + }) + // }) + } +} + +impl<'a> ::der::Sequence<'a> for Certificate<'a> { + fn fields(&self, f: F) -> ::der::Result + where + F: FnOnce(&[&dyn der::Encodable]) -> ::der::Result, + { + f(&[ + &self.tbs_certificate, + &self.signature_algorithm, + &self.signature, + ]) + } +} + /// 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. diff --git a/x509/src/lib.rs b/x509/src/lib.rs index 746a7da82..f711ba27c 100644 --- a/x509/src/lib.rs +++ b/x509/src/lib.rs @@ -22,6 +22,7 @@ pub mod pkix_extensions; pub mod pkix_oids; mod rdn; mod time; +pub mod trust_anchor_format; mod validity; pub use crate::{ diff --git a/x509/src/pkix_extensions.rs b/x509/src/pkix_extensions.rs index be00ff5a5..f15b960a9 100644 --- a/x509/src/pkix_extensions.rs +++ b/x509/src/pkix_extensions.rs @@ -338,20 +338,19 @@ pub struct NameConstraints<'a> { const PERMITTED_SUBTREES_TAG: TagNumber = TagNumber::new(0); const EXCLUDED_SUBTREES_TAG: TagNumber = TagNumber::new(1); -impl<'a> ::der::Decodable<'a> for NameConstraints<'a> { - fn decode(decoder: &mut ::der::Decoder<'a>) -> ::der::Result { - decoder.sequence(|decoder| { - let permitted_subtrees = - ::der::asn1::ContextSpecific::decode_implicit(decoder, ::der::TagNumber::N0)? - .map(|cs| cs.value); - let excluded_subtrees = - ::der::asn1::ContextSpecific::decode_implicit(decoder, ::der::TagNumber::N1)? - .map(|cs| cs.value); - Ok(Self { - permitted_subtrees, - excluded_subtrees, - }) +impl<'a> DecodeValue<'a> for NameConstraints<'a> { + fn decode_value(decoder: &mut Decoder<'a>, _length: Length) -> der::Result { + let permitted_subtrees = + ::der::asn1::ContextSpecific::decode_implicit(decoder, ::der::TagNumber::N0)? + .map(|cs| cs.value); + let excluded_subtrees = + ::der::asn1::ContextSpecific::decode_implicit(decoder, ::der::TagNumber::N1)? + .map(|cs| cs.value); + Ok(Self { + permitted_subtrees, + excluded_subtrees, }) + // }) } } diff --git a/x509/src/trust_anchor_format.rs b/x509/src/trust_anchor_format.rs new file mode 100644 index 000000000..ead33f489 --- /dev/null +++ b/x509/src/trust_anchor_format.rs @@ -0,0 +1,343 @@ +//! Trust anchor-related structures as defined in RFC 5914 + +use crate::{Certificate, CertificatePolicies, Extensions, Name, NameConstraints}; +use der::asn1::{BitString, ContextSpecific, OctetString, Utf8String}; +use der::{ + DecodeValue, Decoder, Encodable, EncodeValue, ErrorKind, FixedTag, Length, Tag, TagMode, + TagNumber, +}; +use spki::SubjectPublicKeyInfo; + +/// TrustAnchorInfo ::= SEQUENCE { +/// version TrustAnchorInfoVersion DEFAULT v1, +/// pubKey SubjectPublicKeyInfo, +/// keyId KeyIdentifier, +/// taTitle TrustAnchorTitle OPTIONAL, +/// certPath CertPathControls OPTIONAL, +/// exts \[1\] EXPLICIT Extensions OPTIONAL, +/// taTitleLangTag \[2\] UTF8String OPTIONAL } +/// +/// TrustAnchorInfoVersion ::= INTEGER { v1(1) } +/// +/// TrustAnchorTitle ::= UTF8String (SIZE (1..64)) +#[derive(Clone, Eq, PartialEq)] +pub struct TrustAnchorInfo<'a> { + /// version TrustAnchorInfoVersion DEFAULT v1, + pub version: Option, + + /// pubKey SubjectPublicKeyInfo, + pub pub_key: SubjectPublicKeyInfo<'a>, + + /// keyId KeyIdentifier, + pub key_id: OctetString<'a>, + + /// taTitle TrustAnchorTitle OPTIONAL, + pub ta_title: Option>, + + /// certPath CertPathControls OPTIONAL, + pub cert_path: Option>, + + /// exts \[1\] EXPLICIT Extensions OPTIONAL, + pub extensions: Option>, + + /// taTitleLangTag \[2\] UTF8String OPTIONAL } + pub ta_title_lang_tag: Option>, +} + +// impl<'a> ::der::Decodable<'a> for TrustAnchorInfo<'a> { +// fn decode(decoder: &mut ::der::Decoder<'a>) -> ::der::Result { +impl<'a> DecodeValue<'a> for TrustAnchorInfo<'a> { + fn decode_value(decoder: &mut Decoder<'a>, _length: Length) -> der::Result { + let version = match decoder.decode()? { + Some(v) => Some(v), + _ => Some(1), + }; + + let pub_key = decoder.decode()?; + let key_id = decoder.decode()?; + let ta_title = decoder.decode()?; + let cert_path = decoder.decode()?; + let extensions = + ::der::asn1::ContextSpecific::decode_explicit(decoder, ::der::TagNumber::N1)? + .map(|cs| cs.value); + let ta_title_lang_tag = + ::der::asn1::ContextSpecific::decode_explicit(decoder, ::der::TagNumber::N2)? + .map(|cs| cs.value); + Ok(Self { + version, + pub_key, + key_id, + ta_title, + cert_path, + extensions, + ta_title_lang_tag, + }) + } +} + +const TAF_EXTENSIONS_TAG: TagNumber = TagNumber::new(1); +const TA_TITLE_LANG_TAG: TagNumber = TagNumber::new(0); +impl<'a> ::der::Sequence<'a> for TrustAnchorInfo<'a> { + fn fields(&self, f: F) -> ::der::Result + where + F: FnOnce(&[&dyn der::Encodable]) -> ::der::Result, + { + #[allow(unused_imports)] + use core::convert::TryFrom; + f(&[ + &::der::asn1::OptionalRef(if self.version == Some(1) { + None + } else { + Some(&self.version) + }), + &self.pub_key, + &self.key_id, + &self.ta_title, + &self.cert_path, + &self.extensions.as_ref().map(|exts| ContextSpecific { + tag_number: TAF_EXTENSIONS_TAG, + tag_mode: TagMode::Explicit, + value: exts.clone(), + }), + &self + .ta_title_lang_tag + .as_ref() + .map(|ta_title_lang_tag| ContextSpecific { + tag_number: TA_TITLE_LANG_TAG, + tag_mode: TagMode::Implicit, + value: *ta_title_lang_tag, + }), + ]) + } +} + +impl<'a> ::core::fmt::Debug for TrustAnchorInfo<'a> { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.write_fmt(format_args!("\n\tVersion: {:02X?}\n", self.version))?; + f.write_fmt(format_args!("\tPublic Key Info: {:?}\n", self.pub_key))?; + f.write_fmt(format_args!("\tKey ID: {:?}\n", self.key_id))?; + f.write_fmt(format_args!("\tTA title: {:?}\n", self.ta_title))?; + f.write_fmt(format_args!( + "\tTA title language tag: {:?}\n", + self.ta_title_lang_tag + ))?; + f.write_fmt(format_args!( + "\tCertificate path controls: {:?}\n", + self.cert_path + ))?; + if let Some(exts) = self.extensions.as_ref() { + for (i, e) in exts.iter().enumerate() { + f.write_fmt(format_args!("\tExtension #{}: {:?}\n", i, e))?; + } + } else { + f.write_fmt(format_args!("\tExtensions: None\n"))?; + } + Ok(()) + } +} + +/// CertPathControls ::= SEQUENCE { +/// taName Name, +/// certificate \[0\] Certificate OPTIONAL, +/// policySet \[1\] CertificatePolicies OPTIONAL, +/// policyFlags \[2\] CertPolicyFlags OPTIONAL, +/// nameConstr \[3\] NameConstraints OPTIONAL, +/// pathLenConstraint\[4\] INTEGER (0..MAX) OPTIONAL} +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct CertPathControls<'a> { + /// taName Name, + pub ta_name: Name<'a>, + + /// certificate \[0\] Certificate OPTIONAL, + pub certificate: Option>, + + /// policySet \[1\] CertificatePolicies OPTIONAL, + pub policy_set: Option>, + + /// policyFlags \[2\] CertPolicyFlags OPTIONAL, + pub policy_flags: Option>, + + /// nameConstr \[3\] NameConstraints OPTIONAL, + pub name_constr: Option>, + + /// pathLenConstraint\[4\] INTEGER (0..MAX) OPTIONAL} + pub path_len_constraint: Option, +} + +impl<'a> ::der::Decodable<'a> for CertPathControls<'a> { + fn decode(decoder: &mut ::der::Decoder<'a>) -> ::der::Result { + decoder.sequence(|decoder| { + let ta_name = decoder.decode()?; + + let certificate = + ::der::asn1::ContextSpecific::decode_implicit(decoder, ::der::TagNumber::N0)? + .map(|cs| cs.value); + let policy_set = + ::der::asn1::ContextSpecific::decode_implicit(decoder, ::der::TagNumber::N1)? + .map(|cs| cs.value); + let policy_flags = + ::der::asn1::ContextSpecific::decode_implicit(decoder, ::der::TagNumber::N2)? + .map(|cs| cs.value); + + let name_constr = + ::der::asn1::ContextSpecific::decode_implicit(decoder, ::der::TagNumber::N3)? + .map(|cs| cs.value); + let path_len_constraint = + ::der::asn1::ContextSpecific::decode_implicit(decoder, ::der::TagNumber::N4)? + .map(|cs| cs.value); + Ok(Self { + ta_name, + certificate, + policy_set, + policy_flags, + name_constr, + path_len_constraint, + }) + }) + } +} +const CPC_CERTIFICATE_TAG: TagNumber = TagNumber::new(0); +const CPC_POLICY_SET_TAG: TagNumber = TagNumber::new(1); +const CPC_POLICY_FLAGS_TAG: TagNumber = TagNumber::new(2); +const CPC_NAME_CONSTRAINTS_TAG: TagNumber = TagNumber::new(3); +const CPC_PATH_LEN_CONSTRAINT_TAG: TagNumber = TagNumber::new(4); +impl<'a> ::der::Sequence<'a> for CertPathControls<'a> { + fn fields(&self, f: F) -> ::der::Result + where + F: FnOnce(&[&dyn der::Encodable]) -> ::der::Result, + { + #[allow(unused_imports)] + use core::convert::TryFrom; + f(&[ + &self.ta_name, + &self.certificate.as_ref().map(|exts| ContextSpecific { + tag_number: CPC_CERTIFICATE_TAG, + tag_mode: TagMode::Implicit, + value: exts.clone(), + }), + &self.policy_set.as_ref().map(|exts| ContextSpecific { + tag_number: CPC_POLICY_SET_TAG, + tag_mode: TagMode::Implicit, + value: exts.clone(), + }), + &self + .policy_flags + .as_ref() + .map(|policy_flags| ContextSpecific { + tag_number: CPC_POLICY_FLAGS_TAG, + tag_mode: TagMode::Implicit, + value: *policy_flags, + }), + &self.name_constr.as_ref().map(|exts| ContextSpecific { + tag_number: CPC_NAME_CONSTRAINTS_TAG, + tag_mode: TagMode::Implicit, + value: exts.clone(), + }), + &self + .path_len_constraint + .as_ref() + .map(|path_len_constraint| ContextSpecific { + tag_number: CPC_PATH_LEN_CONSTRAINT_TAG, + tag_mode: TagMode::Implicit, + value: *path_len_constraint, + }), + ]) + } +} + +/// CertPolicyFlags ::= BIT STRING { +/// inhibitPolicyMapping (0), +/// requireExplicitPolicy (1), +/// inhibitAnyPolicy (2) } +pub type CertPolicyFlags<'a> = BitString<'a>; + +/// TrustAnchorChoice ::= CHOICE { +/// certificate Certificate, +/// tbsCert \[1\] EXPLICIT TBSCertificate, +/// taInfo \[2\] EXPLICIT TrustAnchorInfo } +#[derive(Clone, Debug, Eq, PartialEq)] +#[allow(clippy::large_enum_variant)] +pub enum TrustAnchorChoice<'a> { + /// certificate Certificate, + Certificate(Certificate<'a>), + // Not supporting TBSCertificate option + // tbsCert \[1\] EXPLICIT TBSCertificate, + //TbsCertificate(TBSCertificate<'a>), + /// taInfo \[2\] EXPLICIT TrustAnchorInfo } + TaInfo(TrustAnchorInfo<'a>), +} + +//const TAC_TBS_CERTIFICATE_TAG: TagNumber = TagNumber::new(1); +const TAC_TA_INFO_TAG: TagNumber = TagNumber::new(2); + +impl<'a> DecodeValue<'a> for TrustAnchorChoice<'a> { + fn decode_value(decoder: &mut Decoder<'a>, _length: Length) -> der::Result { + let t = decoder.peek_tag()?; + let o = t.octet(); + // Context specific support always returns an Option<>, just ignore since OPTIONAL does not apply here + match o { + 0x30 => { + let cert = decoder.decode()?; + Ok(TrustAnchorChoice::Certificate(cert)) + } + // TODO - need DecodeValue on TBSCertificate to support this + // 0xA1 => { + // let on = decoder + // .context_specific::>(TAC_TBS_CERTIFICATE_TAG, TagMode::Explicit)?; + // match on { + // Some(on) => Ok(TrustAnchorChoice::TbsCertificate(on)), + // _ => Err(ErrorKind::Failed.into()), + // } + // } + 0xA2 => { + let on = decoder + .context_specific::>(TAC_TA_INFO_TAG, TagMode::Explicit)?; + match on { + Some(on) => Ok(TrustAnchorChoice::TaInfo(on)), + _ => Err(ErrorKind::Failed.into()), + } + } + _ => Err(ErrorKind::TagUnknown { byte: o }.into()), + } + } +} + +impl<'a> EncodeValue for TrustAnchorChoice<'a> { + fn encode_value(&self, encoder: &mut ::der::Encoder<'_>) -> ::der::Result<()> { + match self { + Self::Certificate(certificate) => certificate.encode(encoder), + // Self::TbsCertificate(variant) => ContextSpecific { + // tag_number: TAC_TBS_CERTIFICATE_TAG, + // tag_mode: TagMode::Explicit, + // value: variant.clone(), + // }.encode(encoder), + Self::TaInfo(variant) => variant.encode(encoder), + } + } + fn value_len(&self) -> ::der::Result<::der::Length> { + match self { + Self::Certificate(certificate) => certificate.encoded_len(), + // Self::TbsCertificate(variant) => ContextSpecific { + // tag_number: TAC_TBS_CERTIFICATE_TAG, + // tag_mode: TagMode::Explicit, + // value: variant.clone(), + // }.encoded_len(), + Self::TaInfo(variant) => variant.encoded_len(), + } + } +} + +//TODO - see why this is necessary to avoid problem at line 78 in context_specific.rs due to mismatched tag +impl<'a> FixedTag for TrustAnchorChoice<'a> { + const TAG: Tag = ::der::Tag::ContextSpecific { + constructed: true, + number: TAC_TA_INFO_TAG, + }; +} + +// Not supporting these structures +// TrustAnchorList ::= SEQUENCE SIZE (1..MAX) OF TrustAnchorChoice +// +// id-ct-trustAnchorList OBJECT IDENTIFIER ::= { iso(1) +// member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9) +// id-smime(16) id-ct(1) 34 } diff --git a/x509/tests/examples/eca.der b/x509/tests/examples/eca.der new file mode 100644 index 0000000000000000000000000000000000000000..fdd35d53bafeeccbc4230fa8c880ffd7e56ce9d2 GIT binary patch literal 859 zcmXqLVh%TGVzOVr%*4pV#K>sC%f_kI=F#?@mywa1mBGN*klTQhjX9KsO_(V(*igbi z48-9Q<`2~i)>ClLFH0@T%T3KIG2}7e0?BX-GrKxF8j2Z+fOyQpyg;5pP=0=i0+2Q_ zkQ3)MG%_$YGB7kVG&V4a66ZCtG&C}Xaj9)x6QdHchZtEIn41{+84Q{jxtN+585wpI zWQOl;h;lq2`E2U*D^0?8bS%8Pnoh}d#P-$M@Z_gHytPB7P-5FX5su2+$GT>|{iS#} zNrFN5gUFdEzw&vXUX+V4iyT||cazY9^#AhaRTm2Sr(G{l;nSV#8fU{G{BD7jq0|J0 z@YE*;;>S+1RNj^Qzu?6C_%#fwR*d_n&0(3^w>D_=#DXth-WWgR=MZn&(Z*$OdGXE! z%j0%CjWwHZa=j3K5NFG)+HfT2ypCRj)&*S$Pw69bwtY6!RC{B{P%L$}eCpb#I^G{e zG|gTZ#@zcF(_a?7n(^BC=V#Sdf7wzT;AEoO9v&qZGShlCf`rv%&X z%=_{EMN{ZS4VBb}r((x9xNu)?3366GaqD;7H^#P`=KKHV?Fcx*`^=`~7k6I&r=G+2 z1GdlC_^~cPX4aW~WqDq=zHHSnT_{^Lu}n(gz10bq2?u1^syCe7aq!uuXnzmUDCNaj zC)uKEdOBPRJ7+!5x@XI|{^IF9Q90W~JrvX(~vs sRXw|N$A0Nc#SRRIeb;oRd@Nqj+{q_ZGGoOQn{6d;ruZ?5zBbGQ05#}5)&Kwi literal 0 HcmV?d00001 diff --git a/x509/tests/examples/eca_policies.ta b/x509/tests/examples/eca_policies.ta new file mode 100755 index 0000000000000000000000000000000000000000..717364a2e446299a83f558757b8e7e4118e3c196 GIT binary patch literal 1954 zcmZ3~#6HiUiG7wq6Qhy=FB_*;n@8JsUPeYnRtDxKMt%mMI2ThBBO}9(g3R!}4N;B< zB%e)vex*tHj*f+QSJNq(j@Z6B8=m~shqrdf6iRHnC&E#A`&ie^x4#tcCP^^peh@hm zXNA zmdd+w{}-HiAHRk{)rxWdv^gwO`_=|+o>=hZ%Nyf|{2byMvW01Ds4$+ry*eLS|aeW_)$@?$pH_inhHeSg5tC_1DLh7E?so znV1daH??sod|itJ`R=K@(e)fv+LA0Vf-CC<~h~Q)sZEgn<}{ z!zIigsu!%M;GSQWT9lWYnpa}TW55NH;TC3gb#^oqGY|psn1y+PJcXeA{1OEqZL*+= zIozO$$$kMd6C)E7BO`LuaI-Q{*){_?ab80s17jltLo-8T1CuCmUL#9GBV!ns+SZMx zH6qg5VkZL!16g3=kmX|$!;$d#K+^n-jQ?3!fC;6|fFHyc2Ju-9n1K{pvH|93Muu(j zi4|@8wpJC2cYVC>$|U-Im%`DflQUK0L<=qb4qm+RqS|?PujIu83iqG;uI`GhZ&2v% zeb1E9b(LX`;&#?G&$st)oDyuiGw;Xu7fqoTHB?d?o{Amc;KF^mCCFL%#I4_P-x%9& zn(zOcwFIDO?40#H>z*y=`irOcOkK_q-WRygQ1Ei$ zhvxSI$KO@vSSu(0n3a~tr>P*lR`u-89s8v(6+18-_FdDN^09b9b0?ov$&3|KY_^rW znc~MJ`r0sWVG~oX0XMLuQ(mXbgT@yE1|qjM8zT#2dI}>@ z9?pGJ11u()P`PXdJZxNG#XX8#z-)`mLn!@kz|6+P1J?=WiXgat&9zKyaBkx^O-4p8 zR4xbH;7KtcAHb{u@z_D`2Ros0cQDX}LTG$pG(On>Nb1?)rg`#%LIY+th{p=zCA0`I zwr4Xkv4Xt^=P`i-HKEOeF_nptTNtbm!~v#D9yK7!aQE73Bp^||DNQ7Hh(mA!LBr`2DIk6-&KTpB2v?L?HD6=Fpwb)SC zKpUb)1*%KIH!&|UJvBukIJKxOGdZdJy=OjA%@V(7%3a>Zt*&fm|Fe5lj&rtyd(-4cC$_&$D=N*F$avO`D-7bZ8ZZMX16hy&ABz}^h*U|aTvsc{{D4@yE;q)m#yLOd z$sva_FaZKXnUTRD@1g7C!{YO;e@1yc|Cse&-pOXOr<;uL^GJg;3KFN7eYE7950w3? zee|?w?zI@JoSzI#=5e#v?4Mi^^qoUMROs^uliHb`7GAgi@V&nAdwtXzlqi z_x;P08!Q|>`q_Pi9-WiyJG!gF%&DZffoY!et;1IeYTlIed<&M5=al@n=-{^p&vWj) zIct>L7f~v4Xli>g(+qCYzRcp3J{-A(7><_3Q{($mj(!oX&a auHWW2E7*4%9Xz_@$gZn@N|e4DyaxaQ7h)m+ literal 0 HcmV?d00001 diff --git a/x509/tests/examples/entrust_dnConstraint.ta b/x509/tests/examples/entrust_dnConstraint.ta new file mode 100755 index 0000000000000000000000000000000000000000..ff784dd755c929690605b351a3c3c51e403040ab GIT binary patch literal 1443 zcmZ3~#5&)giFLL?6Qhy=FB_*;n@8JsUPeYnRtDxKMt%mMI2ThBBO}8m_eU4>_!fLw z)m|7P>r~zv`d<0a_7@WAvX2<&F4)C)@0m|jv&8S2a+kMpt1H{t|Lk6s5btekk%Z+8g;&zczx72>BA9P`dT?wT`MGwG+FIH&t^?ZjJan8kt~ zq-oS99y%^}r?4R;J$u%?DdrFU9%sCB;XlXB?#U|+v?M;(H=1sG-KFjq!?RX!U2u~k zhitB$eBFE#j~?5wV`BgGZwG=smag+#*JRCl{&(zx*;&HB9Fs&+_!Ou3CoQ*lZ)k8? zlZly;fssW-sw7mdtCeGZK&)Mt8)H}FoS*aL44PP?4T=o84LI4DLs{5_nL>jN1q}E= z94=vY*SwOV(&7?BB?ASJ2)D4Lb81mZW?E))Vo7Fxo`Pd(Nk)EAW=Uphv7xSkHbjjI zRF{HpVqRi;YKlT|YEfBca%!=HpPQ#bP=0=ig0tg-CgvpuO-wxtn3))vm{`1)AIe3J zLRMCWfpC?9oH(z6B?uat7@3`$btm;Sj2GT1*9?rm;ixg2qS|*-b2^NhsEbx|BUi@{xR#l zypzplPd6Fg=aB|y6eLbD`)J8IA1M1(`{-%W+-osbIX@Yg%;RRS*+01;=sSmisLD}zCu zA-4f18*?ZNn=n&ou%U>75QxJi%2ym?Ni9k&Nlj7kOi9fv$t|3%S=vH z2+GedQE+xtFf@=8=QT7iFf}wVG&eCeF^m%DHHLCc4UCMV2Hbs3j7rEs#>mRR+{DPw zV9>fak*7=2v*f9KT-z5{t>Db>btA2mA8bfoc17^%*UvdH<${UGm8 znC5|%t?SqIX)3?krBUn_sk0_CHqumec_D43}oN?jt{|0~WpOqi}3P;|ZR<%-BOz6CLm#NZA z)vz;@a&!#DpGQRAy}#_IXv^iBw=Zk39X-c&R$P0=qE+)Z=Dbo}A!EKn=GihmL7%K- z>#~Tm_gQ9nb?)~M+5D4#+6T5g<;oRDS>=3g@g*4km65;mcKf4USqXMs9CI1Yp4zk0 z`p1i9N5tGV&6f{({x$G*?}j!-CT2zk#>Gws4hDR{=$GYZWc<&<0!(_x4ERBOVGy6y zfEh>`$btm;Sj1RF^!80$R-R>U^YyRnw!0N4mp%QWq<|dCz=R15Wkv=y%hY{8W4>>+ zQrP3rP*WwctG1wCL;6|lN7*M;Mk+~rJvFS42d$Rb6L8J5{QUI83lC29(|0|+@`VU>dE&fmMqTDQ0bi^y63#gfutV&%X`)y+%e&6nn8e*dDY$S z_zxE~|DAlFoTzd_Nv-etQ%1v`YJy$j(xuD)-Hj3Pb8X18Ft~ka<4n)hf~MPbR$6DW zZul3{)aJs!ck9O1<8^23YXa*vUj!=zGa4V3iaopJAe+&iWj{j?8J5HeOuixfZd=LL zJ38&!e|#qt^55*7oL~Rc`&YbE8Sg#*dqH@8t!F($lu5=~$?tC&{1#OA F0ss%@c4+_r literal 0 HcmV?d00001 diff --git a/x509/tests/examples/exostar_policyFlags.ta b/x509/tests/examples/exostar_policyFlags.ta new file mode 100755 index 0000000000000000000000000000000000000000..46e5f9248c57c6c4cb5f45a3e7f8abdf9b8d48ef GIT binary patch literal 1495 zcmZ3~#CqAFiS@ie6Qhy=FB_*;n@8JsUPeYnRtDxKMt%mMI2ThBBO}AUS*w3f3IMb2FFJYuQH_9UCEBAxEKVg~&R<^ER*QcrcYL{A(THtMd z=N*mH61H=u$NwAry?<7I_$wTFcUsj-T`{5a;$5anFIB_NOv=$Q5Pu#KdH4RZpQ0_7 zZ{EJF!FKc<*I9Ax8H-lU-U^YyRnw!0N4mp%QWq+rm*(r-{_$Zf#M#vIDRCd?EXY$#$N z1mbWBbGugL7ndX!Dfsv}8!8znfJC{4C7n}?N;1Q&RIvGD|8If>VpiGLuskg7WiA6r3Fu3>P#ppD<`* z+OU9`iIIs(py1AKR zUSlZN)WFC%YQWt$nj4774U3%&91Qq?iB*=Lk?}tZ3oz*&GvEjDg+Y8)17;v)APW-U zV-drVcaX{)V8R5JIgAWymZ|%G#(dvsrLf1Lp{7b?S8YMPhV--8kFrmyj8u~LdTLl7 z4_Ym=C*YcA`T6OG7aq)(dG^KNhsCbCYH!}IX)dai5rAwFp zyBj0o=h~2GVQ~A<#+jb01x>f>thCN#-S97@sm+Cd@79g2$Lr46*96vUz6e$bW;8x5 z6?=BcK{lg3%YKF)GAxM`n0!O{-L{ggcXZmd|M*TQvR50W*-~!2T3p2aqy8r+MD?c*; literal 0 HcmV?d00001 diff --git a/x509/tests/examples/raytheon.der b/x509/tests/examples/raytheon.der new file mode 100644 index 0000000000000000000000000000000000000000..9b577432dcfb8cdc13c71832635847dafcba5927 GIT binary patch literal 907 zcmXqLVs1BRV#;5@%*4pV#Nrk^OUr@5qwPB{BO@y-gF%R)uz?^O7w06k&dHy2 zQWz!0n3MB!4J8c3Py{)O5-UqGQuFf+c?`JNm_u2(gqfWkiw#8$gh4!RVV)qUf}s5T z5(7DLUPBWDLqk&|LsL^@%P4VPBM8^X2*jn4txb$d$lhaQWngY%|M>rtfyG9Y<{cY{r>~C6YL=9PRN}yD#UsbL)jwb7!#M z6_OD-GwEGgXSCLSH?wZx$r7qBX5J7ySp7xR|8nXvj)v+vd9rehOYCBf->SWM`N6NE z{U^5zvkAo}{bXWhWMEvJXb^9}4~#TfVMfOPEUX61K+1p*B)|_6U;(BTHUn7@pN~b1 zMMT4(?P{2)lYmpqhiVzYP0gKGDiwgz;6(JTmfewoMZkbhnj_3Y&(O+5&w!bUWdd>} z0Mi&S5*QiO%_=7I2QTJ6GLhS--|?p+m(7=JESAL`Gn>4-WU4sNE?RDQUqbB4<&XPo z_MSE6<*vFG5ZbnY|NpFAGlMlgtzFi>dta^I)wZ3<$?Vdack5qtAK#YQH(6!HEAfhl zDQWW)uNJ>to&3zk?T>54ip*ff59NOsv0ZlV%4c1J{or&bdh3ntb-Sb$0sy4$O$7h| literal 0 HcmV?d00001 diff --git a/x509/tests/examples/raytheon_pathLenConstraint.ta b/x509/tests/examples/raytheon_pathLenConstraint.ta new file mode 100644 index 0000000000000000000000000000000000000000..eb0fd7f3511a7bba891936b3e25e9ebc943d6592 GIT binary patch literal 1324 zcmZ3~#HwM?#HwP@#HeJz%f_kI=F#?@mywZ?m4Ug5k)Hu5&c)Qk$jC5lnr|cPnoQ^S z*UXicPv;U4t=YnK`p5s{Dc2098ecp$Vfxw=%O?vn&MdJg7hIEf|BlD9wmWCH&N4n$ z%9ydc#^7e#sp}@&)~J2k*?4(dvgv1KkApdZa}S#5pZ^!IZl$vLbjKqxx7Tm0t}9z1 zC@om7tyin>_RZ``i?_4bA_19A-|bpEj@m@JXdg{G%uhDdt19jNqo`&MTD)22IRQ3_=Wr4FuV^I47xfPX45m!YC=m zoSdI)C}ALmBFIscSXq*hnxALLW5C769LmBa%ECME z9T`{z4EUru!YuR*txWU`n3-56prtWjLBPnMZdNgwKX@_sk%`f~oOZhu@WR%8Y_{s s8YYJ6n#`JaM61ip@GS2!_P5z@(~emM*d{i8aDHvOK2252wuO-i0J { + assert_eq!( + tai.pub_key.algorithm.oid.to_string(), + "1.2.840.113549.1.1.1" + ); + + assert_eq!( + &hex!("335BA56F7A55602B814B2614CC79BF4ABA8B32BD"), + tai.key_id.as_bytes() + ); + + let policy_ids: [&str; 42] = [ + "1.2.36.1.334.1.2.1.2", + "1.2.840.113549.5.6.1.3.1.12", + "1.2.840.113549.5.6.1.3.1.18", + "1.3.6.1.4.1.103.100.1.1.3.1", + "1.3.6.1.4.1.13948.1.1.1.2", + "1.3.6.1.4.1.13948.1.1.1.6", + "1.3.6.1.4.1.1569.10.1.1", + "1.3.6.1.4.1.1569.10.1.2", + "1.3.6.1.4.1.16304.3.6.2.12", + "1.3.6.1.4.1.16304.3.6.2.20", + "1.3.6.1.4.1.16334.509.2.6", + "1.3.6.1.4.1.23337.1.1.10", + "1.3.6.1.4.1.23337.1.1.8", + "1.3.6.1.4.1.2396.2.1.2", + "1.3.6.1.4.1.2396.2.1.7", + "1.3.6.1.4.1.24019.1.1.1.18", + "1.3.6.1.4.1.24019.1.1.1.19", + "1.3.6.1.4.1.24019.1.1.1.2", + "1.3.6.1.4.1.24019.1.1.1.7", + "1.3.6.1.4.1.73.15.3.1.12", + "1.3.6.1.4.1.73.15.3.1.5", + "2.16.528.1.1003.1.2.5.1", + "2.16.528.1.1003.1.2.5.2", + "2.16.840.1.101.2.1.11.19", + "2.16.840.1.101.3.2.1.12.2", + "2.16.840.1.101.3.2.1.12.3", + "2.16.840.1.101.3.2.1.3.12", + "2.16.840.1.101.3.2.1.3.13", + "2.16.840.1.101.3.2.1.3.16", + "2.16.840.1.101.3.2.1.3.18", + "2.16.840.1.101.3.2.1.3.24", + "2.16.840.1.101.3.2.1.3.4", + "2.16.840.1.101.3.2.1.3.7", + "2.16.840.1.101.3.2.1.5.4", + "2.16.840.1.101.3.2.1.5.5", + "2.16.840.1.101.3.2.1.6.12", + "2.16.840.1.101.3.2.1.6.4", + "2.16.840.1.113733.1.7.23.3.1.18", + "2.16.840.1.113733.1.7.23.3.1.7", + "2.16.840.1.114027.200.3.10.7.2", + "2.16.840.1.114027.200.3.10.7.4", + "2.16.840.1.114027.200.3.10.7.6", + ]; + + let cert_path = tai.cert_path.as_ref().unwrap(); + let mut counter = 0; + let exts = cert_path.policy_set.as_ref().unwrap(); + let i = exts.iter(); + for ext in i { + assert_eq!(policy_ids[counter], ext.policy_identifier.to_string()); + counter += 1; + } + + counter = 0; + let i = cert_path.ta_name.iter(); + for rdn in i { + let i1 = rdn.iter(); + for atav in i1 { + if 0 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.6"); + assert_eq!(atav.value.printable_string().unwrap().to_string(), "US"); + } else if 1 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.10"); + assert_eq!( + atav.value.printable_string().unwrap().to_string(), + "U.S. Government" + ); + } else if 2 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.11"); + assert_eq!(atav.value.printable_string().unwrap().to_string(), "ECA"); + } else if 3 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.3"); + assert_eq!( + atav.value.printable_string().unwrap().to_string(), + "ECA Root CA 4" + ); + } + counter += 1; + } + } + + let reencoded_cert = cert_path.certificate.to_vec().unwrap(); + assert_eq!(der_encoded_cert, reencoded_cert.as_slice()); + } + _ => panic!("Unexpected TrustAnchorChoice contents"), + } +} + +#[test] +fn decode_ta2() { + // features an Entrust cert wrapped in a TrustAnchorInfo that contains an excluded subtree in the + // name constraint in the cert path controls field + let der_encoded_tac = include_bytes!("examples/entrust_dnConstraint.ta"); + let der_encoded_cert = include_bytes!("examples/entrust.der"); + + let mut decoder = Decoder::new(der_encoded_tac).unwrap(); + let header = decoder.peek_header().unwrap(); + let tac = TrustAnchorChoice::decode_value(&mut decoder, header.length).unwrap(); + let reencoded_tac = tac.to_vec().unwrap(); + println!("Original : {:02X?}", der_encoded_cert); + println!("Reencoded: {:02X?}", reencoded_tac); + assert_eq!(der_encoded_tac, reencoded_tac.as_slice()); + + match tac { + TrustAnchorChoice::TaInfo(tai) => { + assert_eq!( + tai.pub_key.algorithm.oid.to_string(), + "1.2.840.113549.1.1.1" + ); + + assert_eq!( + &hex!("1A74551E8A85089F505D3E8A46018A819CF99E1E"), + tai.key_id.as_bytes() + ); + + let cert_path = tai.cert_path.as_ref().unwrap(); + + let mut counter = 0; + let i = cert_path.ta_name.iter(); + for rdn in i { + let i1 = rdn.iter(); + for atav in i1 { + if 0 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.6"); + assert_eq!(atav.value.printable_string().unwrap().to_string(), "US"); + } else if 1 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.10"); + assert_eq!( + atav.value.printable_string().unwrap().to_string(), + "Entrust" + ); + } else if 2 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.11"); + assert_eq!( + atav.value.printable_string().unwrap().to_string(), + "Certification Authorities" + ); + } else if 3 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.11"); + assert_eq!( + atav.value.printable_string().unwrap().to_string(), + "Entrust Managed Services NFI Root CA" + ); + } + counter += 1; + } + } + + let nc = cert_path.name_constr.as_ref().unwrap(); + counter = 0; + let gsi = nc.excluded_subtrees.as_ref().unwrap().iter(); + for gs in gsi { + match &gs.base { + GeneralName::DirectoryName(dn) => { + let i = dn.iter(); + for rdn in i { + let i1 = rdn.iter(); + for atav in i1 { + if 0 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.6"); + assert_eq!( + atav.value.printable_string().unwrap().to_string(), + "US" + ); + } else if 1 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.10"); + assert_eq!( + atav.value.printable_string().unwrap().to_string(), + "U.S. Government" + ); + } else if 2 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.11"); + assert_eq!( + atav.value.printable_string().unwrap().to_string(), + "DoD" + ); + } + counter += 1; + } + } + } + _ => panic!("Unexpected GeneralSubtree type"), + } + } + + let reencoded_cert = cert_path.certificate.to_vec().unwrap(); + assert_eq!(der_encoded_cert, reencoded_cert.as_slice()); + } + _ => panic!("Unexpected TrustAnchorChoice contents"), + } +} + +#[test] +fn decode_ta3() { + // features an Exostar cert wrapped in a TrustAnchorInfo that contains an excluded subtree in the + // name constraint and policy flags in the cert path controls field + let der_encoded_tac = include_bytes!("examples/exostar_policyFlags.ta"); + let der_encoded_cert = include_bytes!("examples/exostar.der"); + + let mut decoder = Decoder::new(der_encoded_tac).unwrap(); + let header = decoder.peek_header().unwrap(); + let tac = TrustAnchorChoice::decode_value(&mut decoder, header.length).unwrap(); + let reencoded_tac = tac.to_vec().unwrap(); + println!("Original : {:02X?}", der_encoded_cert); + println!("Reencoded: {:02X?}", reencoded_tac); + assert_eq!(der_encoded_tac, reencoded_tac.as_slice()); + + match tac { + TrustAnchorChoice::TaInfo(tai) => { + assert_eq!( + tai.pub_key.algorithm.oid.to_string(), + "1.2.840.113549.1.1.1" + ); + + assert_eq!( + &hex!("2EBE91A6776A373CF5FD1DB6DD78C9A6E5F42220"), + tai.key_id.as_bytes() + ); + + let cert_path = tai.cert_path.as_ref().unwrap(); + + let cpf = cert_path.policy_flags.unwrap(); + let b = cpf.raw_bytes(); + if 0x80 != 0x80 & b[0] { + panic!("Missing policy flag bit 0") + } + if 0x40 != 0x40 & b[0] { + panic!("Missing policy flag bit 1") + } + if 0x20 != 0x20 & b[0] { + panic!("Missing policy flag bit 2") + } + if cpf.unused_bits() != 5 { + panic!("Wrong unused bits for policy flags") + } + + let mut counter = 0; + let i = cert_path.ta_name.iter(); + for rdn in i { + let i1 = rdn.iter(); + for atav in i1 { + if 0 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.6"); + assert_eq!(atav.value.printable_string().unwrap().to_string(), "US"); + } else if 1 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.10"); + assert_eq!( + atav.value.printable_string().unwrap().to_string(), + "Exostar LLC" + ); + } else if 2 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.11"); + assert_eq!( + atav.value.printable_string().unwrap().to_string(), + "Certification Authorities" + ); + } else if 3 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.3"); + assert_eq!( + atav.value.printable_string().unwrap().to_string(), + "Exostar Federated Identity Service Root CA 1" + ); + } + counter += 1; + } + } + + let nc = cert_path.name_constr.as_ref().unwrap(); + counter = 0; + let gsi = nc.excluded_subtrees.as_ref().unwrap().iter(); + for gs in gsi { + match &gs.base { + GeneralName::DirectoryName(dn) => { + let i = dn.iter(); + for rdn in i { + let i1 = rdn.iter(); + for atav in i1 { + if 0 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.6"); + assert_eq!( + atav.value.printable_string().unwrap().to_string(), + "US" + ); + } else if 1 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.10"); + assert_eq!( + atav.value.printable_string().unwrap().to_string(), + "U.S. Government" + ); + } else if 2 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.11"); + assert_eq!( + atav.value.printable_string().unwrap().to_string(), + "DoD" + ); + } + counter += 1; + } + } + } + _ => panic!("Unexpected GeneralSubtree type"), + } + } + + let reencoded_cert = cert_path.certificate.to_vec().unwrap(); + assert_eq!(der_encoded_cert, reencoded_cert.as_slice()); + } + _ => panic!("Unexpected TrustAnchorChoice contents"), + } +} + +#[test] +fn decode_ta4() { + // features an Exostar cert wrapped in a TrustAnchorInfo that contains path length constraint in + // the cert path controls field + let der_encoded_tac = include_bytes!("examples/raytheon_pathLenConstraint.ta"); + let der_encoded_cert = include_bytes!("examples/raytheon.der"); + + let mut decoder = Decoder::new(der_encoded_tac).unwrap(); + let header = decoder.peek_header().unwrap(); + let tac = TrustAnchorChoice::decode_value(&mut decoder, header.length).unwrap(); + let reencoded_tac = tac.to_vec().unwrap(); + println!("Original : {:02X?}", der_encoded_cert); + println!("Reencoded: {:02X?}", reencoded_tac); + assert_eq!(der_encoded_tac, reencoded_tac.as_slice()); + + match tac { + TrustAnchorChoice::TaInfo(tai) => { + assert_eq!( + tai.pub_key.algorithm.oid.to_string(), + "1.2.840.113549.1.1.1" + ); + + assert_eq!( + &hex!("283086D556154210425CF07B1C11B28389D47920"), + tai.key_id.as_bytes() + ); + + let cert_path = tai.cert_path.as_ref().unwrap(); + + let mut counter = 0; + let i = cert_path.ta_name.iter(); + for rdn in i { + let i1 = rdn.iter(); + for atav in i1 { + if 0 == counter { + assert_eq!(atav.oid.to_string(), "0.9.2342.19200300.100.1.25"); + assert_eq!(atav.value.ia5_string().unwrap().to_string(), "com"); + } else if 1 == counter { + assert_eq!(atav.oid.to_string(), "0.9.2342.19200300.100.1.25"); + assert_eq!(atav.value.ia5_string().unwrap().to_string(), "raytheon"); + } else if 2 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.10"); + assert_eq!(atav.value.printable_string().unwrap().to_string(), "CAs"); + } else if 3 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.11"); + assert_eq!( + atav.value.printable_string().unwrap().to_string(), + "RaytheonRoot" + ); + } + counter += 1; + } + } + + let pl = cert_path.path_len_constraint.unwrap(); + if 2 != pl { + panic!("Wrong path length constraint"); + } + + let reencoded_cert = cert_path.certificate.to_vec().unwrap(); + assert_eq!(der_encoded_cert, reencoded_cert.as_slice()); + } + _ => panic!("Unexpected TrustAnchorChoice contents"), + } +} From 9db095df0ff5b65075465de9cbedcc4ecf716184 Mon Sep 17 00:00:00 2001 From: Carl Wallace Date: Tue, 1 Feb 2022 13:01:58 -0500 Subject: [PATCH 2/3] Align with new Sequence macro output that used DecodeValue instead of Decodable (#375) and remove custom impls on Certificate, NameConstraints and CertPathControls. --- x509/src/certificate.rs | 31 +---------- x509/src/pkix_extensions.rs | 48 ++--------------- x509/src/trust_anchor_format.rs | 92 +++------------------------------ 3 files changed, 13 insertions(+), 158 deletions(-) diff --git a/x509/src/certificate.rs b/x509/src/certificate.rs index 57528c6a3..85ac1cfc4 100644 --- a/x509/src/certificate.rs +++ b/x509/src/certificate.rs @@ -2,7 +2,7 @@ use crate::{Name, Validity}; use der::asn1::{BitString, ContextSpecific, ObjectIdentifier, UIntBytes}; -use der::{DecodeValue, Decoder, Length, Sequence, TagMode, TagNumber}; +use der::{Sequence, TagMode, TagNumber}; use spki::{AlgorithmIdentifier, SubjectPublicKeyInfo}; /// returns false in support of integer DEFAULT fields set to 0 @@ -192,7 +192,7 @@ impl<'a> ::core::fmt::Debug for TBSCertificate<'a> { /// ``` /// /// [RFC 5280 Section 4.1]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1 -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] pub struct Certificate<'a> { /// tbsCertificate TBSCertificate, pub tbs_certificate: TBSCertificate<'a>, @@ -202,33 +202,6 @@ pub struct Certificate<'a> { pub signature: BitString<'a>, } -impl<'a> DecodeValue<'a> for Certificate<'a> { - fn decode_value(decoder: &mut Decoder<'a>, _length: Length) -> der::Result { - let tbs_certificate = decoder.decode()?; - let signature_algorithm = decoder.decode()?; - let signature = decoder.decode()?; - Ok(Self { - tbs_certificate, - signature_algorithm, - signature, - }) - // }) - } -} - -impl<'a> ::der::Sequence<'a> for Certificate<'a> { - fn fields(&self, f: F) -> ::der::Result - where - F: FnOnce(&[&dyn der::Encodable]) -> ::der::Result, - { - f(&[ - &self.tbs_certificate, - &self.signature_algorithm, - &self.signature, - ]) - } -} - /// 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. diff --git a/x509/src/pkix_extensions.rs b/x509/src/pkix_extensions.rs index f15b960a9..8ce271370 100644 --- a/x509/src/pkix_extensions.rs +++ b/x509/src/pkix_extensions.rs @@ -324,59 +324,17 @@ pub struct PolicyMapping { /// ``` /// /// [RFC 5280 Section 4.2.1.10]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.10 -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] pub struct NameConstraints<'a> { /// permittedSubtrees [0] GeneralSubtrees OPTIONAL, - //#[asn1(context_specific = "0", optional = "true", tag_mode = "IMPLICIT")] + #[asn1(context_specific = "0", optional = "true", tag_mode = "IMPLICIT")] pub permitted_subtrees: Option>, /// excludedSubtrees [1] GeneralSubtrees OPTIONAL } - //#[asn1(context_specific = "1", optional = "true", tag_mode = "IMPLICIT")] + #[asn1(context_specific = "1", optional = "true", tag_mode = "IMPLICIT")] pub excluded_subtrees: Option>, } -const PERMITTED_SUBTREES_TAG: TagNumber = TagNumber::new(0); -const EXCLUDED_SUBTREES_TAG: TagNumber = TagNumber::new(1); - -impl<'a> DecodeValue<'a> for NameConstraints<'a> { - fn decode_value(decoder: &mut Decoder<'a>, _length: Length) -> der::Result { - let permitted_subtrees = - ::der::asn1::ContextSpecific::decode_implicit(decoder, ::der::TagNumber::N0)? - .map(|cs| cs.value); - let excluded_subtrees = - ::der::asn1::ContextSpecific::decode_implicit(decoder, ::der::TagNumber::N1)? - .map(|cs| cs.value); - Ok(Self { - permitted_subtrees, - excluded_subtrees, - }) - // }) - } -} - -impl<'a> ::der::Sequence<'a> for NameConstraints<'a> { - fn fields(&self, f: F) -> ::der::Result - where - F: FnOnce(&[&dyn der::Encodable]) -> ::der::Result, - { - f(&[ - &self - .permitted_subtrees - .as_ref() - .map(|elem| ContextSpecific { - tag_number: PERMITTED_SUBTREES_TAG, - tag_mode: TagMode::Implicit, - value: elem.clone(), - }), - &self.excluded_subtrees.as_ref().map(|elem| ContextSpecific { - tag_number: EXCLUDED_SUBTREES_TAG, - tag_mode: TagMode::Implicit, - value: elem.clone(), - }), - ]) - } -} - /// GeneralSubtrees as defined in [RFC 5280 Section 4.2.1.10] in support of the Name Constraints extension. /// /// ```text diff --git a/x509/src/trust_anchor_format.rs b/x509/src/trust_anchor_format.rs index ead33f489..b35ebbd87 100644 --- a/x509/src/trust_anchor_format.rs +++ b/x509/src/trust_anchor_format.rs @@ -3,8 +3,8 @@ use crate::{Certificate, CertificatePolicies, Extensions, Name, NameConstraints}; use der::asn1::{BitString, ContextSpecific, OctetString, Utf8String}; use der::{ - DecodeValue, Decoder, Encodable, EncodeValue, ErrorKind, FixedTag, Length, Tag, TagMode, - TagNumber, + DecodeValue, Decoder, Encodable, EncodeValue, ErrorKind, FixedTag, Length, Sequence, Tag, + TagMode, TagNumber, }; use spki::SubjectPublicKeyInfo; @@ -143,108 +143,32 @@ impl<'a> ::core::fmt::Debug for TrustAnchorInfo<'a> { /// policyFlags \[2\] CertPolicyFlags OPTIONAL, /// nameConstr \[3\] NameConstraints OPTIONAL, /// pathLenConstraint\[4\] INTEGER (0..MAX) OPTIONAL} -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Sequence)] pub struct CertPathControls<'a> { /// taName Name, pub ta_name: Name<'a>, /// certificate \[0\] Certificate OPTIONAL, + #[asn1(context_specific = "0", optional = "true", tag_mode = "IMPLICIT")] pub certificate: Option>, /// policySet \[1\] CertificatePolicies OPTIONAL, + #[asn1(context_specific = "1", optional = "true", tag_mode = "IMPLICIT")] pub policy_set: Option>, /// policyFlags \[2\] CertPolicyFlags OPTIONAL, + #[asn1(context_specific = "2", optional = "true", tag_mode = "IMPLICIT")] pub policy_flags: Option>, /// nameConstr \[3\] NameConstraints OPTIONAL, + #[asn1(context_specific = "3", optional = "true", tag_mode = "IMPLICIT")] pub name_constr: Option>, /// pathLenConstraint\[4\] INTEGER (0..MAX) OPTIONAL} + #[asn1(context_specific = "4", optional = "true", tag_mode = "IMPLICIT")] pub path_len_constraint: Option, } -impl<'a> ::der::Decodable<'a> for CertPathControls<'a> { - fn decode(decoder: &mut ::der::Decoder<'a>) -> ::der::Result { - decoder.sequence(|decoder| { - let ta_name = decoder.decode()?; - - let certificate = - ::der::asn1::ContextSpecific::decode_implicit(decoder, ::der::TagNumber::N0)? - .map(|cs| cs.value); - let policy_set = - ::der::asn1::ContextSpecific::decode_implicit(decoder, ::der::TagNumber::N1)? - .map(|cs| cs.value); - let policy_flags = - ::der::asn1::ContextSpecific::decode_implicit(decoder, ::der::TagNumber::N2)? - .map(|cs| cs.value); - - let name_constr = - ::der::asn1::ContextSpecific::decode_implicit(decoder, ::der::TagNumber::N3)? - .map(|cs| cs.value); - let path_len_constraint = - ::der::asn1::ContextSpecific::decode_implicit(decoder, ::der::TagNumber::N4)? - .map(|cs| cs.value); - Ok(Self { - ta_name, - certificate, - policy_set, - policy_flags, - name_constr, - path_len_constraint, - }) - }) - } -} -const CPC_CERTIFICATE_TAG: TagNumber = TagNumber::new(0); -const CPC_POLICY_SET_TAG: TagNumber = TagNumber::new(1); -const CPC_POLICY_FLAGS_TAG: TagNumber = TagNumber::new(2); -const CPC_NAME_CONSTRAINTS_TAG: TagNumber = TagNumber::new(3); -const CPC_PATH_LEN_CONSTRAINT_TAG: TagNumber = TagNumber::new(4); -impl<'a> ::der::Sequence<'a> for CertPathControls<'a> { - fn fields(&self, f: F) -> ::der::Result - where - F: FnOnce(&[&dyn der::Encodable]) -> ::der::Result, - { - #[allow(unused_imports)] - use core::convert::TryFrom; - f(&[ - &self.ta_name, - &self.certificate.as_ref().map(|exts| ContextSpecific { - tag_number: CPC_CERTIFICATE_TAG, - tag_mode: TagMode::Implicit, - value: exts.clone(), - }), - &self.policy_set.as_ref().map(|exts| ContextSpecific { - tag_number: CPC_POLICY_SET_TAG, - tag_mode: TagMode::Implicit, - value: exts.clone(), - }), - &self - .policy_flags - .as_ref() - .map(|policy_flags| ContextSpecific { - tag_number: CPC_POLICY_FLAGS_TAG, - tag_mode: TagMode::Implicit, - value: *policy_flags, - }), - &self.name_constr.as_ref().map(|exts| ContextSpecific { - tag_number: CPC_NAME_CONSTRAINTS_TAG, - tag_mode: TagMode::Implicit, - value: exts.clone(), - }), - &self - .path_len_constraint - .as_ref() - .map(|path_len_constraint| ContextSpecific { - tag_number: CPC_PATH_LEN_CONSTRAINT_TAG, - tag_mode: TagMode::Implicit, - value: *path_len_constraint, - }), - ]) - } -} - /// CertPolicyFlags ::= BIT STRING { /// inhibitPolicyMapping (0), /// requireExplicitPolicy (1), From 1890f602b231a107333c15d408b1b6262b983905 Mon Sep 17 00:00:00 2001 From: Carl Wallace Date: Wed, 2 Feb 2022 10:04:53 -0500 Subject: [PATCH 3/3] use x501 crate for Name --- x509/src/trust_anchor_format.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x509/src/trust_anchor_format.rs b/x509/src/trust_anchor_format.rs index b35ebbd87..ec2cf8539 100644 --- a/x509/src/trust_anchor_format.rs +++ b/x509/src/trust_anchor_format.rs @@ -1,12 +1,13 @@ //! Trust anchor-related structures as defined in RFC 5914 -use crate::{Certificate, CertificatePolicies, Extensions, Name, NameConstraints}; +use crate::{Certificate, CertificatePolicies, Extensions, NameConstraints}; use der::asn1::{BitString, ContextSpecific, OctetString, Utf8String}; use der::{ DecodeValue, Decoder, Encodable, EncodeValue, ErrorKind, FixedTag, Length, Sequence, Tag, TagMode, TagNumber, }; use spki::SubjectPublicKeyInfo; +use x501::name::Name; /// TrustAnchorInfo ::= SEQUENCE { /// version TrustAnchorInfoVersion DEFAULT v1,