x509_cert/ext/pkix/name/dirstr.rs
1use alloc::borrow::Cow;
2use alloc::string::String;
3use alloc::string::ToString;
4use der::{
5 Choice, ValueOrd,
6 asn1::{Any, BmpString, PrintableString, TeletexString},
7};
8
9/// DirectoryString as defined in [RFC 5280 Section 4.2.1.4].
10///
11/// ASN.1 structure for DirectoryString is below.
12///
13/// ```text
14/// DirectoryString ::= CHOICE {
15/// teletexString TeletexString (SIZE (1..MAX)),
16/// printableString PrintableString (SIZE (1..MAX)),
17/// universalString UniversalString (SIZE (1..MAX)),
18/// utf8String UTF8String (SIZE (1..MAX)),
19/// bmpString BMPString (SIZE (1..MAX))
20/// }
21/// ```
22///
23/// Further, [RFC 5280 Section 4.2.1.4] states:
24///
25/// ```text
26/// The DirectoryString type is defined as a choice of PrintableString,
27/// TeletexString, BMPString, UTF8String, and UniversalString. CAs
28/// conforming to this profile MUST use either the PrintableString or
29/// UTF8String encoding of DirectoryString, with two exceptions. When
30/// CAs have previously issued certificates with issuer fields with
31/// attributes encoded using TeletexString, BMPString, or
32/// UniversalString, then the CA MAY continue to use these encodings of
33/// the DirectoryString to preserve backward compatibility. Also, new
34/// CAs that are added to a domain where existing CAs issue certificates
35/// with issuer fields with attributes encoded using TeletexString,
36/// BMPString, or UniversalString MAY encode attributes that they share
37/// with the existing CAs using the same encodings as the existing CAs
38/// use.
39/// ```
40///
41/// The implication of the above paragraph is that `PrintableString` and
42/// `UTF8String` are the new types and the other types are legacy. Until
43/// the need arises, we only support `PrintableString` and `UTF8String`.
44///
45/// [RFC 5280 Section 4.2.1.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.4
46#[derive(Clone, Debug, Eq, PartialEq, Choice, ValueOrd)]
47#[allow(missing_docs)]
48pub enum DirectoryString {
49 #[asn1(type = "PrintableString")]
50 PrintableString(PrintableString),
51
52 #[asn1(type = "TeletexString")]
53 TeletexString(TeletexString),
54
55 #[asn1(type = "UTF8String")]
56 Utf8String(String),
57
58 #[asn1(type = "BMPString")]
59 BmpString(BmpString),
60}
61
62impl<'a> TryFrom<&'a Any> for DirectoryString {
63 type Error = der::Error;
64 fn try_from(any: &'a Any) -> der::Result<Self> {
65 any.decode_as()
66 }
67}
68
69impl DirectoryString {
70 /// Returns `Borrowed` variant for UTF-8 compatible strings
71 /// and `Owned` variant otherwise.
72 pub fn value(&self) -> Cow<'_, str> {
73 match self {
74 Self::PrintableString(s) => Cow::Borrowed(s.as_ref()),
75 Self::TeletexString(s) => Cow::Borrowed(s.as_ref()),
76 Self::Utf8String(s) => Cow::Borrowed(s.as_ref()),
77 Self::BmpString(s) => Cow::Owned(s.to_string()),
78 }
79 }
80
81 /// Returns `&str` for `PrintableString`, `TeletexString` and `Utf8String`
82 ///
83 /// Warning: Returns `""` empty string for [`DirectoryString::BmpString`] variant
84 #[deprecated(since = "0.3.0-pre.0", note = "use `DirectoryString::value` instead")]
85 #[allow(clippy::should_implement_trait)]
86 pub fn as_ref(&self) -> &str {
87 match self {
88 Self::PrintableString(s) => s.as_ref(),
89 Self::TeletexString(s) => s.as_ref(),
90 Self::Utf8String(s) => s.as_ref(),
91 // BMPString is not str-compatible
92 Self::BmpString(_s) => "",
93 }
94 }
95}
96
97impl From<DirectoryString> for String {
98 fn from(value: DirectoryString) -> Self {
99 value.value().into_owned()
100 }
101}