1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
//! 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<RelativeDistinguishedName<'a>>,
}
impl<'a> FromDer<'a> for Name<'a> {
fn from_der(bytes: &'a [u8]) -> ParseResult<'a, Self> {
let (rem, rdn_sequence) = <Vec<RelativeDistinguishedName>>::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<AttributeTypeAndValue<'a>>,
}
impl<'a> FromDer<'a> for RelativeDistinguishedName<'a> {
fn from_der(bytes: &'a [u8]) -> ParseResult<'a, Self> {
let (rem, set) = SetOf::<AttributeTypeAndValue>::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 CheckDerConstraints for AttributeTypeAndValue<'_> {
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<Any<'a>> for DirectoryString {
type Error = Error;
fn try_from(any: Any<'a>) -> Result<Self, Self::Error> {
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);
}
|