diff options
Diffstat (limited to 'vendor/pkcs8')
38 files changed, 2100 insertions, 0 deletions
diff --git a/vendor/pkcs8/.cargo-checksum.json b/vendor/pkcs8/.cargo-checksum.json new file mode 100644 index 000000000..32f3df041 --- /dev/null +++ b/vendor/pkcs8/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"aea933ccfc3923c0c3e88b77a0b7d5aa5a4a36bf35e8b0e8f911692423020a1f","Cargo.toml":"ac0261d5f8e063c6d064ea76c8a51260a075927091fbdf95c0fb21e9dd34875b","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"904801faf3f1850328af8e1aa1047b9190cc22ed40df5c87f2d93d17f847ef67","README.md":"c0eea4fc2110743a2f6e07d9f80e2df3c92801b48e512cedd345ce01098eb732","src/encrypted_private_key_info.rs":"442ccb41c4b5d1ea6867501052fe78642705353afacf2bd8c50b14cfb0a712f8","src/error.rs":"be7deaf3abc0f5b41cb76f145654a8b6027616cd835be329cd55ce2e0b12a2c5","src/lib.rs":"e5e99696f70e28939a5d5b5259743ee053b7d1c990e8554b32a46a5a8b120e98","src/private_key_info.rs":"1e8a85260ff557adb1218cab27f651e0797cfc374a309c63061c6394ac8909b9","src/traits.rs":"651db842ecc79bf98a18f424737a9167ddd554ba2c85260a8ef83210c35f7655","src/version.rs":"6c8d36789f2aa0b1a4850b7ca97f6fa603bc62ebdece56cc9193e605582174de","tests/encrypted_private_key.rs":"d2d631fea2b086815605986f1d49b303b7e09eea68a614fa4a72ec3cb1c9b07a","tests/examples/ed25519-encpriv-aes128-pbkdf2-sha1.der":"b41702662d6a645cc81af5be79455509e02efbf6eb5166e91346c19334485e9a","tests/examples/ed25519-encpriv-aes256-pbkdf2-sha256.der":"72ea607c5f0e560f68ee914dca8a5a74bfa22a667333656864f7938960acd302","tests/examples/ed25519-encpriv-aes256-pbkdf2-sha256.pem":"0c8bd6713af3f28392f684c5ba8b1bd842d8b483d00c136cb1fb24976aab447a","tests/examples/ed25519-encpriv-aes256-scrypt.der":"81f29098750ab282fd071692173d4da09b2c81371e7a02da7a8a14d6bed7c8a0","tests/examples/ed25519-encpriv-aes256-scrypt.pem":"e643345b62b43ea255fccbad6efd21453c62a7bbbb4d94dfae151fe04562313d","tests/examples/ed25519-encpriv-des-pbkdf2-sha256.der":"2a2412eac2aebec977563ee503358513c179f0216d93701ecd901f0062df79dd","tests/examples/ed25519-encpriv-des3-pbkdf2-sha256.der":"e064ed2a875be1388a05be89948236c2765d85943ccf093ee3df6e9a16baa619","tests/examples/ed25519-priv-pkcs8v1.der":"c1c3b09c4d18e096209edf25bc8dfc2f11dc29896085e49e5f4e487fbd97dbb6","tests/examples/ed25519-priv-pkcs8v1.pem":"8e39c38052cd63ab3870831a9f6cab76645426ca21ef77e24e2ead445aa4df16","tests/examples/ed25519-priv-pkcs8v2.der":"78f1cd2051065b209431249093f218b0e01a5fd0b9e756db820d4893d9dbbf55","tests/examples/ed25519-priv-pkcs8v2.pem":"a7cc1efd420b972a1b0776cc8b703624c62617eb2be3705876cc145227bd8427","tests/examples/ed25519-pub.der":"55dd4c74b0e48534e2f4e173ceceb50df8f27a7ac2aa8991cc7ae914e030bced","tests/examples/ed25519-pub.pem":"36d717203cbca1812f05f30e0415251c928b659882092e653221a028571c6853","tests/examples/p256-priv.der":"8125ab208d2181ed3ef05ff0ab1906e5898c36a858277e5b987e78e505288769","tests/examples/p256-priv.pem":"f4171f5ea72bf95ee444ceb868872f5c5d2bbc5fca038ae801b06fb9ac6b9429","tests/examples/p256-pub.der":"b9968d56ed8d6aa3fb43b15fa01e355d7a3a0203b1408b3fd2733637c4d1642c","tests/examples/p256-pub.pem":"d1ff198dc495da63f5f909db0254d6e49cff519487fcb26d055a762fc3ca47a1","tests/examples/rsa2048-priv.der":"ea7fe20f854f4fb908c12f1344e6cffbb83f367bbd8bfebca20687402394266f","tests/examples/rsa2048-priv.pem":"4df5e3254935a4f7d71e3b693d1b874091717f8b6075cd33f80ce4338d2ab0f2","tests/examples/rsa2048-pub.der":"efeda9bfead9fd0594f6a5cf6fdf6c163116a3b1fad6d73cea05295b68fd1794","tests/examples/rsa2048-pub.pem":"078c3983093e86784590a2a454547acad1d50992419334be697e442e954f02f8","tests/examples/x25519-priv.der":"bc4561e57bcb0e5b8be9bbdf4fb51e5e34dc46047ce50239c35fe7f119f52f91","tests/examples/x25519-priv.pem":"c618022ab6a2e345b475830c1e0a9332458791df939d116b6e6d4da9c918771b","tests/private_key.rs":"44b42494e74087860020e9799c8e50922de36385e8d5ea74b0285879c6e43063","tests/traits.rs":"420524fd3394c9fd5cfcf02a4f1da3f3193a91712dfd513915aec9bddfaf57e9"},"package":"9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba"}
\ No newline at end of file diff --git a/vendor/pkcs8/CHANGELOG.md b/vendor/pkcs8/CHANGELOG.md new file mode 100644 index 000000000..15889d971 --- /dev/null +++ b/vendor/pkcs8/CHANGELOG.md @@ -0,0 +1,210 @@ +# 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.9.0 (2022-05-08) +### Added +- Error conversion support to `pkcs8::spki::Error` ([#335]) +- Re-export `AssociatedOid` ([#645]) + +### Changed +- Use `finish_non_exhaustive` in `Debug` impls ([#245]) +- Replace `PrivateKeyDocument` with `der::SecretDocument` ([#571]) +- Bump `der` to v0.6 ([#653]) +- Bump `spki` to v0.6 ([#654]) +- Bump `pkcs5` to v0.5 ([#655]) + +### Removed +- `PrivateKeyDocument` ([#571]) + +[#245]: https://github.com/RustCrypto/formats/pull/245 +[#335]: https://github.com/RustCrypto/formats/pull/335 +[#571]: https://github.com/RustCrypto/formats/pull/571 +[#645]: https://github.com/RustCrypto/formats/pull/645 +[#653]: https://github.com/RustCrypto/formats/pull/653 +[#654]: https://github.com/RustCrypto/formats/pull/654 +[#655]: https://github.com/RustCrypto/formats/pull/655 + +## 0.8.0 (2021-11-16) +### Added +- Re-export `spki` crate ([#210]) + +### Changed +- Replace usages of `expect` with fallible methods ([#108]) +- Impl `From*Key`/`To*Key` traits on `Document` types ([#110]) +- Rename `From/ToPrivateKey` => `DecodePrivateKey`/`EncodePrivateKey` ([#121]) +- Rust 2021 edition upgrade; MSRV 1.56 ([#136]) +- Use `der::Document` to impl `*PrivateKeyDocument` ([#140]) +- Rename `Error::Crypto` => `Error::EncryptedPrivateKey` ([#213], [#214]) +- Bump `der` dependency to v0.5 ([#222]) +- Bump `spki` dependency to v0.5 ([#223]) +- Bump `pkcs5` dependency to v0.4 ([#224]) +- Replace `from_pkcs8_private_key_info` with `TryFrom` ([#230]) + +### Removed +- `*_with_le` PEM encoding methods ([#109]) +- PKCS#1 support; moved to `pkcs1` crate ([#124]) +- I/O related errors from key format crates ([#158]) +- `der::pem` export ([#211]) + +[#108]: https://github.com/RustCrypto/formats/pull/108 +[#109]: https://github.com/RustCrypto/formats/pull/109 +[#110]: https://github.com/RustCrypto/formats/pull/110 +[#121]: https://github.com/RustCrypto/formats/pull/121 +[#124]: https://github.com/RustCrypto/formats/pull/124 +[#136]: https://github.com/RustCrypto/formats/pull/136 +[#140]: https://github.com/RustCrypto/formats/pull/140 +[#158]: https://github.com/RustCrypto/formats/pull/158 +[#210]: https://github.com/RustCrypto/formats/pull/210 +[#211]: https://github.com/RustCrypto/formats/pull/211 +[#213]: https://github.com/RustCrypto/formats/pull/213 +[#214]: https://github.com/RustCrypto/formats/pull/214 +[#222]: https://github.com/RustCrypto/formats/pull/222 +[#223]: https://github.com/RustCrypto/formats/pull/223 +[#224]: https://github.com/RustCrypto/formats/pull/224 +[#230]: https://github.com/RustCrypto/formats/pull/230 + +## 0.7.6 (2021-09-14) +### Added +- `3des` and `des-insecure` features +- `sha1` feature +- Support for AES-192-CBC + +### Changed +- Moved to `formats` repo ([#2]) + +[#2]: https://github.com/RustCrypto/formats/pull/2 + +## 0.7.5 (2021-07-26) +### Added +- Support for customizing PEM `LineEnding` + +### Changed +- Bump `pem-rfc7468` dependency to v0.2 + +## 0.7.4 (2021-07-25) +### Added +- PKCS#1 support + +## 0.7.3 (2021-07-24) +### Changed +- Use `pem-rfc7468` crate + +## 0.7.2 (2021-07-20) +### Added +- `Error::ParametersMalformed` variant + +## 0.7.1 (2021-07-20) +### Added +- `Error::KeyMalformed` variant + +## 0.7.0 (2021-06-07) +### Added +- ASN.1 error improvements + +### Changed +- Merge `OneAsymmetricKey` into `PrivateKeyInfo` +- Use scrypt as the default PBES2 KDF +- Return `Result`(s) when encoding +- Bump `der` to v0.4 +- Bump `spki` to v0.4 +- Bump `pkcs5` to v0.3 + +## 0.6.1 (2021-05-24) +### Added +- Support for RFC5958's `OneAsymmetricKey` + +### Changed +- Bump `der` to v0.3.5 + +## 0.6.0 (2021-03-22) +### Changed +- Bump `der` dependency to v0.3 +- Bump `spki` dependency to v0.3 +- Bump `pkcs5` dependency to v0.2 + +## 0.5.5 (2021-03-17) +### Changed +- Bump `base64ct` dependency to v1.0 + +## 0.5.4 (2021-02-24) +### Added +- Encryption helper methods for `FromPrivateKey`/`ToPrivateKey` + +## 0.5.3 (2021-02-23) +### Added +- Support for decrypting/encrypting `EncryptedPrivateKeyInfo` +- PEM support for `EncryptedPrivateKeyInfo` +- `Error::Crypto` variant + +## 0.5.2 (2021-02-20) +### Changed +- Use `pkcs5` crate + +## 0.5.1 (2021-02-18) [YANKED] +### Added +- `pkcs5` feature + +### Changed +- Bump `spki` dependency to v0.2.0 + +## 0.5.0 (2021-02-16) [YANKED] +### Added +- Initial `EncryptedPrivateKeyInfo` support + +### Changed +- Extract SPKI-related types into the `spki` crate + +## 0.4.1 (2021-02-01) +### Changed +- Bump `basec4ct` dependency to v0.2 + +## 0.4.0 (2021-01-26) +### Changed +- Bump `der` crate dependency to v0.2 +- Use `base64ct` v0.1 for PEM encoding + +## 0.3.3 (2020-12-21) +### Changed +- Use `der` crate for decoding/encoding ASN.1 DER + +## 0.3.2 (2020-12-16) +### Added +- `AlgorithmIdentifier::parameters_oid` method + +## 0.3.1 (2020-12-16) +### Changed +- Bump `const-oid` dependency to v0.4 + +## 0.3.0 (2020-12-16) [YANKED] +### Added +- `AlgorithmParameters` enum + +## 0.2.2 (2020-12-14) +### Fixed +- Decoding/encoding support for Ed25519 keys + +## 0.2.1 (2020-12-14) +### Added +- rustdoc improvements + +## 0.2.0 (2020-12-14) +### Added +- File writing methods for public/private keys +- Methods for loading `*Document` types from files +- DER encoding support +- PEM encoding support +- `ToPrivateKey`/`ToPublicKey` traits + +### Changed +- `Error` enum +- Rename `load_*_file` methods to `read_*_file` + +## 0.1.1 (2020-12-06) +### Added +- Helper methods to load keys from the local filesystem + +## 0.1.0 (2020-12-05) +- Initial release diff --git a/vendor/pkcs8/Cargo.toml b/vendor/pkcs8/Cargo.toml new file mode 100644 index 000000000..6de007a54 --- /dev/null +++ b/vendor/pkcs8/Cargo.toml @@ -0,0 +1,109 @@ +# 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 = "pkcs8" +version = "0.9.0" +authors = ["RustCrypto Developers"] +description = """ +Pure Rust implementation of Public-Key Cryptography Standards (PKCS) #8: +Private-Key Information Syntax Specification (RFC 5208), with additional +support for PKCS#8v2 asymmetric key packages (RFC 5958) +""" +readme = "README.md" +keywords = [ + "crypto", + "key", + "pkcs", + "private", +] +categories = [ + "cryptography", + "data-structures", + "encoding", + "no-std", + "parser-implementations", +] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/RustCrypto/formats/tree/master/pkcs8" +resolver = "2" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", +] + +[dependencies.der] +version = "0.6" +features = ["oid"] + +[dependencies.pkcs5] +version = "0.5" +optional = true + +[dependencies.rand_core] +version = "0.6" +optional = true +default-features = false + +[dependencies.spki] +version = "0.6" + +[dependencies.subtle] +version = "2" +optional = true +default-features = false + +[dev-dependencies.hex-literal] +version = "0.3" + +[dev-dependencies.tempfile] +version = "3" + +[features] +3des = [ + "encryption", + "pkcs5/3des", +] +alloc = [ + "der/alloc", + "der/zeroize", + "spki/alloc", +] +des-insecure = [ + "encryption", + "pkcs5/des-insecure", +] +encryption = [ + "alloc", + "pkcs5/alloc", + "pkcs5/pbes2", + "rand_core", +] +getrandom = ["rand_core/getrandom"] +pem = [ + "alloc", + "der/pem", + "spki/pem", +] +sha1 = [ + "encryption", + "pkcs5/sha1", +] +std = [ + "alloc", + "der/std", + "spki/std", +] diff --git a/vendor/pkcs8/LICENSE-APACHE b/vendor/pkcs8/LICENSE-APACHE new file mode 100644 index 000000000..78173fa2e --- /dev/null +++ b/vendor/pkcs8/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/pkcs8/LICENSE-MIT b/vendor/pkcs8/LICENSE-MIT new file mode 100644 index 000000000..2726e14a4 --- /dev/null +++ b/vendor/pkcs8/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2020 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/pkcs8/README.md b/vendor/pkcs8/README.md new file mode 100644 index 000000000..2fa301ced --- /dev/null +++ b/vendor/pkcs8/README.md @@ -0,0 +1,94 @@ +# [RustCrypto]: PKCS#8 (Private Keys) + +[![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 implementation of Public-Key Cryptography Standards (PKCS) #8: +Private-Key Information Syntax Specification ([RFC 5208]). + +[Documentation][docs-link] + +## About PKCS#8 + +PKCS#8 is a format for cryptographic private keys, often containing pairs +of private and public keys. + +You can identify a PKCS#8 private key encoded as PEM (i.e. text) by the +following: + +```text +-----BEGIN PRIVATE KEY----- +``` + +PKCS#8 private keys can optionally be encrypted under a password using +key derivation algorithms like PBKDF2 and [scrypt], and encrypted with +ciphers like AES-CBC. When a PKCS#8 private key has been encrypted, +it starts with the following: + +```text +-----BEGIN ENCRYPTED PRIVATE KEY----- +``` + +PKCS#8 private keys can also be serialized in an ASN.1-based binary format. +The PEM text encoding is a Base64 representation of this format. + +## Supported Algorithms + +This crate is implemented in an algorithm-agnostic manner with the goal of +enabling PKCS#8 support for any algorithm. + +That said, it has been tested for interoperability against keys generated by +OpenSSL for the following algorithms: + +- ECC (`id-ecPublicKey`) +- Ed25519 (`id-Ed25519`) +- RSA (`id-rsaEncryption`) +- X25519 (`id-X25519`) + +Please open an issue if you encounter trouble using it with a particular +algorithm, including the ones listed above or other algorithms. + +## 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/pkcs8 +[crate-link]: https://crates.io/crates/pkcs8 +[docs-image]: https://docs.rs/pkcs8/badge.svg +[docs-link]: https://docs.rs/pkcs8/ +[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 +[build-image]: https://github.com/RustCrypto/formats/workflows/pkcs8/badge.svg?branch=master&event=push +[build-link]: https://github.com/RustCrypto/formats/actions + +[//]: # (links) + +[RustCrypto]: https://github.com/rustcrypto +[RFC 5208]: https://tools.ietf.org/html/rfc5208 +[scrypt]: https://en.wikipedia.org/wiki/Scrypt diff --git a/vendor/pkcs8/src/encrypted_private_key_info.rs b/vendor/pkcs8/src/encrypted_private_key_info.rs new file mode 100644 index 000000000..460e3f6e3 --- /dev/null +++ b/vendor/pkcs8/src/encrypted_private_key_info.rs @@ -0,0 +1,166 @@ +//! PKCS#8 `EncryptedPrivateKeyInfo` + +use crate::{Error, Result}; +use core::fmt; +use der::{asn1::OctetStringRef, Decode, DecodeValue, Encode, Header, Reader, Sequence}; +use pkcs5::EncryptionScheme; + +#[cfg(feature = "alloc")] +use der::SecretDocument; + +#[cfg(feature = "encryption")] +use { + pkcs5::pbes2, + rand_core::{CryptoRng, RngCore}, +}; + +#[cfg(feature = "pem")] +use der::pem::PemLabel; + +/// PKCS#8 `EncryptedPrivateKeyInfo`. +/// +/// ASN.1 structure containing a PKCS#5 [`EncryptionScheme`] identifier for a +/// password-based symmetric encryption scheme and encrypted private key data. +/// +/// ## Schema +/// Structure described in [RFC 5208 Section 6]: +/// +/// ```text +/// EncryptedPrivateKeyInfo ::= SEQUENCE { +/// encryptionAlgorithm EncryptionAlgorithmIdentifier, +/// encryptedData EncryptedData } +/// +/// EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier +/// +/// EncryptedData ::= OCTET STRING +/// ``` +/// +/// [RFC 5208 Section 6]: https://tools.ietf.org/html/rfc5208#section-6 +#[cfg_attr(docsrs, doc(cfg(feature = "pkcs5")))] +#[derive(Clone, Eq, PartialEq)] +pub struct EncryptedPrivateKeyInfo<'a> { + /// Algorithm identifier describing a password-based symmetric encryption + /// scheme used to encrypt the `encrypted_data` field. + pub encryption_algorithm: EncryptionScheme<'a>, + + /// Private key data + pub encrypted_data: &'a [u8], +} + +impl<'a> EncryptedPrivateKeyInfo<'a> { + /// Attempt to decrypt this encrypted private key using the provided + /// password to derive an encryption key. + #[cfg(feature = "encryption")] + #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))] + pub fn decrypt(&self, password: impl AsRef<[u8]>) -> Result<SecretDocument> { + Ok(self + .encryption_algorithm + .decrypt(password, self.encrypted_data)? + .try_into()?) + } + + /// Encrypt the given ASN.1 DER document using a symmetric encryption key + /// derived from the provided password. + #[cfg(feature = "encryption")] + #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))] + pub(crate) fn encrypt( + mut rng: impl CryptoRng + RngCore, + password: impl AsRef<[u8]>, + doc: &[u8], + ) -> Result<SecretDocument> { + let mut salt = [0u8; 16]; + rng.fill_bytes(&mut salt); + + let mut iv = [0u8; 16]; + rng.fill_bytes(&mut iv); + + let pbes2_params = pbes2::Parameters::scrypt_aes256cbc(Default::default(), &salt, &iv)?; + EncryptedPrivateKeyInfo::encrypt_with(pbes2_params, password, doc) + } + + /// Encrypt this private key using a symmetric encryption key derived + /// from the provided password and [`pbes2::Parameters`]. + #[cfg(feature = "encryption")] + #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))] + pub(crate) fn encrypt_with( + pbes2_params: pbes2::Parameters<'a>, + password: impl AsRef<[u8]>, + doc: &[u8], + ) -> Result<SecretDocument> { + let encrypted_data = pbes2_params.encrypt(password, doc)?; + + EncryptedPrivateKeyInfo { + encryption_algorithm: pbes2_params.into(), + encrypted_data: &encrypted_data, + } + .try_into() + } +} + +impl<'a> DecodeValue<'a> for EncryptedPrivateKeyInfo<'a> { + fn decode_value<R: Reader<'a>>( + reader: &mut R, + header: Header, + ) -> der::Result<EncryptedPrivateKeyInfo<'a>> { + reader.read_nested(header.length, |reader| { + Ok(Self { + encryption_algorithm: reader.decode()?, + encrypted_data: OctetStringRef::decode(reader)?.as_bytes(), + }) + }) + } +} + +impl<'a> Sequence<'a> for EncryptedPrivateKeyInfo<'a> { + fn fields<F, T>(&self, f: F) -> der::Result<T> + where + F: FnOnce(&[&dyn Encode]) -> der::Result<T>, + { + f(&[ + &self.encryption_algorithm, + &OctetStringRef::new(self.encrypted_data)?, + ]) + } +} + +impl<'a> TryFrom<&'a [u8]> for EncryptedPrivateKeyInfo<'a> { + type Error = Error; + + fn try_from(bytes: &'a [u8]) -> Result<Self> { + Ok(Self::from_der(bytes)?) + } +} + +impl<'a> fmt::Debug for EncryptedPrivateKeyInfo<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("EncryptedPrivateKeyInfo") + .field("encryption_algorithm", &self.encryption_algorithm) + .finish_non_exhaustive() + } +} + +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "pkcs5"))))] +impl TryFrom<EncryptedPrivateKeyInfo<'_>> for SecretDocument { + type Error = Error; + + fn try_from(encrypted_private_key: EncryptedPrivateKeyInfo<'_>) -> Result<SecretDocument> { + SecretDocument::try_from(&encrypted_private_key) + } +} + +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "pkcs5"))))] +impl TryFrom<&EncryptedPrivateKeyInfo<'_>> for SecretDocument { + type Error = Error; + + fn try_from(encrypted_private_key: &EncryptedPrivateKeyInfo<'_>) -> Result<SecretDocument> { + Ok(Self::encode_msg(encrypted_private_key)?) + } +} + +#[cfg(feature = "pem")] +#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] +impl PemLabel for EncryptedPrivateKeyInfo<'_> { + const PEM_LABEL: &'static str = "ENCRYPTED PRIVATE KEY"; +} diff --git a/vendor/pkcs8/src/error.rs b/vendor/pkcs8/src/error.rs new file mode 100644 index 000000000..bc4c2eafe --- /dev/null +++ b/vendor/pkcs8/src/error.rs @@ -0,0 +1,93 @@ +//! Error types + +use core::fmt; + +#[cfg(feature = "pem")] +use der::pem; + +/// Result type +pub type Result<T> = core::result::Result<T, Error>; + +/// Error type +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[non_exhaustive] +pub enum Error { + /// ASN.1 DER-related errors. + Asn1(der::Error), + + /// Errors relating to PKCS#5-encrypted keys. + #[cfg(feature = "pkcs5")] + EncryptedPrivateKey(pkcs5::Error), + + /// Malformed cryptographic key contained in a PKCS#8 document. + /// + /// This is intended for relaying errors related to the raw data contained + /// within [`PrivateKeyInfo::private_key`][`crate::PrivateKeyInfo::private_key`] + /// or [`SubjectPublicKeyInfo::subject_public_key`][`crate::SubjectPublicKeyInfo::subject_public_key`]. + KeyMalformed, + + /// [`AlgorithmIdentifier::parameters`][`crate::AlgorithmIdentifier::parameters`] + /// is malformed or otherwise encoded in an unexpected manner. + ParametersMalformed, + + /// Public key errors propagated from the [`spki::Error`] type. + PublicKey(spki::Error), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::Asn1(err) => write!(f, "PKCS#8 ASN.1 error: {}", err), + #[cfg(feature = "pkcs5")] + Error::EncryptedPrivateKey(err) => write!(f, "{}", err), + Error::KeyMalformed => f.write_str("PKCS#8 cryptographic key data malformed"), + Error::ParametersMalformed => f.write_str("PKCS#8 algorithm parameters malformed"), + Error::PublicKey(err) => write!(f, "public key error: {}", err), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for Error {} + +impl From<der::Error> for Error { + fn from(err: der::Error) -> Error { + Error::Asn1(err) + } +} + +impl From<der::ErrorKind> for Error { + fn from(err: der::ErrorKind) -> Error { + Error::Asn1(err.into()) + } +} + +#[cfg(feature = "pem")] +impl From<pem::Error> for Error { + fn from(err: pem::Error) -> Error { + der::Error::from(err).into() + } +} + +#[cfg(feature = "pkcs5")] +impl From<pkcs5::Error> for Error { + fn from(err: pkcs5::Error) -> Error { + Error::EncryptedPrivateKey(err) + } +} + +impl From<spki::Error> for Error { + fn from(err: spki::Error) -> Error { + Error::PublicKey(err) + } +} + +impl From<Error> for spki::Error { + fn from(err: Error) -> spki::Error { + match err { + Error::Asn1(e) => spki::Error::Asn1(e), + Error::PublicKey(e) => e, + _ => spki::Error::KeyMalformed, + } + } +} diff --git a/vendor/pkcs8/src/lib.rs b/vendor/pkcs8/src/lib.rs new file mode 100644 index 000000000..1d2dfa284 --- /dev/null +++ b/vendor/pkcs8/src/lib.rs @@ -0,0 +1,104 @@ +#![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", + html_root_url = "https://docs.rs/pkcs8/0.9.0-pre" +)] +#![forbid(unsafe_code, clippy::unwrap_used)] +#![warn(missing_docs, rust_2018_idioms, unused_qualifications)] + +//! ## About this crate +//! This library provides generalized PKCS#8 support designed to work with a +//! number of different algorithms. It supports `no_std` platforms including +//! ones without a heap (albeit with reduced functionality). +//! +//! It supports decoding/encoding the following types: +//! +//! - [`EncryptedPrivateKeyInfo`]: (with `pkcs5` feature) encrypted key. +//! - [`PrivateKeyInfo`]: algorithm identifier and data representing a private key. +//! Optionally also includes public key data for asymmetric keys. +//! - [`SubjectPublicKeyInfo`]: algorithm identifier and data representing a public key +//! (re-exported from the [`spki`] crate) +//! +//! When the `pem` feature is enabled, it also supports decoding/encoding +//! documents from "PEM encoding" format as defined in RFC 7468. +//! +//! ## Encrypted Private Key Support +//! [`EncryptedPrivateKeyInfo`] supports decoding/encoding encrypted PKCS#8 +//! private keys and is gated under the `pkcs5` feature. +//! +//! When the `encryption` feature of this crate is enabled, it provides +//! [`EncryptedPrivateKeyInfo::decrypt`] and [`PrivateKeyInfo::encrypt`] +//! functions which are able to decrypt/encrypt keys using the following +//! algorithms: +//! +//! - [PKCS#5v2 Password Based Encryption Scheme 2 (RFC 8018)] +//! - Key derivation functions: +//! - [scrypt] ([RFC 7914]) +//! - PBKDF2 ([RFC 8018](https://datatracker.ietf.org/doc/html/rfc8018#section-5.2)) +//! - SHA-2 based PRF with HMAC-SHA224, HMAC-SHA256, HMAC-SHA384, or HMAC-SHA512 +//! - SHA-1 based PRF with HMAC-SHA1, when the `sha1` feature of this crate is enabled. +//! - Symmetric encryption: AES-128-CBC, AES-192-CBC, or AES-256-CBC +//! (best available options for PKCS#5v2) +//! +//! ## Legacy DES-CBC and DES-EDE3-CBC (3DES) support (optional) +//! When the `des-insecure` and/or `3des` features are enabled this crate provides support for +//! private keys encrypted with with DES-CBC and DES-EDE3-CBC (3DES or Triple DES) symmetric +//! encryption, respectively. +//! +//! ⚠️ WARNING ⚠️ +//! +//! DES support (gated behind the `des-insecure` feature) is implemented to +//! allow for decryption of legacy PKCS#8 files only. +//! +//! Such PKCS#8 documents should be considered *INSECURE* due to the short +//! 56-bit key size of DES. +//! +//! New keys should use AES instead. +//! +//! [RFC 5208]: https://tools.ietf.org/html/rfc5208 +//! [RFC 5958]: https://tools.ietf.org/html/rfc5958 +//! [RFC 7914]: https://datatracker.ietf.org/doc/html/rfc7914 +//! [PKCS#5v2 Password Based Encryption Scheme 2 (RFC 8018)]: https://tools.ietf.org/html/rfc8018#section-6.2 +//! [scrypt]: https://en.wikipedia.org/wiki/Scrypt + +#[cfg(feature = "pem")] +extern crate alloc; +#[cfg(feature = "std")] +extern crate std; + +mod error; +mod private_key_info; +mod traits; +mod version; + +#[cfg(feature = "pkcs5")] +pub(crate) mod encrypted_private_key_info; + +pub use crate::{ + error::{Error, Result}, + private_key_info::PrivateKeyInfo, + traits::DecodePrivateKey, + version::Version, +}; +pub use der::{self, asn1::ObjectIdentifier, oid::AssociatedOid}; +pub use spki::{self, AlgorithmIdentifier, DecodePublicKey, SubjectPublicKeyInfo}; + +#[cfg(feature = "alloc")] +pub use { + crate::traits::EncodePrivateKey, + der::{Document, SecretDocument}, + spki::EncodePublicKey, +}; + +#[cfg(feature = "pem")] +#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] +pub use der::pem::LineEnding; + +#[cfg(feature = "pkcs5")] +pub use {encrypted_private_key_info::EncryptedPrivateKeyInfo, pkcs5}; + +#[cfg(feature = "rand_core")] +pub use rand_core; diff --git a/vendor/pkcs8/src/private_key_info.rs b/vendor/pkcs8/src/private_key_info.rs new file mode 100644 index 000000000..52f0878d7 --- /dev/null +++ b/vendor/pkcs8/src/private_key_info.rs @@ -0,0 +1,293 @@ +//! PKCS#8 `PrivateKeyInfo`. + +use crate::{AlgorithmIdentifier, Error, Result, Version}; +use core::fmt; +use der::{ + asn1::{AnyRef, BitStringRef, ContextSpecific, OctetStringRef}, + Decode, DecodeValue, Encode, Header, Reader, Sequence, TagMode, TagNumber, +}; + +#[cfg(feature = "alloc")] +use der::SecretDocument; + +#[cfg(feature = "encryption")] +use { + crate::EncryptedPrivateKeyInfo, + der::zeroize::Zeroizing, + pkcs5::pbes2, + rand_core::{CryptoRng, RngCore}, +}; + +#[cfg(feature = "pem")] +use der::pem::PemLabel; + +#[cfg(feature = "subtle")] +use subtle::{Choice, ConstantTimeEq}; + +/// Context-specific tag number for the public key. +const PUBLIC_KEY_TAG: TagNumber = TagNumber::N1; + +/// PKCS#8 `PrivateKeyInfo`. +/// +/// ASN.1 structure containing an [`AlgorithmIdentifier`], private key +/// data in an algorithm specific format, and optional attributes +/// (ignored by this implementation). +/// +/// Supports PKCS#8 v1 as described in [RFC 5208] and PKCS#8 v2 as described +/// in [RFC 5958]. PKCS#8 v2 keys include an additional public key field. +/// +/// # PKCS#8 v1 `PrivateKeyInfo` +/// +/// Described in [RFC 5208 Section 5]: +/// +/// ```text +/// PrivateKeyInfo ::= SEQUENCE { +/// version Version, +/// privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, +/// privateKey PrivateKey, +/// attributes [0] IMPLICIT Attributes OPTIONAL } +/// +/// Version ::= INTEGER +/// +/// PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier +/// +/// PrivateKey ::= OCTET STRING +/// +/// Attributes ::= SET OF Attribute +/// ``` +/// +/// # PKCS#8 v2 `OneAsymmetricKey` +/// +/// PKCS#8 `OneAsymmetricKey` as described in [RFC 5958 Section 2]: +/// +/// ```text +/// PrivateKeyInfo ::= OneAsymmetricKey +/// +/// OneAsymmetricKey ::= SEQUENCE { +/// version Version, +/// privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, +/// privateKey PrivateKey, +/// attributes [0] Attributes OPTIONAL, +/// ..., +/// [[2: publicKey [1] PublicKey OPTIONAL ]], +/// ... +/// } +/// +/// Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2) +/// +/// PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier +/// +/// PrivateKey ::= OCTET STRING +/// +/// Attributes ::= SET OF Attribute +/// +/// PublicKey ::= BIT STRING +/// ``` +/// +/// [RFC 5208]: https://tools.ietf.org/html/rfc5208 +/// [RFC 5958]: https://datatracker.ietf.org/doc/html/rfc5958 +/// [RFC 5208 Section 5]: https://tools.ietf.org/html/rfc5208#section-5 +/// [RFC 5958 Section 2]: https://datatracker.ietf.org/doc/html/rfc5958#section-2 +#[derive(Clone)] +pub struct PrivateKeyInfo<'a> { + /// X.509 [`AlgorithmIdentifier`] for the private key type. + pub algorithm: AlgorithmIdentifier<'a>, + + /// Private key data. + pub private_key: &'a [u8], + + /// Public key data, optionally available if version is V2. + pub public_key: Option<&'a [u8]>, +} + +impl<'a> PrivateKeyInfo<'a> { + /// Create a new PKCS#8 [`PrivateKeyInfo`] message. + /// + /// This is a helper method which initializes `attributes` and `public_key` + /// to `None`, helpful if you aren't using those. + pub fn new(algorithm: AlgorithmIdentifier<'a>, private_key: &'a [u8]) -> Self { + Self { + algorithm, + private_key, + public_key: None, + } + } + + /// Get the PKCS#8 [`Version`] for this structure. + /// + /// [`Version::V1`] if `public_key` is `None`, [`Version::V2`] if `Some`. + pub fn version(&self) -> Version { + if self.public_key.is_some() { + Version::V2 + } else { + Version::V1 + } + } + + /// Encrypt this private key using a symmetric encryption key derived + /// from the provided password. + /// + /// Uses the following algorithms for encryption: + /// - PBKDF: scrypt with default parameters: + /// - log₂(N): 15 + /// - r: 8 + /// - p: 1 + /// - Cipher: AES-256-CBC (best available option for PKCS#5 encryption) + #[cfg(feature = "encryption")] + #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))] + pub fn encrypt( + &self, + rng: impl CryptoRng + RngCore, + password: impl AsRef<[u8]>, + ) -> Result<SecretDocument> { + let der = Zeroizing::new(self.to_vec()?); + EncryptedPrivateKeyInfo::encrypt(rng, password, der.as_ref()) + } + + /// Encrypt this private key using a symmetric encryption key derived + /// from the provided password and [`pbes2::Parameters`]. + #[cfg(feature = "encryption")] + #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))] + pub fn encrypt_with_params( + &self, + pbes2_params: pbes2::Parameters<'_>, + password: impl AsRef<[u8]>, + ) -> Result<SecretDocument> { + let der = Zeroizing::new(self.to_vec()?); + EncryptedPrivateKeyInfo::encrypt_with(pbes2_params, password, der.as_ref()) + } +} + +impl<'a> DecodeValue<'a> for PrivateKeyInfo<'a> { + fn decode_value<R: Reader<'a>>( + reader: &mut R, + header: Header, + ) -> der::Result<PrivateKeyInfo<'a>> { + reader.read_nested(header.length, |reader| { + // Parse and validate `version` INTEGER. + let version = Version::decode(reader)?; + let algorithm = reader.decode()?; + let private_key = OctetStringRef::decode(reader)?.into(); + let public_key = reader + .context_specific::<BitStringRef<'_>>(PUBLIC_KEY_TAG, TagMode::Implicit)? + .map(|bs| { + bs.as_bytes() + .ok_or_else(|| der::Tag::BitString.value_error()) + }) + .transpose()?; + + if version.has_public_key() != public_key.is_some() { + return Err(reader.error( + der::Tag::ContextSpecific { + constructed: true, + number: PUBLIC_KEY_TAG, + } + .value_error() + .kind(), + )); + } + + // Ignore any remaining extension fields + while !reader.is_finished() { + reader.decode::<ContextSpecific<AnyRef<'_>>>()?; + } + + Ok(Self { + algorithm, + private_key, + public_key, + }) + }) + } +} + +impl<'a> Sequence<'a> for PrivateKeyInfo<'a> { + fn fields<F, T>(&self, f: F) -> der::Result<T> + where + F: FnOnce(&[&dyn Encode]) -> der::Result<T>, + { + f(&[ + &u8::from(self.version()), + &self.algorithm, + &OctetStringRef::new(self.private_key)?, + &self + .public_key + .map(|pk| { + BitStringRef::from_bytes(pk).map(|value| ContextSpecific { + tag_number: PUBLIC_KEY_TAG, + tag_mode: TagMode::Implicit, + value, + }) + }) + .transpose()?, + ]) + } +} + +impl<'a> TryFrom<&'a [u8]> for PrivateKeyInfo<'a> { + type Error = Error; + + fn try_from(bytes: &'a [u8]) -> Result<Self> { + Ok(Self::from_der(bytes)?) + } +} + +impl<'a> fmt::Debug for PrivateKeyInfo<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("PrivateKeyInfo") + .field("version", &self.version()) + .field("algorithm", &self.algorithm) + .field("public_key", &self.public_key) + .finish_non_exhaustive() + } +} + +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +impl TryFrom<PrivateKeyInfo<'_>> for SecretDocument { + type Error = Error; + + fn try_from(private_key: PrivateKeyInfo<'_>) -> Result<SecretDocument> { + SecretDocument::try_from(&private_key) + } +} + +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +impl TryFrom<&PrivateKeyInfo<'_>> for SecretDocument { + type Error = Error; + + fn try_from(private_key: &PrivateKeyInfo<'_>) -> Result<SecretDocument> { + Ok(Self::encode_msg(private_key)?) + } +} + +#[cfg(feature = "pem")] +#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] +impl PemLabel for PrivateKeyInfo<'_> { + const PEM_LABEL: &'static str = "PRIVATE KEY"; +} + +#[cfg(feature = "subtle")] +#[cfg_attr(docsrs, doc(cfg(feature = "subtle")))] +impl<'a> ConstantTimeEq for PrivateKeyInfo<'a> { + fn ct_eq(&self, other: &Self) -> Choice { + // NOTE: public fields are not compared in constant time + let public_fields_eq = + self.algorithm == other.algorithm && self.public_key == other.public_key; + + self.private_key.ct_eq(other.private_key) & Choice::from(public_fields_eq as u8) + } +} + +#[cfg(feature = "subtle")] +#[cfg_attr(docsrs, doc(cfg(feature = "subtle")))] +impl<'a> Eq for PrivateKeyInfo<'a> {} + +#[cfg(feature = "subtle")] +#[cfg_attr(docsrs, doc(cfg(feature = "subtle")))] +impl<'a> PartialEq for PrivateKeyInfo<'a> { + fn eq(&self, other: &Self) -> bool { + self.ct_eq(other).into() + } +} diff --git a/vendor/pkcs8/src/traits.rs b/vendor/pkcs8/src/traits.rs new file mode 100644 index 000000000..dd86b90ef --- /dev/null +++ b/vendor/pkcs8/src/traits.rs @@ -0,0 +1,145 @@ +//! Traits for parsing objects from PKCS#8 encoded documents + +use crate::{Error, PrivateKeyInfo, Result}; + +#[cfg(feature = "alloc")] +use der::SecretDocument; + +#[cfg(feature = "encryption")] +use { + crate::EncryptedPrivateKeyInfo, + rand_core::{CryptoRng, RngCore}, +}; + +#[cfg(feature = "pem")] +use {crate::LineEnding, alloc::string::String, der::zeroize::Zeroizing}; + +#[cfg(feature = "pem")] +use der::pem::PemLabel; + +#[cfg(feature = "std")] +use std::path::Path; + +/// Parse a private key object from a PKCS#8 encoded document. +pub trait DecodePrivateKey: for<'a> TryFrom<PrivateKeyInfo<'a>, Error = Error> + Sized { + /// Deserialize PKCS#8 private key from ASN.1 DER-encoded data + /// (binary format). + fn from_pkcs8_der(bytes: &[u8]) -> Result<Self> { + Self::try_from(PrivateKeyInfo::try_from(bytes)?) + } + + /// Deserialize encrypted PKCS#8 private key from ASN.1 DER-encoded data + /// (binary format) and attempt to decrypt it using the provided password. + #[cfg(feature = "encryption")] + #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))] + fn from_pkcs8_encrypted_der(bytes: &[u8], password: impl AsRef<[u8]>) -> Result<Self> { + let doc = EncryptedPrivateKeyInfo::try_from(bytes)?.decrypt(password)?; + Self::from_pkcs8_der(doc.as_bytes()) + } + + /// Deserialize PKCS#8-encoded private key from PEM. + /// + /// Keys in this format begin with the following delimiter: + /// + /// ```text + /// -----BEGIN PRIVATE KEY----- + /// ``` + #[cfg(feature = "pem")] + #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] + fn from_pkcs8_pem(s: &str) -> Result<Self> { + let (label, doc) = SecretDocument::from_pem(s)?; + PrivateKeyInfo::validate_pem_label(label)?; + Self::from_pkcs8_der(doc.as_bytes()) + } + + /// Deserialize encrypted PKCS#8-encoded private key from PEM and attempt + /// to decrypt it using the provided password. + /// + /// Keys in this format begin with the following delimiter: + /// + /// ```text + /// -----BEGIN ENCRYPTED PRIVATE KEY----- + /// ``` + #[cfg(all(feature = "encryption", feature = "pem"))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "encryption", feature = "pem"))))] + fn from_pkcs8_encrypted_pem(s: &str, password: impl AsRef<[u8]>) -> Result<Self> { + let (label, doc) = SecretDocument::from_pem(s)?; + EncryptedPrivateKeyInfo::validate_pem_label(label)?; + Self::from_pkcs8_encrypted_der(doc.as_bytes(), password) + } + + /// Load PKCS#8 private key 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_pkcs8_der_file(path: impl AsRef<Path>) -> Result<Self> { + Self::from_pkcs8_der(SecretDocument::read_der_file(path)?.as_bytes()) + } + + /// Load PKCS#8 private key from a PEM-encoded file on the local filesystem. + #[cfg(all(feature = "pem", feature = "std"))] + #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + fn read_pkcs8_pem_file(path: impl AsRef<Path>) -> Result<Self> { + let (label, doc) = SecretDocument::read_pem_file(path)?; + PrivateKeyInfo::validate_pem_label(&label)?; + Self::from_pkcs8_der(doc.as_bytes()) + } +} + +/// Serialize a private key object to a PKCS#8 encoded document. +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +pub trait EncodePrivateKey { + /// Serialize a [`SecretDocument`] containing a PKCS#8-encoded private key. + fn to_pkcs8_der(&self) -> Result<SecretDocument>; + + /// Create an [`SecretDocument`] containing the ciphertext of + /// a PKCS#8 encoded private key encrypted under the given `password`. + #[cfg(feature = "encryption")] + #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))] + fn to_pkcs8_encrypted_der( + &self, + rng: impl CryptoRng + RngCore, + password: impl AsRef<[u8]>, + ) -> Result<SecretDocument> { + EncryptedPrivateKeyInfo::encrypt(rng, password, self.to_pkcs8_der()?.as_bytes()) + } + + /// Serialize this private key as PEM-encoded PKCS#8 with the given [`LineEnding`]. + #[cfg(feature = "pem")] + #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] + fn to_pkcs8_pem(&self, line_ending: LineEnding) -> Result<Zeroizing<String>> { + let doc = self.to_pkcs8_der()?; + Ok(doc.to_pem(PrivateKeyInfo::PEM_LABEL, line_ending)?) + } + + /// Serialize this private key as an encrypted PEM-encoded PKCS#8 private + /// key using the `provided` to derive an encryption key. + #[cfg(all(feature = "encryption", feature = "pem"))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "encryption", feature = "pem"))))] + fn to_pkcs8_encrypted_pem( + &self, + rng: impl CryptoRng + RngCore, + password: impl AsRef<[u8]>, + line_ending: LineEnding, + ) -> Result<Zeroizing<String>> { + let doc = self.to_pkcs8_encrypted_der(rng, password)?; + Ok(doc.to_pem(EncryptedPrivateKeyInfo::PEM_LABEL, line_ending)?) + } + + /// Write ASN.1 DER-encoded PKCS#8 private key to the given path + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] + fn write_pkcs8_der_file(&self, path: impl AsRef<Path>) -> Result<()> { + Ok(self.to_pkcs8_der()?.write_der_file(path)?) + } + + /// Write ASN.1 DER-encoded PKCS#8 private key to the given path + #[cfg(all(feature = "pem", feature = "std"))] + #[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "std"))))] + fn write_pkcs8_pem_file(&self, path: impl AsRef<Path>, line_ending: LineEnding) -> Result<()> { + let doc = self.to_pkcs8_der()?; + Ok(doc.write_pem_file(path, PrivateKeyInfo::PEM_LABEL, line_ending)?) + } +} diff --git a/vendor/pkcs8/src/version.rs b/vendor/pkcs8/src/version.rs new file mode 100644 index 000000000..339368392 --- /dev/null +++ b/vendor/pkcs8/src/version.rs @@ -0,0 +1,63 @@ +//! PKCS#8 version identifier. + +use crate::Error; +use der::{Decode, Encode, FixedTag, Reader, Tag, Writer}; + +/// Version identifier for PKCS#8 documents. +/// +/// (RFC 5958 designates `0` and `1` as the only valid versions for PKCS#8 documents) +#[derive(Clone, Debug, Copy, PartialEq)] +pub enum Version { + /// Denotes PKCS#8 v1: no public key field. + V1 = 0, + + /// Denotes PKCS#8 v2: `OneAsymmetricKey` with public key field. + V2 = 1, +} + +impl Version { + /// Is this version expected to have a public key? + pub fn has_public_key(self) -> bool { + match self { + Version::V1 => false, + Version::V2 => true, + } + } +} + +impl<'a> Decode<'a> for Version { + fn decode<R: Reader<'a>>(decoder: &mut R) -> der::Result<Self> { + Version::try_from(u8::decode(decoder)?).map_err(|_| Self::TAG.value_error()) + } +} + +impl Encode for Version { + fn encoded_len(&self) -> der::Result<der::Length> { + der::Length::from(1u8).for_tlv() + } + + fn encode(&self, writer: &mut dyn Writer) -> der::Result<()> { + u8::from(*self).encode(writer) + } +} + +impl From<Version> for u8 { + fn from(version: Version) -> Self { + version as u8 + } +} + +impl TryFrom<u8> for Version { + type Error = Error; + fn try_from(byte: u8) -> Result<Version, Error> { + match byte { + 0 => Ok(Version::V1), + 1 => Ok(Version::V2), + _ => Err(Self::TAG.value_error().into()), + } + } +} + +impl FixedTag for Version { + const TAG: Tag = Tag::Integer; +} diff --git a/vendor/pkcs8/tests/encrypted_private_key.rs b/vendor/pkcs8/tests/encrypted_private_key.rs new file mode 100644 index 000000000..2bd72aef9 --- /dev/null +++ b/vendor/pkcs8/tests/encrypted_private_key.rs @@ -0,0 +1,234 @@ +//! Encrypted PKCS#8 private key tests. + +#![cfg(feature = "pkcs5")] + +use hex_literal::hex; +use pkcs8::{pkcs5::pbes2, EncryptedPrivateKeyInfo, PrivateKeyInfo}; + +#[cfg(feature = "alloc")] +use der::Encode; + +#[cfg(feature = "pem")] +use der::EncodePem; + +/// Ed25519 PKCS#8 private key plaintext encoded as ASN.1 DER +#[cfg(feature = "encryption")] +const ED25519_DER_PLAINTEXT_EXAMPLE: &[u8] = include_bytes!("examples/ed25519-priv-pkcs8v1.der"); + +/// Ed25519 PKCS#8 encrypted private key (PBES2 + AES-128-CBC + PBKDF2-SHA1) encoded as ASN.1 DER. +/// +/// Generated using: +/// +/// ``` +/// $ openssl pkcs8 -v2 aes256-cbc -v2prf hmacWithSHA1 -topk8 -inform der -in ed25519-priv.der -outform der -out ed25519-encpriv-aes128-pbkdf2-sha1.der +/// ``` +const ED25519_DER_AES128_PBKDF2_SHA1_EXAMPLE: &[u8] = + include_bytes!("examples/ed25519-encpriv-aes128-pbkdf2-sha1.der"); + +/// Ed25519 PKCS#8 encrypted private key (PBES2 + AES-256-CBC + PBKDF2-SHA256) encoded as ASN.1 DER. +/// +/// Generated using: +/// +/// ``` +/// $ openssl pkcs8 -v2 aes256-cbc -v2prf hmacWithSHA256 -topk8 -inform der -in ed25519-priv.der -outform der -out ed25519-encpriv-aes256-pbkdf2-sha256.der +/// ``` +const ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE: &[u8] = + include_bytes!("examples/ed25519-encpriv-aes256-pbkdf2-sha256.der"); + +/// Ed25519 PKCS#8 encrypted private key (PBES2 + AES-256-CBC + scrypt) encoded as ASN.1 DER. +/// +/// Generated using: +/// +/// ``` +/// $ openssl pkcs8 -v2 aes256-cbc -scrypt -topk8 -inform der -in ed25519-priv.der -outform der -out ed25519-encpriv-aes256-scrypt.der +/// ``` +#[cfg(feature = "encryption")] +const ED25519_DER_AES256_SCRYPT_EXAMPLE: &[u8] = + include_bytes!("examples/ed25519-encpriv-aes256-scrypt.der"); + +/// Ed25519 PKCS#8 encrypted private key encoded as PEM +#[cfg(feature = "pem")] +const ED25519_PEM_AES256_PBKDF2_SHA256_EXAMPLE: &str = + include_str!("examples/ed25519-encpriv-aes256-pbkdf2-sha256.pem"); + +/// Ed25519 PKCS#8 encrypted private key (PBES2 + 3DES + PBKDF2-SHA256) encoded as ASN.1 DER +/// +/// Generated using: +/// +/// ``` +/// $ openssl pkcs8 -v2 des3 -topk8 -inform der -in ed25519-priv-pkcs8v1.der -outform der -out ed25519-encpriv-des3-pbkdf2-sha256.der +/// ``` +#[cfg(feature = "3des")] +const ED25519_DER_DES3_PBKDF2_SHA256_EXAMPLE: &[u8] = + include_bytes!("examples/ed25519-encpriv-des3-pbkdf2-sha256.der"); + +/// Ed25519 PKCS#8 encrypted private key (PBES2 + DES + PBKDF2-SHA256) encoded as ASN.1 DER +/// +/// Generated using: +/// +/// ``` +/// $ openssl pkcs8 -v2 des -topk8 -inform der -in ed25519-priv-pkcs8v1.der -outform der -out ed25519-encpriv-des3-pbkdf2-sha256.der +/// ``` +#[cfg(feature = "des-insecure")] +const ED25519_DER_DES_PBKDF2_SHA256_EXAMPLE: &[u8] = + include_bytes!("examples/ed25519-encpriv-des-pbkdf2-sha256.der"); + +/// Password used to encrypt the keys. +#[cfg(feature = "encryption")] +const PASSWORD: &[u8] = b"hunter42"; // Bad password; don't actually use outside tests! + +#[test] +fn decode_ed25519_encpriv_aes128_pbkdf2_sha1_der() { + let pk = EncryptedPrivateKeyInfo::try_from(ED25519_DER_AES128_PBKDF2_SHA1_EXAMPLE).unwrap(); + + assert_eq!( + pk.encryption_algorithm.oid(), + "1.2.840.113549.1.5.13".parse().unwrap() + ); // PBES2 + + let pbes2_params = pk.encryption_algorithm.pbes2().unwrap(); + let pbkdf2_params = pbes2_params.kdf.pbkdf2().unwrap(); + + assert_eq!(pbkdf2_params.salt, hex!("e8765e01e43b6bad")); + assert_eq!(pbkdf2_params.iteration_count, 2048); + assert_eq!(pbkdf2_params.key_length, None); + assert_eq!(pbkdf2_params.prf, pbes2::Pbkdf2Prf::HmacWithSha1); + + match pbes2_params.encryption { + pbes2::EncryptionScheme::Aes128Cbc { iv } => { + assert_eq!(iv, &hex!("223080a71bcd2b9a256d876c924979d2")); + } + other => panic!("unexpected encryption scheme: {:?}", other), + } + + // Extracted with: + // $ openssl asn1parse -inform der -in tests/examples/ed25519-encpriv-aes128-sha1.der + assert_eq!( + pk.encrypted_data, + &hex!("4B4D091548EAC381EE7663B21234CD4FF3C9DF664D713394CACCEA7C9B982BD8F29910FABCA4BF7BE0431FAC5C4D657BE997C1F5BF40E2DA465AC1FCC2E30470") + ); +} + +#[test] +fn decode_ed25519_encpriv_aes256_pbkdf2_sha256_der() { + let pk = EncryptedPrivateKeyInfo::try_from(ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE).unwrap(); + + assert_eq!( + pk.encryption_algorithm.oid(), + "1.2.840.113549.1.5.13".parse().unwrap() + ); // PBES2 + + let pbes2_params = pk.encryption_algorithm.pbes2().unwrap(); + let pbkdf2_params = pbes2_params.kdf.pbkdf2().unwrap(); + + assert_eq!(pbkdf2_params.salt, hex!("79d982e70df91a88")); + assert_eq!(pbkdf2_params.iteration_count, 2048); + assert_eq!(pbkdf2_params.key_length, None); + assert_eq!(pbkdf2_params.prf, pbes2::Pbkdf2Prf::HmacWithSha256); + + match pbes2_params.encryption { + pbes2::EncryptionScheme::Aes256Cbc { iv } => { + assert_eq!(iv, &hex!("b2d02d78b2efd9dff694cf8e0af40925")); + } + other => panic!("unexpected encryption scheme: {:?}", other), + } + + // Extracted with: + // $ openssl asn1parse -inform der -in tests/examples/ed25519-encpriv-aes256-sha256.der + assert_eq!( + pk.encrypted_data, + &hex!("D0CD6C770F4BB87176422305C17401809E226674CE74185D221BFDAA95069890C8882FCE02B05D41BCBF54B035595BCD4154B32593708469B86AACF8815A7B2B") + ); +} + +#[cfg(feature = "encryption")] +#[test] +fn decrypt_ed25519_der_encpriv_aes256_pbkdf2_sha256() { + let enc_pk = + EncryptedPrivateKeyInfo::try_from(ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE).unwrap(); + let pk = enc_pk.decrypt(PASSWORD).unwrap(); + assert_eq!(pk.as_bytes(), ED25519_DER_PLAINTEXT_EXAMPLE); +} + +#[cfg(feature = "encryption")] +#[test] +fn decrypt_ed25519_der_encpriv_aes256_scrypt() { + let enc_pk = EncryptedPrivateKeyInfo::try_from(ED25519_DER_AES256_SCRYPT_EXAMPLE).unwrap(); + let pk = enc_pk.decrypt(PASSWORD).unwrap(); + assert_eq!(pk.as_bytes(), ED25519_DER_PLAINTEXT_EXAMPLE); +} + +#[cfg(feature = "encryption")] +#[test] +fn encrypt_ed25519_der_encpriv_aes256_pbkdf2_sha256() { + let pbes2_params = pkcs5::pbes2::Parameters::pbkdf2_sha256_aes256cbc( + 2048, + &hex!("79d982e70df91a88"), + &hex!("b2d02d78b2efd9dff694cf8e0af40925"), + ) + .unwrap(); + + let pk_plaintext = PrivateKeyInfo::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); + let pk_encrypted = pk_plaintext + .encrypt_with_params(pbes2_params, PASSWORD) + .unwrap(); + + assert_eq!( + pk_encrypted.as_bytes(), + ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE + ); +} + +#[cfg(feature = "encryption")] +#[test] +fn encrypt_ed25519_der_encpriv_aes256_scrypt() { + let scrypt_params = pkcs5::pbes2::Parameters::scrypt_aes256cbc( + Default::default(), + &hex!("E6211E2348AD69E0"), + &hex!("9BD0A6251F2254F9FD5963887C27CF01"), + ) + .unwrap(); + + let pk_plaintext = PrivateKeyInfo::try_from(ED25519_DER_PLAINTEXT_EXAMPLE).unwrap(); + let pk_encrypted = pk_plaintext + .encrypt_with_params(scrypt_params, PASSWORD) + .unwrap(); + + assert_eq!(pk_encrypted.as_bytes(), ED25519_DER_AES256_SCRYPT_EXAMPLE); +} + +#[test] +#[cfg(feature = "alloc")] +fn encode_ed25519_encpriv_aes256_pbkdf2_sha256_der() { + let pk = EncryptedPrivateKeyInfo::try_from(ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE).unwrap(); + assert_eq!( + ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE, + &pk.to_vec().unwrap() + ); +} + +#[test] +#[cfg(feature = "pem")] +fn encode_ed25519_encpriv_aes256_pbkdf2_sha256_pem() { + let pk = EncryptedPrivateKeyInfo::try_from(ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE).unwrap(); + assert_eq!( + ED25519_PEM_AES256_PBKDF2_SHA256_EXAMPLE, + pk.to_pem(Default::default()).unwrap() + ); +} + +#[test] +#[cfg(feature = "3des")] +fn decrypt_ed25519_der_encpriv_des3_pbkdf2_sha256() { + let enc_pk = EncryptedPrivateKeyInfo::try_from(ED25519_DER_DES3_PBKDF2_SHA256_EXAMPLE).unwrap(); + let pk = enc_pk.decrypt(PASSWORD).unwrap(); + assert_eq!(pk.as_bytes(), ED25519_DER_PLAINTEXT_EXAMPLE); +} + +#[test] +#[cfg(feature = "des-insecure")] +fn decrypt_ed25519_der_encpriv_des_pbkdf2_sha256() { + let enc_pk = EncryptedPrivateKeyInfo::try_from(ED25519_DER_DES_PBKDF2_SHA256_EXAMPLE).unwrap(); + let pk = enc_pk.decrypt(PASSWORD).unwrap(); + assert_eq!(pk.as_bytes(), ED25519_DER_PLAINTEXT_EXAMPLE); +} diff --git a/vendor/pkcs8/tests/examples/ed25519-encpriv-aes128-pbkdf2-sha1.der b/vendor/pkcs8/tests/examples/ed25519-encpriv-aes128-pbkdf2-sha1.der Binary files differnew file mode 100644 index 000000000..c8d6edf7c --- /dev/null +++ b/vendor/pkcs8/tests/examples/ed25519-encpriv-aes128-pbkdf2-sha1.der diff --git a/vendor/pkcs8/tests/examples/ed25519-encpriv-aes256-pbkdf2-sha256.der b/vendor/pkcs8/tests/examples/ed25519-encpriv-aes256-pbkdf2-sha256.der Binary files differnew file mode 100644 index 000000000..5170c06e4 --- /dev/null +++ b/vendor/pkcs8/tests/examples/ed25519-encpriv-aes256-pbkdf2-sha256.der diff --git a/vendor/pkcs8/tests/examples/ed25519-encpriv-aes256-pbkdf2-sha256.pem b/vendor/pkcs8/tests/examples/ed25519-encpriv-aes256-pbkdf2-sha256.pem new file mode 100644 index 000000000..e5d3207a6 --- /dev/null +++ b/vendor/pkcs8/tests/examples/ed25519-encpriv-aes256-pbkdf2-sha256.pem @@ -0,0 +1,6 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIGbMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAh52YLnDfkaiAICCAAw +DAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEELLQLXiy79nf9pTPjgr0CSUEQNDN +bHcPS7hxdkIjBcF0AYCeImZ0znQYXSIb/aqVBpiQyIgvzgKwXUG8v1SwNVlbzUFU +syWTcIRpuGqs+IFaeys= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/vendor/pkcs8/tests/examples/ed25519-encpriv-aes256-scrypt.der b/vendor/pkcs8/tests/examples/ed25519-encpriv-aes256-scrypt.der Binary files differnew file mode 100644 index 000000000..a045982f7 --- /dev/null +++ b/vendor/pkcs8/tests/examples/ed25519-encpriv-aes256-scrypt.der diff --git a/vendor/pkcs8/tests/examples/ed25519-encpriv-aes256-scrypt.pem b/vendor/pkcs8/tests/examples/ed25519-encpriv-aes256-scrypt.pem new file mode 100644 index 000000000..1f0562d80 --- /dev/null +++ b/vendor/pkcs8/tests/examples/ed25519-encpriv-aes256-scrypt.pem @@ -0,0 +1,6 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIGTME8GCSqGSIb3DQEFDTBCMCEGCSsGAQQB2kcECzAUBAjmIR4jSK1p4AICQAAC +AQgCAQEwHQYJYIZIAWUDBAEqBBCb0KYlHyJU+f1ZY4h8J88BBEDMYrp3PA9JX6s2 +aOT8782wjnig7hXgoVAT9iq+CNqnQgZe6zZtbmyYzDsOfmm9yGHIiv648D26Hixt +mdBtFzYM +-----END ENCRYPTED PRIVATE KEY----- diff --git a/vendor/pkcs8/tests/examples/ed25519-encpriv-des-pbkdf2-sha256.der b/vendor/pkcs8/tests/examples/ed25519-encpriv-des-pbkdf2-sha256.der Binary files differnew file mode 100644 index 000000000..85d3b83b2 --- /dev/null +++ b/vendor/pkcs8/tests/examples/ed25519-encpriv-des-pbkdf2-sha256.der diff --git a/vendor/pkcs8/tests/examples/ed25519-encpriv-des3-pbkdf2-sha256.der b/vendor/pkcs8/tests/examples/ed25519-encpriv-des3-pbkdf2-sha256.der Binary files differnew file mode 100644 index 000000000..aed05ab63 --- /dev/null +++ b/vendor/pkcs8/tests/examples/ed25519-encpriv-des3-pbkdf2-sha256.der diff --git a/vendor/pkcs8/tests/examples/ed25519-priv-pkcs8v1.der b/vendor/pkcs8/tests/examples/ed25519-priv-pkcs8v1.der Binary files differnew file mode 100644 index 000000000..0cfccc399 --- /dev/null +++ b/vendor/pkcs8/tests/examples/ed25519-priv-pkcs8v1.der diff --git a/vendor/pkcs8/tests/examples/ed25519-priv-pkcs8v1.pem b/vendor/pkcs8/tests/examples/ed25519-priv-pkcs8v1.pem new file mode 100644 index 000000000..0c0ee10b4 --- /dev/null +++ b/vendor/pkcs8/tests/examples/ed25519-priv-pkcs8v1.pem @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIBftnHPp22SewYmmEoMcX8VwI4IHwaqd+9LFPj/15eqF +-----END PRIVATE KEY----- diff --git a/vendor/pkcs8/tests/examples/ed25519-priv-pkcs8v2.der b/vendor/pkcs8/tests/examples/ed25519-priv-pkcs8v2.der Binary files differnew file mode 100644 index 000000000..3358e8a73 --- /dev/null +++ b/vendor/pkcs8/tests/examples/ed25519-priv-pkcs8v2.der diff --git a/vendor/pkcs8/tests/examples/ed25519-priv-pkcs8v2.pem b/vendor/pkcs8/tests/examples/ed25519-priv-pkcs8v2.pem new file mode 100644 index 000000000..84961082a --- /dev/null +++ b/vendor/pkcs8/tests/examples/ed25519-priv-pkcs8v2.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MHICAQEwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC +oB8wHQYKKoZIhvcNAQkJFDEPDA1DdXJkbGUgQ2hhaXJzgSEAGb9ECWmEzf6FQbrB +Z9w7lshQhqowtrbLDFw4rXAxZuE= +-----END PRIVATE KEY----- diff --git a/vendor/pkcs8/tests/examples/ed25519-pub.der b/vendor/pkcs8/tests/examples/ed25519-pub.der Binary files differnew file mode 100644 index 000000000..1b602ee1f --- /dev/null +++ b/vendor/pkcs8/tests/examples/ed25519-pub.der diff --git a/vendor/pkcs8/tests/examples/ed25519-pub.pem b/vendor/pkcs8/tests/examples/ed25519-pub.pem new file mode 100644 index 000000000..6891701f7 --- /dev/null +++ b/vendor/pkcs8/tests/examples/ed25519-pub.pem @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEATSkWfz8ZEqb3rfopOgUaFcBexnuPFyZ7HFVQ3OhTvQ0= +-----END PUBLIC KEY----- diff --git a/vendor/pkcs8/tests/examples/p256-priv.der b/vendor/pkcs8/tests/examples/p256-priv.der Binary files differnew file mode 100644 index 000000000..c0de45ef2 --- /dev/null +++ b/vendor/pkcs8/tests/examples/p256-priv.der diff --git a/vendor/pkcs8/tests/examples/p256-priv.pem b/vendor/pkcs8/tests/examples/p256-priv.pem new file mode 100644 index 000000000..09b9343c0 --- /dev/null +++ b/vendor/pkcs8/tests/examples/p256-priv.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgaWJBcVYaYzQN4OfY +afKgVJJVjhoEhotqn4VKhmeIGI2hRANCAAQcrP+1Xy8s79idies3SyaBFSRSgC3u +oJkWBoE32DnPf8SBpESSME1+9mrBF77+g6jQjxVfK1L59hjdRHApBI4P +-----END PRIVATE KEY----- diff --git a/vendor/pkcs8/tests/examples/p256-pub.der b/vendor/pkcs8/tests/examples/p256-pub.der Binary files differnew file mode 100644 index 000000000..67c719c76 --- /dev/null +++ b/vendor/pkcs8/tests/examples/p256-pub.der diff --git a/vendor/pkcs8/tests/examples/p256-pub.pem b/vendor/pkcs8/tests/examples/p256-pub.pem new file mode 100644 index 000000000..ee7e5b612 --- /dev/null +++ b/vendor/pkcs8/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/pkcs8/tests/examples/rsa2048-priv.der b/vendor/pkcs8/tests/examples/rsa2048-priv.der Binary files differnew file mode 100644 index 000000000..f4590bbee --- /dev/null +++ b/vendor/pkcs8/tests/examples/rsa2048-priv.der diff --git a/vendor/pkcs8/tests/examples/rsa2048-priv.pem b/vendor/pkcs8/tests/examples/rsa2048-priv.pem new file mode 100644 index 000000000..e2a218c86 --- /dev/null +++ b/vendor/pkcs8/tests/examples/rsa2048-priv.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2xCxRXxCmqvKC +xj7b4kJDoXDz+iYzvUgzY39Hyk9vNuA6XSnvwxkayA85DYdLOeMPQU/Owfyg7YHl +R+3CzTgsdvYckBiXPbn6U3lyp8cB9rd+CYLfwV/AGSfuXnzZS09Zn/BwE6fIKBvf +Ity8mtfKu3xDEcmC9Y7bchOtRVizMiZtdDrtgZLRiEytuLFHOaja2mbclwgG2ces +RQyxPQ18V1+xmFNPxhvEG8DwV04OATDHu7+9/cn2puLj4q/xy+rIm6V4hFKNVc+w +gyeh6MifTgA88oiOkzJB2daVvLus3JC0Tj4JX6NwWOolsT9eKVy+rG3oOKuMUK9h +4piXW4cvAgMBAAECggEAfsyDYsDtsHQRZCFeIvdKudkboGkAcAz2NpDlEU2O5r3P +uy4/lhRpKmd6CD8Wil5S5ZaOZAe52XxuDkBk+C2gt1ihTxe5t9QfX0jijWVRcE9W +5p56qfpjD8dkKMBtJeRV3PxVt6wrT3ZkP97T/hX/eKuyfmWsxKrQvfbbJ+9gppEM +XEoIXtQydasZwdmXoyxu/8598tGTX25gHu3hYaErXMJ8oh+B0smcPR6gjpDjBTqw +m++nJN7w0MOjwel0DA2fdhJqFJ7Aqn2AeCBUhCVNlR2wfEz5H7ZFTAlliP1ZJNur +6zWcogJSaNAE+dZus9b3rcETm61A8W3eY54RZHN2wQKBgQDcwGEkLU6Sr67nKsUT +ymW593A2+b1+Dm5hRhp+92VCJewVPH5cMaYVem5aE/9uF46HWMHLM9nWu+MXnvGJ +mOQi7Ny+149Oz9vl9PzYrsLJ0NyGRzypvRbZ0jjSH7Xd776xQ8ph0L1qqNkfM6CX +eQ6WQNvJEIXcXyY0O6MTj2stZwKBgQDT8xR1fkDpVINvkr4kI2ry8NoEo0ZTwYCv +Z+lgCG2T/eZcsj79nQk3R2L1mB42GEmvaM3XU5T/ak4G62myCeQijbLfpw5A9/l1 +ClKBdmR7eI0OV3eiy4si480mf/cLTzsC06r7DhjFkKVksDGIsKpfxIFWsHYiIUJD +vRIn76fy+QKBgQDOaLesGw0QDWNuVUiHU8XAmEP9s5DicF33aJRXyb2Nl2XjCXhh +fi78gEj0wyQgbbhgh7ZU6Xuz1GTn7j+M2D/hBDb33xjpqWPE5kkR1n7eNAQvLibj +06GtNGra1rm39ncIywlOYt7p/01dZmmvmIryJV0c6O0xfGp9hpHaNU0S2wKBgCX2 +5ZRCIChrTfu/QjXA7lhD0hmAkYlRINbKeyALgm0+znOOLgBJj6wKKmypacfww8oa +sLxAKXEyvnU4177fTLDvxrmO99ulT1aqmaq85TTEnCeUfUZ4xRxjx4x84WhyMbTI +61h65u8EgMuvT8AXPP1Yen5nr1FfubnedREYOXIpAoGAMZlUBtQGIHyt6uo1s40E +DF+Kmhrggn6e0GsVPYO2ghk1tLNqgr6dVseRtYwnJxpXk9U6HWV8CJl5YLFDPlFx +mH9FLxRKfHIwbWPh0//Atxt1qwjy5FpILpiEUcvkeOEusijQdFbJJLZvbO0EjYU/ +Uz4xpoYU8cPObY7JmDznKvc= +-----END PRIVATE KEY----- diff --git a/vendor/pkcs8/tests/examples/rsa2048-pub.der b/vendor/pkcs8/tests/examples/rsa2048-pub.der Binary files differnew file mode 100644 index 000000000..4148aaaaa --- /dev/null +++ b/vendor/pkcs8/tests/examples/rsa2048-pub.der diff --git a/vendor/pkcs8/tests/examples/rsa2048-pub.pem b/vendor/pkcs8/tests/examples/rsa2048-pub.pem new file mode 100644 index 000000000..5ecd89239 --- /dev/null +++ b/vendor/pkcs8/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/pkcs8/tests/examples/x25519-priv.der b/vendor/pkcs8/tests/examples/x25519-priv.der Binary files differnew file mode 100644 index 000000000..79355d27c --- /dev/null +++ b/vendor/pkcs8/tests/examples/x25519-priv.der diff --git a/vendor/pkcs8/tests/examples/x25519-priv.pem b/vendor/pkcs8/tests/examples/x25519-priv.pem new file mode 100644 index 000000000..501f95da6 --- /dev/null +++ b/vendor/pkcs8/tests/examples/x25519-priv.pem @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VuBCIEIHBgJSkzrG56SpsOsmMsWgQKhyV624aaPszD0WtyTyZH +-----END PRIVATE KEY----- diff --git a/vendor/pkcs8/tests/private_key.rs b/vendor/pkcs8/tests/private_key.rs new file mode 100644 index 000000000..15d669495 --- /dev/null +++ b/vendor/pkcs8/tests/private_key.rs @@ -0,0 +1,182 @@ +//! PKCS#8 private key tests + +use hex_literal::hex; +use pkcs8::{PrivateKeyInfo, Version}; + +#[cfg(feature = "alloc")] +use der::Encode; + +#[cfg(feature = "pem")] +use der::{pem::LineEnding, EncodePem}; + +/// Elliptic Curve (P-256) PKCS#8 private key encoded as ASN.1 DER +const EC_P256_DER_EXAMPLE: &[u8] = include_bytes!("examples/p256-priv.der"); + +/// Ed25519 PKCS#8 v1 private key encoded as ASN.1 DER +const ED25519_DER_V1_EXAMPLE: &[u8] = include_bytes!("examples/ed25519-priv-pkcs8v1.der"); + +/// Ed25519 PKCS#8 v2 private key + public key encoded as ASN.1 DER +const ED25519_DER_V2_EXAMPLE: &[u8] = include_bytes!("examples/ed25519-priv-pkcs8v2.der"); + +/// RSA-2048 PKCS#8 private key encoded as ASN.1 DER +const RSA_2048_DER_EXAMPLE: &[u8] = include_bytes!("examples/rsa2048-priv.der"); + +/// X25519 PKCS#8 private key encoded as ASN.1 DER +const X25519_DER_EXAMPLE: &[u8] = include_bytes!("examples/x25519-priv.der"); + +/// Elliptic Curve (P-256) PKCS#8 private key encoded as PEM +#[cfg(feature = "pem")] +const EC_P256_PEM_EXAMPLE: &str = include_str!("examples/p256-priv.pem"); + +/// Ed25519 PKCS#8 private key encoded as PEM +#[cfg(feature = "pem")] +const ED25519_PEM_V1_EXAMPLE: &str = include_str!("examples/ed25519-priv-pkcs8v1.pem"); + +/// RSA-2048 PKCS#8 private key encoded as PEM +#[cfg(feature = "pem")] +const RSA_2048_PEM_EXAMPLE: &str = include_str!("examples/rsa2048-priv.pem"); + +/// X25519 PKCS#8 private key encoded as PEM +#[cfg(feature = "pem")] +const X25519_PEM_EXAMPLE: &str = include_str!("examples/x25519-priv.pem"); + +#[test] +fn decode_ec_p256_der() { + let pk = PrivateKeyInfo::try_from(EC_P256_DER_EXAMPLE).unwrap(); + + assert_eq!(pk.version(), Version::V1); + assert_eq!(pk.algorithm.oid, "1.2.840.10045.2.1".parse().unwrap()); + + assert_eq!( + pk.algorithm.parameters.unwrap().oid().unwrap(), + "1.2.840.10045.3.1.7".parse().unwrap() + ); + + // Extracted with: + // $ openssl asn1parse -inform der -in tests/examples/p256-priv.der + assert_eq!(pk.private_key, &hex!("306B020101042069624171561A63340DE0E7D869F2A05492558E1A04868B6A9F854A866788188DA144034200041CACFFB55F2F2CEFD89D89EB374B2681152452802DEEA09916068137D839CF7FC481A44492304D7EF66AC117BEFE83A8D08F155F2B52F9F618DD447029048E0F")[..]); +} + +// Test vector from RFC8410 Section 10.3: +// https://datatracker.ietf.org/doc/html/rfc8410#section-10.3 +#[test] +fn decode_ed25519_der_v1() { + let pk = PrivateKeyInfo::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); + assert_eq!(pk.version(), Version::V1); + assert_eq!(pk.algorithm.oid, "1.3.101.112".parse().unwrap()); + assert_eq!(pk.algorithm.parameters, None); + + // Extracted with: + // $ openssl asn1parse -inform der -in tests/examples/ed25519-priv.der + assert_eq!( + pk.private_key, + &hex!("042017ED9C73E9DB649EC189A612831C5FC570238207C1AA9DFBD2C53E3FF5E5EA85")[..] + ); +} + +// Test vector from RFC8410 Section 10.3: +// https://datatracker.ietf.org/doc/html/rfc8410#section-10.3 +#[test] +fn decode_ed25519_der_v2() { + // Extracted with: + // $ openssl asn1parse -inform der -in tests/examples/ed25519-priv-pkcs8v2.der + const PRIV_KEY: [u8; 34] = + hex!("0420D4EE72DBF913584AD5B6D8F1F769F8AD3AFE7C28CBF1D4FBE097A88F44755842"); + const PUB_KEY: [u8; 32] = + hex!("19BF44096984CDFE8541BAC167DC3B96C85086AA30B6B6CB0C5C38AD703166E1"); + + let pk = PrivateKeyInfo::try_from(ED25519_DER_V2_EXAMPLE).unwrap(); + assert_eq!(pk.version(), Version::V2); + assert_eq!(pk.algorithm.oid, "1.3.101.112".parse().unwrap()); + assert_eq!(pk.algorithm.parameters, None); + assert_eq!(pk.private_key, PRIV_KEY); + assert_eq!(pk.public_key, Some(&PUB_KEY[..])); +} + +#[test] +fn decode_rsa_2048_der() { + let pk = PrivateKeyInfo::try_from(RSA_2048_DER_EXAMPLE).unwrap(); + assert_eq!(pk.version(), Version::V1); + assert_eq!(pk.algorithm.oid, "1.2.840.113549.1.1.1".parse().unwrap()); + assert!(pk.algorithm.parameters.unwrap().is_null()); + + // Extracted with: + // $ openssl asn1parse -inform der -in tests/examples/rsa2048-priv.der + assert_eq!(pk.private_key, &hex!("308204A30201000282010100B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C76F61C9018973DB9FA537972A7C701F6B77E0982DFC15FC01927EE5E7CD94B4F599FF07013A7C8281BDF22DCBC9AD7CABB7C4311C982F58EDB7213AD4558B332266D743AED8192D1884CADB8B14739A8DADA66DC970806D9C7AC450CB13D0D7C575FB198534FC61BC41BC0F0574E0E0130C7BBBFBDFDC9F6A6E2E3E2AFF1CBEAC89BA57884528D55CFB08327A1E8C89F4E003CF2888E933241D9D695BCBBACDC90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F0203010001028201007ECC8362C0EDB0741164215E22F74AB9D91BA06900700CF63690E5114D8EE6BDCFBB2E3F9614692A677A083F168A5E52E5968E6407B9D97C6E0E4064F82DA0B758A14F17B9B7D41F5F48E28D6551704F56E69E7AA9FA630FC76428C06D25E455DCFC55B7AC2B4F76643FDED3FE15FF78ABB27E65ACC4AAD0BDF6DB27EF60A6910C5C4A085ED43275AB19C1D997A32C6EFFCE7DF2D1935F6E601EEDE161A12B5CC27CA21F81D2C99C3D1EA08E90E3053AB09BEFA724DEF0D0C3A3C1E9740C0D9F76126A149EC0AA7D8078205484254D951DB07C4CF91FB6454C096588FD5924DBABEB359CA2025268D004F9D66EB3D6F7ADC1139BAD40F16DDE639E11647376C102818100DCC061242D4E92AFAEE72AC513CA65B9F77036F9BD7E0E6E61461A7EF7654225EC153C7E5C31A6157A6E5A13FF6E178E8758C1CB33D9D6BBE3179EF18998E422ECDCBED78F4ECFDBE5F4FCD8AEC2C9D0DC86473CA9BD16D9D238D21FB5DDEFBEB143CA61D0BD6AA8D91F33A097790E9640DBC91085DC5F26343BA3138F6B2D6702818100D3F314757E40E954836F92BE24236AF2F0DA04A34653C180AF67E960086D93FDE65CB23EFD9D09374762F5981E361849AF68CDD75394FF6A4E06EB69B209E4228DB2DFA70E40F7F9750A528176647B788D0E5777A2CB8B22E3CD267FF70B4F3B02D3AAFB0E18C590A564B03188B0AA5FC48156B07622214243BD1227EFA7F2F902818100CE68B7AC1B0D100D636E55488753C5C09843FDB390E2705DF7689457C9BD8D9765E30978617E2EFC8048F4C324206DB86087B654E97BB3D464E7EE3F8CD83FE10436F7DF18E9A963C4E64911D67EDE34042F2E26E3D3A1AD346ADAD6B9B7F67708CB094E62DEE9FF4D5D6669AF988AF2255D1CE8ED317C6A7D8691DA354D12DB02818025F6E5944220286B4DFBBF4235C0EE5843D2198091895120D6CA7B200B826D3ECE738E2E00498FAC0A2A6CA969C7F0C3CA1AB0BC40297132BE7538D7BEDF4CB0EFC6B98EF7DBA54F56AA99AABCE534C49C27947D4678C51C63C78C7CE1687231B4C8EB587AE6EF0480CBAF4FC0173CFD587A7E67AF515FB9B9DE75111839722902818031995406D406207CADEAEA35B38D040C5F8A9A1AE0827E9ED06B153D83B6821935B4B36A82BE9D56C791B58C27271A5793D53A1D657C08997960B1433E5171987F452F144A7C72306D63E1D3FFC0B71B75AB08F2E45A482E988451CBE478E12EB228D07456C924B66F6CED048D853F533E31A68614F1C3CE6D8EC9983CE72AF7")[..]); +} + +#[test] +fn decode_x25519_der() { + let pk = PrivateKeyInfo::try_from(X25519_DER_EXAMPLE).unwrap(); + assert_eq!(pk.version(), Version::V1); + assert_eq!(pk.algorithm.oid, "1.3.101.110".parse().unwrap()); + assert_eq!(pk.algorithm.parameters, None); + + // Extracted with: + // $ openssl asn1parse -inform der -in tests/examples/x25519-priv.der + assert_eq!( + pk.private_key, + &hex!("04207060252933AC6E7A4A9B0EB2632C5A040A87257ADB869A3ECCC3D16B724F2647")[..] + ); +} + +#[test] +#[cfg(feature = "alloc")] +fn encode_ec_p256_der() { + let pk = PrivateKeyInfo::try_from(EC_P256_DER_EXAMPLE).unwrap(); + let pk_encoded = pk.to_vec().unwrap(); + assert_eq!(EC_P256_DER_EXAMPLE, pk_encoded); +} + +#[test] +#[cfg(feature = "alloc")] +fn encode_ed25519_der_v1() { + let pk = PrivateKeyInfo::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); + assert_eq!(ED25519_DER_V1_EXAMPLE, pk.to_vec().unwrap()); +} + +#[test] +#[cfg(all(feature = "alloc", feature = "subtle"))] +fn encode_ed25519_der_v2() { + let private_key = PrivateKeyInfo::try_from(ED25519_DER_V2_EXAMPLE).unwrap(); + let private_der = private_key.to_vec().unwrap(); + assert_eq!( + private_key, + PrivateKeyInfo::try_from(private_der.as_ref()).unwrap() + ); +} + +#[test] +#[cfg(feature = "alloc")] +fn encode_rsa_2048_der() { + let pk = PrivateKeyInfo::try_from(RSA_2048_DER_EXAMPLE).unwrap(); + assert_eq!(RSA_2048_DER_EXAMPLE, &pk.to_vec().unwrap()); +} + +#[test] +#[cfg(feature = "pem")] +fn encode_ec_p256_pem() { + let pk = PrivateKeyInfo::try_from(EC_P256_DER_EXAMPLE).unwrap(); + assert_eq!(EC_P256_PEM_EXAMPLE, pk.to_pem(LineEnding::LF).unwrap()); +} + +#[test] +#[cfg(feature = "pem")] +fn encode_ed25519_pem() { + let pk = PrivateKeyInfo::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); + assert_eq!(ED25519_PEM_V1_EXAMPLE, pk.to_pem(LineEnding::LF).unwrap()); +} + +#[test] +#[cfg(feature = "pem")] +fn encode_rsa_2048_pem() { + let pk = PrivateKeyInfo::try_from(RSA_2048_DER_EXAMPLE).unwrap(); + assert_eq!(RSA_2048_PEM_EXAMPLE, pk.to_pem(LineEnding::LF).unwrap()); +} + +#[test] +#[cfg(feature = "pem")] +fn encode_x25519_pem() { + let pk = PrivateKeyInfo::try_from(X25519_DER_EXAMPLE).unwrap(); + assert_eq!(X25519_PEM_EXAMPLE, pk.to_pem(LineEnding::LF).unwrap()); +} diff --git a/vendor/pkcs8/tests/traits.rs b/vendor/pkcs8/tests/traits.rs new file mode 100644 index 000000000..1c8a969bc --- /dev/null +++ b/vendor/pkcs8/tests/traits.rs @@ -0,0 +1,108 @@ +//! Tests for PKCS#8 encoding/decoding traits. + +#![cfg(any(feature = "pem", feature = "std"))] + +use der::Encode; +use pkcs8::{DecodePrivateKey, EncodePrivateKey, Error, PrivateKeyInfo, Result, SecretDocument}; + +#[cfg(feature = "pem")] +use pkcs8::der::pem::LineEnding; + +#[cfg(feature = "std")] +use tempfile::tempdir; + +#[cfg(all(feature = "pem", feature = "std"))] +use std::fs; + +/// Ed25519 `PrivateKeyInfo` encoded as ASN.1 DER +const ED25519_DER_EXAMPLE: &[u8] = include_bytes!("examples/ed25519-priv-pkcs8v1.der"); + +/// Ed25519 private key encoded as PEM +#[cfg(feature = "pem")] +const ED25519_PEM_EXAMPLE: &str = include_str!("examples/ed25519-priv-pkcs8v1.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 DecodePrivateKey for MockKey { + fn from_pkcs8_der(bytes: &[u8]) -> Result<MockKey> { + Ok(MockKey(bytes.to_vec())) + } +} + +impl EncodePrivateKey for MockKey { + fn to_pkcs8_der(&self) -> Result<SecretDocument> { + Ok(SecretDocument::try_from(self.as_ref())?) + } +} + +impl TryFrom<PrivateKeyInfo<'_>> for MockKey { + type Error = Error; + + fn try_from(pkcs8: PrivateKeyInfo<'_>) -> Result<MockKey> { + Ok(MockKey(pkcs8.to_vec()?)) + } +} + +#[cfg(feature = "pem")] +#[test] +fn from_pkcs8_pem() { + let key = MockKey::from_pkcs8_pem(ED25519_PEM_EXAMPLE).unwrap(); + assert_eq!(key.as_ref(), ED25519_DER_EXAMPLE); +} + +#[cfg(feature = "std")] +#[test] +fn read_pkcs8_der_file() { + let key = MockKey::read_pkcs8_der_file("tests/examples/ed25519-priv-pkcs8v1.der").unwrap(); + assert_eq!(key.as_ref(), ED25519_DER_EXAMPLE); +} + +#[cfg(all(feature = "pem", feature = "std"))] +#[test] +fn read_pkcs8_pem_file() { + let key = MockKey::read_pkcs8_pem_file("tests/examples/ed25519-priv-pkcs8v1.pem").unwrap(); + assert_eq!(key.as_ref(), ED25519_DER_EXAMPLE); +} + +#[cfg(feature = "pem")] +#[test] +fn to_pkcs8_pem() { + let pem = MockKey(ED25519_DER_EXAMPLE.to_vec()) + .to_pkcs8_pem(LineEnding::LF) + .unwrap(); + + assert_eq!(&*pem, ED25519_PEM_EXAMPLE); +} + +#[cfg(feature = "std")] +#[test] +fn write_pkcs8_der_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("example.der"); + MockKey(ED25519_DER_EXAMPLE.to_vec()) + .write_pkcs8_der_file(&path) + .unwrap(); + + let key = MockKey::read_pkcs8_der_file(&path).unwrap(); + assert_eq!(key.as_ref(), ED25519_DER_EXAMPLE); +} + +#[cfg(all(feature = "pem", feature = "std"))] +#[test] +fn write_pkcs8_pem_file() { + let dir = tempdir().unwrap(); + let path = dir.path().join("example.pem"); + MockKey(ED25519_DER_EXAMPLE.to_vec()) + .write_pkcs8_pem_file(&path, LineEnding::LF) + .unwrap(); + + let pem = fs::read_to_string(path).unwrap(); + assert_eq!(&pem, ED25519_PEM_EXAMPLE); +} |