diff --git a/cms/tests/builder.rs b/cms/tests/builder.rs index a3fa2322b..5eea5deaa 100644 --- a/cms/tests/builder.rs +++ b/cms/tests/builder.rs @@ -13,7 +13,7 @@ use cms::enveloped_data::RecipientInfo::Ktri; use cms::enveloped_data::{EnvelopedData, RecipientIdentifier, RecipientInfo}; use cms::signed_data::{EncapsulatedContentInfo, SignedData, SignerIdentifier}; use const_oid::ObjectIdentifier; -use der::asn1::{OctetString, PrintableString, SetOfVec, Utf8StringRef}; +use der::asn1::{OctetString, PrintableString, SetOfVec}; use der::{Any, AnyRef, Decode, DecodePem, Encode, Tag, Tagged}; use p256::{pkcs8::DecodePrivateKey, NistP256}; use pem_rfc7468::LineEnding; @@ -24,8 +24,7 @@ use rsa::{Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey}; use sha2::Sha256; use signature::Verifier; use spki::AlgorithmIdentifierOwned; -use x509_cert::attr::{Attribute, AttributeTypeAndValue, AttributeValue}; -use x509_cert::name::{RdnSequence, RelativeDistinguishedName}; +use x509_cert::attr::{Attribute, AttributeValue}; use x509_cert::serial_number::SerialNumber; // TODO bk replace this by const_oid definitions as soon as released @@ -50,34 +49,18 @@ fn ecdsa_signer() -> ecdsa::SigningKey { } fn signer_identifier(id: i32) -> SignerIdentifier { - let mut rdn_sequence = RdnSequence::default(); - let rdn = &[AttributeTypeAndValue { - oid: const_oid::db::rfc4519::CN, - value: Any::from(Utf8StringRef::new(&format!("test client {id}")).unwrap()), - }]; - let set_of_vector = SetOfVec::try_from(rdn.to_vec()).unwrap(); - rdn_sequence - .0 - .push(RelativeDistinguishedName::from(set_of_vector)); + let issuer = format!("CN=test client {id}").parse().unwrap(); SignerIdentifier::IssuerAndSerialNumber(IssuerAndSerialNumber { - issuer: rdn_sequence, + issuer, serial_number: SerialNumber::new(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]) .expect("failed to create a serial number"), }) } fn recipient_identifier(id: i32) -> RecipientIdentifier { - let mut rdn_sequence = RdnSequence::default(); - let rdn = &[AttributeTypeAndValue { - oid: const_oid::db::rfc4519::CN, - value: Any::from(Utf8StringRef::new(&format!("test client {id}")).unwrap()), - }]; - let set_of_vector = SetOfVec::try_from(rdn.to_vec()).unwrap(); - rdn_sequence - .0 - .push(RelativeDistinguishedName::from(set_of_vector)); + let issuer = format!("CN=test client {id}").parse().unwrap(); RecipientIdentifier::IssuerAndSerialNumber(IssuerAndSerialNumber { - issuer: rdn_sequence, + issuer, serial_number: SerialNumber::new(&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]) .expect("failed to create a serial number"), }) diff --git a/x509-cert/src/builder/profile/cabf.rs b/x509-cert/src/builder/profile/cabf.rs index fd9d207dd..d72745587 100644 --- a/x509-cert/src/builder/profile/cabf.rs +++ b/x509-cert/src/builder/profile/cabf.rs @@ -43,7 +43,7 @@ pub fn check_names_encoding(name: &Name, multiple_allowed: bool) -> Result<()> { let mut seen = HashSet::new(); - for rdn in name.0.iter() { + for rdn in name.iter_rdn() { if rdn.0.len() != 1 { return Err(Error::NonUniqueRdn); } @@ -87,13 +87,11 @@ pub fn ca_certificate_naming(subject: &Name) -> Result<()> { check_names_encoding(subject, false)?; - for rdn in subject.0.iter() { - for atv in rdn.0.iter() { - if !allowed.remove(&atv.oid) { - return Err(Error::InvalidAttribute { oid: atv.oid }); - } - required.remove(&atv.oid); + for atv in subject.iter() { + if !allowed.remove(&atv.oid) { + return Err(Error::InvalidAttribute { oid: atv.oid }); } + required.remove(&atv.oid); } if !required.is_empty() { diff --git a/x509-cert/src/builder/profile/cabf/tls.rs b/x509-cert/src/builder/profile/cabf/tls.rs index 87d9a529c..13f885419 100644 --- a/x509-cert/src/builder/profile/cabf/tls.rs +++ b/x509-cert/src/builder/profile/cabf/tls.rs @@ -22,7 +22,7 @@ use crate::{ }, AsExtension, Extension, }, - name::{Name, RelativeDistinguishedName}, + name::{Name, RdnSequence, RelativeDistinguishedName}, }; use spki::SubjectPublicKeyInfoRef; @@ -145,8 +145,7 @@ impl CertificateType { // TODO(baloo): not very happy with all that, might as well throw that in a helper // or something. let rdns: vec::Vec = subject - .0 - .iter() + .iter_rdn() .filter_map(|rdn| { let out = SetOfVec::::from_iter( rdn.0 @@ -161,7 +160,8 @@ impl CertificateType { .filter(|rdn| !rdn.0.is_empty()) .collect(); - let subject: Name = rdns.into(); + let subject: RdnSequence = rdns.into(); + let subject: Name = subject.into(); Ok(Self::DomainValidated(DomainValidated { subject, names })) } diff --git a/x509-cert/src/name.rs b/x509-cert/src/name.rs index c12a25c6d..bd1a1ec8a 100644 --- a/x509-cert/src/name.rs +++ b/x509-cert/src/name.rs @@ -2,8 +2,15 @@ use crate::attr::AttributeTypeAndValue; use alloc::vec::Vec; +use const_oid::{ + db::{rfc3280, rfc4519}, + ObjectIdentifier, +}; use core::{fmt, str::FromStr}; -use der::{asn1::SetOfVec, Encode}; +use der::{ + asn1::{Any, Ia5StringRef, PrintableStringRef, SetOfVec, Utf8StringRef}, + Encode, +}; /// X.501 Name as defined in [RFC 5280 Section 4.1.2.4]. X.501 Name is used to represent distinguished names. /// @@ -11,8 +18,185 @@ use der::{asn1::SetOfVec, Encode}; /// Name ::= CHOICE { rdnSequence RDNSequence } /// ``` /// +/// # Example +/// +/// ``` +/// use std::str::FromStr; +/// use x509_cert::name::Name; +/// +/// let subject = Name::from_str("CN=example.com").expect("correctly formatted subject"); +/// ``` +/// /// [RFC 5280 Section 4.1.2.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.4 -pub type Name = RdnSequence; +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct Name(RdnSequence); + +impl_newtype!(Name, RdnSequence); + +impl Name { + /// Is this [`Name`] empty? + #[inline] + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// Returns the number of [`RelativeDistinguishedName`] elements in this [`Name`]. + pub fn len(&self) -> usize { + self.0 .0.len() + } + + /// Returns an iterator over the inner [`AttributeTypeAndValue`]s. + /// + /// This iterator does not expose which attributes are grouped together as + /// [`RelativeDistinguishedName`]s. If you need this, use [`Self::iter_rdn`]. + #[inline] + pub fn iter(&self) -> impl Iterator + '_ { + self.0 .0.iter().flat_map(move |rdn| rdn.0.as_slice()) + } + + /// Returns an iterator over the inner [`RelativeDistinguishedName`]s. + #[inline] + pub fn iter_rdn(&self) -> impl Iterator + '_ { + self.0 .0.iter() + } +} + +impl Name { + /// Returns the element found in the name identified by `oid` + /// + /// This will return `Ok(None)` if no such element is present. + /// + /// # Errors + /// + /// This will return [`der::Error`] if the content is not serialized as expected or if the more + /// than one attribute with the given oid is present. + pub fn by_oid<'a, T>(&'a self, oid: ObjectIdentifier) -> der::Result> + where + T: TryFrom<&'a Any, Error = der::Error>, + T: fmt::Debug, + { + let mut iter = self + .iter() + .filter(|atav| atav.oid == oid) + .map(|atav| T::try_from(&atav.value)) + .peekable(); + + match iter.next() { + None => Ok(None), + Some(item) => match iter.peek() { + Some(..) => Err(der::Error::from(der::ErrorKind::Failed).into()), + None => Ok(Some(item?)), + }, + } + } + + /// Returns the Common Name (CN) found in the name. + /// + /// This will return `Ok(None)` if no CN is found. + /// + /// # Errors + /// + /// This will return [`der::Error`] if the content is not serialized as an utf8String or if the more + /// than one CN is present + pub fn common_name(&self) -> der::Result>> { + self.by_oid::>(rfc4519::COMMON_NAME) + } + + /// Returns the Country (C) found in the name. + /// + /// This will return `Ok(None)` if no Country is found. + /// + /// # Errors + /// + /// This will return [`der::Error`] if the content is not serialized as a printableString or if the more + /// than one C is present. + pub fn country(&self) -> der::Result>> { + self.by_oid::>(rfc4519::COUNTRY_NAME) + } + + /// Returns the State or Province (ST) found in the name. + /// + /// This will return `Ok(None)` if no State or Province is found. + /// + /// # Errors + /// + /// This will return [`der::Error`] if the content is not serialized as an utf8String or if the more + /// than one ST is present + pub fn state_or_province(&self) -> der::Result>> { + self.by_oid::>(rfc4519::ST) + } + + /// Returns the Locality (L) found in the name. + /// + /// This will return `Ok(None)` if no Locality is found. + /// + /// # Errors + /// + /// This will return [`der::Error`] if the content is not serialized as an utf8String or if the more + /// than one L is present + pub fn locality(&self) -> der::Result>> { + self.by_oid::>(rfc4519::LOCALITY_NAME) + } + + /// Returns the Organization (O) found in the name. + /// + /// This will return `Ok(None)` if no Organization is found. + /// + /// # Errors + /// + /// This will return [`der::Error`] if the content is not serialized as an utf8String or if the more + /// than one O is present + pub fn organization(&self) -> der::Result>> { + self.by_oid::>(rfc4519::ORGANIZATION_NAME) + } + + /// Returns the Organization Unit (OU) found in the name. + /// + /// This will return `Ok(None)` if no Organization Unit is found. + /// + /// # Errors + /// + /// This will return [`der::Error`] if the content is not serialized as an utf8String or if the more + /// than one OU is present + pub fn organization_unit(&self) -> der::Result>> { + self.by_oid::>(rfc4519::ORGANIZATIONAL_UNIT_NAME) + } + + /// Returns the Email Address (emailAddress) found in the name. + /// + /// This will return `Ok(None)` if no email address is found. + /// + /// # Errors + /// + /// This will return [`der::Error`] if the content is not serialized as an ia5String or if the more + /// than one emailAddress is present + pub fn email_address(&self) -> der::Result>> { + self.by_oid::>(rfc3280::EMAIL_ADDRESS) + } +} + +/// Parse a [`Name`] string. +/// +/// Follows the rules in [RFC 4514]. +/// +/// [RFC 4514]: https://datatracker.ietf.org/doc/html/rfc4514 +impl FromStr for Name { + type Err = der::Error; + + fn from_str(s: &str) -> der::Result { + Ok(Self(RdnSequence::from_str(s)?)) + } +} + +/// Serializes the name according to the rules in [RFC 4514]. +/// +/// [RFC 4514]: https://datatracker.ietf.org/doc/html/rfc4514 +impl fmt::Display for Name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} /// X.501 RDNSequence as defined in [RFC 5280 Section 4.1.2.4]. /// diff --git a/x509-cert/tests/certificate.rs b/x509-cert/tests/certificate.rs index 3984f9f03..306b1de05 100644 --- a/x509-cert/tests/certificate.rs +++ b/x509-cert/tests/certificate.rs @@ -238,41 +238,35 @@ fn decode_cert() { .unwrap() .is_null()); - let mut counter = 0; - let i = cert.tbs_certificate.issuer.0.iter(); - for rdn in i { - let i1 = rdn.0.iter(); - for atav in i1 { - if 0 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.6"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "US" - ); - } else if 1 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.10"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "Mock" - ); - } else if 2 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.10"); - assert_eq!( - Utf8StringRef::try_from(&atav.value).unwrap().to_string(), - "IdenTrust Services LLC" - ); - } else if 3 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.3"); - assert_eq!( - Utf8StringRef::try_from(&atav.value).unwrap().to_string(), - "PTE IdenTrust Global Common Root CA 1" - ); - } - counter += 1; + for (counter, atav) in cert.tbs_certificate.issuer.iter().enumerate() { + if 0 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.6"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "US" + ); + } else if 1 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.10"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "Mock" + ); + } else if 2 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.10"); + assert_eq!( + Utf8StringRef::try_from(&atav.value).unwrap().to_string(), + "IdenTrust Services LLC" + ); + } else if 3 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.3"); + assert_eq!( + Utf8StringRef::try_from(&atav.value).unwrap().to_string(), + "PTE IdenTrust Global Common Root CA 1" + ); } } @@ -293,46 +287,40 @@ fn decode_cert() { 1516628593 ); - counter = 0; - let i = cert.tbs_certificate.subject.0.iter(); - for rdn in i { - let i1 = rdn.0.iter(); - for atav in i1 { - // Yes, this cert features RDNs encoded in reverse order - if 0 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.3"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "Test Federal Bridge CA" - ); - } else if 1 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.11"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "TestFPKI" - ); - } else if 2 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.10"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "U.S. Government" - ); - } else if 3 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.6"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "US" - ); - } - counter += 1; + for (counter, atav) in cert.tbs_certificate.subject.iter().enumerate() { + // Yes, this cert features RDNs encoded in reverse order + if 0 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.3"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "Test Federal Bridge CA" + ); + } else if 1 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.11"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "TestFPKI" + ); + } else if 2 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.10"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "U.S. Government" + ); + } else if 3 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.6"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "US" + ); } } diff --git a/x509-cert/tests/certreq.rs b/x509-cert/tests/certreq.rs index 82ce41c53..e1948c61f 100644 --- a/x509-cert/tests/certreq.rs +++ b/x509-cert/tests/certreq.rs @@ -35,8 +35,8 @@ fn decode_rsa_2048_der() { assert_eq!(cr.info.version, Version::V1); // Check all the RDNs. - assert_eq!(cr.info.subject.0.len(), NAMES.len()); - for (name, (oid, val)) in cr.info.subject.0.iter().zip(NAMES) { + assert_eq!(cr.info.subject.len(), NAMES.len()); + for (name, (oid, val)) in cr.info.subject.iter_rdn().zip(NAMES) { let kind = name.0.get(0).unwrap(); let value = match kind.value.tag() { Tag::Utf8String => Utf8StringRef::try_from(&kind.value).unwrap().as_str(), diff --git a/x509-cert/tests/name.rs b/x509-cert/tests/name.rs index 27af2b563..dab07fbdf 100644 --- a/x509-cert/tests/name.rs +++ b/x509-cert/tests/name.rs @@ -33,37 +33,31 @@ fn decode_name() { Name::from_der(&hex!("3040310B3009060355040613025553311F301D060355040A1316546573742043657274696669636174657320323031313110300E06035504031307476F6F64204341")[..]); let rdn1a = rdn1.unwrap(); - let mut counter = 0; - let i = rdn1a.0.iter(); - for rdn in i { - let i1 = rdn.0.iter(); - for atav in i1 { - if 0 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.6"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "US" - ); - } else if 1 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.10"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "Test Certificates 2011" - ); - } else if 2 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.3"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "Good CA" - ); - } - counter += 1; + for (counter, atav) in rdn1a.iter().enumerate() { + if 0 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.6"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "US" + ); + } else if 1 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.10"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "Test Certificates 2011" + ); + } else if 2 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.3"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "Good CA" + ); } } @@ -368,3 +362,53 @@ fn rdns_serde() { } } } + +#[cfg(feature = "std")] +#[test] +fn access_attributes() { + use std::str::FromStr; + + let name = Name::from_str("emailAddress=foo@example.com,UID=identity:ds.group.3891111,OU=management:ds.group.3891111,CN=OQFAvDNDWs.google.com,O=Google LLC,L=Mountain View,ST=California,C=US").unwrap(); + + assert_eq!( + <_ as AsRef>::as_ref(&name.common_name().unwrap().unwrap()), + "OQFAvDNDWs.google.com" + ); + + assert_eq!( + <_ as AsRef>::as_ref(&name.country().unwrap().unwrap()), + "US" + ); + + assert_eq!( + <_ as AsRef>::as_ref(&name.state_or_province().unwrap().unwrap()), + "California" + ); + + assert_eq!( + <_ as AsRef>::as_ref(&name.locality().unwrap().unwrap()), + "Mountain View" + ); + + assert_eq!( + <_ as AsRef>::as_ref(&name.organization().unwrap().unwrap()), + "Google LLC" + ); + + assert_eq!( + <_ as AsRef>::as_ref(&name.organization_unit().unwrap().unwrap()), + "management:ds.group.3891111" + ); + + assert_eq!( + <_ as AsRef>::as_ref(&name.email_address().unwrap().unwrap()), + "foo@example.com" + ); + + let name = Name::from_str("C=DE,C=US").unwrap(); + + assert!( + name.country().is_err(), + "if more than one attribute is present, we expect an error" + ); +} diff --git a/x509-cert/tests/pkix_extensions.rs b/x509-cert/tests/pkix_extensions.rs index 9d9973a0a..0038ccf80 100644 --- a/x509-cert/tests/pkix_extensions.rs +++ b/x509-cert/tests/pkix_extensions.rs @@ -580,37 +580,31 @@ fn decode_cert() { true ); - let mut counter = 0; - let i = cert.tbs_certificate.issuer.0.iter(); - for rdn in i { - let i1 = rdn.0.iter(); - for atav in i1 { - if 0 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.6"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "US" - ); - } else if 1 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.10"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "Test Certificates 2011" - ); - } else if 2 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.3"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "Trust Anchor" - ); - } - counter += 1; + for (counter, atav) in cert.tbs_certificate.issuer.iter().enumerate() { + if 0 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.6"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "US" + ); + } else if 1 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.10"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "Test Certificates 2011" + ); + } else if 2 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.3"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "Trust Anchor" + ); } } @@ -631,37 +625,31 @@ fn decode_cert() { 1924936200 ); - counter = 0; - let i = cert.tbs_certificate.subject.0.iter(); - for rdn in i { - let i1 = rdn.0.iter(); - for atav in i1 { - if 0 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.6"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "US" - ); - } else if 1 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.10"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "Test Certificates 2011" - ); - } else if 2 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.3"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "Good CA" - ); - } - counter += 1; + for (counter, atav) in cert.tbs_certificate.subject.iter().enumerate() { + if 0 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.6"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "US" + ); + } else if 1 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.10"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "Test Certificates 2011" + ); + } else if 2 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.3"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "Good CA" + ); } } @@ -696,10 +684,8 @@ fn decode_cert() { // TODO - parse and compare public key - counter = 0; let exts = cert.tbs_certificate.extensions.unwrap(); - let i = exts.iter(); - for ext in i { + for (counter, ext) in exts.iter().enumerate() { if 0 == counter { assert_eq!( ext.extn_id.to_string(), @@ -746,8 +732,6 @@ fn decode_cert() { assert_eq!(bc.ca, true); assert_eq!(bc.path_len_constraint, Option::None); } - - counter += 1; } assert_eq!( cert.signature_algorithm.oid.to_string(), @@ -858,19 +842,19 @@ fn decode_idp() { let n = Name::from_der(&hex!("305A310B3009060355040613025553311F301D060355040A131654657374204365727469666963617465732032303137311C301A060355040B13136F6E6C79536F6D65526561736F6E7320434133310C300A0603550403130343524C")).unwrap(); - assert_eq!(4, n.0.len()); + assert_eq!(4, n.as_ref().0.len()); let gn = GeneralName::from_der(&hex!("A45C305A310B3009060355040613025553311F301D060355040A131654657374204365727469666963617465732032303137311C301A060355040B13136F6E6C79536F6D65526561736F6E7320434133310C300A0603550403130343524C")).unwrap(); if let GeneralName::DirectoryName(gn) = gn { - assert_eq!(4, gn.0.len()); + assert_eq!(4, gn.as_ref().0.len()); } let gns = GeneralNames::from_der(&hex!("305EA45C305A310B3009060355040613025553311F301D060355040A131654657374204365727469666963617465732032303137311C301A060355040B13136F6E6C79536F6D65526561736F6E7320434133310C300A0603550403130343524C")).unwrap(); assert_eq!(1, gns.len()); if let GeneralName::DirectoryName(gn) = gns.first().unwrap() { - assert_eq!(4, gn.0.len()); + assert_eq!(4, gn.as_ref().0.len()); } //TODO - fix decode impl (expecting a SEQUENCE despite this being a CHOICE). Sort out FixedTag implementation. @@ -895,7 +879,7 @@ fn decode_idp() { if let DistributionPointName::FullName(dpn) = dp.distribution_point.unwrap() { assert_eq!(1, dpn.len()); if let GeneralName::DirectoryName(gn) = dpn.first().unwrap() { - assert_eq!(4, gn.0.len()); + assert_eq!(4, gn.as_ref().0.len()); } } @@ -1073,7 +1057,7 @@ fn decode_idp() { for gn in dp { match gn { GeneralName::DirectoryName(gn) => { - assert_eq!(4, gn.0.len()); + assert_eq!(4, gn.as_ref().0.len()); } _ => { panic!("Expected DirectoryName") @@ -1102,7 +1086,7 @@ fn decode_idp() { for gn in dp { match gn { GeneralName::DirectoryName(gn) => { - assert_eq!(4, gn.0.len()); + assert_eq!(4, gn.as_ref().0.len()); } _ => { panic!("Expected DirectoryName") diff --git a/x509-cert/tests/trust_anchor_format.rs b/x509-cert/tests/trust_anchor_format.rs index 0b0c53aef..405d3b3ee 100644 --- a/x509-cert/tests/trust_anchor_format.rs +++ b/x509-cert/tests/trust_anchor_format.rs @@ -81,53 +81,44 @@ fn decode_ta1() { ]; 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.0.iter(); - for ext in i { + for (counter, ext) in exts.0.iter().enumerate() { assert_eq!(policy_ids[counter], ext.policy_identifier.to_string()); - counter += 1; } - counter = 0; - let i = cert_path.ta_name.0.iter(); - for rdn in i { - let i1 = rdn.0.iter(); - for atav in i1 { - if 0 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.6"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "US" - ); - } else if 1 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.10"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "U.S. Government" - ); - } else if 2 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.11"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "ECA" - ); - } else if 3 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.3"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "ECA Root CA 4" - ); - } - counter += 1; + for (counter, atav) in cert_path.ta_name.iter().enumerate() { + if 0 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.6"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "US" + ); + } else if 1 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.10"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "U.S. Government" + ); + } else if 2 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.11"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "ECA" + ); + } else if 3 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.3"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "ECA Root CA 4" + ); } } @@ -166,84 +157,72 @@ fn decode_ta2() { let cert_path = tai.cert_path.as_ref().unwrap(); - let mut counter = 0; - let i = cert_path.ta_name.0.iter(); - for rdn in i { - let i1 = rdn.0.iter(); - for atav in i1 { - if 0 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.6"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "US" - ); - } else if 1 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.10"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "Entrust" - ); - } else if 2 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.11"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "Certification Authorities" - ); - } else if 3 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.11"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "Entrust Managed Services NFI Root CA" - ); - } - counter += 1; + for (counter, atav) in cert_path.ta_name.iter().enumerate() { + if 0 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.6"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "US" + ); + } else if 1 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.10"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "Entrust" + ); + } else if 2 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.11"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "Certification Authorities" + ); + } else if 3 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.11"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "Entrust Managed Services NFI Root CA" + ); } } 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.0.iter(); - for rdn in i { - let i1 = rdn.0.iter(); - for atav in i1 { - if 0 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.6"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "US" - ); - } else if 1 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.10"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "U.S. Government" - ); - } else if 2 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.11"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "DoD" - ); - } - counter += 1; + for (counter, atav) in dn.iter().enumerate() { + if 0 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.6"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "US" + ); + } else if 1 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.10"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "U.S. Government" + ); + } else if 2 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.11"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "DoD" + ); } } } @@ -293,84 +272,72 @@ fn decode_ta3() { cert_path.policy_flags.unwrap() ); - let mut counter = 0; - let i = cert_path.ta_name.0.iter(); - for rdn in i { - let i1 = rdn.0.iter(); - for atav in i1 { - if 0 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.6"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "US" - ); - } else if 1 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.10"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "Exostar LLC" - ); - } else if 2 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.11"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "Certification Authorities" - ); - } else if 3 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.3"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "Exostar Federated Identity Service Root CA 1" - ); - } - counter += 1; + for (counter, atav) in cert_path.ta_name.iter().enumerate() { + if 0 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.6"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "US" + ); + } else if 1 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.10"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "Exostar LLC" + ); + } else if 2 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.11"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "Certification Authorities" + ); + } else if 3 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.3"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "Exostar Federated Identity Service Root CA 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.0.iter(); - for rdn in i { - let i1 = rdn.0.iter(); - for atav in i1 { - if 0 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.6"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "US" - ); - } else if 1 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.10"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "U.S. Government" - ); - } else if 2 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.11"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "DoD" - ); - } - counter += 1; + for (counter, atav) in dn.iter().enumerate() { + if 0 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.6"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "US" + ); + } else if 1 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.10"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "U.S. Government" + ); + } else if 2 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.11"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "DoD" + ); } } } @@ -413,41 +380,35 @@ fn decode_ta4() { let cert_path = tai.cert_path.as_ref().unwrap(); - let mut counter = 0; - let i = cert_path.ta_name.0.iter(); - for rdn in i { - let i1 = rdn.0.iter(); - for atav in i1 { - if 0 == counter { - assert_eq!(atav.oid.to_string(), "0.9.2342.19200300.100.1.25"); - assert_eq!( - Ia5StringRef::try_from(&atav.value).unwrap().to_string(), - "com" - ); - } else if 1 == counter { - assert_eq!(atav.oid.to_string(), "0.9.2342.19200300.100.1.25"); - assert_eq!( - Ia5StringRef::try_from(&atav.value).unwrap().to_string(), - "raytheon" - ); - } else if 2 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.10"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "CAs" - ); - } else if 3 == counter { - assert_eq!(atav.oid.to_string(), "2.5.4.11"); - assert_eq!( - PrintableStringRef::try_from(&atav.value) - .unwrap() - .to_string(), - "RaytheonRoot" - ); - } - counter += 1; + for (counter, atav) in cert_path.ta_name.iter().enumerate() { + if 0 == counter { + assert_eq!(atav.oid.to_string(), "0.9.2342.19200300.100.1.25"); + assert_eq!( + Ia5StringRef::try_from(&atav.value).unwrap().to_string(), + "com" + ); + } else if 1 == counter { + assert_eq!(atav.oid.to_string(), "0.9.2342.19200300.100.1.25"); + assert_eq!( + Ia5StringRef::try_from(&atav.value).unwrap().to_string(), + "raytheon" + ); + } else if 2 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.10"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "CAs" + ); + } else if 3 == counter { + assert_eq!(atav.oid.to_string(), "2.5.4.11"); + assert_eq!( + PrintableStringRef::try_from(&atav.value) + .unwrap() + .to_string(), + "RaytheonRoot" + ); } }