[−][src]Crate der_parser
BER/DER Parser
A parser for Basic Encoding Rules (BER [X.690]) and Distinguished Encoding Rules(DER [X.690]), implemented with the nom parser combinator framework.
It is written in pure Rust, fast, and makes extensive use of zero-copy. A lot of care is taken to ensure security and safety of this crate, including design (recursion limit, defensive programming), tests, and fuzzing. It also aims to be panic-free.
Historically, this parser was intended for DER only, and BER support was added later. This may
still reflect on some naming schemes, but has no other consequence: the BerObject
and
DerObject
used in this crate are type aliases, so all functions are compatible.
DER parsing functions have additional constraints verification, however.
Serialization has also been added (see Serialization )
The code is available on Github and is part of the Rusticata project.
DER parser design
Parsing functions are inspired from nom
, and follow the same interface. The most common
return type is BerResult
, that stores the remaining bytes and
parsed BerObject
, or an error. Reading the nom documentation may
help understanding how to write parsers and use the output.
There are two different approaches for parsing DER objects: reading the objects recursively as long as the tags are known, or specifying a description of the expected objects (generally from the ASN.1 description).
The first parsing method can be done using the parse_ber
and
parse_der
methods.
It is useful when decoding an arbitrary DER object.
However, it cannot fully parse all objects, especially those containing IMPLICIT, OPTIONAL, or
DEFINED BY items.
use der_parser::parse_der; let bytes = [ 0x30, 0x0a, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, ]; let parsed = parse_der(&bytes);
The second (and preferred) parsing method is to specify the expected objects recursively. The following functions can be used:
parse_ber_sequence_defined
and similar functions for sequences and sets variantsparse_ber_tagged_explicit
for tagged explicitparse_ber_tagged_implicit
for tagged implicitparse_ber_container
for generic parsing, etc.
For example, to read a sequence containing two integers:
use der_parser::ber::*; use der_parser::error::BerResult; fn localparse_seq(i:&[u8]) -> BerResult { parse_ber_sequence_defined(|data| { let (rem, a) = parse_ber_integer(data)?; let (rem, b) = parse_ber_integer(rem)?; Ok((rem, vec![a, b])) })(i) } let bytes = [ 0x30, 0x0a, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x03, 0x01, 0x00, 0x00, ]; let (_, parsed) = localparse_seq(&bytes).expect("parsing failed"); assert_eq!(parsed[0].as_u64(), Ok(65537)); assert_eq!(parsed[1].as_u64(), Ok(65536));
All functions return a BerResult
object: the parsed
BerObject
, an Incomplete
value, or an error.
Note that this type is also a Result
, so usual functions (map
, unwrap
etc.) are available.
Notes
BER/DER Integers
DER integers can be of any size, so it is not possible to store them as simple integers (they are stored as raw bytes).
To get a simple value, use BerObject::as_u32
(knowning that this method will return an error if the integer is too large),
BerObject::as_u64
, or use the bigint
feature of
this crate and use BerObject::as_bigint
.
use der_parser::ber::*; let data = &[0x02, 0x03, 0x01, 0x00, 0x01]; let (_, object) = parse_ber_integer(data).expect("parsing failed"); assert_eq!(object.as_u64(), Ok(65537));
Access to the raw value is possible using the as_slice
method.
Parsers, combinators, macros
Some parsing tools (for ex for tagged objects) are available in different forms:
- parsers: (regular) functions that takes input and create an object
- combinators: functions that takes parsers (or combinators) as input, and return a function (usually, the parser). They are used (combined) as building blocks to create more complex parsers.
- macros: these are generally previous (historic) versions of parsers, kept for compatibility. They can sometime reduce the amount of code to write, but are hard to debug. Parsers should be preferred when possible.
Misc Notes
- The DER constraints are verified if using
parse_der
. BerObject
andDerObject
are the same objects (type alias). The only difference is the verification of constraints during parsing.
Rust version requirements
The 5.0 series of der-parser
requires Rustc version 1.44 or greater, based on nom 6
dependencies.
Serialization
Support for encoding BER/DER objects is currently being tested and can be used by activating the serialize
feature.
Note that current status is experimental.
See the ber_encode_*
functions in the ber
module, and
BerObject::to_vec
References
Re-exports
pub extern crate nom; |
pub extern crate num_bigint; |
Modules
ber | Basic Encoding Rules (BER) objects and parser |
der | Distinguished Encoding Rules (DER) objects and parser |
error | Error type for BER/DER parsers |
oid | Object ID (OID) representations. |
Macros
oid | Procedural macro to get encoded oids, see the oid module. |
parse_der_application | Parse an application DER element |
parse_der_optional | Parse an optional DER element |
parse_der_sequence_defined | Parse a defined sequence of DER elements |
parse_der_sequence_defined_m | Deprecated Parse a defined sequence of DER elements (deprecated) |
parse_der_sequence_of | Parse a sequence of identical DER elements |
parse_der_set_defined | Parse a defined set of DER elements |
parse_der_set_defined_m | Deprecated Parse a defined set of DER elements (deprecated) |
parse_der_set_of | Parse a set of identical DER elements |
parse_der_struct | Parse a constructed DER element |
parse_der_tagged | Parse a tagged DER element |
Functions
parse_ber | Parse BER object recursively |
parse_der | Parse DER object recursively |
Type Definitions
IResult | Holds the result of parsing functions |