From f987ab749ffd9a77e10f69cf7efeb2c8ae2b5636 Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Fri, 2 May 2025 21:50:03 +0200 Subject: [PATCH 1/3] x509-cert: add `DirectoryString::BmpString` x509-cert: use alloc instead of std x509-cert: apply clippy Cow<'_, str> x509-cert: fix test decode_cert_bmpstring --- x509-cert/src/ext/pkix/name/dirstr.rs | 23 ++++++++++++++++++- x509-cert/tests/certificate.rs | 15 ++++++++++++ .../tests/examples/windows_bmpstring.pem | 20 ++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 x509-cert/tests/examples/windows_bmpstring.pem diff --git a/x509-cert/src/ext/pkix/name/dirstr.rs b/x509-cert/src/ext/pkix/name/dirstr.rs index 045cb19cc..045e9cf2c 100644 --- a/x509-cert/src/ext/pkix/name/dirstr.rs +++ b/x509-cert/src/ext/pkix/name/dirstr.rs @@ -1,7 +1,9 @@ +use alloc::borrow::Cow; use alloc::string::String; +use alloc::string::ToString; use der::{ Choice, FixedTag, Header, Reader, ValueOrd, - asn1::{Any, PrintableString, TeletexString}, + asn1::{Any, BmpString, PrintableString, TeletexString}, }; /// DirectoryString as defined in [RFC 5280 Section 4.2.1.4]. @@ -52,6 +54,9 @@ pub enum DirectoryString { #[asn1(type = "UTF8String")] Utf8String(String), + + #[asn1(type = "BMPString")] + BmpString(BmpString), } impl<'a> TryFrom<&'a Any> for DirectoryString { @@ -73,6 +78,7 @@ impl<'a> der::DecodeValue<'a> for DirectoryString { TeletexString::decode_value(reader, header).map(Self::TeletexString) } String::TAG => String::decode_value(reader, header).map(Self::Utf8String), + BmpString::TAG => BmpString::decode_value(reader, header).map(Self::BmpString), actual => Err(der::ErrorKind::TagUnexpected { expected: None, actual, @@ -81,13 +87,28 @@ impl<'a> der::DecodeValue<'a> for DirectoryString { } } } +impl DirectoryString { + /// Returns `Borrowed` variant for UTF-8 compatible strings + /// and `Owned` variant otherwise. + pub fn value(&self) -> Cow<'_, str> { + match self { + Self::PrintableString(s) => Cow::Borrowed(s.as_ref()), + Self::TeletexString(s) => Cow::Borrowed(s.as_ref()), + Self::Utf8String(s) => Cow::Borrowed(s.as_ref()), + Self::BmpString(s) => Cow::Owned(s.to_string()), + } + } +} impl AsRef for DirectoryString { + // #[deprecated(since = "0.3.0-pre.0", note = "use `DirectoryString::value` instead")] fn as_ref(&self) -> &str { match self { Self::PrintableString(s) => s.as_ref(), Self::TeletexString(s) => s.as_ref(), Self::Utf8String(s) => s.as_ref(), + // TODO(dishmaker): BMPString as ref + Self::BmpString(_s) => "", } } } diff --git a/x509-cert/tests/certificate.rs b/x509-cert/tests/certificate.rs index bd4c73b9b..417286628 100644 --- a/x509-cert/tests/certificate.rs +++ b/x509-cert/tests/certificate.rs @@ -468,3 +468,18 @@ fn certificate_arbitrary() { check_arbitrary(certificate); } } + +#[cfg(feature = "pem")] +#[test] +fn decode_cert_bmpstring() { + let der_encoded_cert = include_bytes!("examples/windows_bmpstring.pem"); + let result = Certificate::from_pem(der_encoded_cert); + let cert: Certificate = result.unwrap(); + + let common_name = cert.tbs_certificate().issuer().common_name().unwrap(); + + assert_eq!( + common_name.unwrap().value(), + "WDKTestCert 混沌,133906716390833193" + ); +} diff --git a/x509-cert/tests/examples/windows_bmpstring.pem b/x509-cert/tests/examples/windows_bmpstring.pem new file mode 100644 index 000000000..a29c4cb4f --- /dev/null +++ b/x509-cert/tests/examples/windows_bmpstring.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDSDCCAjCgAwIBAgIQKPABcjfrcIpG1K6NEhSpIjANBgkqhkiG9w0BAQUFADBN +MUswSQYDVQQDHkIAVwBEAEsAVABlAHMAdABDAGUAcgB0ACBt92yMACwAMQAzADMA +OQAwADYANwAxADYAMwA5ADAAOAAzADMAMQA5ADMwHhcNMjUwNTAyMTUwMDM5WhcN +MzUwNTAyMDAwMDAwWjBNMUswSQYDVQQDHkIAVwBEAEsAVABlAHMAdABDAGUAcgB0 +ACBt92yMACwAMQAzADMAOQAwADYANwAxADYAMwA5ADAAOAAzADMAMQA5ADMwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDlgz7PDdlf6UzTtcWMRpaGGCdg +KYQOBOJWg6lnTQMxALfWD2bzVrbLM8N2HlMUi1AhDmr3EX6xgFi3gdXB9DgZKwEB +C1yq9CtU3QEyb/BKdsSaBasZPwfNEak8shAacvi0ssDhd05CIPYpvAlyO1RP1+m9 +g3LaHaTYnlPM1PYGr3yJ8qMprGsMepgrLf1AlHQRhWyEml5C0s/1WaflYo/NJnBy +thyxksCEM2+AeO8A6CtwkL1yL47i6WImqk68NbeDiYalGwFt1Nb1Yd8PVbE7FT36 +4vdMJ7jdQxzsCDiIq+KORZGSF/nVVpDeWRy8W0YtcfQ0LRbpIdEpRJOpK2UZAgMB +AAGjJDAiMAsGA1UdDwQEAwIEMDATBgNVHSUEDDAKBggrBgEFBQcDAzANBgkqhkiG +9w0BAQUFAAOCAQEAycUVQ5SKUGsdQL5hkvJchs5I43/zEfEHRaT75lYlMn2lAMsa +qX4vDBanWs0no9+0/7j0hPRBamNZGFThE6MswXcYdJrxhfp0ZjHntK0IMWO8riVO +Y6O/4xHF8rUPQkOBFIcRBF19Ads2Qdfgtjzc+288YRCLiZ4TmWjYlg9TVst7x/Fo +Hl1xH2Nbvm8AYPX9iPoqEzbq9aPy2MWi9Pf+R0lfqAjsdvj85A4dZKD2ovjOYzPX +PBSJQizmCHjovucot2iB5MumoSGloHbIFZl2fe/2jqDjPwX4wDoYO94kenlhxedo +lX4Tf6VRXWA0hVpJiE7NQMaVtO6rO/5P0pE1Pg== +-----END CERTIFICATE----- \ No newline at end of file From 611057e87c6d513b365e299a4b6c860cc3462b44 Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Sun, 4 May 2025 04:59:14 +0200 Subject: [PATCH 2/3] x509-cert: remove `DirectoryString::as_ref` --- x509-cert/src/ext/pkix/name/dirstr.rs | 13 ------------- x509-cert/tests/name.rs | 16 +++++----------- 2 files changed, 5 insertions(+), 24 deletions(-) diff --git a/x509-cert/src/ext/pkix/name/dirstr.rs b/x509-cert/src/ext/pkix/name/dirstr.rs index 045e9cf2c..2f57b6f8f 100644 --- a/x509-cert/src/ext/pkix/name/dirstr.rs +++ b/x509-cert/src/ext/pkix/name/dirstr.rs @@ -99,16 +99,3 @@ impl DirectoryString { } } } - -impl AsRef for DirectoryString { - // #[deprecated(since = "0.3.0-pre.0", note = "use `DirectoryString::value` instead")] - fn as_ref(&self) -> &str { - match self { - Self::PrintableString(s) => s.as_ref(), - Self::TeletexString(s) => s.as_ref(), - Self::Utf8String(s) => s.as_ref(), - // TODO(dishmaker): BMPString as ref - Self::BmpString(_s) => "", - } - } -} diff --git a/x509-cert/tests/name.rs b/x509-cert/tests/name.rs index f8eba5784..a4eb6b474 100644 --- a/x509-cert/tests/name.rs +++ b/x509-cert/tests/name.rs @@ -381,7 +381,7 @@ fn access_attributes() { 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()), + name.common_name().unwrap().unwrap().value(), "OQFAvDNDWs.google.com" ); @@ -391,22 +391,16 @@ fn access_attributes() { ); assert_eq!( - <_ as AsRef>::as_ref(&name.state_or_province().unwrap().unwrap()), + name.state_or_province().unwrap().unwrap().value(), "California" ); - assert_eq!( - <_ as AsRef>::as_ref(&name.locality().unwrap().unwrap()), - "Mountain View" - ); + assert_eq!(name.locality().unwrap().unwrap().value(), "Mountain View"); - assert_eq!( - <_ as AsRef>::as_ref(&name.organization().unwrap().unwrap()), - "Google LLC" - ); + assert_eq!(name.organization().unwrap().unwrap().value(), "Google LLC"); assert_eq!( - <_ as AsRef>::as_ref(&name.organization_unit().unwrap().unwrap()), + name.organization_unit().unwrap().unwrap().value(), "management:ds.group.3891111" ); From a0fb1e478a8fa819984ed741b5d52850f136dab4 Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Tue, 6 May 2025 14:36:02 +0200 Subject: [PATCH 3/3] x509-cert: add deprecated `as_ref` and `From for String` --- x509-cert/src/ext/pkix/name/dirstr.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/x509-cert/src/ext/pkix/name/dirstr.rs b/x509-cert/src/ext/pkix/name/dirstr.rs index 2f57b6f8f..385cdc5e7 100644 --- a/x509-cert/src/ext/pkix/name/dirstr.rs +++ b/x509-cert/src/ext/pkix/name/dirstr.rs @@ -98,4 +98,25 @@ impl DirectoryString { Self::BmpString(s) => Cow::Owned(s.to_string()), } } + + /// Returns `&str` for `PrintableString`, `TeletexString` and `Utf8String` + /// + /// Warning: Returns `""` empty string for [`DirectoryString::BmpString`] variant + #[deprecated(since = "0.3.0-pre.0", note = "use `DirectoryString::value` instead")] + #[allow(clippy::should_implement_trait)] + pub fn as_ref(&self) -> &str { + match self { + Self::PrintableString(s) => s.as_ref(), + Self::TeletexString(s) => s.as_ref(), + Self::Utf8String(s) => s.as_ref(), + // BMPString is not str-compatible + Self::BmpString(_s) => "", + } + } +} + +impl From for String { + fn from(value: DirectoryString) -> Self { + value.value().into_owned() + } }