Skip to main content

netget/server/m3ua/
ber.rs

1//! A bounded BER reader and writer (ITU-T X.690) for the subset TCAP, MAP and CAP use.
2//!
3//! Hand-written rather than generated: the SS7 upper layers need perhaps forty ASN.1 types out of
4//! the thousands in 3GPP TS 29.002 and 29.078, every one of them a SEQUENCE of tagged OCTET
5//! STRINGs, INTEGERs, ENUMERATEDs, NULLs and nested SEQUENCEs. A generic tree of [`Tlv`] plus
6//! per-operation field mappings (`map.rs`, `cap.rs`) is a few hundred lines; `rasn` with the 3GPP
7//! modules would be thousands of generated types and a second copy of a crate the tree already
8//! carries at another version for SNMP.
9//!
10//! # Bounds
11//!
12//! BER is recursive and a peer chooses the nesting, so every decode carries a depth and an
13//! element budget:
14//!
15//! - [`MAX_BER_DEPTH`] constructed levels. The deepest real structure here (TCAP → component
16//!   portion → invoke → MAP argument → SubscriberInfo → LocationInformation → CHOICE) is about 9.
17//! - [`MAX_BER_ELEMENTS`] TLVs per decode, so a flat message of zero-length elements cannot cost
18//!   more than a fixed amount of work.
19//! - Lengths are checked against the octets actually present before anything is allocated;
20//!   indefinite lengths are accepted (some stacks use them for the dialogue portion) and their
21//!   end-of-contents is found within the same budget.
22//! - Tag numbers are limited to three subsequent octets (2^21), far above anything a 3GPP module
23//!   uses (CAP's highest is 59).
24//!
25//! Nothing here allocates more than the input already occupies, and no input can recurse past
26//! the depth bound — the recursion takes a `depth` parameter and refuses at the bound.
27
28use std::fmt;
29
30/// Constructed nesting levels a decode will follow.
31pub const MAX_BER_DEPTH: usize = 16;
32/// TLVs a single decode may produce, counted across every level.
33pub 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
40/// Universal tag numbers used here.
41pub 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/// A BER decode failure. The text names the position and what was wrong; it goes to the log,
52/// never to the peer.
53#[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/// An identifier octet group: class, primitive/constructed, tag number.
69#[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    /// Whether `self` is `other` irrespective of the primitive/constructed bit.
107    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    /// The identifier octets.
120    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    /// A short human-readable form, e.g. `[2]`, `[APPLICATION 11]`, `UNIVERSAL 4`.
143    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/// One decoded TLV.
154#[derive(Clone, Debug, PartialEq, Eq)]
155pub struct Tlv {
156    pub tag: Tag,
157    /// Primitive contents; empty for a constructed element.
158    pub value: Vec<u8>,
159    /// Children of a constructed element.
160    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    /// The first child with this context-specific tag number.
181    pub fn ctx(&self, number: u32) -> Option<&Tlv> {
182        self.children.iter().find(|c| c.tag.is_context(number))
183    }
184
185    /// The first child with this universal tag number.
186    pub fn univ(&self, number: u32) -> Option<&Tlv> {
187        self.children.iter().find(|c| c.tag.is_universal(number))
188    }
189
190    /// The first child with exactly this class and number.
191    pub fn child(&self, class: u8, number: u32) -> Option<&Tlv> {
192        self.children.iter().find(|c| c.tag.same(class, number))
193    }
194
195    /// INTEGER / ENUMERATED contents as a signed value (at most 8 octets).
196    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    /// Re-encode with definite lengths.
212    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    /// The tags present among this element's children, for reporting what was not interpreted.
225    pub fn child_labels(&self) -> Vec<String> {
226        self.children.iter().map(|c| c.tag.label()).collect()
227    }
228}
229
230/// Encode one TLV with a definite length.
231pub 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
238/// Encode a constructed TLV from already-encoded children.
239pub 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
255/// Minimal two's-complement INTEGER contents.
256pub 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
289/// OBJECT IDENTIFIER contents from arcs.
290pub 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
312/// Arcs from OBJECT IDENTIFIER contents. At most 32 arcs, each within 56 bits.
313pub 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
353/// A cursor over BER octets carrying the element budget shared across one decode.
354pub 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    /// `None` for the indefinite form.
406    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    /// Read one element, following constructed contents down to `MAX_BER_DEPTH`.
426    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    /// A child that must end by `end`.
495    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
504/// Decode exactly one element occupying all of `input`.
505pub 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
517/// Decode a run of elements occupying all of `input` (contents of an implicit SEQUENCE).
518pub 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
527/// Hex rendering for identifiers that have no other natural text form (transaction ids, LMSI).
528pub fn hex(bytes: &[u8]) -> String {
529    bytes.iter().map(|b| format!("{b:02x}")).collect()
530}
531
532/// Parse a hex identifier the model supplied. Only for fields that are opaque identifiers by
533/// nature; every encoded value is built from structured fields instead.
534pub 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
545/// The direct children of the one element in `input`, by tag and contents, without descending
546/// into any of them. Definite lengths only. For recovering a transaction id from a message whose
547/// full decode was refused (a depth bomb must still be answered with a P-Abort), so it does no
548/// recursion at all.
549pub 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}