1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
//! [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE-MIT)
//! [![Apache License 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](./LICENSE-APACHE)
//! [![docs.rs](https://docs.rs/asn1-rs/badge.svg)](https://docs.rs/asn1-rs)
//! [![crates.io](https://img.shields.io/crates/v/asn1-rs.svg)](https://crates.io/crates/asn1-rs)
//! [![Download numbers](https://img.shields.io/crates/d/asn1-rs.svg)](https://crates.io/crates/asn1-rs)
//! [![Github CI](https://github.com/rusticata/asn1-rs/workflows/Continuous%20integration/badge.svg)](https://github.com/rusticata/asn1-rs/actions)
//! [![Minimum rustc version](https://img.shields.io/badge/rustc-1.53.0+-lightgray.svg)](#rust-version-requirements)
//!
//! # BER/DER Parsers/Encoders
//!
//! A set of parsers/encoders for Basic Encoding Rules (BER [[X.690]]) and Distinguished Encoding Rules(DER
//! [[X.690]]) formats, 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.
//!
//! This crate is a rewrite of [der-parser](https://crates.io/crates/der-parser) to propose a more data-oriented API,
//! and add generalized support for serialization.
//!
//! Many ideas were borrowed from the [crypto/utils/der](https://github.com/RustCrypto/utils/tree/master/der) crate (like
//! the `Any`/`TryFrom`/`FromDer` mechanism), adapted and merged into a generalized BER/DER crate.
//! Credits (and many thanks) go to Tony Arcieri for writing the original crate.
//!
//! # BER/DER parsers
//!
//! BER stands for Basic Encoding Rules, and is defined in [[X.690]]. It defines a set of rules to
//! encode and decode ASN.1 [[X.680]] objects in binary.
//!
//! [[X.690]] also defines Distinguished Encoding Rules (DER), which is BER with added rules to
//! ensure canonical and unequivocal binary representation of objects.
//!
//! The choice of which one to use is usually guided by the speficication of the data format based
//! on BER or DER: for example, X.509 uses DER as encoding representation.
//!
//! The main traits for parsing are the [`FromBer`] and [`FromDer`] traits.
//! These traits provide methods to parse binary input, and return either the remaining (unparsed) bytes
//! and the parsed object, or an error.
//!
//! The parsers follow the interface from [nom], and the [`ParseResult`] object is a specialized version
//! of `nom::IResult`. This means that most `nom` combinators (`map`, `many0`, etc.) can be used in
//! combination to objects and methods from this crate. Reading the nom documentation may
//! help understanding how to write and combine parsers and use the output.
//!
//! **Minimum Supported Rust Version**: 1.53.0
//!
//! Note: if the `bits` feature is enabled, MSRV is 1.56.0 (due to `bitvec` 1.0)
//!
//! # Recipes
//!
//! See [doc::recipes] and [doc::derive] for more examples and recipes.
//!
//! ## Examples
//!
//! Parse 2 BER integers:
//!
//! ```rust
//! use asn1_rs::{Integer, FromBer};
//!
//! let bytes = [ 0x02, 0x03, 0x01, 0x00, 0x01,
//!               0x02, 0x03, 0x01, 0x00, 0x00,
//! ];
//!
//! let (rem, obj1) = Integer::from_ber(&bytes).expect("parsing failed");
//! let (rem, obj2) = Integer::from_ber(&bytes).expect("parsing failed");
//!
//! assert_eq!(obj1, Integer::from_u32(65537));
//! ```
//!
//! In the above example, the generic [`Integer`] type is used. This type can contain integers of any
//! size, but do not provide a simple API to manipulate the numbers.
//!
//! In most cases, the integer either has a limit, or is expected to fit into a primitive type.
//! To get a simple value, just use the `from_ber`/`from_der` methods on the primitive types:
//!
//! ```rust
//! use asn1_rs::FromBer;
//!
//! let bytes = [ 0x02, 0x03, 0x01, 0x00, 0x01,
//!               0x02, 0x03, 0x01, 0x00, 0x00,
//! ];
//!
//! let (rem, obj1) = u32::from_ber(&bytes).expect("parsing failed");
//! let (rem, obj2) = u32::from_ber(&rem).expect("parsing failed");
//!
//! assert_eq!(obj1, 65537);
//! assert_eq!(obj2, 65536);
//! ```
//!
//! If the parsing succeeds, but the integer cannot fit into the expected type, the method will return
//! an `IntegerTooLarge` error.
//!
//! # BER/DER encoders
//!
//! BER/DER encoding is symmetrical to decoding, using the traits `ToBer` and [`ToDer`] traits.
//! These traits provide methods to write encoded content to objects with the `io::Write` trait,
//! or return an allocated `Vec<u8>` with the encoded data.
//! If the serialization fails, an error is returned.
//!
//! ## Examples
//!
//! Writing 2 BER integers:
//!
//! ```rust
//! use asn1_rs::{Integer, ToDer};
//!
//! let mut writer = Vec::new();
//!
//! let obj1 = Integer::from_u32(65537);
//! let obj2 = Integer::from_u32(65536);
//!
//! let _ = obj1.write_der(&mut writer).expect("serialization failed");
//! let _ = obj2.write_der(&mut writer).expect("serialization failed");
//!
//! let bytes = &[ 0x02, 0x03, 0x01, 0x00, 0x01,
//!                0x02, 0x03, 0x01, 0x00, 0x00,
//! ];
//! assert_eq!(&writer, bytes);
//! ```
//!
//! Similarly to `FromBer`/`FromDer`, serialization methods are also implemented for primitive types:
//!
//! ```rust
//! use asn1_rs::ToDer;
//!
//! let mut writer = Vec::new();
//!
//! let _ = 65537.write_der(&mut writer).expect("serialization failed");
//! let _ = 65536.write_der(&mut writer).expect("serialization failed");
//!
//! let bytes = &[ 0x02, 0x03, 0x01, 0x00, 0x01,
//!                0x02, 0x03, 0x01, 0x00, 0x00,
//! ];
//! assert_eq!(&writer, bytes);
//! ```
//!
//! If the parsing succeeds, but the integer cannot fit into the expected type, the method will return
//! an `IntegerTooLarge` error.
//!
//! ## Changes
//!
//! See `CHANGELOG.md`.
//!
//! # References
//!
//! - [[X.680]] Abstract Syntax Notation One (ASN.1): Specification of basic notation.
//! - [[X.690]] ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical
//!   Encoding Rules (CER) and Distinguished Encoding Rules (DER).
//!
//! [X.680]: http://www.itu.int/rec/T-REC-X.680/en "Abstract Syntax Notation One (ASN.1):
//!   Specification of basic notation."
//! [X.690]: https://www.itu.int/rec/T-REC-X.690/en "ASN.1 encoding rules: Specification of
//!   Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished Encoding Rules
//!   (DER)."
//! [nom]: https://github.com/Geal/nom "Nom parser combinator framework"
#![deny(/*missing_docs,*/
    unstable_features,
    unused_import_braces,
    unused_qualifications,
    // unreachable_pub
)]
#![forbid(unsafe_code)]
#![warn(
/* missing_docs,
rust_2018_idioms,*/
missing_debug_implementations,
)]
// pragmas for doc
#![deny(rustdoc::broken_intra_doc_links)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc(test(
no_crate_inject,
attr(deny(warnings/*, rust_2018_idioms*/), allow(dead_code, unused_variables))
))]
#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(feature = "std")]
extern crate core;

// #[cfg(feature = "alloc")]
extern crate alloc;

mod asn1_types;
mod ber;
mod class;
mod datetime;
mod derive;
mod error;
mod header;
mod length;
mod tag;
mod traits;

pub use asn1_types::*;
pub use class::*;
pub use datetime::*;
pub use derive::*;
pub use error::*;
pub use header::*;
pub use length::*;
pub use tag::*;
pub use traits::*;

pub use nom;
pub use nom::{Err, IResult, Needed};

#[doc(hidden)]
pub mod exports {
    pub use alloc::borrow;
    pub use asn1_rs_impl;
}

#[cfg(doc)]
pub mod doc;