der/
lib.rs

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