1use std::fmt;
29
30pub const MAX_BER_DEPTH: usize = 16;
32pub const MAX_BER_ELEMENTS: usize = 1024;
34
35pub const CLASS_UNIVERSAL: u8 = 0;
36pub const CLASS_APPLICATION: u8 = 1;
37pub const CLASS_CONTEXT: u8 = 2;
38pub const CLASS_PRIVATE: u8 = 3;
39
40pub const UNIV_BOOLEAN: u32 = 1;
42pub const UNIV_INTEGER: u32 = 2;
43pub const UNIV_BIT_STRING: u32 = 3;
44pub const UNIV_OCTET_STRING: u32 = 4;
45pub const UNIV_NULL: u32 = 5;
46pub const UNIV_OID: u32 = 6;
47pub const UNIV_EXTERNAL: u32 = 8;
48pub const UNIV_ENUMERATED: u32 = 10;
49pub const UNIV_SEQUENCE: u32 = 16;
50
51#[derive(Clone, Debug, PartialEq, Eq)]
54pub struct BerError(pub String);
55
56impl fmt::Display for BerError {
57 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58 write!(f, "BER: {}", self.0)
59 }
60}
61
62impl std::error::Error for BerError {}
63
64fn err<T>(msg: impl Into<String>) -> Result<T, BerError> {
65 Err(BerError(msg.into()))
66}
67
68#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
70pub struct Tag {
71 pub class: u8,
72 pub constructed: bool,
73 pub number: u32,
74}
75
76impl Tag {
77 pub const fn universal(number: u32, constructed: bool) -> Self {
78 Tag {
79 class: CLASS_UNIVERSAL,
80 constructed,
81 number,
82 }
83 }
84 pub const fn application(number: u32, constructed: bool) -> Self {
85 Tag {
86 class: CLASS_APPLICATION,
87 constructed,
88 number,
89 }
90 }
91 pub const fn context(number: u32, constructed: bool) -> Self {
92 Tag {
93 class: CLASS_CONTEXT,
94 constructed,
95 number,
96 }
97 }
98 pub const SEQUENCE: Tag = Tag::universal(UNIV_SEQUENCE, true);
99 pub const INTEGER: Tag = Tag::universal(UNIV_INTEGER, false);
100 pub const OCTET_STRING: Tag = Tag::universal(UNIV_OCTET_STRING, false);
101 pub const ENUMERATED: Tag = Tag::universal(UNIV_ENUMERATED, false);
102 pub const NULL: Tag = Tag::universal(UNIV_NULL, false);
103 pub const BOOLEAN: Tag = Tag::universal(UNIV_BOOLEAN, false);
104 pub const OID: Tag = Tag::universal(UNIV_OID, false);
105
106 pub fn same(&self, class: u8, number: u32) -> bool {
108 self.class == class && self.number == number
109 }
110
111 pub fn is_context(&self, number: u32) -> bool {
112 self.same(CLASS_CONTEXT, number)
113 }
114
115 pub fn is_universal(&self, number: u32) -> bool {
116 self.same(CLASS_UNIVERSAL, number)
117 }
118
119 pub fn encode(&self) -> Vec<u8> {
121 let first = (self.class << 6) | if self.constructed { 0x20 } else { 0 };
122 if self.number < 31 {
123 return vec![first | self.number as u8];
124 }
125 let mut out = vec![first | 0x1f];
126 let mut groups = Vec::new();
127 let mut n = self.number;
128 loop {
129 groups.push((n & 0x7f) as u8);
130 n >>= 7;
131 if n == 0 {
132 break;
133 }
134 }
135 for (i, g) in groups.iter().rev().enumerate() {
136 let more = i + 1 < groups.len();
137 out.push(if more { g | 0x80 } else { *g });
138 }
139 out
140 }
141
142 pub fn label(&self) -> String {
144 match self.class {
145 CLASS_CONTEXT => format!("[{}]", self.number),
146 CLASS_APPLICATION => format!("[APPLICATION {}]", self.number),
147 CLASS_PRIVATE => format!("[PRIVATE {}]", self.number),
148 _ => format!("UNIVERSAL {}", self.number),
149 }
150 }
151}
152
153#[derive(Clone, Debug, PartialEq, Eq)]
155pub struct Tlv {
156 pub tag: Tag,
157 pub value: Vec<u8>,
159 pub children: Vec<Tlv>,
161}
162
163impl Tlv {
164 pub fn primitive(tag: Tag, value: impl Into<Vec<u8>>) -> Self {
165 Tlv {
166 tag,
167 value: value.into(),
168 children: Vec::new(),
169 }
170 }
171
172 pub fn constructed(tag: Tag, children: Vec<Tlv>) -> Self {
173 Tlv {
174 tag,
175 value: Vec::new(),
176 children,
177 }
178 }
179
180 pub fn ctx(&self, number: u32) -> Option<&Tlv> {
182 self.children.iter().find(|c| c.tag.is_context(number))
183 }
184
185 pub fn univ(&self, number: u32) -> Option<&Tlv> {
187 self.children.iter().find(|c| c.tag.is_universal(number))
188 }
189
190 pub fn child(&self, class: u8, number: u32) -> Option<&Tlv> {
192 self.children.iter().find(|c| c.tag.same(class, number))
193 }
194
195 pub fn as_i64(&self) -> Result<i64, BerError> {
197 decode_integer(&self.value)
198 }
199
200 pub fn as_bool(&self) -> Result<bool, BerError> {
201 match self.value.as_slice() {
202 [b] => Ok(*b != 0),
203 _ => err(format!(
204 "BOOLEAN {} has {} octets, expected 1",
205 self.tag.label(),
206 self.value.len()
207 )),
208 }
209 }
210
211 pub fn encode(&self) -> Vec<u8> {
213 if self.tag.constructed {
214 let mut body = Vec::new();
215 for c in &self.children {
216 body.extend_from_slice(&c.encode());
217 }
218 tlv(self.tag, &body)
219 } else {
220 tlv(self.tag, &self.value)
221 }
222 }
223
224 pub fn child_labels(&self) -> Vec<String> {
226 self.children.iter().map(|c| c.tag.label()).collect()
227 }
228}
229
230pub fn tlv(tag: Tag, contents: &[u8]) -> Vec<u8> {
232 let mut out = tag.encode();
233 push_length(&mut out, contents.len());
234 out.extend_from_slice(contents);
235 out
236}
237
238pub fn seq(tag: Tag, children: &[Vec<u8>]) -> Vec<u8> {
240 let body: Vec<u8> = children.iter().flatten().copied().collect();
241 tlv(tag, &body)
242}
243
244fn push_length(out: &mut Vec<u8>, len: usize) {
245 if len < 0x80 {
246 out.push(len as u8);
247 } else {
248 let bytes = (len as u64).to_be_bytes();
249 let skip = bytes.iter().take_while(|b| **b == 0).count();
250 out.push(0x80 | (8 - skip) as u8);
251 out.extend_from_slice(&bytes[skip..]);
252 }
253}
254
255pub fn integer_contents(v: i64) -> Vec<u8> {
257 let bytes = v.to_be_bytes();
258 let mut start = 0;
259 while start < 7 {
260 let b = bytes[start];
261 let next = bytes[start + 1];
262 if (b == 0x00 && next & 0x80 == 0) || (b == 0xff && next & 0x80 != 0) {
263 start += 1;
264 } else {
265 break;
266 }
267 }
268 bytes[start..].to_vec()
269}
270
271pub fn integer(tag: Tag, v: i64) -> Vec<u8> {
272 tlv(tag, &integer_contents(v))
273}
274
275pub fn decode_integer(contents: &[u8]) -> Result<i64, BerError> {
276 if contents.is_empty() || contents.len() > 8 {
277 return err(format!(
278 "INTEGER of {} octets (1..8 accepted)",
279 contents.len()
280 ));
281 }
282 let mut v: i64 = if contents[0] & 0x80 != 0 { -1 } else { 0 };
283 for b in contents {
284 v = (v << 8) | *b as i64;
285 }
286 Ok(v)
287}
288
289pub fn oid_contents(arcs: &[u64]) -> Vec<u8> {
291 let mut out = Vec::new();
292 if arcs.len() < 2 {
293 return out;
294 }
295 let mut push = |mut v: u64| {
296 let mut groups = vec![(v & 0x7f) as u8];
297 v >>= 7;
298 while v > 0 {
299 groups.push(((v & 0x7f) as u8) | 0x80);
300 v >>= 7;
301 }
302 groups.reverse();
303 out.extend_from_slice(&groups);
304 };
305 push(arcs[0] * 40 + arcs[1]);
306 for a in &arcs[2..] {
307 push(*a);
308 }
309 out
310}
311
312pub fn decode_oid(contents: &[u8]) -> Result<Vec<u64>, BerError> {
314 if contents.is_empty() {
315 return err("empty OBJECT IDENTIFIER");
316 }
317 let mut arcs = Vec::new();
318 let mut v: u64 = 0;
319 let mut octets = 0;
320 for (i, b) in contents.iter().enumerate() {
321 octets += 1;
322 if octets > 8 {
323 return err("OBJECT IDENTIFIER arc longer than 8 octets");
324 }
325 v = (v << 7) | (*b & 0x7f) as u64;
326 if b & 0x80 == 0 {
327 if arcs.is_empty() {
328 let first = (v / 40).min(2);
329 arcs.push(first);
330 arcs.push(v - first * 40);
331 } else {
332 arcs.push(v);
333 }
334 if arcs.len() > 32 {
335 return err("OBJECT IDENTIFIER with more than 32 arcs");
336 }
337 v = 0;
338 octets = 0;
339 } else if i + 1 == contents.len() {
340 return err("OBJECT IDENTIFIER ends inside an arc");
341 }
342 }
343 Ok(arcs)
344}
345
346pub fn oid_string(arcs: &[u64]) -> String {
347 arcs.iter()
348 .map(|a| a.to_string())
349 .collect::<Vec<_>>()
350 .join(".")
351}
352
353pub struct Reader<'a> {
355 input: &'a [u8],
356 pos: usize,
357 elements: usize,
358}
359
360impl<'a> Reader<'a> {
361 pub fn new(input: &'a [u8]) -> Self {
362 Reader {
363 input,
364 pos: 0,
365 elements: 0,
366 }
367 }
368
369 fn byte(&mut self) -> Result<u8, BerError> {
370 let b = *self
371 .input
372 .get(self.pos)
373 .ok_or_else(|| BerError(format!("truncated at octet {}", self.pos)))?;
374 self.pos += 1;
375 Ok(b)
376 }
377
378 fn read_tag(&mut self) -> Result<Tag, BerError> {
379 let first = self.byte()?;
380 let class = first >> 6;
381 let constructed = first & 0x20 != 0;
382 let mut number = (first & 0x1f) as u32;
383 if number == 0x1f {
384 number = 0;
385 let mut count = 0;
386 loop {
387 let b = self.byte()?;
388 count += 1;
389 if count > 3 {
390 return err("tag number longer than 3 octets");
391 }
392 number = (number << 7) | (b & 0x7f) as u32;
393 if b & 0x80 == 0 {
394 break;
395 }
396 }
397 }
398 Ok(Tag {
399 class,
400 constructed,
401 number,
402 })
403 }
404
405 fn read_length(&mut self) -> Result<Option<usize>, BerError> {
407 let first = self.byte()?;
408 if first < 0x80 {
409 return Ok(Some(first as usize));
410 }
411 if first == 0x80 {
412 return Ok(None);
413 }
414 let n = (first & 0x7f) as usize;
415 if n > 4 {
416 return err(format!("length of {n} octets (at most 4 accepted)"));
417 }
418 let mut len = 0usize;
419 for _ in 0..n {
420 len = (len << 8) | self.byte()? as usize;
421 }
422 Ok(Some(len))
423 }
424
425 fn element(&mut self, depth: usize) -> Result<Tlv, BerError> {
427 if depth >= MAX_BER_DEPTH {
428 return err(format!(
429 "nesting deeper than {MAX_BER_DEPTH} levels at octet {}",
430 self.pos
431 ));
432 }
433 self.elements += 1;
434 if self.elements > MAX_BER_ELEMENTS {
435 return err(format!("more than {MAX_BER_ELEMENTS} elements"));
436 }
437 let start = self.pos;
438 let tag = self.read_tag()?;
439 let len = self.read_length()?;
440 match len {
441 Some(len) => {
442 let end = self.pos.checked_add(len).filter(|e| *e <= self.input.len());
443 let Some(end) = end else {
444 return err(format!(
445 "{} at octet {start} declares {len} octets, {} remain",
446 tag.label(),
447 self.input.len().saturating_sub(self.pos)
448 ));
449 };
450 if tag.constructed {
451 let mut children = Vec::new();
452 while self.pos < end {
453 children.push(self.bounded_child(end, depth + 1)?);
454 }
455 if self.pos != end {
456 return err(format!(
457 "{} at octet {start}: contents overrun the declared length",
458 tag.label()
459 ));
460 }
461 Ok(Tlv::constructed(tag, children))
462 } else {
463 let value = self.input[self.pos..end].to_vec();
464 self.pos = end;
465 Ok(Tlv::primitive(tag, value))
466 }
467 }
468 None => {
469 if !tag.constructed {
470 return err(format!(
471 "primitive {} at octet {start} uses the indefinite length form",
472 tag.label()
473 ));
474 }
475 let mut children = Vec::new();
476 loop {
477 if self.input.get(self.pos..self.pos + 2) == Some(&[0, 0]) {
478 self.pos += 2;
479 break;
480 }
481 if self.pos >= self.input.len() {
482 return err(format!(
483 "{} at octet {start}: no end-of-contents before the end",
484 tag.label()
485 ));
486 }
487 children.push(self.element(depth + 1)?);
488 }
489 Ok(Tlv::constructed(tag, children))
490 }
491 }
492 }
493
494 fn bounded_child(&mut self, end: usize, depth: usize) -> Result<Tlv, BerError> {
496 let saved = self.input;
497 self.input = &saved[..end];
498 let r = self.element(depth);
499 self.input = saved;
500 r
501 }
502}
503
504pub fn decode(input: &[u8]) -> Result<Tlv, BerError> {
506 let mut r = Reader::new(input);
507 let t = r.element(0)?;
508 if r.pos != input.len() {
509 return err(format!(
510 "{} trailing octets after the element",
511 input.len() - r.pos
512 ));
513 }
514 Ok(t)
515}
516
517pub fn decode_all(input: &[u8]) -> Result<Vec<Tlv>, BerError> {
519 let mut r = Reader::new(input);
520 let mut out = Vec::new();
521 while r.pos < input.len() {
522 out.push(r.element(0)?);
523 }
524 Ok(out)
525}
526
527pub fn hex(bytes: &[u8]) -> String {
529 bytes.iter().map(|b| format!("{b:02x}")).collect()
530}
531
532pub fn unhex(s: &str) -> Result<Vec<u8>, BerError> {
535 let s = s.trim();
536 if !s.len().is_multiple_of(2) || !s.chars().all(|c| c.is_ascii_hexdigit()) {
537 return err(format!("{s:?} is not an even-length hex string"));
538 }
539 Ok((0..s.len())
540 .step_by(2)
541 .map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap_or(0))
542 .collect())
543}
544
545pub fn shallow_children(input: &[u8]) -> Option<Vec<(Tag, &[u8])>> {
550 let mut r = Reader::new(input);
551 let _top = r.read_tag().ok()?;
552 let len = r.read_length().ok()??;
553 let end = r.pos.checked_add(len).filter(|e| *e <= input.len())?;
554 let mut out = Vec::new();
555 while r.pos < end && out.len() < MAX_BER_ELEMENTS {
556 let tag = r.read_tag().ok()?;
557 let len = r.read_length().ok()??;
558 let stop = r.pos.checked_add(len).filter(|e| *e <= end)?;
559 out.push((tag, &input[r.pos..stop]));
560 r.pos = stop;
561 }
562 Some(out)
563}