diff options
Diffstat (limited to 'vendor/der/src/lib.rs')
-rw-r--r-- | vendor/der/src/lib.rs | 409 |
1 files changed, 409 insertions, 0 deletions
diff --git a/vendor/der/src/lib.rs b/vendor/der/src/lib.rs new file mode 100644 index 000000000..413b2e4af --- /dev/null +++ b/vendor/der/src/lib.rs @@ -0,0 +1,409 @@ +#![no_std] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![doc = include_str!("../README.md")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" +)] +#![forbid(unsafe_code)] +#![warn( + clippy::cast_lossless, + clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::cast_precision_loss, + clippy::cast_sign_loss, + clippy::checked_conversions, + clippy::implicit_saturating_sub, + clippy::integer_arithmetic, + clippy::panic, + clippy::panic_in_result_fn, + clippy::unwrap_used, + missing_docs, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications +)] + +//! # Usage +//! ## [`Decode`] and [`Encode`] traits +//! The [`Decode`] and [`Encode`] traits provide the decoding/encoding API +//! respectively, and are designed to work in conjunction with concrete ASN.1 +//! types, including all types which impl the [`Sequence`] trait. +//! +//! The traits are impl'd for the following Rust core types: +//! - `()`: ASN.1 `NULL`. See also [`Null`]. +//! - [`bool`]: ASN.1 `BOOLEAN`. +//! - [`i8`], [`i16`], [`i32`], [`i64`], [`i128`]: ASN.1 `INTEGER`. +//! - [`u8`], [`u16`], [`u32`], [`u64`], [`u128`]: ASN.1 `INTEGER`. +//! - [`f64`]: ASN.1 `REAL` (gated on `real` crate feature) +//! - [`str`], [`String`][`alloc::string::String`]: ASN.1 `UTF8String`. +//! `String` requires `alloc` feature. See also [`Utf8StringRef`]. +//! - [`Option`]: ASN.1 `OPTIONAL`. +//! - [`SystemTime`][`std::time::SystemTime`]: ASN.1 `GeneralizedTime`. Requires `std` feature. +//! - [`Vec`][`alloc::vec::Vec`]: ASN.1 `SEQUENCE OF`. Requires `alloc` feature. +//! - `[T; N]`: ASN.1 `SEQUENCE OF`. See also [`SequenceOf`]. +//! +//! The following ASN.1 types provided by this crate also impl these traits: +//! - [`Any`], [`AnyRef`]: ASN.1 `ANY`. +//! - [`BitString`], [`BitStringRef`]: ASN.1 `BIT STRING` +//! - [`GeneralizedTime`]: ASN.1 `GeneralizedTime`. +//! - [`Ia5StringRef`]: ASN.1 `IA5String`. +//! - [`Null`]: ASN.1 `NULL`. +//! - [`ObjectIdentifier`]: ASN.1 `OBJECT IDENTIFIER`. +//! - [`OctetString`], [`OctetStringRef`]: ASN.1 `OCTET STRING`. +//! - [`PrintableStringRef`]: ASN.1 `PrintableString` (ASCII subset). +//! - [`TeletexStringRef`]: ASN.1 `TeletexString`. +//! - [`VideotexStringRef`]: ASN.1 `VideotexString`. +//! - [`SequenceOf`]: ASN.1 `SEQUENCE OF`. +//! - [`SetOf`], [`SetOfVec`]: ASN.1 `SET OF`. +//! - [`UIntRef`]: ASN.1 unsigned `INTEGER` with raw access to encoded bytes. +//! - [`UtcTime`]: ASN.1 `UTCTime`. +//! - [`Utf8StringRef`]: ASN.1 `UTF8String`. +//! +//! Context specific fields can be modeled using these generic types: +//! - [`ContextSpecific`]: decoder/encoder for owned context-specific fields +//! - [`ContextSpecificRef`]: encode-only type for references to context-specific fields +//! +//! ## Example +//! The following example implements X.509's `AlgorithmIdentifier` message type +//! as defined in [RFC 5280 Section 4.1.1.2]. +//! +//! The ASN.1 schema for this message type is as follows: +//! +//! ```text +//! AlgorithmIdentifier ::= SEQUENCE { +//! algorithm OBJECT IDENTIFIER, +//! parameters ANY DEFINED BY algorithm OPTIONAL } +//! ``` +//! +//! Structured ASN.1 messages are typically encoded as a `SEQUENCE`, which +//! this crate maps to a Rust struct using the [`Sequence`] trait. This +//! trait is bounded on the [`Decode`] trait and provides a blanket impl +//! of the [`Encode`] trait, so any type which impls [`Sequence`] can be +//! used for both decoding and encoding. +//! +//! The following code example shows how to define a struct which maps to the +//! above schema, as well as impl the [`Sequence`] trait for that struct: +//! +//! ``` +//! # #[cfg(all(feature = "alloc", feature = "oid"))] +//! # { +//! // Note: the following example does not require the `std` feature at all. +//! // It does leverage the `alloc` feature, but also provides instructions for +//! // "heapless" usage when the `alloc` feature is disabled. +//! use der::{ +//! asn1::{AnyRef, ObjectIdentifier}, +//! DecodeValue, Decode, SliceReader, Encode, Header, Reader, Sequence +//! }; +//! +//! /// X.509 `AlgorithmIdentifier`. +//! #[derive(Copy, Clone, Debug, Eq, PartialEq)] +//! pub struct AlgorithmIdentifier<'a> { +//! /// This field contains an ASN.1 `OBJECT IDENTIFIER`, a.k.a. OID. +//! pub algorithm: ObjectIdentifier, +//! +//! /// This field is `OPTIONAL` and contains the ASN.1 `ANY` type, which +//! /// in this example allows arbitrary algorithm-defined parameters. +//! pub parameters: Option<AnyRef<'a>> +//! } +//! +//! impl<'a> DecodeValue<'a> for AlgorithmIdentifier<'a> { +//! fn decode_value<R: Reader<'a>>(reader: &mut R, _header: Header) -> der::Result<Self> { +//! // The `der::Decoder::Decode` method can be used to decode any +//! // type which impls the `Decode` trait, which is impl'd for +//! // all of the ASN.1 built-in types in the `der` crate. +//! // +//! // Note that if your struct's fields don't contain an ASN.1 +//! // built-in type specifically, there are also helper methods +//! // for all of the built-in types supported by this library +//! // which can be used to select a specific type. +//! // +//! // For example, another way of decoding this particular field, +//! // which contains an ASN.1 `OBJECT IDENTIFIER`, is by calling +//! // `decoder.oid()`. Similar methods are defined for other +//! // ASN.1 built-in types. +//! let algorithm = reader.decode()?; +//! +//! // This field contains an ASN.1 `OPTIONAL` type. The `der` crate +//! // maps this directly to Rust's `Option` type and provides +//! // impls of the `Decode` and `Encode` traits for `Option`. +//! // To explicitly request an `OPTIONAL` type be decoded, use the +//! // `decoder.optional()` method. +//! let parameters = reader.decode()?; +//! +//! // The value returned from the provided `FnOnce` will be +//! // returned from the `any.sequence(...)` call above. +//! // Note that the entire sequence body *MUST* be consumed +//! // or an error will be returned. +//! Ok(Self { algorithm, parameters }) +//! } +//! } +//! +//! impl<'a> Sequence<'a> for AlgorithmIdentifier<'a> { +//! // The `Sequence::fields` method is used for encoding and functions as +//! // a visitor for all of the fields in a message. +//! // +//! // To implement it, you must define a slice containing `Encode` +//! // trait objects, then pass it to the provided `field_encoder` +//! // function, which is implemented by the `der` crate and handles +//! // message serialization. +//! // +//! // Trait objects are used because they allow for slices containing +//! // heterogeneous field types, and a callback is used to allow for the +//! // construction of temporary field encoder types. The latter means +//! // that the fields of your Rust struct don't necessarily need to +//! // impl the `Encode` trait, but if they don't you must construct +//! // a temporary wrapper value which does. +//! // +//! // Types which impl the `Sequence` trait receive blanket impls of both +//! // the `Encode` and `Tagged` traits (where the latter is impl'd as +//! // `Tagged::TAG = der::Tag::Sequence`. +//! fn fields<F, T>(&self, field_encoder: F) -> der::Result<T> +//! where +//! F: FnOnce(&[&dyn Encode]) -> der::Result<T>, +//! { +//! field_encoder(&[&self.algorithm, &self.parameters]) +//! } +//! } +//! +//! // Example parameters value: OID for the NIST P-256 elliptic curve. +//! let parameters = "1.2.840.10045.3.1.7".parse::<ObjectIdentifier>().unwrap(); +//! +//! // We need to convert `parameters` into an `Any<'a>` type, which wraps a +//! // `&'a [u8]` byte slice. +//! // +//! // To do that, we need owned DER-encoded data so that we can have +//! // `AnyRef` borrow a reference to it, so we have to serialize the OID. +//! // +//! // When the `alloc` feature of this crate is enabled, any type that impls +//! // the `Encode` trait including all ASN.1 built-in types and any type +//! // which impls `Sequence` can be serialized by calling `Encode::to_der()`. +//! // +//! // If you would prefer to avoid allocations, you can create a byte array +//! // as backing storage instead, pass that to `der::Encoder::new`, and then +//! // encode the `parameters` value using `encoder.encode(parameters)`. +//! let der_encoded_parameters = parameters.to_vec().unwrap(); +//! +//! let algorithm_identifier = AlgorithmIdentifier { +//! // OID for `id-ecPublicKey`, if you're curious +//! algorithm: "1.2.840.10045.2.1".parse().unwrap(), +//! +//! // `Any<'a>` impls `TryFrom<&'a [u8]>`, which parses the provided +//! // slice as an ASN.1 DER-encoded message. +//! parameters: Some(der_encoded_parameters.as_slice().try_into().unwrap()) +//! }; +//! +//! // Serialize the `AlgorithmIdentifier` created above as ASN.1 DER, +//! // allocating a `Vec<u8>` for storage. +//! // +//! // As mentioned earlier, if you don't have the `alloc` feature enabled you +//! // can create a fix-sized array instead, then call `Encoder::new` with a +//! // reference to it, then encode the message using +//! // `encoder.encode(algorithm_identifier)`, then finally `encoder.finish()` +//! // to obtain a byte slice containing the encoded message. +//! let der_encoded_algorithm_identifier = algorithm_identifier.to_vec().unwrap(); +//! +//! // Deserialize the `AlgorithmIdentifier` we just serialized from ASN.1 DER +//! // using `der::Decode::from_bytes`. +//! let decoded_algorithm_identifier = AlgorithmIdentifier::from_der( +//! &der_encoded_algorithm_identifier +//! ).unwrap(); +//! +//! // Ensure the original `AlgorithmIdentifier` is the same as the one we just +//! // decoded from ASN.1 DER. +//! assert_eq!(algorithm_identifier, decoded_algorithm_identifier); +//! # } +//! ``` +//! +//! ## Custom derive support +//! When the `derive` feature of this crate is enabled, the following custom +//! derive macros are available: +//! +//! - [`Choice`]: derive for `CHOICE` enum (see [`der_derive::Choice`]) +//! - [`Enumerated`]: derive for `ENUMERATED` enum (see [`der_derive::Enumerated`]) +//! - [`Sequence`]: derive for `SEQUENCE` struct (see [`der_derive::Sequence`]) +//! +//! ### Derive [`Sequence`] for struct +//! The following is a code example of how to use the [`Sequence`] custom derive: +//! +//! ``` +//! # #[cfg(all(feature = "alloc", feature = "derive", feature = "oid"))] +//! # { +//! use der::{asn1::{AnyRef, ObjectIdentifier}, Encode, Decode, Sequence}; +//! +//! /// X.509 `AlgorithmIdentifier` (same as above) +//! #[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence)] // NOTE: added `Sequence` +//! pub struct AlgorithmIdentifier<'a> { +//! /// This field contains an ASN.1 `OBJECT IDENTIFIER`, a.k.a. OID. +//! pub algorithm: ObjectIdentifier, +//! +//! /// This field is `OPTIONAL` and contains the ASN.1 `ANY` type, which +//! /// in this example allows arbitrary algorithm-defined parameters. +//! pub parameters: Option<AnyRef<'a>> +//! } +//! +//! // Example parameters value: OID for the NIST P-256 elliptic curve. +//! let parameters_oid = "1.2.840.10045.3.1.7".parse::<ObjectIdentifier>().unwrap(); +//! +//! let algorithm_identifier = AlgorithmIdentifier { +//! // OID for `id-ecPublicKey`, if you're curious +//! algorithm: "1.2.840.10045.2.1".parse().unwrap(), +//! +//! // `Any<'a>` impls `From<&'a ObjectIdentifier>`, allowing OID constants to +//! // be directly converted to an `AnyRef` type for this use case. +//! parameters: Some(AnyRef::from(¶meters_oid)) +//! }; +//! +//! // Encode +//! let der_encoded_algorithm_identifier = algorithm_identifier.to_vec().unwrap(); +//! +//! // Decode +//! let decoded_algorithm_identifier = AlgorithmIdentifier::from_der( +//! &der_encoded_algorithm_identifier +//! ).unwrap(); +//! +//! assert_eq!(algorithm_identifier, decoded_algorithm_identifier); +//! # } +//! ``` +//! +//! For fields which don't directly impl [`Decode`] and [`Encode`], +//! you can add annotations to convert to an intermediate ASN.1 type +//! first, so long as that type impls `TryFrom` and `Into` for the +//! ASN.1 type. +//! +//! For example, structs containing `&'a [u8]` fields may want them encoded +//! as either a `BIT STRING` or `OCTET STRING`. By using the +//! `#[asn1(type = "BIT STRING")]` annotation it's possible to select which +//! ASN.1 type should be used. +//! +//! Building off the above example: +//! +//! ```rust +//! # #[cfg(all(feature = "alloc", feature = "derive", feature = "oid"))] +//! # { +//! # use der::{asn1::{AnyRef, BitStringRef, ObjectIdentifier}, Sequence}; +//! # +//! # #[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence)] +//! # pub struct AlgorithmIdentifier<'a> { +//! # pub algorithm: ObjectIdentifier, +//! # pub parameters: Option<AnyRef<'a>> +//! # } +//! /// X.509 `SubjectPublicKeyInfo` (SPKI) +//! #[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence)] +//! pub struct SubjectPublicKeyInfo<'a> { +//! /// X.509 `AlgorithmIdentifier` +//! pub algorithm: AlgorithmIdentifier<'a>, +//! +//! /// Public key data +//! pub subject_public_key: BitStringRef<'a>, +//! } +//! # } +//! ``` +//! +//! # See also +//! For more information about ASN.1 DER we recommend the following guides: +//! +//! - [A Layman's Guide to a Subset of ASN.1, BER, and DER] (RSA Laboratories) +//! - [A Warm Welcome to ASN.1 and DER] (Let's Encrypt) +//! +//! [RFC 5280 Section 4.1.1.2]: https://tools.ietf.org/html/rfc5280#section-4.1.1.2 +//! [A Layman's Guide to a Subset of ASN.1, BER, and DER]: https://luca.ntop.org/Teaching/Appunti/asn1.html +//! [A Warm Welcome to ASN.1 and DER]: https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/ +//! +//! [`Any`]: asn1::Any +//! [`AnyRef`]: asn1::AnyRef +//! [`ContextSpecific`]: asn1::ContextSpecific +//! [`ContextSpecificRef`]: asn1::ContextSpecificRef +//! [`BitString`]: asn1::BitString +//! [`BitStringRef`]: asn1::BitStringRef +//! [`GeneralizedTime`]: asn1::GeneralizedTime +//! [`Ia5StringRef`]: asn1::Ia5StringRef +//! [`Null`]: asn1::Null +//! [`ObjectIdentifier`]: asn1::ObjectIdentifier +//! [`OctetString`]: asn1::OctetString +//! [`OctetStringRef`]: asn1::OctetStringRef +//! [`PrintableStringRef`]: asn1::PrintableStringRef +//! [`TeletexStringRef`]: asn1::TeletexStringRef +//! [`VideotexStringRef`]: asn1::VideotexStringRef +//! [`SequenceOf`]: asn1::SequenceOf +//! [`SetOf`]: asn1::SetOf +//! [`SetOfVec`]: asn1::SetOfVec +//! [`UIntRef`]: asn1::UIntRef +//! [`UtcTime`]: asn1::UtcTime +//! [`Utf8StringRef`]: asn1::Utf8StringRef + +#[cfg(feature = "alloc")] +#[allow(unused_imports)] +#[macro_use] +extern crate alloc; +#[cfg(feature = "std")] +extern crate std; + +pub mod asn1; + +pub(crate) mod arrayvec; +mod byte_slice; +mod datetime; +mod decode; +mod encode; +mod encode_ref; +mod error; +mod header; +mod length; +mod ord; +mod reader; +mod str_slice; +mod tag; +mod writer; + +#[cfg(feature = "alloc")] +mod document; + +pub use crate::{ + asn1::{AnyRef, Choice, Sequence}, + datetime::DateTime, + decode::{Decode, DecodeOwned, DecodeValue}, + encode::{Encode, EncodeValue}, + encode_ref::{EncodeRef, EncodeValueRef}, + error::{Error, ErrorKind, Result}, + header::Header, + length::Length, + ord::{DerOrd, ValueOrd}, + reader::{slice::SliceReader, Reader}, + tag::{Class, FixedTag, Tag, TagMode, TagNumber, Tagged}, + writer::{slice::SliceWriter, Writer}, +}; + +#[cfg(feature = "alloc")] +pub use crate::document::Document; + +#[cfg(feature = "bigint")] +#[cfg_attr(docsrs, doc(cfg(feature = "bigint")))] +pub use crypto_bigint as bigint; + +#[cfg(feature = "derive")] +#[cfg_attr(docsrs, doc(cfg(feature = "derive")))] +pub use der_derive::{Choice, Enumerated, Sequence, ValueOrd}; + +#[cfg(feature = "oid")] +#[cfg_attr(docsrs, doc(cfg(feature = "oid")))] +pub use const_oid as oid; + +#[cfg(feature = "pem")] +#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] +pub use { + crate::{decode::DecodePem, encode::EncodePem, reader::pem::PemReader, writer::pem::PemWriter}, + pem_rfc7468 as pem, +}; + +#[cfg(feature = "time")] +#[cfg_attr(docsrs, doc(cfg(feature = "time")))] +pub use time; + +#[cfg(feature = "zeroize")] +pub use zeroize; + +#[cfg(all(feature = "alloc", feature = "zeroize"))] +pub use crate::document::SecretDocument; + +pub(crate) use crate::{arrayvec::ArrayVec, byte_slice::ByteSlice, str_slice::StrSlice}; |