//! Test implementation for X.509 //! //! This is mostly used to verify that required types and functions are implemented, //! and that provided API is convenient. use asn1_rs::{ nom, Any, CheckDerConstraints, Choice, Error, FromBer, FromDer, Oid, ParseResult, Sequence, SetOf, Tag, Tagged, }; use hex_literal::hex; use nom::sequence::pair; use std::convert::{TryFrom, TryInto}; const DN: &[u8] = &hex!( " 30 45 31 0b 30 09 06 03 55 04 06 13 02 46 52 31 13 30 11 06 03 55 04 08 0c 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 0c 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c 74 64 " ); // Name ::= CHOICE { -- only one possibility for now -- // rdnSequence RDNSequence } // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName #[derive(Debug)] pub struct Name<'a> { pub rdn_sequence: Vec>, } impl<'a> FromDer<'a> for Name<'a> { fn from_der(bytes: &'a [u8]) -> ParseResult<'a, Self> { let (rem, rdn_sequence) = >::from_der(bytes)?; let dn = Name { rdn_sequence }; Ok((rem, dn)) } } // RelativeDistinguishedName ::= // SET SIZE (1..MAX) OF AttributeTypeAndValue #[derive(Debug)] pub struct RelativeDistinguishedName<'a> { pub v: Vec>, } impl<'a> FromDer<'a> for RelativeDistinguishedName<'a> { fn from_der(bytes: &'a [u8]) -> ParseResult<'a, Self> { let (rem, set) = SetOf::::from_der(bytes)?; let v: Vec<_> = set.into(); if v.is_empty() { return Err(nom::Err::Failure(Error::InvalidLength)); } Ok((rem, RelativeDistinguishedName { v })) } } // AttributeTypeAndValue ::= SEQUENCE { // type AttributeType, // value AttributeValue } #[derive(Debug)] pub struct AttributeTypeAndValue<'a> { pub oid: Oid<'a>, pub value: AttributeValue<'a>, } impl<'a> FromBer<'a> for AttributeTypeAndValue<'a> { fn from_ber(bytes: &'a [u8]) -> ParseResult<'a, Self> { let (rem, seq) = Sequence::from_der(bytes)?; let (_, (oid, value)) = seq.parse_into(|i| pair(Oid::from_der, AttributeValue::from_der)(i))?; let attr = AttributeTypeAndValue { oid, value }; Ok((rem, attr)) } } impl<'a> FromDer<'a> for AttributeTypeAndValue<'a> { fn from_der(bytes: &'a [u8]) -> ParseResult<'a, Self> { let (rem, seq) = Sequence::from_der(bytes)?; let (_, (oid, value)) = seq.parse_into(|i| pair(Oid::from_der, AttributeValue::from_der)(i))?; let attr = AttributeTypeAndValue { oid, value }; Ok((rem, attr)) } } impl<'a> CheckDerConstraints for AttributeTypeAndValue<'a> { fn check_constraints(any: &Any) -> asn1_rs::Result<()> { any.tag().assert_eq(Sequence::TAG)?; Ok(()) } } // AttributeType ::= OBJECT IDENTIFIER // AttributeValue ::= ANY -- DEFINED BY AttributeType #[derive(Debug)] pub enum AttributeValue<'a> { DirectoryString(DirectoryString), Other(Any<'a>), } impl<'a> FromDer<'a> for AttributeValue<'a> { fn from_der(bytes: &'a [u8]) -> ParseResult<'a, Self> { let (rem, any) = Any::from_der(bytes)?; let ds = if DirectoryString::can_decode(any.tag()) { AttributeValue::DirectoryString(any.try_into()?) } else { AttributeValue::Other(any) }; Ok((rem, ds)) } } // DirectoryString ::= CHOICE { // teletexString TeletexString (SIZE (1..MAX)), // printableString PrintableString (SIZE (1..MAX)), // universalString UniversalString (SIZE (1..MAX)), // utf8String UTF8String (SIZE (1..MAX)), // bmpString BMPString (SIZE (1..MAX)) } #[derive(Debug)] pub enum DirectoryString { Printable(String), Utf8(String), } impl Choice for DirectoryString { fn can_decode(tag: Tag) -> bool { matches!(tag, Tag::PrintableString | Tag::Utf8String) } } impl<'a> TryFrom> for DirectoryString { type Error = Error; fn try_from(any: Any<'a>) -> Result { match any.tag() { Tag::PrintableString => { let s = any.printablestring()?; Ok(DirectoryString::Printable(s.string())) } Tag::Utf8String => { let s = any.string()?; Ok(DirectoryString::Utf8(s)) } _ => Err(Error::InvalidTag), } } } #[test] fn x509_decode_dn() { let (rem, dn) = Name::from_der(DN).expect("parsing failed"); assert!(rem.is_empty()); // dbg!(&dn); assert_eq!(dn.rdn_sequence.len(), 3); }