x509_cert/
name.rs

1//! Name-related definitions as defined in X.501 (and updated by RFC 5280).
2
3use crate::attr::AttributeTypeAndValue;
4use alloc::vec::Vec;
5use core::{fmt, str::FromStr};
6use der::{asn1::SetOfVec, Encode};
7
8/// X.501 Name as defined in [RFC 5280 Section 4.1.2.4]. X.501 Name is used to represent distinguished names.
9///
10/// ```text
11/// Name ::= CHOICE { rdnSequence  RDNSequence }
12/// ```
13///
14/// [RFC 5280 Section 4.1.2.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.4
15pub type Name = RdnSequence;
16
17/// X.501 RDNSequence as defined in [RFC 5280 Section 4.1.2.4].
18///
19/// ```text
20/// RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
21/// ```
22///
23/// [RFC 5280 Section 4.1.2.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.4
24#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
25#[derive(Clone, Debug, Default, PartialEq, Eq)]
26pub struct RdnSequence(pub Vec<RelativeDistinguishedName>);
27
28impl RdnSequence {
29    /// Converts an `RDNSequence` string into an encoded `RDNSequence`.
30    #[deprecated(since = "0.2.1", note = "use RdnSequence::from_str(...)?.to_der()")]
31    pub fn encode_from_string(s: &str) -> Result<Vec<u8>, der::Error> {
32        Self::from_str(s)?.to_der()
33    }
34
35    /// Is this [`RdnSequence`] empty?
36    pub fn is_empty(&self) -> bool {
37        self.0.is_empty()
38    }
39}
40
41/// Parse an [`RdnSequence`] string.
42///
43/// Follows the rules in [RFC 4514].
44///
45/// [RFC 4514]: https://datatracker.ietf.org/doc/html/rfc4514
46impl FromStr for RdnSequence {
47    type Err = der::Error;
48
49    fn from_str(s: &str) -> der::Result<Self> {
50        let mut parts = split(s, b',')
51            .map(RelativeDistinguishedName::from_str)
52            .collect::<der::Result<Vec<_>>>()?;
53        parts.reverse();
54        Ok(Self(parts))
55    }
56}
57
58/// Serializes the structure according to the rules in [RFC 4514].
59///
60/// [RFC 4514]: https://datatracker.ietf.org/doc/html/rfc4514
61impl fmt::Display for RdnSequence {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63        // As per RFC 4514 Section 2.1, the elements are reversed
64        for (i, atv) in self.0.iter().rev().enumerate() {
65            match i {
66                0 => write!(f, "{}", atv)?,
67                _ => write!(f, ",{}", atv)?,
68            }
69        }
70
71        Ok(())
72    }
73}
74
75impl_newtype!(RdnSequence, Vec<RelativeDistinguishedName>);
76
77/// Find the indices of all non-escaped separators.
78fn find(s: &str, b: u8) -> impl '_ + Iterator<Item = usize> {
79    (0..s.len())
80        .filter(move |i| s.as_bytes()[*i] == b)
81        .filter(|i| {
82            let x = i
83                .checked_sub(2)
84                .map(|i| s.as_bytes()[i])
85                .unwrap_or_default();
86
87            let y = i
88                .checked_sub(1)
89                .map(|i| s.as_bytes()[i])
90                .unwrap_or_default();
91
92            y != b'\\' || x == b'\\'
93        })
94}
95
96/// Split a string at all non-escaped separators.
97fn split(s: &str, b: u8) -> impl '_ + Iterator<Item = &'_ str> {
98    let mut prev = 0;
99    find(s, b).chain([s.len()]).map(move |i| {
100        let x = &s[prev..i];
101        prev = i + 1;
102        x
103    })
104}
105
106/// X.501 DistinguishedName as defined in [RFC 5280 Section 4.1.2.4].
107///
108/// ```text
109/// DistinguishedName ::=   RDNSequence
110/// ```
111///
112/// [RFC 5280 Section 4.1.2.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.4
113pub type DistinguishedName = RdnSequence;
114
115/// RelativeDistinguishedName as defined in [RFC 5280 Section 4.1.2.4].
116///
117/// ```text
118/// RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
119/// ```
120///
121/// Note that we follow the more common definition above. This technically
122/// differs from the definition in X.501, which is:
123///
124/// ```text
125/// RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndDistinguishedValue
126///
127/// AttributeTypeAndDistinguishedValue ::= SEQUENCE {
128///     type ATTRIBUTE.&id ({SupportedAttributes}),
129///     value ATTRIBUTE.&Type({SupportedAttributes}{@type}),
130///     primaryDistinguished BOOLEAN DEFAULT TRUE,
131///     valuesWithContext SET SIZE (1..MAX) OF SEQUENCE {
132///         distingAttrValue [0] ATTRIBUTE.&Type ({SupportedAttributes}{@type}) OPTIONAL,
133///         contextList SET SIZE (1..MAX) OF Context
134///     } OPTIONAL
135/// }
136/// ```
137///
138/// [RFC 5280 Section 4.1.2.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.4
139#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
140#[derive(Clone, Debug, Default, PartialEq, Eq)]
141pub struct RelativeDistinguishedName(pub SetOfVec<AttributeTypeAndValue>);
142
143impl RelativeDistinguishedName {
144    /// Converts an RelativeDistinguishedName string into an encoded RelativeDistinguishedName
145    #[deprecated(
146        since = "0.2.1",
147        note = "use RelativeDistinguishedName::from_str(...)?.to_der()"
148    )]
149    pub fn encode_from_string(s: &str) -> Result<Vec<u8>, der::Error> {
150        Self::from_str(s)?.to_der()
151    }
152}
153
154/// Parse a [`RelativeDistinguishedName`] string.
155///
156/// This function follows the rules in [RFC 4514].
157///
158/// [RFC 4514]: https://datatracker.ietf.org/doc/html/rfc4514
159impl FromStr for RelativeDistinguishedName {
160    type Err = der::Error;
161
162    fn from_str(s: &str) -> der::Result<Self> {
163        split(s, b'+')
164            .map(AttributeTypeAndValue::from_str)
165            .collect::<der::Result<Vec<_>>>()?
166            .try_into()
167            .map(Self)
168    }
169}
170
171impl TryFrom<Vec<AttributeTypeAndValue>> for RelativeDistinguishedName {
172    type Error = der::Error;
173
174    fn try_from(vec: Vec<AttributeTypeAndValue>) -> der::Result<RelativeDistinguishedName> {
175        Ok(RelativeDistinguishedName(SetOfVec::try_from(vec)?))
176    }
177}
178
179/// Serializes the structure according to the rules in [RFC 4514].
180///
181/// [RFC 4514]: https://datatracker.ietf.org/doc/html/rfc4514
182impl fmt::Display for RelativeDistinguishedName {
183    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184        for (i, atv) in self.0.iter().enumerate() {
185            match i {
186                0 => write!(f, "{}", atv)?,
187                _ => write!(f, "+{}", atv)?,
188            }
189        }
190
191        Ok(())
192    }
193}
194
195impl_newtype!(RelativeDistinguishedName, SetOfVec<AttributeTypeAndValue>);