1 //! Pure Rust embedded-friendly implementation of the Distinguished Encoding Rules (DER)
2 //! for Abstract Syntax Notation One (ASN.1) as described in ITU [X.690].
3 //!
4 //! # About
5 //!
6 //! This crate provides a `no_std`-friendly implementation of a subset of ASN.1
7 //! DER necessary for decoding/encoding various cryptography-related formats
8 //! implemented as part of the [RustCrypto] project, e.g. the [`pkcs5`] and
9 //! [`pkcs8`] crates.
10 //!
11 //! The core implementation avoids any heap usage (with convenience methods
12 //! that allocate gated under the off-by-default `alloc` feature).
13 //!
14 //! # Minimum Supported Rust Version
15 //!
16 //! This crate requires **Rust 1.51** at a minimum.
17 //!
18 //! We may change the MSRV in the future, but it will be accompanied by a minor
19 //! version bump.
20 //!
21 //! # Usage
22 //!
23 //! ## [`Decodable`] and [`Encodable`] traits
24 //!
25 //! The [`Decodable`] and [`Encodable`] traits are the core abstractions on
26 //! which this crate is built and control what types can be (de)serialized
27 //! as ASN.1 DER.
28 //!
29 //! The traits are impl'd for the following Rust core types:
30 //!
31 //! - `()`: ASN.1 `NULL` (see also [`Null`])
32 //! - [`bool`]: ASN.1 `BOOLEAN`
33 //! - [`i8`], [`i16`], [`i32`], [`i64`], [`i128`]: ASN.1 `INTEGER`
34 //! - [`u8`], [`u16`], [`u32`], [`u64`], [`u128`]: ASN.1 `INTEGER`
35 //! - [`str`], [`String`][`alloc::string::String`]: ASN.1 `UTF8String`
36 //!   (see also [`Utf8String`]. `String` requires `alloc` feature)
37 //! - [`BTreeSet`][`alloc::collections::BTreeSet`]: ASN.1 `SET OF` (requires `alloc` feature)
38 //! - [`Option`]: ASN.1 `OPTIONAL`
39 //! - [`SystemTime`][`std::time::SystemTime`]: ASN.1 `GeneralizedTime` (requires `std` feature)
40 //!
41 //! The following ASN.1 types provided by this crate also impl these traits:
42 //!
43 //! - [`Any`]: ASN.1 `ANY`
44 //! - [`BitString`]: ASN.1 `BIT STRING`
45 //! - [`GeneralizedTime`]: ASN.1 `GeneralizedTime`
46 //! - [`Ia5String`]: ASN.1 `IA5String`
47 //! - [`Null`]: ASN.1 `NULL`
48 //! - [`ObjectIdentifier`]: ASN.1 `OBJECT IDENTIFIER`
49 //! - [`OctetString`]: ASN.1 `OCTET STRING`
50 //! - [`PrintableString`]: ASN.1 `PrintableString` (ASCII subset)
51 //! - [`Sequence`]: ASN.1 `SEQUENCE`
52 //! - [`SetOfRef`]: ASN.1 `SET OF`
53 //! - [`UIntBytes`]: ASN.1 unsigned `INTEGER` with raw access to encoded bytes
54 //! - [`UtcTime`]: ASN.1 `UTCTime`
55 //! - [`Utf8String`]: ASN.1 `UTF8String`
56 //!
57 //! ## Example
58 //!
59 //! The following example implements X.509's `AlgorithmIdentifier` message type
60 //! as defined in [RFC 5280 Section 4.1.1.2].
61 //!
62 //! The ASN.1 schema for this message type is as follows:
63 //!
64 //! ```text
65 //! AlgorithmIdentifier  ::=  SEQUENCE  {
66 //!      algorithm               OBJECT IDENTIFIER,
67 //!      parameters              ANY DEFINED BY algorithm OPTIONAL  }
68 //! ```
69 //!
70 //! Structured ASN.1 messages are typically encoded as a `SEQUENCE`, which
71 //! this crate maps to a Rust struct using the [`Message`] trait. This
72 //! trait is bounded on the [`Decodable`] trait and provides a blanket impl
73 //! of the [`Encodable`] trait, so any type which impls [`Message`] can be
74 //! used for both decoding and encoding.
75 //!
76 //! The [`Decoder`] and [`Encoder`] types provide the decoding/encoding API
77 //! respectively, and are designed to work in conjunction with concrete ASN.1
78 //! types which impl the [`Decodable`] and [`Encodable`] traits, including
79 //! all types which impl the [`Message`] trait.
80 //!
81 //! The following code example shows how to define a struct which maps to the
82 //! above schema, as well as impl the [`Message`] trait for that struct:
83 //!
84 //! ```
85 //! # #[cfg(all(feature = "alloc", feature = "oid"))]
86 //! # {
87 //! // Note: the following example does not require the `std` feature at all.
88 //! // It does leverage the `alloc` feature, but also provides instructions for
89 //! // "heapless" usage when the `alloc` feature is disabled.
90 //! use core::convert::{TryFrom, TryInto};
91 //! use der::{
92 //!     asn1::{Any, ObjectIdentifier},
93 //!     Decodable, Encodable, Message
94 //! };
95 //!
96 //! /// X.509 `AlgorithmIdentifier`.
97 //! #[derive(Copy, Clone, Debug, Eq, PartialEq)]
98 //! pub struct AlgorithmIdentifier<'a> {
99 //!     /// This field contains an ASN.1 `OBJECT IDENTIFIER`, a.k.a. OID.
100 //!     pub algorithm: ObjectIdentifier,
101 //!
102 //!     /// This field is `OPTIONAL` and contains the ASN.1 `ANY` type, which
103 //!     /// in this example allows arbitrary algorithm-defined parameters.
104 //!     pub parameters: Option<Any<'a>>
105 //! }
106 //!
107 //! // Note: types which impl `TryFrom<Any<'a>, Error = der::Error>` receive a
108 //! // blanket impl of the `Decodable` trait, therefore satisfying the
109 //! // `Decodable` trait bounds on `Message`, which is impl'd below.
110 //! impl<'a> TryFrom<Any<'a>> for AlgorithmIdentifier<'a> {
111 //!    type Error = der::Error;
112 //!
113 //!     fn try_from(any: Any<'a>) -> der::Result<AlgorithmIdentifier> {
114 //!         // The `Any::sequence` method asserts that an `Any` value
115 //!         // contains an ASN.1 `SEQUENCE` then calls the provided `FnOnce`
116 //!         // with a `der::Decoder` which can be used to decode it.
117 //!         any.sequence(|decoder| {
118 //!             // The `der::Decoder::Decode` method can be used to decode any
119 //!             // type which impls the `Decodable` trait, which is impl'd for
120 //!             // all of the ASN.1 built-in types in the `der` crate.
121 //!             //
122 //!             // Note that if your struct's fields don't contain an ASN.1
123 //!             // built-in type specifically, there are also helper methods
124 //!             // for all of the built-in types supported by this library
125 //!             // which can be used to select a specific type.
126 //!             //
127 //!             // For example, another way of decoding this particular field,
128 //!             // which contains an ASN.1 `OBJECT IDENTIFIER`, is by calling
129 //!             // `decoder.oid()`. Similar methods are defined for other
130 //!             // ASN.1 built-in types.
131 //!             let algorithm = decoder.decode()?;
132 //!
133 //!             // This field contains an ASN.1 `OPTIONAL` type. The `der` crate
134 //!             // maps this directly to Rust's `Option` type and provides
135 //!             // impls of the `Decodable` and `Encodable` traits for `Option`.
136 //!             // To explicitly request an `OPTIONAL` type be decoded, use the
137 //!             // `decoder.optional()` method.
138 //!             let parameters = decoder.decode()?;
139 //!
140 //!             // The value returned from the provided `FnOnce` will be
141 //!             // returned from the `any.sequence(...)` call above.
142 //!             // Note that the entire sequence body *MUST* be consumed
143 //!             // or an error will be returned.
144 //!             Ok(Self { algorithm, parameters })
145 //!         })
146 //!     }
147 //! }
148 //!
149 //! impl<'a> Message<'a> for AlgorithmIdentifier<'a> {
150 //!     // The `Message::fields` method is used for encoding and functions as
151 //!     // a visitor for all of the fields in a message.
152 //!     //
153 //!     // To implement it, you must define a slice containing `Encodable`
154 //!     // trait objects, then pass it to the provided `field_encoder`
155 //!     // function, which is implemented by the `der` crate and handles
156 //!     // message serialization.
157 //!     //
158 //!     // Trait objects are used because they allow for slices containing
159 //!     // heterogeneous field types, and a callback is used to allow for the
160 //!     // construction of temporary field encoder types. The latter means
161 //!     // that the fields of your Rust struct don't necessarily need to
162 //!     // impl the `Encodable` trait, but if they don't you must construct
163 //!     // a temporary wrapper value which does.
164 //!     //
165 //!     // Types which impl the `Message` trait receive blanket impls of both
166 //!     // the `Encodable` and `Tagged` traits (where the latter is impl'd as
167 //!     // `Tagged::TAG = der::Tag::Sequence`.
168 //!     fn fields<F, T>(&self, field_encoder: F) -> der::Result<T>
169 //!     where
170 //!         F: FnOnce(&[&dyn Encodable]) -> der::Result<T>,
171 //!     {
172 //!         field_encoder(&[&self.algorithm, &self.parameters])
173 //!     }
174 //! }
175 //!
176 //! // Example parameters value: OID for the NIST P-256 elliptic curve.
177 //! let parameters = "1.2.840.10045.3.1.7".parse::<ObjectIdentifier>().unwrap();
178 //!
179 //! // We need to convert `parameters` into an `Any<'a>` type, which wraps a
180 //! // `&'a [u8]` byte slice.
181 //! //
182 //! // To do that, we need owned DER-encoded data so that we can have
183 //! // `Any` borrow a reference to it, so we have to serialize the OID.
184 //! //
185 //! // When the `alloc` feature of this crate is enabled, any type that impls
186 //! // the `Encodable` trait including all ASN.1 built-in types and any type
187 //! // which impls `Message` can be serialized by calling `Encodable::to_vec()`.
188 //! //
189 //! // If you would prefer to avoid allocations, you can create a byte array
190 //! // as backing storage instead, pass that to `der::Encoder::new`, and then
191 //! // encode the `parameters` value using `encoder.encode(parameters)`.
192 //! let der_encoded_parameters = parameters.to_vec().unwrap();
193 //!
194 //! let algorithm_identifier = AlgorithmIdentifier {
195 //!     // OID for `id-ecPublicKey`, if you're curious
196 //!     algorithm: "1.2.840.10045.2.1".parse().unwrap(),
197 //!
198 //!     // `Any<'a>` impls `TryFrom<&'a [u8]>`, which parses the provided
199 //!     // slice as an ASN.1 DER-encoded message.
200 //!     parameters: Some(der_encoded_parameters.as_slice().try_into().unwrap())
201 //! };
202 //!
203 //! // Serialize the `AlgorithmIdentifier` created above as ASN.1 DER,
204 //! // allocating a `Vec<u8>` for storage.
205 //! //
206 //! // As mentioned earlier, if you don't have the `alloc` feature enabled you
207 //! // can create a fix-sized array instead, then call `Encoder::new` with a
208 //! // reference to it, then encode the message using
209 //! // `encoder.encode(algorithm_identifier)`, then finally `encoder.finish()`
210 //! // to obtain a byte slice containing the encoded message.
211 //! let der_encoded_algorithm_identifier = algorithm_identifier.to_vec().unwrap();
212 //!
213 //! // Deserialize the `AlgorithmIdentifier` we just serialized from ASN.1 DER
214 //! // using `der::Decodable::from_bytes`.
215 //! let decoded_algorithm_identifier = AlgorithmIdentifier::from_der(
216 //!     &der_encoded_algorithm_identifier
217 //! ).unwrap();
218 //!
219 //! // Ensure the original `AlgorithmIdentifier` is the same as the one we just
220 //! // decoded from ASN.1 DER.
221 //! assert_eq!(algorithm_identifier, decoded_algorithm_identifier);
222 //! # }
223 //! ```
224 //!
225 //! ## Custom derive support
226 //!
227 //! When the `derive` feature of this crate is enabled, the following custom
228 //! derive macros are available:
229 //!
230 //! - [`Choice`]: derive for `CHOICE` enum (see [`der_derive::Choice`])
231 //! - [`Message`]: derive for `SEQUENCE` struct (see [`der_derive::Message`])
232 //!
233 //! ### Derive [`Message`] for `SEQUENCE` struct
234 //!
235 //! The following is a code example of how to use the [`Message`] custom derive:
236 //!
237 //! ```
238 //! # #[cfg(all(feature = "alloc", feature = "derive", feature = "oid"))]
239 //! # {
240 //! use der::{asn1::{Any, ObjectIdentifier}, Encodable, Decodable, Message};
241 //! use core::convert::TryInto;
242 //!
243 //! /// X.509 `AlgorithmIdentifier` (same as above)
244 //! #[derive(Copy, Clone, Debug, Eq, PartialEq, Message)] // NOTE: added `Message`
245 //! pub struct AlgorithmIdentifier<'a> {
246 //!     /// This field contains an ASN.1 `OBJECT IDENTIFIER`, a.k.a. OID.
247 //!     pub algorithm: ObjectIdentifier,
248 //!
249 //!     /// This field is `OPTIONAL` and contains the ASN.1 `ANY` type, which
250 //!     /// in this example allows arbitrary algorithm-defined parameters.
251 //!     pub parameters: Option<Any<'a>>
252 //! }
253 //!
254 //! // Example parameters value: OID for the NIST P-256 elliptic curve.
255 //! let parameters = "1.2.840.10045.3.1.7".parse::<ObjectIdentifier>().unwrap();
256 //! let der_encoded_parameters = parameters.to_vec().unwrap();
257 //!
258 //! let algorithm_identifier = AlgorithmIdentifier {
259 //!     // OID for `id-ecPublicKey`, if you're curious
260 //!     algorithm: "1.2.840.10045.2.1".parse().unwrap(),
261 //!
262 //!     // `Any<'a>` impls `TryFrom<&'a [u8]>`, which parses the provided
263 //!     // slice as an ASN.1 DER-encoded message.
264 //!     parameters: Some(der_encoded_parameters.as_slice().try_into().unwrap())
265 //! };
266 //!
267 //! // Encode
268 //! let der_encoded_algorithm_identifier = algorithm_identifier.to_vec().unwrap();
269 //!
270 //! // Decode
271 //! let decoded_algorithm_identifier = AlgorithmIdentifier::from_der(
272 //!     &der_encoded_algorithm_identifier
273 //! ).unwrap();
274 //!
275 //! assert_eq!(algorithm_identifier, decoded_algorithm_identifier);
276 //! # }
277 //! ```
278 //!
279 //! For fields which don't directly impl [`Decodable`] and [`Encodable`],
280 //! you can add annotations to convert to an intermediate ASN.1 type
281 //! first, so long as that type impls `TryFrom` and `Into` for the
282 //! ASN.1 type.
283 //!
284 //! For example, structs containing `&'a [u8]` fields may want them encoded
285 //! as either a `BIT STRING` or `OCTET STRING`. By using the
286 //! `#[asn1(type = "BIT STRING")]` annotation it's possible to select which
287 //! ASN.1 type should be used.
288 //!
289 //! Building off the above example:
290 //!
291 //! ```rust
292 //! # #[cfg(all(feature = "alloc", feature = "derive", feature = "oid"))]
293 //! # {
294 //! # use der::{asn1::{Any, ObjectIdentifier}, Message};
295 //! #
296 //! # #[derive(Copy, Clone, Debug, Eq, PartialEq, Message)]
297 //! # pub struct AlgorithmIdentifier<'a> {
298 //! #     pub algorithm: ObjectIdentifier,
299 //! #     pub parameters: Option<Any<'a>>
300 //! # }
301 //! /// X.509 `SubjectPublicKeyInfo` (SPKI)
302 //! #[derive(Copy, Clone, Debug, Eq, PartialEq, Message)]
303 //! pub struct SubjectPublicKeyInfo<'a> {
304 //!     /// X.509 `AlgorithmIdentifier`
305 //!     pub algorithm: AlgorithmIdentifier<'a>,
306 //!
307 //!     /// Public key data
308 //!     #[asn1(type = "BIT STRING")]
309 //!     pub subject_public_key: &'a [u8],
310 //! }
311 //! # }
312 //! ```
313 //!
314 //! # See also
315 //!
316 //! For more information about ASN.1 DER we recommend the following guides:
317 //!
318 //! - [A Layman's Guide to a Subset of ASN.1, BER, and DER] (RSA Laboratories)
319 //! - [A Warm Welcome to ASN.1 and DER] (Let's Encrypt)
320 //!
321 //! [X.690]: https://www.itu.int/rec/T-REC-X.690/
322 //! [RustCrypto]: https://github.com/rustcrypto
323 //! [`pkcs5`]: https://docs.rs/pkcs5/
324 //! [`pkcs8`]: https://docs.rs/pkcs8/
325 //! [RustCrypto/utils#370]: https://github.com/RustCrypto/utils/issues/370
326 //! [RFC 5280 Section 4.1.1.2]: https://tools.ietf.org/html/rfc5280#section-4.1.1.2
327 //! [A Layman's Guide to a Subset of ASN.1, BER, and DER]: https://luca.ntop.org/Teaching/Appunti/asn1.html
328 //! [A Warm Welcome to ASN.1 and DER]: https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/
329 //!
330 //! [`Any`]: asn1::Any
331 //! [`UIntBytes`]: asn1::UIntBytes
332 //! [`BitString`]: asn1::BitString
333 //! [`GeneralizedTime`]: asn1::GeneralizedTime
334 //! [`Ia5String`]: asn1::Ia5String
335 //! [`Null`]: asn1::Null
336 //! [`ObjectIdentifier`]: asn1::ObjectIdentifier
337 //! [`OctetString`]: asn1::OctetString
338 //! [`PrintableString`]: asn1::PrintableString
339 //! [`Sequence`]: asn1::Sequence
340 //! [`SetOfRef`]: asn1::SetOfRef
341 //! [`UtcTime`]: asn1::UtcTime
342 //! [`Utf8String`]: asn1::Utf8String
343 
344 #![no_std]
345 #![cfg_attr(docsrs, feature(doc_cfg))]
346 #![doc(
347     html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
348     html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
349     html_root_url = "https://docs.rs/der/0.4.1"
350 )]
351 #![forbid(unsafe_code, clippy::unwrap_used)]
352 #![warn(missing_docs, rust_2018_idioms, unused_qualifications)]
353 
354 #[cfg(feature = "alloc")]
355 extern crate alloc;
356 
357 #[cfg(feature = "std")]
358 extern crate std;
359 
360 pub mod asn1;
361 pub mod message;
362 
363 mod byte_slice;
364 mod choice;
365 mod datetime;
366 mod decodable;
367 mod decoder;
368 mod encodable;
369 mod encoder;
370 mod error;
371 mod header;
372 mod length;
373 mod str_slice;
374 mod tag;
375 
376 pub use crate::{
377     choice::Choice,
378     decodable::Decodable,
379     decoder::Decoder,
380     encodable::Encodable,
381     encoder::Encoder,
382     error::{Error, ErrorKind, Result},
383     header::Header,
384     length::Length,
385     message::Message,
386     tag::{Class, Tag, TagNumber, Tagged},
387 };
388 
389 #[cfg(feature = "bigint")]
390 #[cfg_attr(docsrs, doc(cfg(feature = "bigint")))]
391 pub use crypto_bigint as bigint;
392 
393 #[cfg(feature = "derive")]
394 #[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
395 pub use der_derive::{Choice, Message};
396 
397 pub(crate) use crate::byte_slice::ByteSlice;
398