111 lines
3.5 KiB
Rust
111 lines
3.5 KiB
Rust
#![cfg(feature = "std")]
|
|
|
|
//! 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)
|
|
}
|
|
|
|
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));
|
|
}
|