summaryrefslogtreecommitdiff
path: root/tests/x509.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/x509.rs')
-rw-r--r--tests/x509.rs158
1 files changed, 158 insertions, 0 deletions
diff --git a/tests/x509.rs b/tests/x509.rs
new file mode 100644
index 0000000..31fa595
--- /dev/null
+++ b/tests/x509.rs
@@ -0,0 +1,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<'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<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);
+}