| //! Name-related definitions as defined in X.501 (and updated by RFC 5280). |
| |
| use crate::attr::AttributeTypeAndValue; |
| use alloc::vec::Vec; |
| use core::fmt; |
| use der::{asn1::SetOfVec, Decode, Encode}; |
| |
| /// X.501 Name as defined in [RFC 5280 Section 4.1.2.4]. X.501 Name is used to represent distinguished names. |
| /// |
| /// ```text |
| /// Name ::= CHOICE { rdnSequence RDNSequence } |
| /// ``` |
| /// |
| /// [RFC 5280 Section 4.1.2.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.4 |
| pub type Name<'a> = RdnSequence<'a>; |
| |
| /// X.501 RDNSequence as defined in [RFC 5280 Section 4.1.2.4]. |
| /// |
| /// ```text |
| /// RDNSequence ::= SEQUENCE OF RelativeDistinguishedName |
| /// ``` |
| /// |
| /// [RFC 5280 Section 4.1.2.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.4 |
| #[derive(Clone, Debug, Default, PartialEq, Eq)] |
| pub struct RdnSequence<'a>(pub Vec<RelativeDistinguishedName<'a>>); |
| |
| impl RdnSequence<'_> { |
| /// Converts an RDNSequence string into an encoded RDNSequence |
| /// |
| /// This function follows the rules in [RFC 4514]. |
| /// |
| /// [RFC 4514]: https://datatracker.ietf.org/doc/html/rfc4514 |
| pub fn encode_from_string(s: &str) -> Result<Vec<u8>, der::Error> { |
| let ders = split(s, b',') |
| .map(RelativeDistinguishedName::encode_from_string) |
| .collect::<Result<Vec<_>, der::Error>>()?; |
| |
| let mut out = Vec::new(); |
| for der in ders.iter() { |
| out.push(RelativeDistinguishedName::from_der(der)?); |
| } |
| |
| RdnSequence(out).to_vec() |
| } |
| } |
| |
| /// Serializes the structure according to the rules in [RFC 4514]. |
| /// |
| /// [RFC 4514]: https://datatracker.ietf.org/doc/html/rfc4514 |
| impl fmt::Display for RdnSequence<'_> { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| for (i, atv) in self.0.iter().enumerate() { |
| match i { |
| 0 => write!(f, "{}", atv)?, |
| _ => write!(f, ",{}", atv)?, |
| } |
| } |
| |
| Ok(()) |
| } |
| } |
| |
| impl_newtype!(RdnSequence<'a>, Vec<RelativeDistinguishedName<'a>>); |
| |
| /// Find the indices of all non-escaped separators. |
| fn find(s: &str, b: u8) -> impl '_ + Iterator<Item = usize> { |
| (0..s.len()) |
| .filter(move |i| s.as_bytes()[*i] == b) |
| .filter(|i| { |
| let x = i |
| .checked_sub(2) |
| .map(|i| s.as_bytes()[i]) |
| .unwrap_or_default(); |
| |
| let y = i |
| .checked_sub(1) |
| .map(|i| s.as_bytes()[i]) |
| .unwrap_or_default(); |
| |
| y != b'\\' || x == b'\\' |
| }) |
| } |
| |
| /// Split a string at all non-escaped separators. |
| fn split(s: &str, b: u8) -> impl '_ + Iterator<Item = &'_ str> { |
| let mut prev = 0; |
| find(s, b).chain([s.len()].into_iter()).map(move |i| { |
| let x = &s[prev..i]; |
| prev = i + 1; |
| x |
| }) |
| } |
| |
| /// X.501 DistinguishedName as defined in [RFC 5280 Section 4.1.2.4]. |
| /// |
| /// ```text |
| /// DistinguishedName ::= RDNSequence |
| /// ``` |
| /// |
| /// [RFC 5280 Section 4.1.2.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.4 |
| pub type DistinguishedName<'a> = RdnSequence<'a>; |
| |
| /// RelativeDistinguishedName as defined in [RFC 5280 Section 4.1.2.4]. |
| /// |
| /// ```text |
| /// RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue |
| /// ``` |
| /// |
| /// Note that we follow the more common definition above. This technically |
| /// differs from the definition in X.501, which is: |
| /// |
| /// ```text |
| /// RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndDistinguishedValue |
| /// |
| /// AttributeTypeAndDistinguishedValue ::= SEQUENCE { |
| /// type ATTRIBUTE.&id ({SupportedAttributes}), |
| /// value ATTRIBUTE.&Type({SupportedAttributes}{@type}), |
| /// primaryDistinguished BOOLEAN DEFAULT TRUE, |
| /// valuesWithContext SET SIZE (1..MAX) OF SEQUENCE { |
| /// distingAttrValue [0] ATTRIBUTE.&Type ({SupportedAttributes}{@type}) OPTIONAL, |
| /// contextList SET SIZE (1..MAX) OF Context |
| /// } OPTIONAL |
| /// } |
| /// ``` |
| /// |
| /// [RFC 5280 Section 4.1.2.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.4 |
| #[derive(Clone, Debug, Default, PartialEq, Eq)] |
| pub struct RelativeDistinguishedName<'a>(pub SetOfVec<AttributeTypeAndValue<'a>>); |
| |
| impl RelativeDistinguishedName<'_> { |
| /// Converts an RelativeDistinguishedName string into an encoded RelativeDistinguishedName |
| /// |
| /// This function follows the rules in [RFC 4514]. |
| /// |
| /// [RFC 4514]: https://datatracker.ietf.org/doc/html/rfc4514 |
| pub fn encode_from_string(s: &str) -> Result<Vec<u8>, der::Error> { |
| let ders = split(s, b'+') |
| .map(AttributeTypeAndValue::encode_from_string) |
| .collect::<Result<Vec<_>, der::Error>>()?; |
| |
| let atvs = ders |
| .iter() |
| .map(|der| AttributeTypeAndValue::from_der(der)) |
| .collect::<Result<Vec<_>, der::Error>>()?; |
| |
| RelativeDistinguishedName(atvs.try_into()?).to_vec() |
| } |
| } |
| |
| /// Serializes the structure according to the rules in [RFC 4514]. |
| /// |
| /// [RFC 4514]: https://datatracker.ietf.org/doc/html/rfc4514 |
| impl fmt::Display for RelativeDistinguishedName<'_> { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| for (i, atv) in self.0.iter().enumerate() { |
| match i { |
| 0 => write!(f, "{}", atv)?, |
| _ => write!(f, "+{}", atv)?, |
| } |
| } |
| |
| Ok(()) |
| } |
| } |
| |
| impl_newtype!( |
| RelativeDistinguishedName<'a>, |
| SetOfVec<AttributeTypeAndValue<'a>> |
| ); |