1 //! ASN.1 types supported by the proc macro 2 3 use proc_macro2::TokenStream; 4 use quote::quote; 5 use std::{fmt, str::FromStr}; 6 7 /// ASN.1 built-in types supported by the `#[asn1(type = "...")]` attribute 8 // TODO(tarcieri): support all ASN.1 types specified in `der::Tag` 9 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] 10 pub(crate) enum Asn1Type { 11 /// ASN.1 `BIT STRING`. 12 BitString, 13 14 /// ASN.1 `IA5String`. 15 Ia5String, 16 17 /// ASN.1 `GeneralizedTime`. 18 GeneralizedTime, 19 20 /// ASN.1 `OCTET STRING`. 21 OctetString, 22 23 /// ASN.1 `PrintableString`. 24 PrintableString, 25 26 /// ASN.1 `TeletexString`. 27 TeletexString, 28 29 /// ASN.1 `VideotexString`. 30 VideotexString, 31 32 /// ASN.1 `UTCTime`. 33 UtcTime, 34 35 /// ASN.1 `UTF8String`. 36 Utf8String, 37 } 38 39 impl Asn1Type { 40 /// Get the `::der::Tag` for this ASN.1 type tag(self) -> TokenStream41 pub fn tag(self) -> TokenStream { 42 match self { 43 Asn1Type::BitString => quote!(::der::Tag::BitString), 44 Asn1Type::Ia5String => quote!(::der::Tag::Ia5String), 45 Asn1Type::GeneralizedTime => quote!(::der::Tag::GeneralizedTime), 46 Asn1Type::OctetString => quote!(::der::Tag::OctetString), 47 Asn1Type::PrintableString => quote!(::der::Tag::PrintableString), 48 Asn1Type::TeletexString => quote!(::der::Tag::TeletexString), 49 Asn1Type::VideotexString => quote!(::der::Tag::VideotexString), 50 Asn1Type::UtcTime => quote!(::der::Tag::UtcTime), 51 Asn1Type::Utf8String => quote!(::der::Tag::Utf8String), 52 } 53 } 54 55 /// Get a `der::Decoder` object for a particular ASN.1 type decoder(self) -> TokenStream56 pub fn decoder(self) -> TokenStream { 57 match self { 58 Asn1Type::BitString => quote!(::der::asn1::BitStringRef::decode(reader)?), 59 Asn1Type::Ia5String => quote!(::der::asn1::Ia5StringRef::decode(reader)?), 60 Asn1Type::GeneralizedTime => quote!(::der::asn1::GeneralizedTime::decode(reader)?), 61 Asn1Type::OctetString => quote!(::der::asn1::OctetStringRef::decode(reader)?), 62 Asn1Type::PrintableString => quote!(::der::asn1::PrintableStringRef::decode(reader)?), 63 Asn1Type::TeletexString => quote!(::der::asn1::TeletexStringRef::decode(reader)?), 64 Asn1Type::VideotexString => quote!(::der::asn1::VideotexStringRef::decode(reader)?), 65 Asn1Type::UtcTime => quote!(::der::asn1::UtcTime::decode(reader)?), 66 Asn1Type::Utf8String => quote!(::der::asn1::Utf8StringRef::decode(reader)?), 67 } 68 } 69 70 /// Get a `der::Encoder` object for a particular ASN.1 type encoder(self, binding: &TokenStream) -> TokenStream71 pub fn encoder(self, binding: &TokenStream) -> TokenStream { 72 let type_path = self.type_path(); 73 74 match self { 75 Asn1Type::Ia5String 76 | Asn1Type::OctetString 77 | Asn1Type::PrintableString 78 | Asn1Type::TeletexString 79 | Asn1Type::VideotexString 80 | Asn1Type::Utf8String => quote!(#type_path::new(#binding)?), 81 _ => quote!(#type_path::try_from(#binding)?), 82 } 83 } 84 85 /// Get the Rust type path for a particular ASN.1 type. 86 /// Get a `der::Encoder` object for a particular ASN.1 type type_path(self) -> TokenStream87 pub fn type_path(self) -> TokenStream { 88 match self { 89 Asn1Type::BitString => quote!(::der::asn1::BitStringRef), 90 Asn1Type::Ia5String => quote!(::der::asn1::Ia5StringRef), 91 Asn1Type::GeneralizedTime => quote!(::der::asn1::GeneralizedTime), 92 Asn1Type::OctetString => quote!(::der::asn1::OctetStringRef), 93 Asn1Type::PrintableString => quote!(::der::asn1::PrintableStringRef), 94 Asn1Type::TeletexString => quote!(::der::asn1::TeletexStringRef), 95 Asn1Type::VideotexString => quote!(::der::asn1::VideotexStringRef), 96 Asn1Type::UtcTime => quote!(::der::asn1::UtcTime), 97 Asn1Type::Utf8String => quote!(::der::asn1::Utf8StringRef), 98 } 99 } 100 } 101 102 impl FromStr for Asn1Type { 103 type Err = ParseError; 104 from_str(s: &str) -> Result<Self, ParseError>105 fn from_str(s: &str) -> Result<Self, ParseError> { 106 match s { 107 "BIT STRING" => Ok(Self::BitString), 108 "IA5String" => Ok(Self::Ia5String), 109 "GeneralizedTime" => Ok(Self::GeneralizedTime), 110 "OCTET STRING" => Ok(Self::OctetString), 111 "PrintableString" => Ok(Self::PrintableString), 112 "TeletexString" => Ok(Self::TeletexString), 113 "VideotexString" => Ok(Self::VideotexString), 114 "UTCTime" => Ok(Self::UtcTime), 115 "UTF8String" => Ok(Self::Utf8String), 116 _ => Err(ParseError), 117 } 118 } 119 } 120 121 impl fmt::Display for Asn1Type { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 123 f.write_str(match self { 124 Asn1Type::BitString => "BIT STRING", 125 Asn1Type::Ia5String => "IA5String", 126 Asn1Type::GeneralizedTime => "GeneralizedTime", 127 Asn1Type::OctetString => "OCTET STRING", 128 Asn1Type::PrintableString => "PrintableString", 129 Asn1Type::TeletexString => "TeletexString", 130 Asn1Type::VideotexString => "VideotexString", 131 Asn1Type::UtcTime => "UTCTime", 132 Asn1Type::Utf8String => "UTF8String", 133 }) 134 } 135 } 136 137 /// Error type 138 #[derive(Debug)] 139 pub(crate) struct ParseError; 140