der-0.7.7/.cargo_vcs_info.json0000644000000001410000000000100116150ustar { "git": { "sha1": "e73c42a45a21e052352f9437d7f852d07d198036" }, "path_in_vcs": "der" }der-0.7.7/CHANGELOG.md000064400000000000000000000351711046102023000122310ustar 00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## 0.7.7 (2023-06-29) ### Added - `TryFrom` impl for strings based on `StrOwned` ([#1064]) [#1064]: https://github.com/RustCrypto/formats/pull/1064 ## 0.7.6 (2023-05-16) ### Added - `SetOfVec::{extend, from_iter}` methods ([#1065]) - `SetOf(Vec)::{insert, insert_ordered}` methods ([#1067]) ### Changed - Deprecate `SetOf(Vec)::add` ([#1067]) ### Fixed - Off-by-one error in `BMPString` tag ([#1037]) - Handling of non-unique items in `SetOf`(Vec) ([#1066]) [#1037]: https://github.com/RustCrypto/formats/pull/1037 [#1065]: https://github.com/RustCrypto/formats/pull/1065 [#1066]: https://github.com/RustCrypto/formats/pull/1066 [#1067]: https://github.com/RustCrypto/formats/pull/1067 ## 0.7.5 (2023-04-24) ### Added - adds support for `DateTime::INFINITY` ([#1026]) [#1026]: https://github.com/RustCrypto/formats/pull/1026 ## 0.7.4 (2023-04-19) ### Added - `Decode` and `Encode` impls for `PhantomData` ([#1009]) - `ValueOrd` and `DerOrd` impls for `PhantomData` ([#1012]) ### Changed - Bump `hex-literal` dependency to v0.4.1 ([#999]) - Bump `der_derive` dependency to v0.7.1 ([#1016]) [#1009]: https://github.com/RustCrypto/formats/pull/1009 [#1012]: https://github.com/RustCrypto/formats/pull/1012 [#1016]: https://github.com/RustCrypto/formats/pull/1016 ## 0.7.3 (2023-04-06) ### Added - `UtcTime::MAX_YEAR` associated constant ([#989]) [#989]: https://github.com/RustCrypto/formats/pull/989 ## 0.7.2 (2023-04-04) ### Added - Expose `NestedReader ([#925]) - `From` impl for `Any` ([#965]) - `Any::null` helper ([#969]) - `Any::encode_from` ([#976]) [#925]: https://github.com/RustCrypto/formats/pull/925 [#965]: https://github.com/RustCrypto/formats/pull/965 [#969]: https://github.com/RustCrypto/formats/pull/969 [#976]: https://github.com/RustCrypto/formats/pull/976 ## 0.7.1 (2023-03-07) ### Changed - Make `zeroize`'s `alloc` feature conditional ([#920]) [#920]: https://github.com/RustCrypto/formats/pull/920 ## 0.7.0 (2023-02-26) [YANKED] ### Added - `OwnedtoRef`/`RefToOwned` traits; MSRV 1.65 ([#797]) - `OctetStringRef::decode_into` ([#817]) - `Int` and `IntRef` types ([#823]) - `IndefiniteLength` type ([#830]) - `Any::value` accessor ([#833]) - Buffered PEM reader ([#839]) - `OctetString::into_bytes` ([#845]) - Blanket impls on `Box` for `DecodeValue`, `EncodeValue`, and `Sequence` ([#860]) ### Changed - Rename `UIntRef` => `UintRef` ([#786]) - Replace use of `dyn Writer` with `impl Writer` ([#828]) - Rename `AnyRef::decode_into` -> `::decode_as` ([#829]) - Bump `pem-rfc7468` dependency to v0.7 ([#894]) - Rename `Encode::to_vec` => `::to_der` ([#898]) ### Removed - `Sequence::fields` method ([#828]) - Inherent `AnyRef` decoding methods ([#829]) [#786]: https://github.com/RustCrypto/formats/pull/786 [#797]: https://github.com/RustCrypto/formats/pull/797 [#817]: https://github.com/RustCrypto/formats/pull/817 [#823]: https://github.com/RustCrypto/formats/pull/823 [#828]: https://github.com/RustCrypto/formats/pull/828 [#829]: https://github.com/RustCrypto/formats/pull/829 [#830]: https://github.com/RustCrypto/formats/pull/830 [#833]: https://github.com/RustCrypto/formats/pull/833 [#839]: https://github.com/RustCrypto/formats/pull/839 [#845]: https://github.com/RustCrypto/formats/pull/845 [#860]: https://github.com/RustCrypto/formats/pull/860 [#894]: https://github.com/RustCrypto/formats/pull/894 [#898]: https://github.com/RustCrypto/formats/pull/898 ## 0.6.1 (2022-12-05) ### Added - Rudimentary implementation of `TeletexString` and `VideotexString` ([#691]) - Impl `ValueOrd` for `FlagSet` and `UIntRef` ([#723]) ### Changed - Eliminate some boilerplate code by using `Deref` ([#697]) [#691]: https://github.com/RustCrypto/formats/pull/691 [#697]: https://github.com/RustCrypto/formats/pull/697 [#723]: https://github.com/RustCrypto/formats/pull/723 ## 0.6.0 (2022-05-08) ### Added - Impl `ValueOrd` for `SetOf` and `SetOfVec` ([#362]) - `SequenceRef` type ([#374]) - Support for `SetOf` sorting on heapless `no_std` targets ([#401]) - Support for mapping `BitString` to/from a `FlagSet` ([#412]) - `DecodeOwned` marker trait ([#529]) - Support for the ASN.1 `REAL` type ([#346]) - `DecodePem` and `EncodePem` traits ([#571]) - `Document` and `SecretDocument` types ([#571]) - `EncodeRef`/`EncodeValueRef` wrapper types ([#604]) - `Writer` trait ([#605]) - `Reader` trait ([#606]) - Streaming on-the-fly `PemReader` and `PemWriter` ([#618], [#636]) - Owned `BitString` ([#636]) - Owned `Any` and `OctetString` types ([#640]) ### Changed - Pass `Header` to `DecodeValue` ([#392]) - Bump `const-oid` dependency to v0.9 ([#507]) - Renamed `Decodable`/`Encodable` => `Decode`/`Encode` ([#523]) - Enable arithmetic, casting, and panic `clippy` lints ([#556], [#579]) - Use `&mut dyn Writer` as output for `Encode::encode` and `EncodeValue::encode_value` ([#611]) - Bump `pem-rfc7468` dependency to v0.6 ([#620]) - Use `Reader<'a>` as input for `Decode::decode` and `DecodeValue::decode_value` ([#633]) - Renamed `Any` => `AnyRef` ([#637]) - Renamed `BitString` => `BitStringRef` ([#637]) - Renamed `Ia5String` => `Ia5StringRef` ([#637]) - Renamed `OctetString` => `OctetStringRef` ([#637]) - Renamed `PrintableString` => `PrintableStringRef` ([#637]) - Renamed `Utf8String` => `Utf8StringRef` ([#637]) - Renamed `UIntBytes` => `UIntRef` ([#637]) - Renamed `Decoder` => `SliceReader` ([#651]) - Renamed `Encoder` => `SliceWriter` ([#651]) ### Fixed - Handling of oversized unsigned `INTEGER` inputs ([#447]) ### Removed - `bigint` feature ([#344]) - `OrdIsValueOrd` trait ([#359]) - `Document` trait ([#571]) - `OptionalRef` ([#604]) - Decode-time SET OF ordering checks ([#625]) [#344]: https://github.com/RustCrypto/formats/pull/344 [#346]: https://github.com/RustCrypto/formats/pull/346 [#359]: https://github.com/RustCrypto/formats/pull/359 [#362]: https://github.com/RustCrypto/formats/pull/362 [#374]: https://github.com/RustCrypto/formats/pull/374 [#392]: https://github.com/RustCrypto/formats/pull/392 [#401]: https://github.com/RustCrypto/formats/pull/401 [#412]: https://github.com/RustCrypto/formats/pull/412 [#447]: https://github.com/RustCrypto/formats/pull/447 [#507]: https://github.com/RustCrypto/formats/pull/507 [#523]: https://github.com/RustCrypto/formats/pull/523 [#529]: https://github.com/RustCrypto/formats/pull/529 [#556]: https://github.com/RustCrypto/formats/pull/556 [#571]: https://github.com/RustCrypto/formats/pull/571 [#579]: https://github.com/RustCrypto/formats/pull/579 [#604]: https://github.com/RustCrypto/formats/pull/604 [#605]: https://github.com/RustCrypto/formats/pull/605 [#606]: https://github.com/RustCrypto/formats/pull/606 [#611]: https://github.com/RustCrypto/formats/pull/611 [#618]: https://github.com/RustCrypto/formats/pull/618 [#620]: https://github.com/RustCrypto/formats/pull/620 [#625]: https://github.com/RustCrypto/formats/pull/625 [#633]: https://github.com/RustCrypto/formats/pull/633 [#636]: https://github.com/RustCrypto/formats/pull/636 [#637]: https://github.com/RustCrypto/formats/pull/637 [#640]: https://github.com/RustCrypto/formats/pull/640 [#651]: https://github.com/RustCrypto/formats/pull/651 ## 0.5.1 (2021-11-17) ### Added - `Any::NULL` constant ([#226]) [#226]: https://github.com/RustCrypto/formats/pull/226 ## 0.5.0 (2021-11-15) [YANKED] ### Added - Support for `IMPLICIT` mode `CONTEXT-SPECIFIC` fields ([#61]) - `DecodeValue`/`EncodeValue` traits ([#63]) - Expose `DateTime` through public API ([#75]) - `SEQUENCE OF` support for `[T; N]` ([#90]) - `SequenceOf` type ([#95]) - `SEQUENCE OF` support for `Vec` ([#96]) - `Document` trait ([#117]) - Basic integration with `time` crate ([#129]) - `Tag::NumericString` ([#132]) - Support for unused bits to `BitString` ([#141]) - `Decoder::{peek_tag, peek_header}` ([#142]) - Type hint in `encoder `sequence` method ([#147]) - `Tag::Enumerated` ([#153]) - `ErrorKind::TagNumberInvalid` ([#156]) - `Tag::VisibleString` and `Tag::BmpString` ([#160]) - Inherent constants for all valid `TagNumber`s ([#165]) - `DerOrd` and `ValueOrd` traits ([#190]) - `ContextSpecificRef` type ([#199]) ### Changed - Make `ContextSpecific` generic around an inner type ([#60]) - Removed `SetOf` trait; rename `SetOfArray` => `SetOf` ([#97]) - Rename `Message` trait to `Sequence` ([#99]) - Make `GeneralizedTime`/`UtcTime` into `DateTime` newtypes ([#102]) - Rust 2021 edition upgrade; MSRV 1.56 ([#136]) - Replace `ErrorKind::Truncated` with `ErrorKind::Incomplete` ([#143]) - Rename `ErrorKind::UnknownTagMode` => `ErrorKind::TagModeUnknown` ([#155]) - Rename `ErrorKind::UnexpectedTag` => `ErrorKind::TagUnexpected` ([#155]) - Rename `ErrorKind::UnknownTag` => `ErrorKind::TagUnknown` ([#155]) - Consolidate `ErrorKind::{Incomplete, Underlength}` ([#157]) - Rename `Tagged` => `FixedTag`; add new `Tagged` trait ([#189]) - Use `DerOrd` for `SetOf*` types ([#200]) - Switch `impl From for &[u8]` to `TryFrom` ([#203]) - Bump `crypto-bigint` dependency to v0.3 ([#215]) - Bump `const-oid` dependency to v0.7 ([#216]) - Bump `pem-rfc7468` dependency to v0.3 ([#217]) - Bump `der_derive` dependency to v0.5 ([#221]) ### Removed - `Sequence` struct ([#98]) - `Tagged` bound on `ContextSpecific::decode_implicit` ([#161]) - `ErrorKind::DuplicateField` ([#162]) [#60]: https://github.com/RustCrypto/formats/pull/60 [#61]: https://github.com/RustCrypto/formats/pull/61 [#63]: https://github.com/RustCrypto/formats/pull/63 [#75]: https://github.com/RustCrypto/formats/pull/75 [#90]: https://github.com/RustCrypto/formats/pull/90 [#95]: https://github.com/RustCrypto/formats/pull/95 [#96]: https://github.com/RustCrypto/formats/pull/96 [#97]: https://github.com/RustCrypto/formats/pull/97 [#98]: https://github.com/RustCrypto/formats/pull/98 [#99]: https://github.com/RustCrypto/formats/pull/99 [#102]: https://github.com/RustCrypto/formats/pull/102 [#117]: https://github.com/RustCrypto/formats/pull/117 [#129]: https://github.com/RustCrypto/formats/pull/129 [#132]: https://github.com/RustCrypto/formats/pull/132 [#136]: https://github.com/RustCrypto/formats/pull/136 [#141]: https://github.com/RustCrypto/formats/pull/141 [#142]: https://github.com/RustCrypto/formats/pull/142 [#143]: https://github.com/RustCrypto/formats/pull/143 [#147]: https://github.com/RustCrypto/formats/pull/147 [#153]: https://github.com/RustCrypto/formats/pull/153 [#155]: https://github.com/RustCrypto/formats/pull/155 [#156]: https://github.com/RustCrypto/formats/pull/156 [#157]: https://github.com/RustCrypto/formats/pull/157 [#160]: https://github.com/RustCrypto/formats/pull/160 [#161]: https://github.com/RustCrypto/formats/pull/161 [#162]: https://github.com/RustCrypto/formats/pull/162 [#165]: https://github.com/RustCrypto/formats/pull/165 [#189]: https://github.com/RustCrypto/formats/pull/189 [#190]: https://github.com/RustCrypto/formats/pull/190 [#199]: https://github.com/RustCrypto/formats/pull/199 [#200]: https://github.com/RustCrypto/formats/pull/200 [#203]: https://github.com/RustCrypto/formats/pull/203 [#215]: https://github.com/RustCrypto/formats/pull/215 [#216]: https://github.com/RustCrypto/formats/pull/216 [#217]: https://github.com/RustCrypto/formats/pull/217 [#221]: https://github.com/RustCrypto/formats/pull/221 ## 0.4.5 (2021-12-01) ### Fixed - Backport [#147] type hint fix for WASM platforms to 0.4.x ## 0.4.4 (2021-10-06) ### Removed - Accidentally checked-in `target/` directory ([#66]) [#66]: https://github.com/RustCrypto/formats/pull/66 ## 0.4.3 (2021-09-15) ### Added - `Tag::unexpected_error` ([#33]) [#33]: https://github.com/RustCrypto/formats/pull/33 ## 0.4.2 (2021-09-14) ### Changed - Moved to `formats` repo ([#2]) ### Fixed - ASN.1 `SET` type now flagged with the constructed bit [#2]: https://github.com/RustCrypto/formats/pull/2 ## 0.4.1 (2021-08-08) ### Fixed - Encoding `UTCTime` for dates with `20xx` years ## 0.4.0 (2021-06-07) ### Added - `TagNumber` type - Const generic integer de/encoders with support for all of Rust's integer primitives - `crypto-bigint` support - `Tag` number helpers - `Tag::octet` - `ErrorKind::Value` helpers - `SequenceIter` ### Changed - Bump `const-oid` crate dependency to v0.6 - Make `Tag` structured - Namespace ASN.1 types in `asn1` module - Refactor context-specific field decoding - MSRV 1.51 - Rename `big-uint` crate feature to `bigint` - Rename `BigUInt` to `UIntBytes` - Have `Decoder::error()` return an `Error` ### Removed - Deprecated methods replaced by associated constants ## 0.3.5 (2021-05-24) ### Added - Helper methods for context-specific fields - `ContextSpecific` field wrapper - Decoder position tracking for errors during `Any<'a>` decoding ### Fixed - `From` conversion for `BitString` into `Any` ## 0.3.4 (2021-05-16) ### Changed - Support `Length` of up to 1 MiB ## 0.3.3 (2021-04-15) ### Added - `Length` constants ### Changed - Deprecate `const fn` methods replaced by `Length` constants ## 0.3.2 (2021-04-15) ### Fixed - Non-critical bug allowing `Length` to exceed the max invariant ## 0.3.1 (2021-04-01) [YANKED] ### Added - `PartialOrd` + `Ord` impls to all ASN.1 types ## 0.3.0 (2021-03-22) [YANKED] ### Added - Impl `Decode`/`Encoded`/`Tagged` for `String` - `Length::one` and `Length::for_tlv` - `SET OF` support with `SetOf` trait and `SetOfRef` ### Changed - Rename `Decodable::from_bytes` => `Decodable::from_der` - Separate `sequence` and `message` - Rename `ErrorKind::Oid` => `ErrorKind::MalformedOid` - Auto-derive `From` impls for variants when deriving `Choice` - Make `Length` use `u32` internally - Make `Sequence` constructor private - Bump `const_oid` to v0.5 - Bump `der_derive` to v0.3 ### Removed - Deprecated methods - `BigUIntSize` ## 0.2.10 (2021-02-28) ### Added - Impl `From` for `Any` ### Changed - Bump minimum `const-oid` dependency to v0.4.4 ## 0.2.9 (2021-02-24) ### Added - Support for `IA5String` ## 0.2.8 (2021-02-22) ### Added - `Choice` trait ## 0.2.7 (2021-02-20) ### Added - Export `Header` publicly - Make `Encoder::reserve` public ## 0.2.6 (2021-02-19) ### Added - Make the unit type an encoding of `NULL` ## 0.2.5 (2021-02-18) ### Added - `ErrorKind::UnknownOid` variant ## 0.2.4 (2021-02-16) ### Added - `Any::is_null` method ### Changed - Deprecate `Any::null` method ## 0.2.3 (2021-02-15) ### Added - Additional `rustdoc` documentation ## 0.2.2 (2021-02-12) ### Added - Support for `UTCTime` and `GeneralizedTime` ## 0.2.1 (2021-02-02) ### Added - Support for `PrintableString` and `Utf8String` ## 0.2.0 (2021-01-22) ### Added - `BigUInt` type - `i16` support - `u8` and `u16` support - Integer decoder helper methods ### Fixed - Handle leading byte of `BIT STRING`s ## 0.1.0 (2020-12-21) - Initial release der-0.7.7/Cargo.toml0000644000000040010000000000100076120ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.65" name = "der" version = "0.7.7" authors = ["RustCrypto Developers"] description = """ Pure Rust embedded-friendly implementation of the Distinguished Encoding Rules (DER) for Abstract Syntax Notation One (ASN.1) as described in ITU X.690 with full support for heapless no_std targets """ readme = "README.md" keywords = [ "asn1", "crypto", "itu", "pkcs", ] categories = [ "cryptography", "data-structures", "encoding", "no-std", "parser-implementations", ] license = "Apache-2.0 OR MIT" repository = "https://github.com/RustCrypto/formats/tree/master/der" [package.metadata.docs.rs] all-features = true rustdoc-args = [ "--cfg", "docsrs", ] [dependencies.arbitrary] version = "1.3" features = ["derive"] optional = true [dependencies.const-oid] version = "0.9.2" optional = true [dependencies.der_derive] version = "0.7.1" optional = true [dependencies.flagset] version = "0.4.3" optional = true [dependencies.pem-rfc7468] version = "0.7" features = ["alloc"] optional = true [dependencies.time] version = "0.3.4" optional = true default-features = false [dependencies.zeroize] version = "1.5" optional = true default-features = false [dev-dependencies.hex-literal] version = "0.4.1" [dev-dependencies.proptest] version = "1" [features] alloc = ["zeroize?/alloc"] arbitrary = [ "dep:arbitrary", "const-oid?/arbitrary", "std", ] derive = ["dep:der_derive"] oid = ["dep:const-oid"] pem = [ "dep:pem-rfc7468", "alloc", "zeroize", ] real = [] std = ["alloc"] der-0.7.7/Cargo.toml.orig000064400000000000000000000026531046102023000133060ustar 00000000000000[package] name = "der" version = "0.7.7" description = """ Pure Rust embedded-friendly implementation of the Distinguished Encoding Rules (DER) for Abstract Syntax Notation One (ASN.1) as described in ITU X.690 with full support for heapless no_std targets """ authors = ["RustCrypto Developers"] license = "Apache-2.0 OR MIT" repository = "https://github.com/RustCrypto/formats/tree/master/der" categories = ["cryptography", "data-structures", "encoding", "no-std", "parser-implementations"] keywords = ["asn1", "crypto", "itu", "pkcs"] readme = "README.md" edition = "2021" rust-version = "1.65" [dependencies] arbitrary = { version = "1.3", features = ["derive"], optional = true } const-oid = { version = "0.9.2", optional = true } # TODO: path = "../const-oid" der_derive = { version = "0.7.1", optional = true } flagset = { version = "0.4.3", optional = true } pem-rfc7468 = { version = "0.7", optional = true, features = ["alloc"] } time = { version = "0.3.4", optional = true, default-features = false } zeroize = { version = "1.5", optional = true, default-features = false } [dev-dependencies] hex-literal = "0.4.1" proptest = "1" [features] alloc = ["zeroize?/alloc"] std = ["alloc"] arbitrary = ["dep:arbitrary", "const-oid?/arbitrary", "std"] derive = ["dep:der_derive"] oid = ["dep:const-oid"] pem = ["dep:pem-rfc7468", "alloc", "zeroize"] real = [] [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] der-0.7.7/LICENSE-APACHE000064400000000000000000000251411046102023000123400ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. der-0.7.7/LICENSE-MIT000064400000000000000000000020721046102023000120460ustar 00000000000000Copyright (c) 2020-2023 The RustCrypto Project Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. der-0.7.7/README.md000064400000000000000000000074761046102023000117060ustar 00000000000000# [RustCrypto]: ASN.1 DER [![Crate][crate-image]][crate-link] [![Docs][docs-image]][docs-link] [![Build Status][build-image]][build-link] ![Apache2/MIT licensed][license-image] ![Rust Version][rustc-image] [![Project Chat][chat-image]][chat-link] Pure Rust embedded-friendly implementation of the Distinguished Encoding Rules (DER) for Abstract Syntax Notation One (ASN.1) as described in ITU X.690. [Documentation][docs-link] ## About This crate provides a `no_std`-friendly implementation of a subset of ASN.1 DER necessary for decoding/encoding the following cryptography-related formats implemented as crates maintained by the [RustCrypto] project: - [`pkcs1`]: RSA Cryptography Specifications - [`pkcs5`]: Password-Based Cryptography Specification - [`pkcs7`]: Cryptographic Message Syntax - [`pkcs8`]: Private-Key Information Syntax Specification - [`pkcs10`]: Certification Request Syntax Specification - [`sec1`]: Elliptic Curve Cryptography - [`spki`]: X.509 Subject Public Key Info - [`x501`]: Directory Services Types - [`x509`]: Public Key Infrastructure Certificate The core implementation avoids any heap usage (with convenience methods that allocate gated under the off-by-default `alloc` feature). The DER decoder in this crate performs checks to ensure that the input document is in canonical form, and will return errors if non-canonical productions are encountered. There is currently no way to disable these checks. ### Features - Rich support for ASN.1 types used by PKCS/PKIX documents - Performs DER canonicalization checks at decoding time - `no_std` friendly: supports "heapless" usage - Optionally supports `alloc` and `std` if desired - No hard dependencies! Self-contained implementation with optional integrations with the following crates, all of which are `no_std` friendly: - `const-oid`: const-friendly OID implementation - `pem-rfc7468`: PKCS/PKIX-flavored PEM library with constant-time decoder/encoders - `time` crate: date/time library ## Minimum Supported Rust Version This crate requires **Rust 1.65** at a minimum. We may change the MSRV in the future, but it will be accompanied by a minor version bump. ## License Licensed under either of: * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) * [MIT license](http://opensource.org/licenses/MIT) at your option. ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. [//]: # (badges) [crate-image]: https://buildstats.info/crate/der [crate-link]: https://crates.io/crates/der [docs-image]: https://docs.rs/der/badge.svg [docs-link]: https://docs.rs/der/ [build-image]: https://github.com/RustCrypto/formats/actions/workflows/der.yml/badge.svg [build-link]: https://github.com/RustCrypto/formats/actions/workflows/der.yml [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg [rustc-image]: https://img.shields.io/badge/rustc-1.65+-blue.svg [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/300570-formats [//]: # (links) [RustCrypto]: https://github.com/rustcrypto [`pkcs1`]: https://github.com/RustCrypto/formats/tree/master/pkcs1 [`pkcs5`]: https://github.com/RustCrypto/formats/tree/master/pkcs5 [`pkcs7`]: https://github.com/RustCrypto/formats/tree/master/pkcs7 [`pkcs8`]: https://github.com/RustCrypto/formats/tree/master/pkcs8 [`pkcs10`]: https://github.com/RustCrypto/formats/tree/master/pkcs10 [`sec1`]: https://github.com/RustCrypto/formats/tree/master/sec1 [`spki`]: https://github.com/RustCrypto/formats/tree/master/spki [`x501`]: https://github.com/RustCrypto/formats/tree/master/x501 [`x509`]: https://github.com/RustCrypto/formats/tree/master/x509 der-0.7.7/src/arrayvec.rs000064400000000000000000000070331046102023000133650ustar 00000000000000//! Array-backed append-only vector type. // TODO(tarcieri): use `core` impl of `ArrayVec` // See: https://github.com/rust-lang/rfcs/pull/2990 use crate::{ErrorKind, Result}; /// Array-backed append-only vector type. #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub(crate) struct ArrayVec { /// Elements of the set. elements: [Option; N], /// Last populated element. length: usize, } impl ArrayVec { /// Create a new [`ArrayVec`]. pub fn new() -> Self { Self { elements: [(); N].map(|_| None), length: 0, } } /// Push an item into this [`ArrayVec`]. pub fn push(&mut self, item: T) -> Result<()> { match self.length.checked_add(1) { Some(n) if n <= N => { self.elements[self.length] = Some(item); self.length = n; Ok(()) } _ => Err(ErrorKind::Overlength.into()), } } /// Get an element from this [`ArrayVec`]. pub fn get(&self, index: usize) -> Option<&T> { match self.elements.get(index) { Some(Some(ref item)) => Some(item), _ => None, } } /// Iterate over the elements in this [`ArrayVec`]. pub fn iter(&self) -> Iter<'_, T> { Iter::new(&self.elements) } /// Is this [`ArrayVec`] empty? pub fn is_empty(&self) -> bool { self.length == 0 } /// Get the number of elements in this [`ArrayVec`]. pub fn len(&self) -> usize { self.length } /// Get the last item from this [`ArrayVec`]. pub fn last(&self) -> Option<&T> { self.length.checked_sub(1).and_then(|n| self.get(n)) } /// Extract the inner array. pub fn into_array(self) -> [Option; N] { self.elements } } impl AsRef<[Option]> for ArrayVec { fn as_ref(&self) -> &[Option] { &self.elements[..self.length] } } impl AsMut<[Option]> for ArrayVec { fn as_mut(&mut self) -> &mut [Option] { &mut self.elements[..self.length] } } impl Default for ArrayVec { fn default() -> Self { Self::new() } } /// Iterator over the elements of an [`ArrayVec`]. #[derive(Clone, Debug)] pub struct Iter<'a, T> { /// Decoder which iterates over the elements of the message. elements: &'a [Option], /// Position within the iterator. position: usize, } impl<'a, T> Iter<'a, T> { pub(crate) fn new(elements: &'a [Option]) -> Self { Self { elements, position: 0, } } } impl<'a, T> Iterator for Iter<'a, T> { type Item = &'a T; fn next(&mut self) -> Option<&'a T> { match self.elements.get(self.position) { Some(Some(res)) => { self.position = self.position.checked_add(1)?; Some(res) } _ => None, } } fn size_hint(&self) -> (usize, Option) { let len = self.elements.len().saturating_sub(self.position); (len, Some(len)) } } impl<'a, T> ExactSizeIterator for Iter<'a, T> {} #[cfg(test)] mod tests { use super::ArrayVec; use crate::ErrorKind; #[test] fn add() { let mut vec = ArrayVec::::new(); vec.push(1).unwrap(); vec.push(2).unwrap(); vec.push(3).unwrap(); assert_eq!(vec.push(4).err().unwrap(), ErrorKind::Overlength.into()); assert_eq!(vec.len(), 3); } } der-0.7.7/src/asn1/any.rs000064400000000000000000000214271046102023000132050ustar 00000000000000//! ASN.1 `ANY` type. #![cfg_attr(feature = "arbitrary", allow(clippy::integer_arithmetic))] use crate::{ BytesRef, Choice, Decode, DecodeValue, DerOrd, EncodeValue, Error, ErrorKind, Header, Length, Reader, Result, SliceReader, Tag, Tagged, ValueOrd, Writer, }; use core::cmp::Ordering; #[cfg(feature = "alloc")] use crate::SliceWriter; /// ASN.1 `ANY`: represents any explicitly tagged ASN.1 value. /// /// This is a zero-copy reference type which borrows from the input data. /// /// Technically `ANY` hasn't been a recommended part of ASN.1 since the X.209 /// revision from 1988. It was deprecated and replaced by Information Object /// Classes in X.680 in 1994, and X.690 no longer refers to it whatsoever. /// /// Nevertheless, this crate defines an `ANY` type as it remains a familiar /// and useful concept which is still extensively used in things like /// PKI-related RFCs. #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct AnyRef<'a> { /// Tag representing the type of the encoded value. tag: Tag, /// Inner value encoded as bytes. value: BytesRef<'a>, } impl<'a> AnyRef<'a> { /// [`AnyRef`] representation of the ASN.1 `NULL` type. pub const NULL: Self = Self { tag: Tag::Null, value: BytesRef::EMPTY, }; /// Create a new [`AnyRef`] from the provided [`Tag`] and DER bytes. pub fn new(tag: Tag, bytes: &'a [u8]) -> Result { let value = BytesRef::new(bytes).map_err(|_| ErrorKind::Length { tag })?; Ok(Self { tag, value }) } /// Infallible creation of an [`AnyRef`] from a [`BytesRef`]. pub(crate) fn from_tag_and_value(tag: Tag, value: BytesRef<'a>) -> Self { Self { tag, value } } /// Get the raw value for this [`AnyRef`] type as a byte slice. pub fn value(self) -> &'a [u8] { self.value.as_slice() } /// Attempt to decode this [`AnyRef`] type into the inner value. pub fn decode_as(self) -> Result where T: Choice<'a> + DecodeValue<'a>, { if !T::can_decode(self.tag) { return Err(self.tag.unexpected_error(None)); } let header = Header { tag: self.tag, length: self.value.len(), }; let mut decoder = SliceReader::new(self.value())?; let result = T::decode_value(&mut decoder, header)?; decoder.finish(result) } /// Is this value an ASN.1 `NULL` value? pub fn is_null(self) -> bool { self == Self::NULL } /// Attempt to decode this value an ASN.1 `SEQUENCE`, creating a new /// nested reader and calling the provided argument with it. pub fn sequence(self, f: F) -> Result where F: FnOnce(&mut SliceReader<'a>) -> Result, { self.tag.assert_eq(Tag::Sequence)?; let mut reader = SliceReader::new(self.value.as_slice())?; let result = f(&mut reader)?; reader.finish(result) } } impl<'a> Choice<'a> for AnyRef<'a> { fn can_decode(_: Tag) -> bool { true } } impl<'a> Decode<'a> for AnyRef<'a> { fn decode>(reader: &mut R) -> Result> { let header = Header::decode(reader)?; Self::decode_value(reader, header) } } impl<'a> DecodeValue<'a> for AnyRef<'a> { fn decode_value>(reader: &mut R, header: Header) -> Result { Ok(Self { tag: header.tag, value: BytesRef::decode_value(reader, header)?, }) } } impl EncodeValue for AnyRef<'_> { fn value_len(&self) -> Result { Ok(self.value.len()) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { writer.write(self.value()) } } impl Tagged for AnyRef<'_> { fn tag(&self) -> Tag { self.tag } } impl ValueOrd for AnyRef<'_> { fn value_cmp(&self, other: &Self) -> Result { self.value.der_cmp(&other.value) } } impl<'a> From> for BytesRef<'a> { fn from(any: AnyRef<'a>) -> BytesRef<'a> { any.value } } impl<'a> TryFrom<&'a [u8]> for AnyRef<'a> { type Error = Error; fn try_from(bytes: &'a [u8]) -> Result> { AnyRef::from_der(bytes) } } #[cfg(feature = "alloc")] pub use self::allocating::Any; #[cfg(feature = "alloc")] mod allocating { use super::*; use crate::{referenced::*, BytesOwned}; use alloc::boxed::Box; /// ASN.1 `ANY`: represents any explicitly tagged ASN.1 value. /// /// This type provides the same functionality as [`AnyRef`] but owns the /// backing data. #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct Any { /// Tag representing the type of the encoded value. tag: Tag, /// Inner value encoded as bytes. value: BytesOwned, } impl Any { /// Create a new [`Any`] from the provided [`Tag`] and DER bytes. pub fn new(tag: Tag, bytes: impl Into>) -> Result { let value = BytesOwned::new(bytes)?; // Ensure the tag and value are a valid `AnyRef`. AnyRef::new(tag, value.as_slice())?; Ok(Self { tag, value }) } /// Allow access to value pub fn value(&self) -> &[u8] { self.value.as_slice() } /// Attempt to decode this [`Any`] type into the inner value. pub fn decode_as<'a, T>(&'a self) -> Result where T: Choice<'a> + DecodeValue<'a>, { AnyRef::from(self).decode_as() } /// Encode the provided type as an [`Any`] value. pub fn encode_from(msg: &T) -> Result where T: Tagged + EncodeValue, { let encoded_len = usize::try_from(msg.value_len()?)?; let mut buf = vec![0u8; encoded_len]; let mut writer = SliceWriter::new(&mut buf); msg.encode_value(&mut writer)?; writer.finish()?; Any::new(msg.tag(), buf) } /// Attempt to decode this value an ASN.1 `SEQUENCE`, creating a new /// nested reader and calling the provided argument with it. pub fn sequence<'a, F, T>(&'a self, f: F) -> Result where F: FnOnce(&mut SliceReader<'a>) -> Result, { AnyRef::from(self).sequence(f) } /// [`Any`] representation of the ASN.1 `NULL` type. pub fn null() -> Self { Self { tag: Tag::Null, value: BytesOwned::default(), } } } impl Choice<'_> for Any { fn can_decode(_: Tag) -> bool { true } } impl<'a> Decode<'a> for Any { fn decode>(reader: &mut R) -> Result { let header = Header::decode(reader)?; Self::decode_value(reader, header) } } impl<'a> DecodeValue<'a> for Any { fn decode_value>(reader: &mut R, header: Header) -> Result { let value = reader.read_vec(header.length)?; Self::new(header.tag, value) } } impl EncodeValue for Any { fn value_len(&self) -> Result { Ok(self.value.len()) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { writer.write(self.value.as_slice()) } } impl<'a> From<&'a Any> for AnyRef<'a> { fn from(any: &'a Any) -> AnyRef<'a> { // Ensured to parse successfully in constructor AnyRef::new(any.tag, any.value.as_slice()).expect("invalid ANY") } } impl Tagged for Any { fn tag(&self) -> Tag { self.tag } } impl ValueOrd for Any { fn value_cmp(&self, other: &Self) -> Result { self.value.der_cmp(&other.value) } } impl<'a, T> From for Any where T: Into>, { fn from(input: T) -> Any { let anyref: AnyRef<'a> = input.into(); Self { tag: anyref.tag(), value: BytesOwned::from(anyref.value), } } } impl<'a> RefToOwned<'a> for AnyRef<'a> { type Owned = Any; fn ref_to_owned(&self) -> Self::Owned { Any { tag: self.tag(), value: BytesOwned::from(self.value), } } } impl OwnedToRef for Any { type Borrowed<'a> = AnyRef<'a>; fn owned_to_ref(&self) -> Self::Borrowed<'_> { self.into() } } impl Any { /// Is this value an ASN.1 `NULL` value? pub fn is_null(&self) -> bool { self.owned_to_ref() == AnyRef::NULL } } } der-0.7.7/src/asn1/bit_string.rs000064400000000000000000000403541046102023000145620ustar 00000000000000//! ASN.1 `BIT STRING` support. use crate::{ BytesRef, DecodeValue, DerOrd, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, ValueOrd, Writer, }; use core::{cmp::Ordering, iter::FusedIterator}; /// ASN.1 `BIT STRING` type. /// /// This type contains a sequence of any number of bits, modeled internally as /// a sequence of bytes with a known number of "unused bits". /// /// This is a zero-copy reference type which borrows from the input data. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct BitStringRef<'a> { /// Number of unused bits in the final octet. unused_bits: u8, /// Length of this `BIT STRING` in bits. bit_length: usize, /// Bitstring represented as a slice of bytes. inner: BytesRef<'a>, } impl<'a> BitStringRef<'a> { /// Maximum number of unused bits allowed. pub const MAX_UNUSED_BITS: u8 = 7; /// Create a new ASN.1 `BIT STRING` from a byte slice. /// /// Accepts an optional number of "unused bits" (0-7) which are omitted /// from the final octet. This number is 0 if the value is octet-aligned. pub fn new(unused_bits: u8, bytes: &'a [u8]) -> Result { if (unused_bits > Self::MAX_UNUSED_BITS) || (unused_bits != 0 && bytes.is_empty()) { return Err(Self::TAG.value_error()); } let inner = BytesRef::new(bytes).map_err(|_| Self::TAG.length_error())?; let bit_length = usize::try_from(inner.len())? .checked_mul(8) .and_then(|n| n.checked_sub(usize::from(unused_bits))) .ok_or(ErrorKind::Overflow)?; Ok(Self { unused_bits, bit_length, inner, }) } /// Create a new ASN.1 `BIT STRING` from the given bytes. /// /// The "unused bits" are set to 0. pub fn from_bytes(bytes: &'a [u8]) -> Result { Self::new(0, bytes) } /// Get the number of unused bits in this byte slice. pub fn unused_bits(&self) -> u8 { self.unused_bits } /// Is the number of unused bits a value other than 0? pub fn has_unused_bits(&self) -> bool { self.unused_bits != 0 } /// Get the length of this `BIT STRING` in bits. pub fn bit_len(&self) -> usize { self.bit_length } /// Get the number of bytes/octets needed to represent this `BIT STRING` /// when serialized in an octet-aligned manner. pub fn byte_len(&self) -> Length { self.inner.len() } /// Is the inner byte slice empty? pub fn is_empty(&self) -> bool { self.inner.is_empty() } /// Borrow the inner byte slice. /// /// Returns `None` if the number of unused bits is *not* equal to zero, /// i.e. if the `BIT STRING` is not octet aligned. /// /// Use [`BitString::raw_bytes`] to obtain access to the raw value /// regardless of the presence of unused bits. pub fn as_bytes(&self) -> Option<&'a [u8]> { if self.has_unused_bits() { None } else { Some(self.raw_bytes()) } } /// Borrow the raw bytes of this `BIT STRING`. /// /// Note that the byte string may contain extra unused bits in the final /// octet. If the number of unused bits is expected to be 0, the /// [`BitStringRef::as_bytes`] function can be used instead. pub fn raw_bytes(&self) -> &'a [u8] { self.inner.as_slice() } /// Iterator over the bits of this `BIT STRING`. pub fn bits(self) -> BitStringIter<'a> { BitStringIter { bit_string: self, position: 0, } } } impl_any_conversions!(BitStringRef<'a>, 'a); impl<'a> DecodeValue<'a> for BitStringRef<'a> { fn decode_value>(reader: &mut R, header: Header) -> Result { let header = Header { tag: header.tag, length: (header.length - Length::ONE)?, }; let unused_bits = reader.read_byte()?; let inner = BytesRef::decode_value(reader, header)?; Self::new(unused_bits, inner.as_slice()) } } impl EncodeValue for BitStringRef<'_> { fn value_len(&self) -> Result { self.byte_len() + Length::ONE } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { writer.write_byte(self.unused_bits)?; writer.write(self.raw_bytes()) } } impl ValueOrd for BitStringRef<'_> { fn value_cmp(&self, other: &Self) -> Result { match self.unused_bits.cmp(&other.unused_bits) { Ordering::Equal => self.inner.der_cmp(&other.inner), ordering => Ok(ordering), } } } impl<'a> From<&BitStringRef<'a>> for BitStringRef<'a> { fn from(value: &BitStringRef<'a>) -> BitStringRef<'a> { *value } } impl<'a> TryFrom<&'a [u8]> for BitStringRef<'a> { type Error = Error; fn try_from(bytes: &'a [u8]) -> Result> { BitStringRef::from_bytes(bytes) } } /// Hack for simplifying the custom derive use case. impl<'a> TryFrom<&&'a [u8]> for BitStringRef<'a> { type Error = Error; fn try_from(bytes: &&'a [u8]) -> Result> { BitStringRef::from_bytes(bytes) } } impl<'a> TryFrom> for &'a [u8] { type Error = Error; fn try_from(bit_string: BitStringRef<'a>) -> Result<&'a [u8]> { bit_string .as_bytes() .ok_or_else(|| Tag::BitString.value_error()) } } impl<'a> FixedTag for BitStringRef<'a> { const TAG: Tag = Tag::BitString; } // Implement by hand because the derive would create invalid values. // Use the constructor to create a valid value. #[cfg(feature = "arbitrary")] impl<'a> arbitrary::Arbitrary<'a> for BitStringRef<'a> { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { Self::new( u.int_in_range(0..=Self::MAX_UNUSED_BITS)?, BytesRef::arbitrary(u)?.as_slice(), ) .map_err(|_| arbitrary::Error::IncorrectFormat) } fn size_hint(depth: usize) -> (usize, Option) { arbitrary::size_hint::and(u8::size_hint(depth), BytesRef::size_hint(depth)) } } #[cfg(feature = "alloc")] pub use self::allocating::BitString; #[cfg(feature = "alloc")] mod allocating { use super::*; use crate::referenced::*; use alloc::vec::Vec; /// Owned form of ASN.1 `BIT STRING` type. /// /// This type provides the same functionality as [`BitStringRef`] but owns the /// backing data. #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct BitString { /// Number of unused bits in the final octet. unused_bits: u8, /// Length of this `BIT STRING` in bits. bit_length: usize, /// Bitstring represented as a slice of bytes. inner: Vec, } impl BitString { /// Maximum number of unused bits allowed. pub const MAX_UNUSED_BITS: u8 = 7; /// Create a new ASN.1 `BIT STRING` from a byte slice. /// /// Accepts an optional number of "unused bits" (0-7) which are omitted /// from the final octet. This number is 0 if the value is octet-aligned. pub fn new(unused_bits: u8, bytes: impl Into>) -> Result { let inner = bytes.into(); // Ensure parameters parse successfully as a `BitStringRef`. let bit_length = BitStringRef::new(unused_bits, &inner)?.bit_length; Ok(BitString { unused_bits, bit_length, inner, }) } /// Create a new ASN.1 `BIT STRING` from the given bytes. /// /// The "unused bits" are set to 0. pub fn from_bytes(bytes: &[u8]) -> Result { Self::new(0, bytes) } /// Get the number of unused bits in the octet serialization of this /// `BIT STRING`. pub fn unused_bits(&self) -> u8 { self.unused_bits } /// Is the number of unused bits a value other than 0? pub fn has_unused_bits(&self) -> bool { self.unused_bits != 0 } /// Get the length of this `BIT STRING` in bits. pub fn bit_len(&self) -> usize { self.bit_length } /// Is the inner byte slice empty? pub fn is_empty(&self) -> bool { self.inner.is_empty() } /// Borrow the inner byte slice. /// /// Returns `None` if the number of unused bits is *not* equal to zero, /// i.e. if the `BIT STRING` is not octet aligned. /// /// Use [`BitString::raw_bytes`] to obtain access to the raw value /// regardless of the presence of unused bits. pub fn as_bytes(&self) -> Option<&[u8]> { if self.has_unused_bits() { None } else { Some(self.raw_bytes()) } } /// Borrow the raw bytes of this `BIT STRING`. pub fn raw_bytes(&self) -> &[u8] { self.inner.as_slice() } /// Iterator over the bits of this `BIT STRING`. pub fn bits(&self) -> BitStringIter<'_> { BitStringRef::from(self).bits() } } impl_any_conversions!(BitString); impl<'a> DecodeValue<'a> for BitString { fn decode_value>(reader: &mut R, header: Header) -> Result { let inner_len = (header.length - Length::ONE)?; let unused_bits = reader.read_byte()?; let inner = reader.read_vec(inner_len)?; Self::new(unused_bits, inner) } } impl EncodeValue for BitString { fn value_len(&self) -> Result { Length::ONE + Length::try_from(self.inner.len())? } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { writer.write_byte(self.unused_bits)?; writer.write(&self.inner) } } impl FixedTag for BitString { const TAG: Tag = Tag::BitString; } impl<'a> From<&'a BitString> for BitStringRef<'a> { fn from(bit_string: &'a BitString) -> BitStringRef<'a> { // Ensured to parse successfully in constructor BitStringRef::new(bit_string.unused_bits, &bit_string.inner) .expect("invalid BIT STRING") } } impl ValueOrd for BitString { fn value_cmp(&self, other: &Self) -> Result { match self.unused_bits.cmp(&other.unused_bits) { Ordering::Equal => self.inner.der_cmp(&other.inner), ordering => Ok(ordering), } } } // Implement by hand because the derive would create invalid values. // Use the constructor to create a valid value. #[cfg(feature = "arbitrary")] impl<'a> arbitrary::Arbitrary<'a> for BitString { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { Self::new( u.int_in_range(0..=Self::MAX_UNUSED_BITS)?, BytesRef::arbitrary(u)?.as_slice(), ) .map_err(|_| arbitrary::Error::IncorrectFormat) } fn size_hint(depth: usize) -> (usize, Option) { arbitrary::size_hint::and(u8::size_hint(depth), BytesRef::size_hint(depth)) } } impl<'a> RefToOwned<'a> for BitStringRef<'a> { type Owned = BitString; fn ref_to_owned(&self) -> Self::Owned { BitString { unused_bits: self.unused_bits, bit_length: self.bit_length, inner: Vec::from(self.inner.as_slice()), } } } impl OwnedToRef for BitString { type Borrowed<'a> = BitStringRef<'a>; fn owned_to_ref(&self) -> Self::Borrowed<'_> { self.into() } } } /// Iterator over the bits of a [`BitString`]. pub struct BitStringIter<'a> { /// [`BitString`] being iterated over. bit_string: BitStringRef<'a>, /// Current bit position within the iterator. position: usize, } impl<'a> Iterator for BitStringIter<'a> { type Item = bool; #[allow(clippy::integer_arithmetic)] fn next(&mut self) -> Option { if self.position >= self.bit_string.bit_len() { return None; } let byte = self.bit_string.raw_bytes().get(self.position / 8)?; let bit = 1u8 << (7 - (self.position % 8)); self.position = self.position.checked_add(1)?; Some(byte & bit != 0) } } impl<'a> ExactSizeIterator for BitStringIter<'a> { fn len(&self) -> usize { self.bit_string.bit_len() } } impl<'a> FusedIterator for BitStringIter<'a> {} #[cfg(feature = "flagset")] impl FixedTag for flagset::FlagSet { const TAG: Tag = BitStringRef::TAG; } #[cfg(feature = "flagset")] impl ValueOrd for flagset::FlagSet where T: flagset::Flags, T::Type: Ord, { fn value_cmp(&self, other: &Self) -> Result { Ok(self.bits().cmp(&other.bits())) } } #[cfg(feature = "flagset")] #[allow(clippy::integer_arithmetic)] impl<'a, T> DecodeValue<'a> for flagset::FlagSet where T: flagset::Flags, T::Type: From, T::Type: core::ops::Shl, { fn decode_value>(reader: &mut R, header: Header) -> Result { let position = reader.position(); let bits = BitStringRef::decode_value(reader, header)?; let mut flags = T::none().bits(); if bits.bit_len() > core::mem::size_of_val(&flags) * 8 { return Err(Error::new(ErrorKind::Overlength, position)); } for (i, bit) in bits.bits().enumerate() { flags |= T::Type::from(bit) << i; } Ok(Self::new_truncated(flags)) } } #[cfg(feature = "flagset")] #[allow(clippy::integer_arithmetic)] #[inline(always)] fn encode_flagset(set: &flagset::FlagSet) -> (usize, [u8; 16]) where T: flagset::Flags, u128: From, { let bits: u128 = set.bits().into(); let mut swap = 0u128; for i in 0..128 { let on = bits & (1 << i); swap |= on >> i << (128 - i - 1); } (bits.leading_zeros() as usize, swap.to_be_bytes()) } #[cfg(feature = "flagset")] #[allow(clippy::cast_possible_truncation, clippy::integer_arithmetic)] impl EncodeValue for flagset::FlagSet where T::Type: From, T::Type: core::ops::Shl, u128: From, { fn value_len(&self) -> Result { let (lead, buff) = encode_flagset(self); let buff = &buff[..buff.len() - lead / 8]; BitStringRef::new((lead % 8) as u8, buff)?.value_len() } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { let (lead, buff) = encode_flagset(self); let buff = &buff[..buff.len() - lead / 8]; BitStringRef::new((lead % 8) as u8, buff)?.encode_value(writer) } } #[cfg(test)] mod tests { use super::{BitStringRef, Result, Tag}; use crate::asn1::AnyRef; use hex_literal::hex; /// Parse a `BitString` from an ASN.1 `Any` value to test decoding behaviors. fn parse_bitstring(bytes: &[u8]) -> Result> { AnyRef::new(Tag::BitString, bytes)?.try_into() } #[test] fn decode_empty_bitstring() { let bs = parse_bitstring(&hex!("00")).unwrap(); assert_eq!(bs.as_bytes().unwrap(), &[]); } #[test] fn decode_non_empty_bitstring() { let bs = parse_bitstring(&hex!("00010203")).unwrap(); assert_eq!(bs.as_bytes().unwrap(), &[0x01, 0x02, 0x03]); } #[test] fn decode_bitstring_with_unused_bits() { let bs = parse_bitstring(&hex!("066e5dc0")).unwrap(); assert_eq!(bs.unused_bits(), 6); assert_eq!(bs.raw_bytes(), &hex!("6e5dc0")); // Expected: 011011100101110111 let mut bits = bs.bits(); assert_eq!(bits.len(), 18); for bit in [0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1] { assert_eq!(u8::from(bits.next().unwrap()), bit) } // Ensure `None` is returned on successive calls assert_eq!(bits.next(), None); assert_eq!(bits.next(), None); } #[test] fn reject_unused_bits_in_empty_string() { assert_eq!( parse_bitstring(&[0x03]).err().unwrap().kind(), Tag::BitString.value_error().kind() ) } } der-0.7.7/src/asn1/boolean.rs000064400000000000000000000040651046102023000140340ustar 00000000000000//! ASN.1 `BOOLEAN` support. use crate::{ asn1::AnyRef, ord::OrdIsValueOrd, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, Writer, }; /// Byte used to encode `true` in ASN.1 DER. From X.690 Section 11.1: /// /// > If the encoding represents the boolean value TRUE, its single contents /// > octet shall have all eight bits set to one. const TRUE_OCTET: u8 = 0b11111111; /// Byte used to encode `false` in ASN.1 DER. const FALSE_OCTET: u8 = 0b00000000; impl<'a> DecodeValue<'a> for bool { fn decode_value>(reader: &mut R, header: Header) -> Result { if header.length != Length::ONE { return Err(reader.error(ErrorKind::Length { tag: Self::TAG })); } match reader.read_byte()? { FALSE_OCTET => Ok(false), TRUE_OCTET => Ok(true), _ => Err(Self::TAG.non_canonical_error()), } } } impl EncodeValue for bool { fn value_len(&self) -> Result { Ok(Length::ONE) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { writer.write_byte(if *self { TRUE_OCTET } else { FALSE_OCTET }) } } impl FixedTag for bool { const TAG: Tag = Tag::Boolean; } impl OrdIsValueOrd for bool {} impl TryFrom> for bool { type Error = Error; fn try_from(any: AnyRef<'_>) -> Result { any.try_into() } } #[cfg(test)] mod tests { use crate::{Decode, Encode}; #[test] fn decode() { assert_eq!(true, bool::from_der(&[0x01, 0x01, 0xFF]).unwrap()); assert_eq!(false, bool::from_der(&[0x01, 0x01, 0x00]).unwrap()); } #[test] fn encode() { let mut buffer = [0u8; 3]; assert_eq!( &[0x01, 0x01, 0xFF], true.encode_to_slice(&mut buffer).unwrap() ); assert_eq!( &[0x01, 0x01, 0x00], false.encode_to_slice(&mut buffer).unwrap() ); } #[test] fn reject_non_canonical() { assert!(bool::from_der(&[0x01, 0x01, 0x01]).is_err()); } } der-0.7.7/src/asn1/choice.rs000064400000000000000000000014111046102023000136370ustar 00000000000000//! ASN.1 `CHOICE` support. use crate::{Decode, FixedTag, Tag, Tagged}; /// ASN.1 `CHOICE` denotes a union of one or more possible alternatives. /// /// The types MUST have distinct tags. /// /// This crate models choice as a trait, with a blanket impl for all types /// which impl `Decode + FixedTag` (i.e. they are modeled as a `CHOICE` /// with only one possible variant) pub trait Choice<'a>: Decode<'a> + Tagged { /// Is the provided [`Tag`] decodable as a variant of this `CHOICE`? fn can_decode(tag: Tag) -> bool; } /// This blanket impl allows any [`Tagged`] type to function as a [`Choice`] /// with a single alternative. impl<'a, T> Choice<'a> for T where T: Decode<'a> + FixedTag, { fn can_decode(tag: Tag) -> bool { T::TAG == tag } } der-0.7.7/src/asn1/context_specific.rs000064400000000000000000000252321046102023000157450ustar 00000000000000//! Context-specific field. use crate::{ asn1::AnyRef, Choice, Decode, DecodeValue, DerOrd, Encode, EncodeValue, EncodeValueRef, Error, Header, Length, Reader, Result, Tag, TagMode, TagNumber, Tagged, ValueOrd, Writer, }; use core::cmp::Ordering; /// Context-specific field which wraps an owned inner value. /// /// This type decodes/encodes a field which is specific to a particular context /// and is identified by a [`TagNumber`]. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct ContextSpecific { /// Context-specific tag number sans the leading `0b10000000` class /// identifier bit and `0b100000` constructed flag. pub tag_number: TagNumber, /// Tag mode: `EXPLICIT` VS `IMPLICIT`. pub tag_mode: TagMode, /// Value of the field. pub value: T, } impl ContextSpecific { /// Attempt to decode an `EXPLICIT` ASN.1 `CONTEXT-SPECIFIC` field with the /// provided [`TagNumber`]. /// /// This method has the following behavior which is designed to simplify /// handling of extension fields, which are denoted in an ASN.1 schema /// using the `...` ellipsis extension marker: /// /// - Skips over [`ContextSpecific`] fields with a tag number lower than /// the current one, consuming and ignoring them. /// - Returns `Ok(None)` if a [`ContextSpecific`] field with a higher tag /// number is encountered. These fields are not consumed in this case, /// allowing a field with a lower tag number to be omitted, then the /// higher numbered field consumed as a follow-up. /// - Returns `Ok(None)` if anything other than a [`ContextSpecific`] field /// is encountered. pub fn decode_explicit<'a, R: Reader<'a>>( reader: &mut R, tag_number: TagNumber, ) -> Result> where T: Decode<'a>, { Self::decode_with(reader, tag_number, |reader| Self::decode(reader)) } /// Attempt to decode an `IMPLICIT` ASN.1 `CONTEXT-SPECIFIC` field with the /// provided [`TagNumber`]. /// /// This method otherwise behaves the same as `decode_explicit`, /// but should be used in cases where the particular fields are `IMPLICIT` /// as opposed to `EXPLICIT`. pub fn decode_implicit<'a, R: Reader<'a>>( reader: &mut R, tag_number: TagNumber, ) -> Result> where T: DecodeValue<'a> + Tagged, { Self::decode_with(reader, tag_number, |reader| { let header = Header::decode(reader)?; let value = T::decode_value(reader, header)?; if header.tag.is_constructed() != value.tag().is_constructed() { return Err(header.tag.non_canonical_error()); } Ok(Self { tag_number, tag_mode: TagMode::Implicit, value, }) }) } /// Attempt to decode a context-specific field with the given /// helper callback. fn decode_with<'a, F, R: Reader<'a>>( reader: &mut R, tag_number: TagNumber, f: F, ) -> Result> where F: FnOnce(&mut R) -> Result, { while let Some(octet) = reader.peek_byte() { let tag = Tag::try_from(octet)?; if !tag.is_context_specific() || (tag.number() > tag_number) { break; } else if tag.number() == tag_number { return Some(f(reader)).transpose(); } else { AnyRef::decode(reader)?; } } Ok(None) } } impl<'a, T> Choice<'a> for ContextSpecific where T: Decode<'a> + Tagged, { fn can_decode(tag: Tag) -> bool { tag.is_context_specific() } } impl<'a, T> Decode<'a> for ContextSpecific where T: Decode<'a>, { fn decode>(reader: &mut R) -> Result { let header = Header::decode(reader)?; match header.tag { Tag::ContextSpecific { number, constructed: true, } => Ok(Self { tag_number: number, tag_mode: TagMode::default(), value: reader.read_nested(header.length, |reader| T::decode(reader))?, }), tag => Err(tag.unexpected_error(None)), } } } impl EncodeValue for ContextSpecific where T: EncodeValue + Tagged, { fn value_len(&self) -> Result { match self.tag_mode { TagMode::Explicit => self.value.encoded_len(), TagMode::Implicit => self.value.value_len(), } } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { match self.tag_mode { TagMode::Explicit => self.value.encode(writer), TagMode::Implicit => self.value.encode_value(writer), } } } impl Tagged for ContextSpecific where T: Tagged, { fn tag(&self) -> Tag { let constructed = match self.tag_mode { TagMode::Explicit => true, TagMode::Implicit => self.value.tag().is_constructed(), }; Tag::ContextSpecific { number: self.tag_number, constructed, } } } impl<'a, T> TryFrom> for ContextSpecific where T: Decode<'a>, { type Error = Error; fn try_from(any: AnyRef<'a>) -> Result> { match any.tag() { Tag::ContextSpecific { number, constructed: true, } => Ok(Self { tag_number: number, tag_mode: TagMode::default(), value: T::from_der(any.value())?, }), tag => Err(tag.unexpected_error(None)), } } } impl ValueOrd for ContextSpecific where T: EncodeValue + ValueOrd + Tagged, { fn value_cmp(&self, other: &Self) -> Result { match self.tag_mode { TagMode::Explicit => self.der_cmp(other), TagMode::Implicit => self.value_cmp(other), } } } /// Context-specific field reference. /// /// This type encodes a field which is specific to a particular context /// and is identified by a [`TagNumber`]. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct ContextSpecificRef<'a, T> { /// Context-specific tag number sans the leading `0b10000000` class /// identifier bit and `0b100000` constructed flag. pub tag_number: TagNumber, /// Tag mode: `EXPLICIT` VS `IMPLICIT`. pub tag_mode: TagMode, /// Value of the field. pub value: &'a T, } impl<'a, T> ContextSpecificRef<'a, T> { /// Convert to a [`ContextSpecific`]. fn encoder(&self) -> ContextSpecific> { ContextSpecific { tag_number: self.tag_number, tag_mode: self.tag_mode, value: EncodeValueRef(self.value), } } } impl<'a, T> EncodeValue for ContextSpecificRef<'a, T> where T: EncodeValue + Tagged, { fn value_len(&self) -> Result { self.encoder().value_len() } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { self.encoder().encode_value(writer) } } impl<'a, T> Tagged for ContextSpecificRef<'a, T> where T: Tagged, { fn tag(&self) -> Tag { self.encoder().tag() } } #[cfg(test)] mod tests { use super::ContextSpecific; use crate::{asn1::BitStringRef, Decode, Encode, SliceReader, TagMode, TagNumber}; use hex_literal::hex; // Public key data from `pkcs8` crate's `ed25519-pkcs8-v2.der` const EXAMPLE_BYTES: &[u8] = &hex!("A123032100A3A7EAE3A8373830BC47E1167BC50E1DB551999651E0E2DC587623438EAC3F31"); #[test] fn round_trip() { let field = ContextSpecific::>::from_der(EXAMPLE_BYTES).unwrap(); assert_eq!(field.tag_number.value(), 1); assert_eq!( field.value, BitStringRef::from_bytes(&EXAMPLE_BYTES[5..]).unwrap() ); let mut buf = [0u8; 128]; let encoded = field.encode_to_slice(&mut buf).unwrap(); assert_eq!(encoded, EXAMPLE_BYTES); } #[test] fn context_specific_with_explicit_field() { let tag_number = TagNumber::new(0); // Empty message let mut reader = SliceReader::new(&[]).unwrap(); assert_eq!( ContextSpecific::::decode_explicit(&mut reader, tag_number).unwrap(), None ); // Message containing a non-context-specific type let mut reader = SliceReader::new(&hex!("020100")).unwrap(); assert_eq!( ContextSpecific::::decode_explicit(&mut reader, tag_number).unwrap(), None ); // Message containing an EXPLICIT context-specific field let mut reader = SliceReader::new(&hex!("A003020100")).unwrap(); let field = ContextSpecific::::decode_explicit(&mut reader, tag_number) .unwrap() .unwrap(); assert_eq!(field.tag_number, tag_number); assert_eq!(field.tag_mode, TagMode::Explicit); assert_eq!(field.value, 0); } #[test] fn context_specific_with_implicit_field() { // From RFC8410 Section 10.3: // // // 81 33: [1] 00 19 BF 44 09 69 84 CD FE 85 41 BA C1 67 DC 3B // 96 C8 50 86 AA 30 B6 B6 CB 0C 5C 38 AD 70 31 66 // E1 let context_specific_implicit_bytes = hex!("81210019BF44096984CDFE8541BAC167DC3B96C85086AA30B6B6CB0C5C38AD703166E1"); let tag_number = TagNumber::new(1); let mut reader = SliceReader::new(&context_specific_implicit_bytes).unwrap(); let field = ContextSpecific::>::decode_implicit(&mut reader, tag_number) .unwrap() .unwrap(); assert_eq!(field.tag_number, tag_number); assert_eq!(field.tag_mode, TagMode::Implicit); assert_eq!( field.value.as_bytes().unwrap(), &context_specific_implicit_bytes[3..] ); } #[test] fn context_specific_skipping_unknown_field() { let tag = TagNumber::new(1); let mut reader = SliceReader::new(&hex!("A003020100A103020101")).unwrap(); let field = ContextSpecific::::decode_explicit(&mut reader, tag) .unwrap() .unwrap(); assert_eq!(field.value, 1); } #[test] fn context_specific_returns_none_on_greater_tag_number() { let tag = TagNumber::new(0); let mut reader = SliceReader::new(&hex!("A103020101")).unwrap(); assert_eq!( ContextSpecific::::decode_explicit(&mut reader, tag).unwrap(), None ); } } der-0.7.7/src/asn1/generalized_time.rs000064400000000000000000000232201046102023000157160ustar 00000000000000//! ASN.1 `GeneralizedTime` support. #![cfg_attr(feature = "arbitrary", allow(clippy::integer_arithmetic))] use crate::{ datetime::{self, DateTime}, ord::OrdIsValueOrd, DecodeValue, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, Writer, }; use core::time::Duration; #[cfg(feature = "std")] use { crate::{asn1::AnyRef, Error}, std::time::SystemTime, }; #[cfg(feature = "time")] use time::PrimitiveDateTime; /// ASN.1 `GeneralizedTime` type. /// /// This type implements the validity requirements specified in /// [RFC 5280 Section 4.1.2.5.2][1], namely: /// /// > For the purposes of this profile, GeneralizedTime values MUST be /// > expressed in Greenwich Mean Time (Zulu) and MUST include seconds /// > (i.e., times are `YYYYMMDDHHMMSSZ`), even where the number of seconds /// > is zero. GeneralizedTime values MUST NOT include fractional seconds. /// /// [1]: https://tools.ietf.org/html/rfc5280#section-4.1.2.5.2 #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct GeneralizedTime(DateTime); impl GeneralizedTime { /// Length of an RFC 5280-flavored ASN.1 DER-encoded [`GeneralizedTime`]. const LENGTH: usize = 15; /// Create a [`GeneralizedTime`] from a [`DateTime`]. pub const fn from_date_time(datetime: DateTime) -> Self { Self(datetime) } /// Convert this [`GeneralizedTime`] into a [`DateTime`]. pub fn to_date_time(&self) -> DateTime { self.0 } /// Create a new [`GeneralizedTime`] given a [`Duration`] since `UNIX_EPOCH` /// (a.k.a. "Unix time") pub fn from_unix_duration(unix_duration: Duration) -> Result { DateTime::from_unix_duration(unix_duration) .map(Into::into) .map_err(|_| Self::TAG.value_error()) } /// Get the duration of this timestamp since `UNIX_EPOCH`. pub fn to_unix_duration(&self) -> Duration { self.0.unix_duration() } /// Instantiate from [`SystemTime`]. #[cfg(feature = "std")] pub fn from_system_time(time: SystemTime) -> Result { DateTime::try_from(time) .map(Into::into) .map_err(|_| Self::TAG.value_error()) } /// Convert to [`SystemTime`]. #[cfg(feature = "std")] pub fn to_system_time(&self) -> SystemTime { self.0.to_system_time() } } impl_any_conversions!(GeneralizedTime); impl<'a> DecodeValue<'a> for GeneralizedTime { fn decode_value>(reader: &mut R, header: Header) -> Result { if Self::LENGTH != usize::try_from(header.length)? { return Err(Self::TAG.value_error()); } let mut bytes = [0u8; Self::LENGTH]; reader.read_into(&mut bytes)?; match bytes { // RFC 5280 requires mandatory seconds and Z-normalized time zone [y1, y2, y3, y4, mon1, mon2, day1, day2, hour1, hour2, min1, min2, sec1, sec2, b'Z'] => { let year = u16::from(datetime::decode_decimal(Self::TAG, y1, y2)?) .checked_mul(100) .and_then(|y| { y.checked_add(datetime::decode_decimal(Self::TAG, y3, y4).ok()?.into()) }) .ok_or(ErrorKind::DateTime)?; let month = datetime::decode_decimal(Self::TAG, mon1, mon2)?; let day = datetime::decode_decimal(Self::TAG, day1, day2)?; let hour = datetime::decode_decimal(Self::TAG, hour1, hour2)?; let minute = datetime::decode_decimal(Self::TAG, min1, min2)?; let second = datetime::decode_decimal(Self::TAG, sec1, sec2)?; DateTime::new(year, month, day, hour, minute, second) .map_err(|_| Self::TAG.value_error()) .and_then(|dt| Self::from_unix_duration(dt.unix_duration())) } _ => Err(Self::TAG.value_error()), } } } impl EncodeValue for GeneralizedTime { fn value_len(&self) -> Result { Self::LENGTH.try_into() } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { let year_hi = u8::try_from(self.0.year() / 100)?; let year_lo = u8::try_from(self.0.year() % 100)?; datetime::encode_decimal(writer, Self::TAG, year_hi)?; datetime::encode_decimal(writer, Self::TAG, year_lo)?; datetime::encode_decimal(writer, Self::TAG, self.0.month())?; datetime::encode_decimal(writer, Self::TAG, self.0.day())?; datetime::encode_decimal(writer, Self::TAG, self.0.hour())?; datetime::encode_decimal(writer, Self::TAG, self.0.minutes())?; datetime::encode_decimal(writer, Self::TAG, self.0.seconds())?; writer.write_byte(b'Z') } } impl FixedTag for GeneralizedTime { const TAG: Tag = Tag::GeneralizedTime; } impl OrdIsValueOrd for GeneralizedTime {} impl From<&GeneralizedTime> for GeneralizedTime { fn from(value: &GeneralizedTime) -> GeneralizedTime { *value } } impl From for DateTime { fn from(utc_time: GeneralizedTime) -> DateTime { utc_time.0 } } impl From<&GeneralizedTime> for DateTime { fn from(utc_time: &GeneralizedTime) -> DateTime { utc_time.0 } } impl From for GeneralizedTime { fn from(datetime: DateTime) -> Self { Self::from_date_time(datetime) } } impl From<&DateTime> for GeneralizedTime { fn from(datetime: &DateTime) -> Self { Self::from_date_time(*datetime) } } impl<'a> DecodeValue<'a> for DateTime { fn decode_value>(reader: &mut R, header: Header) -> Result { Ok(GeneralizedTime::decode_value(reader, header)?.into()) } } impl EncodeValue for DateTime { fn value_len(&self) -> Result { GeneralizedTime::from(self).value_len() } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { GeneralizedTime::from(self).encode_value(writer) } } impl FixedTag for DateTime { const TAG: Tag = Tag::GeneralizedTime; } impl OrdIsValueOrd for DateTime {} #[cfg(feature = "std")] impl<'a> DecodeValue<'a> for SystemTime { fn decode_value>(reader: &mut R, header: Header) -> Result { Ok(GeneralizedTime::decode_value(reader, header)?.into()) } } #[cfg(feature = "std")] impl EncodeValue for SystemTime { fn value_len(&self) -> Result { GeneralizedTime::try_from(self)?.value_len() } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { GeneralizedTime::try_from(self)?.encode_value(writer) } } #[cfg(feature = "std")] impl From for SystemTime { fn from(time: GeneralizedTime) -> SystemTime { time.to_system_time() } } #[cfg(feature = "std")] impl From<&GeneralizedTime> for SystemTime { fn from(time: &GeneralizedTime) -> SystemTime { time.to_system_time() } } #[cfg(feature = "std")] impl TryFrom for GeneralizedTime { type Error = Error; fn try_from(time: SystemTime) -> Result { GeneralizedTime::from_system_time(time) } } #[cfg(feature = "std")] impl TryFrom<&SystemTime> for GeneralizedTime { type Error = Error; fn try_from(time: &SystemTime) -> Result { GeneralizedTime::from_system_time(*time) } } #[cfg(feature = "std")] impl<'a> TryFrom> for SystemTime { type Error = Error; fn try_from(any: AnyRef<'a>) -> Result { GeneralizedTime::try_from(any).map(|s| s.to_system_time()) } } #[cfg(feature = "std")] impl FixedTag for SystemTime { const TAG: Tag = Tag::GeneralizedTime; } #[cfg(feature = "std")] impl OrdIsValueOrd for SystemTime {} #[cfg(feature = "time")] impl<'a> DecodeValue<'a> for PrimitiveDateTime { fn decode_value>(reader: &mut R, header: Header) -> Result { GeneralizedTime::decode_value(reader, header)?.try_into() } } #[cfg(feature = "time")] impl EncodeValue for PrimitiveDateTime { fn value_len(&self) -> Result { GeneralizedTime::try_from(self)?.value_len() } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { GeneralizedTime::try_from(self)?.encode_value(writer) } } #[cfg(feature = "time")] impl FixedTag for PrimitiveDateTime { const TAG: Tag = Tag::GeneralizedTime; } #[cfg(feature = "time")] impl OrdIsValueOrd for PrimitiveDateTime {} #[cfg(feature = "time")] impl TryFrom for GeneralizedTime { type Error = Error; fn try_from(time: PrimitiveDateTime) -> Result { Ok(GeneralizedTime::from_date_time(DateTime::try_from(time)?)) } } #[cfg(feature = "time")] impl TryFrom<&PrimitiveDateTime> for GeneralizedTime { type Error = Error; fn try_from(time: &PrimitiveDateTime) -> Result { Self::try_from(*time) } } #[cfg(feature = "time")] impl TryFrom for PrimitiveDateTime { type Error = Error; fn try_from(time: GeneralizedTime) -> Result { time.to_date_time().try_into() } } #[cfg(test)] mod tests { use super::GeneralizedTime; use crate::{Decode, Encode, SliceWriter}; use hex_literal::hex; #[test] fn round_trip() { let example_bytes = hex!("18 0f 31 39 39 31 30 35 30 36 32 33 34 35 34 30 5a"); let utc_time = GeneralizedTime::from_der(&example_bytes).unwrap(); assert_eq!(utc_time.to_unix_duration().as_secs(), 673573540); let mut buf = [0u8; 128]; let mut encoder = SliceWriter::new(&mut buf); utc_time.encode(&mut encoder).unwrap(); assert_eq!(example_bytes, encoder.finish().unwrap()); } } der-0.7.7/src/asn1/ia5_string.rs000064400000000000000000000126411046102023000144600ustar 00000000000000//! ASN.1 `IA5String` support. use crate::{asn1::AnyRef, FixedTag, Result, StrRef, Tag}; use core::{fmt, ops::Deref}; macro_rules! impl_ia5_string { ($type: ty) => { impl_ia5_string!($type,); }; ($type: ty, $($li: lifetime)?) => { impl_string_type!($type, $($li),*); impl<$($li),*> FixedTag for $type { const TAG: Tag = Tag::Ia5String; } impl<$($li),*> fmt::Debug for $type { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Ia5String({:?})", self.as_str()) } } }; } /// ASN.1 `IA5String` type. /// /// Supports the [International Alphabet No. 5 (IA5)] character encoding, i.e. /// the lower 128 characters of the ASCII alphabet. (Note: IA5 is now /// technically known as the International Reference Alphabet or IRA as /// specified in the ITU-T's T.50 recommendation). /// /// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`]. /// /// This is a zero-copy reference type which borrows from the input data. /// /// [International Alphabet No. 5 (IA5)]: https://en.wikipedia.org/wiki/T.50_%28standard%29 #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] pub struct Ia5StringRef<'a> { /// Inner value inner: StrRef<'a>, } impl<'a> Ia5StringRef<'a> { /// Create a new `IA5String`. pub fn new(input: &'a T) -> Result where T: AsRef<[u8]> + ?Sized, { let input = input.as_ref(); // Validate all characters are within IA5String's allowed set if input.iter().any(|&c| c > 0x7F) { return Err(Self::TAG.value_error()); } StrRef::from_bytes(input) .map(|inner| Self { inner }) .map_err(|_| Self::TAG.value_error()) } } impl_ia5_string!(Ia5StringRef<'a>, 'a); impl<'a> Deref for Ia5StringRef<'a> { type Target = StrRef<'a>; fn deref(&self) -> &Self::Target { &self.inner } } impl<'a> From<&Ia5StringRef<'a>> for Ia5StringRef<'a> { fn from(value: &Ia5StringRef<'a>) -> Ia5StringRef<'a> { *value } } impl<'a> From> for AnyRef<'a> { fn from(internationalized_string: Ia5StringRef<'a>) -> AnyRef<'a> { AnyRef::from_tag_and_value(Tag::Ia5String, internationalized_string.inner.into()) } } #[cfg(feature = "alloc")] pub use self::allocation::Ia5String; #[cfg(feature = "alloc")] mod allocation { use super::Ia5StringRef; use crate::{ asn1::AnyRef, referenced::{OwnedToRef, RefToOwned}, Error, FixedTag, Result, StrOwned, Tag, }; use alloc::string::String; use core::{fmt, ops::Deref}; /// ASN.1 `IA5String` type. /// /// Supports the [International Alphabet No. 5 (IA5)] character encoding, i.e. /// the lower 128 characters of the ASCII alphabet. (Note: IA5 is now /// technically known as the International Reference Alphabet or IRA as /// specified in the ITU-T's T.50 recommendation). /// /// For UTF-8, use [`String`][`alloc::string::String`]. /// /// [International Alphabet No. 5 (IA5)]: https://en.wikipedia.org/wiki/T.50_%28standard%29 #[derive(Clone, Eq, PartialEq, PartialOrd, Ord)] pub struct Ia5String { /// Inner value inner: StrOwned, } impl Ia5String { /// Create a new `IA5String`. pub fn new(input: &T) -> Result where T: AsRef<[u8]> + ?Sized, { let input = input.as_ref(); Ia5StringRef::new(input)?; StrOwned::from_bytes(input) .map(|inner| Self { inner }) .map_err(|_| Self::TAG.value_error()) } } impl_ia5_string!(Ia5String); impl Deref for Ia5String { type Target = StrOwned; fn deref(&self) -> &Self::Target { &self.inner } } impl<'a> From> for Ia5String { fn from(international_string: Ia5StringRef<'a>) -> Ia5String { let inner = international_string.inner.into(); Self { inner } } } impl<'a> From<&'a Ia5String> for AnyRef<'a> { fn from(international_string: &'a Ia5String) -> AnyRef<'a> { AnyRef::from_tag_and_value(Tag::Ia5String, (&international_string.inner).into()) } } impl<'a> RefToOwned<'a> for Ia5StringRef<'a> { type Owned = Ia5String; fn ref_to_owned(&self) -> Self::Owned { Ia5String { inner: self.inner.ref_to_owned(), } } } impl OwnedToRef for Ia5String { type Borrowed<'a> = Ia5StringRef<'a>; fn owned_to_ref(&self) -> Self::Borrowed<'_> { Ia5StringRef { inner: self.inner.owned_to_ref(), } } } impl TryFrom for Ia5String { type Error = Error; fn try_from(input: String) -> Result { Ia5StringRef::new(&input)?; StrOwned::new(input) .map(|inner| Self { inner }) .map_err(|_| Self::TAG.value_error()) } } } #[cfg(test)] mod tests { use super::Ia5StringRef; use crate::Decode; use hex_literal::hex; #[test] fn parse_bytes() { let example_bytes = hex!("16 0d 74 65 73 74 31 40 72 73 61 2e 63 6f 6d"); let internationalized_string = Ia5StringRef::from_der(&example_bytes).unwrap(); assert_eq!(internationalized_string.as_str(), "test1@rsa.com"); } } der-0.7.7/src/asn1/integer/int.rs000064400000000000000000000326341046102023000146470ustar 00000000000000//! Support for encoding signed integers use super::{is_highest_bit_set, uint, value_cmp}; use crate::{ ord::OrdIsValueOrd, AnyRef, BytesRef, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, ValueOrd, Writer, }; use core::cmp::Ordering; #[cfg(feature = "alloc")] pub use allocating::Int; macro_rules! impl_encoding_traits { ($($int:ty => $uint:ty),+) => { $( impl<'a> DecodeValue<'a> for $int { fn decode_value>(reader: &mut R, header: Header) -> Result { let mut buf = [0u8; Self::BITS as usize / 8]; let max_length = u32::from(header.length) as usize; if max_length > buf.len() { return Err(Self::TAG.non_canonical_error()); } let bytes = reader.read_into(&mut buf[..max_length])?; let result = if is_highest_bit_set(bytes) { <$uint>::from_be_bytes(decode_to_array(bytes)?) as $int } else { Self::from_be_bytes(uint::decode_to_array(bytes)?) }; // Ensure we compute the same encoded length as the original any value if header.length != result.value_len()? { return Err(Self::TAG.non_canonical_error()); } Ok(result) } } impl EncodeValue for $int { fn value_len(&self) -> Result { if *self < 0 { negative_encoded_len(&(*self as $uint).to_be_bytes()) } else { uint::encoded_len(&self.to_be_bytes()) } } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { if *self < 0 { encode_bytes(writer, &(*self as $uint).to_be_bytes()) } else { uint::encode_bytes(writer, &self.to_be_bytes()) } } } impl FixedTag for $int { const TAG: Tag = Tag::Integer; } impl ValueOrd for $int { fn value_cmp(&self, other: &Self) -> Result { value_cmp(*self, *other) } } impl TryFrom> for $int { type Error = Error; fn try_from(any: AnyRef<'_>) -> Result { any.decode_as() } } )+ }; } impl_encoding_traits!(i8 => u8, i16 => u16, i32 => u32, i64 => u64, i128 => u128); /// Signed arbitrary precision ASN.1 `INTEGER` reference type. /// /// Provides direct access to the underlying big endian bytes which comprise /// an signed integer value. /// /// Intended for use cases like very large integers that are used in /// cryptographic applications (e.g. keys, signatures). #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct IntRef<'a> { /// Inner value inner: BytesRef<'a>, } impl<'a> IntRef<'a> { /// Create a new [`IntRef`] from a byte slice. pub fn new(bytes: &'a [u8]) -> Result { let inner = BytesRef::new(strip_leading_ones(bytes)) .map_err(|_| ErrorKind::Length { tag: Self::TAG })?; Ok(Self { inner }) } /// Borrow the inner byte slice which contains the least significant bytes /// of a big endian integer value with all leading ones stripped. pub fn as_bytes(&self) -> &'a [u8] { self.inner.as_slice() } /// Get the length of this [`IntRef`] in bytes. pub fn len(&self) -> Length { self.inner.len() } /// Is the inner byte slice empty? pub fn is_empty(&self) -> bool { self.inner.is_empty() } } impl_any_conversions!(IntRef<'a>, 'a); impl<'a> DecodeValue<'a> for IntRef<'a> { fn decode_value>(reader: &mut R, header: Header) -> Result { let bytes = BytesRef::decode_value(reader, header)?; validate_canonical(bytes.as_slice())?; let result = Self::new(bytes.as_slice())?; // Ensure we compute the same encoded length as the original any value. if result.value_len()? != header.length { return Err(Self::TAG.non_canonical_error()); } Ok(result) } } impl<'a> EncodeValue for IntRef<'a> { fn value_len(&self) -> Result { // Signed integers always hold their full encoded form. Ok(self.inner.len()) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { writer.write(self.as_bytes()) } } impl<'a> From<&IntRef<'a>> for IntRef<'a> { fn from(value: &IntRef<'a>) -> IntRef<'a> { *value } } impl<'a> FixedTag for IntRef<'a> { const TAG: Tag = Tag::Integer; } impl<'a> OrdIsValueOrd for IntRef<'a> {} #[cfg(feature = "alloc")] mod allocating { use super::{strip_leading_ones, validate_canonical, IntRef}; use crate::{ asn1::Uint, ord::OrdIsValueOrd, referenced::{OwnedToRef, RefToOwned}, BytesOwned, DecodeValue, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, Writer, }; use alloc::vec::Vec; /// Signed arbitrary precision ASN.1 `INTEGER` type. /// /// Provides heap-allocated storage for big endian bytes which comprise an /// signed integer value. /// /// Intended for use cases like very large integers that are used in /// cryptographic applications (e.g. keys, signatures). #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct Int { /// Inner value inner: BytesOwned, } impl Int { /// Create a new [`Int`] from a byte slice. pub fn new(bytes: &[u8]) -> Result { let inner = BytesOwned::new(strip_leading_ones(bytes)) .map_err(|_| ErrorKind::Length { tag: Self::TAG })?; Ok(Self { inner }) } /// Borrow the inner byte slice which contains the least significant bytes /// of a big endian integer value with all leading ones stripped. pub fn as_bytes(&self) -> &[u8] { self.inner.as_slice() } /// Get the length of this [`Int`] in bytes. pub fn len(&self) -> Length { self.inner.len() } /// Is the inner byte slice empty? pub fn is_empty(&self) -> bool { self.inner.is_empty() } } impl_any_conversions!(Int); impl<'a> DecodeValue<'a> for Int { fn decode_value>(reader: &mut R, header: Header) -> Result { let bytes = BytesOwned::decode_value(reader, header)?; validate_canonical(bytes.as_slice())?; let result = Self::new(bytes.as_slice())?; // Ensure we compute the same encoded length as the original any value. if result.value_len()? != header.length { return Err(Self::TAG.non_canonical_error()); } Ok(result) } } impl EncodeValue for Int { fn value_len(&self) -> Result { // Signed integers always hold their full encoded form. Ok(self.inner.len()) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { writer.write(self.as_bytes()) } } impl<'a> From<&IntRef<'a>> for Int { fn from(value: &IntRef<'a>) -> Int { let inner = BytesOwned::new(value.as_bytes()).expect("Invalid Int"); Int { inner } } } impl From for Int { fn from(value: Uint) -> Self { let mut inner: Vec = Vec::new(); // Add leading `0x00` byte if required if value.value_len().expect("invalid Uint") > value.len() { inner.push(0x00); } inner.extend_from_slice(value.as_bytes()); let inner = BytesOwned::new(inner).expect("invalid Uint"); Int { inner } } } impl FixedTag for Int { const TAG: Tag = Tag::Integer; } impl OrdIsValueOrd for Int {} impl<'a> RefToOwned<'a> for IntRef<'a> { type Owned = Int; fn ref_to_owned(&self) -> Self::Owned { let inner = self.inner.ref_to_owned(); Int { inner } } } impl OwnedToRef for Int { type Borrowed<'a> = IntRef<'a>; fn owned_to_ref(&self) -> Self::Borrowed<'_> { let inner = self.inner.owned_to_ref(); IntRef { inner } } } } /// Ensure `INTEGER` is canonically encoded. fn validate_canonical(bytes: &[u8]) -> Result<()> { // The `INTEGER` type always encodes a signed value and we're decoding // as signed here, so we allow a zero extension or sign extension byte, // but only as permitted under DER canonicalization. match bytes { [] => Err(Tag::Integer.non_canonical_error()), [0x00, byte, ..] if *byte < 0x80 => Err(Tag::Integer.non_canonical_error()), [0xFF, byte, ..] if *byte >= 0x80 => Err(Tag::Integer.non_canonical_error()), _ => Ok(()), } } /// Decode an signed integer of the specified size. /// /// Returns a byte array of the requested size containing a big endian integer. fn decode_to_array(bytes: &[u8]) -> Result<[u8; N]> { match N.checked_sub(bytes.len()) { Some(offset) => { let mut output = [0xFFu8; N]; output[offset..].copy_from_slice(bytes); Ok(output) } None => { let expected_len = Length::try_from(N)?; let actual_len = Length::try_from(bytes.len())?; Err(ErrorKind::Incomplete { expected_len, actual_len, } .into()) } } } /// Encode the given big endian bytes representing an integer as ASN.1 DER. fn encode_bytes(writer: &mut W, bytes: &[u8]) -> Result<()> where W: Writer + ?Sized, { writer.write(strip_leading_ones(bytes)) } /// Get the encoded length for the given **negative** integer serialized as bytes. #[inline] fn negative_encoded_len(bytes: &[u8]) -> Result { Length::try_from(strip_leading_ones(bytes).len()) } /// Strip the leading all-ones bytes from the given byte slice. pub(crate) fn strip_leading_ones(mut bytes: &[u8]) -> &[u8] { while let Some((byte, rest)) = bytes.split_first() { if *byte == 0xFF && is_highest_bit_set(rest) { bytes = rest; continue; } break; } bytes } #[cfg(test)] mod tests { use super::{validate_canonical, IntRef}; use crate::{asn1::integer::tests::*, Decode, Encode, SliceWriter}; #[test] fn validate_canonical_ok() { assert_eq!(validate_canonical(&[0x00]), Ok(())); assert_eq!(validate_canonical(&[0x01]), Ok(())); assert_eq!(validate_canonical(&[0x00, 0x80]), Ok(())); assert_eq!(validate_canonical(&[0xFF, 0x00]), Ok(())); } #[test] fn validate_canonical_err() { // Empty integers are always non-canonical. assert!(validate_canonical(&[]).is_err()); // Positives with excessive zero extension are non-canonical. assert!(validate_canonical(&[0x00, 0x00]).is_err()); // Negatives with excessive sign extension are non-canonical. assert!(validate_canonical(&[0xFF, 0x80]).is_err()); } #[test] fn decode_intref() { // Positive numbers decode, but have zero extensions as necessary // (to distinguish them from negative representations). assert_eq!(&[0], IntRef::from_der(I0_BYTES).unwrap().as_bytes()); assert_eq!(&[127], IntRef::from_der(I127_BYTES).unwrap().as_bytes()); assert_eq!(&[0, 128], IntRef::from_der(I128_BYTES).unwrap().as_bytes()); assert_eq!(&[0, 255], IntRef::from_der(I255_BYTES).unwrap().as_bytes()); assert_eq!( &[0x01, 0x00], IntRef::from_der(I256_BYTES).unwrap().as_bytes() ); assert_eq!( &[0x7F, 0xFF], IntRef::from_der(I32767_BYTES).unwrap().as_bytes() ); // Negative integers decode. assert_eq!(&[128], IntRef::from_der(INEG128_BYTES).unwrap().as_bytes()); assert_eq!( &[255, 127], IntRef::from_der(INEG129_BYTES).unwrap().as_bytes() ); assert_eq!( &[128, 0], IntRef::from_der(INEG32768_BYTES).unwrap().as_bytes() ); } #[test] fn encode_intref() { for &example in &[ I0_BYTES, I127_BYTES, I128_BYTES, I255_BYTES, I256_BYTES, I32767_BYTES, ] { let uint = IntRef::from_der(example).unwrap(); let mut buf = [0u8; 128]; let mut encoder = SliceWriter::new(&mut buf); uint.encode(&mut encoder).unwrap(); let result = encoder.finish().unwrap(); assert_eq!(example, result); } for &example in &[INEG128_BYTES, INEG129_BYTES, INEG32768_BYTES] { let uint = IntRef::from_der(example).unwrap(); let mut buf = [0u8; 128]; let mut encoder = SliceWriter::new(&mut buf); uint.encode(&mut encoder).unwrap(); let result = encoder.finish().unwrap(); assert_eq!(example, result); } } } der-0.7.7/src/asn1/integer/uint.rs000064400000000000000000000317321046102023000150320ustar 00000000000000//! Unsigned integer decoders/encoders. use super::value_cmp; use crate::{ ord::OrdIsValueOrd, AnyRef, BytesRef, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, ValueOrd, Writer, }; use core::cmp::Ordering; #[cfg(feature = "alloc")] pub use allocating::Uint; macro_rules! impl_encoding_traits { ($($uint:ty),+) => { $( impl<'a> DecodeValue<'a> for $uint { fn decode_value>(reader: &mut R, header: Header) -> Result { // Integers always encodes as a signed value, unsigned gets a leading 0x00 that // needs to be stripped off. We need to provide room for it. const UNSIGNED_HEADROOM: usize = 1; let mut buf = [0u8; (Self::BITS as usize / 8) + UNSIGNED_HEADROOM]; let max_length = u32::from(header.length) as usize; if max_length > buf.len() { return Err(Self::TAG.non_canonical_error()); } let bytes = reader.read_into(&mut buf[..max_length])?; let result = Self::from_be_bytes(decode_to_array(bytes)?); // Ensure we compute the same encoded length as the original any value if header.length != result.value_len()? { return Err(Self::TAG.non_canonical_error()); } Ok(result) } } impl EncodeValue for $uint { fn value_len(&self) -> Result { encoded_len(&self.to_be_bytes()) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { encode_bytes(writer, &self.to_be_bytes()) } } impl FixedTag for $uint { const TAG: Tag = Tag::Integer; } impl ValueOrd for $uint { fn value_cmp(&self, other: &Self) -> Result { value_cmp(*self, *other) } } impl TryFrom> for $uint { type Error = Error; fn try_from(any: AnyRef<'_>) -> Result { any.decode_as() } } )+ }; } impl_encoding_traits!(u8, u16, u32, u64, u128); /// Unsigned arbitrary precision ASN.1 `INTEGER` reference type. /// /// Provides direct access to the underlying big endian bytes which comprise an /// unsigned integer value. /// /// Intended for use cases like very large integers that are used in /// cryptographic applications (e.g. keys, signatures). #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct UintRef<'a> { /// Inner value inner: BytesRef<'a>, } impl<'a> UintRef<'a> { /// Create a new [`UintRef`] from a byte slice. pub fn new(bytes: &'a [u8]) -> Result { let inner = BytesRef::new(strip_leading_zeroes(bytes)) .map_err(|_| ErrorKind::Length { tag: Self::TAG })?; Ok(Self { inner }) } /// Borrow the inner byte slice which contains the least significant bytes /// of a big endian integer value with all leading zeros stripped. pub fn as_bytes(&self) -> &'a [u8] { self.inner.as_slice() } /// Get the length of this [`UintRef`] in bytes. pub fn len(&self) -> Length { self.inner.len() } /// Is the inner byte slice empty? pub fn is_empty(&self) -> bool { self.inner.is_empty() } } impl_any_conversions!(UintRef<'a>, 'a); impl<'a> DecodeValue<'a> for UintRef<'a> { fn decode_value>(reader: &mut R, header: Header) -> Result { let bytes = BytesRef::decode_value(reader, header)?.as_slice(); let result = Self::new(decode_to_slice(bytes)?)?; // Ensure we compute the same encoded length as the original any value. if result.value_len()? != header.length { return Err(Self::TAG.non_canonical_error()); } Ok(result) } } impl<'a> EncodeValue for UintRef<'a> { fn value_len(&self) -> Result { encoded_len(self.inner.as_slice()) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { // Add leading `0x00` byte if required if self.value_len()? > self.len() { writer.write_byte(0)?; } writer.write(self.as_bytes()) } } impl<'a> From<&UintRef<'a>> for UintRef<'a> { fn from(value: &UintRef<'a>) -> UintRef<'a> { *value } } impl<'a> FixedTag for UintRef<'a> { const TAG: Tag = Tag::Integer; } impl<'a> OrdIsValueOrd for UintRef<'a> {} #[cfg(feature = "alloc")] mod allocating { use super::{decode_to_slice, encoded_len, strip_leading_zeroes, UintRef}; use crate::{ ord::OrdIsValueOrd, referenced::{OwnedToRef, RefToOwned}, BytesOwned, DecodeValue, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, Writer, }; /// Unsigned arbitrary precision ASN.1 `INTEGER` type. /// /// Provides heap-allocated storage for big endian bytes which comprise an /// unsigned integer value. /// /// Intended for use cases like very large integers that are used in /// cryptographic applications (e.g. keys, signatures). #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct Uint { /// Inner value inner: BytesOwned, } impl Uint { /// Create a new [`Uint`] from a byte slice. pub fn new(bytes: &[u8]) -> Result { let inner = BytesOwned::new(strip_leading_zeroes(bytes)) .map_err(|_| ErrorKind::Length { tag: Self::TAG })?; Ok(Self { inner }) } /// Borrow the inner byte slice which contains the least significant bytes /// of a big endian integer value with all leading zeros stripped. pub fn as_bytes(&self) -> &[u8] { self.inner.as_slice() } /// Get the length of this [`Uint`] in bytes. pub fn len(&self) -> Length { self.inner.len() } /// Is the inner byte slice empty? pub fn is_empty(&self) -> bool { self.inner.is_empty() } } impl_any_conversions!(Uint); impl<'a> DecodeValue<'a> for Uint { fn decode_value>(reader: &mut R, header: Header) -> Result { let bytes = BytesOwned::decode_value(reader, header)?; let result = Self::new(decode_to_slice(bytes.as_slice())?)?; // Ensure we compute the same encoded length as the original any value. if result.value_len()? != header.length { return Err(Self::TAG.non_canonical_error()); } Ok(result) } } impl EncodeValue for Uint { fn value_len(&self) -> Result { encoded_len(self.inner.as_slice()) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { // Add leading `0x00` byte if required if self.value_len()? > self.len() { writer.write_byte(0)?; } writer.write(self.as_bytes()) } } impl<'a> From<&UintRef<'a>> for Uint { fn from(value: &UintRef<'a>) -> Uint { let inner = BytesOwned::new(value.as_bytes()).expect("Invalid Uint"); Uint { inner } } } impl FixedTag for Uint { const TAG: Tag = Tag::Integer; } impl OrdIsValueOrd for Uint {} impl<'a> RefToOwned<'a> for UintRef<'a> { type Owned = Uint; fn ref_to_owned(&self) -> Self::Owned { let inner = self.inner.ref_to_owned(); Uint { inner } } } impl OwnedToRef for Uint { type Borrowed<'a> = UintRef<'a>; fn owned_to_ref(&self) -> Self::Borrowed<'_> { let inner = self.inner.owned_to_ref(); UintRef { inner } } } } /// Decode an unsigned integer into a big endian byte slice with all leading /// zeroes removed. /// /// Returns a byte array of the requested size containing a big endian integer. pub(crate) fn decode_to_slice(bytes: &[u8]) -> Result<&[u8]> { // The `INTEGER` type always encodes a signed value, so for unsigned // values the leading `0x00` byte may need to be removed. // // We also disallow a leading byte which would overflow a signed ASN.1 // integer (since we're decoding an unsigned integer). // We expect all such cases to have a leading `0x00` byte. match bytes { [] => Err(Tag::Integer.non_canonical_error()), [0] => Ok(bytes), [0, byte, ..] if *byte < 0x80 => Err(Tag::Integer.non_canonical_error()), [0, rest @ ..] => Ok(rest), [byte, ..] if *byte >= 0x80 => Err(Tag::Integer.value_error()), _ => Ok(bytes), } } /// Decode an unsigned integer into a byte array of the requested size /// containing a big endian integer. pub(super) fn decode_to_array(bytes: &[u8]) -> Result<[u8; N]> { let input = decode_to_slice(bytes)?; // Compute number of leading zeroes to add let num_zeroes = N .checked_sub(input.len()) .ok_or_else(|| Tag::Integer.length_error())?; // Copy input into `N`-sized output buffer with leading zeroes let mut output = [0u8; N]; output[num_zeroes..].copy_from_slice(input); Ok(output) } /// Encode the given big endian bytes representing an integer as ASN.1 DER. pub(crate) fn encode_bytes(encoder: &mut W, bytes: &[u8]) -> Result<()> where W: Writer + ?Sized, { let bytes = strip_leading_zeroes(bytes); if needs_leading_zero(bytes) { encoder.write_byte(0)?; } encoder.write(bytes) } /// Get the encoded length for the given unsigned integer serialized as bytes. #[inline] pub(crate) fn encoded_len(bytes: &[u8]) -> Result { let bytes = strip_leading_zeroes(bytes); Length::try_from(bytes.len())? + u8::from(needs_leading_zero(bytes)) } /// Strip the leading zeroes from the given byte slice pub(crate) fn strip_leading_zeroes(mut bytes: &[u8]) -> &[u8] { while let Some((byte, rest)) = bytes.split_first() { if *byte == 0 && !rest.is_empty() { bytes = rest; } else { break; } } bytes } /// Does the given integer need a leading zero? fn needs_leading_zero(bytes: &[u8]) -> bool { matches!(bytes.first(), Some(byte) if *byte >= 0x80) } #[cfg(test)] mod tests { use super::{decode_to_array, UintRef}; use crate::{asn1::integer::tests::*, AnyRef, Decode, Encode, ErrorKind, SliceWriter, Tag}; #[test] fn decode_to_array_no_leading_zero() { let arr = decode_to_array::<4>(&[1, 2]).unwrap(); assert_eq!(arr, [0, 0, 1, 2]); } #[test] fn decode_to_array_leading_zero() { let arr = decode_to_array::<4>(&[0x00, 0xFF, 0xFE]).unwrap(); assert_eq!(arr, [0x00, 0x00, 0xFF, 0xFE]); } #[test] fn decode_to_array_extra_zero() { let err = decode_to_array::<4>(&[0, 1, 2]).err().unwrap(); assert_eq!(err.kind(), ErrorKind::Noncanonical { tag: Tag::Integer }); } #[test] fn decode_to_array_missing_zero() { // We're decoding an unsigned integer, but this value would be signed let err = decode_to_array::<4>(&[0xFF, 0xFE]).err().unwrap(); assert_eq!(err.kind(), ErrorKind::Value { tag: Tag::Integer }); } #[test] fn decode_to_array_oversized_input() { let err = decode_to_array::<1>(&[1, 2, 3]).err().unwrap(); assert_eq!(err.kind(), ErrorKind::Length { tag: Tag::Integer }); } #[test] fn decode_uintref() { assert_eq!(&[0], UintRef::from_der(I0_BYTES).unwrap().as_bytes()); assert_eq!(&[127], UintRef::from_der(I127_BYTES).unwrap().as_bytes()); assert_eq!(&[128], UintRef::from_der(I128_BYTES).unwrap().as_bytes()); assert_eq!(&[255], UintRef::from_der(I255_BYTES).unwrap().as_bytes()); assert_eq!( &[0x01, 0x00], UintRef::from_der(I256_BYTES).unwrap().as_bytes() ); assert_eq!( &[0x7F, 0xFF], UintRef::from_der(I32767_BYTES).unwrap().as_bytes() ); } #[test] fn encode_uintref() { for &example in &[ I0_BYTES, I127_BYTES, I128_BYTES, I255_BYTES, I256_BYTES, I32767_BYTES, ] { let uint = UintRef::from_der(example).unwrap(); let mut buf = [0u8; 128]; let mut encoder = SliceWriter::new(&mut buf); uint.encode(&mut encoder).unwrap(); let result = encoder.finish().unwrap(); assert_eq!(example, result); } } #[test] fn reject_oversize_without_extra_zero() { let err = UintRef::try_from(AnyRef::new(Tag::Integer, &[0x81]).unwrap()) .err() .unwrap(); assert_eq!(err.kind(), ErrorKind::Value { tag: Tag::Integer }); } } der-0.7.7/src/asn1/integer.rs000064400000000000000000000132531046102023000140510ustar 00000000000000//! ASN.1 `INTEGER` support. pub(super) mod int; pub(super) mod uint; use core::{cmp::Ordering, mem}; use crate::{EncodeValue, Result, SliceWriter}; /// Is the highest bit of the first byte in the slice set to `1`? (if present) #[inline] fn is_highest_bit_set(bytes: &[u8]) -> bool { bytes .first() .map(|byte| byte & 0b10000000 != 0) .unwrap_or(false) } /// Compare two integer values fn value_cmp(a: T, b: T) -> Result where T: Copy + EncodeValue + Sized, { const MAX_INT_SIZE: usize = 16; debug_assert!(mem::size_of::() <= MAX_INT_SIZE); let mut buf1 = [0u8; MAX_INT_SIZE]; let mut encoder1 = SliceWriter::new(&mut buf1); a.encode_value(&mut encoder1)?; let mut buf2 = [0u8; MAX_INT_SIZE]; let mut encoder2 = SliceWriter::new(&mut buf2); b.encode_value(&mut encoder2)?; Ok(encoder1.finish()?.cmp(encoder2.finish()?)) } #[cfg(test)] pub(crate) mod tests { use crate::{Decode, Encode}; // Vectors from Section 5.7 of: // https://luca.ntop.org/Teaching/Appunti/asn1.html pub(crate) const I0_BYTES: &[u8] = &[0x02, 0x01, 0x00]; pub(crate) const I127_BYTES: &[u8] = &[0x02, 0x01, 0x7F]; pub(crate) const I128_BYTES: &[u8] = &[0x02, 0x02, 0x00, 0x80]; pub(crate) const I256_BYTES: &[u8] = &[0x02, 0x02, 0x01, 0x00]; pub(crate) const INEG128_BYTES: &[u8] = &[0x02, 0x01, 0x80]; pub(crate) const INEG129_BYTES: &[u8] = &[0x02, 0x02, 0xFF, 0x7F]; // Additional vectors pub(crate) const I255_BYTES: &[u8] = &[0x02, 0x02, 0x00, 0xFF]; pub(crate) const I32767_BYTES: &[u8] = &[0x02, 0x02, 0x7F, 0xFF]; pub(crate) const I65535_BYTES: &[u8] = &[0x02, 0x03, 0x00, 0xFF, 0xFF]; pub(crate) const INEG32768_BYTES: &[u8] = &[0x02, 0x02, 0x80, 0x00]; #[test] fn decode_i8() { assert_eq!(0, i8::from_der(I0_BYTES).unwrap()); assert_eq!(127, i8::from_der(I127_BYTES).unwrap()); assert_eq!(-128, i8::from_der(INEG128_BYTES).unwrap()); } #[test] fn decode_i16() { assert_eq!(0, i16::from_der(I0_BYTES).unwrap()); assert_eq!(127, i16::from_der(I127_BYTES).unwrap()); assert_eq!(128, i16::from_der(I128_BYTES).unwrap()); assert_eq!(255, i16::from_der(I255_BYTES).unwrap()); assert_eq!(256, i16::from_der(I256_BYTES).unwrap()); assert_eq!(32767, i16::from_der(I32767_BYTES).unwrap()); assert_eq!(-128, i16::from_der(INEG128_BYTES).unwrap()); assert_eq!(-129, i16::from_der(INEG129_BYTES).unwrap()); assert_eq!(-32768, i16::from_der(INEG32768_BYTES).unwrap()); } #[test] fn decode_u8() { assert_eq!(0, u8::from_der(I0_BYTES).unwrap()); assert_eq!(127, u8::from_der(I127_BYTES).unwrap()); assert_eq!(255, u8::from_der(I255_BYTES).unwrap()); } #[test] fn decode_u16() { assert_eq!(0, u16::from_der(I0_BYTES).unwrap()); assert_eq!(127, u16::from_der(I127_BYTES).unwrap()); assert_eq!(255, u16::from_der(I255_BYTES).unwrap()); assert_eq!(256, u16::from_der(I256_BYTES).unwrap()); assert_eq!(32767, u16::from_der(I32767_BYTES).unwrap()); assert_eq!(65535, u16::from_der(I65535_BYTES).unwrap()); } #[test] fn encode_i8() { let mut buffer = [0u8; 3]; assert_eq!(I0_BYTES, 0i8.encode_to_slice(&mut buffer).unwrap()); assert_eq!(I127_BYTES, 127i8.encode_to_slice(&mut buffer).unwrap()); assert_eq!( INEG128_BYTES, (-128i8).encode_to_slice(&mut buffer).unwrap() ); } #[test] fn encode_i16() { let mut buffer = [0u8; 4]; assert_eq!(I0_BYTES, 0i16.encode_to_slice(&mut buffer).unwrap()); assert_eq!(I127_BYTES, 127i16.encode_to_slice(&mut buffer).unwrap()); assert_eq!(I128_BYTES, 128i16.encode_to_slice(&mut buffer).unwrap()); assert_eq!(I255_BYTES, 255i16.encode_to_slice(&mut buffer).unwrap()); assert_eq!(I256_BYTES, 256i16.encode_to_slice(&mut buffer).unwrap()); assert_eq!(I32767_BYTES, 32767i16.encode_to_slice(&mut buffer).unwrap()); assert_eq!( INEG128_BYTES, (-128i16).encode_to_slice(&mut buffer).unwrap() ); assert_eq!( INEG129_BYTES, (-129i16).encode_to_slice(&mut buffer).unwrap() ); assert_eq!( INEG32768_BYTES, (-32768i16).encode_to_slice(&mut buffer).unwrap() ); } #[test] fn encode_u8() { let mut buffer = [0u8; 4]; assert_eq!(I0_BYTES, 0u8.encode_to_slice(&mut buffer).unwrap()); assert_eq!(I127_BYTES, 127u8.encode_to_slice(&mut buffer).unwrap()); assert_eq!(I255_BYTES, 255u8.encode_to_slice(&mut buffer).unwrap()); } #[test] fn encode_u16() { let mut buffer = [0u8; 5]; assert_eq!(I0_BYTES, 0u16.encode_to_slice(&mut buffer).unwrap()); assert_eq!(I127_BYTES, 127u16.encode_to_slice(&mut buffer).unwrap()); assert_eq!(I128_BYTES, 128u16.encode_to_slice(&mut buffer).unwrap()); assert_eq!(I255_BYTES, 255u16.encode_to_slice(&mut buffer).unwrap()); assert_eq!(I256_BYTES, 256u16.encode_to_slice(&mut buffer).unwrap()); assert_eq!(I32767_BYTES, 32767u16.encode_to_slice(&mut buffer).unwrap()); assert_eq!(I65535_BYTES, 65535u16.encode_to_slice(&mut buffer).unwrap()); } /// Integers must be encoded with a minimum number of octets #[test] fn reject_non_canonical() { assert!(i8::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err()); assert!(i16::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err()); assert!(u8::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err()); assert!(u16::from_der(&[0x02, 0x02, 0x00, 0x00]).is_err()); } } der-0.7.7/src/asn1/internal_macros.rs000064400000000000000000000043761046102023000156020ustar 00000000000000macro_rules! impl_any_conversions { ($type: ty) => { impl_any_conversions!($type, ); }; ($type: ty, $($li: lifetime)?) => { impl<'__der: $($li),*, $($li),*> TryFrom<$crate::AnyRef<'__der>> for $type { type Error = $crate::Error; fn try_from(any: $crate::AnyRef<'__der>) -> Result<$type> { any.decode_as() } } #[cfg(feature = "alloc")] impl<'__der: $($li),*, $($li),*> TryFrom<&'__der $crate::Any> for $type { type Error = $crate::Error; fn try_from(any: &'__der $crate::Any) -> Result<$type> { any.decode_as() } } }; } macro_rules! impl_string_type { ($type: ty, $($li: lifetime)?) => { impl_any_conversions!($type, $($li),*); mod __impl_string { use super::*; use crate::{ ord::OrdIsValueOrd, BytesRef, DecodeValue, EncodeValue, Header, Length, Reader, Result, Writer, }; use core::{fmt, str}; impl<$($li),*> AsRef for $type { fn as_ref(&self) -> &str { self.as_str() } } impl<$($li),*> AsRef<[u8]> for $type { fn as_ref(&self) -> &[u8] { self.as_bytes() } } impl<'__der: $($li),*, $($li),*> DecodeValue<'__der> for $type { fn decode_value>(reader: &mut R, header: Header) -> Result { Self::new(BytesRef::decode_value(reader, header)?.as_slice()) } } impl<$($li),*> EncodeValue for $type { fn value_len(&self) -> Result { self.inner.value_len() } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { self.inner.encode_value(writer) } } impl<$($li),*> OrdIsValueOrd for $type {} impl<$($li),*> fmt::Display for $type { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self.as_str()) } } } }; } der-0.7.7/src/asn1/null.rs000064400000000000000000000043211046102023000133620ustar 00000000000000//! ASN.1 `NULL` support. use crate::{ asn1::AnyRef, ord::OrdIsValueOrd, BytesRef, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, Writer, }; /// ASN.1 `NULL` type. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct Null; impl_any_conversions!(Null); impl<'a> DecodeValue<'a> for Null { fn decode_value>(reader: &mut R, header: Header) -> Result { if header.length.is_zero() { Ok(Null) } else { Err(reader.error(ErrorKind::Length { tag: Self::TAG })) } } } impl EncodeValue for Null { fn value_len(&self) -> Result { Ok(Length::ZERO) } fn encode_value(&self, _writer: &mut impl Writer) -> Result<()> { Ok(()) } } impl FixedTag for Null { const TAG: Tag = Tag::Null; } impl OrdIsValueOrd for Null {} impl<'a> From for AnyRef<'a> { fn from(_: Null) -> AnyRef<'a> { AnyRef::from_tag_and_value(Tag::Null, BytesRef::default()) } } impl TryFrom> for () { type Error = Error; fn try_from(any: AnyRef<'_>) -> Result<()> { Null::try_from(any).map(|_| ()) } } impl<'a> From<()> for AnyRef<'a> { fn from(_: ()) -> AnyRef<'a> { Null.into() } } impl<'a> DecodeValue<'a> for () { fn decode_value>(reader: &mut R, header: Header) -> Result { Null::decode_value(reader, header)?; Ok(()) } } impl EncodeValue for () { fn value_len(&self) -> Result { Ok(Length::ZERO) } fn encode_value(&self, _writer: &mut impl Writer) -> Result<()> { Ok(()) } } impl FixedTag for () { const TAG: Tag = Tag::Null; } #[cfg(test)] mod tests { use super::Null; use crate::{Decode, Encode}; #[test] fn decode() { Null::from_der(&[0x05, 0x00]).unwrap(); } #[test] fn encode() { let mut buffer = [0u8; 2]; assert_eq!(&[0x05, 0x00], Null.encode_to_slice(&mut buffer).unwrap()); assert_eq!(&[0x05, 0x00], ().encode_to_slice(&mut buffer).unwrap()); } #[test] fn reject_non_canonical() { assert!(Null::from_der(&[0x05, 0x81, 0x00]).is_err()); } } der-0.7.7/src/asn1/octet_string.rs000064400000000000000000000146161046102023000151240ustar 00000000000000//! ASN.1 `OCTET STRING` support. use crate::{ asn1::AnyRef, ord::OrdIsValueOrd, BytesRef, Decode, DecodeValue, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, Writer, }; /// ASN.1 `OCTET STRING` type: borrowed form. /// /// Octet strings represent contiguous sequences of octets, a.k.a. bytes. /// /// This is a zero-copy reference type which borrows from the input data. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct OctetStringRef<'a> { /// Inner value inner: BytesRef<'a>, } impl<'a> OctetStringRef<'a> { /// Create a new ASN.1 `OCTET STRING` from a byte slice. pub fn new(slice: &'a [u8]) -> Result { BytesRef::new(slice) .map(|inner| Self { inner }) .map_err(|_| ErrorKind::Length { tag: Self::TAG }.into()) } /// Borrow the inner byte slice. pub fn as_bytes(&self) -> &'a [u8] { self.inner.as_slice() } /// Get the length of the inner byte slice. pub fn len(&self) -> Length { self.inner.len() } /// Is the inner byte slice empty? pub fn is_empty(&self) -> bool { self.inner.is_empty() } /// Parse `T` from this `OCTET STRING`'s contents. pub fn decode_into>(&self) -> Result { Decode::from_der(self.as_bytes()) } } impl_any_conversions!(OctetStringRef<'a>, 'a); impl AsRef<[u8]> for OctetStringRef<'_> { fn as_ref(&self) -> &[u8] { self.as_bytes() } } impl<'a> DecodeValue<'a> for OctetStringRef<'a> { fn decode_value>(reader: &mut R, header: Header) -> Result { let inner = BytesRef::decode_value(reader, header)?; Ok(Self { inner }) } } impl EncodeValue for OctetStringRef<'_> { fn value_len(&self) -> Result { self.inner.value_len() } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { self.inner.encode_value(writer) } } impl FixedTag for OctetStringRef<'_> { const TAG: Tag = Tag::OctetString; } impl OrdIsValueOrd for OctetStringRef<'_> {} impl<'a> From<&OctetStringRef<'a>> for OctetStringRef<'a> { fn from(value: &OctetStringRef<'a>) -> OctetStringRef<'a> { *value } } impl<'a> From> for AnyRef<'a> { fn from(octet_string: OctetStringRef<'a>) -> AnyRef<'a> { AnyRef::from_tag_and_value(Tag::OctetString, octet_string.inner) } } impl<'a> From> for &'a [u8] { fn from(octet_string: OctetStringRef<'a>) -> &'a [u8] { octet_string.as_bytes() } } #[cfg(feature = "alloc")] pub use self::allocating::OctetString; #[cfg(feature = "alloc")] mod allocating { use super::*; use crate::referenced::*; use alloc::vec::Vec; /// ASN.1 `OCTET STRING` type: owned form.. /// /// Octet strings represent contiguous sequences of octets, a.k.a. bytes. /// /// This type provides the same functionality as [`OctetStringRef`] but owns /// the backing data. #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct OctetString { /// Bitstring represented as a slice of bytes. inner: Vec, } impl OctetString { /// Create a new ASN.1 `OCTET STRING`. pub fn new(bytes: impl Into>) -> Result { let inner = bytes.into(); // Ensure the bytes parse successfully as an `OctetStringRef` OctetStringRef::new(&inner)?; Ok(Self { inner }) } /// Borrow the inner byte slice. pub fn as_bytes(&self) -> &[u8] { self.inner.as_slice() } /// Take ownership of the octet string. pub fn into_bytes(self) -> Vec { self.inner } /// Get the length of the inner byte slice. pub fn len(&self) -> Length { self.value_len().expect("invalid OCTET STRING length") } /// Is the inner byte slice empty? pub fn is_empty(&self) -> bool { self.inner.is_empty() } } impl_any_conversions!(OctetString); impl AsRef<[u8]> for OctetString { fn as_ref(&self) -> &[u8] { self.as_bytes() } } impl<'a> DecodeValue<'a> for OctetString { fn decode_value>(reader: &mut R, header: Header) -> Result { Self::new(reader.read_vec(header.length)?) } } impl EncodeValue for OctetString { fn value_len(&self) -> Result { self.inner.len().try_into() } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { writer.write(&self.inner) } } impl FixedTag for OctetString { const TAG: Tag = Tag::OctetString; } impl<'a> From<&'a OctetString> for OctetStringRef<'a> { fn from(octet_string: &'a OctetString) -> OctetStringRef<'a> { // Ensured to parse successfully in constructor OctetStringRef::new(&octet_string.inner).expect("invalid OCTET STRING") } } impl OrdIsValueOrd for OctetString {} impl<'a> RefToOwned<'a> for OctetStringRef<'a> { type Owned = OctetString; fn ref_to_owned(&self) -> Self::Owned { OctetString { inner: Vec::from(self.inner.as_slice()), } } } impl OwnedToRef for OctetString { type Borrowed<'a> = OctetStringRef<'a>; fn owned_to_ref(&self) -> Self::Borrowed<'_> { self.into() } } // Implement by hand because the derive would create invalid values. // Use the constructor to create a valid value. #[cfg(feature = "arbitrary")] impl<'a> arbitrary::Arbitrary<'a> for OctetString { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { Self::new(Vec::arbitrary(u)?).map_err(|_| arbitrary::Error::IncorrectFormat) } fn size_hint(depth: usize) -> (usize, Option) { arbitrary::size_hint::and(u8::size_hint(depth), Vec::::size_hint(depth)) } } } #[cfg(test)] mod tests { use crate::asn1::{OctetStringRef, PrintableStringRef}; #[test] fn octet_string_decode_into() { // PrintableString "hi" let der = b"\x13\x02\x68\x69"; let oct = OctetStringRef::new(der).unwrap(); let res = oct.decode_into::>().unwrap(); assert_eq!(AsRef::::as_ref(&res), "hi"); } } der-0.7.7/src/asn1/oid.rs000064400000000000000000000055031046102023000131660ustar 00000000000000//! ASN.1 `OBJECT IDENTIFIER` use crate::{ asn1::AnyRef, ord::OrdIsValueOrd, DecodeValue, EncodeValue, Error, FixedTag, Header, Length, Reader, Result, Tag, Tagged, Writer, }; use const_oid::ObjectIdentifier; #[cfg(feature = "alloc")] use super::Any; impl<'a> DecodeValue<'a> for ObjectIdentifier { fn decode_value>(reader: &mut R, header: Header) -> Result { let mut buf = [0u8; ObjectIdentifier::MAX_SIZE]; let slice = buf .get_mut(..header.length.try_into()?) .ok_or_else(|| Self::TAG.length_error())?; let actual_len = reader.read_into(slice)?.len(); debug_assert_eq!(actual_len, header.length.try_into()?); Ok(Self::from_bytes(slice)?) } } impl EncodeValue for ObjectIdentifier { fn value_len(&self) -> Result { Length::try_from(self.as_bytes().len()) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { writer.write(self.as_bytes()) } } impl FixedTag for ObjectIdentifier { const TAG: Tag = Tag::ObjectIdentifier; } impl OrdIsValueOrd for ObjectIdentifier {} impl<'a> From<&'a ObjectIdentifier> for AnyRef<'a> { fn from(oid: &'a ObjectIdentifier) -> AnyRef<'a> { // Note: ensuring an infallible conversion is possible relies on the // invariant that `const_oid::MAX_LEN <= Length::max()`. // // The `length()` test below ensures this is the case. let value = oid .as_bytes() .try_into() .expect("OID length invariant violated"); AnyRef::from_tag_and_value(Tag::ObjectIdentifier, value) } } #[cfg(feature = "alloc")] impl From for Any { fn from(oid: ObjectIdentifier) -> Any { AnyRef::from(&oid).into() } } impl TryFrom> for ObjectIdentifier { type Error = Error; fn try_from(any: AnyRef<'_>) -> Result { any.tag().assert_eq(Tag::ObjectIdentifier)?; Ok(ObjectIdentifier::from_bytes(any.value())?) } } #[cfg(test)] mod tests { use super::ObjectIdentifier; use crate::{Decode, Encode, Length}; const EXAMPLE_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549"); const EXAMPLE_OID_BYTES: &[u8; 8] = &[0x06, 0x06, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d]; #[test] fn decode() { let oid = ObjectIdentifier::from_der(EXAMPLE_OID_BYTES).unwrap(); assert_eq!(EXAMPLE_OID, oid); } #[test] fn encode() { let mut buffer = [0u8; 8]; assert_eq!( EXAMPLE_OID_BYTES, EXAMPLE_OID.encode_to_slice(&mut buffer).unwrap() ); } #[test] fn length() { // Ensure an infallible `From` conversion to `Any` will never panic assert!(ObjectIdentifier::MAX_SIZE <= Length::MAX.try_into().unwrap()); } } der-0.7.7/src/asn1/optional.rs000064400000000000000000000030241046102023000142340ustar 00000000000000//! ASN.1 `OPTIONAL` as mapped to Rust's `Option` type use crate::{Choice, Decode, DerOrd, Encode, Length, Reader, Result, Tag, Writer}; use core::cmp::Ordering; impl<'a, T> Decode<'a> for Option where T: Choice<'a>, // NOTE: all `Decode + Tagged` types receive a blanket `Choice` impl { fn decode>(reader: &mut R) -> Result> { if let Some(byte) = reader.peek_byte() { if T::can_decode(Tag::try_from(byte)?) { return T::decode(reader).map(Some); } } Ok(None) } } impl DerOrd for Option where T: DerOrd, { fn der_cmp(&self, other: &Self) -> Result { match self { Some(a) => match other { Some(b) => a.der_cmp(b), None => Ok(Ordering::Greater), }, None => Ok(Ordering::Less), } } } impl Encode for Option where T: Encode, { fn encoded_len(&self) -> Result { (&self).encoded_len() } fn encode(&self, writer: &mut impl Writer) -> Result<()> { (&self).encode(writer) } } impl Encode for &Option where T: Encode, { fn encoded_len(&self) -> Result { match self { Some(encodable) => encodable.encoded_len(), None => Ok(0u8.into()), } } fn encode(&self, encoder: &mut impl Writer) -> Result<()> { match self { Some(encodable) => encodable.encode(encoder), None => Ok(()), } } } der-0.7.7/src/asn1/printable_string.rs000064400000000000000000000146731046102023000157710ustar 00000000000000//! ASN.1 `PrintableString` support. use crate::{asn1::AnyRef, FixedTag, Result, StrRef, Tag}; use core::{fmt, ops::Deref}; macro_rules! impl_printable_string { ($type: ty) => { impl_printable_string!($type,); }; ($type: ty, $($li: lifetime)?) => { impl_string_type!($type, $($li),*); impl<$($li),*> FixedTag for $type { const TAG: Tag = Tag::PrintableString; } impl<$($li),*> fmt::Debug for $type { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "PrintableString({:?})", self.as_str()) } } }; } /// ASN.1 `PrintableString` type. /// /// Supports a subset the ASCII character set (described below). /// /// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead. /// For the full ASCII character set, use /// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`]. /// /// This is a zero-copy reference type which borrows from the input data. /// /// # Supported characters /// /// The following ASCII characters/ranges are supported: /// /// - `A..Z` /// - `a..z` /// - `0..9` /// - "` `" (i.e. space) /// - `\` /// - `(` /// - `)` /// - `+` /// - `,` /// - `-` /// - `.` /// - `/` /// - `:` /// - `=` /// - `?` #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] pub struct PrintableStringRef<'a> { /// Inner value inner: StrRef<'a>, } impl<'a> PrintableStringRef<'a> { /// Create a new ASN.1 `PrintableString`. pub fn new(input: &'a T) -> Result where T: AsRef<[u8]> + ?Sized, { let input = input.as_ref(); // Validate all characters are within PrintableString's allowed set for &c in input.iter() { match c { b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b' ' | b'\'' | b'(' | b')' | b'+' | b',' | b'-' | b'.' | b'/' | b':' | b'=' | b'?' => (), _ => return Err(Self::TAG.value_error()), } } StrRef::from_bytes(input) .map(|inner| Self { inner }) .map_err(|_| Self::TAG.value_error()) } } impl_printable_string!(PrintableStringRef<'a>, 'a); impl<'a> Deref for PrintableStringRef<'a> { type Target = StrRef<'a>; fn deref(&self) -> &Self::Target { &self.inner } } impl<'a> From<&PrintableStringRef<'a>> for PrintableStringRef<'a> { fn from(value: &PrintableStringRef<'a>) -> PrintableStringRef<'a> { *value } } impl<'a> From> for AnyRef<'a> { fn from(printable_string: PrintableStringRef<'a>) -> AnyRef<'a> { AnyRef::from_tag_and_value(Tag::PrintableString, printable_string.inner.into()) } } #[cfg(feature = "alloc")] pub use self::allocation::PrintableString; #[cfg(feature = "alloc")] mod allocation { use super::PrintableStringRef; use crate::{ asn1::AnyRef, referenced::{OwnedToRef, RefToOwned}, BytesRef, Error, FixedTag, Result, StrOwned, Tag, }; use alloc::string::String; use core::{fmt, ops::Deref}; /// ASN.1 `PrintableString` type. /// /// Supports a subset the ASCII character set (described below). /// /// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead. /// For the full ASCII character set, use /// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`]. /// /// # Supported characters /// /// The following ASCII characters/ranges are supported: /// /// - `A..Z` /// - `a..z` /// - `0..9` /// - "` `" (i.e. space) /// - `\` /// - `(` /// - `)` /// - `+` /// - `,` /// - `-` /// - `.` /// - `/` /// - `:` /// - `=` /// - `?` #[derive(Clone, Eq, PartialEq, PartialOrd, Ord)] pub struct PrintableString { /// Inner value inner: StrOwned, } impl PrintableString { /// Create a new ASN.1 `PrintableString`. pub fn new(input: &T) -> Result where T: AsRef<[u8]> + ?Sized, { let input = input.as_ref(); PrintableStringRef::new(input)?; StrOwned::from_bytes(input) .map(|inner| Self { inner }) .map_err(|_| Self::TAG.value_error()) } } impl_printable_string!(PrintableString); impl Deref for PrintableString { type Target = StrOwned; fn deref(&self) -> &Self::Target { &self.inner } } impl<'a> From> for PrintableString { fn from(value: PrintableStringRef<'a>) -> PrintableString { let inner = StrOwned::from_bytes(value.inner.as_bytes()).expect("Invalid PrintableString"); Self { inner } } } impl<'a> From<&'a PrintableString> for AnyRef<'a> { fn from(printable_string: &'a PrintableString) -> AnyRef<'a> { AnyRef::from_tag_and_value( Tag::PrintableString, BytesRef::new(printable_string.inner.as_bytes()).expect("Invalid PrintableString"), ) } } impl<'a> RefToOwned<'a> for PrintableStringRef<'a> { type Owned = PrintableString; fn ref_to_owned(&self) -> Self::Owned { PrintableString { inner: self.inner.ref_to_owned(), } } } impl OwnedToRef for PrintableString { type Borrowed<'a> = PrintableStringRef<'a>; fn owned_to_ref(&self) -> Self::Borrowed<'_> { PrintableStringRef { inner: self.inner.owned_to_ref(), } } } impl TryFrom for PrintableString { type Error = Error; fn try_from(input: String) -> Result { PrintableStringRef::new(&input)?; StrOwned::new(input) .map(|inner| Self { inner }) .map_err(|_| Self::TAG.value_error()) } } } #[cfg(test)] mod tests { use super::PrintableStringRef; use crate::Decode; #[test] fn parse_bytes() { let example_bytes = &[ 0x13, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x65, 0x72, 0x20, 0x31, ]; let printable_string = PrintableStringRef::from_der(example_bytes).unwrap(); assert_eq!(printable_string.as_str(), "Test User 1"); } } der-0.7.7/src/asn1/real.rs000064400000000000000000001047411046102023000133420ustar 00000000000000//! ASN.1 `REAL` support. // TODO(tarcieri): checked arithmetic #![allow( clippy::cast_lossless, clippy::cast_sign_loss, clippy::integer_arithmetic )] use crate::{ BytesRef, DecodeValue, EncodeValue, FixedTag, Header, Length, Reader, Result, StrRef, Tag, Writer, }; use super::integer::uint::strip_leading_zeroes; impl<'a> DecodeValue<'a> for f64 { fn decode_value>(reader: &mut R, header: Header) -> Result { let bytes = BytesRef::decode_value(reader, header)?.as_slice(); if header.length == Length::ZERO { Ok(0.0) } else if is_nth_bit_one::<7>(bytes) { // Binary encoding from section 8.5.7 applies let sign: u64 = u64::from(is_nth_bit_one::<6>(bytes)); // Section 8.5.7.2: Check the base -- the DER specs say that only base 2 should be supported in DER let base = mnth_bits_to_u8::<5, 4>(bytes); if base != 0 { // Real related error: base is not DER compliant (base encoded in enum) return Err(Tag::Real.value_error()); } // Section 8.5.7.3 let scaling_factor = mnth_bits_to_u8::<3, 2>(bytes); // Section 8.5.7.4 let mantissa_start; let exponent = match mnth_bits_to_u8::<1, 0>(bytes) { 0 => { mantissa_start = 2; let ebytes = (i16::from_be_bytes([0x0, bytes[1]])).to_be_bytes(); u64::from_be_bytes([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ebytes[0], ebytes[1]]) } 1 => { mantissa_start = 3; let ebytes = (i16::from_be_bytes([bytes[1], bytes[2]])).to_be_bytes(); u64::from_be_bytes([0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ebytes[0], ebytes[1]]) } _ => { // Real related error: encoded exponent cannot be represented on an IEEE-754 double return Err(Tag::Real.value_error()); } }; // Section 8.5.7.5: Read the remaining bytes for the mantissa let mut n_bytes = [0x0; 8]; for (pos, byte) in bytes[mantissa_start..].iter().rev().enumerate() { n_bytes[7 - pos] = *byte; } let n = u64::from_be_bytes(n_bytes); // Multiply byt 2^F corresponds to just a left shift let mantissa = n << scaling_factor; // Create the f64 Ok(encode_f64(sign, exponent, mantissa)) } else if is_nth_bit_one::<6>(bytes) { // This either a special value, or it's the value minus zero is encoded, section 8.5.9 applies match mnth_bits_to_u8::<1, 0>(bytes) { 0 => Ok(f64::INFINITY), 1 => Ok(f64::NEG_INFINITY), 2 => Ok(f64::NAN), 3 => Ok(-0.0_f64), _ => Err(Tag::Real.value_error()), } } else { let astr = StrRef::from_bytes(&bytes[1..])?; match astr.inner.parse::() { Ok(val) => Ok(val), // Real related error: encoding not supported or malformed Err(_) => Err(Tag::Real.value_error()), } } } } impl EncodeValue for f64 { fn value_len(&self) -> Result { if self.is_sign_positive() && (*self) < f64::MIN_POSITIVE { // Zero: positive yet smaller than the minimum positive number Ok(Length::ZERO) } else if self.is_nan() || self.is_infinite() || (self.is_sign_negative() && -self < f64::MIN_POSITIVE) { // NaN, infinite (positive or negative), or negative zero (negative but its negative is less than the min positive number) Ok(Length::ONE) } else { // The length is that of the first octets plus those needed for the exponent plus those needed for the mantissa let (_sign, exponent, mantissa) = decode_f64(*self); let exponent_len = if exponent == 0 { // Section 8.5.7.4: there must be at least one octet for exponent encoding // But, if the exponent is zero, it'll be skipped, so we make sure force it to 1 Length::ONE } else { let ebytes = exponent.to_be_bytes(); Length::try_from(strip_leading_zeroes(&ebytes).len())? }; let mantissa_len = if mantissa == 0 { Length::ONE } else { let mbytes = mantissa.to_be_bytes(); Length::try_from(strip_leading_zeroes(&mbytes).len())? }; exponent_len + mantissa_len + Length::ONE } } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { // Check if special value // Encode zero first, if it's zero // Special value from section 8.5.9 if non zero if self.is_nan() || self.is_infinite() || (self.is_sign_negative() && -self < f64::MIN_POSITIVE) || (self.is_sign_positive() && (*self) < f64::MIN_POSITIVE) { if self.is_sign_positive() && (*self) < f64::MIN_POSITIVE { // Zero return Ok(()); } else if self.is_nan() { // Not a number writer.write_byte(0b0100_0010)?; } else if self.is_infinite() { if self.is_sign_negative() { // Negative infinity writer.write_byte(0b0100_0001)?; } else { // Plus infinity writer.write_byte(0b0100_0000)?; } } else { // Minus zero writer.write_byte(0b0100_0011)?; } } else { // Always use binary encoding, set bit 8 to 1 let mut first_byte = 0b1000_0000; if self.is_sign_negative() { // Section 8.5.7.1: set bit 7 to 1 if negative first_byte |= 0b0100_0000; } // Bits 6 and 5 are set to 0 to specify that binary encoding is used // // NOTE: the scaling factor is only used to align the implicit point of the mantissa. // This is unnecessary in DER because the base is 2, and therefore necessarily aligned. // Therefore, we do not modify the mantissa in anyway after this function call, which // already adds the implicit one of the IEEE 754 representation. let (_sign, exponent, mantissa) = decode_f64(*self); // Encode the exponent as two's complement on 16 bits and remove the bias let exponent_bytes = exponent.to_be_bytes(); let ebytes = strip_leading_zeroes(&exponent_bytes); match ebytes.len() { 0 | 1 => {} 2 => first_byte |= 0b0000_0001, 3 => first_byte |= 0b0000_0010, _ => { // TODO: support multi octet exponent encoding? return Err(Tag::Real.value_error()); } } writer.write_byte(first_byte)?; // Encode both bytes or just the last one, handled by encode_bytes directly // Rust already encodes the data as two's complement, so no further processing is needed writer.write(ebytes)?; // Now, encode the mantissa as unsigned binary number let mantissa_bytes = mantissa.to_be_bytes(); let mbytes = strip_leading_zeroes(&mantissa_bytes); writer.write(mbytes)?; } Ok(()) } } impl FixedTag for f64 { const TAG: Tag = Tag::Real; } /// Is the N-th bit 1 in the first octet? /// NOTE: this function is zero indexed pub(crate) fn is_nth_bit_one(bytes: &[u8]) -> bool { if N < 8 { bytes .first() .map(|byte| byte & (1 << N) != 0) .unwrap_or(false) } else { false } } /// Convert bits M, N into a u8, in the first octet only pub(crate) fn mnth_bits_to_u8(bytes: &[u8]) -> u8 { let bit_m = is_nth_bit_one::(bytes); let bit_n = is_nth_bit_one::(bytes); (bit_m as u8) << 1 | bit_n as u8 } /// Decode an f64 as its sign, exponent, and mantissa in u64 and in that order, using bit shifts and masks. /// Note: this function **removes** the 1023 bias from the exponent and adds the implicit 1 #[allow(clippy::cast_possible_truncation)] pub(crate) fn decode_f64(f: f64) -> (u64, u64, u64) { let bits = f.to_bits(); let sign = bits >> 63; let exponent = bits >> 52 & 0x7ff; let exponent_bytes_no_bias = (exponent as i16 - 1023).to_be_bytes(); let exponent_no_bias = u64::from_be_bytes([ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, exponent_bytes_no_bias[0], exponent_bytes_no_bias[1], ]); let mantissa = bits & 0xfffffffffffff; (sign, exponent_no_bias, mantissa + 1) } /// Encode an f64 from its sign, exponent (**without** the 1023 bias), and (mantissa - 1) using bit shifts as received by ASN1 pub(crate) fn encode_f64(sign: u64, exponent: u64, mantissa: u64) -> f64 { // Add the bias to the exponent let exponent_with_bias = (i16::from_be_bytes([exponent.to_be_bytes()[6], exponent.to_be_bytes()[7]]) + 1023) as u64; let bits = sign << 63 | exponent_with_bias << 52 | (mantissa - 1); f64::from_bits(bits) } #[cfg(test)] mod tests { use crate::{Decode, Encode}; #[test] fn decode_subnormal() { assert!(f64::from_der(&[0x09, 0x01, 0b0100_0010]).unwrap().is_nan()); let plus_infty = f64::from_der(&[0x09, 0x01, 0b0100_0000]).unwrap(); assert!(plus_infty.is_infinite() && plus_infty.is_sign_positive()); let neg_infty = f64::from_der(&[0x09, 0x01, 0b0100_0001]).unwrap(); assert!(neg_infty.is_infinite() && neg_infty.is_sign_negative()); let neg_zero = f64::from_der(&[0x09, 0x01, 0b0100_0011]).unwrap(); assert!(neg_zero.is_sign_negative() && neg_zero.abs() < f64::EPSILON); } #[test] fn encode_subnormal() { // All subnormal fit in three bytes let mut buffer = [0u8; 3]; assert_eq!( &[0x09, 0x01, 0b0100_0010], f64::NAN.encode_to_slice(&mut buffer).unwrap() ); assert_eq!( &[0x09, 0x01, 0b0100_0000], f64::INFINITY.encode_to_slice(&mut buffer).unwrap() ); assert_eq!( &[0x09, 0x01, 0b0100_0001], f64::NEG_INFINITY.encode_to_slice(&mut buffer).unwrap() ); assert_eq!( &[0x09, 0x01, 0b0100_0011], (-0.0_f64).encode_to_slice(&mut buffer).unwrap() ); } #[test] fn encdec_normal() { // The comments correspond to the decoded value from the ASN.1 playground when the bytes are inputed. { // rec1value R ::= 0 let val = 0.0; let expected = &[0x09, 0x0]; let mut buffer = [0u8; 2]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } { // rec1value R ::= { mantissa 1, base 2, exponent 0 } let val = 1.0; let expected = &[0x09, 0x03, 0x80, 0x00, 0x01]; let mut buffer = [0u8; 5]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } { // rec1value R ::= { mantissa -1, base 2, exponent 0 } let val = -1.0; let expected = &[0x09, 0x03, 0xc0, 0x00, 0x01]; let mut buffer = [0u8; 5]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } { // rec1value R ::= { mantissa -1, base 2, exponent 1 } let val = -1.0000000000000002; let expected = &[0x09, 0x03, 0xc0, 0x00, 0x02]; let mut buffer = [0u8; 5]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } { // rec1value R ::= { mantissa 1, base 2, exponent -1022 } // NOTE: f64::MIN_EXP == -1021 so the exponent decoded by ASN.1 is what we expect let val = f64::MIN_POSITIVE; let expected = &[0x09, 0x04, 0x81, 0xfc, 0x02, 0x01]; let mut buffer = [0u8; 7]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } { // rec4value R ::= { mantissa 1, base 2, exponent 3 } let val = 1.0000000000000016; let expected = &[0x09, 0x03, 0x80, 0x00, 0x08]; let mut buffer = [0u8; 5]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } { // rec5value R ::= { mantissa 4222124650659841, base 2, exponent 4 } let val = 31.0; let expected = &[ 0x9, 0x9, 0x80, 0x04, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, ]; let mut buffer = [0u8; 11]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } } #[test] fn encdec_irrationals() { { let val = core::f64::consts::PI; let expected = &[ 0x09, 0x09, 0x80, 0x01, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x19, ]; let mut buffer = [0u8; 11]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } { let val = core::f64::consts::E; let expected = &[ 0x09, 0x09, 0x80, 0x01, 0x05, 0xbf, 0x0a, 0x8b, 0x14, 0x57, 0x6a, ]; let mut buffer = [0u8; 12]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } { let val = core::f64::consts::LN_2; let expected = &[ 0x09, 0x0a, 0x81, 0xff, 0xff, 0x6, 0x2e, 0x42, 0xfe, 0xfa, 0x39, 0xf0, ]; let mut buffer = [0u8; 12]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } } #[test] fn encdec_reasonable_f64() { // Tests the encoding and decoding of reals with some arbitrary numbers { // rec1value R ::= { mantissa 2414341043715239, base 2, exponent 21 } let val = 3221417.1584163485; let expected = &[ 0x9, 0x9, 0x80, 0x15, 0x8, 0x93, 0xd4, 0x94, 0x46, 0xfc, 0xa7, ]; let mut buffer = [0u8; 11]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } { // rec1value R ::= { mantissa 2671155248072715, base 2, exponent 23 } let val = 13364022.365665454; let expected = &[ 0x09, 0x09, 0x80, 0x17, 0x09, 0x7d, 0x66, 0xcb, 0xb3, 0x88, 0x0b, ]; let mut buffer = [0u8; 12]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } { // rec1value R ::= { mantissa -4386812962460287, base 2, exponent 14 } let val = -32343.132588105735; let expected = &[ 0x09, 0x09, 0xc0, 0x0e, 0x0f, 0x95, 0xc8, 0x7c, 0x52, 0xd2, 0x7f, ]; let mut buffer = [0u8; 12]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } { let val = -27084.866751869475; let expected = &[ 0x09, 0x09, 0xc0, 0x0e, 0x0a, 0x73, 0x37, 0x78, 0xdc, 0xd5, 0x4a, ]; let mut buffer = [0u8; 12]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } { // rec1value R ::= { mantissa -4372913134428149, base 2, exponent 7 } let val = -252.28566647111404; let expected = &[ 0x09, 0x09, 0xc0, 0x07, 0x0f, 0x89, 0x24, 0x2e, 0x02, 0xdf, 0xf5, ]; let mut buffer = [0u8; 12]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } { let val = -14.399709612928548; let expected = &[ 0x09, 0x09, 0xc0, 0x03, 0x0c, 0xcc, 0xa6, 0xbd, 0x06, 0xd9, 0x92, ]; let mut buffer = [0u8; 12]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } { let val = -0.08340570261832964; let expected = &[ 0x09, 0x0a, 0xc1, 0xff, 0xfc, 0x05, 0x5a, 0x13, 0x7d, 0x0b, 0xae, 0x3d, ]; let mut buffer = [0u8; 12]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } { let val = 0.00536851453803701; let expected = &[ 0x09, 0x0a, 0x81, 0xff, 0xf8, 0x05, 0xfd, 0x4b, 0xa5, 0xe7, 0x4c, 0x93, ]; let mut buffer = [0u8; 12]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } { let val = 0.00045183525648866433; let expected = &[ 0x09, 0x0a, 0x81, 0xff, 0xf4, 0x0d, 0x9c, 0x89, 0xa6, 0x59, 0x33, 0x39, ]; let mut buffer = [0u8; 12]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } { let val = 0.000033869092002682955; let expected = &[ 0x09, 0x0a, 0x81, 0xff, 0xf1, 0x01, 0xc1, 0xd5, 0x23, 0xd5, 0x54, 0x7c, ]; let mut buffer = [0u8; 12]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } { let val = 0.0000011770891033600088; let expected = &[ 0x09, 0x0a, 0x81, 0xff, 0xec, 0x03, 0xbf, 0x8f, 0x27, 0xf4, 0x62, 0x56, ]; let mut buffer = [0u8; 12]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } { let val = 0.00000005549514041997082; let expected = &[ 0x09, 0x0a, 0x81, 0xff, 0xe7, 0x0d, 0xcb, 0x31, 0xab, 0x6e, 0xb8, 0xd7, ]; let mut buffer = [0u8; 12]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } { let val = 0.0000000012707044685547803; let expected = &[ 0x09, 0x0a, 0x81, 0xff, 0xe2, 0x05, 0xd4, 0x9e, 0x0a, 0xf2, 0xff, 0x1f, ]; let mut buffer = [0u8; 12]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } { let val = 0.00000000002969611878378562; let expected = &[ 0x09, 0x09, 0x81, 0xff, 0xdd, 0x53, 0x5b, 0x6f, 0x97, 0xee, 0xb6, ]; let mut buffer = [0u8; 11]; let encoded = val.encode_to_slice(&mut buffer).unwrap(); assert_eq!( expected, encoded, "invalid encoding of {}:\ngot {:x?}\nwant: {:x?}", val, encoded, expected ); let decoded = f64::from_der(encoded).unwrap(); assert!( (decoded - val).abs() < f64::EPSILON, "wanted: {}\tgot: {}", val, decoded ); } } #[test] fn reject_non_canonical() { assert!(f64::from_der(&[0x09, 0x81, 0x00]).is_err()); } #[test] fn encdec_f64() { use super::{decode_f64, encode_f64}; // Test that the extraction and recreation works for val in [ 1.0, 0.1, -0.1, -1.0, 0.0, f64::MIN_POSITIVE, f64::MAX, f64::MIN, 3.1415, 951.2357864, -3.1415, -951.2357864, ] { let (s, e, m) = decode_f64(val); let val2 = encode_f64(s, e, m); assert!( (val - val2).abs() < f64::EPSILON, "fail - want {}\tgot {}", val, val2 ); } } #[test] fn validation_cases() { // Caveat: these test cases are validated on the ASN.1 playground: https://asn1.io/asn1playground/ . // The test case consists in inputing the bytes in the "decode" field and checking that the decoded // value corresponds to the one encoded here. // This tool encodes _all_ values that are non-zero in the ISO 6093 NR3 representation. // This does not seem to perfectly adhere to the ITU specifications, Special Cases section. // The implementation of this crate correctly supports decoding such values. It will, however, // systematically encode REALs in their base 2 form, with a scaling factor where needed to // ensure that the mantissa is either odd or zero (as per section 11.3.1). // Positive trivial numbers { let expect = 10.0; let testcase = &[0x09, 0x05, 0x03, 0x31, 0x2E, 0x45, 0x31]; let decoded = f64::from_der(testcase).unwrap(); assert!( (decoded - expect).abs() < f64::EPSILON, "wanted: {}\tgot: {}", expect, decoded ); } { let expect = 100.0; let testcase = &[0x09, 0x05, 0x03, 0x31, 0x2E, 0x45, 0x32]; let decoded = f64::from_der(testcase).unwrap(); assert!( (decoded - expect).abs() < f64::EPSILON, "wanted: {}\tgot: {}", expect, decoded ); } { let expect = 101.0; let testcase = &[0x09, 0x08, 0x03, 0x31, 0x30, 0x31, 0x2E, 0x45, 0x2B, 0x30]; let decoded = f64::from_der(testcase).unwrap(); assert!( (decoded - expect).abs() < f64::EPSILON, "wanted: {}\tgot: {}", expect, decoded ); } { let expect = 101.0; let testcase = &[0x09, 0x08, 0x03, 0x31, 0x30, 0x31, 0x2E, 0x45, 0x2B, 0x30]; let decoded = f64::from_der(testcase).unwrap(); assert!( (decoded - expect).abs() < f64::EPSILON, "wanted: {}\tgot: {}", expect, decoded ); } { let expect = 0.0; let testcase = &[0x09, 0x00]; let decoded = f64::from_der(testcase).unwrap(); assert!( (decoded - expect).abs() < f64::EPSILON, "wanted: {}\tgot: {}", expect, decoded ); } { let expect = 951.2357864; let testcase = &[ 0x09, 0x0F, 0x03, 0x39, 0x35, 0x31, 0x32, 0x33, 0x35, 0x37, 0x38, 0x36, 0x34, 0x2E, 0x45, 0x2D, 0x37, ]; let decoded = f64::from_der(testcase).unwrap(); assert!( (decoded - expect).abs() < f64::EPSILON, "wanted: {}\tgot: {}", expect, decoded ); } // Negative trivial numbers { let expect = -10.0; let testcase = &[0x09, 0x06, 0x03, 0x2D, 0x31, 0x2E, 0x45, 0x31]; let decoded = f64::from_der(testcase).unwrap(); assert!( (decoded - expect).abs() < f64::EPSILON, "wanted: {}\tgot: {}", expect, decoded ); } { let expect = -100.0; let testcase = &[0x09, 0x06, 0x03, 0x2D, 0x31, 0x2E, 0x45, 0x32]; let decoded = f64::from_der(testcase).unwrap(); assert!( (decoded - expect).abs() < f64::EPSILON, "wanted: {}\tgot: {}", expect, decoded ); } { let expect = -101.0; let testcase = &[ 0x09, 0x09, 0x03, 0x2D, 0x31, 0x30, 0x31, 0x2E, 0x45, 0x2B, 0x30, ]; let decoded = f64::from_der(testcase).unwrap(); assert!( (decoded - expect).abs() < f64::EPSILON, "wanted: {}\tgot: {}", expect, decoded ); } { let expect = -0.5; let testcase = &[0x09, 0x07, 0x03, 0x2D, 0x35, 0x2E, 0x45, 0x2D, 0x31]; let decoded = f64::from_der(testcase).unwrap(); assert!( (decoded - expect).abs() < f64::EPSILON, "wanted: {}\tgot: {}", expect, decoded ); } { let expect = -0.0; let testcase = &[0x09, 0x03, 0x01, 0x2D, 0x30]; let decoded = f64::from_der(testcase).unwrap(); assert!( (decoded - expect).abs() < f64::EPSILON, "wanted: {}\tgot: {}", expect, decoded ); } { // Test NR3 decoding let expect = -951.2357864; let testcase = &[ 0x09, 0x10, 0x03, 0x2D, 0x39, 0x35, 0x31, 0x32, 0x33, 0x35, 0x37, 0x38, 0x36, 0x34, 0x2E, 0x45, 0x2D, 0x37, ]; let decoded = f64::from_der(testcase).unwrap(); assert!( (decoded - expect).abs() < f64::EPSILON, "wanted: {}\tgot: {}", expect, decoded ); } } } der-0.7.7/src/asn1/sequence.rs000064400000000000000000000025531046102023000142250ustar 00000000000000//! The [`Sequence`] trait simplifies writing decoders/encoders which map ASN.1 //! `SEQUENCE`s to Rust structs. use crate::{ BytesRef, DecodeValue, EncodeValue, FixedTag, Header, Length, Reader, Result, Tag, Writer, }; #[cfg(feature = "alloc")] use alloc::boxed::Box; /// Marker trait for ASN.1 `SEQUENCE`s. /// /// This is mainly used for custom derive. pub trait Sequence<'a>: DecodeValue<'a> + EncodeValue {} impl<'a, S> FixedTag for S where S: Sequence<'a>, { const TAG: Tag = Tag::Sequence; } #[cfg(feature = "alloc")] impl<'a, T> Sequence<'a> for Box where T: Sequence<'a> {} /// The [`SequenceRef`] type provides raw access to the octets which comprise a /// DER-encoded `SEQUENCE`. /// /// This is a zero-copy reference type which borrows from the input data. pub struct SequenceRef<'a> { /// Body of the `SEQUENCE`. body: BytesRef<'a>, } impl<'a> DecodeValue<'a> for SequenceRef<'a> { fn decode_value>(reader: &mut R, header: Header) -> Result { Ok(Self { body: BytesRef::decode_value(reader, header)?, }) } } impl EncodeValue for SequenceRef<'_> { fn value_len(&self) -> Result { Ok(self.body.len()) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { self.body.encode_value(writer) } } impl<'a> Sequence<'a> for SequenceRef<'a> {} der-0.7.7/src/asn1/sequence_of.rs000064400000000000000000000126221046102023000147070ustar 00000000000000//! ASN.1 `SEQUENCE OF` support. use crate::{ arrayvec, ord::iter_cmp, ArrayVec, Decode, DecodeValue, DerOrd, Encode, EncodeValue, FixedTag, Header, Length, Reader, Result, Tag, ValueOrd, Writer, }; use core::cmp::Ordering; #[cfg(feature = "alloc")] use alloc::vec::Vec; /// ASN.1 `SEQUENCE OF` backed by an array. /// /// This type implements an append-only `SEQUENCE OF` type which is stack-based /// and does not depend on `alloc` support. // TODO(tarcieri): use `ArrayVec` when/if it's merged into `core` // See: https://github.com/rust-lang/rfcs/pull/2990 #[derive(Clone, Debug, Eq, PartialEq)] pub struct SequenceOf { inner: ArrayVec, } impl SequenceOf { /// Create a new [`SequenceOf`]. pub fn new() -> Self { Self { inner: ArrayVec::new(), } } /// Add an element to this [`SequenceOf`]. pub fn add(&mut self, element: T) -> Result<()> { self.inner.push(element) } /// Get an element of this [`SequenceOf`]. pub fn get(&self, index: usize) -> Option<&T> { self.inner.get(index) } /// Iterate over the elements in this [`SequenceOf`]. pub fn iter(&self) -> SequenceOfIter<'_, T> { SequenceOfIter { inner: self.inner.iter(), } } /// Is this [`SequenceOf`] empty? pub fn is_empty(&self) -> bool { self.inner.is_empty() } /// Number of elements in this [`SequenceOf`]. pub fn len(&self) -> usize { self.inner.len() } } impl Default for SequenceOf { fn default() -> Self { Self::new() } } impl<'a, T, const N: usize> DecodeValue<'a> for SequenceOf where T: Decode<'a>, { fn decode_value>(reader: &mut R, header: Header) -> Result { reader.read_nested(header.length, |reader| { let mut sequence_of = Self::new(); while !reader.is_finished() { sequence_of.add(T::decode(reader)?)?; } Ok(sequence_of) }) } } impl EncodeValue for SequenceOf where T: Encode, { fn value_len(&self) -> Result { self.iter() .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { for elem in self.iter() { elem.encode(writer)?; } Ok(()) } } impl FixedTag for SequenceOf { const TAG: Tag = Tag::Sequence; } impl ValueOrd for SequenceOf where T: DerOrd, { fn value_cmp(&self, other: &Self) -> Result { iter_cmp(self.iter(), other.iter()) } } /// Iterator over the elements of an [`SequenceOf`]. #[derive(Clone, Debug)] pub struct SequenceOfIter<'a, T> { /// Inner iterator. inner: arrayvec::Iter<'a, T>, } impl<'a, T> Iterator for SequenceOfIter<'a, T> { type Item = &'a T; fn next(&mut self) -> Option<&'a T> { self.inner.next() } } impl<'a, T> ExactSizeIterator for SequenceOfIter<'a, T> {} impl<'a, T, const N: usize> DecodeValue<'a> for [T; N] where T: Decode<'a>, { fn decode_value>(reader: &mut R, header: Header) -> Result { let sequence_of = SequenceOf::::decode_value(reader, header)?; // TODO(tarcieri): use `[T; N]::try_map` instead of `expect` when stable if sequence_of.inner.len() == N { Ok(sequence_of .inner .into_array() .map(|elem| elem.expect("arrayvec length mismatch"))) } else { Err(Self::TAG.length_error()) } } } impl EncodeValue for [T; N] where T: Encode, { fn value_len(&self) -> Result { self.iter() .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { for elem in self { elem.encode(writer)?; } Ok(()) } } impl FixedTag for [T; N] { const TAG: Tag = Tag::Sequence; } impl ValueOrd for [T; N] where T: DerOrd, { fn value_cmp(&self, other: &Self) -> Result { iter_cmp(self.iter(), other.iter()) } } #[cfg(feature = "alloc")] impl<'a, T> DecodeValue<'a> for Vec where T: Decode<'a>, { fn decode_value>(reader: &mut R, header: Header) -> Result { reader.read_nested(header.length, |reader| { let mut sequence_of = Self::new(); while !reader.is_finished() { sequence_of.push(T::decode(reader)?); } Ok(sequence_of) }) } } #[cfg(feature = "alloc")] impl EncodeValue for Vec where T: Encode, { fn value_len(&self) -> Result { self.iter() .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { for elem in self { elem.encode(writer)?; } Ok(()) } } #[cfg(feature = "alloc")] impl FixedTag for Vec { const TAG: Tag = Tag::Sequence; } #[cfg(feature = "alloc")] impl ValueOrd for Vec where T: DerOrd, { fn value_cmp(&self, other: &Self) -> Result { iter_cmp(self.iter(), other.iter()) } } der-0.7.7/src/asn1/set_of.rs000064400000000000000000000330661046102023000136770ustar 00000000000000//! ASN.1 `SET OF` support. //! //! # Ordering Notes //! //! Some DER serializer implementations fail to properly sort elements of a //! `SET OF`. This is technically non-canonical, but occurs frequently //! enough that most DER decoders tolerate it. Unfortunately because //! of that, we must also follow suit. //! //! However, all types in this module sort elements of a set at decode-time, //! ensuring they'll be in the proper order if reserialized. use crate::{ arrayvec, ord::iter_cmp, ArrayVec, Decode, DecodeValue, DerOrd, Encode, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, ValueOrd, Writer, }; use core::cmp::Ordering; #[cfg(feature = "alloc")] use {alloc::vec::Vec, core::slice}; /// ASN.1 `SET OF` backed by an array. /// /// This type implements an append-only `SET OF` type which is stack-based /// and does not depend on `alloc` support. // TODO(tarcieri): use `ArrayVec` when/if it's merged into `core` // See: https://github.com/rust-lang/rfcs/pull/2990 #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct SetOf where T: DerOrd, { inner: ArrayVec, } impl SetOf where T: DerOrd, { /// Create a new [`SetOf`]. pub fn new() -> Self { Self { inner: ArrayVec::default(), } } /// Add an item to this [`SetOf`]. /// /// Items MUST be added in lexicographical order according to the /// [`DerOrd`] impl on `T`. #[deprecated(since = "0.7.6", note = "use `insert` or `insert_ordered` instead")] pub fn add(&mut self, new_elem: T) -> Result<()> { self.insert_ordered(new_elem) } /// Insert an item into this [`SetOf`]. pub fn insert(&mut self, item: T) -> Result<()> { self.inner.push(item)?; der_sort(self.inner.as_mut()) } /// Insert an item into this [`SetOf`]. /// /// Items MUST be added in lexicographical order according to the /// [`DerOrd`] impl on `T`. pub fn insert_ordered(&mut self, item: T) -> Result<()> { // Ensure set elements are lexicographically ordered if let Some(last) = self.inner.last() { check_der_ordering(last, &item)?; } self.inner.push(item) } /// Get the nth element from this [`SetOf`]. pub fn get(&self, index: usize) -> Option<&T> { self.inner.get(index) } /// Iterate over the elements of this [`SetOf`]. pub fn iter(&self) -> SetOfIter<'_, T> { SetOfIter { inner: self.inner.iter(), } } /// Is this [`SetOf`] empty? pub fn is_empty(&self) -> bool { self.inner.is_empty() } /// Number of elements in this [`SetOf`]. pub fn len(&self) -> usize { self.inner.len() } } impl Default for SetOf where T: DerOrd, { fn default() -> Self { Self::new() } } impl<'a, T, const N: usize> DecodeValue<'a> for SetOf where T: Decode<'a> + DerOrd, { fn decode_value>(reader: &mut R, header: Header) -> Result { reader.read_nested(header.length, |reader| { let mut result = Self::new(); while !reader.is_finished() { result.inner.push(T::decode(reader)?)?; } der_sort(result.inner.as_mut())?; validate(result.inner.as_ref())?; Ok(result) }) } } impl<'a, T, const N: usize> EncodeValue for SetOf where T: 'a + Decode<'a> + Encode + DerOrd, { fn value_len(&self) -> Result { self.iter() .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { for elem in self.iter() { elem.encode(writer)?; } Ok(()) } } impl<'a, T, const N: usize> FixedTag for SetOf where T: Decode<'a> + DerOrd, { const TAG: Tag = Tag::Set; } impl TryFrom<[T; N]> for SetOf where T: DerOrd, { type Error = Error; fn try_from(mut arr: [T; N]) -> Result> { der_sort(&mut arr)?; let mut result = SetOf::new(); for elem in arr { result.insert_ordered(elem)?; } Ok(result) } } impl ValueOrd for SetOf where T: DerOrd, { fn value_cmp(&self, other: &Self) -> Result { iter_cmp(self.iter(), other.iter()) } } /// Iterator over the elements of an [`SetOf`]. #[derive(Clone, Debug)] pub struct SetOfIter<'a, T> { /// Inner iterator. inner: arrayvec::Iter<'a, T>, } impl<'a, T> Iterator for SetOfIter<'a, T> { type Item = &'a T; fn next(&mut self) -> Option<&'a T> { self.inner.next() } } impl<'a, T> ExactSizeIterator for SetOfIter<'a, T> {} /// ASN.1 `SET OF` backed by a [`Vec`]. /// /// This type implements an append-only `SET OF` type which is heap-backed /// and depends on `alloc` support. #[cfg(feature = "alloc")] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct SetOfVec where T: DerOrd, { inner: Vec, } #[cfg(feature = "alloc")] impl Default for SetOfVec { fn default() -> Self { Self { inner: Default::default(), } } } #[cfg(feature = "alloc")] impl SetOfVec where T: DerOrd, { /// Create a new [`SetOfVec`]. pub fn new() -> Self { Self { inner: Vec::default(), } } /// Create a new [`SetOfVec`] from the given iterator. /// /// Note: this is an inherent method instead of an impl of the /// [`FromIterator`] trait in order to be fallible. #[allow(clippy::should_implement_trait)] pub fn from_iter(iter: I) -> Result where I: IntoIterator, { Vec::from_iter(iter).try_into() } /// Add an element to this [`SetOfVec`]. /// /// Items MUST be added in lexicographical order according to the /// [`DerOrd`] impl on `T`. #[deprecated(since = "0.7.6", note = "use `insert` or `insert_ordered` instead")] pub fn add(&mut self, item: T) -> Result<()> { self.insert_ordered(item) } /// Extend a [`SetOfVec`] using an iterator. /// /// Note: this is an inherent method instead of an impl of the /// [`Extend`] trait in order to be fallible. pub fn extend(&mut self, iter: I) -> Result<()> where I: IntoIterator, { self.inner.extend(iter); der_sort(&mut self.inner) } /// Insert an item into this [`SetOfVec`]. Must be unique. pub fn insert(&mut self, item: T) -> Result<()> { self.inner.push(item); der_sort(&mut self.inner) } /// Insert an item into this [`SetOfVec`]. Must be unique. /// /// Items MUST be added in lexicographical order according to the /// [`DerOrd`] impl on `T`. pub fn insert_ordered(&mut self, item: T) -> Result<()> { // Ensure set elements are lexicographically ordered if let Some(last) = self.inner.last() { check_der_ordering(last, &item)?; } self.inner.push(item); Ok(()) } /// Borrow the elements of this [`SetOfVec`] as a slice. pub fn as_slice(&self) -> &[T] { self.inner.as_slice() } /// Get the nth element from this [`SetOfVec`]. pub fn get(&self, index: usize) -> Option<&T> { self.inner.get(index) } /// Convert this [`SetOfVec`] into the inner [`Vec`]. pub fn into_vec(self) -> Vec { self.inner } /// Iterate over the elements of this [`SetOfVec`]. pub fn iter(&self) -> slice::Iter<'_, T> { self.inner.iter() } /// Is this [`SetOfVec`] empty? pub fn is_empty(&self) -> bool { self.inner.is_empty() } /// Number of elements in this [`SetOfVec`]. pub fn len(&self) -> usize { self.inner.len() } } #[cfg(feature = "alloc")] impl AsRef<[T]> for SetOfVec where T: DerOrd, { fn as_ref(&self) -> &[T] { self.as_slice() } } #[cfg(feature = "alloc")] impl<'a, T> DecodeValue<'a> for SetOfVec where T: Decode<'a> + DerOrd, { fn decode_value>(reader: &mut R, header: Header) -> Result { reader.read_nested(header.length, |reader| { let mut inner = Vec::new(); while !reader.is_finished() { inner.push(T::decode(reader)?); } der_sort(inner.as_mut())?; validate(inner.as_ref())?; Ok(Self { inner }) }) } } #[cfg(feature = "alloc")] impl<'a, T> EncodeValue for SetOfVec where T: 'a + Decode<'a> + Encode + DerOrd, { fn value_len(&self) -> Result { self.iter() .fold(Ok(Length::ZERO), |len, elem| len + elem.encoded_len()?) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { for elem in self.iter() { elem.encode(writer)?; } Ok(()) } } #[cfg(feature = "alloc")] impl FixedTag for SetOfVec where T: DerOrd, { const TAG: Tag = Tag::Set; } #[cfg(feature = "alloc")] impl From> for Vec where T: DerOrd, { fn from(set: SetOfVec) -> Vec { set.into_vec() } } #[cfg(feature = "alloc")] impl TryFrom> for SetOfVec where T: DerOrd, { type Error = Error; fn try_from(mut vec: Vec) -> Result> { der_sort(vec.as_mut_slice())?; Ok(SetOfVec { inner: vec }) } } #[cfg(feature = "alloc")] impl TryFrom<[T; N]> for SetOfVec where T: DerOrd, { type Error = Error; fn try_from(arr: [T; N]) -> Result> { Vec::from(arr).try_into() } } #[cfg(feature = "alloc")] impl ValueOrd for SetOfVec where T: DerOrd, { fn value_cmp(&self, other: &Self) -> Result { iter_cmp(self.iter(), other.iter()) } } // Implement by hand because the derive would create invalid values. // Use the conversion from Vec to create a valid value. #[cfg(feature = "arbitrary")] impl<'a, T> arbitrary::Arbitrary<'a> for SetOfVec where T: DerOrd + arbitrary::Arbitrary<'a>, { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { Self::try_from( u.arbitrary_iter()? .collect::, _>>()?, ) .map_err(|_| arbitrary::Error::IncorrectFormat) } fn size_hint(_depth: usize) -> (usize, Option) { (0, None) } } /// Ensure set elements are lexicographically ordered using [`DerOrd`]. fn check_der_ordering(a: &T, b: &T) -> Result<()> { match a.der_cmp(b)? { Ordering::Less => Ok(()), Ordering::Equal => Err(ErrorKind::SetDuplicate.into()), Ordering::Greater => Err(ErrorKind::SetOrdering.into()), } } /// Sort a mut slice according to its [`DerOrd`], returning any errors which /// might occur during the comparison. /// /// The algorithm is insertion sort, which should perform well when the input /// is mostly sorted to begin with. /// /// This function is used rather than Rust's built-in `[T]::sort_by` in order /// to support heapless `no_std` targets as well as to enable bubbling up /// sorting errors. #[allow(clippy::integer_arithmetic)] fn der_sort(slice: &mut [T]) -> Result<()> { for i in 0..slice.len() { let mut j = i; while j > 0 { match slice[j - 1].der_cmp(&slice[j])? { Ordering::Less => break, Ordering::Equal => return Err(ErrorKind::SetDuplicate.into()), Ordering::Greater => { slice.swap(j - 1, j); j -= 1; } } } } Ok(()) } /// Validate the elements of a `SET OF`, ensuring that they are all in order /// and that there are no duplicates. fn validate(slice: &[T]) -> Result<()> { if let Some(len) = slice.len().checked_sub(1) { for i in 0..len { let j = i.checked_add(1).ok_or(ErrorKind::Overflow)?; match slice.get(i..=j) { Some([a, b]) => { if a.der_cmp(b)? != Ordering::Less { return Err(ErrorKind::SetOrdering.into()); } } _ => return Err(Tag::Set.value_error()), } } } Ok(()) } #[cfg(test)] mod tests { use super::SetOf; #[cfg(feature = "alloc")] use super::SetOfVec; use crate::ErrorKind; #[test] fn setof_tryfrom_array() { let arr = [3u16, 2, 1, 65535, 0]; let set = SetOf::try_from(arr).unwrap(); assert!(set.iter().copied().eq([0, 1, 2, 3, 65535])); } #[test] fn setof_tryfrom_array_reject_duplicates() { let arr = [1u16, 1]; let err = SetOf::try_from(arr).err().unwrap(); assert_eq!(err.kind(), ErrorKind::SetDuplicate); } #[cfg(feature = "alloc")] #[test] fn setofvec_tryfrom_array() { let arr = [3u16, 2, 1, 65535, 0]; let set = SetOfVec::try_from(arr).unwrap(); assert_eq!(set.as_ref(), &[0, 1, 2, 3, 65535]); } #[cfg(feature = "alloc")] #[test] fn setofvec_tryfrom_vec() { let vec = vec![3u16, 2, 1, 65535, 0]; let set = SetOfVec::try_from(vec).unwrap(); assert_eq!(set.as_ref(), &[0, 1, 2, 3, 65535]); } #[cfg(feature = "alloc")] #[test] fn setofvec_tryfrom_vec_reject_duplicates() { let vec = vec![1u16, 1]; let err = SetOfVec::try_from(vec).err().unwrap(); assert_eq!(err.kind(), ErrorKind::SetDuplicate); } } der-0.7.7/src/asn1/teletex_string.rs000064400000000000000000000143401046102023000154520ustar 00000000000000//! ASN.1 `TeletexString` support. //! use crate::{asn1::AnyRef, FixedTag, Result, StrRef, Tag}; use core::{fmt, ops::Deref}; macro_rules! impl_teletex_string { ($type: ty) => { impl_teletex_string!($type,); }; ($type: ty, $($li: lifetime)?) => { impl_string_type!($type, $($li),*); impl<$($li),*> FixedTag for $type { const TAG: Tag = Tag::TeletexString; } impl<$($li),*> fmt::Debug for $type { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "TeletexString({:?})", self.as_str()) } } }; } /// ASN.1 `TeletexString` type. /// /// Supports a subset the ASCII character set (described below). /// /// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead. /// For the full ASCII character set, use /// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`]. /// /// This is a zero-copy reference type which borrows from the input data. /// /// # Supported characters /// /// The standard defines a complex character set allowed in this type. However, quoting the ASN.1 /// mailing list, "a sizable volume of software in the world treats TeletexString (T61String) as a /// simple 8-bit string with mostly Windows Latin 1 (superset of iso-8859-1) encoding". /// #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] pub struct TeletexStringRef<'a> { /// Inner value inner: StrRef<'a>, } impl<'a> TeletexStringRef<'a> { /// Create a new ASN.1 `TeletexString`. pub fn new(input: &'a T) -> Result where T: AsRef<[u8]> + ?Sized, { let input = input.as_ref(); // FIXME: support higher part of the charset if input.iter().any(|&c| c > 0x7F) { return Err(Self::TAG.value_error()); } StrRef::from_bytes(input) .map(|inner| Self { inner }) .map_err(|_| Self::TAG.value_error()) } } impl_teletex_string!(TeletexStringRef<'a>, 'a); impl<'a> Deref for TeletexStringRef<'a> { type Target = StrRef<'a>; fn deref(&self) -> &Self::Target { &self.inner } } impl<'a> From<&TeletexStringRef<'a>> for TeletexStringRef<'a> { fn from(value: &TeletexStringRef<'a>) -> TeletexStringRef<'a> { *value } } impl<'a> From> for AnyRef<'a> { fn from(teletex_string: TeletexStringRef<'a>) -> AnyRef<'a> { AnyRef::from_tag_and_value(Tag::TeletexString, teletex_string.inner.into()) } } #[cfg(feature = "alloc")] pub use self::allocation::TeletexString; #[cfg(feature = "alloc")] mod allocation { use super::TeletexStringRef; use crate::{ asn1::AnyRef, referenced::{OwnedToRef, RefToOwned}, BytesRef, Error, FixedTag, Result, StrOwned, Tag, }; use alloc::string::String; use core::{fmt, ops::Deref}; /// ASN.1 `TeletexString` type. /// /// Supports a subset the ASCII character set (described below). /// /// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead. /// For the full ASCII character set, use /// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`]. /// /// # Supported characters /// /// The standard defines a complex character set allowed in this type. However, quoting the ASN.1 /// mailing list, "a sizable volume of software in the world treats TeletexString (T61String) as a /// simple 8-bit string with mostly Windows Latin 1 (superset of iso-8859-1) encoding". /// #[derive(Clone, Eq, PartialEq, PartialOrd, Ord)] pub struct TeletexString { /// Inner value inner: StrOwned, } impl TeletexString { /// Create a new ASN.1 `TeletexString`. pub fn new(input: &T) -> Result where T: AsRef<[u8]> + ?Sized, { let input = input.as_ref(); TeletexStringRef::new(input)?; StrOwned::from_bytes(input) .map(|inner| Self { inner }) .map_err(|_| Self::TAG.value_error()) } } impl_teletex_string!(TeletexString); impl Deref for TeletexString { type Target = StrOwned; fn deref(&self) -> &Self::Target { &self.inner } } impl<'a> From> for TeletexString { fn from(value: TeletexStringRef<'a>) -> TeletexString { let inner = StrOwned::from_bytes(value.inner.as_bytes()).expect("Invalid TeletexString"); Self { inner } } } impl<'a> From<&'a TeletexString> for AnyRef<'a> { fn from(teletex_string: &'a TeletexString) -> AnyRef<'a> { AnyRef::from_tag_and_value( Tag::TeletexString, BytesRef::new(teletex_string.inner.as_bytes()).expect("Invalid TeletexString"), ) } } impl<'a> RefToOwned<'a> for TeletexStringRef<'a> { type Owned = TeletexString; fn ref_to_owned(&self) -> Self::Owned { TeletexString { inner: self.inner.ref_to_owned(), } } } impl OwnedToRef for TeletexString { type Borrowed<'a> = TeletexStringRef<'a>; fn owned_to_ref(&self) -> Self::Borrowed<'_> { TeletexStringRef { inner: self.inner.owned_to_ref(), } } } impl TryFrom for TeletexString { type Error = Error; fn try_from(input: String) -> Result { TeletexStringRef::new(&input)?; StrOwned::new(input) .map(|inner| Self { inner }) .map_err(|_| Self::TAG.value_error()) } } } #[cfg(test)] mod tests { use super::TeletexStringRef; use crate::Decode; use crate::SliceWriter; #[test] fn parse_bytes() { let example_bytes = &[ 0x14, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x65, 0x72, 0x20, 0x31, ]; let teletex_string = TeletexStringRef::from_der(example_bytes).unwrap(); assert_eq!(teletex_string.as_str(), "Test User 1"); let mut out = [0_u8; 30]; let mut writer = SliceWriter::new(&mut out); writer.encode(&teletex_string).unwrap(); let encoded = writer.finish().unwrap(); assert_eq!(encoded, example_bytes); } } der-0.7.7/src/asn1/utc_time.rs000064400000000000000000000176341046102023000142340ustar 00000000000000//! ASN.1 `UTCTime` support. use crate::{ datetime::{self, DateTime}, ord::OrdIsValueOrd, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, Writer, }; use core::time::Duration; #[cfg(feature = "std")] use std::time::SystemTime; /// ASN.1 `UTCTime` type. /// /// This type implements the validity requirements specified in /// [RFC 5280 Section 4.1.2.5.1][1], namely: /// /// > For the purposes of this profile, UTCTime values MUST be expressed in /// > Greenwich Mean Time (Zulu) and MUST include seconds (i.e., times are /// > `YYMMDDHHMMSSZ`), even where the number of seconds is zero. Conforming /// > systems MUST interpret the year field (`YY`) as follows: /// > /// > - Where `YY` is greater than or equal to 50, the year SHALL be /// > interpreted as `19YY`; and /// > - Where `YY` is less than 50, the year SHALL be interpreted as `20YY`. /// /// Note: Due to common operations working on `UNIX_EPOCH` [`UtcTime`]s are /// only supported for the years 1970-2049. /// /// [1]: https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct UtcTime(DateTime); impl UtcTime { /// Length of an RFC 5280-flavored ASN.1 DER-encoded [`UtcTime`]. pub const LENGTH: usize = 13; /// Maximum year that can be represented as a `UTCTime`. pub const MAX_YEAR: u16 = 2049; /// Create a [`UtcTime`] from a [`DateTime`]. pub fn from_date_time(datetime: DateTime) -> Result { if datetime.year() <= UtcTime::MAX_YEAR { Ok(Self(datetime)) } else { Err(Self::TAG.value_error()) } } /// Convert this [`UtcTime`] into a [`DateTime`]. pub fn to_date_time(&self) -> DateTime { self.0 } /// Create a new [`UtcTime`] given a [`Duration`] since `UNIX_EPOCH` /// (a.k.a. "Unix time") pub fn from_unix_duration(unix_duration: Duration) -> Result { DateTime::from_unix_duration(unix_duration)?.try_into() } /// Get the duration of this timestamp since `UNIX_EPOCH`. pub fn to_unix_duration(&self) -> Duration { self.0.unix_duration() } /// Instantiate from [`SystemTime`]. #[cfg(feature = "std")] pub fn from_system_time(time: SystemTime) -> Result { DateTime::try_from(time) .map_err(|_| Self::TAG.value_error())? .try_into() } /// Convert to [`SystemTime`]. #[cfg(feature = "std")] pub fn to_system_time(&self) -> SystemTime { self.0.to_system_time() } } impl_any_conversions!(UtcTime); impl<'a> DecodeValue<'a> for UtcTime { fn decode_value>(reader: &mut R, header: Header) -> Result { if Self::LENGTH != usize::try_from(header.length)? { return Err(Self::TAG.value_error()); } let mut bytes = [0u8; Self::LENGTH]; reader.read_into(&mut bytes)?; match bytes { // RFC 5280 requires mandatory seconds and Z-normalized time zone [year1, year2, mon1, mon2, day1, day2, hour1, hour2, min1, min2, sec1, sec2, b'Z'] => { let year = u16::from(datetime::decode_decimal(Self::TAG, year1, year2)?); let month = datetime::decode_decimal(Self::TAG, mon1, mon2)?; let day = datetime::decode_decimal(Self::TAG, day1, day2)?; let hour = datetime::decode_decimal(Self::TAG, hour1, hour2)?; let minute = datetime::decode_decimal(Self::TAG, min1, min2)?; let second = datetime::decode_decimal(Self::TAG, sec1, sec2)?; // RFC 5280 rules for interpreting the year let year = if year >= 50 { year.checked_add(1900) } else { year.checked_add(2000) } .ok_or(ErrorKind::DateTime)?; DateTime::new(year, month, day, hour, minute, second) .map_err(|_| Self::TAG.value_error()) .and_then(|dt| Self::from_unix_duration(dt.unix_duration())) } _ => Err(Self::TAG.value_error()), } } } impl EncodeValue for UtcTime { fn value_len(&self) -> Result { Self::LENGTH.try_into() } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { let year = match self.0.year() { y @ 1950..=1999 => y.checked_sub(1900), y @ 2000..=2049 => y.checked_sub(2000), _ => return Err(Self::TAG.value_error()), } .and_then(|y| u8::try_from(y).ok()) .ok_or(ErrorKind::DateTime)?; datetime::encode_decimal(writer, Self::TAG, year)?; datetime::encode_decimal(writer, Self::TAG, self.0.month())?; datetime::encode_decimal(writer, Self::TAG, self.0.day())?; datetime::encode_decimal(writer, Self::TAG, self.0.hour())?; datetime::encode_decimal(writer, Self::TAG, self.0.minutes())?; datetime::encode_decimal(writer, Self::TAG, self.0.seconds())?; writer.write_byte(b'Z') } } impl FixedTag for UtcTime { const TAG: Tag = Tag::UtcTime; } impl OrdIsValueOrd for UtcTime {} impl From<&UtcTime> for UtcTime { fn from(value: &UtcTime) -> UtcTime { *value } } impl From for DateTime { fn from(utc_time: UtcTime) -> DateTime { utc_time.0 } } impl From<&UtcTime> for DateTime { fn from(utc_time: &UtcTime) -> DateTime { utc_time.0 } } impl TryFrom for UtcTime { type Error = Error; fn try_from(datetime: DateTime) -> Result { Self::from_date_time(datetime) } } impl TryFrom<&DateTime> for UtcTime { type Error = Error; fn try_from(datetime: &DateTime) -> Result { Self::from_date_time(*datetime) } } #[cfg(feature = "std")] impl From for SystemTime { fn from(utc_time: UtcTime) -> SystemTime { utc_time.to_system_time() } } // Implement by hand because the derive would create invalid values. // Use the conversion from DateTime to create a valid value. // The DateTime type has a way bigger range of valid years than UtcTime, // so the DateTime year is mapped into a valid range to throw away less inputs. #[cfg(feature = "arbitrary")] impl<'a> arbitrary::Arbitrary<'a> for UtcTime { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { const MIN_YEAR: u16 = 1970; const VALID_YEAR_COUNT: u16 = UtcTime::MAX_YEAR - MIN_YEAR + 1; const AVERAGE_SECONDS_IN_YEAR: u64 = 31_556_952; let datetime = DateTime::arbitrary(u)?; let year = datetime.year(); let duration = datetime.unix_duration(); // Clamp the year into a valid range to not throw away too much input let valid_year = (year.saturating_sub(MIN_YEAR)) .rem_euclid(VALID_YEAR_COUNT) .saturating_add(MIN_YEAR); let year_to_remove = year.saturating_sub(valid_year); let valid_duration = duration - Duration::from_secs( u64::from(year_to_remove).saturating_mul(AVERAGE_SECONDS_IN_YEAR), ); Self::from_date_time(DateTime::from_unix_duration(valid_duration).expect("supported range")) .map_err(|_| arbitrary::Error::IncorrectFormat) } fn size_hint(depth: usize) -> (usize, Option) { DateTime::size_hint(depth) } } #[cfg(test)] mod tests { use super::UtcTime; use crate::{Decode, Encode, SliceWriter}; use hex_literal::hex; #[test] fn round_trip_vector() { let example_bytes = hex!("17 0d 39 31 30 35 30 36 32 33 34 35 34 30 5a"); let utc_time = UtcTime::from_der(&example_bytes).unwrap(); assert_eq!(utc_time.to_unix_duration().as_secs(), 673573540); let mut buf = [0u8; 128]; let mut encoder = SliceWriter::new(&mut buf); utc_time.encode(&mut encoder).unwrap(); assert_eq!(example_bytes, encoder.finish().unwrap()); } } der-0.7.7/src/asn1/utf8_string.rs000064400000000000000000000103171046102023000146660ustar 00000000000000//! ASN.1 `UTF8String` support. use crate::{ asn1::AnyRef, ord::OrdIsValueOrd, EncodeValue, Error, FixedTag, Length, Result, StrRef, Tag, Writer, }; use core::{fmt, ops::Deref, str}; #[cfg(feature = "alloc")] use { crate::{DecodeValue, Header, Reader}, alloc::{borrow::ToOwned, string::String}, }; /// ASN.1 `UTF8String` type. /// /// Supports the full UTF-8 encoding. /// /// Note that the [`Decode`][`crate::Decode`] and [`Encode`][`crate::Encode`] /// traits are impl'd for Rust's [`str`][`prim@str`] primitive, which /// decodes/encodes as a [`Utf8StringRef`]. /// /// You are free to use [`str`][`prim@str`] instead of this type, however it's /// still provided for explicitness in cases where it might be ambiguous with /// other ASN.1 string encodings such as /// [`PrintableStringRef`][`crate::asn1::PrintableStringRef`]. /// /// This is a zero-copy reference type which borrows from the input data. #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] pub struct Utf8StringRef<'a> { /// Inner value inner: StrRef<'a>, } impl<'a> Utf8StringRef<'a> { /// Create a new ASN.1 `UTF8String`. pub fn new(input: &'a T) -> Result where T: AsRef<[u8]> + ?Sized, { StrRef::from_bytes(input.as_ref()).map(|inner| Self { inner }) } } impl_string_type!(Utf8StringRef<'a>, 'a); impl<'a> Deref for Utf8StringRef<'a> { type Target = StrRef<'a>; fn deref(&self) -> &Self::Target { &self.inner } } impl FixedTag for Utf8StringRef<'_> { const TAG: Tag = Tag::Utf8String; } impl<'a> From<&Utf8StringRef<'a>> for Utf8StringRef<'a> { fn from(value: &Utf8StringRef<'a>) -> Utf8StringRef<'a> { *value } } impl<'a> From> for AnyRef<'a> { fn from(utf_string: Utf8StringRef<'a>) -> AnyRef<'a> { AnyRef::from_tag_and_value(Tag::Utf8String, utf_string.inner.into()) } } impl<'a> fmt::Debug for Utf8StringRef<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Utf8String({:?})", self.as_str()) } } impl<'a> TryFrom> for &'a str { type Error = Error; fn try_from(any: AnyRef<'a>) -> Result<&'a str> { Utf8StringRef::try_from(any).map(|s| s.as_str()) } } impl EncodeValue for str { fn value_len(&self) -> Result { Utf8StringRef::new(self)?.value_len() } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { Utf8StringRef::new(self)?.encode_value(writer) } } impl FixedTag for str { const TAG: Tag = Tag::Utf8String; } impl OrdIsValueOrd for str {} #[cfg(feature = "alloc")] impl<'a> From> for String { fn from(s: Utf8StringRef<'a>) -> String { s.as_str().to_owned() } } #[cfg(feature = "alloc")] impl<'a> TryFrom> for String { type Error = Error; fn try_from(any: AnyRef<'a>) -> Result { Utf8StringRef::try_from(any).map(|s| s.as_str().to_owned()) } } #[cfg(feature = "alloc")] impl<'a> DecodeValue<'a> for String { fn decode_value>(reader: &mut R, header: Header) -> Result { Ok(String::from_utf8(reader.read_vec(header.length)?)?) } } #[cfg(feature = "alloc")] impl EncodeValue for String { fn value_len(&self) -> Result { Utf8StringRef::new(self)?.value_len() } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { Utf8StringRef::new(self)?.encode_value(writer) } } #[cfg(feature = "alloc")] impl FixedTag for String { const TAG: Tag = Tag::Utf8String; } #[cfg(feature = "alloc")] impl OrdIsValueOrd for String {} #[cfg(test)] mod tests { use super::Utf8StringRef; use crate::Decode; #[test] fn parse_ascii_bytes() { let example_bytes = &[ 0x0c, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x65, 0x72, 0x20, 0x31, ]; let utf8_string = Utf8StringRef::from_der(example_bytes).unwrap(); assert_eq!(utf8_string.as_str(), "Test User 1"); } #[test] fn parse_utf8_bytes() { let example_bytes = &[0x0c, 0x06, 0x48, 0x65, 0x6c, 0x6c, 0xc3, 0xb3]; let utf8_string = Utf8StringRef::from_der(example_bytes).unwrap(); assert_eq!(utf8_string.as_str(), "Helló"); } } der-0.7.7/src/asn1/videotex_string.rs000064400000000000000000000052501046102023000156270ustar 00000000000000//! ASN.1 `VideotexString` support. use crate::{asn1::AnyRef, FixedTag, Result, StrRef, Tag}; use core::{fmt, ops::Deref}; /// ASN.1 `VideotexString` type. /// /// Supports a subset the ASCII character set (described below). /// /// For UTF-8, use [`Utf8StringRef`][`crate::asn1::Utf8StringRef`] instead. /// For the full ASCII character set, use /// [`Ia5StringRef`][`crate::asn1::Ia5StringRef`]. /// /// This is a zero-copy reference type which borrows from the input data. /// /// # Supported characters /// /// For the practical purposes VideotexString is treated as IA5string, disallowing non-ASCII chars. /// #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] pub struct VideotexStringRef<'a> { /// Inner value inner: StrRef<'a>, } impl<'a> VideotexStringRef<'a> { /// Create a new ASN.1 `VideotexString`. pub fn new(input: &'a T) -> Result where T: AsRef<[u8]> + ?Sized, { let input = input.as_ref(); // Validate all characters are within VideotexString's allowed set // FIXME: treat as if it were IA5String if input.iter().any(|&c| c > 0x7F) { return Err(Self::TAG.value_error()); } StrRef::from_bytes(input) .map(|inner| Self { inner }) .map_err(|_| Self::TAG.value_error()) } } impl_string_type!(VideotexStringRef<'a>, 'a); impl<'a> Deref for VideotexStringRef<'a> { type Target = StrRef<'a>; fn deref(&self) -> &Self::Target { &self.inner } } impl FixedTag for VideotexStringRef<'_> { const TAG: Tag = Tag::VideotexString; } impl<'a> From<&VideotexStringRef<'a>> for VideotexStringRef<'a> { fn from(value: &VideotexStringRef<'a>) -> VideotexStringRef<'a> { *value } } impl<'a> From> for AnyRef<'a> { fn from(printable_string: VideotexStringRef<'a>) -> AnyRef<'a> { AnyRef::from_tag_and_value(Tag::VideotexString, printable_string.inner.into()) } } impl<'a> From> for &'a [u8] { fn from(printable_string: VideotexStringRef<'a>) -> &'a [u8] { printable_string.as_bytes() } } impl<'a> fmt::Debug for VideotexStringRef<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "VideotexString({:?})", self.as_str()) } } #[cfg(test)] mod tests { use super::VideotexStringRef; use crate::Decode; #[test] fn parse_bytes() { let example_bytes = &[ 0x15, 0x0b, 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x65, 0x72, 0x20, 0x31, ]; let printable_string = VideotexStringRef::from_der(example_bytes).unwrap(); assert_eq!(printable_string.as_str(), "Test User 1"); } } der-0.7.7/src/asn1.rs000064400000000000000000000026631046102023000124170ustar 00000000000000//! Module containing all of the various ASN.1 built-in types supported by //! this library. #[macro_use] mod internal_macros; mod any; mod bit_string; mod boolean; mod choice; mod context_specific; mod generalized_time; mod ia5_string; mod integer; mod null; mod octet_string; #[cfg(feature = "oid")] mod oid; mod optional; mod printable_string; #[cfg(feature = "real")] mod real; mod sequence; mod sequence_of; mod set_of; mod teletex_string; mod utc_time; mod utf8_string; mod videotex_string; pub use self::{ any::AnyRef, bit_string::{BitStringIter, BitStringRef}, choice::Choice, context_specific::{ContextSpecific, ContextSpecificRef}, generalized_time::GeneralizedTime, ia5_string::Ia5StringRef, integer::{int::IntRef, uint::UintRef}, null::Null, octet_string::OctetStringRef, printable_string::PrintableStringRef, sequence::{Sequence, SequenceRef}, sequence_of::{SequenceOf, SequenceOfIter}, set_of::{SetOf, SetOfIter}, teletex_string::TeletexStringRef, utc_time::UtcTime, utf8_string::Utf8StringRef, videotex_string::VideotexStringRef, }; #[cfg(feature = "alloc")] pub use self::{ any::Any, bit_string::BitString, ia5_string::Ia5String, integer::{int::Int, uint::Uint}, octet_string::OctetString, printable_string::PrintableString, set_of::SetOfVec, teletex_string::TeletexString, }; #[cfg(feature = "oid")] pub use const_oid::ObjectIdentifier; der-0.7.7/src/bytes_owned.rs000064400000000000000000000074701046102023000141000ustar 00000000000000//! Common handling for types backed by byte allocation with enforcement of a //! library-level length limitation i.e. `Length::max()`. use crate::{ referenced::OwnedToRef, BytesRef, DecodeValue, DerOrd, EncodeValue, Error, Header, Length, Reader, Result, StrRef, Writer, }; use alloc::{boxed::Box, vec::Vec}; use core::cmp::Ordering; /// Byte slice newtype which respects the `Length::max()` limit. #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub(crate) struct BytesOwned { /// Precomputed `Length` (avoids possible panicking conversions) length: Length, /// Inner value inner: Box<[u8]>, } impl BytesOwned { /// Create a new [`BytesOwned`], ensuring that the provided `slice` value /// is shorter than `Length::max()`. pub fn new(data: impl Into>) -> Result { let inner: Box<[u8]> = data.into(); Ok(Self { length: Length::try_from(inner.len())?, inner, }) } /// Borrow the inner byte slice pub fn as_slice(&self) -> &[u8] { &self.inner } /// Get the [`Length`] of this [`BytesRef`] pub fn len(&self) -> Length { self.length } /// Is this [`BytesOwned`] empty? pub fn is_empty(&self) -> bool { self.len() == Length::ZERO } } impl AsRef<[u8]> for BytesOwned { fn as_ref(&self) -> &[u8] { self.as_slice() } } impl<'a> DecodeValue<'a> for BytesOwned { fn decode_value>(reader: &mut R, header: Header) -> Result { reader.read_vec(header.length).and_then(Self::new) } } impl EncodeValue for BytesOwned { fn value_len(&self) -> Result { Ok(self.length) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { writer.write(self.as_ref()) } } impl Default for BytesOwned { fn default() -> Self { Self { length: Length::ZERO, inner: Box::new([]), } } } impl DerOrd for BytesOwned { fn der_cmp(&self, other: &Self) -> Result { Ok(self.as_slice().cmp(other.as_slice())) } } impl From> for BytesOwned { fn from(s: StrRef<'_>) -> BytesOwned { let bytes = s.as_bytes(); debug_assert_eq!(bytes.len(), usize::try_from(s.length).expect("overflow")); BytesOwned { inner: Box::from(bytes), length: s.length, } } } impl OwnedToRef for BytesOwned { type Borrowed<'a> = BytesRef<'a>; fn owned_to_ref(&self) -> Self::Borrowed<'_> { BytesRef { length: self.length, inner: self.inner.as_ref(), } } } impl From> for BytesOwned { fn from(s: BytesRef<'_>) -> BytesOwned { BytesOwned { length: s.length, inner: Box::from(s.inner), } } } impl TryFrom<&[u8]> for BytesOwned { type Error = Error; fn try_from(bytes: &[u8]) -> Result { Self::new(bytes) } } impl TryFrom> for BytesOwned { type Error = Error; fn try_from(bytes: Box<[u8]>) -> Result { Self::new(bytes) } } impl TryFrom> for BytesOwned { type Error = Error; fn try_from(bytes: Vec) -> Result { Self::new(bytes) } } // Implement by hand because the derive would create invalid values. // Make sure the length and the inner.len matches. #[cfg(feature = "arbitrary")] impl<'a> arbitrary::Arbitrary<'a> for BytesOwned { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { let length = u.arbitrary()?; Ok(Self { length, inner: Box::from(u.bytes(u32::from(length) as usize)?), }) } fn size_hint(depth: usize) -> (usize, Option) { arbitrary::size_hint::and(Length::size_hint(depth), (0, None)) } } der-0.7.7/src/bytes_ref.rs000064400000000000000000000074711046102023000135410ustar 00000000000000//! Common handling for types backed by byte slices with enforcement of a //! library-level length limitation i.e. `Length::max()`. use crate::{ DecodeValue, DerOrd, EncodeValue, Error, Header, Length, Reader, Result, StrRef, Writer, }; use core::cmp::Ordering; #[cfg(feature = "alloc")] use crate::StrOwned; /// Byte slice newtype which respects the `Length::max()` limit. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub(crate) struct BytesRef<'a> { /// Precomputed `Length` (avoids possible panicking conversions) pub length: Length, /// Inner value pub inner: &'a [u8], } impl<'a> BytesRef<'a> { /// Constant value representing an empty byte slice. pub const EMPTY: Self = Self { length: Length::ZERO, inner: &[], }; /// Create a new [`BytesRef`], ensuring that the provided `slice` value /// is shorter than `Length::max()`. pub fn new(slice: &'a [u8]) -> Result { Ok(Self { length: Length::try_from(slice.len())?, inner: slice, }) } /// Borrow the inner byte slice pub fn as_slice(&self) -> &'a [u8] { self.inner } /// Get the [`Length`] of this [`BytesRef`] pub fn len(self) -> Length { self.length } /// Is this [`BytesRef`] empty? pub fn is_empty(self) -> bool { self.len() == Length::ZERO } } impl AsRef<[u8]> for BytesRef<'_> { fn as_ref(&self) -> &[u8] { self.as_slice() } } impl<'a> DecodeValue<'a> for BytesRef<'a> { fn decode_value>(reader: &mut R, header: Header) -> Result { reader.read_slice(header.length).and_then(Self::new) } } impl EncodeValue for BytesRef<'_> { fn value_len(&self) -> Result { Ok(self.length) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { writer.write(self.as_ref()) } } impl Default for BytesRef<'_> { fn default() -> Self { Self { length: Length::ZERO, inner: &[], } } } impl DerOrd for BytesRef<'_> { fn der_cmp(&self, other: &Self) -> Result { Ok(self.as_slice().cmp(other.as_slice())) } } impl<'a> From> for BytesRef<'a> { fn from(s: StrRef<'a>) -> BytesRef<'a> { let bytes = s.as_bytes(); debug_assert_eq!(bytes.len(), usize::try_from(s.length).expect("overflow")); BytesRef { inner: bytes, length: s.length, } } } #[cfg(feature = "alloc")] impl<'a> From<&'a StrOwned> for BytesRef<'a> { fn from(s: &'a StrOwned) -> BytesRef<'a> { let bytes = s.as_bytes(); debug_assert_eq!(bytes.len(), usize::try_from(s.length).expect("overflow")); BytesRef { inner: bytes, length: s.length, } } } impl<'a> TryFrom<&'a [u8]> for BytesRef<'a> { type Error = Error; fn try_from(slice: &'a [u8]) -> Result { Self::new(slice) } } // Implement by hand because the derive would create invalid values. // Make sure the length and the inner.len matches. #[cfg(feature = "arbitrary")] impl<'a> arbitrary::Arbitrary<'a> for BytesRef<'a> { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { let length = u.arbitrary()?; Ok(Self { length, inner: u.bytes(u32::from(length) as usize)?, }) } fn size_hint(depth: usize) -> (usize, Option) { arbitrary::size_hint::and(Length::size_hint(depth), (0, None)) } } #[cfg(feature = "alloc")] mod allocating { use super::BytesRef; use crate::{referenced::RefToOwned, BytesOwned}; impl<'a> RefToOwned<'a> for BytesRef<'a> { type Owned = BytesOwned; fn ref_to_owned(&self) -> Self::Owned { BytesOwned::from(*self) } } } der-0.7.7/src/datetime.rs000064400000000000000000000316611046102023000133510ustar 00000000000000//! Date and time functionality shared between various ASN.1 types //! (e.g. `GeneralizedTime`, `UTCTime`) // Adapted from the `humantime` crate. // Copyright (c) 2016 The humantime Developers // Released under the MIT OR Apache 2.0 licenses use crate::{Error, ErrorKind, Result, Tag, Writer}; use core::{fmt, str::FromStr, time::Duration}; #[cfg(feature = "std")] use std::time::{SystemTime, UNIX_EPOCH}; #[cfg(feature = "time")] use time::PrimitiveDateTime; /// Minimum year allowed in [`DateTime`] values. const MIN_YEAR: u16 = 1970; /// Maximum duration since `UNIX_EPOCH` which can be represented as a /// [`DateTime`] (non-inclusive). /// /// This corresponds to: 9999-12-31T23:59:59Z const MAX_UNIX_DURATION: Duration = Duration::from_secs(253_402_300_799); /// Date-and-time type shared by multiple ASN.1 types /// (e.g. `GeneralizedTime`, `UTCTime`). /// /// Following conventions from RFC 5280, this type is always Z-normalized /// (i.e. represents a UTC time). However, it isn't named "UTC time" in order /// to prevent confusion with ASN.1 `UTCTime`. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct DateTime { /// Full year (e.g. 2000). /// /// Must be >=1970 to permit positive conversions to Unix time. year: u16, /// Month (1-12) month: u8, /// Day of the month (1-31) day: u8, /// Hour (0-23) hour: u8, /// Minutes (0-59) minutes: u8, /// Seconds (0-59) seconds: u8, /// [`Duration`] since the Unix epoch. unix_duration: Duration, } impl DateTime { /// This is the maximum date represented by the [`DateTime`] /// This corresponds to: 9999-12-31T23:59:59Z pub const INFINITY: DateTime = DateTime { year: 9999, month: 12, day: 31, hour: 23, minutes: 59, seconds: 59, unix_duration: MAX_UNIX_DURATION, }; /// Create a new [`DateTime`] from the given UTC time components. // TODO(tarcieri): checked arithmetic #[allow(clippy::integer_arithmetic)] pub fn new(year: u16, month: u8, day: u8, hour: u8, minutes: u8, seconds: u8) -> Result { // Basic validation of the components. if year < MIN_YEAR || !(1..=12).contains(&month) || !(1..=31).contains(&day) || !(0..=23).contains(&hour) || !(0..=59).contains(&minutes) || !(0..=59).contains(&seconds) { return Err(ErrorKind::DateTime.into()); } let leap_years = ((year - 1) - 1968) / 4 - ((year - 1) - 1900) / 100 + ((year - 1) - 1600) / 400; let is_leap_year = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); let (mut ydays, mdays): (u16, u8) = match month { 1 => (0, 31), 2 if is_leap_year => (31, 29), 2 => (31, 28), 3 => (59, 31), 4 => (90, 30), 5 => (120, 31), 6 => (151, 30), 7 => (181, 31), 8 => (212, 31), 9 => (243, 30), 10 => (273, 31), 11 => (304, 30), 12 => (334, 31), _ => return Err(ErrorKind::DateTime.into()), }; if day > mdays || day == 0 { return Err(ErrorKind::DateTime.into()); } ydays += u16::from(day) - 1; if is_leap_year && month > 2 { ydays += 1; } let days = u64::from(year - 1970) * 365 + u64::from(leap_years) + u64::from(ydays); let time = u64::from(seconds) + (u64::from(minutes) * 60) + (u64::from(hour) * 3600); let unix_duration = Duration::from_secs(time + days * 86400); if unix_duration > MAX_UNIX_DURATION { return Err(ErrorKind::DateTime.into()); } Ok(Self { year, month, day, hour, minutes, seconds, unix_duration, }) } /// Compute a [`DateTime`] from the given [`Duration`] since the `UNIX_EPOCH`. /// /// Returns `None` if the value is outside the supported date range. // TODO(tarcieri): checked arithmetic #[allow(clippy::integer_arithmetic)] pub fn from_unix_duration(unix_duration: Duration) -> Result { if unix_duration > MAX_UNIX_DURATION { return Err(ErrorKind::DateTime.into()); } let secs_since_epoch = unix_duration.as_secs(); /// 2000-03-01 (mod 400 year, immediately after Feb 29) const LEAPOCH: i64 = 11017; const DAYS_PER_400Y: i64 = 365 * 400 + 97; const DAYS_PER_100Y: i64 = 365 * 100 + 24; const DAYS_PER_4Y: i64 = 365 * 4 + 1; let days = i64::try_from(secs_since_epoch / 86400)? - LEAPOCH; let secs_of_day = secs_since_epoch % 86400; let mut qc_cycles = days / DAYS_PER_400Y; let mut remdays = days % DAYS_PER_400Y; if remdays < 0 { remdays += DAYS_PER_400Y; qc_cycles -= 1; } let mut c_cycles = remdays / DAYS_PER_100Y; if c_cycles == 4 { c_cycles -= 1; } remdays -= c_cycles * DAYS_PER_100Y; let mut q_cycles = remdays / DAYS_PER_4Y; if q_cycles == 25 { q_cycles -= 1; } remdays -= q_cycles * DAYS_PER_4Y; let mut remyears = remdays / 365; if remyears == 4 { remyears -= 1; } remdays -= remyears * 365; let mut year = 2000 + remyears + 4 * q_cycles + 100 * c_cycles + 400 * qc_cycles; let months = [31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29]; let mut mon = 0; for mon_len in months.iter() { mon += 1; if remdays < *mon_len { break; } remdays -= *mon_len; } let mday = remdays + 1; let mon = if mon + 2 > 12 { year += 1; mon - 10 } else { mon + 2 }; let second = secs_of_day % 60; let mins_of_day = secs_of_day / 60; let minute = mins_of_day % 60; let hour = mins_of_day / 60; Self::new( year.try_into()?, mon, mday.try_into()?, hour.try_into()?, minute.try_into()?, second.try_into()?, ) } /// Get the year. pub fn year(&self) -> u16 { self.year } /// Get the month. pub fn month(&self) -> u8 { self.month } /// Get the day. pub fn day(&self) -> u8 { self.day } /// Get the hour. pub fn hour(&self) -> u8 { self.hour } /// Get the minutes. pub fn minutes(&self) -> u8 { self.minutes } /// Get the seconds. pub fn seconds(&self) -> u8 { self.seconds } /// Compute [`Duration`] since `UNIX_EPOCH` from the given calendar date. pub fn unix_duration(&self) -> Duration { self.unix_duration } /// Instantiate from [`SystemTime`]. #[cfg(feature = "std")] pub fn from_system_time(time: SystemTime) -> Result { time.duration_since(UNIX_EPOCH) .map_err(|_| ErrorKind::DateTime.into()) .and_then(Self::from_unix_duration) } /// Convert to [`SystemTime`]. #[cfg(feature = "std")] pub fn to_system_time(&self) -> SystemTime { UNIX_EPOCH + self.unix_duration() } } impl FromStr for DateTime { type Err = Error; fn from_str(s: &str) -> Result { match *s.as_bytes() { [year1, year2, year3, year4, b'-', month1, month2, b'-', day1, day2, b'T', hour1, hour2, b':', min1, min2, b':', sec1, sec2, b'Z'] => { let tag = Tag::GeneralizedTime; let year = decode_year(&[year1, year2, year3, year4])?; let month = decode_decimal(tag, month1, month2).map_err(|_| ErrorKind::DateTime)?; let day = decode_decimal(tag, day1, day2).map_err(|_| ErrorKind::DateTime)?; let hour = decode_decimal(tag, hour1, hour2).map_err(|_| ErrorKind::DateTime)?; let minutes = decode_decimal(tag, min1, min2).map_err(|_| ErrorKind::DateTime)?; let seconds = decode_decimal(tag, sec1, sec2).map_err(|_| ErrorKind::DateTime)?; Self::new(year, month, day, hour, minutes, seconds) } _ => Err(ErrorKind::DateTime.into()), } } } impl fmt::Display for DateTime { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "{:02}-{:02}-{:02}T{:02}:{:02}:{:02}Z", self.year, self.month, self.day, self.hour, self.minutes, self.seconds ) } } #[cfg(feature = "std")] impl From for SystemTime { fn from(time: DateTime) -> SystemTime { time.to_system_time() } } #[cfg(feature = "std")] impl From<&DateTime> for SystemTime { fn from(time: &DateTime) -> SystemTime { time.to_system_time() } } #[cfg(feature = "std")] impl TryFrom for DateTime { type Error = Error; fn try_from(time: SystemTime) -> Result { DateTime::from_system_time(time) } } #[cfg(feature = "std")] impl TryFrom<&SystemTime> for DateTime { type Error = Error; fn try_from(time: &SystemTime) -> Result { DateTime::from_system_time(*time) } } #[cfg(feature = "time")] impl TryFrom for PrimitiveDateTime { type Error = Error; fn try_from(time: DateTime) -> Result { let month = time.month().try_into()?; let date = time::Date::from_calendar_date(i32::from(time.year()), month, time.day())?; let time = time::Time::from_hms(time.hour(), time.minutes(), time.seconds())?; Ok(PrimitiveDateTime::new(date, time)) } } #[cfg(feature = "time")] impl TryFrom for DateTime { type Error = Error; fn try_from(time: PrimitiveDateTime) -> Result { DateTime::new( time.year().try_into().map_err(|_| ErrorKind::DateTime)?, time.month().into(), time.day(), time.hour(), time.minute(), time.second(), ) } } // Implement by hand because the derive would create invalid values. // Use the conversion from Duration to create a valid value. #[cfg(feature = "arbitrary")] impl<'a> arbitrary::Arbitrary<'a> for DateTime { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { Self::from_unix_duration(Duration::new( u.int_in_range(0..=MAX_UNIX_DURATION.as_secs().saturating_sub(1))?, u.int_in_range(0..=999_999_999)?, )) .map_err(|_| arbitrary::Error::IncorrectFormat) } fn size_hint(depth: usize) -> (usize, Option) { arbitrary::size_hint::and(u64::size_hint(depth), u32::size_hint(depth)) } } /// Decode 2-digit decimal value // TODO(tarcieri): checked arithmetic #[allow(clippy::integer_arithmetic)] pub(crate) fn decode_decimal(tag: Tag, hi: u8, lo: u8) -> Result { if hi.is_ascii_digit() && lo.is_ascii_digit() { Ok((hi - b'0') * 10 + (lo - b'0')) } else { Err(tag.value_error()) } } /// Encode 2-digit decimal value pub(crate) fn encode_decimal(writer: &mut W, tag: Tag, value: u8) -> Result<()> where W: Writer + ?Sized, { let hi_val = value / 10; if hi_val >= 10 { return Err(tag.value_error()); } writer.write_byte(b'0'.checked_add(hi_val).ok_or(ErrorKind::Overflow)?)?; writer.write_byte(b'0'.checked_add(value % 10).ok_or(ErrorKind::Overflow)?) } /// Decode 4-digit year. // TODO(tarcieri): checked arithmetic #[allow(clippy::integer_arithmetic)] fn decode_year(year: &[u8; 4]) -> Result { let tag = Tag::GeneralizedTime; let hi = decode_decimal(tag, year[0], year[1]).map_err(|_| ErrorKind::DateTime)?; let lo = decode_decimal(tag, year[2], year[3]).map_err(|_| ErrorKind::DateTime)?; Ok(u16::from(hi) * 100 + u16::from(lo)) } #[cfg(test)] mod tests { use super::DateTime; /// Ensure a day is OK fn is_date_valid(year: u16, month: u8, day: u8, hour: u8, minute: u8, second: u8) -> bool { DateTime::new(year, month, day, hour, minute, second).is_ok() } #[test] fn feb_leap_year_handling() { assert!(is_date_valid(2000, 2, 29, 0, 0, 0)); assert!(!is_date_valid(2001, 2, 29, 0, 0, 0)); assert!(!is_date_valid(2100, 2, 29, 0, 0, 0)); } #[test] fn from_str() { let datetime = "2001-01-02T12:13:14Z".parse::().unwrap(); assert_eq!(datetime.year(), 2001); assert_eq!(datetime.month(), 1); assert_eq!(datetime.day(), 2); assert_eq!(datetime.hour(), 12); assert_eq!(datetime.minutes(), 13); assert_eq!(datetime.seconds(), 14); } #[cfg(feature = "alloc")] #[test] fn display() { use alloc::string::ToString; let datetime = DateTime::new(2001, 01, 02, 12, 13, 14).unwrap(); assert_eq!(&datetime.to_string(), "2001-01-02T12:13:14Z"); } } der-0.7.7/src/decode.rs000064400000000000000000000057701046102023000130020ustar 00000000000000//! Trait definition for [`Decode`]. use crate::{FixedTag, Header, Reader, Result, SliceReader}; use core::marker::PhantomData; #[cfg(feature = "pem")] use crate::{pem::PemLabel, PemReader}; #[cfg(doc)] use crate::{Length, Tag}; #[cfg(feature = "alloc")] use alloc::boxed::Box; /// Decoding trait. /// /// This trait provides the core abstraction upon which all decoding operations /// are based. pub trait Decode<'a>: Sized { /// Attempt to decode this message using the provided decoder. fn decode>(decoder: &mut R) -> Result; /// Parse `Self` from the provided DER-encoded byte slice. fn from_der(bytes: &'a [u8]) -> Result { let mut reader = SliceReader::new(bytes)?; let result = Self::decode(&mut reader)?; reader.finish(result) } } impl<'a, T> Decode<'a> for T where T: DecodeValue<'a> + FixedTag, { fn decode>(reader: &mut R) -> Result { let header = Header::decode(reader)?; header.tag.assert_eq(T::TAG)?; T::decode_value(reader, header) } } /// Dummy implementation for [`PhantomData`] which allows deriving /// implementations on structs with phantom fields. impl<'a, T> Decode<'a> for PhantomData where T: ?Sized, { fn decode>(_reader: &mut R) -> Result> { Ok(PhantomData) } } /// Marker trait for data structures that can be decoded from DER without /// borrowing any data from the decoder. /// /// This is primarily useful for trait bounds on functions which require that /// no data is borrowed from the decoder, for example a PEM decoder which needs /// to first decode data from Base64. /// /// This trait is inspired by the [`DeserializeOwned` trait from `serde`](https://docs.rs/serde/latest/serde/de/trait.DeserializeOwned.html). pub trait DecodeOwned: for<'a> Decode<'a> {} impl DecodeOwned for T where T: for<'a> Decode<'a> {} /// PEM decoding trait. /// /// This trait is automatically impl'd for any type which impls both /// [`DecodeOwned`] and [`PemLabel`]. #[cfg(feature = "pem")] pub trait DecodePem: DecodeOwned + PemLabel { /// Try to decode this type from PEM. fn from_pem(pem: impl AsRef<[u8]>) -> Result; } #[cfg(feature = "pem")] impl DecodePem for T { fn from_pem(pem: impl AsRef<[u8]>) -> Result { let mut reader = PemReader::new(pem.as_ref())?; Self::validate_pem_label(reader.type_label())?; T::decode(&mut reader) } } /// Decode the value part of a Tag-Length-Value encoded field, sans the [`Tag`] /// and [`Length`]. pub trait DecodeValue<'a>: Sized { /// Attempt to decode this message using the provided [`Reader`]. fn decode_value>(reader: &mut R, header: Header) -> Result; } #[cfg(feature = "alloc")] impl<'a, T> DecodeValue<'a> for Box where T: DecodeValue<'a>, { fn decode_value>(reader: &mut R, header: Header) -> Result { Ok(Box::new(T::decode_value(reader, header)?)) } } der-0.7.7/src/document.rs000064400000000000000000000241511046102023000133670ustar 00000000000000//! ASN.1 DER-encoded documents stored on the heap. use crate::{Decode, Encode, Error, FixedTag, Length, Reader, Result, SliceReader, Tag, Writer}; use alloc::vec::Vec; use core::fmt::{self, Debug}; #[cfg(feature = "pem")] use {crate::pem, alloc::string::String}; #[cfg(feature = "std")] use std::{fs, path::Path}; #[cfg(all(feature = "pem", feature = "std"))] use alloc::borrow::ToOwned; #[cfg(feature = "zeroize")] use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing}; /// ASN.1 DER-encoded document. /// /// This type wraps an encoded ASN.1 DER message. The document checked to /// ensure it contains a valid DER-encoded `SEQUENCE`. /// /// It implements common functionality related to encoding/decoding such /// documents, such as PEM encapsulation as well as reading/writing documents /// from/to the filesystem. /// /// The [`SecretDocument`] provides a wrapper for this type with additional /// hardening applied. #[derive(Clone, Eq, PartialEq)] pub struct Document { /// ASN.1 DER encoded bytes. der_bytes: Vec, /// Length of this document. length: Length, } impl Document { /// Get the ASN.1 DER-encoded bytes of this document. pub fn as_bytes(&self) -> &[u8] { self.der_bytes.as_slice() } /// Convert to a [`SecretDocument`]. #[cfg(feature = "zeroize")] pub fn into_secret(self) -> SecretDocument { SecretDocument(self) } /// Convert to an ASN.1 DER-encoded byte vector. pub fn into_vec(self) -> Vec { self.der_bytes } /// Return an ASN.1 DER-encoded byte vector. pub fn to_vec(&self) -> Vec { self.der_bytes.clone() } /// Get the length of the encoded ASN.1 DER in bytes. pub fn len(&self) -> Length { self.length } /// Try to decode the inner ASN.1 DER message contained in this /// [`Document`] as the given type. pub fn decode_msg<'a, T: Decode<'a>>(&'a self) -> Result { T::from_der(self.as_bytes()) } /// Encode the provided type as ASN.1 DER, storing the resulting encoded DER /// as a [`Document`]. pub fn encode_msg(msg: &T) -> Result { msg.to_der()?.try_into() } /// Decode ASN.1 DER document from PEM. /// /// Returns the PEM label and decoded [`Document`] on success. #[cfg(feature = "pem")] pub fn from_pem(pem: &str) -> Result<(&str, Self)> { let (label, der_bytes) = pem::decode_vec(pem.as_bytes())?; Ok((label, der_bytes.try_into()?)) } /// Encode ASN.1 DER document as a PEM string with encapsulation boundaries /// containing the provided PEM type `label` (e.g. `CERTIFICATE`). #[cfg(feature = "pem")] pub fn to_pem(&self, label: &'static str, line_ending: pem::LineEnding) -> Result { Ok(pem::encode_string(label, line_ending, self.as_bytes())?) } /// Read ASN.1 DER document from a file. #[cfg(feature = "std")] pub fn read_der_file(path: impl AsRef) -> Result { fs::read(path)?.try_into() } /// Write ASN.1 DER document to a file. #[cfg(feature = "std")] pub fn write_der_file(&self, path: impl AsRef) -> Result<()> { Ok(fs::write(path, self.as_bytes())?) } /// Read PEM-encoded ASN.1 DER document from a file. #[cfg(all(feature = "pem", feature = "std"))] pub fn read_pem_file(path: impl AsRef) -> Result<(String, Self)> { Self::from_pem(&fs::read_to_string(path)?).map(|(label, doc)| (label.to_owned(), doc)) } /// Write PEM-encoded ASN.1 DER document to a file. #[cfg(all(feature = "pem", feature = "std"))] pub fn write_pem_file( &self, path: impl AsRef, label: &'static str, line_ending: pem::LineEnding, ) -> Result<()> { let pem = self.to_pem(label, line_ending)?; Ok(fs::write(path, pem.as_bytes())?) } } impl AsRef<[u8]> for Document { fn as_ref(&self) -> &[u8] { self.as_bytes() } } impl Debug for Document { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("Document(")?; for byte in self.as_bytes() { write!(f, "{:02X}", byte)?; } f.write_str(")") } } impl<'a> Decode<'a> for Document { fn decode>(reader: &mut R) -> Result { let header = reader.peek_header()?; let length = (header.encoded_len()? + header.length)?; let bytes = reader.read_slice(length)?; Ok(Self { der_bytes: bytes.into(), length, }) } } impl Encode for Document { fn encoded_len(&self) -> Result { Ok(self.len()) } fn encode(&self, writer: &mut impl Writer) -> Result<()> { writer.write(self.as_bytes()) } } impl FixedTag for Document { const TAG: Tag = Tag::Sequence; } impl TryFrom<&[u8]> for Document { type Error = Error; fn try_from(der_bytes: &[u8]) -> Result { Self::from_der(der_bytes) } } impl TryFrom> for Document { type Error = Error; fn try_from(der_bytes: Vec) -> Result { let mut decoder = SliceReader::new(&der_bytes)?; decode_sequence(&mut decoder)?; decoder.finish(())?; let length = der_bytes.len().try_into()?; Ok(Self { der_bytes, length }) } } /// Secret [`Document`] type. /// /// Useful for formats which represent potentially secret data, such as /// cryptographic keys. /// /// This type provides additional hardening such as ensuring that the contents /// are zeroized-on-drop, and also using more restrictive file permissions when /// writing files to disk. #[cfg(feature = "zeroize")] #[derive(Clone)] pub struct SecretDocument(Document); #[cfg(feature = "zeroize")] impl SecretDocument { /// Borrow the inner serialized bytes of this document. pub fn as_bytes(&self) -> &[u8] { self.0.as_bytes() } /// Return an allocated ASN.1 DER serialization as a byte vector. pub fn to_bytes(&self) -> Zeroizing> { Zeroizing::new(self.0.to_vec()) } /// Get the length of the encoded ASN.1 DER in bytes. pub fn len(&self) -> Length { self.0.len() } /// Try to decode the inner ASN.1 DER message as the given type. pub fn decode_msg<'a, T: Decode<'a>>(&'a self) -> Result { self.0.decode_msg() } /// Encode the provided type as ASN.1 DER. pub fn encode_msg(msg: &T) -> Result { Document::encode_msg(msg).map(Self) } /// Decode ASN.1 DER document from PEM. #[cfg(feature = "pem")] pub fn from_pem(pem: &str) -> Result<(&str, Self)> { Document::from_pem(pem).map(|(label, doc)| (label, Self(doc))) } /// Encode ASN.1 DER document as a PEM string. #[cfg(feature = "pem")] pub fn to_pem( &self, label: &'static str, line_ending: pem::LineEnding, ) -> Result> { self.0.to_pem(label, line_ending).map(Zeroizing::new) } /// Read ASN.1 DER document from a file. #[cfg(feature = "std")] pub fn read_der_file(path: impl AsRef) -> Result { Document::read_der_file(path).map(Self) } /// Write ASN.1 DER document to a file. #[cfg(feature = "std")] pub fn write_der_file(&self, path: impl AsRef) -> Result<()> { write_secret_file(path, self.as_bytes()) } /// Read PEM-encoded ASN.1 DER document from a file. #[cfg(all(feature = "pem", feature = "std"))] pub fn read_pem_file(path: impl AsRef) -> Result<(String, Self)> { Document::read_pem_file(path).map(|(label, doc)| (label, Self(doc))) } /// Write PEM-encoded ASN.1 DER document to a file. #[cfg(all(feature = "pem", feature = "std"))] pub fn write_pem_file( &self, path: impl AsRef, label: &'static str, line_ending: pem::LineEnding, ) -> Result<()> { write_secret_file(path, self.to_pem(label, line_ending)?.as_bytes()) } } #[cfg(feature = "zeroize")] impl Debug for SecretDocument { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("SecretDocument").finish_non_exhaustive() } } #[cfg(feature = "zeroize")] impl Drop for SecretDocument { fn drop(&mut self) { self.0.der_bytes.zeroize(); } } #[cfg(feature = "zeroize")] impl From for SecretDocument { fn from(doc: Document) -> SecretDocument { SecretDocument(doc) } } #[cfg(feature = "zeroize")] impl TryFrom<&[u8]> for SecretDocument { type Error = Error; fn try_from(der_bytes: &[u8]) -> Result { Document::try_from(der_bytes).map(Self) } } #[cfg(feature = "zeroize")] impl TryFrom> for SecretDocument { type Error = Error; fn try_from(der_bytes: Vec) -> Result { Document::try_from(der_bytes).map(Self) } } #[cfg(feature = "zeroize")] impl ZeroizeOnDrop for SecretDocument {} /// Attempt to decode a ASN.1 `SEQUENCE` from the given decoder, returning the /// entire sequence including the header. fn decode_sequence<'a>(decoder: &mut SliceReader<'a>) -> Result<&'a [u8]> { let header = decoder.peek_header()?; header.tag.assert_eq(Tag::Sequence)?; let len = (header.encoded_len()? + header.length)?; decoder.read_slice(len) } /// Write a file containing secret data to the filesystem, restricting the /// file permissions so it's only readable by the owner #[cfg(all(unix, feature = "std", feature = "zeroize"))] fn write_secret_file(path: impl AsRef, data: &[u8]) -> Result<()> { use std::{io::Write, os::unix::fs::OpenOptionsExt}; /// File permissions for secret data #[cfg(unix)] const SECRET_FILE_PERMS: u32 = 0o600; fs::OpenOptions::new() .create(true) .write(true) .truncate(true) .mode(SECRET_FILE_PERMS) .open(path) .and_then(|mut file| file.write_all(data))?; Ok(()) } /// Write a file containing secret data to the filesystem // TODO(tarcieri): permissions hardening on Windows #[cfg(all(not(unix), feature = "std", feature = "zeroize"))] fn write_secret_file(path: impl AsRef, data: &[u8]) -> Result<()> { fs::write(path, data)?; Ok(()) } der-0.7.7/src/encode.rs000064400000000000000000000110271046102023000130040ustar 00000000000000//! Trait definition for [`Encode`]. use crate::{Header, Length, Result, SliceWriter, Tagged, Writer}; use core::marker::PhantomData; #[cfg(feature = "alloc")] use {alloc::boxed::Box, alloc::vec::Vec, core::iter}; #[cfg(feature = "pem")] use { crate::PemWriter, alloc::string::String, pem_rfc7468::{self as pem, LineEnding, PemLabel}, }; #[cfg(any(feature = "alloc", feature = "pem"))] use crate::ErrorKind; #[cfg(doc)] use crate::Tag; /// Encoding trait. pub trait Encode { /// Compute the length of this value in bytes when encoded as ASN.1 DER. fn encoded_len(&self) -> Result; /// Encode this value as ASN.1 DER using the provided [`Writer`]. fn encode(&self, encoder: &mut impl Writer) -> Result<()>; /// Encode this value to the provided byte slice, returning a sub-slice /// containing the encoded message. fn encode_to_slice<'a>(&self, buf: &'a mut [u8]) -> Result<&'a [u8]> { let mut writer = SliceWriter::new(buf); self.encode(&mut writer)?; writer.finish() } /// Encode this message as ASN.1 DER, appending it to the provided /// byte vector. #[cfg(feature = "alloc")] fn encode_to_vec(&self, buf: &mut Vec) -> Result { let expected_len = usize::try_from(self.encoded_len()?)?; buf.reserve(expected_len); buf.extend(iter::repeat(0).take(expected_len)); let mut writer = SliceWriter::new(buf); self.encode(&mut writer)?; let actual_len = writer.finish()?.len(); if expected_len != actual_len { return Err(ErrorKind::Incomplete { expected_len: expected_len.try_into()?, actual_len: actual_len.try_into()?, } .into()); } actual_len.try_into() } /// Encode this type as DER, returning a byte vector. #[cfg(feature = "alloc")] fn to_der(&self) -> Result> { let mut buf = Vec::new(); self.encode_to_vec(&mut buf)?; Ok(buf) } } impl Encode for T where T: EncodeValue + Tagged, { /// Compute the length of this value in bytes when encoded as ASN.1 DER. fn encoded_len(&self) -> Result { self.value_len().and_then(|len| len.for_tlv()) } /// Encode this value as ASN.1 DER using the provided [`Writer`]. fn encode(&self, writer: &mut impl Writer) -> Result<()> { self.header()?.encode(writer)?; self.encode_value(writer) } } /// Dummy implementation for [`PhantomData`] which allows deriving /// implementations on structs with phantom fields. impl Encode for PhantomData where T: ?Sized, { fn encoded_len(&self) -> Result { Ok(Length::ZERO) } fn encode(&self, _writer: &mut impl Writer) -> Result<()> { Ok(()) } } /// PEM encoding trait. /// /// This trait is automatically impl'd for any type which impls both /// [`Encode`] and [`PemLabel`]. #[cfg(feature = "pem")] pub trait EncodePem: Encode + PemLabel { /// Try to encode this type as PEM. fn to_pem(&self, line_ending: LineEnding) -> Result; } #[cfg(feature = "pem")] impl EncodePem for T { fn to_pem(&self, line_ending: LineEnding) -> Result { let der_len = usize::try_from(self.encoded_len()?)?; let pem_len = pem::encapsulated_len(Self::PEM_LABEL, line_ending, der_len)?; let mut buf = vec![0u8; pem_len]; let mut writer = PemWriter::new(Self::PEM_LABEL, line_ending, &mut buf)?; self.encode(&mut writer)?; let actual_len = writer.finish()?; buf.truncate(actual_len); Ok(String::from_utf8(buf)?) } } /// Encode the value part of a Tag-Length-Value encoded field, sans the [`Tag`] /// and [`Length`]. pub trait EncodeValue { /// Get the [`Header`] used to encode this value. fn header(&self) -> Result
where Self: Tagged, { Header::new(self.tag(), self.value_len()?) } /// Compute the length of this value (sans [`Tag`]+[`Length`] header) when /// encoded as ASN.1 DER. fn value_len(&self) -> Result; /// Encode value (sans [`Tag`]+[`Length`] header) as ASN.1 DER using the /// provided [`Writer`]. fn encode_value(&self, encoder: &mut impl Writer) -> Result<()>; } #[cfg(feature = "alloc")] impl EncodeValue for Box where T: EncodeValue, { fn value_len(&self) -> Result { T::value_len(self) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { T::encode_value(self, writer) } } der-0.7.7/src/encode_ref.rs000064400000000000000000000031701046102023000136400ustar 00000000000000//! Wrapper object for encoding reference types. // TODO(tarcieri): replace with blanket impls of `Encode(Value)` for reference types? use crate::{Encode, EncodeValue, Length, Result, Tag, Tagged, ValueOrd, Writer}; use core::cmp::Ordering; /// Reference encoder: wrapper type which impls `Encode` for any reference to a /// type which impls the same. pub struct EncodeRef<'a, T>(pub &'a T); impl<'a, T> AsRef for EncodeRef<'a, T> { fn as_ref(&self) -> &T { self.0 } } impl<'a, T> Encode for EncodeRef<'a, T> where T: Encode, { fn encoded_len(&self) -> Result { self.0.encoded_len() } fn encode(&self, writer: &mut impl Writer) -> Result<()> { self.0.encode(writer) } } /// Reference value encoder: wrapper type which impls `EncodeValue` and `Tagged` /// for any reference type which impls the same. /// /// By virtue of the blanket impl, this type also impls `Encode`. pub struct EncodeValueRef<'a, T>(pub &'a T); impl<'a, T> AsRef for EncodeValueRef<'a, T> { fn as_ref(&self) -> &T { self.0 } } impl<'a, T> EncodeValue for EncodeValueRef<'a, T> where T: EncodeValue, { fn value_len(&self) -> Result { self.0.value_len() } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { self.0.encode_value(writer) } } impl<'a, T> Tagged for EncodeValueRef<'a, T> where T: Tagged, { fn tag(&self) -> Tag { self.0.tag() } } impl<'a, T> ValueOrd for EncodeValueRef<'a, T> where T: ValueOrd, { fn value_cmp(&self, other: &Self) -> Result { self.0.value_cmp(other.0) } } der-0.7.7/src/error.rs000064400000000000000000000250661046102023000127100ustar 00000000000000//! Error types. pub use core::str::Utf8Error; use crate::{Length, Tag}; use core::{convert::Infallible, fmt, num::TryFromIntError}; #[cfg(feature = "oid")] use crate::asn1::ObjectIdentifier; #[cfg(feature = "pem")] use crate::pem; /// Result type. pub type Result = core::result::Result; /// Error type. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct Error { /// Kind of error. kind: ErrorKind, /// Position inside of message where error occurred. position: Option, } impl Error { /// Create a new [`Error`]. pub fn new(kind: ErrorKind, position: Length) -> Error { Error { kind, position: Some(position), } } /// Create a new [`ErrorKind::Incomplete`] for the given length. /// /// Computes the expected len as being one greater than `actual_len`. pub fn incomplete(actual_len: Length) -> Self { match actual_len + Length::ONE { Ok(expected_len) => ErrorKind::Incomplete { expected_len, actual_len, } .at(actual_len), Err(err) => err.kind().at(actual_len), } } /// Get the [`ErrorKind`] which occurred. pub fn kind(self) -> ErrorKind { self.kind } /// Get the position inside of the message where the error occurred. pub fn position(self) -> Option { self.position } /// For errors occurring inside of a nested message, extend the position /// count by the location where the nested message occurs. pub(crate) fn nested(self, nested_position: Length) -> Self { // TODO(tarcieri): better handle length overflows occurring in this calculation? let position = (nested_position + self.position.unwrap_or_default()).ok(); Self { kind: self.kind, position, } } } #[cfg(feature = "std")] impl std::error::Error for Error {} impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.kind)?; if let Some(pos) = self.position { write!(f, " at DER byte {}", pos)?; } Ok(()) } } impl From for Error { fn from(kind: ErrorKind) -> Error { Error { kind, position: None, } } } impl From for Error { fn from(_: Infallible) -> Error { unreachable!() } } impl From for Error { fn from(_: TryFromIntError) -> Error { Error { kind: ErrorKind::Overflow, position: None, } } } impl From for Error { fn from(err: Utf8Error) -> Error { Error { kind: ErrorKind::Utf8(err), position: None, } } } #[cfg(feature = "alloc")] impl From for Error { fn from(err: alloc::string::FromUtf8Error) -> Error { ErrorKind::Utf8(err.utf8_error()).into() } } #[cfg(feature = "oid")] impl From for Error { fn from(_: const_oid::Error) -> Error { ErrorKind::OidMalformed.into() } } #[cfg(feature = "pem")] impl From for Error { fn from(err: pem::Error) -> Error { ErrorKind::Pem(err).into() } } #[cfg(feature = "std")] impl From for Error { fn from(err: std::io::Error) -> Error { match err.kind() { std::io::ErrorKind::NotFound => ErrorKind::FileNotFound, std::io::ErrorKind::PermissionDenied => ErrorKind::PermissionDenied, other => ErrorKind::Io(other), } .into() } } #[cfg(feature = "time")] impl From for Error { fn from(_: time::error::ComponentRange) -> Error { ErrorKind::DateTime.into() } } /// Error type. #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[non_exhaustive] pub enum ErrorKind { /// Date-and-time related errors. DateTime, /// This error indicates a previous DER parsing operation resulted in /// an error and tainted the state of a `Decoder` or `Encoder`. /// /// Once this occurs, the overall operation has failed and cannot be /// subsequently resumed. Failed, /// File not found error. #[cfg(feature = "std")] FileNotFound, /// Message is incomplete and does not contain all of the expected data. Incomplete { /// Expected message length. /// /// Note that this length represents a *minimum* lower bound on how /// much additional data is needed to continue parsing the message. /// /// It's possible upon subsequent message parsing that the parser will /// discover even more data is needed. expected_len: Length, /// Actual length of the message buffer currently being processed. actual_len: Length, }, /// I/O errors. #[cfg(feature = "std")] Io(std::io::ErrorKind), /// Indefinite length disallowed. IndefiniteLength, /// Incorrect length for a given field. Length { /// Tag of the value being decoded. tag: Tag, }, /// Message is not canonically encoded. Noncanonical { /// Tag of the value which is not canonically encoded. tag: Tag, }, /// OID is improperly encoded. OidMalformed, /// Unknown OID. /// /// This error is intended to be used by libraries which parse DER-based /// formats which encounter unknown or unsupported OID libraries. /// /// It enables passing back the OID value to the caller, which allows them /// to determine which OID(s) are causing the error (and then potentially /// contribute upstream support for algorithms they care about). #[cfg(feature = "oid")] OidUnknown { /// OID value that was unrecognized by a parser for a DER-based format. oid: ObjectIdentifier, }, /// `SET` cannot contain duplicates. SetDuplicate, /// `SET` ordering error: items not in canonical order. SetOrdering, /// Integer overflow occurred (library bug!). Overflow, /// Message is longer than this library's internal limits support. Overlength, /// PEM encoding errors. #[cfg(feature = "pem")] Pem(pem::Error), /// Permission denied reading file. #[cfg(feature = "std")] PermissionDenied, /// Reader does not support the requested operation. Reader, /// Unknown tag mode. TagModeUnknown, /// Invalid tag number. /// /// The "tag number" is the lower 5-bits of a tag's octet. /// This error occurs in the case that all 5-bits are set to `1`, /// which indicates a multi-byte tag which is unsupported by this library. TagNumberInvalid, /// Unexpected tag. TagUnexpected { /// Tag the decoder was expecting (if there is a single such tag). /// /// `None` if multiple tags are expected/allowed, but the `actual` tag /// does not match any of them. expected: Option, /// Actual tag encountered in the message. actual: Tag, }, /// Unknown/unsupported tag. TagUnknown { /// Raw byte value of the tag. byte: u8, }, /// Undecoded trailing data at end of message. TrailingData { /// Length of the decoded data. decoded: Length, /// Total length of the remaining data left in the buffer. remaining: Length, }, /// UTF-8 errors. Utf8(Utf8Error), /// Unexpected value. Value { /// Tag of the unexpected value. tag: Tag, }, } impl ErrorKind { /// Annotate an [`ErrorKind`] with context about where it occurred, /// returning an error. pub fn at(self, position: Length) -> Error { Error::new(self, position) } } impl fmt::Display for ErrorKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ErrorKind::DateTime => write!(f, "date/time error"), ErrorKind::Failed => write!(f, "operation failed"), #[cfg(feature = "std")] ErrorKind::FileNotFound => write!(f, "file not found"), ErrorKind::Incomplete { expected_len, actual_len, } => write!( f, "ASN.1 DER message is incomplete: expected {}, actual {}", expected_len, actual_len ), #[cfg(feature = "std")] ErrorKind::Io(err) => write!(f, "I/O error: {:?}", err), ErrorKind::IndefiniteLength => write!(f, "indefinite length disallowed"), ErrorKind::Length { tag } => write!(f, "incorrect length for {}", tag), ErrorKind::Noncanonical { tag } => { write!(f, "ASN.1 {} not canonically encoded as DER", tag) } ErrorKind::OidMalformed => write!(f, "malformed OID"), #[cfg(feature = "oid")] ErrorKind::OidUnknown { oid } => { write!(f, "unknown/unsupported OID: {}", oid) } ErrorKind::SetDuplicate => write!(f, "SET OF contains duplicate"), ErrorKind::SetOrdering => write!(f, "SET OF ordering error"), ErrorKind::Overflow => write!(f, "integer overflow"), ErrorKind::Overlength => write!(f, "ASN.1 DER message is too long"), #[cfg(feature = "pem")] ErrorKind::Pem(e) => write!(f, "PEM error: {}", e), #[cfg(feature = "std")] ErrorKind::PermissionDenied => write!(f, "permission denied"), ErrorKind::Reader => write!(f, "reader does not support the requested operation"), ErrorKind::TagModeUnknown => write!(f, "unknown tag mode"), ErrorKind::TagNumberInvalid => write!(f, "invalid tag number"), ErrorKind::TagUnexpected { expected, actual } => { write!(f, "unexpected ASN.1 DER tag: ")?; if let Some(tag) = expected { write!(f, "expected {}, ", tag)?; } write!(f, "got {}", actual) } ErrorKind::TagUnknown { byte } => { write!(f, "unknown/unsupported ASN.1 DER tag: 0x{:02x}", byte) } ErrorKind::TrailingData { decoded, remaining } => { write!( f, "trailing data at end of DER message: decoded {} bytes, {} bytes remaining", decoded, remaining ) } ErrorKind::Utf8(e) => write!(f, "{}", e), ErrorKind::Value { tag } => write!(f, "malformed ASN.1 DER value for {}", tag), } } } der-0.7.7/src/header.rs000064400000000000000000000032421046102023000127770ustar 00000000000000//! ASN.1 DER headers. use crate::{Decode, DerOrd, Encode, ErrorKind, Length, Reader, Result, Tag, Writer}; use core::cmp::Ordering; /// ASN.1 DER headers: tag + length component of TLV-encoded values #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct Header { /// Tag representing the type of the encoded value pub tag: Tag, /// Length of the encoded value pub length: Length, } impl Header { /// Create a new [`Header`] from a [`Tag`] and a specified length. /// /// Returns an error if the length exceeds the limits of [`Length`]. pub fn new(tag: Tag, length: impl TryInto) -> Result { let length = length.try_into().map_err(|_| ErrorKind::Overflow)?; Ok(Self { tag, length }) } } impl<'a> Decode<'a> for Header { fn decode>(reader: &mut R) -> Result
{ let tag = Tag::decode(reader)?; let length = Length::decode(reader).map_err(|e| { if e.kind() == ErrorKind::Overlength { ErrorKind::Length { tag }.into() } else { e } })?; Ok(Self { tag, length }) } } impl Encode for Header { fn encoded_len(&self) -> Result { self.tag.encoded_len()? + self.length.encoded_len()? } fn encode(&self, writer: &mut impl Writer) -> Result<()> { self.tag.encode(writer)?; self.length.encode(writer) } } impl DerOrd for Header { fn der_cmp(&self, other: &Self) -> Result { match self.tag.der_cmp(&other.tag)? { Ordering::Equal => self.length.der_cmp(&other.length), ordering => Ok(ordering), } } } der-0.7.7/src/length.rs000064400000000000000000000343221046102023000130330ustar 00000000000000//! Length calculations for encoded ASN.1 DER values use crate::{Decode, DerOrd, Encode, Error, ErrorKind, Reader, Result, SliceWriter, Writer}; use core::{ cmp::Ordering, fmt, ops::{Add, Sub}, }; /// Maximum number of octets in a DER encoding of a [`Length`] using the /// rules implemented by this crate. const MAX_DER_OCTETS: usize = 5; /// Maximum length as a `u32` (256 MiB). const MAX_U32: u32 = 0xfff_ffff; /// Octet identifying an indefinite length as described in X.690 Section /// 8.1.3.6.1: /// /// > The single octet shall have bit 8 set to one, and bits 7 to /// > 1 set to zero. const INDEFINITE_LENGTH_OCTET: u8 = 0b10000000; // 0x80 /// ASN.1-encoded length. /// /// Maximum length is defined by the [`Length::MAX`] constant (256 MiB). #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] pub struct Length(u32); impl Length { /// Length of `0` pub const ZERO: Self = Self(0); /// Length of `1` pub const ONE: Self = Self(1); /// Maximum length currently supported: 256 MiB pub const MAX: Self = Self(MAX_U32); /// Create a new [`Length`] for any value which fits inside of a [`u16`]. /// /// This function is const-safe and therefore useful for [`Length`] constants. pub const fn new(value: u16) -> Self { Self(value as u32) } /// Is this length equal to zero? pub fn is_zero(self) -> bool { self == Self::ZERO } /// Get the length of DER Tag-Length-Value (TLV) encoded data if `self` /// is the length of the inner "value" portion of the message. pub fn for_tlv(self) -> Result { Self::ONE + self.encoded_len()? + self } /// Perform saturating addition of two lengths. pub fn saturating_add(self, rhs: Self) -> Self { Self(self.0.saturating_add(rhs.0)) } /// Perform saturating subtraction of two lengths. pub fn saturating_sub(self, rhs: Self) -> Self { Self(self.0.saturating_sub(rhs.0)) } /// Get initial octet of the encoded length (if one is required). /// /// From X.690 Section 8.1.3.5: /// > In the long form, the length octets shall consist of an initial octet /// > and one or more subsequent octets. The initial octet shall be encoded /// > as follows: /// > /// > a) bit 8 shall be one; /// > b) bits 7 to 1 shall encode the number of subsequent octets in the /// > length octets, as an unsigned binary integer with bit 7 as the /// > most significant bit; /// > c) the value 11111111₂ shall not be used. fn initial_octet(self) -> Option { match self.0 { 0x80..=0xFF => Some(0x81), 0x100..=0xFFFF => Some(0x82), 0x10000..=0xFFFFFF => Some(0x83), 0x1000000..=MAX_U32 => Some(0x84), _ => None, } } } impl Add for Length { type Output = Result; fn add(self, other: Self) -> Result { self.0 .checked_add(other.0) .ok_or_else(|| ErrorKind::Overflow.into()) .and_then(TryInto::try_into) } } impl Add for Length { type Output = Result; fn add(self, other: u8) -> Result { self + Length::from(other) } } impl Add for Length { type Output = Result; fn add(self, other: u16) -> Result { self + Length::from(other) } } impl Add for Length { type Output = Result; fn add(self, other: u32) -> Result { self + Length::try_from(other)? } } impl Add for Length { type Output = Result; fn add(self, other: usize) -> Result { self + Length::try_from(other)? } } impl Add for Result { type Output = Self; fn add(self, other: Length) -> Self { self? + other } } impl Sub for Length { type Output = Result; fn sub(self, other: Length) -> Result { self.0 .checked_sub(other.0) .ok_or_else(|| ErrorKind::Overflow.into()) .and_then(TryInto::try_into) } } impl Sub for Result { type Output = Self; fn sub(self, other: Length) -> Self { self? - other } } impl From for Length { fn from(len: u8) -> Length { Length(len.into()) } } impl From for Length { fn from(len: u16) -> Length { Length(len.into()) } } impl From for u32 { fn from(length: Length) -> u32 { length.0 } } impl TryFrom for Length { type Error = Error; fn try_from(len: u32) -> Result { if len <= Self::MAX.0 { Ok(Length(len)) } else { Err(ErrorKind::Overflow.into()) } } } impl TryFrom for Length { type Error = Error; fn try_from(len: usize) -> Result { u32::try_from(len) .map_err(|_| ErrorKind::Overflow)? .try_into() } } impl TryFrom for usize { type Error = Error; fn try_from(len: Length) -> Result { len.0.try_into().map_err(|_| ErrorKind::Overflow.into()) } } impl<'a> Decode<'a> for Length { fn decode>(reader: &mut R) -> Result { match reader.read_byte()? { // Note: per X.690 Section 8.1.3.6.1 the byte 0x80 encodes indefinite // lengths, which are not allowed in DER, so disallow that byte. len if len < INDEFINITE_LENGTH_OCTET => Ok(len.into()), INDEFINITE_LENGTH_OCTET => Err(ErrorKind::IndefiniteLength.into()), // 1-4 byte variable-sized length prefix tag @ 0x81..=0x84 => { let nbytes = tag.checked_sub(0x80).ok_or(ErrorKind::Overlength)? as usize; debug_assert!(nbytes <= 4); let mut decoded_len = 0u32; for _ in 0..nbytes { decoded_len = decoded_len.checked_shl(8).ok_or(ErrorKind::Overflow)? | u32::from(reader.read_byte()?); } let length = Length::try_from(decoded_len)?; // X.690 Section 10.1: DER lengths must be encoded with a minimum // number of octets if length.initial_octet() == Some(tag) { Ok(length) } else { Err(ErrorKind::Overlength.into()) } } _ => { // We specialize to a maximum 4-byte length (including initial octet) Err(ErrorKind::Overlength.into()) } } } } impl Encode for Length { fn encoded_len(&self) -> Result { match self.0 { 0..=0x7F => Ok(Length(1)), 0x80..=0xFF => Ok(Length(2)), 0x100..=0xFFFF => Ok(Length(3)), 0x10000..=0xFFFFFF => Ok(Length(4)), 0x1000000..=MAX_U32 => Ok(Length(5)), _ => Err(ErrorKind::Overflow.into()), } } fn encode(&self, writer: &mut impl Writer) -> Result<()> { match self.initial_octet() { Some(tag_byte) => { writer.write_byte(tag_byte)?; // Strip leading zeroes match self.0.to_be_bytes() { [0, 0, 0, byte] => writer.write_byte(byte), [0, 0, bytes @ ..] => writer.write(&bytes), [0, bytes @ ..] => writer.write(&bytes), bytes => writer.write(&bytes), } } #[allow(clippy::cast_possible_truncation)] None => writer.write_byte(self.0 as u8), } } } impl DerOrd for Length { fn der_cmp(&self, other: &Self) -> Result { let mut buf1 = [0u8; MAX_DER_OCTETS]; let mut buf2 = [0u8; MAX_DER_OCTETS]; let mut encoder1 = SliceWriter::new(&mut buf1); encoder1.encode(self)?; let mut encoder2 = SliceWriter::new(&mut buf2); encoder2.encode(other)?; Ok(encoder1.finish()?.cmp(encoder2.finish()?)) } } impl fmt::Display for Length { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } // Implement by hand because the derive would create invalid values. // Generate a u32 with a valid range. #[cfg(feature = "arbitrary")] impl<'a> arbitrary::Arbitrary<'a> for Length { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { Ok(Self(u.int_in_range(0..=MAX_U32)?)) } fn size_hint(depth: usize) -> (usize, Option) { u32::size_hint(depth) } } /// Length type with support for indefinite lengths as used by ASN.1 BER, /// as described in X.690 Section 8.1.3.6: /// /// > 8.1.3.6 For the indefinite form, the length octets indicate that the /// > contents octets are terminated by end-of-contents /// > octets (see 8.1.5), and shall consist of a single octet. /// > /// > 8.1.3.6.1 The single octet shall have bit 8 set to one, and bits 7 to /// > 1 set to zero. /// > /// > 8.1.3.6.2 If this form of length is used, then end-of-contents octets /// > (see 8.1.5) shall be present in the encoding following the contents /// > octets. /// /// Indefinite lengths are non-canonical and therefore invalid DER, however /// there are interoperability corner cases where we have little choice but to /// tolerate some BER productions where this is helpful. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct IndefiniteLength(Option); impl IndefiniteLength { /// Length of `0`. pub const ZERO: Self = Self(Some(Length::ZERO)); /// Length of `1`. pub const ONE: Self = Self(Some(Length::ONE)); /// Indefinite length. pub const INDEFINITE: Self = Self(None); } impl IndefiniteLength { /// Create a definite length from a type which can be converted into a /// `Length`. pub fn new(length: impl Into) -> Self { Self(Some(length.into())) } /// Is this length definite? pub fn is_definite(self) -> bool { self.0.is_some() } /// Is this length indefinite? pub fn is_indefinite(self) -> bool { self.0.is_none() } } impl<'a> Decode<'a> for IndefiniteLength { fn decode>(reader: &mut R) -> Result { if reader.peek_byte() == Some(INDEFINITE_LENGTH_OCTET) { // Consume the byte we already peeked at. let byte = reader.read_byte()?; debug_assert_eq!(byte, INDEFINITE_LENGTH_OCTET); Ok(Self::INDEFINITE) } else { Length::decode(reader).map(Into::into) } } } impl Encode for IndefiniteLength { fn encoded_len(&self) -> Result { match self.0 { Some(length) => length.encoded_len(), None => Ok(Length::ONE), } } fn encode(&self, writer: &mut impl Writer) -> Result<()> { match self.0 { Some(length) => length.encode(writer), None => writer.write_byte(INDEFINITE_LENGTH_OCTET), } } } impl From for IndefiniteLength { fn from(length: Length) -> IndefiniteLength { Self(Some(length)) } } impl From> for IndefiniteLength { fn from(length: Option) -> IndefiniteLength { IndefiniteLength(length) } } impl From for Option { fn from(length: IndefiniteLength) -> Option { length.0 } } impl TryFrom for Length { type Error = Error; fn try_from(length: IndefiniteLength) -> Result { length.0.ok_or_else(|| ErrorKind::IndefiniteLength.into()) } } #[cfg(test)] mod tests { use super::{IndefiniteLength, Length}; use crate::{Decode, DerOrd, Encode, ErrorKind}; use core::cmp::Ordering; #[test] fn decode() { assert_eq!(Length::ZERO, Length::from_der(&[0x00]).unwrap()); assert_eq!(Length::from(0x7Fu8), Length::from_der(&[0x7F]).unwrap()); assert_eq!( Length::from(0x80u8), Length::from_der(&[0x81, 0x80]).unwrap() ); assert_eq!( Length::from(0xFFu8), Length::from_der(&[0x81, 0xFF]).unwrap() ); assert_eq!( Length::from(0x100u16), Length::from_der(&[0x82, 0x01, 0x00]).unwrap() ); assert_eq!( Length::try_from(0x10000u32).unwrap(), Length::from_der(&[0x83, 0x01, 0x00, 0x00]).unwrap() ); } #[test] fn encode() { let mut buffer = [0u8; 4]; assert_eq!(&[0x00], Length::ZERO.encode_to_slice(&mut buffer).unwrap()); assert_eq!( &[0x7F], Length::from(0x7Fu8).encode_to_slice(&mut buffer).unwrap() ); assert_eq!( &[0x81, 0x80], Length::from(0x80u8).encode_to_slice(&mut buffer).unwrap() ); assert_eq!( &[0x81, 0xFF], Length::from(0xFFu8).encode_to_slice(&mut buffer).unwrap() ); assert_eq!( &[0x82, 0x01, 0x00], Length::from(0x100u16).encode_to_slice(&mut buffer).unwrap() ); assert_eq!( &[0x83, 0x01, 0x00, 0x00], Length::try_from(0x10000u32) .unwrap() .encode_to_slice(&mut buffer) .unwrap() ); } #[test] fn indefinite_lengths() { // DER disallows indefinite lengths assert!(Length::from_der(&[0x80]).is_err()); // The `IndefiniteLength` type supports them let indefinite_length = IndefiniteLength::from_der(&[0x80]).unwrap(); assert!(indefinite_length.is_indefinite()); assert_eq!(indefinite_length, IndefiniteLength::INDEFINITE); // It also supports definite lengths. let length = IndefiniteLength::from_der(&[0x83, 0x01, 0x00, 0x00]).unwrap(); assert!(length.is_definite()); assert_eq!( Length::try_from(0x10000u32).unwrap(), length.try_into().unwrap() ); } #[test] fn add_overflows_when_max_length_exceeded() { let result = Length::MAX + Length::ONE; assert_eq!( result.err().map(|err| err.kind()), Some(ErrorKind::Overflow) ); } #[test] fn der_ord() { assert_eq!(Length::ONE.der_cmp(&Length::MAX).unwrap(), Ordering::Less); } } der-0.7.7/src/lib.rs000064400000000000000000000364361046102023000123300ustar 00000000000000#![no_std] #![cfg_attr(docsrs, feature(doc_auto_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::mod_module_files, 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> //! } //! //! impl<'a> DecodeValue<'a> for AlgorithmIdentifier<'a> { //! fn decode_value>(reader: &mut R, _header: Header) -> der::Result { //! // 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> ::der::EncodeValue for AlgorithmIdentifier<'a> { //! fn value_len(&self) -> ::der::Result<::der::Length> { //! self.algorithm.encoded_len()? + self.parameters.encoded_len()? //! } //! //! fn encode_value(&self, writer: &mut impl ::der::Writer) -> ::der::Result<()> { //! self.algorithm.encode(writer)?; //! self.parameters.encode(writer)?; //! Ok(()) //! } //! } //! //! impl<'a> Sequence<'a> for AlgorithmIdentifier<'a> {} //! //! // Example parameters value: OID for the NIST P-256 elliptic curve. //! let parameters = "1.2.840.10045.3.1.7".parse::().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_der().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` 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_der().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> //! } //! //! // Example parameters value: OID for the NIST P-256 elliptic curve. //! let parameters_oid = "1.2.840.10045.3.1.7".parse::().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_der().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> //! # } //! /// 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 mod referenced; pub(crate) mod arrayvec; mod bytes_ref; mod datetime; mod decode; mod encode; mod encode_ref; mod error; mod header; mod length; mod ord; mod reader; mod str_ref; mod tag; mod writer; #[cfg(feature = "alloc")] mod bytes_owned; #[cfg(feature = "alloc")] mod document; #[cfg(feature = "alloc")] mod str_owned; 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::{IndefiniteLength, Length}, ord::{DerOrd, ValueOrd}, reader::{nested::NestedReader, slice::SliceReader, Reader}, tag::{Class, FixedTag, Tag, TagMode, TagNumber, Tagged}, writer::{slice::SliceWriter, Writer}, }; #[cfg(feature = "alloc")] pub use crate::{asn1::Any, document::Document}; #[cfg(feature = "bigint")] pub use crypto_bigint as bigint; #[cfg(feature = "derive")] pub use der_derive::{Choice, Enumerated, Sequence, ValueOrd}; #[cfg(feature = "flagset")] pub use flagset; #[cfg(feature = "oid")] pub use const_oid as oid; #[cfg(feature = "pem")] pub use { crate::{decode::DecodePem, encode::EncodePem, reader::pem::PemReader, writer::pem::PemWriter}, pem_rfc7468 as pem, }; #[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, bytes_ref::BytesRef, str_ref::StrRef}; #[cfg(feature = "alloc")] pub(crate) use crate::{bytes_owned::BytesOwned, str_owned::StrOwned}; der-0.7.7/src/ord.rs000064400000000000000000000044021046102023000123320ustar 00000000000000//! Ordering trait. use crate::{EncodeValue, Result, Tagged}; use core::{cmp::Ordering, marker::PhantomData}; /// DER ordering trait. /// /// Compares the ordering of two values based on their ASN.1 DER /// serializations. /// /// This is used by the DER encoding for `SET OF` in order to establish an /// ordering for the elements of sets. pub trait DerOrd { /// Return an [`Ordering`] between `self` and `other` when serialized as /// ASN.1 DER. fn der_cmp(&self, other: &Self) -> Result; } /// DER value ordering trait. /// /// Compares the ordering of the value portion of TLV-encoded DER productions. pub trait ValueOrd { /// Return an [`Ordering`] between value portion of TLV-encoded `self` and /// `other` when serialized as ASN.1 DER. fn value_cmp(&self, other: &Self) -> Result; } impl DerOrd for T where T: EncodeValue + ValueOrd + Tagged, { fn der_cmp(&self, other: &Self) -> Result { match self.header()?.der_cmp(&other.header()?)? { Ordering::Equal => self.value_cmp(other), ordering => Ok(ordering), } } } /// Marker trait for types whose `Ord` impl can be used as `ValueOrd`. /// /// This means the `Ord` impl will sort values in the same order as their DER /// encodings. pub trait OrdIsValueOrd: Ord {} impl ValueOrd for T where T: OrdIsValueOrd, { fn value_cmp(&self, other: &Self) -> Result { Ok(self.cmp(other)) } } /// Compare the order of two iterators using [`DerCmp`] on the values. pub(crate) fn iter_cmp<'a, I, T: 'a>(a: I, b: I) -> Result where I: Iterator + ExactSizeIterator, T: DerOrd, { let length_ord = a.len().cmp(&b.len()); for (value1, value2) in a.zip(b) { match value1.der_cmp(value2)? { Ordering::Equal => (), other => return Ok(other), } } Ok(length_ord) } /// Provide a no-op implementation for PhantomData impl ValueOrd for PhantomData { fn value_cmp(&self, _other: &Self) -> Result { Ok(Ordering::Equal) } } /// Provide a no-op implementation for PhantomData impl DerOrd for PhantomData { fn der_cmp(&self, _other: &Self) -> Result { Ok(Ordering::Equal) } } der-0.7.7/src/reader/nested.rs000064400000000000000000000052461046102023000143010ustar 00000000000000//! Reader type for consuming nested TLV records within a DER document. use crate::{reader::Reader, Error, ErrorKind, Header, Length, Result}; /// Reader type used by [`Reader::read_nested`]. pub struct NestedReader<'i, R> { /// Inner reader type. inner: &'i mut R, /// Nested input length. input_len: Length, /// Position within the nested input. position: Length, } impl<'i, 'r, R: Reader<'r>> NestedReader<'i, R> { /// Create a new nested reader which can read the given [`Length`]. pub(crate) fn new(inner: &'i mut R, len: Length) -> Result { if len <= inner.remaining_len() { Ok(Self { inner, input_len: len, position: Length::ZERO, }) } else { Err(ErrorKind::Incomplete { expected_len: (inner.offset() + len)?, actual_len: (inner.offset() + inner.remaining_len())?, } .at(inner.offset())) } } /// Move the position cursor the given length, returning an error if there /// isn't enough remaining data in the nested input. fn advance_position(&mut self, len: Length) -> Result<()> { let new_position = (self.position + len)?; if new_position <= self.input_len { self.position = new_position; Ok(()) } else { Err(ErrorKind::Incomplete { expected_len: (self.inner.offset() + len)?, actual_len: (self.inner.offset() + self.remaining_len())?, } .at(self.inner.offset())) } } } impl<'i, 'r, R: Reader<'r>> Reader<'r> for NestedReader<'i, R> { fn input_len(&self) -> Length { self.input_len } fn peek_byte(&self) -> Option { if self.is_finished() { None } else { self.inner.peek_byte() } } fn peek_header(&self) -> Result
{ if self.is_finished() { Err(Error::incomplete(self.offset())) } else { // TODO(tarcieri): handle peeking past nested length self.inner.peek_header() } } fn position(&self) -> Length { self.position } fn read_slice(&mut self, len: Length) -> Result<&'r [u8]> { self.advance_position(len)?; self.inner.read_slice(len) } fn error(&mut self, kind: ErrorKind) -> Error { self.inner.error(kind) } fn offset(&self) -> Length { self.inner.offset() } fn read_into<'o>(&mut self, out: &'o mut [u8]) -> Result<&'o [u8]> { self.advance_position(Length::try_from(out.len())?)?; self.inner.read_into(out) } } der-0.7.7/src/reader/pem.rs000064400000000000000000000127261046102023000136010ustar 00000000000000//! Streaming PEM reader. use super::Reader; use crate::{Decode, Error, ErrorKind, Header, Length, Result}; use core::cell::RefCell; #[allow(clippy::integer_arithmetic)] mod utils { use crate::{Error, Length, Result}; use pem_rfc7468::Decoder; #[derive(Clone)] pub(super) struct BufReader<'i> { /// Inner PEM decoder. decoder: Decoder<'i>, /// Remaining after base64 decoding remaining: usize, /// Read buffer buf: [u8; BufReader::CAPACITY], /// Position of the head in the buffer, pos: usize, /// Position of the tail in the buffer, cap: usize, } impl<'i> BufReader<'i> { const CAPACITY: usize = 256; pub fn new(pem: &'i [u8]) -> Result { let decoder = Decoder::new(pem)?; let remaining = decoder.remaining_len(); Ok(Self { decoder, remaining, buf: [0u8; 256], pos: 0, cap: 0, }) } pub fn remaining_len(&self) -> usize { self.decoder.remaining_len() + self.cap - self.pos } fn fill_buffer(&mut self) -> Result<()> { debug_assert!(self.pos <= self.cap); if self.is_empty() { self.pos = 0; self.cap = 0; } let end = (self.cap + self.remaining).min(Self::CAPACITY); let writable_slice = &mut self.buf[self.cap..end]; if writable_slice.is_empty() { return Ok(()); } let wrote = self.decoder.decode(writable_slice)?.len(); if wrote == 0 { return Err(Error::incomplete(Length::try_from(self.pos)?)); } self.cap += wrote; self.remaining -= wrote; debug_assert!(self.cap <= Self::CAPACITY); Ok(()) } /// Get the PEM label which will be used in the encapsulation boundaries /// for this document. pub fn type_label(&self) -> &'i str { self.decoder.type_label() } fn is_empty(&self) -> bool { self.pos == self.cap } fn as_slice(&self) -> &[u8] { &self.buf[self.pos..self.cap] } } impl<'i> BufReader<'i> { pub fn peek_byte(&self) -> Option { let s = self.as_slice(); s.first().copied() } pub fn copy_to_slice<'o>(&mut self, buf: &'o mut [u8]) -> Result<&'o [u8]> { let mut output_pos = 0; while output_pos < buf.len() { if self.is_empty() { self.fill_buffer()?; } let available = &self.buf[self.pos..self.cap]; let window_len = (buf.len() - output_pos).min(available.len()); let window = &mut buf[output_pos..output_pos + window_len]; window.copy_from_slice(&available[..window_len]); self.pos += window_len; output_pos += window_len; } // Don't leave the read buffer empty for peek_byte() if self.is_empty() && self.decoder.remaining_len() != 0 { self.fill_buffer()? } debug_assert_eq!(output_pos, buf.len()); Ok(buf) } } } /// `Reader` type which decodes PEM on-the-fly. #[cfg(feature = "pem")] #[derive(Clone)] pub struct PemReader<'i> { /// Inner PEM decoder wrapped in a BufReader. reader: RefCell>, /// Input length (in bytes after Base64 decoding). input_len: Length, /// Position in the input buffer (in bytes after Base64 decoding). position: Length, } #[cfg(feature = "pem")] impl<'i> PemReader<'i> { /// Create a new PEM reader which decodes data on-the-fly. /// /// Uses the default 64-character line wrapping. pub fn new(pem: &'i [u8]) -> Result { let reader = utils::BufReader::new(pem)?; let input_len = Length::try_from(reader.remaining_len())?; Ok(Self { reader: RefCell::new(reader), input_len, position: Length::ZERO, }) } /// Get the PEM label which will be used in the encapsulation boundaries /// for this document. pub fn type_label(&self) -> &'i str { self.reader.borrow().type_label() } } #[cfg(feature = "pem")] impl<'i> Reader<'i> for PemReader<'i> { fn input_len(&self) -> Length { self.input_len } fn peek_byte(&self) -> Option { if self.is_finished() { None } else { self.reader.borrow().peek_byte() } } fn peek_header(&self) -> Result
{ if self.is_finished() { Err(Error::incomplete(self.offset())) } else { Header::decode(&mut self.clone()) } } fn position(&self) -> Length { self.position } fn read_slice(&mut self, _len: Length) -> Result<&'i [u8]> { // Can't borrow from PEM because it requires decoding Err(ErrorKind::Reader.into()) } fn read_into<'o>(&mut self, buf: &'o mut [u8]) -> Result<&'o [u8]> { let bytes = self.reader.borrow_mut().copy_to_slice(buf)?; self.position = (self.position + bytes.len())?; debug_assert_eq!( self.position, (self.input_len - Length::try_from(self.reader.borrow().remaining_len())?)? ); Ok(bytes) } } der-0.7.7/src/reader/slice.rs000064400000000000000000000137611046102023000141170ustar 00000000000000//! Slice reader. use crate::{BytesRef, Decode, Error, ErrorKind, Header, Length, Reader, Result, Tag}; /// [`Reader`] which consumes an input byte slice. #[derive(Clone, Debug)] pub struct SliceReader<'a> { /// Byte slice being decoded. bytes: BytesRef<'a>, /// Did the decoding operation fail? failed: bool, /// Position within the decoded slice. position: Length, } impl<'a> SliceReader<'a> { /// Create a new slice reader for the given byte slice. pub fn new(bytes: &'a [u8]) -> Result { Ok(Self { bytes: BytesRef::new(bytes)?, failed: false, position: Length::ZERO, }) } /// Return an error with the given [`ErrorKind`], annotating it with /// context about where the error occurred. pub fn error(&mut self, kind: ErrorKind) -> Error { self.failed = true; kind.at(self.position) } /// Return an error for an invalid value with the given tag. pub fn value_error(&mut self, tag: Tag) -> Error { self.error(tag.value_error().kind()) } /// Did the decoding operation fail due to an error? pub fn is_failed(&self) -> bool { self.failed } /// Obtain the remaining bytes in this slice reader from the current cursor /// position. fn remaining(&self) -> Result<&'a [u8]> { if self.is_failed() { Err(ErrorKind::Failed.at(self.position)) } else { self.bytes .as_slice() .get(self.position.try_into()?..) .ok_or_else(|| Error::incomplete(self.input_len())) } } } impl<'a> Reader<'a> for SliceReader<'a> { fn input_len(&self) -> Length { self.bytes.len() } fn peek_byte(&self) -> Option { self.remaining() .ok() .and_then(|bytes| bytes.first().cloned()) } fn peek_header(&self) -> Result
{ Header::decode(&mut self.clone()) } fn position(&self) -> Length { self.position } fn read_slice(&mut self, len: Length) -> Result<&'a [u8]> { if self.is_failed() { return Err(self.error(ErrorKind::Failed)); } match self.remaining()?.get(..len.try_into()?) { Some(result) => { self.position = (self.position + len)?; Ok(result) } None => Err(self.error(ErrorKind::Incomplete { expected_len: (self.position + len)?, actual_len: self.input_len(), })), } } fn decode>(&mut self) -> Result { if self.is_failed() { return Err(self.error(ErrorKind::Failed)); } T::decode(self).map_err(|e| { self.failed = true; e.nested(self.position) }) } fn error(&mut self, kind: ErrorKind) -> Error { self.failed = true; kind.at(self.position) } fn finish(self, value: T) -> Result { if self.is_failed() { Err(ErrorKind::Failed.at(self.position)) } else if !self.is_finished() { Err(ErrorKind::TrailingData { decoded: self.position, remaining: self.remaining_len(), } .at(self.position)) } else { Ok(value) } } fn remaining_len(&self) -> Length { debug_assert!(self.position <= self.input_len()); self.input_len().saturating_sub(self.position) } } #[cfg(test)] mod tests { use super::SliceReader; use crate::{Decode, ErrorKind, Length, Reader, Tag}; use hex_literal::hex; // INTEGER: 42 const EXAMPLE_MSG: &[u8] = &hex!("02012A00"); #[test] fn empty_message() { let mut reader = SliceReader::new(&[]).unwrap(); let err = bool::decode(&mut reader).err().unwrap(); assert_eq!(Some(Length::ZERO), err.position()); match err.kind() { ErrorKind::Incomplete { expected_len, actual_len, } => { assert_eq!(actual_len, 0u8.into()); assert_eq!(expected_len, 1u8.into()); } other => panic!("unexpected error kind: {:?}", other), } } #[test] fn invalid_field_length() { const MSG_LEN: usize = 2; let mut reader = SliceReader::new(&EXAMPLE_MSG[..MSG_LEN]).unwrap(); let err = i8::decode(&mut reader).err().unwrap(); assert_eq!(Some(Length::from(2u8)), err.position()); match err.kind() { ErrorKind::Incomplete { expected_len, actual_len, } => { assert_eq!(actual_len, MSG_LEN.try_into().unwrap()); assert_eq!(expected_len, (MSG_LEN + 1).try_into().unwrap()); } other => panic!("unexpected error kind: {:?}", other), } } #[test] fn trailing_data() { let mut reader = SliceReader::new(EXAMPLE_MSG).unwrap(); let x = i8::decode(&mut reader).unwrap(); assert_eq!(42i8, x); let err = reader.finish(x).err().unwrap(); assert_eq!(Some(Length::from(3u8)), err.position()); assert_eq!( ErrorKind::TrailingData { decoded: 3u8.into(), remaining: 1u8.into() }, err.kind() ); } #[test] fn peek_tag() { let reader = SliceReader::new(EXAMPLE_MSG).unwrap(); assert_eq!(reader.position(), Length::ZERO); assert_eq!(reader.peek_tag().unwrap(), Tag::Integer); assert_eq!(reader.position(), Length::ZERO); // Position unchanged } #[test] fn peek_header() { let reader = SliceReader::new(EXAMPLE_MSG).unwrap(); assert_eq!(reader.position(), Length::ZERO); let header = reader.peek_header().unwrap(); assert_eq!(header.tag, Tag::Integer); assert_eq!(header.length, Length::ONE); assert_eq!(reader.position(), Length::ZERO); // Position unchanged } } der-0.7.7/src/reader.rs000064400000000000000000000127001046102023000130100ustar 00000000000000//! Reader trait. pub(crate) mod nested; #[cfg(feature = "pem")] pub(crate) mod pem; pub(crate) mod slice; pub(crate) use nested::NestedReader; use crate::{ asn1::ContextSpecific, Decode, DecodeValue, Encode, Error, ErrorKind, FixedTag, Header, Length, Result, Tag, TagMode, TagNumber, }; #[cfg(feature = "alloc")] use alloc::vec::Vec; /// Reader trait which reads DER-encoded input. pub trait Reader<'r>: Sized { /// Get the length of the input. fn input_len(&self) -> Length; /// Peek at the next byte of input without modifying the cursor. fn peek_byte(&self) -> Option; /// Peek forward in the input data, attempting to decode a [`Header`] from /// the data at the current position in the decoder. /// /// Does not modify the decoder's state. fn peek_header(&self) -> Result
; /// Get the position within the buffer. fn position(&self) -> Length; /// Attempt to read data borrowed directly from the input as a slice, /// updating the internal cursor position. /// /// # Returns /// - `Ok(slice)` on success /// - `Err(ErrorKind::Incomplete)` if there is not enough data /// - `Err(ErrorKind::Reader)` if the reader can't borrow from the input fn read_slice(&mut self, len: Length) -> Result<&'r [u8]>; /// Attempt to decode an ASN.1 `CONTEXT-SPECIFIC` field with the /// provided [`TagNumber`]. fn context_specific(&mut self, tag_number: TagNumber, tag_mode: TagMode) -> Result> where T: DecodeValue<'r> + FixedTag, { Ok(match tag_mode { TagMode::Explicit => ContextSpecific::::decode_explicit(self, tag_number)?, TagMode::Implicit => ContextSpecific::::decode_implicit(self, tag_number)?, } .map(|field| field.value)) } /// Decode a value which impls the [`Decode`] trait. fn decode>(&mut self) -> Result { T::decode(self).map_err(|e| e.nested(self.position())) } /// Return an error with the given [`ErrorKind`], annotating it with /// context about where the error occurred. fn error(&mut self, kind: ErrorKind) -> Error { kind.at(self.position()) } /// Finish decoding, returning the given value if there is no /// remaining data, or an error otherwise fn finish(self, value: T) -> Result { if !self.is_finished() { Err(ErrorKind::TrailingData { decoded: self.position(), remaining: self.remaining_len(), } .at(self.position())) } else { Ok(value) } } /// Have we read all of the input data? fn is_finished(&self) -> bool { self.remaining_len().is_zero() } /// Offset within the original input stream. /// /// This is used for error reporting, and doesn't need to be overridden /// by any reader implementations (except for the built-in `NestedReader`, /// which consumes nested input messages) fn offset(&self) -> Length { self.position() } /// Peek at the next byte in the decoder and attempt to decode it as a /// [`Tag`] value. /// /// Does not modify the decoder's state. fn peek_tag(&self) -> Result { match self.peek_byte() { Some(byte) => byte.try_into(), None => Err(Error::incomplete(self.input_len())), } } /// Read a single byte. fn read_byte(&mut self) -> Result { let mut buf = [0]; self.read_into(&mut buf)?; Ok(buf[0]) } /// Attempt to read input data, writing it into the provided buffer, and /// returning a slice on success. /// /// # Returns /// - `Ok(slice)` if there is sufficient data /// - `Err(ErrorKind::Incomplete)` if there is not enough data fn read_into<'o>(&mut self, buf: &'o mut [u8]) -> Result<&'o [u8]> { let input = self.read_slice(buf.len().try_into()?)?; buf.copy_from_slice(input); Ok(buf) } /// Read nested data of the given length. fn read_nested<'n, T, F>(&'n mut self, len: Length, f: F) -> Result where F: FnOnce(&mut NestedReader<'n, Self>) -> Result, { let mut reader = NestedReader::new(self, len)?; let ret = f(&mut reader)?; reader.finish(ret) } /// Read a byte vector of the given length. #[cfg(feature = "alloc")] fn read_vec(&mut self, len: Length) -> Result> { let mut bytes = vec![0u8; usize::try_from(len)?]; self.read_into(&mut bytes)?; Ok(bytes) } /// Get the number of bytes still remaining in the buffer. fn remaining_len(&self) -> Length { debug_assert!(self.position() <= self.input_len()); self.input_len().saturating_sub(self.position()) } /// Read an ASN.1 `SEQUENCE`, creating a nested [`Reader`] for the body and /// calling the provided closure with it. fn sequence<'n, F, T>(&'n mut self, f: F) -> Result where F: FnOnce(&mut NestedReader<'n, Self>) -> Result, { let header = Header::decode(self)?; header.tag.assert_eq(Tag::Sequence)?; self.read_nested(header.length, f) } /// Obtain a slice of bytes contain a complete TLV production suitable for parsing later. fn tlv_bytes(&mut self) -> Result<&'r [u8]> { let header = self.peek_header()?; let header_len = header.encoded_len()?; self.read_slice((header_len + header.length)?) } } der-0.7.7/src/referenced.rs000064400000000000000000000022561046102023000136550ustar 00000000000000//! A module for working with referenced data. /// A trait for borrowing data from an owned struct pub trait OwnedToRef { /// The resulting type referencing back to Self type Borrowed<'a> where Self: 'a; /// Creates a new object referencing back to the self for storage fn owned_to_ref(&self) -> Self::Borrowed<'_>; } /// A trait for cloning a referenced structure and getting owned objects /// /// This is the pendant to [`OwnedToRef`] pub trait RefToOwned<'a> { /// The resulting type after obtaining ownership. type Owned: OwnedToRef = Self> where Self: 'a; /// Creates a new object taking ownership of the data fn ref_to_owned(&self) -> Self::Owned; } impl OwnedToRef for Option where T: OwnedToRef, { type Borrowed<'a> = Option> where T: 'a; fn owned_to_ref(&self) -> Self::Borrowed<'_> { self.as_ref().map(|o| o.owned_to_ref()) } } impl<'a, T> RefToOwned<'a> for Option where T: RefToOwned<'a> + 'a, T::Owned: OwnedToRef, { type Owned = Option; fn ref_to_owned(&self) -> Self::Owned { self.as_ref().map(|o| o.ref_to_owned()) } } der-0.7.7/src/str_owned.rs000064400000000000000000000050721046102023000135560ustar 00000000000000//! Common handling for types backed by `String` with enforcement of a //! library-level length limitation i.e. `Length::max()`. use crate::{ referenced::OwnedToRef, BytesRef, DecodeValue, EncodeValue, Header, Length, Reader, Result, StrRef, Writer, }; use alloc::string::String; use core::str; /// String newtype which respects the [`Length::max`] limit. #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct StrOwned { /// Inner value pub(crate) inner: String, /// Precomputed `Length` (avoids possible panicking conversions) pub(crate) length: Length, } impl StrOwned { /// Create a new [`StrOwned`], ensuring that the byte representation of /// the provided `str` value is shorter than `Length::max()`. pub fn new(s: String) -> Result { let length = Length::try_from(s.as_bytes().len())?; Ok(Self { inner: s, length }) } /// Parse a [`String`] from UTF-8 encoded bytes. pub fn from_bytes(bytes: &[u8]) -> Result { Ok(Self { inner: String::from_utf8(bytes.to_vec())?, length: Length::try_from(bytes.len())?, }) } /// Borrow the inner `str` pub fn as_str(&self) -> &str { &self.inner } /// Borrow the inner byte slice pub fn as_bytes(&self) -> &[u8] { self.inner.as_bytes() } /// Get the [`Length`] of this [`StrOwned`] pub fn len(&self) -> Length { self.length } /// Is this [`StrOwned`] empty? pub fn is_empty(&self) -> bool { self.len() == Length::ZERO } } impl AsRef for StrOwned { fn as_ref(&self) -> &str { self.as_str() } } impl AsRef<[u8]> for StrOwned { fn as_ref(&self) -> &[u8] { self.as_bytes() } } impl<'a> DecodeValue<'a> for StrOwned { fn decode_value>(reader: &mut R, header: Header) -> Result { Self::from_bytes(BytesRef::decode_value(reader, header)?.as_slice()) } } impl EncodeValue for StrOwned { fn value_len(&self) -> Result { Ok(self.length) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { writer.write(self.as_ref()) } } impl From> for StrOwned { fn from(s: StrRef<'_>) -> StrOwned { Self { inner: String::from(s.inner), length: s.length, } } } impl OwnedToRef for StrOwned { type Borrowed<'a> = StrRef<'a>; fn owned_to_ref(&self) -> Self::Borrowed<'_> { StrRef { length: self.length, inner: self.inner.as_ref(), } } } der-0.7.7/src/str_ref.rs000064400000000000000000000045231046102023000132160ustar 00000000000000//! Common handling for types backed by `str` slices with enforcement of a //! library-level length limitation i.e. `Length::max()`. use crate::{BytesRef, DecodeValue, EncodeValue, Header, Length, Reader, Result, Writer}; use core::str; /// String slice newtype which respects the [`Length::max`] limit. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct StrRef<'a> { /// Inner value pub(crate) inner: &'a str, /// Precomputed `Length` (avoids possible panicking conversions) pub(crate) length: Length, } impl<'a> StrRef<'a> { /// Create a new [`StrRef`], ensuring that the byte representation of /// the provided `str` value is shorter than `Length::max()`. pub fn new(s: &'a str) -> Result { Ok(Self { inner: s, length: Length::try_from(s.as_bytes().len())?, }) } /// Parse a [`StrRef`] from UTF-8 encoded bytes. pub fn from_bytes(bytes: &'a [u8]) -> Result { Self::new(str::from_utf8(bytes)?) } /// Borrow the inner `str` pub fn as_str(&self) -> &'a str { self.inner } /// Borrow the inner byte slice pub fn as_bytes(&self) -> &'a [u8] { self.inner.as_bytes() } /// Get the [`Length`] of this [`StrRef`] pub fn len(self) -> Length { self.length } /// Is this [`StrRef`] empty? pub fn is_empty(self) -> bool { self.len() == Length::ZERO } } impl AsRef for StrRef<'_> { fn as_ref(&self) -> &str { self.as_str() } } impl AsRef<[u8]> for StrRef<'_> { fn as_ref(&self) -> &[u8] { self.as_bytes() } } impl<'a> DecodeValue<'a> for StrRef<'a> { fn decode_value>(reader: &mut R, header: Header) -> Result { Self::from_bytes(BytesRef::decode_value(reader, header)?.as_slice()) } } impl<'a> EncodeValue for StrRef<'a> { fn value_len(&self) -> Result { Ok(self.length) } fn encode_value(&self, writer: &mut impl Writer) -> Result<()> { writer.write(self.as_ref()) } } #[cfg(feature = "alloc")] mod allocating { use super::StrRef; use crate::{referenced::RefToOwned, StrOwned}; impl<'a> RefToOwned<'a> for StrRef<'a> { type Owned = StrOwned; fn ref_to_owned(&self) -> Self::Owned { StrOwned::from(*self) } } } der-0.7.7/src/tag/class.rs000064400000000000000000000032471046102023000134340ustar 00000000000000//! Class of an ASN.1 tag. use super::{TagNumber, CONSTRUCTED_FLAG}; use core::fmt; /// Class of an ASN.1 tag. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[repr(u8)] pub enum Class { /// `UNIVERSAL`: built-in types whose meaning is the same in all /// applications. Universal = 0b00000000, /// `APPLICATION`: types whose meaning is specific to an application, /// /// Types in two different applications may have the same /// application-specific tag and different meanings. Application = 0b01000000, /// `CONTEXT-SPECIFIC`: types whose meaning is specific to a given /// structured type. /// /// Context-specific tags are used to distinguish between component types /// with the same underlying tag within the context of a given structured /// type, and component types in two different structured types may have /// the same tag and different meanings. ContextSpecific = 0b10000000, /// `PRIVATE`: types whose meaning is specific to a given enterprise. Private = 0b11000000, } impl Class { /// Compute the identifier octet for a tag number of this class. #[allow(clippy::integer_arithmetic)] pub(super) fn octet(self, constructed: bool, number: TagNumber) -> u8 { self as u8 | number.value() | (u8::from(constructed) * CONSTRUCTED_FLAG) } } impl fmt::Display for Class { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(match self { Class::Universal => "UNIVERSAL", Class::Application => "APPLICATION", Class::ContextSpecific => "CONTEXT-SPECIFIC", Class::Private => "PRIVATE", }) } } der-0.7.7/src/tag/mode.rs000064400000000000000000000020011046102023000132360ustar 00000000000000//! Tag modes. use crate::{Error, ErrorKind, Result}; use core::{fmt, str::FromStr}; /// Tagging modes: `EXPLICIT` versus `IMPLICIT`. #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] pub enum TagMode { /// `EXPLICIT` tagging. /// /// Tag is added in addition to the inner tag of the type. #[default] Explicit, /// `IMPLICIT` tagging. /// /// Tag replaces the existing tag of the inner type. Implicit, } impl FromStr for TagMode { type Err = Error; fn from_str(s: &str) -> Result { match s { "EXPLICIT" | "explicit" => Ok(TagMode::Explicit), "IMPLICIT" | "implicit" => Ok(TagMode::Implicit), _ => Err(ErrorKind::TagModeUnknown.into()), } } } impl fmt::Display for TagMode { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { TagMode::Explicit => f.write_str("EXPLICIT"), TagMode::Implicit => f.write_str("IMPLICIT"), } } } der-0.7.7/src/tag/number.rs000064400000000000000000000113631046102023000136150ustar 00000000000000//! ASN.1 tag numbers use super::Tag; use crate::{Error, ErrorKind, Result}; use core::fmt; /// ASN.1 tag numbers (i.e. lower 5 bits of a [`Tag`]). /// /// From X.690 Section 8.1.2.2: /// /// > bits 5 to 1 shall encode the number of the tag as a binary integer with /// > bit 5 as the most significant bit. /// /// This library supports tag numbers ranging from zero to 30 (inclusive), /// which can be represented as a single identifier octet. /// /// Section 8.1.2.4 describes how to support multi-byte tag numbers, which are /// encoded by using a leading tag number of 31 (`0b11111`). This library /// deliberately does not support this: tag numbers greater than 30 are /// disallowed. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct TagNumber(pub(super) u8); impl TagNumber { /// Tag number `0` pub const N0: Self = Self(0); /// Tag number `1` pub const N1: Self = Self(1); /// Tag number `2` pub const N2: Self = Self(2); /// Tag number `3` pub const N3: Self = Self(3); /// Tag number `4` pub const N4: Self = Self(4); /// Tag number `5` pub const N5: Self = Self(5); /// Tag number `6` pub const N6: Self = Self(6); /// Tag number `7` pub const N7: Self = Self(7); /// Tag number `8` pub const N8: Self = Self(8); /// Tag number `9` pub const N9: Self = Self(9); /// Tag number `10` pub const N10: Self = Self(10); /// Tag number `11` pub const N11: Self = Self(11); /// Tag number `12` pub const N12: Self = Self(12); /// Tag number `13` pub const N13: Self = Self(13); /// Tag number `14` pub const N14: Self = Self(14); /// Tag number `15` pub const N15: Self = Self(15); /// Tag number `16` pub const N16: Self = Self(16); /// Tag number `17` pub const N17: Self = Self(17); /// Tag number `18` pub const N18: Self = Self(18); /// Tag number `19` pub const N19: Self = Self(19); /// Tag number `20` pub const N20: Self = Self(20); /// Tag number `21` pub const N21: Self = Self(21); /// Tag number `22` pub const N22: Self = Self(22); /// Tag number `23` pub const N23: Self = Self(23); /// Tag number `24` pub const N24: Self = Self(24); /// Tag number `25` pub const N25: Self = Self(25); /// Tag number `26` pub const N26: Self = Self(26); /// Tag number `27` pub const N27: Self = Self(27); /// Tag number `28` pub const N28: Self = Self(28); /// Tag number `29` pub const N29: Self = Self(29); /// Tag number `30` pub const N30: Self = Self(30); /// Mask value used to obtain the tag number from a tag octet. pub(super) const MASK: u8 = 0b11111; /// Maximum tag number supported (inclusive). const MAX: u8 = 30; /// Create a new tag number (const-friendly). /// /// Panics if the tag number is greater than `30`. /// For a fallible conversion, use [`TryFrom`] instead. pub const fn new(byte: u8) -> Self { #[allow(clippy::panic)] if byte > Self::MAX { panic!("tag number out of range"); } Self(byte) } /// Create an `APPLICATION` tag with this tag number. pub fn application(self, constructed: bool) -> Tag { Tag::Application { constructed, number: self, } } /// Create a `CONTEXT-SPECIFIC` tag with this tag number. pub fn context_specific(self, constructed: bool) -> Tag { Tag::ContextSpecific { constructed, number: self, } } /// Create a `PRIVATE` tag with this tag number. pub fn private(self, constructed: bool) -> Tag { Tag::Private { constructed, number: self, } } /// Get the inner value. pub fn value(self) -> u8 { self.0 } } impl TryFrom for TagNumber { type Error = Error; fn try_from(byte: u8) -> Result { match byte { 0..=Self::MAX => Ok(Self(byte)), _ => Err(ErrorKind::TagNumberInvalid.into()), } } } impl From for u8 { fn from(tag_number: TagNumber) -> u8 { tag_number.0 } } impl fmt::Display for TagNumber { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) } } // Implement by hand because the derive would create invalid values. // Use the constructor to create a valid value. #[cfg(feature = "arbitrary")] impl<'a> arbitrary::Arbitrary<'a> for TagNumber { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { Ok(Self::new(u.int_in_range(0..=Self::MAX)?)) } fn size_hint(depth: usize) -> (usize, Option) { u8::size_hint(depth) } } der-0.7.7/src/tag.rs000064400000000000000000000316331046102023000123270ustar 00000000000000//! ASN.1 tags. #![cfg_attr(feature = "arbitrary", allow(clippy::integer_arithmetic))] mod class; mod mode; mod number; pub use self::{class::Class, mode::TagMode, number::TagNumber}; use crate::{Decode, DerOrd, Encode, Error, ErrorKind, Length, Reader, Result, Writer}; use core::{cmp::Ordering, fmt}; /// Indicator bit for constructed form encoding (i.e. vs primitive form) const CONSTRUCTED_FLAG: u8 = 0b100000; /// Types which have a constant ASN.1 [`Tag`]. pub trait FixedTag { /// ASN.1 tag const TAG: Tag; } /// Types which have an ASN.1 [`Tag`]. pub trait Tagged { /// Get the ASN.1 tag that this type is encoded with. fn tag(&self) -> Tag; } /// Types which are [`FixedTag`] always have a known [`Tag`] type. impl Tagged for T { fn tag(&self) -> Tag { T::TAG } } /// ASN.1 tags. /// /// Tags are the leading identifier octet of the Tag-Length-Value encoding /// used by ASN.1 DER and identify the type of the subsequent value. /// /// They are described in X.690 Section 8.1.2: Identifier octets, and /// structured as follows: /// /// ```text /// | Class | P/C | Tag Number | /// ``` /// /// - Bits 8/7: [`Class`] /// - Bit 6: primitive (0) or constructed (1) /// - Bits 5-1: tag number #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)] #[non_exhaustive] pub enum Tag { /// `BOOLEAN` tag: `1`. Boolean, /// `INTEGER` tag: `2`. Integer, /// `BIT STRING` tag: `3`. BitString, /// `OCTET STRING` tag: `4`. OctetString, /// `NULL` tag: `5`. Null, /// `OBJECT IDENTIFIER` tag: `6`. ObjectIdentifier, /// `REAL` tag: `9`. Real, /// `ENUMERATED` tag: `10`. Enumerated, /// `UTF8String` tag: `12`. Utf8String, /// `SEQUENCE` tag: `16`. Sequence, /// `SET` and `SET OF` tag: `17`. Set, /// `NumericString` tag: `18`. NumericString, /// `PrintableString` tag: `19`. PrintableString, /// `TeletexString` tag: `20`. TeletexString, /// `VideotexString` tag: `21`. VideotexString, /// `IA5String` tag: `22`. Ia5String, /// `UTCTime` tag: `23`. UtcTime, /// `GeneralizedTime` tag: `24`. GeneralizedTime, /// `VisibleString` tag: `26`. VisibleString, /// `BMPString` tag: `30`. BmpString, /// Application tag. Application { /// Is this tag constructed? (vs primitive). constructed: bool, /// Tag number. number: TagNumber, }, /// Context-specific tag. ContextSpecific { /// Is this tag constructed? (vs primitive). constructed: bool, /// Tag number. number: TagNumber, }, /// Private tag number. Private { /// Is this tag constructed? (vs primitive). constructed: bool, /// Tag number. number: TagNumber, }, } impl Tag { /// Assert that this [`Tag`] matches the provided expected tag. /// /// On mismatch, returns an [`Error`] with [`ErrorKind::TagUnexpected`]. pub fn assert_eq(self, expected: Tag) -> Result { if self == expected { Ok(self) } else { Err(self.unexpected_error(Some(expected))) } } /// Get the [`Class`] that corresponds to this [`Tag`]. pub fn class(self) -> Class { match self { Tag::Application { .. } => Class::Application, Tag::ContextSpecific { .. } => Class::ContextSpecific, Tag::Private { .. } => Class::Private, _ => Class::Universal, } } /// Get the [`TagNumber`] (lower 6-bits) for this tag. pub fn number(self) -> TagNumber { TagNumber(self.octet() & TagNumber::MASK) } /// Does this tag represent a constructed (as opposed to primitive) field? pub fn is_constructed(self) -> bool { self.octet() & CONSTRUCTED_FLAG != 0 } /// Is this an application tag? pub fn is_application(self) -> bool { self.class() == Class::Application } /// Is this a context-specific tag? pub fn is_context_specific(self) -> bool { self.class() == Class::ContextSpecific } /// Is this a private tag? pub fn is_private(self) -> bool { self.class() == Class::Private } /// Is this a universal tag? pub fn is_universal(self) -> bool { self.class() == Class::Universal } /// Get the octet encoding for this [`Tag`]. pub fn octet(self) -> u8 { match self { Tag::Boolean => 0x01, Tag::Integer => 0x02, Tag::BitString => 0x03, Tag::OctetString => 0x04, Tag::Null => 0x05, Tag::ObjectIdentifier => 0x06, Tag::Real => 0x09, Tag::Enumerated => 0x0A, Tag::Utf8String => 0x0C, Tag::Sequence => 0x10 | CONSTRUCTED_FLAG, Tag::Set => 0x11 | CONSTRUCTED_FLAG, Tag::NumericString => 0x12, Tag::PrintableString => 0x13, Tag::TeletexString => 0x14, Tag::VideotexString => 0x15, Tag::Ia5String => 0x16, Tag::UtcTime => 0x17, Tag::GeneralizedTime => 0x18, Tag::VisibleString => 0x1A, Tag::BmpString => 0x1E, Tag::Application { constructed, number, } | Tag::ContextSpecific { constructed, number, } | Tag::Private { constructed, number, } => self.class().octet(constructed, number), } } /// Create an [`Error`] for an invalid [`Length`]. pub fn length_error(self) -> Error { ErrorKind::Length { tag: self }.into() } /// Create an [`Error`] for an non-canonical value with the ASN.1 type /// identified by this tag. pub fn non_canonical_error(self) -> Error { ErrorKind::Noncanonical { tag: self }.into() } /// Create an [`Error`] because the current tag was unexpected, with an /// optional expected tag. pub fn unexpected_error(self, expected: Option) -> Error { ErrorKind::TagUnexpected { expected, actual: self, } .into() } /// Create an [`Error`] for an invalid value with the ASN.1 type identified /// by this tag. pub fn value_error(self) -> Error { ErrorKind::Value { tag: self }.into() } } impl TryFrom for Tag { type Error = Error; fn try_from(byte: u8) -> Result { let constructed = byte & CONSTRUCTED_FLAG != 0; let number = TagNumber::try_from(byte & TagNumber::MASK)?; match byte { 0x01 => Ok(Tag::Boolean), 0x02 => Ok(Tag::Integer), 0x03 => Ok(Tag::BitString), 0x04 => Ok(Tag::OctetString), 0x05 => Ok(Tag::Null), 0x06 => Ok(Tag::ObjectIdentifier), 0x09 => Ok(Tag::Real), 0x0A => Ok(Tag::Enumerated), 0x0C => Ok(Tag::Utf8String), 0x12 => Ok(Tag::NumericString), 0x13 => Ok(Tag::PrintableString), 0x14 => Ok(Tag::TeletexString), 0x15 => Ok(Tag::VideotexString), 0x16 => Ok(Tag::Ia5String), 0x17 => Ok(Tag::UtcTime), 0x18 => Ok(Tag::GeneralizedTime), 0x1A => Ok(Tag::VisibleString), 0x1E => Ok(Tag::BmpString), 0x30 => Ok(Tag::Sequence), // constructed 0x31 => Ok(Tag::Set), // constructed 0x40..=0x7E => Ok(Tag::Application { constructed, number, }), 0x80..=0xBE => Ok(Tag::ContextSpecific { constructed, number, }), 0xC0..=0xFE => Ok(Tag::Private { constructed, number, }), _ => Err(ErrorKind::TagUnknown { byte }.into()), } } } impl From for u8 { fn from(tag: Tag) -> u8 { tag.octet() } } impl From<&Tag> for u8 { fn from(tag: &Tag) -> u8 { u8::from(*tag) } } impl<'a> Decode<'a> for Tag { fn decode>(reader: &mut R) -> Result { reader.read_byte().and_then(Self::try_from) } } impl Encode for Tag { fn encoded_len(&self) -> Result { Ok(Length::ONE) } fn encode(&self, writer: &mut impl Writer) -> Result<()> { writer.write_byte(self.into()) } } impl DerOrd for Tag { fn der_cmp(&self, other: &Self) -> Result { Ok(self.octet().cmp(&other.octet())) } } impl fmt::Display for Tag { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { const FIELD_TYPE: [&str; 2] = ["primitive", "constructed"]; match *self { Tag::Boolean => f.write_str("BOOLEAN"), Tag::Integer => f.write_str("INTEGER"), Tag::BitString => f.write_str("BIT STRING"), Tag::OctetString => f.write_str("OCTET STRING"), Tag::Null => f.write_str("NULL"), Tag::ObjectIdentifier => f.write_str("OBJECT IDENTIFIER"), Tag::Real => f.write_str("REAL"), Tag::Enumerated => f.write_str("ENUMERATED"), Tag::Utf8String => f.write_str("UTF8String"), Tag::Set => f.write_str("SET"), Tag::NumericString => f.write_str("NumericString"), Tag::PrintableString => f.write_str("PrintableString"), Tag::TeletexString => f.write_str("TeletexString"), Tag::VideotexString => f.write_str("VideotexString"), Tag::Ia5String => f.write_str("IA5String"), Tag::UtcTime => f.write_str("UTCTime"), Tag::GeneralizedTime => f.write_str("GeneralizedTime"), Tag::VisibleString => f.write_str("VisibleString"), Tag::BmpString => f.write_str("BMPString"), Tag::Sequence => f.write_str("SEQUENCE"), Tag::Application { constructed, number, } => write!( f, "APPLICATION [{}] ({})", number, FIELD_TYPE[usize::from(constructed)] ), Tag::ContextSpecific { constructed, number, } => write!( f, "CONTEXT-SPECIFIC [{}] ({})", number, FIELD_TYPE[usize::from(constructed)] ), Tag::Private { constructed, number, } => write!( f, "PRIVATE [{}] ({})", number, FIELD_TYPE[usize::from(constructed)] ), } } } impl fmt::Debug for Tag { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Tag(0x{:02x}: {})", u8::from(*self), self) } } #[cfg(test)] mod tests { use super::TagNumber; use super::{Class, Tag}; #[test] fn tag_class() { assert_eq!(Tag::Boolean.class(), Class::Universal); assert_eq!(Tag::Integer.class(), Class::Universal); assert_eq!(Tag::BitString.class(), Class::Universal); assert_eq!(Tag::OctetString.class(), Class::Universal); assert_eq!(Tag::Null.class(), Class::Universal); assert_eq!(Tag::ObjectIdentifier.class(), Class::Universal); assert_eq!(Tag::Real.class(), Class::Universal); assert_eq!(Tag::Enumerated.class(), Class::Universal); assert_eq!(Tag::Utf8String.class(), Class::Universal); assert_eq!(Tag::Set.class(), Class::Universal); assert_eq!(Tag::NumericString.class(), Class::Universal); assert_eq!(Tag::PrintableString.class(), Class::Universal); assert_eq!(Tag::TeletexString.class(), Class::Universal); assert_eq!(Tag::VideotexString.class(), Class::Universal); assert_eq!(Tag::Ia5String.class(), Class::Universal); assert_eq!(Tag::UtcTime.class(), Class::Universal); assert_eq!(Tag::GeneralizedTime.class(), Class::Universal); assert_eq!(Tag::Sequence.class(), Class::Universal); for num in 0..=30 { for &constructed in &[false, true] { let number = TagNumber::new(num); assert_eq!( Tag::Application { constructed, number } .class(), Class::Application ); assert_eq!( Tag::ContextSpecific { constructed, number } .class(), Class::ContextSpecific ); assert_eq!( Tag::Private { constructed, number } .class(), Class::Private ); } } } } der-0.7.7/src/writer/pem.rs000064400000000000000000000021571046102023000136500ustar 00000000000000//! Streaming PEM writer. use super::Writer; use crate::Result; use pem_rfc7468::{Encoder, LineEnding}; /// `Writer` type which outputs PEM-encoded data. pub struct PemWriter<'w>(Encoder<'static, 'w>); impl<'w> PemWriter<'w> { /// Create a new PEM writer which outputs into the provided buffer. /// /// Uses the default 64-character line wrapping. pub fn new( type_label: &'static str, line_ending: LineEnding, out: &'w mut [u8], ) -> Result { Ok(Self(Encoder::new(type_label, line_ending, out)?)) } /// Get the PEM label which will be used in the encapsulation boundaries /// for this document. pub fn type_label(&self) -> &'static str { self.0.type_label() } /// Finish encoding PEM, writing the post-encapsulation boundary. /// /// On success, returns the total number of bytes written to the output buffer. pub fn finish(self) -> Result { Ok(self.0.finish()?) } } impl Writer for PemWriter<'_> { fn write(&mut self, slice: &[u8]) -> Result<()> { self.0.encode(slice)?; Ok(()) } } der-0.7.7/src/writer/slice.rs000064400000000000000000000103201046102023000141550ustar 00000000000000//! Slice writer. use crate::{ asn1::*, Encode, EncodeValue, ErrorKind, Header, Length, Result, Tag, TagMode, TagNumber, Tagged, Writer, }; /// [`Writer`] which encodes DER into a mutable output byte slice. #[derive(Debug)] pub struct SliceWriter<'a> { /// Buffer into which DER-encoded message is written bytes: &'a mut [u8], /// Has the encoding operation failed? failed: bool, /// Total number of bytes written to buffer so far position: Length, } impl<'a> SliceWriter<'a> { /// Create a new encoder with the given byte slice as a backing buffer. pub fn new(bytes: &'a mut [u8]) -> Self { Self { bytes, failed: false, position: Length::ZERO, } } /// Encode a value which impls the [`Encode`] trait. pub fn encode(&mut self, encodable: &T) -> Result<()> { if self.is_failed() { self.error(ErrorKind::Failed)?; } encodable.encode(self).map_err(|e| { self.failed = true; e.nested(self.position) }) } /// Return an error with the given [`ErrorKind`], annotating it with /// context about where the error occurred. pub fn error(&mut self, kind: ErrorKind) -> Result { self.failed = true; Err(kind.at(self.position)) } /// Did the decoding operation fail due to an error? pub fn is_failed(&self) -> bool { self.failed } /// Finish encoding to the buffer, returning a slice containing the data /// written to the buffer. pub fn finish(self) -> Result<&'a [u8]> { let position = self.position; if self.is_failed() { return Err(ErrorKind::Failed.at(position)); } self.bytes .get(..usize::try_from(position)?) .ok_or_else(|| ErrorKind::Overlength.at(position)) } /// Encode a `CONTEXT-SPECIFIC` field with the provided tag number and mode. pub fn context_specific( &mut self, tag_number: TagNumber, tag_mode: TagMode, value: &T, ) -> Result<()> where T: EncodeValue + Tagged, { ContextSpecificRef { tag_number, tag_mode, value, } .encode(self) } /// Encode an ASN.1 `SEQUENCE` of the given length. /// /// Spawns a nested slice writer which is expected to be exactly the /// specified length upon completion. pub fn sequence(&mut self, length: Length, f: F) -> Result<()> where F: FnOnce(&mut SliceWriter<'_>) -> Result<()>, { Header::new(Tag::Sequence, length).and_then(|header| header.encode(self))?; let mut nested_encoder = SliceWriter::new(self.reserve(length)?); f(&mut nested_encoder)?; if nested_encoder.finish()?.len() == usize::try_from(length)? { Ok(()) } else { self.error(ErrorKind::Length { tag: Tag::Sequence }) } } /// Reserve a portion of the internal buffer, updating the internal cursor /// position and returning a mutable slice. fn reserve(&mut self, len: impl TryInto) -> Result<&mut [u8]> { if self.is_failed() { return Err(ErrorKind::Failed.at(self.position)); } let len = len .try_into() .or_else(|_| self.error(ErrorKind::Overflow))?; let end = (self.position + len).or_else(|e| self.error(e.kind()))?; let slice = self .bytes .get_mut(self.position.try_into()?..end.try_into()?) .ok_or_else(|| ErrorKind::Overlength.at(end))?; self.position = end; Ok(slice) } } impl<'a> Writer for SliceWriter<'a> { fn write(&mut self, slice: &[u8]) -> Result<()> { self.reserve(slice.len())?.copy_from_slice(slice); Ok(()) } } #[cfg(test)] mod tests { use super::SliceWriter; use crate::{Encode, ErrorKind, Length}; #[test] fn overlength_message() { let mut buffer = []; let mut writer = SliceWriter::new(&mut buffer); let err = false.encode(&mut writer).err().unwrap(); assert_eq!(err.kind(), ErrorKind::Overlength); assert_eq!(err.position(), Some(Length::ONE)); } } der-0.7.7/src/writer.rs000064400000000000000000000011541046102023000130630ustar 00000000000000//! Writer trait. #[cfg(feature = "pem")] pub(crate) mod pem; pub(crate) mod slice; use crate::Result; #[cfg(feature = "std")] use std::io; /// Writer trait which outputs encoded DER. pub trait Writer { /// Write the given DER-encoded bytes as output. fn write(&mut self, slice: &[u8]) -> Result<()>; /// Write a single byte. fn write_byte(&mut self, byte: u8) -> Result<()> { self.write(&[byte]) } } #[cfg(feature = "std")] impl Writer for W { fn write(&mut self, slice: &[u8]) -> Result<()> { ::write(self, slice)?; Ok(()) } } der-0.7.7/tests/datetime.proptest-regressions000064400000000000000000000011031046102023000175050ustar 00000000000000# Seeds for failure cases proptest has generated in the past. It is # automatically read and these particular cases re-run before any # novel cases are generated. # # It is recommended to check this file in to source control so that # everyone who runs the test benefits from these saved cases. cc 00dbea7e90761c16aa20e2fbf7ffad420da0c84d4ed4e6df123de03c9b4567e5 # shrinks to year = 1970, month = 1, day = 1, hour = 0, min = 60, sec = 0 cc 3b0bd01ef4cad6bea0a287f9cdcd56bad186125ec388d204f6afcd193ca12c39 # shrinks to year = 1970, month = 1, day = 1, hour = 0, min = 0, sec = 60 der-0.7.7/tests/datetime.rs000064400000000000000000000034311046102023000137160ustar 00000000000000//! Tests for the [`DateTime`] type. use der::{asn1::UtcTime, DateTime, Decode, Encode}; use proptest::prelude::*; proptest! { #[test] fn roundtrip_datetime( year in 1970u16..=9999, month in 1u8..=12, day in 1u8..=31, hour in 0u8..=23, min in 0u8..=59, sec in 0u8..=59, ) { let datetime1 = make_datetime(year, month, day, hour, min, sec); let datetime2 = DateTime::from_unix_duration(datetime1.unix_duration()).unwrap(); prop_assert_eq!(datetime1, datetime2); } #[test] fn roundtrip_utctime( year in 1970u16..=2049, month in 1u8..=12, day in 1u8..=31, hour in 0u8..=23, min in 0u8..=59, sec in 0u8..=59, ) { let datetime = make_datetime(year, month, day, hour, min, sec); let utc_time1 = UtcTime::try_from(datetime).unwrap(); let mut buf = [0u8; 128]; let mut encoder = der::SliceWriter::new(&mut buf); utc_time1.encode(&mut encoder).unwrap(); let der_bytes = encoder.finish().unwrap(); let utc_time2 = UtcTime::from_der(der_bytes).unwrap(); prop_assert_eq!(utc_time1, utc_time2); } } fn make_datetime(year: u16, month: u8, day: u8, hour: u8, min: u8, sec: u8) -> DateTime { let max_day = if month == 2 { let is_leap_year = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); if is_leap_year { 29 } else { 28 } } else { 30 }; let day = if day > max_day { max_day } else { day }; DateTime::new(year, month, day, hour, min, sec).unwrap_or_else(|e| { panic!( "invalid DateTime: {:02}-{:02}-{:02}T{:02}:{:02}:{:02}: {}", year, month, day, hour, min, sec, e ); }) } der-0.7.7/tests/derive.rs000064400000000000000000000406561046102023000134120ustar 00000000000000//! Tests for custom derive support. //! //! # Debugging with `cargo expand` //! //! To expand the Rust code generated by the proc macro when debugging //! issues related to these tests, run: //! //! $ cargo expand --test derive --all-features #![cfg(all(feature = "derive", feature = "alloc"))] /// Custom derive test cases for the `Choice` macro. mod choice { /// `Choice` with `EXPLICIT` tagging. mod explicit { use der::{ asn1::{GeneralizedTime, UtcTime}, Choice, Decode, Encode, SliceWriter, }; use hex_literal::hex; use std::time::Duration; /// Custom derive test case for the `Choice` macro. /// /// Based on `Time` as defined in RFC 5280: /// /// /// ```text /// Time ::= CHOICE { /// utcTime UTCTime, /// generalTime GeneralizedTime } /// ``` #[derive(Choice)] pub enum Time { #[asn1(type = "UTCTime")] UtcTime(UtcTime), #[asn1(type = "GeneralizedTime")] GeneralTime(GeneralizedTime), } impl Time { fn to_unix_duration(self) -> Duration { match self { Time::UtcTime(t) => t.to_unix_duration(), Time::GeneralTime(t) => t.to_unix_duration(), } } } const UTC_TIMESTAMP_DER: &[u8] = &hex!("17 0d 39 31 30 35 30 36 32 33 34 35 34 30 5a"); const GENERAL_TIMESTAMP_DER: &[u8] = &hex!("18 0f 31 39 39 31 30 35 30 36 32 33 34 35 34 30 5a"); #[test] fn decode() { let utc_time = Time::from_der(UTC_TIMESTAMP_DER).unwrap(); assert_eq!(utc_time.to_unix_duration().as_secs(), 673573540); let general_time = Time::from_der(GENERAL_TIMESTAMP_DER).unwrap(); assert_eq!(general_time.to_unix_duration().as_secs(), 673573540); } #[test] fn encode() { let mut buf = [0u8; 128]; let utc_time = Time::from_der(UTC_TIMESTAMP_DER).unwrap(); let mut encoder = SliceWriter::new(&mut buf); utc_time.encode(&mut encoder).unwrap(); assert_eq!(UTC_TIMESTAMP_DER, encoder.finish().unwrap()); let general_time = Time::from_der(GENERAL_TIMESTAMP_DER).unwrap(); let mut encoder = SliceWriter::new(&mut buf); general_time.encode(&mut encoder).unwrap(); assert_eq!(GENERAL_TIMESTAMP_DER, encoder.finish().unwrap()); } } /// `Choice` with `IMPLICIT` tagging. mod implicit { use der::{ asn1::{BitStringRef, GeneralizedTime}, Choice, Decode, Encode, SliceWriter, }; use hex_literal::hex; /// `Choice` macro test case for `IMPLICIT` tagging. #[derive(Choice, Debug, Eq, PartialEq)] #[asn1(tag_mode = "IMPLICIT")] pub enum ImplicitChoice<'a> { #[asn1(context_specific = "0", type = "BIT STRING")] BitString(BitStringRef<'a>), #[asn1(context_specific = "1", type = "GeneralizedTime")] Time(GeneralizedTime), #[asn1(context_specific = "2", type = "UTF8String")] Utf8String(String), } impl<'a> ImplicitChoice<'a> { pub fn bit_string(&self) -> Option> { match self { Self::BitString(bs) => Some(*bs), _ => None, } } pub fn time(&self) -> Option { match self { Self::Time(time) => Some(*time), _ => None, } } } const BITSTRING_DER: &[u8] = &hex!("80 04 00 01 02 03"); const TIME_DER: &[u8] = &hex!("81 0f 31 39 39 31 30 35 30 36 32 33 34 35 34 30 5a"); #[test] fn decode() { let cs_bit_string = ImplicitChoice::from_der(BITSTRING_DER).unwrap(); assert_eq!( cs_bit_string.bit_string().unwrap().as_bytes().unwrap(), &[1, 2, 3] ); let cs_time = ImplicitChoice::from_der(TIME_DER).unwrap(); assert_eq!( cs_time.time().unwrap().to_unix_duration().as_secs(), 673573540 ); } #[test] fn encode() { let mut buf = [0u8; 128]; let cs_bit_string = ImplicitChoice::from_der(BITSTRING_DER).unwrap(); let mut encoder = SliceWriter::new(&mut buf); cs_bit_string.encode(&mut encoder).unwrap(); assert_eq!(BITSTRING_DER, encoder.finish().unwrap()); let cs_time = ImplicitChoice::from_der(TIME_DER).unwrap(); let mut encoder = SliceWriter::new(&mut buf); cs_time.encode(&mut encoder).unwrap(); assert_eq!(TIME_DER, encoder.finish().unwrap()); } } } /// Custom derive test cases for the `Enumerated` macro. mod enumerated { use der::{Decode, Encode, Enumerated, SliceWriter}; use hex_literal::hex; /// X.509 `CRLReason`. #[derive(Enumerated, Copy, Clone, Debug, Eq, PartialEq)] #[repr(u32)] pub enum CrlReason { Unspecified = 0, KeyCompromise = 1, CaCompromise = 2, AffiliationChanged = 3, Superseded = 4, CessationOfOperation = 5, CertificateHold = 6, RemoveFromCrl = 8, PrivilegeWithdrawn = 9, AaCompromised = 10, } const UNSPECIFIED_DER: &[u8] = &hex!("0a 01 00"); const KEY_COMPROMISE_DER: &[u8] = &hex!("0a 01 01"); #[test] fn decode() { let unspecified = CrlReason::from_der(UNSPECIFIED_DER).unwrap(); assert_eq!(CrlReason::Unspecified, unspecified); let key_compromise = CrlReason::from_der(KEY_COMPROMISE_DER).unwrap(); assert_eq!(CrlReason::KeyCompromise, key_compromise); } #[test] fn encode() { let mut buf = [0u8; 128]; let mut encoder = SliceWriter::new(&mut buf); CrlReason::Unspecified.encode(&mut encoder).unwrap(); assert_eq!(UNSPECIFIED_DER, encoder.finish().unwrap()); let mut encoder = SliceWriter::new(&mut buf); CrlReason::KeyCompromise.encode(&mut encoder).unwrap(); assert_eq!(KEY_COMPROMISE_DER, encoder.finish().unwrap()); } } /// Custom derive test cases for the `Sequence` macro. #[cfg(feature = "oid")] mod sequence { use core::marker::PhantomData; use der::{ asn1::{AnyRef, ObjectIdentifier, SetOf}, Decode, Encode, Sequence, ValueOrd, }; use hex_literal::hex; pub fn default_false_example() -> bool { false } // Issuing distribution point extension as defined in [RFC 5280 Section 5.2.5] and as identified by the [`PKIX_PE_SUBJECTINFOACCESS`](constant.PKIX_PE_SUBJECTINFOACCESS.html) OID. // // ```text // IssuingDistributionPoint ::= SEQUENCE { // distributionPoint [0] DistributionPointName OPTIONAL, // onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE, // onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE, // onlySomeReasons [3] ReasonFlags OPTIONAL, // indirectCRL [4] BOOLEAN DEFAULT FALSE, // onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE } // -- at most one of onlyContainsUserCerts, onlyContainsCACerts, // -- and onlyContainsAttributeCerts may be set to TRUE. // ``` // // [RFC 5280 Section 5.2.5]: https://datatracker.ietf.org/doc/html/rfc5280#section-5.2.5 #[derive(Sequence)] pub struct IssuingDistributionPointExample { // Omit distributionPoint and only_some_reasons because corresponding structs are not // available here and are not germane to the example // distributionPoint [0] DistributionPointName OPTIONAL, //#[asn1(context_specific="0", optional="true", tag_mode="IMPLICIT")] //pub distribution_point: Option>, /// onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE, #[asn1( context_specific = "1", default = "default_false_example", tag_mode = "IMPLICIT" )] pub only_contains_user_certs: bool, /// onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE, #[asn1( context_specific = "2", default = "default_false_example", tag_mode = "IMPLICIT" )] pub only_contains_cacerts: bool, // onlySomeReasons [3] ReasonFlags OPTIONAL, //#[asn1(context_specific="3", optional="true", tag_mode="IMPLICIT")] //pub only_some_reasons: Option>, /// indirectCRL [4] BOOLEAN DEFAULT FALSE, #[asn1( context_specific = "4", default = "default_false_example", tag_mode = "IMPLICIT" )] pub indirect_crl: bool, /// onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE #[asn1( context_specific = "5", default = "default_false_example", tag_mode = "IMPLICIT" )] pub only_contains_attribute_certs: bool, /// Test handling of PhantomData. pub phantom: PhantomData<()>, } // Extension as defined in [RFC 5280 Section 4.1.2.9]. // // The ASN.1 definition for Extension objects is below. The extnValue type may be further parsed using a decoder corresponding to the extnID value. // // ```text // Extension ::= SEQUENCE { // extnID OBJECT IDENTIFIER, // critical BOOLEAN DEFAULT FALSE, // extnValue OCTET STRING // -- contains the DER encoding of an ASN.1 value // -- corresponding to the extension type identified // -- by extnID // } // ``` // // [RFC 5280 Section 4.1.2.9]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.9 #[derive(Clone, Debug, Eq, PartialEq, Sequence)] pub struct ExtensionExample<'a> { /// extnID OBJECT IDENTIFIER, pub extn_id: ObjectIdentifier, /// critical BOOLEAN DEFAULT FALSE, #[asn1(default = "default_false_example")] pub critical: bool, /// extnValue OCTET STRING #[asn1(type = "OCTET STRING")] pub extn_value: &'a [u8], } /// X.509 `AlgorithmIdentifier` #[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)] pub struct AlgorithmIdentifier<'a> { pub algorithm: ObjectIdentifier, pub parameters: Option>, } /// X.509 `SubjectPublicKeyInfo` (SPKI) #[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)] pub struct SubjectPublicKeyInfo<'a> { pub algorithm: AlgorithmIdentifier<'a>, #[asn1(type = "BIT STRING")] pub subject_public_key: &'a [u8], } /// PKCS#8v2 `OneAsymmetricKey` #[derive(Sequence)] pub struct OneAsymmetricKey<'a> { pub version: u8, pub private_key_algorithm: AlgorithmIdentifier<'a>, #[asn1(type = "OCTET STRING")] pub private_key: &'a [u8], #[asn1(context_specific = "0", extensible = "true", optional = "true")] pub attributes: Option, 1>>, #[asn1( context_specific = "1", extensible = "true", optional = "true", type = "BIT STRING" )] pub public_key: Option<&'a [u8]>, } /// X.509 extension // TODO(tarcieri): tests for code derived with the `default` attribute #[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)] pub struct Extension<'a> { extn_id: ObjectIdentifier, #[asn1(default = "critical_default")] critical: bool, #[asn1(type = "OCTET STRING")] extn_value: &'a [u8], } /// Default value of the `critical` bit fn critical_default() -> bool { false } const ID_EC_PUBLIC_KEY_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.2.1"); const PRIME256V1_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.3.1.7"); const ALGORITHM_IDENTIFIER_DER: &[u8] = &hex!("30 13 06 07 2a 86 48 ce 3d 02 01 06 08 2a 86 48 ce 3d 03 01 07"); #[derive(Sequence)] #[asn1(tag_mode = "IMPLICIT")] pub struct TypeCheckExpandedSequenceFieldAttributeCombinations<'a> { pub simple: bool, #[asn1(type = "BIT STRING")] pub typed: &'a [u8], #[asn1(context_specific = "0")] pub context_specific: bool, #[asn1(optional = "true")] pub optional: Option, #[asn1(default = "default_false_example")] pub default: bool, #[asn1(type = "BIT STRING", context_specific = "1")] pub typed_context_specific: &'a [u8], #[asn1(context_specific = "2", optional = "true")] pub context_specific_optional: Option, #[asn1(context_specific = "3", default = "default_false_example")] pub context_specific_default: bool, #[asn1(type = "BIT STRING", context_specific = "4", optional = "true")] pub typed_context_specific_optional: Option<&'a [u8]>, } #[test] fn idp_test() { let idp = IssuingDistributionPointExample::from_der(&hex!("30038101FF")).unwrap(); assert_eq!(idp.only_contains_user_certs, true); assert_eq!(idp.only_contains_cacerts, false); assert_eq!(idp.indirect_crl, false); assert_eq!(idp.only_contains_attribute_certs, false); let idp = IssuingDistributionPointExample::from_der(&hex!("30038201FF")).unwrap(); assert_eq!(idp.only_contains_user_certs, false); assert_eq!(idp.only_contains_cacerts, true); assert_eq!(idp.indirect_crl, false); assert_eq!(idp.only_contains_attribute_certs, false); let idp = IssuingDistributionPointExample::from_der(&hex!("30038401FF")).unwrap(); assert_eq!(idp.only_contains_user_certs, false); assert_eq!(idp.only_contains_cacerts, false); assert_eq!(idp.indirect_crl, true); assert_eq!(idp.only_contains_attribute_certs, false); let idp = IssuingDistributionPointExample::from_der(&hex!("30038501FF")).unwrap(); assert_eq!(idp.only_contains_user_certs, false); assert_eq!(idp.only_contains_cacerts, false); assert_eq!(idp.indirect_crl, false); assert_eq!(idp.only_contains_attribute_certs, true); } // demonstrates default field that is not context specific #[test] fn extension_test() { let ext1 = ExtensionExample::from_der(&hex!( "300F" // 0 15: SEQUENCE { "0603551D13" // 2 3: OBJECT IDENTIFIER basicConstraints (2 5 29 19) "0101FF" // 7 1: BOOLEAN TRUE "0405" // 10 5: OCTET STRING, encapsulates { "3003" // 12 3: SEQUENCE { "0101FF" // 14 1: BOOLEAN TRUE )) .unwrap(); assert_eq!(ext1.critical, true); let ext2 = ExtensionExample::from_der(&hex!( "301F" // 0 31: SEQUENCE { "0603551D23" // 2 3: OBJECT IDENTIFIER authorityKeyIdentifier (2 5 29 35) "0418" // 7 24: OCTET STRING, encapsulates { "3016" // 9 22: SEQUENCE { "8014E47D5FD15C9586082C05AEBE75B665A7D95DA866" // 11 20: [0] E4 7D 5F D1 5C 95 86 08 2C 05 AE BE 75 B6 65 A7 D9 5D A8 66 )) .unwrap(); assert_eq!(ext2.critical, false); } #[test] fn decode() { let algorithm_identifier = AlgorithmIdentifier::from_der(ALGORITHM_IDENTIFIER_DER).unwrap(); assert_eq!(ID_EC_PUBLIC_KEY_OID, algorithm_identifier.algorithm); assert_eq!( PRIME256V1_OID, ObjectIdentifier::try_from(algorithm_identifier.parameters.unwrap()).unwrap() ); } #[test] fn encode() { let parameters_oid = PRIME256V1_OID; let algorithm_identifier = AlgorithmIdentifier { algorithm: ID_EC_PUBLIC_KEY_OID, parameters: Some(AnyRef::from(¶meters_oid)), }; assert_eq!( ALGORITHM_IDENTIFIER_DER, algorithm_identifier.to_der().unwrap() ); } } der-0.7.7/tests/examples/spki.der000064400000000000000000000000541046102023000150320ustar 000000000000000*0+ep!M)?):^{&{UPS der-0.7.7/tests/examples/spki.pem000064400000000000000000000001611046102023000150400ustar 00000000000000-----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEATSkWfz8ZEqb3rfopOgUaFcBexnuPFyZ7HFVQ3OhTvQ0= -----END PUBLIC KEY----- der-0.7.7/tests/pem.rs000064400000000000000000000034601046102023000127050ustar 00000000000000//! PEM decoding and encoding tests. #![cfg(all(feature = "derive", feature = "oid", feature = "pem"))] use der::{ asn1::{BitString, ObjectIdentifier}, pem::{LineEnding, PemLabel}, Decode, DecodePem, EncodePem, Sequence, }; /// Example SPKI document encoded as DER. const SPKI_DER: &[u8] = include_bytes!("examples/spki.der"); /// Example SPKI document encoded as PEM. const SPKI_PEM: &str = include_str!("examples/spki.pem"); /// X.509 `AlgorithmIdentifier` #[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence)] pub struct AlgorithmIdentifier { pub algorithm: ObjectIdentifier, // pub parameters: ... (not used in spki.pem) } /// X.509 `SubjectPublicKeyInfo` (SPKI) in borrowed form #[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence)] pub struct SpkiBorrowed<'a> { pub algorithm: AlgorithmIdentifier, #[asn1(type = "BIT STRING")] pub subject_public_key: &'a [u8], } impl PemLabel for SpkiBorrowed<'_> { const PEM_LABEL: &'static str = "PUBLIC KEY"; } /// X.509 `SubjectPublicKeyInfo` (SPKI) in owned form #[derive(Clone, Debug, Eq, PartialEq, Sequence)] pub struct SpkiOwned { pub algorithm: AlgorithmIdentifier, pub subject_public_key: BitString, } impl PemLabel for SpkiOwned { const PEM_LABEL: &'static str = "PUBLIC KEY"; } #[test] fn from_pem() { // Decode PEM to owned form. let pem_spki = SpkiOwned::from_pem(SPKI_PEM).unwrap(); // Decode DER to borrowed form. let der_spki = SpkiBorrowed::from_der(SPKI_DER).unwrap(); assert_eq!(pem_spki.algorithm, der_spki.algorithm); assert_eq!( pem_spki.subject_public_key.raw_bytes(), der_spki.subject_public_key ); } #[test] fn to_pem() { let spki = SpkiBorrowed::from_der(SPKI_DER).unwrap(); let pem = spki.to_pem(LineEnding::LF).unwrap(); assert_eq!(&pem, SPKI_PEM); } der-0.7.7/tests/set_of.rs000064400000000000000000000042351046102023000134040ustar 00000000000000//! `SetOf` tests. #![cfg(feature = "alloc")] use der::{asn1::SetOfVec, DerOrd}; use proptest::{prelude::*, string::*}; use std::collections::BTreeSet; proptest! { #[test] fn sort_equiv(bytes in bytes_regex(".{0,64}").unwrap()) { let mut uniq = BTreeSet::new(); // Ensure there are no duplicates if bytes.iter().copied().all(move |x| uniq.insert(x)) { let mut expected = bytes.clone(); expected.sort_by(|a, b| a.der_cmp(b).unwrap()); let set = SetOfVec::try_from(bytes).unwrap(); prop_assert_eq!(expected.as_slice(), set.as_slice()); } } } /// Set ordering tests. #[cfg(all(feature = "derive", feature = "oid"))] mod ordering { use der::{ asn1::{AnyRef, ObjectIdentifier, SetOf, SetOfVec}, Decode, Sequence, ValueOrd, }; use hex_literal::hex; /// X.501 `AttributeTypeAndValue` #[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)] pub struct AttributeTypeAndValue<'a> { pub oid: ObjectIdentifier, pub value: AnyRef<'a>, } const OUT_OF_ORDER_RDN_EXAMPLE: &[u8] = &hex!("311F301106035504030C0A4A4F484E20534D495448300A060355040A0C03313233"); /// For compatibility reasons, we allow non-canonical DER with out-of-order /// sets in order to match the behavior of other implementations. #[test] fn allow_out_of_order_setof() { assert!(SetOf::, 2>::from_der(OUT_OF_ORDER_RDN_EXAMPLE).is_ok()); } /// Same as above, with `SetOfVec` instead of `SetOf`. #[test] fn allow_out_of_order_setofvec() { assert!(SetOfVec::>::from_der(OUT_OF_ORDER_RDN_EXAMPLE).is_ok()); } /// Test to ensure ordering is handled correctly. #[test] fn ordering_regression() { let der_bytes = hex!("3139301906035504030C12546573742055736572393031353734333830301C060A0992268993F22C640101130E3437303031303030303134373333"); let set = SetOf::, 3>::from_der(&der_bytes).unwrap(); let attr1 = set.get(0).unwrap(); assert_eq!(ObjectIdentifier::new("2.5.4.3").unwrap(), attr1.oid); } }