46个版本

0.17.0 2024年8月1日
0.16.2 2024年6月2日
0.16.1 2024年3月4日
0.15.5 2023年8月9日
0.1.0 2015年7月21日

#99解析器实现

Download history 44134/week @ 2024-05-03 40149/week @ 2024-05-10 42230/week @ 2024-05-17 42143/week @ 2024-05-24 47997/week @ 2024-05-31 41012/week @ 2024-06-07 41278/week @ 2024-06-14 46896/week @ 2024-06-21 41793/week @ 2024-06-28 42119/week @ 2024-07-05 42133/week @ 2024-07-12 51182/week @ 2024-07-19 50887/week @ 2024-07-26 49295/week @ 2024-08-02 51359/week @ 2024-08-09 50535/week @ 2024-08-16

215,317 每月下载量
用于 4 crates

BSD-3-Clause

185KB
4.5K SLoC

rust-asn1

Dependency Status Documentation

这是一个用于解析和生成ASN.1数据(仅DER)的Rust库。

安装

asn1添加到您的[dependencies]部分中的Cargo.toml

[dependencies]
asn1 = "0.17"

基于Rust 1.59.0及更高版本构建。

rust-asn1#![no_std]环境兼容

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

lib.rs:

这个crate为您提供了生成和解析ASN.1编码数据的能力。更准确地说,它为您提供了生成和解析使用ASN.1的DER(区分编码规则)编码的数据的能力。它不支持BER(基本编码规则)、CER(规范编码规则)、XER(XML编码规则)、CXER(规范XML编码规则)或其他任何字母汤编码——并且永远也不会。

如果您想解析如下所示的ASN.1结构

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

那么您将编写以下代码

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

通常,所有关于解析的内容都是由向Parser.read_element提供不同的类型参数驱动的。一些类型直接在基本类型上实现了Asn1Readable trait,如u64&[u8]OCTET STRING),而其他类型使用包装类型,这些类型只是为其他类型提供ASN.1编码和解码(如PrintableStringUtcTime)。还有如ImplicitExplicit这样的类型用于处理标记值,以及用于选择的Choice1Choice2Choice3,以及用于处理OPTIONAL值的Option<T>

要序列化DER的Sequence结构,你需要编写以下内容:

let result = asn1::write(|w| {
    w.write_element(&asn1::SequenceWriter::new(&|w| {
        w.write_element(&r)?;
        w.write_element(&s)?;
        Ok(())
    }))
});

派生

当使用derive特性构建时(默认启用),这些也可以表示为Rust结构体

#[derive(asn1::Asn1Read, asn1::Asn1Write)]
struct Signature {
    r: u64,
    s: u64,
}

let sig = asn1::parse_single::<Signature>(data);
let result = asn1::write_single(&Signature{r, s});

字段可以标记为EXPLICITIMPLICIT,通过结构体成员具有类型ExplicitImplicit,或者通过使用#[explicit]#[implicit]注解来实现

#[derive(asn1::Asn1Read, asn1::Asn1Write)]
struct SomeSequence<'a> {
    #[implicit(0)]
    a: Option<&'a [u8]>,
    #[explicit(1)]
    b: Option<u64>,
}

字段也可以使用#[default(VALUE)]注解来表示ASN.1的OPTIONAL DEFAULT值。在这种情况下,字段类型应该是T,而不是Option<T>

这些派生也可以与enum一起使用来生成CHOICE实现。

#[derive(asn1::Asn1Read, asn1::Asn1Write)]
enum Time {
    UTCTime(asn1::UtcTime),
    GeneralizedTime(asn1::GeneralizedTime)
}

所有变体都必须有一个未命名的字段。

定义

rust-asn1还为处理ASN.1结构中的ANY DEFINED BY情况提供了便捷的实用工具。例如,给定以下ASN.1;

MySequence ::= SEQUENCE {
    contentType OBJECT IDENTIFIER,
    content ANY DEFINED BY contentType
}

这可以表示为

#[derive(asn1::Asn1Read, asn1::Asn1Write)]
struct MySequence {
    content_type: asn1::DefinedByMarker<asn1::ObjectIdentifier>,
    #[defined_by(content_type)]
    content: Content,
}

#[derive(asn1::Asn1DefinedByRead, asn1::Asn1DefinedByWrite)]
enum Content {
    #[defined_by(SOME_OID_CONSTANT)]
    SomeVariant(i32),
}

设计理念

正如我们所设计的asn1crate,我们重视以下事物,按此顺序:

  • 安全性
  • 正确性
  • 性能
  • 易用性

依赖性

~260–710KB
~17K SLoC