use alloc::string::String;
use alloc::vec::Vec;
use super::{Error, oid};
use crate::der::{Reader, encode_sequence, encode_string, encode_tlv, oid_tlv, parse_oid, tag};
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct DistinguishedName {
pub country: Option<String>,
pub organization: Option<String>,
pub organizational_unit: Option<String>,
pub common_name: Option<String>,
}
impl DistinguishedName {
pub fn new() -> Self {
Self::default()
}
pub fn common_name(cn: &str) -> Self {
DistinguishedName {
common_name: Some(String::from(cn)),
..Self::default()
}
}
pub fn with_organization(mut self, o: &str) -> Self {
self.organization = Some(String::from(o));
self
}
pub fn with_country(mut self, c: &str) -> Self {
self.country = Some(String::from(c));
self
}
pub(crate) fn to_der(&self) -> Vec<u8> {
let mut rdns = Vec::new();
if let Some(c) = &self.country {
rdns.extend_from_slice(&rdn(oid::COUNTRY, tag::PRINTABLE_STRING, c));
}
if let Some(o) = &self.organization {
rdns.extend_from_slice(&rdn(oid::ORGANIZATION, tag::UTF8_STRING, o));
}
if let Some(ou) = &self.organizational_unit {
rdns.extend_from_slice(&rdn(oid::ORGANIZATIONAL_UNIT, tag::UTF8_STRING, ou));
}
if let Some(cn) = &self.common_name {
rdns.extend_from_slice(&rdn(oid::COMMON_NAME, tag::UTF8_STRING, cn));
}
encode_sequence(&rdns)
}
pub(crate) fn decode(reader: &mut Reader) -> Result<Self, Error> {
let mut dn = DistinguishedName::default();
let mut seq = reader.read_sequence()?;
while !seq.is_empty() {
let set = seq.read_tlv(tag::SET)?;
let mut set_reader = Reader::new(set);
let mut atv = set_reader.read_sequence()?;
let oid_body = atv.read_oid()?;
let (_, value) = atv.read_any()?;
let s = core::str::from_utf8(value)
.map_err(|_| Error::Malformed)?
.into();
let arcs = parse_oid(oid_body)?;
let arcs = arcs.as_slice();
if arcs == oid::COMMON_NAME {
dn.common_name = Some(s);
} else if arcs == oid::ORGANIZATION {
dn.organization = Some(s);
} else if arcs == oid::ORGANIZATIONAL_UNIT {
dn.organizational_unit = Some(s);
} else if arcs == oid::COUNTRY {
dn.country = Some(s);
}
}
Ok(dn)
}
}
fn rdn(attr_oid: &[u64], value_tag: u8, value: &str) -> Vec<u8> {
let atv = encode_sequence(&[oid_tlv(attr_oid), encode_string(value_tag, value)].concat());
encode_tlv(tag::SET, &atv)
}