1mod tag;
7mod length;
8mod reader;
9mod writer;
10mod value;
11
12pub use tag::{Tag, TagClass, TagType};
13pub use length::Length;
14pub use reader::BerReader;
15pub use writer::BerWriter;
16pub use value::BerValue;
17
18use crate::error::{BerError, Result};
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22#[repr(u8)]
23pub enum UniversalTag {
24 Boolean = 1,
26 Integer = 2,
28 BitString = 3,
30 OctetString = 4,
32 Null = 5,
34 ObjectIdentifier = 6,
36 ObjectDescriptor = 7,
38 External = 8,
40 Real = 9,
42 Enumerated = 10,
44 EmbeddedPdv = 11,
46 Utf8String = 12,
48 RelativeOid = 13,
50 Sequence = 16,
52 Set = 17,
54 NumericString = 18,
56 PrintableString = 19,
58 T61String = 20,
60 VideotexString = 21,
62 Ia5String = 22,
64 UtcTime = 23,
66 GeneralizedTime = 24,
68 GraphicString = 25,
70 VisibleString = 26,
72 GeneralString = 27,
74 UniversalString = 28,
76 CharacterString = 29,
78 BmpString = 30,
80}
81
82impl TryFrom<u32> for UniversalTag {
83 type Error = BerError;
84
85 fn try_from(value: u32) -> std::result::Result<Self, Self::Error> {
86 match value {
87 1 => Ok(UniversalTag::Boolean),
88 2 => Ok(UniversalTag::Integer),
89 3 => Ok(UniversalTag::BitString),
90 4 => Ok(UniversalTag::OctetString),
91 5 => Ok(UniversalTag::Null),
92 6 => Ok(UniversalTag::ObjectIdentifier),
93 7 => Ok(UniversalTag::ObjectDescriptor),
94 8 => Ok(UniversalTag::External),
95 9 => Ok(UniversalTag::Real),
96 10 => Ok(UniversalTag::Enumerated),
97 11 => Ok(UniversalTag::EmbeddedPdv),
98 12 => Ok(UniversalTag::Utf8String),
99 13 => Ok(UniversalTag::RelativeOid),
100 16 => Ok(UniversalTag::Sequence),
101 17 => Ok(UniversalTag::Set),
102 18 => Ok(UniversalTag::NumericString),
103 19 => Ok(UniversalTag::PrintableString),
104 20 => Ok(UniversalTag::T61String),
105 21 => Ok(UniversalTag::VideotexString),
106 22 => Ok(UniversalTag::Ia5String),
107 23 => Ok(UniversalTag::UtcTime),
108 24 => Ok(UniversalTag::GeneralizedTime),
109 25 => Ok(UniversalTag::GraphicString),
110 26 => Ok(UniversalTag::VisibleString),
111 27 => Ok(UniversalTag::GeneralString),
112 28 => Ok(UniversalTag::UniversalString),
113 29 => Ok(UniversalTag::CharacterString),
114 30 => Ok(UniversalTag::BmpString),
115 _ => Err(BerError::InvalidTag(format!("unknown universal tag: {}", value))),
116 }
117 }
118}
119
120pub fn encode<T: BerEncode>(value: &T) -> Result<Vec<u8>> {
122 let mut writer = BerWriter::new();
123 value.encode(&mut writer)?;
124 Ok(writer.into_bytes())
125}
126
127pub fn decode<T: BerDecode>(data: &[u8]) -> Result<T> {
129 let mut reader = BerReader::new(data);
130 T::decode(&mut reader)
131}
132
133pub trait BerEncode {
135 fn encode(&self, writer: &mut BerWriter) -> Result<()>;
137}
138
139pub trait BerDecode: Sized {
141 fn decode(reader: &mut BerReader) -> Result<Self>;
143}
144
145impl BerEncode for bool {
147 fn encode(&self, writer: &mut BerWriter) -> Result<()> {
148 writer.write_boolean(*self)
149 }
150}
151
152impl BerEncode for i64 {
153 fn encode(&self, writer: &mut BerWriter) -> Result<()> {
154 writer.write_integer(*self)
155 }
156}
157
158impl BerEncode for i32 {
159 fn encode(&self, writer: &mut BerWriter) -> Result<()> {
160 writer.write_integer(*self as i64)
161 }
162}
163
164impl BerEncode for f64 {
165 fn encode(&self, writer: &mut BerWriter) -> Result<()> {
166 writer.write_real(*self)
167 }
168}
169
170impl BerEncode for str {
171 fn encode(&self, writer: &mut BerWriter) -> Result<()> {
172 writer.write_utf8_string(self)
173 }
174}
175
176impl BerEncode for String {
177 fn encode(&self, writer: &mut BerWriter) -> Result<()> {
178 writer.write_utf8_string(self)
179 }
180}
181
182impl BerEncode for [u8] {
183 fn encode(&self, writer: &mut BerWriter) -> Result<()> {
184 writer.write_octet_string(self)
185 }
186}
187
188impl BerEncode for Vec<u8> {
189 fn encode(&self, writer: &mut BerWriter) -> Result<()> {
190 writer.write_octet_string(self)
191 }
192}
193
194impl BerDecode for bool {
196 fn decode(reader: &mut BerReader) -> Result<Self> {
197 reader.read_boolean()
198 }
199}
200
201impl BerDecode for i64 {
202 fn decode(reader: &mut BerReader) -> Result<Self> {
203 reader.read_integer()
204 }
205}
206
207impl BerDecode for i32 {
208 fn decode(reader: &mut BerReader) -> Result<Self> {
209 let value = reader.read_integer()?;
210 i32::try_from(value).map_err(|_| BerError::IntegerConversion.into())
211 }
212}
213
214impl BerDecode for f64 {
215 fn decode(reader: &mut BerReader) -> Result<Self> {
216 reader.read_real()
217 }
218}
219
220impl BerDecode for String {
221 fn decode(reader: &mut BerReader) -> Result<Self> {
222 reader.read_utf8_string()
223 }
224}
225
226impl BerDecode for Vec<u8> {
227 fn decode(reader: &mut BerReader) -> Result<Self> {
228 reader.read_octet_string()
229 }
230}
231
232#[cfg(test)]
233mod tests {
234 use super::*;
235
236 #[test]
237 fn test_boolean_roundtrip() {
238 let encoded = encode(&true).unwrap();
239 let decoded: bool = decode(&encoded).unwrap();
240 assert!(decoded);
241
242 let encoded = encode(&false).unwrap();
243 let decoded: bool = decode(&encoded).unwrap();
244 assert!(!decoded);
245 }
246
247 #[test]
248 fn test_integer_roundtrip() {
249 for value in [0i64, 1, -1, 127, 128, -128, -129, 32767, -32768, i64::MAX, i64::MIN] {
250 let encoded = encode(&value).unwrap();
251 let decoded: i64 = decode(&encoded).unwrap();
252 assert_eq!(value, decoded);
253 }
254 }
255
256 #[test]
257 fn test_string_roundtrip() {
258 let value = "Hello, Ember+!".to_string();
259 let encoded = encode(&value).unwrap();
260 let decoded: String = decode(&encoded).unwrap();
261 assert_eq!(value, decoded);
262 }
263}