1 //! ASN.1 `PrintableString` support.
2 
3 use crate::{asn1::AnyRef, FixedTag, Result, StrRef, Tag};
4 use core::{fmt, ops::Deref};
5 
6 macro_rules! impl_printable_string {
7     ($type: ty) => {
8         impl_printable_string!($type,);
9     };
10     ($type: ty, $($li: lifetime)?) => {
11         impl_string_type!($type, $($li),*);
12 
13         impl<$($li),*> FixedTag for $type {
14             const TAG: Tag = Tag::PrintableString;
15         }
16 
17         impl<$($li),*> fmt::Debug for $type {
18             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19                 write!(f, "PrintableString({:?})", self.as_str())
20             }
21         }
22     };
23 }
24 
25 /// ASN.1 `PrintableString` type.
26 ///
27 /// Supports a subset the ASCII character set (described below).
28 ///
29 /// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead.
30 /// For the full ASCII character set, use
31 /// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`].
32 ///
33 /// This is a zero-copy reference type which borrows from the input data.
34 ///
35 /// # Supported characters
36 ///
37 /// The following ASCII characters/ranges are supported:
38 ///
39 /// - `A..Z`
40 /// - `a..z`
41 /// - `0..9`
42 /// - "` `" (i.e. space)
43 /// - `\`
44 /// - `(`
45 /// - `)`
46 /// - `+`
47 /// - `,`
48 /// - `-`
49 /// - `.`
50 /// - `/`
51 /// - `:`
52 /// - `=`
53 /// - `?`
54 #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
55 pub struct PrintableStringRef<'a> {
56     /// Inner value
57     inner: StrRef<'a>,
58 }
59 
60 impl<'a> PrintableStringRef<'a> {
61     /// Create a new ASN.1 `PrintableString`.
new<T>(input: &'a T) -> Result<Self> where T: AsRef<[u8]> + ?Sized,62     pub fn new<T>(input: &'a T) -> Result<Self>
63     where
64         T: AsRef<[u8]> + ?Sized,
65     {
66         let input = input.as_ref();
67 
68         // Validate all characters are within PrintableString's allowed set
69         for &c in input.iter() {
70             match c {
71                 b'A'..=b'Z'
72                 | b'a'..=b'z'
73                 | b'0'..=b'9'
74                 | b' '
75                 | b'\''
76                 | b'('
77                 | b')'
78                 | b'+'
79                 | b','
80                 | b'-'
81                 | b'.'
82                 | b'/'
83                 | b':'
84                 | b'='
85                 | b'?' => (),
86                 _ => return Err(Self::TAG.value_error()),
87             }
88         }
89 
90         StrRef::from_bytes(input)
91             .map(|inner| Self { inner })
92             .map_err(|_| Self::TAG.value_error())
93     }
94 }
95 
96 impl_printable_string!(PrintableStringRef<'a>, 'a);
97 
98 impl<'a> Deref for PrintableStringRef<'a> {
99     type Target = StrRef<'a>;
100 
deref(&self) -> &Self::Target101     fn deref(&self) -> &Self::Target {
102         &self.inner
103     }
104 }
105 impl<'a> From<&PrintableStringRef<'a>> for PrintableStringRef<'a> {
from(value: &PrintableStringRef<'a>) -> PrintableStringRef<'a>106     fn from(value: &PrintableStringRef<'a>) -> PrintableStringRef<'a> {
107         *value
108     }
109 }
110 
111 impl<'a> From<PrintableStringRef<'a>> for AnyRef<'a> {
from(printable_string: PrintableStringRef<'a>) -> AnyRef<'a>112     fn from(printable_string: PrintableStringRef<'a>) -> AnyRef<'a> {
113         AnyRef::from_tag_and_value(Tag::PrintableString, printable_string.inner.into())
114     }
115 }
116 
117 #[cfg(feature = "alloc")]
118 pub use self::allocation::PrintableString;
119 
120 #[cfg(feature = "alloc")]
121 mod allocation {
122     use super::PrintableStringRef;
123 
124     use crate::{
125         asn1::AnyRef,
126         referenced::{OwnedToRef, RefToOwned},
127         BytesRef, Error, FixedTag, Result, StrOwned, Tag,
128     };
129     use alloc::string::String;
130     use core::{fmt, ops::Deref};
131 
132     /// ASN.1 `PrintableString` type.
133     ///
134     /// Supports a subset the ASCII character set (described below).
135     ///
136     /// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead.
137     /// For the full ASCII character set, use
138     /// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`].
139     ///
140     /// # Supported characters
141     ///
142     /// The following ASCII characters/ranges are supported:
143     ///
144     /// - `A..Z`
145     /// - `a..z`
146     /// - `0..9`
147     /// - "` `" (i.e. space)
148     /// - `\`
149     /// - `(`
150     /// - `)`
151     /// - `+`
152     /// - `,`
153     /// - `-`
154     /// - `.`
155     /// - `/`
156     /// - `:`
157     /// - `=`
158     /// - `?`
159     #[derive(Clone, Eq, PartialEq, PartialOrd, Ord)]
160     pub struct PrintableString {
161         /// Inner value
162         inner: StrOwned,
163     }
164 
165     impl PrintableString {
166         /// Create a new ASN.1 `PrintableString`.
new<T>(input: &T) -> Result<Self> where T: AsRef<[u8]> + ?Sized,167         pub fn new<T>(input: &T) -> Result<Self>
168         where
169             T: AsRef<[u8]> + ?Sized,
170         {
171             let input = input.as_ref();
172             PrintableStringRef::new(input)?;
173 
174             StrOwned::from_bytes(input)
175                 .map(|inner| Self { inner })
176                 .map_err(|_| Self::TAG.value_error())
177         }
178     }
179 
180     impl_printable_string!(PrintableString);
181 
182     impl Deref for PrintableString {
183         type Target = StrOwned;
184 
deref(&self) -> &Self::Target185         fn deref(&self) -> &Self::Target {
186             &self.inner
187         }
188     }
189 
190     impl<'a> From<PrintableStringRef<'a>> for PrintableString {
from(value: PrintableStringRef<'a>) -> PrintableString191         fn from(value: PrintableStringRef<'a>) -> PrintableString {
192             let inner =
193                 StrOwned::from_bytes(value.inner.as_bytes()).expect("Invalid PrintableString");
194             Self { inner }
195         }
196     }
197 
198     impl<'a> From<&'a PrintableString> for AnyRef<'a> {
from(printable_string: &'a PrintableString) -> AnyRef<'a>199         fn from(printable_string: &'a PrintableString) -> AnyRef<'a> {
200             AnyRef::from_tag_and_value(
201                 Tag::PrintableString,
202                 BytesRef::new(printable_string.inner.as_bytes()).expect("Invalid PrintableString"),
203             )
204         }
205     }
206 
207     impl<'a> RefToOwned<'a> for PrintableStringRef<'a> {
208         type Owned = PrintableString;
ref_to_owned(&self) -> Self::Owned209         fn ref_to_owned(&self) -> Self::Owned {
210             PrintableString {
211                 inner: self.inner.ref_to_owned(),
212             }
213         }
214     }
215 
216     impl OwnedToRef for PrintableString {
217         type Borrowed<'a> = PrintableStringRef<'a>;
owned_to_ref(&self) -> Self::Borrowed<'_>218         fn owned_to_ref(&self) -> Self::Borrowed<'_> {
219             PrintableStringRef {
220                 inner: self.inner.owned_to_ref(),
221             }
222         }
223     }
224 
225     impl TryFrom<String> for PrintableString {
226         type Error = Error;
227 
try_from(input: String) -> Result<Self>228         fn try_from(input: String) -> Result<Self> {
229             PrintableStringRef::new(&input)?;
230 
231             StrOwned::new(input)
232                 .map(|inner| Self { inner })
233                 .map_err(|_| Self::TAG.value_error())
234         }
235     }
236 }
237 
238 #[cfg(test)]
239 mod tests {
240     use super::PrintableStringRef;
241     use crate::Decode;
242 
243     #[test]
parse_bytes()244     fn parse_bytes() {
245         let example_bytes = &[
246             0x13, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x65, 0x72, 0x20, 0x31,
247         ];
248 
249         let printable_string = PrintableStringRef::from_der(example_bytes).unwrap();
250         assert_eq!(printable_string.as_str(), "Test User 1");
251     }
252 }
253