diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:41:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:41:41 +0000 |
commit | 10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 (patch) | |
tree | bdffd5d80c26cf4a7a518281a204be1ace85b4c1 /vendor/spki | |
parent | Releasing progress-linux version 1.70.0+dfsg1-9~progress7.99u1. (diff) | |
download | rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.tar.xz rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.zip |
Merging upstream version 1.70.0+dfsg2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/spki')
-rw-r--r-- | vendor/spki/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | vendor/spki/CHANGELOG.md | 103 | ||||
-rw-r--r-- | vendor/spki/Cargo.toml | 77 | ||||
-rw-r--r-- | vendor/spki/LICENSE-APACHE | 201 | ||||
-rw-r--r-- | vendor/spki/LICENSE-MIT | 25 | ||||
-rw-r--r-- | vendor/spki/README.md | 56 | ||||
-rw-r--r-- | vendor/spki/src/algorithm.rs | 132 | ||||
-rw-r--r-- | vendor/spki/src/error.rs | 68 | ||||
-rw-r--r-- | vendor/spki/src/fingerprint.rs | 43 | ||||
-rw-r--r-- | vendor/spki/src/lib.rs | 55 | ||||
-rw-r--r-- | vendor/spki/src/spki.rs | 141 | ||||
-rw-r--r-- | vendor/spki/src/traits.rs | 94 | ||||
-rw-r--r-- | vendor/spki/tests/examples/ed25519-pub.der | bin | 0 -> 44 bytes | |||
-rw-r--r-- | vendor/spki/tests/examples/ed25519-pub.pem | 3 | ||||
-rw-r--r-- | vendor/spki/tests/examples/p256-pub.der | bin | 0 -> 91 bytes | |||
-rw-r--r-- | vendor/spki/tests/examples/p256-pub.pem | 4 | ||||
-rw-r--r-- | vendor/spki/tests/examples/rsa2048-pub.der | bin | 0 -> 294 bytes | |||
-rw-r--r-- | vendor/spki/tests/examples/rsa2048-pub.pem | 9 | ||||
-rw-r--r-- | vendor/spki/tests/spki.rs | 156 | ||||
-rw-r--r-- | vendor/spki/tests/traits.rs | 108 |
20 files changed, 1276 insertions, 0 deletions
diff --git a/vendor/spki/.cargo-checksum.json b/vendor/spki/.cargo-checksum.json new file mode 100644 index 000000000..b9ffbdae9 --- /dev/null +++ b/vendor/spki/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"f1d990e95d496dbb2c4dee0b486ef44df8402768f461c5572f3aa8467d4831e2","Cargo.toml":"e6432d40fb16fb01a54e1fd8a29fc07573a36dd64d7140ad4fe9d9a6410c1e1c","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"4a883ecc3bb1010faed542bf63d53e530fea5e5e12cf676aed588784298ba929","README.md":"e2fee03d66193bb5a5c82137f879cd5011f7f9d21d157765f87d614b4506a4cd","src/algorithm.rs":"9bc057fd99b8511b5356fdcf9834d6d5c892fa0d5a30020fdb4c7cf97f095f33","src/error.rs":"ce99da5f369ae830bbac6a958ee0e93c8045df5ca7b7ea306e55bb3209c1f81f","src/fingerprint.rs":"bdfc1c1194d06bdb8b74ab7326f956e140968c1737cb407d0de8f29eaaf4bd8b","src/lib.rs":"f70bb8b6199790125ee0e84a0c3614cb42a76cc6f735c47648c9ffc197aeab29","src/spki.rs":"05e163cd33b6be54fa7dea9a2f462f1a73e06fc4eccfd3bd36238c775b57f81d","src/traits.rs":"740ac98d5106cceff14aea6e2b81c3724e240107339e36e5a19075b0e6590f87","tests/examples/ed25519-pub.der":"55dd4c74b0e48534e2f4e173ceceb50df8f27a7ac2aa8991cc7ae914e030bced","tests/examples/ed25519-pub.pem":"36d717203cbca1812f05f30e0415251c928b659882092e653221a028571c6853","tests/examples/p256-pub.der":"b9968d56ed8d6aa3fb43b15fa01e355d7a3a0203b1408b3fd2733637c4d1642c","tests/examples/p256-pub.pem":"d1ff198dc495da63f5f909db0254d6e49cff519487fcb26d055a762fc3ca47a1","tests/examples/rsa2048-pub.der":"efeda9bfead9fd0594f6a5cf6fdf6c163116a3b1fad6d73cea05295b68fd1794","tests/examples/rsa2048-pub.pem":"078c3983093e86784590a2a454547acad1d50992419334be697e442e954f02f8","tests/spki.rs":"f6e4baed201276901f13b9ce1b342e4a74b557f2bd553500398a70256bee5e75","tests/traits.rs":"8c6b79b648549e1f06612c80469ca0c73e200798eb314ca4b8c5a1507f23c585"},"package":"67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b"}
\ No newline at end of file diff --git a/vendor/spki/CHANGELOG.md b/vendor/spki/CHANGELOG.md new file mode 100644 index 000000000..ce0f5b7db --- /dev/null +++ b/vendor/spki/CHANGELOG.md @@ -0,0 +1,103 @@ +# 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.6.0 (2022-05-08) +### Added +- `AlgorithmIdentifier::oids()` helper function ([#443]) +- Impl `PartialOrd` for `AlgorithmIdentifier` ([#476]) +- Impl `DecodeValue` for `AlgorithmIdentifier` ([#449]) +- Impl `ValueOrd` for `SubjectPublicKeyInfo` ([#522]) + +### Changed +- Replace `PublicKeyDocument` with `der` crate's `Document` type ([#571]) +- Streaming fingerprint builder ([#616]) +- Bump `der` crate dependency to v0.6 ([#653]) + +### Removed +- `PublicKeyDocument` ([#571]) + +[#443]: https://github.com/RustCrypto/formats/pull/443 +[#449]: https://github.com/RustCrypto/formats/pull/449 +[#476]: https://github.com/RustCrypto/formats/pull/476 +[#522]: https://github.com/RustCrypto/formats/pull/522 +[#571]: https://github.com/RustCrypto/formats/pull/571 +[#616]: https://github.com/RustCrypto/formats/pull/616 +[#653]: https://github.com/RustCrypto/formats/pull/653 + +## 0.5.4 (2022-01-05) +### Added +- `Error::KeyMalformed` variant ([#318]) + +[#318]: https://github.com/RustCrypto/formats/pull/318 + +## 0.5.3 (2021-12-19) +### Added +- Impl `ValueOrd` for `AlgorithmIdentifier` ([#289]) + +[#289]: https://github.com/RustCrypto/formats/pull/289 + +## 0.5.2 (2021-11-17) +### Changed +- Relax `base64ct` version requirement to `^1` ([#239]) + +[#239]: https://github.com/RustCrypto/formats/pull/239 + +## 0.5.1 (2021-11-17) +### Changed +- Replace `from_spki` with `TryFrom` ([#231]) + +[#231]: https://github.com/RustCrypto/formats/pull/231 + +## 0.5.0 (2021-11-15) [YANKED] +### Added +- SPKI fingerprint support ([#36]) +- `PublicKeyDocument` type originally from `pkcs8` crate ([#118]) +- `Error` type ([#143]) + +### Changed +- Rename `From/ToPublicKey` => `DecodePublicKey`/`EncodePublicKey` ([#119]) +- Use `der::Document` to impl `PublicKeyDocument` ([#134]) +- Rust 2021 edition upgrade; MSRV 1.56 ([#136]) +- Bump `der` dependency to v0.5 ([#222]) + +[#36]: https://github.com/RustCrypto/formats/pull/36 +[#118]: https://github.com/RustCrypto/formats/pull/118 +[#119]: https://github.com/RustCrypto/formats/pull/119 +[#134]: https://github.com/RustCrypto/formats/pull/134 +[#136]: https://github.com/RustCrypto/formats/pull/136 +[#143]: https://github.com/RustCrypto/formats/pull/143 +[#222]: https://github.com/RustCrypto/formats/pull/222 + +## 0.4.1 (2021-09-14) +### Changed +- Moved to `formats` repo ([#2]) + +[#2]: https://github.com/RustCrypto/formats/pull/2 + +## 0.4.0 (2021-06-07) +### Added +- `AlgorithmIdentifier::assert_oids` + +### Changed +- Bump `der` to v0.4 + +## 0.3.0 (2021-03-22) +### Changed +- Bump `der` to v0.3 + +### Removed +- `AlgorithmParameters` enum + +## 0.2.1 (2021-02-22) +### Added +- Impl `Choice` for `AlgorithmParameters` + +## 0.2.0 (2021-02-18) +### Changed +- Return `Result` from `AlgorithmIdentifier::params_*` + +## 0.1.0 (2021-02-16) +- Initial release diff --git a/vendor/spki/Cargo.toml b/vendor/spki/Cargo.toml new file mode 100644 index 000000000..13205cb43 --- /dev/null +++ b/vendor/spki/Cargo.toml @@ -0,0 +1,77 @@ +# 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.57" +name = "spki" +version = "0.6.0" +authors = ["RustCrypto Developers"] +description = """ +X.509 Subject Public Key Info (RFC5280) describing public keys as well as their +associated AlgorithmIdentifiers (i.e. OIDs) +""" +readme = "README.md" +keywords = [ + "crypto", + "x509", +] +categories = [ + "cryptography", + "data-structures", + "encoding", + "no-std", +] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/RustCrypto/formats/tree/master/spki" +resolver = "2" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[dependencies.base64ct] +version = "1" +optional = true +default-features = false + +[dependencies.der] +version = "0.6" +features = ["oid"] + +[dependencies.sha2] +version = "0.10" +optional = true +default-features = false + +[dev-dependencies.hex-literal] +version = "0.3" + +[dev-dependencies.tempfile] +version = "3" + +[features] +alloc = [ + "base64ct/alloc", + "der/alloc", +] +fingerprint = ["sha2"] +pem = [ + "alloc", + "der/pem", +] +std = [ + "der/std", + "alloc", +] diff --git a/vendor/spki/LICENSE-APACHE b/vendor/spki/LICENSE-APACHE new file mode 100644 index 000000000..78173fa2e --- /dev/null +++ b/vendor/spki/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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. diff --git a/vendor/spki/LICENSE-MIT b/vendor/spki/LICENSE-MIT new file mode 100644 index 000000000..68ddaa3c9 --- /dev/null +++ b/vendor/spki/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2021-2022 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. diff --git a/vendor/spki/README.md b/vendor/spki/README.md new file mode 100644 index 000000000..caa01cc8c --- /dev/null +++ b/vendor/spki/README.md @@ -0,0 +1,56 @@ +# [RustCrypto]: X.509 Subject Public Key Info (SPKI) + +[![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] + +[X.509] Subject Public Key Info types describing public keys as well as their +associated AlgorithmIdentifiers (i.e. OIDs). + +Specified in [RFC 5280 § 4.1]. + +[Documentation][docs-link] + +## Minimum Supported Rust Version + +This crate requires **Rust 1.57** 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/spki +[crate-link]: https://crates.io/crates/spki +[docs-image]: https://docs.rs/spki/badge.svg +[docs-link]: https://docs.rs/spki/ +[build-image]: https://github.com/RustCrypto/formats/actions/workflows/spki.yml/badge.svg +[build-link]: https://github.com/RustCrypto/formats/actions/workflows/spki.yml +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.57+-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 +[X.509]: https://en.wikipedia.org/wiki/X.509 +[RFC 5280 § 4.1]: https://tools.ietf.org/html/rfc5280#section-4.1 diff --git a/vendor/spki/src/algorithm.rs b/vendor/spki/src/algorithm.rs new file mode 100644 index 000000000..2a8b6c7f9 --- /dev/null +++ b/vendor/spki/src/algorithm.rs @@ -0,0 +1,132 @@ +//! X.509 `AlgorithmIdentifier` + +use crate::{Error, Result}; +use core::cmp::Ordering; +use der::asn1::{AnyRef, ObjectIdentifier}; +use der::{Decode, DecodeValue, DerOrd, Encode, Header, Reader, Sequence, ValueOrd}; + +/// X.509 `AlgorithmIdentifier` as defined in [RFC 5280 Section 4.1.1.2]. +/// +/// ```text +/// AlgorithmIdentifier ::= SEQUENCE { +/// algorithm OBJECT IDENTIFIER, +/// parameters ANY DEFINED BY algorithm OPTIONAL } +/// ``` +/// +/// [RFC 5280 Section 4.1.1.2]: https://tools.ietf.org/html/rfc5280#section-4.1.1.2 +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +pub struct AlgorithmIdentifier<'a> { + /// Algorithm OID, i.e. the `algorithm` field in the `AlgorithmIdentifier` + /// ASN.1 schema. + pub oid: ObjectIdentifier, + + /// Algorithm `parameters`. + pub parameters: Option<AnyRef<'a>>, +} + +impl<'a> AlgorithmIdentifier<'a> { + /// Assert the `algorithm` OID is an expected value. + pub fn assert_algorithm_oid(&self, expected_oid: ObjectIdentifier) -> Result<ObjectIdentifier> { + if self.oid == expected_oid { + Ok(expected_oid) + } else { + Err(Error::OidUnknown { oid: expected_oid }) + } + } + + /// Assert `parameters` is an OID and has the expected value. + pub fn assert_parameters_oid( + &self, + expected_oid: ObjectIdentifier, + ) -> Result<ObjectIdentifier> { + let actual_oid = self.parameters_oid()?; + + if actual_oid == expected_oid { + Ok(actual_oid) + } else { + Err(Error::OidUnknown { oid: expected_oid }) + } + } + + /// Assert the values of the `algorithm` and `parameters` OIDs. + pub fn assert_oids( + &self, + algorithm: ObjectIdentifier, + parameters: ObjectIdentifier, + ) -> Result<()> { + self.assert_algorithm_oid(algorithm)?; + self.assert_parameters_oid(parameters)?; + Ok(()) + } + + /// Get the `parameters` field as an [`AnyRef`]. + /// + /// Returns an error if `parameters` are `None`. + pub fn parameters_any(&self) -> Result<AnyRef<'a>> { + self.parameters.ok_or(Error::AlgorithmParametersMissing) + } + + /// Get the `parameters` field as an [`ObjectIdentifier`]. + /// + /// Returns an error if it is absent or not an OID. + pub fn parameters_oid(&self) -> Result<ObjectIdentifier> { + Ok(ObjectIdentifier::try_from(self.parameters_any()?)?) + } + + /// Convert to a pair of [`ObjectIdentifier`]s. + /// + /// This method is helpful for decomposing in match statements. Note in + /// particular that `NULL` parameters are treated the same as missing + /// parameters. + /// + /// Returns an error if parameters are present but not an OID. + pub fn oids(&self) -> der::Result<(ObjectIdentifier, Option<ObjectIdentifier>)> { + Ok(( + self.oid, + match self.parameters { + None => None, + Some(p) => match p { + AnyRef::NULL => None, + _ => Some(p.oid()?), + }, + }, + )) + } +} + +impl<'a> DecodeValue<'a> for AlgorithmIdentifier<'a> { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> { + reader.read_nested(header.length, |reader| { + Ok(Self { + oid: reader.decode()?, + parameters: reader.decode()?, + }) + }) + } +} + +impl<'a> Sequence<'a> for AlgorithmIdentifier<'a> { + fn fields<F, T>(&self, f: F) -> der::Result<T> + where + F: FnOnce(&[&dyn Encode]) -> der::Result<T>, + { + f(&[&self.oid, &self.parameters]) + } +} + +impl<'a> TryFrom<&'a [u8]> for AlgorithmIdentifier<'a> { + type Error = Error; + + fn try_from(bytes: &'a [u8]) -> Result<Self> { + Ok(Self::from_der(bytes)?) + } +} + +impl ValueOrd for AlgorithmIdentifier<'_> { + fn value_cmp(&self, other: &Self) -> der::Result<Ordering> { + match self.oid.der_cmp(&other.oid)? { + Ordering::Equal => self.parameters.der_cmp(&other.parameters), + other => Ok(other), + } + } +} diff --git a/vendor/spki/src/error.rs b/vendor/spki/src/error.rs new file mode 100644 index 000000000..9d05990f3 --- /dev/null +++ b/vendor/spki/src/error.rs @@ -0,0 +1,68 @@ +//! Error types + +use core::fmt; +use der::asn1::ObjectIdentifier; + +/// Result type with `spki` crate's [`Error`] type. +pub type Result<T> = core::result::Result<T, Error>; + +#[cfg(feature = "pem")] +use der::pem; + +/// Error type +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[non_exhaustive] +pub enum Error { + /// Algorithm parameters are missing. + AlgorithmParametersMissing, + + /// ASN.1 DER-related errors. + Asn1(der::Error), + + /// Malformed cryptographic key contained in a SPKI document. + /// + /// This is intended for relaying errors related to the raw data contained + /// in [`SubjectPublicKeyInfo::subject_public_key`][`crate::SubjectPublicKeyInfo::subject_public_key`]. + KeyMalformed, + + /// Unknown algorithm OID. + OidUnknown { + /// Unrecognized OID value found in e.g. a SPKI `AlgorithmIdentifier`. + oid: ObjectIdentifier, + }, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::AlgorithmParametersMissing => { + f.write_str("AlgorithmIdentifier parameters missing") + } + Error::Asn1(err) => write!(f, "ASN.1 error: {}", err), + Error::KeyMalformed => f.write_str("SPKI cryptographic key data malformed"), + Error::OidUnknown { oid } => { + write!(f, "unknown/unsupported algorithm OID: {}", oid) + } + } + } +} + +impl From<der::Error> for Error { + fn from(err: der::Error) -> Error { + if let der::ErrorKind::OidUnknown { oid } = err.kind() { + Error::OidUnknown { oid } + } else { + Error::Asn1(err) + } + } +} + +#[cfg(feature = "pem")] +impl From<pem::Error> for Error { + fn from(err: pem::Error) -> Error { + der::Error::from(err).into() + } +} + +#[cfg(feature = "std")] +impl std::error::Error for Error {} diff --git a/vendor/spki/src/fingerprint.rs b/vendor/spki/src/fingerprint.rs new file mode 100644 index 000000000..6a3901fb1 --- /dev/null +++ b/vendor/spki/src/fingerprint.rs @@ -0,0 +1,43 @@ +//! SPKI fingerprint support. + +use der::Writer; +use sha2::{Digest, Sha256}; + +/// Size of a SHA-256 SPKI fingerprint in bytes. +pub(crate) const SIZE: usize = 32; + +/// Raw bytes of a SPKI fingerprint i.e. SHA-256 digest of +/// `SubjectPublicKeyInfo`'s DER encoding. +/// +/// See [RFC7469 § 2.1.1] for more information. +/// +/// [RFC7469 § 2.1.1]: https://datatracker.ietf.org/doc/html/rfc7469#section-2.1.1 +#[cfg_attr(docsrs, doc(cfg(feature = "fingerprint")))] +pub type FingerprintBytes = [u8; SIZE]; + +/// Writer newtype which accepts DER being serialized on-the-fly and computes a +/// hash of the contents. +#[derive(Clone, Default)] +pub(crate) struct Builder { + /// In-progress digest being computed from streaming DER. + digest: Sha256, +} + +impl Builder { + /// Create a new fingerprint builder. + pub fn new() -> Self { + Self::default() + } + + /// Finish computing a fingerprint, returning the computed digest. + pub fn finish(self) -> FingerprintBytes { + self.digest.finalize().into() + } +} + +impl Writer for Builder { + fn write(&mut self, der_bytes: &[u8]) -> der::Result<()> { + self.digest.update(der_bytes); + Ok(()) + } +} diff --git a/vendor/spki/src/lib.rs b/vendor/spki/src/lib.rs new file mode 100644 index 000000000..f46675674 --- /dev/null +++ b/vendor/spki/src/lib.rs @@ -0,0 +1,55 @@ +#![no_std] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![doc = include_str!("../README.md")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg" +)] +#![forbid(unsafe_code, clippy::unwrap_used)] +#![warn(missing_docs, rust_2018_idioms, unused_qualifications)] + +//! # Usage +//! The following example demonstrates how to use an OID as the `parameters` +//! of an [`AlgorithmIdentifier`]. +//! +//! Borrow the [`ObjectIdentifier`] first then use [`der::AnyRef::from`] or `.into()`: +//! +//! ``` +//! use spki::{AlgorithmIdentifier, ObjectIdentifier, der::AnyRef}; +//! +//! let alg_oid = "1.2.840.10045.2.1".parse::<ObjectIdentifier>().unwrap(); +//! let params_oid = "1.2.840.10045.3.1.7".parse::<ObjectIdentifier>().unwrap(); +//! +//! let alg_id = AlgorithmIdentifier { +//! oid: alg_oid, +//! parameters: Some(AnyRef::from(¶ms_oid)) +//! }; +//! ``` + +#[cfg(feature = "alloc")] +#[allow(unused_extern_crates)] +extern crate alloc; +#[cfg(feature = "std")] +extern crate std; + +mod algorithm; +mod error; +mod spki; +mod traits; + +#[cfg(feature = "fingerprint")] +mod fingerprint; + +pub use crate::{ + algorithm::AlgorithmIdentifier, + error::{Error, Result}, + spki::SubjectPublicKeyInfo, + traits::DecodePublicKey, +}; +pub use der::{self, asn1::ObjectIdentifier}; + +#[cfg(feature = "alloc")] +pub use {crate::traits::EncodePublicKey, der::Document}; + +#[cfg(feature = "fingerprint")] +pub use crate::fingerprint::FingerprintBytes; diff --git a/vendor/spki/src/spki.rs b/vendor/spki/src/spki.rs new file mode 100644 index 000000000..9058e49c7 --- /dev/null +++ b/vendor/spki/src/spki.rs @@ -0,0 +1,141 @@ +//! X.509 `SubjectPublicKeyInfo` + +use crate::{AlgorithmIdentifier, Error, Result}; +use core::cmp::Ordering; +use der::{ + asn1::BitStringRef, Decode, DecodeValue, DerOrd, Encode, Header, Reader, Sequence, ValueOrd, +}; + +#[cfg(feature = "alloc")] +use der::Document; + +#[cfg(feature = "fingerprint")] +use crate::{fingerprint, FingerprintBytes}; + +#[cfg(all(feature = "alloc", feature = "fingerprint"))] +use { + alloc::string::String, + base64ct::{Base64, Encoding}, +}; + +#[cfg(feature = "pem")] +use der::pem::PemLabel; + +/// X.509 `SubjectPublicKeyInfo` (SPKI) as defined in [RFC 5280 § 4.1.2.7]. +/// +/// ASN.1 structure containing an [`AlgorithmIdentifier`] and public key +/// data in an algorithm specific format. +/// +/// ```text +/// SubjectPublicKeyInfo ::= SEQUENCE { +/// algorithm AlgorithmIdentifier, +/// subjectPublicKey BIT STRING } +/// ``` +/// +/// [RFC 5280 § 4.1.2.7]: https://tools.ietf.org/html/rfc5280#section-4.1.2.7 +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct SubjectPublicKeyInfo<'a> { + /// X.509 [`AlgorithmIdentifier`] for the public key type + pub algorithm: AlgorithmIdentifier<'a>, + + /// Public key data + pub subject_public_key: &'a [u8], +} + +impl<'a> SubjectPublicKeyInfo<'a> { + /// Calculate the SHA-256 fingerprint of this [`SubjectPublicKeyInfo`] and + /// encode it as a Base64 string. + /// + /// See [RFC7469 § 2.1.1] for more information. + /// + /// [RFC7469 § 2.1.1]: https://datatracker.ietf.org/doc/html/rfc7469#section-2.1.1 + #[cfg(all(feature = "fingerprint", feature = "alloc"))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "fingerprint", feature = "alloc"))))] + pub fn fingerprint_base64(&self) -> Result<String> { + Ok(Base64::encode_string(&self.fingerprint_bytes()?)) + } + + /// Calculate the SHA-256 fingerprint of this [`SubjectPublicKeyInfo`] as + /// a raw byte array. + /// + /// See [RFC7469 § 2.1.1] for more information. + /// + /// [RFC7469 § 2.1.1]: https://datatracker.ietf.org/doc/html/rfc7469#section-2.1.1 + #[cfg(feature = "fingerprint")] + #[cfg_attr(docsrs, doc(cfg(feature = "fingerprint")))] + pub fn fingerprint_bytes(&self) -> Result<FingerprintBytes> { + let mut builder = fingerprint::Builder::new(); + self.encode(&mut builder)?; + Ok(builder.finish()) + } + + /// Get a [`BitString`] representing the `subject_public_key` + fn bitstring(&self) -> der::Result<BitStringRef<'a>> { + BitStringRef::from_bytes(self.subject_public_key) + } +} + +impl<'a> DecodeValue<'a> for SubjectPublicKeyInfo<'a> { + fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> { + reader.read_nested(header.length, |reader| { + Ok(Self { + algorithm: reader.decode()?, + subject_public_key: BitStringRef::decode(reader)? + .as_bytes() + .ok_or_else(|| der::Tag::BitString.value_error())?, + }) + }) + } +} + +impl<'a> Sequence<'a> for SubjectPublicKeyInfo<'a> { + fn fields<F, T>(&self, f: F) -> der::Result<T> + where + F: FnOnce(&[&dyn Encode]) -> der::Result<T>, + { + f(&[&self.algorithm, &self.bitstring()?]) + } +} + +impl<'a> TryFrom<&'a [u8]> for SubjectPublicKeyInfo<'a> { + type Error = Error; + + fn try_from(bytes: &'a [u8]) -> Result<Self> { + Ok(Self::from_der(bytes)?) + } +} + +impl ValueOrd for SubjectPublicKeyInfo<'_> { + fn value_cmp(&self, other: &Self) -> der::Result<Ordering> { + match self.algorithm.der_cmp(&other.algorithm)? { + Ordering::Equal => self.bitstring()?.der_cmp(&other.bitstring()?), + other => Ok(other), + } + } +} + +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +impl TryFrom<SubjectPublicKeyInfo<'_>> for Document { + type Error = Error; + + fn try_from(spki: SubjectPublicKeyInfo<'_>) -> Result<Document> { + Self::try_from(&spki) + } +} + +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +impl TryFrom<&SubjectPublicKeyInfo<'_>> for Document { + type Error = Error; + + fn try_from(spki: &SubjectPublicKeyInfo<'_>) -> Result<Document> { + Ok(Self::encode_msg(spki)?) + } +} + +#[cfg(feature = "pem")] +#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] +impl PemLabel for SubjectPublicKeyInfo<'_> { + const PEM_LABEL: &'static str = "PUBLIC KEY"; +} diff --git a/vendor/spki/src/traits.rs b/vendor/spki/src/traits.rs new file mode 100644 index 000000000..c16e3974d --- /dev/null +++ b/vendor/spki/src/traits.rs @@ -0,0 +1,94 @@ +//! Traits for encoding/decoding SPKI public keys. + +use crate::{Error, Result, SubjectPublicKeyInfo}; + +#[cfg(feature = "alloc")] +use der::Document; + +#[cfg(feature = "pem")] +use { + alloc::string::String, + der::pem::{LineEnding, PemLabel}, +}; + +#[cfg(feature = "std")] +use std::path::Path; + +/// Parse a public key object from an encoded SPKI document. +pub trait DecodePublicKey: + for<'a> TryFrom<SubjectPublicKeyInfo<'a>, Error = Error> + Sized +{ + /// Deserialize object from ASN.1 DER-encoded [`SubjectPublicKeyInfo`] + /// (binary format). + fn from_public_key_der(bytes: &[u8]) -> Result<Self> { + Self::try_from(SubjectPublicKeyInfo::try_from(bytes)?) + } + + /// Deserialize PEM-encoded [`SubjectPublicKeyInfo`]. + /// + /// Keys in this format begin with the following delimiter: + /// + /// ```text + /// -----BEGIN PUBLIC KEY----- + /// ``` + #[cfg(feature = "pem")] + #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] + fn from_public_key_pem(s: &str) -> Result<Self> { + let (label, doc) = Document::from_pem(s)?; + SubjectPublicKeyInfo::validate_pem_label(label)?; + Self::from_public_key_der(doc.as_bytes()) + } + + /// Load public key object from an ASN.1 DER-encoded file on the local + /// filesystem (binary format). + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + fn read_public_key_der_file(path: impl AsRef<Path>) -> Result<Self> { + let doc = Document::read_der_file(path)?; + Self::from_public_key_der(doc.as_bytes()) + } + + /// Load public key object from a PEM-encoded file on the local filesystem. + #[cfg(all(feature = "pem", feature = "std"))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "std"))))] + fn read_public_key_pem_file(path: impl AsRef<Path>) -> Result<Self> { + let (label, doc) = Document::read_pem_file(path)?; + SubjectPublicKeyInfo::validate_pem_label(&label)?; + Self::from_public_key_der(doc.as_bytes()) + } +} + +/// Serialize a public key object to a SPKI-encoded document. +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +pub trait EncodePublicKey { + /// Serialize a [`Document`] containing a SPKI-encoded public key. + fn to_public_key_der(&self) -> Result<Document>; + + /// Serialize this public key as PEM-encoded SPKI with the given [`LineEnding`]. + #[cfg(feature = "pem")] + #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] + fn to_public_key_pem(&self, line_ending: LineEnding) -> Result<String> { + let doc = self.to_public_key_der()?; + Ok(doc.to_pem(SubjectPublicKeyInfo::PEM_LABEL, line_ending)?) + } + + /// Write ASN.1 DER-encoded public key to the given path + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + fn write_public_key_der_file(&self, path: impl AsRef<Path>) -> Result<()> { + Ok(self.to_public_key_der()?.write_der_file(path)?) + } + + /// Write ASN.1 DER-encoded public key to the given path + #[cfg(all(feature = "pem", feature = "std"))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "std"))))] + fn write_public_key_pem_file( + &self, + path: impl AsRef<Path>, + line_ending: LineEnding, + ) -> Result<()> { + let doc = self.to_public_key_der()?; + Ok(doc.write_pem_file(path, SubjectPublicKeyInfo::PEM_LABEL, line_ending)?) + } +} diff --git a/vendor/spki/tests/examples/ed25519-pub.der b/vendor/spki/tests/examples/ed25519-pub.der Binary files differnew file mode 100644 index 000000000..1b602ee1f --- /dev/null +++ b/vendor/spki/tests/examples/ed25519-pub.der diff --git a/vendor/spki/tests/examples/ed25519-pub.pem b/vendor/spki/tests/examples/ed25519-pub.pem new file mode 100644 index 000000000..6891701f7 --- /dev/null +++ b/vendor/spki/tests/examples/ed25519-pub.pem @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEATSkWfz8ZEqb3rfopOgUaFcBexnuPFyZ7HFVQ3OhTvQ0= +-----END PUBLIC KEY----- diff --git a/vendor/spki/tests/examples/p256-pub.der b/vendor/spki/tests/examples/p256-pub.der Binary files differnew file mode 100644 index 000000000..67c719c76 --- /dev/null +++ b/vendor/spki/tests/examples/p256-pub.der diff --git a/vendor/spki/tests/examples/p256-pub.pem b/vendor/spki/tests/examples/p256-pub.pem new file mode 100644 index 000000000..ee7e5b612 --- /dev/null +++ b/vendor/spki/tests/examples/p256-pub.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHKz/tV8vLO/YnYnrN0smgRUkUoAt +7qCZFgaBN9g5z3/EgaREkjBNfvZqwRe+/oOo0I8VXytS+fYY3URwKQSODw== +-----END PUBLIC KEY----- diff --git a/vendor/spki/tests/examples/rsa2048-pub.der b/vendor/spki/tests/examples/rsa2048-pub.der Binary files differnew file mode 100644 index 000000000..4148aaaaa --- /dev/null +++ b/vendor/spki/tests/examples/rsa2048-pub.der diff --git a/vendor/spki/tests/examples/rsa2048-pub.pem b/vendor/spki/tests/examples/rsa2048-pub.pem new file mode 100644 index 000000000..5ecd89239 --- /dev/null +++ b/vendor/spki/tests/examples/rsa2048-pub.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtsQsUV8QpqrygsY+2+JC +Q6Fw8/omM71IM2N/R8pPbzbgOl0p78MZGsgPOQ2HSznjD0FPzsH8oO2B5Uftws04 +LHb2HJAYlz25+lN5cqfHAfa3fgmC38FfwBkn7l582UtPWZ/wcBOnyCgb3yLcvJrX +yrt8QxHJgvWO23ITrUVYszImbXQ67YGS0YhMrbixRzmo2tpm3JcIBtnHrEUMsT0N +fFdfsZhTT8YbxBvA8FdODgEwx7u/vf3J9qbi4+Kv8cvqyJuleIRSjVXPsIMnoejI +n04APPKIjpMyQdnWlby7rNyQtE4+CV+jcFjqJbE/Xilcvqxt6DirjFCvYeKYl1uH +LwIDAQAB +-----END PUBLIC KEY----- diff --git a/vendor/spki/tests/spki.rs b/vendor/spki/tests/spki.rs new file mode 100644 index 000000000..3d6b19f48 --- /dev/null +++ b/vendor/spki/tests/spki.rs @@ -0,0 +1,156 @@ +//! `SubjectPublicKeyInfo` tests. + +use hex_literal::hex; +use spki::SubjectPublicKeyInfo; + +#[cfg(feature = "alloc")] +use der::Encode; + +#[cfg(feature = "pem")] +use der::{pem::LineEnding, EncodePem}; + +/// Elliptic Curve (P-256) `SubjectPublicKeyInfo` encoded as ASN.1 DER +const EC_P256_DER_EXAMPLE: &[u8] = include_bytes!("examples/p256-pub.der"); + +/// Ed25519 `SubjectPublicKeyInfo` encoded as ASN.1 DER +#[cfg(any(feature = "alloc", feature = "fingerprint"))] +const ED25519_DER_EXAMPLE: &[u8] = include_bytes!("examples/ed25519-pub.der"); + +/// RSA-2048 `SubjectPublicKeyInfo` encoded as ASN.1 DER +const RSA_2048_DER_EXAMPLE: &[u8] = include_bytes!("examples/rsa2048-pub.der"); + +/// Elliptic Curve (P-256) public key encoded as PEM +#[cfg(feature = "pem")] +const EC_P256_PEM_EXAMPLE: &str = include_str!("examples/p256-pub.pem"); + +/// Ed25519 public key encoded as PEM +#[cfg(feature = "pem")] +const ED25519_PEM_EXAMPLE: &str = include_str!("examples/ed25519-pub.pem"); + +/// RSA-2048 PKCS#8 public key encoded as PEM +#[cfg(feature = "pem")] +const RSA_2048_PEM_EXAMPLE: &str = include_str!("examples/rsa2048-pub.pem"); + +/// The SPKI fingerprint for `ED25519_SPKI_FINGERPRINT` as a Base64 string +/// +/// Generated using `cat ed25519-pub.der | openssl dgst -binary -sha256 | base64` +#[cfg(all(feature = "fingerprint", feature = "alloc"))] +const ED25519_SPKI_FINGERPRINT_BASE64: &str = "Vd1MdLDkhTTi9OFzzs61DfjyenrCqomRzHrpFOAwvO0="; + +/// The SPKI fingerprint for `ED25519_SPKI_FINGERPRINT` as straight hash bytes +/// +/// Generated using `cat ed25519-pub.der | openssl dgst -sha256` +#[cfg(all(feature = "fingerprint"))] +const ED25519_SPKI_FINGERPRINT: &[u8] = + &hex!("55dd4c74b0e48534e2f4e173ceceb50df8f27a7ac2aa8991cc7ae914e030bced"); + +#[test] +fn decode_ec_p256_der() { + let spki = SubjectPublicKeyInfo::try_from(EC_P256_DER_EXAMPLE).unwrap(); + + assert_eq!(spki.algorithm.oid, "1.2.840.10045.2.1".parse().unwrap()); + + assert_eq!( + spki.algorithm.parameters.unwrap().oid().unwrap(), + "1.2.840.10045.3.1.7".parse().unwrap() + ); + + assert_eq!(spki.subject_public_key, &hex!("041CACFFB55F2F2CEFD89D89EB374B2681152452802DEEA09916068137D839CF7FC481A44492304D7EF66AC117BEFE83A8D08F155F2B52F9F618DD447029048E0F")[..]); +} + +#[test] +#[cfg(feature = "fingerprint")] +fn decode_ed25519_and_fingerprint_spki() { + // Repeat the decode test from the pkcs8 crate + let spki = SubjectPublicKeyInfo::try_from(ED25519_DER_EXAMPLE).unwrap(); + + assert_eq!(spki.algorithm.oid, "1.3.101.112".parse().unwrap()); + assert_eq!(spki.algorithm.parameters, None); + assert_eq!( + spki.subject_public_key, + &hex!("4D29167F3F1912A6F7ADFA293A051A15C05EC67B8F17267B1C5550DCE853BD0D")[..] + ); + + // Check the fingerprint + assert_eq!( + spki.fingerprint_bytes().unwrap().as_slice(), + ED25519_SPKI_FINGERPRINT + ); +} + +#[test] +#[cfg(all(feature = "fingerprint", feature = "alloc"))] +fn decode_ed25519_and_fingerprint_base64() { + // Repeat the decode test from the pkcs8 crate + let spki = SubjectPublicKeyInfo::try_from(ED25519_DER_EXAMPLE).unwrap(); + + assert_eq!(spki.algorithm.oid, "1.3.101.112".parse().unwrap()); + assert_eq!(spki.algorithm.parameters, None); + assert_eq!( + spki.subject_public_key, + &hex!("4D29167F3F1912A6F7ADFA293A051A15C05EC67B8F17267B1C5550DCE853BD0D")[..] + ); + + // Check the fingerprint + assert_eq!( + spki.fingerprint_base64().unwrap(), + ED25519_SPKI_FINGERPRINT_BASE64 + ); +} + +#[test] +fn decode_rsa_2048_der() { + let spki = SubjectPublicKeyInfo::try_from(RSA_2048_DER_EXAMPLE).unwrap(); + + assert_eq!(spki.algorithm.oid, "1.2.840.113549.1.1.1".parse().unwrap()); + assert!(spki.algorithm.parameters.unwrap().is_null()); + assert_eq!(spki.subject_public_key, &hex!("3082010A0282010100B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C76F61C9018973DB9FA537972A7C701F6B77E0982DFC15FC01927EE5E7CD94B4F599FF07013A7C8281BDF22DCBC9AD7CABB7C4311C982F58EDB7213AD4558B332266D743AED8192D1884CADB8B14739A8DADA66DC970806D9C7AC450CB13D0D7C575FB198534FC61BC41BC0F0574E0E0130C7BBBFBDFDC9F6A6E2E3E2AFF1CBEAC89BA57884528D55CFB08327A1E8C89F4E003CF2888E933241D9D695BCBBACDC90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F0203010001")[..]); +} + +#[test] +#[cfg(feature = "alloc")] +fn encode_ec_p256_der() { + let pk = SubjectPublicKeyInfo::try_from(EC_P256_DER_EXAMPLE).unwrap(); + let pk_encoded = pk.to_vec().unwrap(); + assert_eq!(EC_P256_DER_EXAMPLE, pk_encoded.as_slice()); +} + +#[test] +#[cfg(feature = "alloc")] +fn encode_ed25519_der() { + let pk = SubjectPublicKeyInfo::try_from(ED25519_DER_EXAMPLE).unwrap(); + let pk_encoded = pk.to_vec().unwrap(); + assert_eq!(ED25519_DER_EXAMPLE, pk_encoded.as_slice()); +} + +#[test] +#[cfg(feature = "alloc")] +fn encode_rsa_2048_der() { + let pk = SubjectPublicKeyInfo::try_from(RSA_2048_DER_EXAMPLE).unwrap(); + let pk_encoded = pk.to_vec().unwrap(); + assert_eq!(RSA_2048_DER_EXAMPLE, pk_encoded.as_slice()); +} + +#[test] +#[cfg(feature = "pem")] +fn encode_ec_p256_pem() { + let pk = SubjectPublicKeyInfo::try_from(EC_P256_DER_EXAMPLE).unwrap(); + let pk_encoded = pk.to_pem(LineEnding::LF).unwrap(); + assert_eq!(EC_P256_PEM_EXAMPLE, pk_encoded); +} + +#[test] +#[cfg(feature = "pem")] +fn encode_ed25519_pem() { + let pk = SubjectPublicKeyInfo::try_from(ED25519_DER_EXAMPLE).unwrap(); + let pk_encoded = pk.to_pem(LineEnding::LF).unwrap(); + assert_eq!(ED25519_PEM_EXAMPLE, pk_encoded); +} + +#[test] +#[cfg(feature = "pem")] +fn encode_rsa_2048_pem() { + let pk = SubjectPublicKeyInfo::try_from(RSA_2048_DER_EXAMPLE).unwrap(); + let pk_encoded = pk.to_pem(LineEnding::LF).unwrap(); + assert_eq!(RSA_2048_PEM_EXAMPLE, pk_encoded); +} diff --git a/vendor/spki/tests/traits.rs b/vendor/spki/tests/traits.rs new file mode 100644 index 000000000..597399e44 --- /dev/null +++ b/vendor/spki/tests/traits.rs @@ -0,0 +1,108 @@ +//! Tests for SPKI encoding/decoding traits. + +#![cfg(any(feature = "pem", feature = "std"))] + +use der::{Decode, Encode}; +use spki::{DecodePublicKey, Document, EncodePublicKey, Error, Result, SubjectPublicKeyInfo}; + +#[cfg(feature = "pem")] +use spki::der::pem::LineEnding; + +#[cfg(feature = "std")] +use tempfile::tempdir; + +#[cfg(all(feature = "pem", feature = "std"))] +use std::fs; + +/// Ed25519 `SubjectPublicKeyInfo` encoded as ASN.1 DER +const ED25519_DER_EXAMPLE: &[u8] = include_bytes!("examples/ed25519-pub.der"); + +/// Ed25519 public key encoded as PEM +#[cfg(feature = "pem")] +const ED25519_PEM_EXAMPLE: &str = include_str!("examples/ed25519-pub.pem"); + +/// Mock key type for testing trait impls against. +pub struct MockKey(Vec<u8>); + +impl AsRef<[u8]> for MockKey { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } +} + +impl DecodePublicKey for MockKey { + fn from_public_key_der(bytes: &[u8]) -> Result<MockKey> { + Ok(MockKey(bytes.to_vec())) + } +} + +impl EncodePublicKey for MockKey { + fn to_public_key_der(&self) -> Result<Document> { + Ok(Document::from_der(self.as_ref())?) + } +} + +impl TryFrom<SubjectPublicKeyInfo<'_>> for MockKey { + type Error = Error; + + fn try_from(spki: SubjectPublicKeyInfo<'_>) -> Result<MockKey> { + Ok(MockKey(spki.to_vec()?)) + } +} + +#[cfg(feature = "pem")] +#[test] +fn from_public_key_pem() { + let key = MockKey::from_public_key_pem(ED25519_PEM_EXAMPLE).unwrap(); + assert_eq!(key.as_ref(), ED25519_DER_EXAMPLE); +} + +#[cfg(feature = "std")] +#[test] +fn read_public_key_der_file() { + let key = MockKey::read_public_key_der_file("tests/examples/ed25519-pub.der").unwrap(); + assert_eq!(key.as_ref(), ED25519_DER_EXAMPLE); +} + +#[cfg(all(feature = "pem", feature = "std"))] +#[test] +fn read_public_key_pem_file() { + let key = MockKey::read_public_key_pem_file("tests/examples/ed25519-pub.pem").unwrap(); + assert_eq!(key.as_ref(), ED25519_DER_EXAMPLE); +} + +#[cfg(feature = "pem")] +#[test] +fn to_public_key_pem() { + let pem = MockKey(ED25519_DER_EXAMPLE.to_vec()) + .to_public_key_pem(LineEnding::LF) + .unwrap(); + + assert_eq!(pem, ED25519_PEM_EXAMPLE); +} + +#[cfg(feature = "std")] +#[test] +fn write_public_key_der_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("example.der"); + MockKey(ED25519_DER_EXAMPLE.to_vec()) + .write_public_key_der_file(&path) + .unwrap(); + + let key = MockKey::read_public_key_der_file(&path).unwrap(); + assert_eq!(key.as_ref(), ED25519_DER_EXAMPLE); +} + +#[cfg(all(feature = "pem", feature = "std"))] +#[test] +fn write_public_key_pem_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("example.pem"); + MockKey(ED25519_DER_EXAMPLE.to_vec()) + .write_public_key_pem_file(&path, LineEnding::LF) + .unwrap(); + + let pem = fs::read_to_string(path).unwrap(); + assert_eq!(&pem, ED25519_PEM_EXAMPLE); +} |