Expand description

Documentation: BER/DER parsing recipes

Builtin types

Most builtin types can be parsed by calling the from_der or from_der functions (see FromBer and FromDer traits for documentation).

For ex:

let (rem, result) = <u32>::from_der(input)?;

Note: this crates makes extensive use of types annotation and turbofish operator, for example <Type>::from_der() or TaggedExplicit::<u32, Error, 0>::from_der().

See table B-3 in https://doc.rust-lang.org/book/appendix-02-operators.html for reference on syntax.

SEQUENCE and SET

The SEQUENCE and SET types are handled very similarly, so recipes will be given for SEQUENCE, but can be adapted to SET by replacing words.

Parsing SEQUENCE

Usually, the sequence envelope does not need to be stored, so it just needs to be parsed to get the sequence content and parse it. The methods from_ber_and_then and from_der_and_then provide helpers for that:

let (rem, result) = Sequence::from_ber_and_then(input, |i| {
    // first item is INTEGER
    let (rem, a) = u32::from_der(input)?;
    // second item is OCTET STRING
    let (rem, b) = <&[u8]>::from_der(input)?;
    Ok((rem, (a, b)))
})?;
// result has type (u32, &[u8])
assert_eq!(result.0, 0);
assert_eq!(result.1, b"\x00\x01");

Automatically deriving sequence parsers

The BerSequence and DerSequence custom derive provide attributes to automatically derive a parser for a sequence.

For ex:

#[derive(DerSequence)]
pub struct S {
    a: u32,
    b: u16,
    c: u16,
}

let (rem, result) = S::from_der(input)?;

This will work for any field type that implements FromBer or FromDer, respectively.

See derive documentation for more examples and documentation.

Parsing SEQUENCE OF

SEQUENCE OF T can be parsed using either type SequenceOf<T> or Vec<T>:

let (rem, result) = SequenceOf::<u32>::from_der(input)?;

or

let (rem, result) = <Vec<u32>>::from_der(input)?;

SET OF T can be parsed using either SetOf<T>, BTreeSet<T> or HashSet<T>.

EXPLICIT tagged values

Parsing EXPLICIT, expecting a known tag

If you expect only a specific tag, use TaggedExplicit.

For ex, to parse a [3] EXPLICIT INTEGER:

let (rem, result) = TaggedExplicit::<u32, Error, 0>::from_der(input)?;
// result has type TaggedValue. Use `.as_ref()` or `.into_inner()` 
// to access content
let tag = result.tag();
let class = result.class();
assert_eq!(result.as_ref(), &0);

Specifying the class

TaggedExplicit does not check the class, and accepts any class. It expects you to check the class after reading the value.

To specify the class in the parser, use TaggedValue:

// Note: the strange notation (using braces) is required by the compiler to use
// a constant instead of the numeric value.
let (rem, result) = TaggedValue::<u32, Error, Explicit, {Class::CONTEXT_SPECIFIC}, 0>::from_der(input)?;

Note that TaggedExplicit is a type alias to TaggedValue, so the objects are the same.

Accepting any EXPLICIT tag

To parse a value, accepting any class or tag, use TaggedParser.

let (rem, result) = TaggedParser::<Explicit, u32>::from_der(input)?;
// result has type TaggedParser. Use `.as_ref()` or `.into_inner()` 
// to access content
let tag = result.tag();
let class = result.class();
assert_eq!(result.as_ref(), &0);

Optional tagged values

To parse optional tagged values, Option<TaggedExplicit<...>> can be used:

let (rem, result) = Option::<TaggedExplicit::<u32, Error, 0>>::from_der(input)?;

The type OptTaggedExplicit is also provided as an alias:

let (rem, result) = OptTaggedExplicit::<u32, Error, 0>::from_der(input)?;

IMPLICIT tagged values

Parsing IMPLICIT, expecting a known tag

If you expect only a specific tag, use TaggedImplicit.

For ex, to parse a [3] EXPLICIT INTEGER:

let (rem, result) = TaggedExplicit::<u32, Error, 0>::from_der(input)?;
// result has type TaggedValue. Use `.as_ref()` or `.into_inner()` 
// to access content
let tag = result.tag();
let class = result.class();
assert_eq!(result.as_ref(), &0);

Specifying the class

TaggedImplicit does not check the class, and accepts any class. It expects you to check the class after reading the value.

To specify the class in the parser, use TaggedValue:

// Note: the strange notation (using braces) is required by the compiler to use
// a constant instead of the numeric value.
let (rem, result) = TaggedValue::<u32, Error, Implicit, { Class::CONTEXT_SPECIFIC }, 1>::from_der(input)?;

Note that TaggedImplicit is a type alias to TaggedValue, so the objects are the same.

Accepting any IMPLICIT tag

To parse a value, accepting any class or tag, use TaggedParser.

let (rem, result) = TaggedParser::<Implicit, u32>::from_der(input)?;
// result has type TaggedParser. Use `.as_ref()` or `.into_inner()` 
// to access content
let tag = result.tag();
let class = result.class();
assert_eq!(result.as_ref(), &0);

Optional tagged values

To parse optional tagged values, Option<TaggedImplicit<...>> can be used:

let (rem, result) = Option::<TaggedImplicit::<u32, Error, 0>>::from_der(input)?;

The type OptTaggedImplicit is also provided as an alias:

let (rem, result) = OptTaggedImplicit::<u32, Error, 0>::from_der(input)?;