A Rust ASN.1 (DER) serializer.

Overview

rust-asn1

Dependency Status

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.3"

Builds on Rust 1.41.0 and newer. However Implicit and Explicit require const generics, which require a recent nightly or beta (1.51.0) and specifying the const-generics feature.

rust-asn1 is compatible with #![no_std] environments:

asn1 = { version = "0.3", default-features = false }

Usage

To parse a structure like:

Signature ::= SEQUENCE {
    r INTEGER,
    s INTEGER
}

you would write:

let result = 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));
    })
});

match result {
    Ok((r, s)) => println!("r={}, s={}", r, s),
    Err(e) => println!("Error! {:?}", e),
}

And to write that structure, you would do:

let result = asn1::write(|w| {
    w.write_element_with_type::<asn1::Sequence>(&|w: &mut asn1::Writer| {
        w.write_element(r);
        w.write_element(s);
    })
});
Comments
  • Parsing DEFINED BY structure

    Parsing DEFINED BY structure

    I'am not finding any example on how to parse a sequnce like the following:

    QCStatement::= SEQUENCE {
        statementId OBJECT IDENTIFIER,
        statementInfo ANY DEFINED BY statementId OPTIONAL
    }
    

    I built a the structs like this:

    #[derive(Debug, asn1::Asn1Read, asn1::Asn1Write)]
    pub struct QCStatement<'a> {
        statement_id: asn1::ObjectIdentifier,
        statement_info: Option<StatementInfo<'a>>,
    }
    
    #[derive(Debug, asn1::Asn1Read, asn1::Asn1Write)]
    pub enum StatementInfo<'a> {
        QcEuRetentionPeriod(u32),
        MonetaryValue(MonetaryValue<'a>),
        QcType(QcType),
        PSD2QcType(PSD2QcType<'a>),
        QcEuPDS(PdsLocations<'a>),
    }
    

    The parser seems able to choose between the u32 and the MonetaryValue, but it's not able to choose between the complex types. As i get this error: thread 'main' panicked at 'calledResult::unwrap()on anErrvalue: ParseError { kind: UnexpectedTag { actual: Tag { value: 6, constructed: false, class: Universal } }, location: [4, "QCStatement::statement_info", "StatementInfo::MonetaryValue", "MonetaryValue::currency"] }'

    At this point I am trying to manually implement the parsing for the QCStatement<'a> as follows:

    impl<'a> SimpleAsn1Readable<'a> for QCStatement<'a> {
        const TAG: asn1::Tag = asn1::Tag::primitive(0x20);
        #[inline]
        fn parse_data(data: &'a [u8]) -> asn1::ParseResult<QCStatement<'a>> {
            asn1::parse_single::<QCStatement<'a>>(data)
            asn1::parse(data, |d| {
                let statement_id = d.read_element::<asn1::ObjectIdentifier>()?;
                let statement_info = match statement_id.to_string().as_str() {
                    "0.4.0.1862.1.2" => Option::Some(StatementInfo::MonetaryValue(
                        d.read_element::<MonetaryValue>()?,
                    )),
                    "0.4.0.1862.1.5" => {
                        Option::Some(StatementInfo::QcEuPDS(d.read_element::<PdsLocations>()?))
                    }
                    "0.4.0.1862.1.6" => {
                        Option::Some(StatementInfo::QcType(d.read_element::<QcType>()?))
                    }
                    "0.4.0.1862.1.3" => {
                        Option::Some(StatementInfo::QcEuRetentionPeriod(d.read_element::<u32>()?))
                    }
                    &_ => None,
                };
                return Ok(QCStatement::new(statement_id, statement_info));
            })
        }
    }
    

    But I'm not sure it's the intended way as it seems that even thought the struct are correct I constantly get unexpected tag.

    opened by mtodescato 11
  • Getting not implemented trait when having nested enums/CHOICE

    Getting not implemented trait when having nested enums/CHOICE

    Hello basically if i have a struct which contains an enum everything works: ``#[derive(asn1::Asn1Read, asn1::Asn1Write)] pub struct InfoAccessItem<'a> { oid: asn1::ObjectIdentifier, accessLocation: GeneralName<'a>, }

    #[derive(Debug, asn1::Asn1Read, asn1::Asn1Write)] pub enum GeneralName<'a> { #[implicit(0)] OtherName(asn1::IA5String<'a>), #[implicit(1)] Rfc822Name(asn1::IA5String<'a>), #[implicit(2)] DNSName(asn1::IA5String<'a>), #[implicit(3)] X400Address(asn1::IA5String<'a>), #[implicit(4)] DirectoryName(asn1::IA5String<'a>), #[implicit(5)] EdiPartyName(asn1::IA5String<'a>), #[implicit(6)] UniformResourceIdentifier(asn1::IA5String<'a>), #[implicit(7)] IPAddress(&'a [u8]), #[implicit(8)] RegisteredID(asn1::ObjectIdentifier), }``

    If i Have an Enum which contain another enum like this:

    ``#[derive(Debug, asn1::Asn1Read, asn1::Asn1Write)] pub struct DistributionPoint<'a> { #[implicit(0)] distributionPoint: Option<DistributionPointName<'a>>, #[implicit(1)] reasons: Option<asn1::BitString<'a>>, #[implicit(2)] crlissuer: Option<GeneralName<'a>>, }

    #[derive(Debug, asn1::Asn1Read, asn1::Asn1Write)] enum DistributionPointName<'a> { #[implicit(0)] FullName(GeneralName<'a>), #[implicit(1)] NameRelativeToCRLIssuer(RelativeDistinguishedName<'a>), }

    #[derive(asn1::Asn1Read, asn1::Asn1Write)] pub struct RelativeDistinguishedName<'a> { data: asn1::SequenceOf<'a, AttributeValueAssertion<'a>>, }

    #[derive(Debug, asn1::Asn1Read, asn1::Asn1Write)] pub struct AttributeValueAssertion<'a> { attribute_type: asn1::ObjectIdentifier, attribute_value: asn1::IA5String<'a>, }``

    Where General name is the same as the previous example, it gives me an error every nested enum as write and read asn1 trait not implemented. Am I doing something wrong or is it a bug?

    opened by mtodescato 11
  • Derive a SEQUENCE OF SEQUENCE?

    Derive a SEQUENCE OF SEQUENCE?

    I was able to derive some structs that deserialize correctly, but I'm struggling to figure out how to represent a SEQUENCE OF SEQUENCE in a struct. Is there an example of this anywhere? Is it possible, or do I need to write my own code with a d.read_element::<asn1::SequenceOf>() to do this?

    opened by joshwatson 7
  • Adding Parser.peek_explicit/implicit_tag()

    Adding Parser.peek_explicit/implicit_tag()

    The idea behind this change is such that when encoding an enum (via CHOICE) using tagging, you can determine which variant to read by peeking at the tag value without advancing the parser.

    peek_explicit_tag() and peek_implicit_tag() return a tuple like

    (<raw-tag>, <decoded-tag>)
    

    such that raw-tag is the tag as it is read directly from the input bytes, and decoded-tag is the tag converted into the same format that would be passed to Writer.write_explicit_element() or Writer.write_implicit_element().

    peek_implicit_tag() requires knowing the type you wish to decode up-front in order to retrieve an accurate decoded-tag value, as implicit tagging embeds the type within the tag.

    opened by orthecreedence 2
  • UTC no longer part of chrono

    UTC no longer part of chrono

    Looks like a bit of bitrot set in

    --> /home/jrconlin/.cargo/registry/src/github.com-1ecc6299db9ec823/asn1-0.1.0/src/lib.rs:9:24
      |
    9 | use chrono::{DateTime, UTC};
      |                        ^^^ no `UTC` in the root
    

    I'm not sure, but I belive that this is now Utc https://docs.rs/chrono/0.4.0/chrono/offset/struct.Utc.html

    opened by jrconlin 2
  • FieldDescription needs to be public

    FieldDescription needs to be public

    Hi Alex,

    In order to successfully use the current Signature example in the README.md, the FieldDescription struct and its fields need to be public, otherwise the expansion of the asn1! macro will fail.

    Easy fix ... although I don't know if this is your intention...

    Cheers Marcus

    opened by mheese 2
  • Try using macros for the API

    Try using macros for the API

    TODO:

    • [ ] CHOICE
    • [ ] INTEGER { v1(0), v2(1), v3(2) }
    • [ ] from_der() with OPTIONAL
    • [ ] from_der() with DEFAULT
    • [ ] from_der() with EXPLICIT tag
    • [ ] from_der() with IMPLICIT tag
    • [ ] to_der() with EXPLICIT tag
    • [ ] to_der() with IMPLICIT tag
    • [ ] Reference other SEQUENCE by name
    • [x] Multiple declerations in a single asn1!() call.
    • [ ] PrintableString
    • [ ] UTCTime
    • [ ] BIT STRING { x (0), y (1) }
    opened by alex 2
  • Bump actions/checkout from 3.1.0 to 3.2.0

    Bump actions/checkout from 3.1.0 to 3.2.0

    Bumps actions/checkout from 3.1.0 to 3.2.0.

    Release notes

    Sourced from actions/checkout's releases.

    v3.2.0

    What's Changed

    New Contributors

    Full Changelog: https://github.com/actions/checkout/compare/v3...v3.2.0

    Changelog

    Sourced from actions/checkout's changelog.

    Changelog

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies github_actions 
    opened by dependabot[bot] 1
  • Add relaxeddefault attribute

    Add relaxeddefault attribute

    Implement [#relaxeddefault(value)] attribute. The new attribute is an alternative to [#default(value)] that does not fail with ParseErrorKind::EncodedDefault when a component is encoded with default value.

    DER requires that encoding of a set value or sequence value shall not include an encoding for any component value which is equal to its default value. However some systems use BER-like syntax and encode components with default values. OpenSSL and NSS are more relaxed and don't fail.

    Signed-off-by: Christian Heimes [email protected]

    opened by tiran 1
  • Write TLV

    Write TLV

    I'm trying to write a Tlv value to a DER key, but I cannot figure out how. Is there any way to do this? Specifically, I am trying to write a NULL value. I don't see any public API to write any of this. Could there be an unsafe constructor added to the Tlv type? It implements Asn1Writable, but does not appear to be constructable.

    A NULL type would only be a partial fix in my opinion. It would be very helpful to be able to construct a Tlv in user space code.

    opened by macmv 1
  • Allow Asn1Writable types to provide their length

    Allow Asn1Writable types to provide their length

    Right now we reserve space for the length, call write(), see how much data was written, and fill it in (potentially resizing the storage if more than 127 bytes are written). We should allow types to pre-declare their size to avoid resizing.

    opened by alex 0
  • Write raw der

    Write raw der

    Hey! Thank you so much for your crate.

    I found a requirement to write a raw DER slice into the writer. Something like https://docs.rs/yasna/0.4.0/yasna/struct.DERWriter.html#method.write_der. Would you please implement it?

    opened by kpp 4
Owner
Alex Gaynor
I program computers, and build teams that program computers, with a heavy focus on security.
Alex Gaynor
MessagePack implementation for Rust / msgpack.org[Rust]

RMP - Rust MessagePack RMP is a pure Rust MessagePack implementation. This repository consists of three separate crates: the RMP core and two implemen

Evgeny Safronov 840 Dec 30, 2022
Implementation of Bencode encoding written in rust

Rust Bencode Implementation of Bencode encoding written in rust. Project Status Not in active developement due to lack of time and other priorities. I

Arjan Topolovec 32 Aug 6, 2022
Encoding and decoding support for BSON in Rust

bson-rs Encoding and decoding support for BSON in Rust Index Overview of BSON Format Usage BSON Values BSON Documents Modeling BSON with strongly type

mongodb 304 Dec 30, 2022
Rust library for reading/writing numbers in big-endian and little-endian.

byteorder This crate provides convenience methods for encoding and decoding numbers in either big-endian or little-endian order. Dual-licensed under M

Andrew Gallant 811 Jan 1, 2023
Cap'n Proto for Rust

Cap'n Proto for Rust documentation blog Introduction Cap'n Proto is a type system for distributed systems. With Cap'n Proto, you describe your data an

Cap'n Proto 1.5k Dec 26, 2022
A Gecko-oriented implementation of the Encoding Standard in Rust

encoding_rs encoding_rs an implementation of the (non-JavaScript parts of) the Encoding Standard written in Rust and used in Gecko (starting with Fire

Henri Sivonen 284 Dec 13, 2022
Character encoding support for Rust

Encoding 0.3.0-dev Character encoding support for Rust. (also known as rust-encoding) It is based on WHATWG Encoding Standard, and also provides an ad

Kang Seonghoon 264 Dec 14, 2022
Rust implementation of CRC(16, 32, 64) with support of various standards

crc Rust implementation of CRC(16, 32, 64). MSRV is 1.46. Usage Add crc to Cargo.toml [dependencies] crc = "2.0" Compute CRC use crc::{Crc, Algorithm,

Rui Hu 120 Dec 23, 2022
A CSV parser for Rust, with Serde support.

csv A fast and flexible CSV reader and writer for Rust, with support for Serde. Dual-licensed under MIT or the UNLICENSE. Documentation https://docs.r

Andrew Gallant 1.3k Jan 5, 2023
A HTTP Archive format (HAR) serialization & deserialization library, written in Rust.

har-rs HTTP Archive format (HAR) serialization & deserialization library, written in Rust. Install Add the following to your Cargo.toml file: [depende

Sebastian Mandrean 25 Dec 24, 2022
A HTML entity encoding library for Rust

A HTML entity encoding library for Rust Example usage All example assume a extern crate htmlescape; and use htmlescape::{relevant functions here}; is

Viktor Dahl 41 Nov 1, 2022
pem-rs pem PEM jcreekmore/pem-rs [pem] — A Rust based way to parse and encode PEM-encoded data

pem A Rust library for parsing and encoding PEM-encoded data. Documentation Module documentation with examples Usage Add this to your Cargo.toml: [dep

Jonathan Creekmore 30 Dec 27, 2022
PROST! a Protocol Buffers implementation for the Rust Language

PROST! prost is a Protocol Buffers implementation for the Rust Language. prost generates simple, idiomatic Rust code from proto2 and proto3 files. Com

Dan Burkert 17 Jan 8, 2023
Rust implementation of Google protocol buffers

rust-protobuf Protobuf implementation in Rust. Written in pure rust Generate rust code Has runtime library for generated code (Coded{Input|Output}Stre

Stepan Koltsov 2.3k Dec 31, 2022
tnetstring serialization library for rust.

TNetStrings: Tagged Netstrings This module implements bindings for the tnetstring serialization format. API let t = tnetstring::str("hello world"); le

Erick Tryzelaar 16 Jul 14, 2019
A TOML encoding/decoding library for Rust

toml-rs A TOML decoder and encoder for Rust. This library is currently compliant with the v0.5.0 version of TOML. This library will also likely contin

Alex Crichton 1k Dec 30, 2022
A fast, performant implementation of skip list in Rust.

Subway A fast, performant implementation of skip list in Rust. A skip list is probabilistic data structure that provides O(log N) search and insertion

Sushrut 16 Apr 5, 2022
A Rust PAC for the RP2040 Microcontroller

rp2040-pac - PAC for Raspberry Pi RP2040 microcontrollers This is a Peripheral Access Crate for the Raspberry Pi RP2040 dual-core Cortex-M0+ microcont

rp-rs 120 Nov 23, 2022
Pure Rust port of CRFsuite: a fast implementation of Conditional Random Fields (CRFs)

crfs-rs Pure Rust port of CRFsuite: a fast implementation of Conditional Random Fields (CRFs) Currently only support prediction, model training is not

messense 24 Nov 23, 2022