der/
lib.rs

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