use crate::{attr::AttributeTypeAndValue, ext::pkix::name::DirectoryString};
use alloc::vec::Vec;
use const_oid::{
ObjectIdentifier,
db::{rfc3280, rfc4519},
};
use core::{cmp::Ordering, fmt, str::FromStr};
use der::{
DecodeValue, Encode, EncodeValue, FixedTag, Header, Length, Reader, Tag, ValueOrd, Writer,
asn1::{Any, Ia5StringRef, PrintableStringRef, SetOfVec},
};
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct Name(pub(crate) RdnSequence);
impl Name {
#[cfg(feature = "hazmat")]
pub fn hazmat_from_rdn_sequence(value: RdnSequence) -> Self {
Self(value)
}
}
impl From<Name> for RdnSequence {
#[inline]
fn from(value: Name) -> Self {
value.0
}
}
impl AsRef<RdnSequence> for Name {
#[inline]
fn as_ref(&self) -> &RdnSequence {
&self.0
}
}
impl FixedTag for Name {
const TAG: Tag = <RdnSequence as FixedTag>::TAG;
}
impl<'a> DecodeValue<'a> for Name {
type Error = der::Error;
fn decode_value<R: Reader<'a>>(decoder: &mut R, header: Header) -> der::Result<Self> {
Ok(Self(RdnSequence::decode_value(decoder, header)?))
}
}
impl EncodeValue for Name {
fn encode_value(&self, encoder: &mut impl Writer) -> der::Result<()> {
self.0.encode_value(encoder)
}
fn value_len(&self) -> der::Result<Length> {
self.0.value_len()
}
}
impl ValueOrd for Name {
fn value_cmp(&self, other: &Self) -> der::Result<Ordering> {
self.0.value_cmp(&other.0)
}
}
impl Name {
#[inline]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn len(&self) -> usize {
self.0.0.len()
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = &'_ AttributeTypeAndValue> + '_ {
self.0.0.iter().flat_map(move |rdn| rdn.0.as_slice())
}
#[inline]
pub fn iter_rdn(&self) -> impl Iterator<Item = &'_ RelativeDistinguishedName> + '_ {
self.0.0.iter()
}
}
impl Name {
pub fn by_oid<'a, T>(&'a self, oid: ObjectIdentifier) -> der::Result<Option<T>>
where
T: TryFrom<&'a Any, Error = der::Error>,
T: fmt::Debug,
{
self.iter()
.filter(|atav| atav.oid == oid)
.map(|atav| T::try_from(&atav.value))
.next()
.transpose()
}
pub fn common_name(&self) -> der::Result<Option<DirectoryString>> {
self.by_oid(rfc4519::COMMON_NAME)
}
pub fn country(&self) -> der::Result<Option<PrintableStringRef<'_>>> {
self.by_oid(rfc4519::COUNTRY_NAME)
}
pub fn state_or_province(&self) -> der::Result<Option<DirectoryString>> {
self.by_oid(rfc4519::ST)
}
pub fn locality(&self) -> der::Result<Option<DirectoryString>> {
self.by_oid(rfc4519::LOCALITY_NAME)
}
pub fn organization(&self) -> der::Result<Option<DirectoryString>> {
self.by_oid(rfc4519::ORGANIZATION_NAME)
}
pub fn organization_unit(&self) -> der::Result<Option<DirectoryString>> {
self.by_oid(rfc4519::ORGANIZATIONAL_UNIT_NAME)
}
pub fn email_address(&self) -> der::Result<Option<Ia5StringRef<'_>>> {
self.by_oid(rfc3280::EMAIL_ADDRESS)
}
}
impl FromStr for Name {
type Err = der::Error;
fn from_str(s: &str) -> der::Result<Self> {
Ok(Self(RdnSequence::from_str(s)?))
}
}
impl fmt::Display for Name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct RdnSequence(Vec<RelativeDistinguishedName>);
impl RdnSequence {
#[deprecated(since = "0.2.1", note = "use RdnSequence::from_str(...)?.to_der()")]
pub fn encode_from_string(s: &str) -> Result<Vec<u8>, der::Error> {
Self::from_str(s)?.to_der()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = &RelativeDistinguishedName> {
self.0.iter()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn push(&mut self, name: RelativeDistinguishedName) {
self.0.push(name)
}
}
impl FromStr for RdnSequence {
type Err = der::Error;
fn from_str(s: &str) -> der::Result<Self> {
let mut parts = split(s, b',')
.map(RelativeDistinguishedName::from_str)
.collect::<der::Result<Vec<_>>>()?;
parts.reverse();
Ok(Self(parts))
}
}
impl fmt::Display for RdnSequence {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (i, atv) in self.0.iter().rev().enumerate() {
match i {
0 => write!(f, "{atv}")?,
_ => write!(f, ",{atv}")?,
}
}
Ok(())
}
}
impl_newtype!(RdnSequence, Vec<RelativeDistinguishedName>);
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'\\'
})
}
fn split(s: &str, b: u8) -> impl '_ + Iterator<Item = &'_ str> {
let mut prev = 0;
find(s, b).chain([s.len()]).map(move |i| {
let x = &s[prev..i];
prev = i + 1;
x
})
}
pub type DistinguishedName = RdnSequence;
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct RelativeDistinguishedName(pub(crate) SetOfVec<AttributeTypeAndValue>);
impl RelativeDistinguishedName {
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = &AttributeTypeAndValue> {
self.0.iter()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn insert(&mut self, item: AttributeTypeAndValue) -> Result<(), der::Error> {
self.0.insert(item)
}
}
impl FromStr for RelativeDistinguishedName {
type Err = der::Error;
fn from_str(s: &str) -> der::Result<Self> {
split(s, b'+')
.map(AttributeTypeAndValue::from_str)
.collect::<der::Result<Vec<_>>>()?
.try_into()
.map(Self)
}
}
impl TryFrom<Vec<AttributeTypeAndValue>> for RelativeDistinguishedName {
type Error = der::Error;
fn try_from(vec: Vec<AttributeTypeAndValue>) -> der::Result<RelativeDistinguishedName> {
Ok(RelativeDistinguishedName(SetOfVec::try_from(vec)?))
}
}
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, SetOfVec<AttributeTypeAndValue>);