Skip to main content

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