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)?;