29 releases (8 breaking)
new 0.10.0 | Jul 4, 2022 |
---|---|
0.9.0 | Apr 29, 2022 |
0.8.7 | Nov 18, 2021 |
0.6.0 | Jul 17, 2021 |
0.1.0 | Jul 21, 2015 |
#6 in #asn1
85,364 downloads per month
140KB
3.5K
SLoC
rust-asn1
This is a Rust library for parsing and generating ASN.1 data (DER only).
Installation
Add asn1
to the [dependencies]
section of your Cargo.toml
:
[dependencies]
asn1 = "0.10"
Builds on Rust 1.47.0 and newer, but versions older than 1.51.0 require disabling the const-generics
feature, which allows using the Implicit
and Explicit
types.
rust-asn1
is compatible with #![no_std]
environments:
asn1 = { version = "0.10", default-features = false }
lib.rs
:
This crate provides you with the ability to generate and parse ASN.1 encoded data. More precisely, it provides you with the ability to generate and parse data encoded with ASN.1's DER (Distinguished Encoding Rules) encoding. It does not support BER (Basic Encoding Rules), CER (Canonical Encoding Rules), XER (XML Encoding Rules), CXER (Canonical XML Encoding Rules), or any other alphabet soup encodings -- and it never will.
If you wanted to parse an ASN.1 structure like this:
Signature ::= SEQUENCE {
r INTEGER,
s INTEGER
}
Then you'd write the following code:
# let data = b"";
let result: asn1::ParseResult<_> = asn1::parse(data, |d| {
return d.read_element::<asn1::Sequence>()?.parse(|d| {
let r = d.read_element::<u64>()?;
let s = d.read_element::<u64>()?;
return Ok((r, s));
})
});
In general everything about parsing is driven by providing different type
parameters to Parser.read_element
. Some types implement the
Asn1Readable
trait directly on a basic type, as seen with u64
or
&[u8]
(OCTET STRING
), while others use wrapper types which simply
provide ASN.1 encoding and decoding for some other type (PrintableString
or UtcTime
). There are also types such as Implicit
and Explicit
for
handling tagged values, Choice1
, Choice2
, and Choice3
available for
choices, and Option<T>
for handling OPTIONAL
values.
To serialize DER for the Sequence
structure, you'd write the following:
# let r = 0u64;
# let s = 0u64;
let result = asn1::write(|w| {
w.write_element(&asn1::SequenceWriter::new(&|w| {
w.write_element(&r);
w.write_element(&s);
}));
});
Derive
When built with the derive
feature (enabled by default), these can also
be expressed as Rust structs:
#[derive(asn1::Asn1Read, asn1::Asn1Write)]
struct Signature {
r: u64,
s: u64,
}
# let data = b"";
# let r = 0u64;
# let s = 0u64;
let sig = asn1::parse_single::<Signature>(data);
let result = asn1::write_single(&Signature{r, s});
On Rust >= 1.51.0, [Explicit
] and [Implicit
] tagging may be specified
with struct members of those types. However on Rust < 1.51.0, this is not
possible, since they require const generics. Instead, the #[implicit]
and #[explicit]
attributes may be used:
#[derive(asn1::Asn1Read, asn1::Asn1Write)]
struct SomeSequence<'a> {
#[implicit(0)]
a: Option<&'a [u8]>,
#[explicit(1)]
b: Option<u64>,
}
Fields can also be annotated with #[default(VALUE)]
to indicate ASN.1
OPTIONAL DEFAULT
values. In this case, the field's type should be T
,
and not Option<T>
.
These derives may also be used with enum
s to generate CHOICE
implementations.
#[derive(asn1::Asn1Read, asn1::Asn1Write)]
enum Time {
UTCTime(asn1::UtcTime),
GeneralizedTime(asn1::GeneralizedTime)
}
All variants must have a single un-named field.
Dependencies
~0.7–1MB
~15K SLoC