blob: d48ed2ffaef03bf14c8e111630cc58b262477176 [file] [log] [blame] [edit]
//! Test implementation for Kerberos v5
//!
//! This is mostly used to verify that required types and functions are implemented,
//! and that provided API is convenient.
use asn1_rs::*;
use hex_literal::hex;
const PRINCIPAL_NAME: &[u8] = &hex!("30 81 11 a0 03 02 01 00 a1 0a 30 81 07 1b 05 4a 6f 6e 65 73");
/// PrincipalName ::= SEQUENCE {
/// name-type [0] Int32,
/// name-string [1] SEQUENCE OF KerberosString
/// }
#[derive(Debug, PartialEq, Eq)]
pub struct PrincipalName {
pub name_type: NameType,
pub name_string: Vec<String>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct NameType(pub i32);
// KerberosString ::= GeneralString (IA5String)
pub type KerberosString<'a> = GeneralString<'a>;
pub type KerberosStringList<'a> = Vec<KerberosString<'a>>;
impl Tagged for PrincipalName {
const TAG: Tag = Tag::Sequence;
}
impl<'a> FromDer<'a> for PrincipalName {
fn from_der(bytes: &'a [u8]) -> ParseResult<'a, Self> {
// XXX in the example above, PRINCIPAL_NAME does not respect DER constraints (length is using long form while < 127)
let (rem, seq) = Sequence::from_ber(bytes)?;
seq.and_then(|data| {
let input = &data;
let (i, t) = parse_der_tagged_explicit::<_, u32, _>(0)(input)?;
let name_type = t.inner;
let name_type = NameType(name_type as i32);
let (_, t) = parse_der_tagged_explicit::<_, KerberosStringList, _>(1)(i)?;
let name_string = t.inner.iter().map(|s| s.string()).collect();
Ok((
rem,
PrincipalName {
name_type,
name_string,
},
))
})
}
}
impl ToDer for PrincipalName {
fn to_der_len(&self) -> Result<usize> {
let sz = self.name_type.0.to_der_len()? + 2 /* tagged */;
let sz = sz + self.name_string.to_der_len()? + 2 /* tagged */;
Ok(sz)
}
fn write_der_header(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
let len = self.to_der_len()?;
let header = Header::new(Class::Universal, true, Self::TAG, Length::Definite(len));
header.write_der_header(writer).map_err(Into::into)
}
fn write_der_content(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
// build DER sequence content
let sz1 = self
.name_type
.0
.explicit(Class::ContextSpecific, 0)
.write_der(writer)?;
let sz2 = self
.name_string
.iter()
.map(|s| KerberosString::from(s.as_ref()))
.collect::<Vec<_>>()
.explicit(Class::ContextSpecific, 1)
.write_der(writer)?;
Ok(sz1 + sz2)
}
}
#[test]
fn krb5_principalname() {
let input = PRINCIPAL_NAME;
let (rem, res) = PrincipalName::from_der(input).expect("parsing failed");
assert!(rem.is_empty());
let expected = PrincipalName {
name_type: NameType(0),
name_string: vec!["Jones".to_string()],
};
assert_eq!(res, expected);
}
#[test]
fn to_der_krb5_principalname() {
let principal = PrincipalName {
name_type: NameType(0),
name_string: vec!["Jones".to_string()],
};
let v = PrincipalName::to_der_vec(&principal).expect("serialization failed");
std::fs::write("/tmp/out.bin", &v).unwrap();
let (_, principal2) = PrincipalName::from_der(&v).expect("parsing failed");
assert!(principal.eq(&principal2));
}