1use rustlavel_core::{Error, Result};
32
33pub const UNIVERSAL: u8 = 0x00;
35pub const APPLICATION: u8 = 0x40;
37pub const CONTEXT: u8 = 0x80;
39pub const CONSTRUCTED: u8 = 0x20;
41
42pub const BOOLEAN: u8 = 0x01;
43pub const INTEGER: u8 = 0x02;
44pub const OCTET_STRING: u8 = 0x04;
45pub const NULL: u8 = 0x05;
46pub const ENUMERATED: u8 = 0x0a;
47pub const SEQUENCE: u8 = 0x30;
48pub const SET: u8 = 0x31;
49
50pub const fn application(number: u8, constructed: bool) -> u8 {
52 APPLICATION | if constructed { CONSTRUCTED } else { 0 } | number
53}
54
55pub const fn context(number: u8, constructed: bool) -> u8 {
57 CONTEXT | if constructed { CONSTRUCTED } else { 0 } | number
58}
59
60pub const MAX_DEPTH: usize = 32;
67
68#[derive(Default)]
80pub struct Encoder {
81 bytes: Vec<u8>,
82}
83
84impl Encoder {
85 pub fn new() -> Encoder {
86 Encoder::default()
87 }
88
89 pub fn as_bytes(&self) -> &[u8] {
90 &self.bytes
91 }
92
93 pub fn into_bytes(self) -> Vec<u8> {
94 self.bytes
95 }
96
97 pub fn len(&self) -> usize {
98 self.bytes.len()
99 }
100
101 pub fn is_empty(&self) -> bool {
102 self.bytes.is_empty()
103 }
104
105 pub fn element(&mut self, tag: u8, contents: &[u8]) -> &mut Encoder {
107 self.bytes.push(tag);
108 encode_length(contents.len(), &mut self.bytes);
109 self.bytes.extend_from_slice(contents);
110 self
111 }
112
113 pub fn constructed(&mut self, tag: u8, body: impl FnOnce(&mut Encoder)) -> &mut Encoder {
115 debug_assert!(tag & CONSTRUCTED != 0, "a constructed element needs its constructed bit");
116 let mut inner = Encoder::new();
117 body(&mut inner);
118 self.element(tag, &inner.bytes)
119 }
120
121 pub fn sequence(&mut self, body: impl FnOnce(&mut Encoder)) -> &mut Encoder {
122 self.constructed(SEQUENCE, body)
123 }
124
125 pub fn set(&mut self, body: impl FnOnce(&mut Encoder)) -> &mut Encoder {
126 self.constructed(SET, body)
127 }
128
129 pub fn integer(&mut self, value: i64) -> &mut Encoder {
130 self.tagged_integer(INTEGER, value)
131 }
132
133 pub fn enumerated(&mut self, value: i64) -> &mut Encoder {
134 self.tagged_integer(ENUMERATED, value)
135 }
136
137 pub fn tagged_integer(&mut self, tag: u8, value: i64) -> &mut Encoder {
139 self.element(tag, &integer_contents(value))
140 }
141
142 pub fn boolean(&mut self, value: bool) -> &mut Encoder {
148 self.element(BOOLEAN, &[if value { 0xff } else { 0x00 }])
149 }
150
151 pub fn octet_string(&mut self, contents: &[u8]) -> &mut Encoder {
152 self.element(OCTET_STRING, contents)
153 }
154
155 pub fn string(&mut self, value: &str) -> &mut Encoder {
157 self.element(OCTET_STRING, value.as_bytes())
158 }
159
160 pub fn tagged_string(&mut self, tag: u8, value: &str) -> &mut Encoder {
163 self.element(tag, value.as_bytes())
164 }
165
166 pub fn null(&mut self) -> &mut Encoder {
167 self.element(NULL, &[])
168 }
169
170 pub fn raw(&mut self, encoded: &[u8]) -> &mut Encoder {
172 self.bytes.extend_from_slice(encoded);
173 self
174 }
175}
176
177fn encode_length(length: usize, out: &mut Vec<u8>) {
179 if length < 0x80 {
180 out.push(length as u8);
181 return;
182 }
183
184 let bytes = length.to_be_bytes();
185 let first = bytes.iter().position(|&byte| byte != 0).unwrap_or(bytes.len() - 1);
186 let significant = &bytes[first..];
187
188 out.push(0x80 | significant.len() as u8);
189 out.extend_from_slice(significant);
190}
191
192fn integer_contents(value: i64) -> Vec<u8> {
194 let mut bytes = value.to_be_bytes().to_vec();
195
196 while bytes.len() > 1 {
197 let redundant = (bytes[0] == 0x00 && bytes[1] & 0x80 == 0)
200 || (bytes[0] == 0xff && bytes[1] & 0x80 != 0);
201 if !redundant {
202 break;
203 }
204 bytes.remove(0);
205 }
206
207 bytes
208}
209
210fn read_header(bytes: &[u8]) -> Result<Option<(u8, usize, usize)>> {
222 let Some(&tag) = bytes.first() else {
223 return Ok(None);
224 };
225
226 if tag & 0x1f == 0x1f {
227 return Err(Error::msg(
228 "BER high-tag-number form is refused: LDAP's highest tag number is 25, so a \
229 multi-byte tag is not something a directory has any way to mean",
230 ));
231 }
232
233 let Some(&first) = bytes.get(1) else {
234 return Ok(None);
235 };
236
237 if first == 0x80 {
238 return Err(Error::msg(
239 "BER indefinite length is refused: RFC 4511 §5.1 uses the definite form only, and a \
240 message whose end has to be searched for is a message whose end can be moved",
241 ));
242 }
243
244 if first < 0x80 {
245 return Ok(Some((tag, 2, first as usize)));
246 }
247
248 let count = (first & 0x7f) as usize;
249 if count > 4 {
250 return Err(Error::msg(format!(
251 "BER length is spread over {count} octets. Nothing in an LDAP message is four \
252 gigabytes long, so this is a header worth refusing rather than believing"
253 )));
254 }
255
256 if bytes.len() < 2 + count {
257 return Ok(None);
258 }
259
260 let mut length = 0usize;
261 for &byte in &bytes[2..2 + count] {
262 length = (length << 8) | byte as usize;
263 }
264
265 if length < 0x80 || bytes[2] == 0 {
266 return Err(Error::msg(format!(
267 "BER length {length} is not in its shortest form. X.690 requires one encoding per \
268 number; a padded one is a second spelling, and two spellings is how two parsers \
269 come to disagree about the same bytes"
270 )));
271 }
272
273 Ok(Some((tag, 2 + count, length)))
274}
275
276pub fn element_size(bytes: &[u8], limit: usize) -> Result<Option<usize>> {
284 let Some((_, header, length)) = read_header(bytes)? else {
285 return Ok(None);
286 };
287
288 let total = header
289 .checked_add(length)
290 .ok_or_else(|| Error::msg("BER element length overflows a usize"))?;
291
292 if total > limit {
293 return Err(Error::msg(format!(
294 "the directory announced a {total} byte message; the limit is {limit}. Raise it \
295 deliberately with `LdapConfig::max_message_size` if a legitimate search really \
296 does return that much"
297 )));
298 }
299
300 if bytes.len() < total {
301 return Ok(None);
302 }
303
304 Ok(Some(total))
305}
306
307pub struct Decoder<'a> {
313 bytes: &'a [u8],
314 position: usize,
315 depth: usize,
316}
317
318impl<'a> Decoder<'a> {
319 pub fn new(bytes: &'a [u8]) -> Decoder<'a> {
320 Decoder { bytes, position: 0, depth: 0 }
321 }
322
323 pub fn is_empty(&self) -> bool {
324 self.position >= self.bytes.len()
325 }
326
327 pub fn remaining(&self) -> &'a [u8] {
328 &self.bytes[self.position..]
329 }
330
331 pub fn peek_tag(&self) -> Option<u8> {
336 self.bytes.get(self.position).copied()
337 }
338
339 pub fn has_tag(&self, tag: u8) -> bool {
340 self.peek_tag() == Some(tag)
341 }
342
343 pub fn element(&mut self) -> Result<(u8, &'a [u8])> {
345 let rest = &self.bytes[self.position..];
346
347 let (tag, header, length) = read_header(rest)?
348 .ok_or_else(|| Error::msg("BER ended in the middle of an element header"))?;
349
350 let end = header
351 .checked_add(length)
352 .ok_or_else(|| Error::msg("BER element length overflows a usize"))?;
353
354 if end > rest.len() {
355 return Err(Error::msg(format!(
356 "a BER element claims {length} content bytes but only {} remain in the message",
357 rest.len() - header
358 )));
359 }
360
361 self.position += end;
362 Ok((tag, &rest[header..end]))
363 }
364
365 pub fn expect(&mut self, tag: u8) -> Result<&'a [u8]> {
367 let found = self.peek_tag();
368 let (actual, contents) = self.element()?;
369 if actual != tag {
370 return Err(Error::msg(format!(
371 "expected a BER element tagged {tag:#04x} but found {:#04x}",
372 found.unwrap_or(actual)
373 )));
374 }
375 Ok(contents)
376 }
377
378 pub fn nested(&mut self, tag: u8) -> Result<Decoder<'a>> {
380 if self.depth + 1 > MAX_DEPTH {
381 return Err(Error::msg(format!(
382 "BER nested deeper than {MAX_DEPTH} levels; a filter that deep is not one a \
383 directory built"
384 )));
385 }
386 let contents = self.expect(tag)?;
387 Ok(Decoder { bytes: contents, position: 0, depth: self.depth + 1 })
388 }
389
390 pub fn sequence(&mut self) -> Result<Decoder<'a>> {
391 self.nested(SEQUENCE)
392 }
393
394 pub fn set(&mut self) -> Result<Decoder<'a>> {
395 self.nested(SET)
396 }
397
398 pub fn integer(&mut self) -> Result<i64> {
399 integer_from(self.expect(INTEGER)?)
400 }
401
402 pub fn enumerated(&mut self) -> Result<i64> {
403 integer_from(self.expect(ENUMERATED)?)
404 }
405
406 pub fn boolean(&mut self) -> Result<bool> {
407 match self.expect(BOOLEAN)? {
408 [byte] => Ok(*byte != 0),
409 other => Err(Error::msg(format!(
410 "a BER BOOLEAN has {} content octets; it must have exactly one",
411 other.len()
412 ))),
413 }
414 }
415
416 pub fn octet_string(&mut self) -> Result<&'a [u8]> {
417 self.expect(OCTET_STRING)
418 }
419
420 pub fn string(&mut self) -> Result<String> {
426 let bytes = self.octet_string()?;
427 utf8(bytes)
428 }
429
430 pub fn tagged_string(&mut self, tag: u8) -> Result<String> {
432 let bytes = self.expect(tag)?;
433 utf8(bytes)
434 }
435
436 pub fn skip(&mut self) -> Result<()> {
442 self.element().map(|_| ())
443 }
444
445 pub fn finish(&self, what: &str) -> Result<()> {
450 if !self.is_empty() {
451 return Err(Error::msg(format!(
452 "{what} had {} trailing bytes after a complete value",
453 self.bytes.len() - self.position
454 )));
455 }
456 Ok(())
457 }
458}
459
460pub fn integer_from(contents: &[u8]) -> Result<i64> {
462 let Some((&first, rest)) = contents.split_first() else {
463 return Err(Error::msg("a BER INTEGER has no content octets; it must have at least one"));
464 };
465
466 if contents.len() > 8 {
467 return Err(Error::msg(format!(
468 "a BER INTEGER of {} octets does not fit in an i64; nothing LDAP defines is that \
469 wide",
470 contents.len()
471 )));
472 }
473
474 if let Some(&second) = rest.first()
478 && ((first == 0x00 && second & 0x80 == 0) || (first == 0xff && second & 0x80 != 0))
479 {
480 return Err(Error::msg(
481 "a BER INTEGER has a redundant leading octet; X.690 requires the shortest form",
482 ));
483 }
484
485 let mut value = first as i8 as i64;
486 for &byte in rest {
487 value = (value << 8) | byte as i64;
488 }
489 Ok(value)
490}
491
492fn utf8(bytes: &[u8]) -> Result<String> {
493 String::from_utf8(bytes.to_vec())
494 .map_err(|_| Error::msg("an LDAPString from the directory is not valid UTF-8"))
495}
496
497#[cfg(test)]
498mod tests {
499 use super::*;
500
501 fn encoded(body: impl FnOnce(&mut Encoder)) -> Vec<u8> {
502 let mut encoder = Encoder::new();
503 body(&mut encoder);
504 encoder.into_bytes()
505 }
506
507 fn failure<T>(result: Result<T>) -> String {
510 match result {
511 Ok(_) => panic!("expected this to fail"),
512 Err(error) => error.to_string(),
513 }
514 }
515
516 #[test]
517 fn integers_use_the_shortest_two_s_complement_form() {
518 assert_eq!(encoded(|e| { e.integer(0); }), vec![0x02, 0x01, 0x00]);
521 assert_eq!(encoded(|e| { e.integer(127); }), vec![0x02, 0x01, 0x7f]);
522 assert_eq!(encoded(|e| { e.integer(128); }), vec![0x02, 0x02, 0x00, 0x80]);
523 assert_eq!(encoded(|e| { e.integer(256); }), vec![0x02, 0x02, 0x01, 0x00]);
524 assert_eq!(encoded(|e| { e.integer(-1); }), vec![0x02, 0x01, 0xff]);
525 assert_eq!(encoded(|e| { e.integer(-128); }), vec![0x02, 0x01, 0x80]);
526 assert_eq!(encoded(|e| { e.integer(-129); }), vec![0x02, 0x02, 0xff, 0x7f]);
527 assert_eq!(
528 encoded(|e| { e.integer(i64::MAX); }),
529 vec![0x02, 0x08, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]
530 );
531 }
532
533 #[test]
534 fn integers_round_trip_through_their_encoding() {
535 for value in [0, 1, -1, 127, 128, -128, -129, 255, 256, 65_535, 65_536, -65_536] {
536 let bytes = encoded(|e| {
537 e.integer(value);
538 });
539 assert_eq!(Decoder::new(&bytes).integer().unwrap(), value, "{value}");
540 }
541 for value in [i64::MIN, i64::MAX, i32::MIN as i64, i32::MAX as i64] {
542 let bytes = encoded(|e| {
543 e.integer(value);
544 });
545 assert_eq!(Decoder::new(&bytes).integer().unwrap(), value, "{value}");
546 }
547 }
548
549 #[test]
550 fn a_padded_integer_is_refused_rather_than_read_leniently() {
551 let error = Decoder::new(&[0x02, 0x02, 0x00, 0x7f]).integer().unwrap_err().to_string();
555 assert!(error.contains("redundant leading octet"), "got {error}");
556
557 let error = Decoder::new(&[0x02, 0x02, 0xff, 0x80]).integer().unwrap_err().to_string();
558 assert!(error.contains("redundant leading octet"), "got {error}");
559
560 let error = Decoder::new(&[0x02, 0x00]).integer().unwrap_err().to_string();
562 assert!(error.contains("no content octets"), "got {error}");
563 }
564
565 #[test]
566 fn booleans_strings_and_sequences_encode_the_way_x690_says() {
567 assert_eq!(encoded(|e| { e.boolean(true); }), vec![0x01, 0x01, 0xff]);
568 assert_eq!(encoded(|e| { e.boolean(false); }), vec![0x01, 0x01, 0x00]);
569 assert_eq!(encoded(|e| { e.string("abc"); }), vec![0x04, 0x03, b'a', b'b', b'c']);
570 assert_eq!(encoded(|e| { e.string(""); }), vec![0x04, 0x00]);
571 assert_eq!(encoded(|e| { e.sequence(|_| {}); }), vec![0x30, 0x00]);
572 assert_eq!(encoded(|e| { e.enumerated(49); }), vec![0x0a, 0x01, 0x31]);
573
574 let nested = encoded(|e| {
575 e.sequence(|body| {
576 body.integer(1);
577 body.string("x");
578 });
579 });
580 assert_eq!(nested, vec![0x30, 0x06, 0x02, 0x01, 0x01, 0x04, 0x01, b'x']);
581 }
582
583 #[test]
584 fn long_lengths_use_as_few_octets_as_the_number_needs() {
585 let short = encoded(|e| {
588 e.octet_string(&[0u8; 127]);
589 });
590 assert_eq!(&short[..2], &[0x04, 0x7f]);
591
592 let long = encoded(|e| {
593 e.octet_string(&[0u8; 128]);
594 });
595 assert_eq!(&long[..3], &[0x04, 0x81, 0x80]);
596
597 let longer = encoded(|e| {
598 e.octet_string(&[0u8; 300]);
599 });
600 assert_eq!(&longer[..4], &[0x04, 0x82, 0x01, 0x2c]);
601
602 assert_eq!(Decoder::new(&longer).octet_string().unwrap().len(), 300);
603 }
604
605 #[test]
606 fn a_padded_length_is_refused() {
607 let error =
609 Decoder::new(&[0x04, 0x82, 0x00, 0x03, 1, 2, 3]).octet_string().unwrap_err().to_string();
610 assert!(error.contains("shortest form"), "got {error}");
611
612 let error =
614 Decoder::new(&[0x04, 0x81, 0x03, 1, 2, 3]).octet_string().unwrap_err().to_string();
615 assert!(error.contains("shortest form"), "got {error}");
616 }
617
618 #[test]
619 fn indefinite_lengths_are_refused_rather_than_parsed() {
620 let error = failure(Decoder::new(&[0x30, 0x80, 0x02, 0x01, 0x01, 0x00, 0x00]).sequence());
623 assert!(error.contains("indefinite"), "got {error}");
624 }
625
626 #[test]
627 fn a_multi_byte_tag_is_refused() {
628 let error = Decoder::new(&[0x1f, 0x81, 0x00, 0x00]).element().unwrap_err().to_string();
629 assert!(error.contains("high-tag-number"), "got {error}");
630 }
631
632 #[test]
633 fn a_length_longer_than_the_message_is_refused_before_allocating() {
634 let error = Decoder::new(&[0x04, 0x84, 0x01, 0x00, 0x00, 0x00, 0x00])
637 .octet_string()
638 .unwrap_err()
639 .to_string();
640 assert!(error.contains("only"), "got {error}");
641 }
642
643 #[test]
644 fn deep_nesting_is_bounded() {
645 let mut bytes = vec![0x30, 0x00];
648 for _ in 0..MAX_DEPTH + 2 {
649 let mut outer = vec![0x30, bytes.len() as u8];
650 outer.extend_from_slice(&bytes);
651 bytes = outer;
652 }
653
654 fn descend(decoder: &mut Decoder<'_>) -> Result<()> {
655 let mut inner = decoder.sequence()?;
656 if !inner.is_empty() {
657 descend(&mut inner)?;
658 }
659 Ok(())
660 }
661
662 let error = descend(&mut Decoder::new(&bytes)).unwrap_err().to_string();
663 assert!(error.contains("nested deeper"), "got {error}");
664 }
665
666 #[test]
667 fn truncation_anywhere_is_an_error_and_never_a_panic() {
668 let complete = encoded(|e| {
671 e.sequence(|body| {
672 body.integer(7);
673 body.string("hello");
674 body.boolean(true);
675 });
676 });
677
678 for length in 0..complete.len() {
679 let mut decoder = Decoder::new(&complete[..length]);
680 let read = (|| -> Result<()> {
681 let mut inner = decoder.sequence()?;
682 inner.integer()?;
683 inner.string()?;
684 inner.boolean()?;
685 Ok(())
686 })();
687 assert!(read.is_err(), "a {length} byte prefix should not parse");
688 }
689 }
690
691 #[test]
692 fn framing_says_not_yet_rather_than_guessing() {
693 let message = encoded(|e| {
694 e.sequence(|body| {
695 body.integer(1);
696 body.string("abcdefghij");
697 });
698 });
699
700 for length in 0..message.len() {
702 assert_eq!(
703 element_size(&message[..length], 1 << 20).unwrap(),
704 None,
705 "{length} bytes should not frame a complete message"
706 );
707 }
708 assert_eq!(element_size(&message, 1 << 20).unwrap(), Some(message.len()));
709
710 let mut two = message.clone();
712 two.extend_from_slice(&message);
713 assert_eq!(element_size(&two, 1 << 20).unwrap(), Some(message.len()));
714 }
715
716 #[test]
717 fn framing_refuses_an_oversized_message_before_buffering_it() {
718 let header = [0x30, 0x84, 0x04, 0x00, 0x00, 0x00];
721 let error = element_size(&header, 1 << 20).unwrap_err().to_string();
722 assert!(error.contains("the limit is"), "got {error}");
723 }
724
725 #[test]
726 fn a_wrong_tag_names_both_tags() {
727 let bytes = encoded(|e| {
728 e.string("not an integer");
729 });
730 let error = Decoder::new(&bytes).integer().unwrap_err().to_string();
731 assert!(error.contains("0x02") && error.contains("0x04"), "got {error}");
732 }
733
734 #[test]
735 fn trailing_bytes_after_a_value_are_refused() {
736 let bytes = encoded(|e| {
737 e.sequence(|body| {
738 body.integer(1);
739 body.integer(2);
740 });
741 });
742 let mut sequence = Decoder::new(&bytes).sequence().unwrap();
743 sequence.integer().unwrap();
744 assert!(sequence.finish("the sequence").is_err());
745 sequence.integer().unwrap();
746 assert!(sequence.finish("the sequence").is_ok());
747 }
748
749 #[test]
750 fn context_and_application_tags_are_built_from_their_parts() {
751 assert_eq!(application(0, true), 0x60);
754 assert_eq!(application(1, true), 0x61);
755 assert_eq!(application(2, false), 0x42);
756 assert_eq!(application(23, true), 0x77);
757 assert_eq!(context(0, false), 0x80);
758 assert_eq!(context(0, true), 0xa0);
759 assert_eq!(context(7, false), 0x87);
760 }
761
762 #[test]
763 fn a_non_utf8_ldapstring_is_refused_but_a_raw_value_is_not() {
764 let bytes = encoded(|e| {
765 e.octet_string(&[0xff, 0xfe]);
766 });
767 assert!(Decoder::new(&bytes).string().is_err());
768 assert_eq!(Decoder::new(&bytes).octet_string().unwrap(), &[0xff, 0xfe]);
771 }
772}