| //! 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)); |
| } |