From dd281edcd14cb0c8dbbcf3e62d5aef19b5b33eb1 Mon Sep 17 00:00:00 2001 From: Adam Wick Date: Sun, 10 Dec 2017 21:54:01 -0800 Subject: [PATCH] Add support for printable strings. --- src/lib.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 46bfb9c..69b2162 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ pub enum ASN1Block { ObjectIdentifier(ASN1Class, OID), IA5String(ASN1Class, String), UTF8String(ASN1Class, String), + PrintableString(ASN1Class, String), Sequence(ASN1Class, Vec), Set(ASN1Class, Vec), Unknown(ASN1Class, BigUint, Vec) @@ -62,6 +63,8 @@ macro_rules! oid { }}; } +const PRINTABLE_CHARS: &'static str = + "ABCDEFGHIJKLMOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'()+,-./:=? "; #[derive(Clone,Copy,Debug,PartialEq)] pub enum ASN1Class { Universal, Application, ContextSpecific, Private } @@ -71,7 +74,8 @@ pub enum ASN1DecodeErr { EmptyBuffer, BadBooleanLength, LengthTooLarge, - UTF8DecodeFailure + UTF8DecodeFailure, + PrintableStringDecodeFailure } #[derive(Clone,Debug,PartialEq)] @@ -173,6 +177,20 @@ pub fn from_der(i: &[u8]) -> Result,ASN1DecodeErr> { return Err(e) } } + // PRINTABLE STRING + Some(0x13) => { + let mut res = String::new(); + let mut val = body.iter().map(|x| *x as char); + + for c in val { + if PRINTABLE_CHARS.contains(c) { + res.push(c); + } else { + return Err(ASN1DecodeErr::PrintableStringDecodeFailure); + } + } + result.push(ASN1Block::PrintableString(class, res)); + } // IA5 (ASCII) STRING Some(0x16) => { let val = body.iter().map(|x| *x as char); @@ -409,6 +427,24 @@ pub fn to_der(i: &ASN1Block) -> Result,ASN1EncodeErr> { res.append(&mut body); Ok(res) } + // PrintableString + &ASN1Block::PrintableString(cl, ref str) => { + let mut body = Vec::new(); + + for c in str.chars() { + body.push(c as u8); + } + + let inttag = BigUint::from_u8(0x13).unwrap(); + let mut lenbytes = encode_len(body.len()); + let mut tagbytes = encode_tag(cl, &inttag); + + let mut res = Vec::new(); + res.append(&mut tagbytes); + res.append(&mut lenbytes); + res.append(&mut body); + Ok(res) + } // IA5String &ASN1Block::IA5String(cl, ref str) => { let mut body = Vec::new(); @@ -724,6 +760,19 @@ mod tests { ASN1Block::Set(class, items) } + fn arb_print(g: &mut G, _d: usize) -> ASN1Block { + let class = ASN1Class::arbitrary(g); + let count = g.gen_range::(0, 384); + let mut items = Vec::new(); + + for _ in 0..count { + let v = g.choose(PRINTABLE_CHARS.as_bytes()).unwrap(); + items.push(*v as char); + } + + ASN1Block::PrintableString(class, String::from_iter(items.iter())) + } + fn arb_ia5(g: &mut G, _d: usize) -> ASN1Block { let class = ASN1Class::arbitrary(g); let count = g.gen_range::(0, 384); @@ -759,6 +808,7 @@ mod tests { arb_octstr, arb_null, arb_objid, + arb_print, arb_ia5, arb_utf8, arb_unknown];