pkcs1-0.7.5/.cargo_vcs_info.json0000644000000001430000000000100120640ustar { "git": { "sha1": "750ae946d284810f582a9c9ad428549561b1ee03" }, "path_in_vcs": "pkcs1" }pkcs1-0.7.5/CHANGELOG.md000064400000000000000000000107461046102023000124770ustar 00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## 0.7.5 (2023-04-24) ### Fixed - Import failure ([#1021]) [#1021]: https://github.com/RustCrypto/formats/pull/1021 ## 0.7.4 (2023-04-21) ### Changed - Have `alloc` feature only weakly activate `pkcs8?/alloc` ([#1013]) - Have `pem` feature only weakly activate `pkcs8?/pem` ([#1013]) [#1013]: https://github.com/RustCrypto/formats/pull/1013 ## 0.7.3 (2023-04-18) ### Added - Provide functions to construct `RsaPss` and `RsaOaepParams` ([#1010]) ### Changed - Use `NULL` parameters for SHA `AlgorithmIdentifier`s ([#1010]) [#1010]: https://github.com/RustCrypto/formats/pull/1010 ## 0.7.2 (2023-04-04) ### Added - `RsaPssParams::SALT_LEN_DEFAULT` ([#953]) [#953]: https://github.com/RustCrypto/formats/pull/953 ## 0.7.1 (2023-03-05) ### Fixed - `DecodeRsaPublicKey` blanket impl ([#916]) [#916]: https://github.com/RustCrypto/formats/pull/916 ## 0.7.0 (2023-02-26) [YANKED] ### Changed - Make PSS/OAEP params use generic `AlgorithmIdentifier` ([#799]) - Bump `der` dependency to v0.7 ([#899]) - Bump `spki` dependency to v0.7 ([#900]) - Bump `pkcs8` to v0.10 ([#902]) [#799]: https://github.com/RustCrypto/formats/pull/799 [#899]: https://github.com/RustCrypto/formats/pull/899 [#900]: https://github.com/RustCrypto/formats/pull/900 [#902]: https://github.com/RustCrypto/formats/pull/902 ## 0.6.0 (Skipped) - Skipped to synchronize version number with `der` and `spki` ## 0.5.0 (Skipped) - Skipped to synchronize version number with `der` and `spki` ## 0.4.1 (2022-10-10) ### Added - `RsaPssParams` support ([#698]) - `RsaOaepParams` support ([#733]) [#698]: https://github.com/RustCrypto/formats/pull/698 [#733]: https://github.com/RustCrypto/formats/pull/733 ## 0.4.0 (2022-05-08) ### Changed - Replace document types with `doc::{Document, SecretDocument}` types ([#571]) - Bump `der` to v0.6 ([#653]) - Bump `pkcs8` to v0.9 ([#656]) [#571]: https://github.com/RustCrypto/formats/pull/571 [#653]: https://github.com/RustCrypto/formats/pull/653 [#656]: https://github.com/RustCrypto/formats/pull/656 ## 0.3.3 (2022-01-16) ### Added - Error conversion support to `pkcs8::spki::Error` ([#333]) [#333]: https://github.com/RustCrypto/formats/pull/331 ## 0.3.2 (2022-01-16) ### Added - Error conversion support to `pkcs8::Error` ([#331]) [#331]: https://github.com/RustCrypto/formats/pull/331 ## 0.3.1 (2021-11-29) ### Changed - Use `finish_non_exhaustive` in Debug impls ([#245]) [#245]: https://github.com/RustCrypto/formats/pull/245 ## 0.3.0 (2021-11-17) ### Added - Support for multi-prime RSA keys ([#115]) - `pkcs8` feature ([#227], [#233]) ### Changed - Rename `From/ToRsa*Key` => `DecodeRsa*Key`/`EncodeRsa*Key` ([#120]) - Use `der::Document` to impl `RsaPrivateKeyDocument` ([#131]) - Rust 2021 edition upgrade; MSRV 1.56 ([#136]) - Make `RsaPrivateKey::version` implicit ([#188]) - Bump `der` crate dependency to v0.5 ([#222]) - Activate `pkcs8/pem` when `pem` feature is enabled ([#232]) ### Removed - `*_with_le` PEM encoding methods ([#109]) - I/O related errors ([#158]) [#109]: https://github.com/RustCrypto/formats/pull/109 [#115]: https://github.com/RustCrypto/formats/pull/115 [#120]: https://github.com/RustCrypto/formats/pull/120 [#131]: https://github.com/RustCrypto/formats/pull/131 [#136]: https://github.com/RustCrypto/formats/pull/136 [#158]: https://github.com/RustCrypto/formats/pull/158 [#188]: https://github.com/RustCrypto/formats/pull/188 [#222]: https://github.com/RustCrypto/formats/pull/222 [#227]: https://github.com/RustCrypto/formats/pull/227 [#232]: https://github.com/RustCrypto/formats/pull/232 [#233]: https://github.com/RustCrypto/formats/pull/233 ## 0.2.4 (2021-09-14) ### Changed - Moved to `formats` repo ([#2]) [#2]: https://github.com/RustCrypto/formats/pull/2 ## 0.2.3 (2021-07-26) ### Added - Support for customizing PEM `LineEnding` ### Changed - Bump `pem-rfc7468` dependency to v0.2 ## 0.2.2 (2021-07-25) ### Fixed - `Version` encoder ## 0.2.1 (2021-07-25) ### Added - `Error::Crypto` variant ## 0.2.0 (2021-07-25) ### Added - `From*`/`To*` traits for `RsaPrivateKey`/`RsaPublicKey` ### Changed - Use `FromRsa*`/`ToRsa*` traits with `*Document` types ## 0.1.1 (2021-07-24) ### Added - Re-export `der` crate and `der::UIntBytes` ### Changed - Replace `Error::{Decode, Encode}` with `Error::Asn1` ## 0.1.0 (2021-07-24) [YANKED] - Initial release pkcs1-0.7.5/Cargo.toml0000644000000032040000000000100100630ustar # 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.60" name = "pkcs1" version = "0.7.5" authors = ["RustCrypto Developers"] description = """ Pure Rust implementation of Public-Key Cryptography Standards (PKCS) #1: RSA Cryptography Specifications Version 2.2 (RFC 8017) """ readme = "README.md" keywords = [ "crypto", "key", "pem", "pkcs", "rsa", ] categories = [ "cryptography", "data-structures", "encoding", "no-std", "parser-implementations", ] license = "Apache-2.0 OR MIT" repository = "https://github.com/RustCrypto/formats/tree/master/pkcs1" [package.metadata.docs.rs] all-features = true rustdoc-args = [ "--cfg", "docsrs", ] [dependencies.der] version = "0.7" features = ["oid"] [dependencies.pkcs8] version = "0.10" optional = true default-features = false [dependencies.spki] version = "0.7" [dev-dependencies.const-oid] version = "0.9" features = ["db"] [dev-dependencies.hex-literal] version = "0.4" [dev-dependencies.tempfile] version = "3" [features] alloc = [ "der/alloc", "zeroize", "pkcs8?/alloc", ] pem = [ "alloc", "der/pem", "pkcs8?/pem", ] std = [ "der/std", "alloc", ] zeroize = ["der/zeroize"] pkcs1-0.7.5/Cargo.toml.orig000064400000000000000000000021121046102023000135410ustar 00000000000000[package] name = "pkcs1" version = "0.7.5" description = """ Pure Rust implementation of Public-Key Cryptography Standards (PKCS) #1: RSA Cryptography Specifications Version 2.2 (RFC 8017) """ authors = ["RustCrypto Developers"] license = "Apache-2.0 OR MIT" repository = "https://github.com/RustCrypto/formats/tree/master/pkcs1" categories = ["cryptography", "data-structures", "encoding", "no-std", "parser-implementations"] keywords = ["crypto", "key", "pem", "pkcs", "rsa"] readme = "README.md" edition = "2021" rust-version = "1.60" [dependencies] der = { version = "0.7", features = ["oid"] } spki = { version = "0.7" } # optional dependencies pkcs8 = { version = "0.10", optional = true, default-features = false } [dev-dependencies] const-oid = { version = "0.9", features = ["db"] } # TODO: path = "../const-oid" hex-literal = "0.4" tempfile = "3" [features] zeroize = ["der/zeroize"] alloc = ["der/alloc", "zeroize", "pkcs8?/alloc"] pem = ["alloc", "der/pem", "pkcs8?/pem"] std = ["der/std", "alloc"] [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] pkcs1-0.7.5/LICENSE-APACHE000064400000000000000000000251411046102023000126050ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. pkcs1-0.7.5/LICENSE-MIT000064400000000000000000000020721046102023000123130ustar 00000000000000Copyright (c) 2021-2023 The RustCrypto Project Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pkcs1-0.7.5/README.md000064400000000000000000000040561046102023000121420ustar 00000000000000# [RustCrypto]: PKCS#1 (RSA) [![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) #1: RSA Cryptography Specifications Version 2.2 ([RFC 8017]). [Documentation][docs-link] ## About This crate supports encoding and decoding RSA private and public keys in either PKCS#1 DER (binary) or PEM (text) formats. PEM encoded RSA private keys begin with: ```text -----BEGIN RSA PRIVATE KEY----- ``` PEM encoded RSA public keys begin with: ```text -----BEGIN RSA PUBLIC KEY----- ``` ## Minimum Supported Rust Version This crate requires **Rust 1.65** at a minimum. We may change the MSRV in the future, but it will be accompanied by a minor version bump. ## License Licensed under either of: * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) * [MIT license](http://opensource.org/licenses/MIT) at your option. ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. [//]: # (badges) [crate-image]: https://buildstats.info/crate/pkcs1 [crate-link]: https://crates.io/crates/pkcs1 [docs-image]: https://docs.rs/pkcs1/badge.svg [docs-link]: https://docs.rs/pkcs1/ [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg [rustc-image]: https://img.shields.io/badge/rustc-1.65+-blue.svg [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/300570-formats [build-image]: https://github.com/RustCrypto/formats/workflows/pkcs1/badge.svg?branch=master&event=push [build-link]: https://github.com/RustCrypto/formats/actions [//]: # (links) [RustCrypto]: https://github.com/rustcrypto [RFC 8017]: https://datatracker.ietf.org/doc/html/rfc8017 pkcs1-0.7.5/src/error.rs000064400000000000000000000045121046102023000131460ustar 00000000000000//! Error types use core::fmt; #[cfg(feature = "pem")] use der::pem; /// Result type pub type Result = core::result::Result; /// Error type #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[non_exhaustive] pub enum Error { /// ASN.1 DER-related errors. Asn1(der::Error), /// Cryptographic errors. /// /// These can be used by RSA implementations to signal that a key is /// invalid for cryptographic reasons. This means the document parsed /// correctly, but one of the values contained within was invalid, e.g. /// a number expected to be a prime was not a prime. Crypto, /// PKCS#8 errors. #[cfg(feature = "pkcs8")] Pkcs8(pkcs8::Error), /// Version errors Version, } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Error::Asn1(err) => write!(f, "PKCS#1 ASN.1 error: {}", err), Error::Crypto => f.write_str("PKCS#1 cryptographic error"), #[cfg(feature = "pkcs8")] Error::Pkcs8(err) => write!(f, "{}", err), Error::Version => f.write_str("PKCS#1 version error"), } } } impl From for Error { fn from(err: der::Error) -> Error { Error::Asn1(err) } } #[cfg(feature = "pem")] impl From for Error { fn from(err: pem::Error) -> Error { der::Error::from(err).into() } } #[cfg(feature = "pkcs8")] impl From for pkcs8::Error { fn from(err: Error) -> pkcs8::Error { match err { Error::Asn1(e) => pkcs8::Error::Asn1(e), Error::Crypto | Error::Version => pkcs8::Error::KeyMalformed, Error::Pkcs8(e) => e, } } } #[cfg(feature = "pkcs8")] impl From for Error { fn from(err: pkcs8::Error) -> Error { Error::Pkcs8(err) } } #[cfg(feature = "pkcs8")] impl From for pkcs8::spki::Error { fn from(err: Error) -> pkcs8::spki::Error { match err { Error::Asn1(e) => pkcs8::spki::Error::Asn1(e), _ => pkcs8::spki::Error::KeyMalformed, } } } #[cfg(feature = "pkcs8")] impl From for Error { fn from(err: pkcs8::spki::Error) -> Error { Error::Pkcs8(pkcs8::Error::PublicKey(err)) } } #[cfg(feature = "std")] impl std::error::Error for Error {} pkcs1-0.7.5/src/lib.rs000064400000000000000000000030671046102023000125670ustar 00000000000000#![no_std] #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![doc = include_str!("../README.md")] #![doc( html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" )] #![forbid(unsafe_code)] #![warn( clippy::mod_module_files, clippy::unwrap_used, missing_docs, rust_2018_idioms, unused_lifetimes, unused_qualifications )] #[cfg(feature = "alloc")] extern crate alloc; #[cfg(feature = "std")] extern crate std; mod error; mod params; mod private_key; mod public_key; mod traits; mod version; pub use der::{ self, asn1::{ObjectIdentifier, UintRef}, }; pub use crate::{ error::{Error, Result}, params::{RsaOaepParams, RsaPssParams, TrailerField}, private_key::RsaPrivateKey, public_key::RsaPublicKey, traits::{DecodeRsaPrivateKey, DecodeRsaPublicKey}, version::Version, }; #[cfg(feature = "alloc")] pub use crate::{ private_key::{other_prime_info::OtherPrimeInfo, OtherPrimeInfos}, traits::{EncodeRsaPrivateKey, EncodeRsaPublicKey}, }; #[cfg(feature = "pem")] pub use der::pem::{self, LineEnding}; /// `rsaEncryption` Object Identifier (OID) #[cfg(feature = "pkcs8")] pub const ALGORITHM_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.1"); /// `AlgorithmIdentifier` for RSA. #[cfg(feature = "pkcs8")] pub const ALGORITHM_ID: pkcs8::AlgorithmIdentifierRef<'static> = pkcs8::AlgorithmIdentifierRef { oid: ALGORITHM_OID, parameters: Some(der::asn1::AnyRef::NULL), }; pkcs1-0.7.5/src/params.rs000064400000000000000000000305361046102023000133050ustar 00000000000000//! PKCS#1 RSA parameters. use crate::{Error, Result}; use der::{ asn1::{AnyRef, ContextSpecificRef, ObjectIdentifier}, oid::AssociatedOid, Decode, DecodeValue, Encode, EncodeValue, FixedTag, Length, Reader, Sequence, Tag, TagMode, TagNumber, Writer, }; use spki::{AlgorithmIdentifier, AlgorithmIdentifierRef}; const OID_SHA_1: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.14.3.2.26"); const OID_MGF_1: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.8"); const OID_PSPECIFIED: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.9"); const SHA_1_AI: AlgorithmIdentifierRef<'_> = AlgorithmIdentifierRef { oid: OID_SHA_1, parameters: Some(AnyRef::NULL), }; /// `TrailerField` as defined in [RFC 8017 Appendix 2.3]. /// ```text /// TrailerField ::= INTEGER { trailerFieldBC(1) } /// ``` /// [RFC 8017 Appendix 2.3]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.2.3 #[derive(Clone, Debug, Copy, PartialEq, Eq)] #[repr(u8)] pub enum TrailerField { /// the only supported value (0xbc, default) BC = 1, } impl Default for TrailerField { fn default() -> Self { Self::BC } } impl<'a> DecodeValue<'a> for TrailerField { fn decode_value>(decoder: &mut R, header: der::Header) -> der::Result { match u8::decode_value(decoder, header)? { 1 => Ok(TrailerField::BC), _ => Err(Self::TAG.value_error()), } } } impl EncodeValue for TrailerField { fn value_len(&self) -> der::Result { Ok(Length::ONE) } fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { (*self as u8).encode_value(writer) } } impl FixedTag for TrailerField { const TAG: Tag = Tag::Integer; } /// PKCS#1 RSASSA-PSS parameters as defined in [RFC 8017 Appendix 2.3] /// /// ASN.1 structure containing a serialized RSASSA-PSS parameters: /// ```text /// RSASSA-PSS-params ::= SEQUENCE { /// hashAlgorithm [0] HashAlgorithm DEFAULT sha1, /// maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1, /// saltLength [2] INTEGER DEFAULT 20, /// trailerField [3] TrailerField DEFAULT trailerFieldBC /// } /// HashAlgorithm ::= AlgorithmIdentifier /// MaskGenAlgorithm ::= AlgorithmIdentifier /// ``` /// /// [RFC 8017 Appendix 2.3]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.2.3 #[derive(Clone, Debug, Eq, PartialEq)] pub struct RsaPssParams<'a> { /// Hash Algorithm pub hash: AlgorithmIdentifierRef<'a>, /// Mask Generation Function (MGF) pub mask_gen: AlgorithmIdentifier>, /// Salt length pub salt_len: u8, /// Trailer field (i.e. [`TrailerField::BC`]) pub trailer_field: TrailerField, } impl<'a> RsaPssParams<'a> { /// Default RSA PSS Salt length in RsaPssParams pub const SALT_LEN_DEFAULT: u8 = 20; /// Create new RsaPssParams for the provided digest and salt len pub fn new(salt_len: u8) -> Self where D: AssociatedOid, { Self { hash: AlgorithmIdentifierRef { oid: D::OID, parameters: Some(AnyRef::NULL), }, mask_gen: AlgorithmIdentifier { oid: OID_MGF_1, parameters: Some(AlgorithmIdentifierRef { oid: D::OID, parameters: Some(AnyRef::NULL), }), }, salt_len, trailer_field: Default::default(), } } fn context_specific_hash(&self) -> Option>> { if self.hash == SHA_1_AI { None } else { Some(ContextSpecificRef { tag_number: TagNumber::N0, tag_mode: TagMode::Explicit, value: &self.hash, }) } } fn context_specific_mask_gen( &self, ) -> Option>>> { if self.mask_gen == default_mgf1_sha1() { None } else { Some(ContextSpecificRef { tag_number: TagNumber::N1, tag_mode: TagMode::Explicit, value: &self.mask_gen, }) } } fn context_specific_salt_len(&self) -> Option> { if self.salt_len == RsaPssParams::SALT_LEN_DEFAULT { None } else { Some(ContextSpecificRef { tag_number: TagNumber::N2, tag_mode: TagMode::Explicit, value: &self.salt_len, }) } } fn context_specific_trailer_field(&self) -> Option> { if self.trailer_field == TrailerField::default() { None } else { Some(ContextSpecificRef { tag_number: TagNumber::N3, tag_mode: TagMode::Explicit, value: &self.trailer_field, }) } } } impl<'a> Default for RsaPssParams<'a> { fn default() -> Self { Self { hash: SHA_1_AI, mask_gen: default_mgf1_sha1(), salt_len: RsaPssParams::SALT_LEN_DEFAULT, trailer_field: Default::default(), } } } impl<'a> DecodeValue<'a> for RsaPssParams<'a> { fn decode_value>(reader: &mut R, header: der::Header) -> der::Result { reader.read_nested(header.length, |reader| { Ok(Self { hash: reader .context_specific(TagNumber::N0, TagMode::Explicit)? .unwrap_or(SHA_1_AI), mask_gen: reader .context_specific(TagNumber::N1, TagMode::Explicit)? .unwrap_or_else(default_mgf1_sha1), salt_len: reader .context_specific(TagNumber::N2, TagMode::Explicit)? .unwrap_or(RsaPssParams::SALT_LEN_DEFAULT), trailer_field: reader .context_specific(TagNumber::N3, TagMode::Explicit)? .unwrap_or_default(), }) }) } } impl EncodeValue for RsaPssParams<'_> { fn value_len(&self) -> der::Result { self.context_specific_hash().encoded_len()? + self.context_specific_mask_gen().encoded_len()? + self.context_specific_salt_len().encoded_len()? + self.context_specific_trailer_field().encoded_len()? } fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { self.context_specific_hash().encode(writer)?; self.context_specific_mask_gen().encode(writer)?; self.context_specific_salt_len().encode(writer)?; self.context_specific_trailer_field().encode(writer)?; Ok(()) } } impl<'a> Sequence<'a> for RsaPssParams<'a> {} impl<'a> TryFrom<&'a [u8]> for RsaPssParams<'a> { type Error = Error; fn try_from(bytes: &'a [u8]) -> Result { Ok(Self::from_der(bytes)?) } } /// Default Mask Generation Function (MGF): SHA-1. fn default_mgf1_sha1<'a>() -> AlgorithmIdentifier> { AlgorithmIdentifier::> { oid: OID_MGF_1, parameters: Some(SHA_1_AI), } } /// PKCS#1 RSAES-OAEP parameters as defined in [RFC 8017 Appendix 2.1] /// /// ASN.1 structure containing a serialized RSAES-OAEP parameters: /// ```text /// RSAES-OAEP-params ::= SEQUENCE { /// hashAlgorithm [0] HashAlgorithm DEFAULT sha1, /// maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1, /// pSourceAlgorithm [2] PSourceAlgorithm DEFAULT pSpecifiedEmpty /// } /// HashAlgorithm ::= AlgorithmIdentifier /// MaskGenAlgorithm ::= AlgorithmIdentifier /// PSourceAlgorithm ::= AlgorithmIdentifier /// ``` /// /// [RFC 8017 Appendix 2.1]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.2.1 #[derive(Clone, Debug, Eq, PartialEq)] pub struct RsaOaepParams<'a> { /// Hash Algorithm pub hash: AlgorithmIdentifierRef<'a>, /// Mask Generation Function (MGF) pub mask_gen: AlgorithmIdentifier>, /// The source (and possibly the value) of the label L pub p_source: AlgorithmIdentifierRef<'a>, } impl<'a> RsaOaepParams<'a> { /// Create new RsaPssParams for the provided digest and default (empty) label pub fn new() -> Self where D: AssociatedOid, { Self::new_with_label::(&[]) } /// Create new RsaPssParams for the provided digest and specified label pub fn new_with_label(label: &'a impl AsRef<[u8]>) -> Self where D: AssociatedOid, { Self { hash: AlgorithmIdentifierRef { oid: D::OID, parameters: Some(AnyRef::NULL), }, mask_gen: AlgorithmIdentifier { oid: OID_MGF_1, parameters: Some(AlgorithmIdentifierRef { oid: D::OID, parameters: Some(AnyRef::NULL), }), }, p_source: pspecicied_algorithm_identifier(label), } } fn context_specific_hash(&self) -> Option>> { if self.hash == SHA_1_AI { None } else { Some(ContextSpecificRef { tag_number: TagNumber::N0, tag_mode: TagMode::Explicit, value: &self.hash, }) } } fn context_specific_mask_gen( &self, ) -> Option>>> { if self.mask_gen == default_mgf1_sha1() { None } else { Some(ContextSpecificRef { tag_number: TagNumber::N1, tag_mode: TagMode::Explicit, value: &self.mask_gen, }) } } fn context_specific_p_source( &self, ) -> Option>> { if self.p_source == default_pempty_string() { None } else { Some(ContextSpecificRef { tag_number: TagNumber::N2, tag_mode: TagMode::Explicit, value: &self.p_source, }) } } } impl<'a> Default for RsaOaepParams<'a> { fn default() -> Self { Self { hash: SHA_1_AI, mask_gen: default_mgf1_sha1(), p_source: default_pempty_string(), } } } impl<'a> DecodeValue<'a> for RsaOaepParams<'a> { fn decode_value>(reader: &mut R, header: der::Header) -> der::Result { reader.read_nested(header.length, |reader| { Ok(Self { hash: reader .context_specific(TagNumber::N0, TagMode::Explicit)? .unwrap_or(SHA_1_AI), mask_gen: reader .context_specific(TagNumber::N1, TagMode::Explicit)? .unwrap_or_else(default_mgf1_sha1), p_source: reader .context_specific(TagNumber::N2, TagMode::Explicit)? .unwrap_or_else(default_pempty_string), }) }) } } impl EncodeValue for RsaOaepParams<'_> { fn value_len(&self) -> der::Result { self.context_specific_hash().encoded_len()? + self.context_specific_mask_gen().encoded_len()? + self.context_specific_p_source().encoded_len()? } fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { self.context_specific_hash().encode(writer)?; self.context_specific_mask_gen().encode(writer)?; self.context_specific_p_source().encode(writer)?; Ok(()) } } impl<'a> Sequence<'a> for RsaOaepParams<'a> {} impl<'a> TryFrom<&'a [u8]> for RsaOaepParams<'a> { type Error = Error; fn try_from(bytes: &'a [u8]) -> Result { Ok(Self::from_der(bytes)?) } } fn pspecicied_algorithm_identifier(label: &impl AsRef<[u8]>) -> AlgorithmIdentifierRef<'_> { AlgorithmIdentifierRef { oid: OID_PSPECIFIED, parameters: Some( AnyRef::new(Tag::OctetString, label.as_ref()).expect("error creating OAEP params"), ), } } /// Default Source Algorithm, empty string fn default_pempty_string<'a>() -> AlgorithmIdentifierRef<'a> { pspecicied_algorithm_identifier(&[]) } pkcs1-0.7.5/src/private_key/other_prime_info.rs000064400000000000000000000033061046102023000176670ustar 00000000000000//! PKCS#1 OtherPrimeInfo support. use der::{ asn1::UintRef, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Writer, }; /// PKCS#1 OtherPrimeInfo as defined in [RFC 8017 Appendix 1.2]. /// /// ASN.1 structure containing an additional prime in a multi-prime RSA key. /// /// ```text /// OtherPrimeInfo ::= SEQUENCE { /// prime INTEGER, -- ri /// exponent INTEGER, -- di /// coefficient INTEGER -- ti /// } /// ``` /// /// [RFC 8017 Appendix 1.2]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.1.2 #[derive(Clone)] pub struct OtherPrimeInfo<'a> { /// Prime factor `r_i` of `n`, where `i` >= 3. pub prime: UintRef<'a>, /// Exponent: `d_i = d mod (r_i - 1)`. pub exponent: UintRef<'a>, /// CRT coefficient: `t_i = (r_1 * r_2 * ... * r_(i-1))^(-1) mod r_i`. pub coefficient: UintRef<'a>, } impl<'a> DecodeValue<'a> for OtherPrimeInfo<'a> { fn decode_value>(reader: &mut R, header: Header) -> der::Result { reader.read_nested(header.length, |reader| { Ok(Self { prime: reader.decode()?, exponent: reader.decode()?, coefficient: reader.decode()?, }) }) } } impl EncodeValue for OtherPrimeInfo<'_> { fn value_len(&self) -> der::Result { self.prime.encoded_len()? + self.exponent.encoded_len()? + self.coefficient.encoded_len()? } fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { self.prime.encode(writer)?; self.exponent.encode(writer)?; self.coefficient.encode(writer)?; Ok(()) } } impl<'a> Sequence<'a> for OtherPrimeInfo<'a> {} pkcs1-0.7.5/src/private_key.rs000064400000000000000000000172071046102023000143440ustar 00000000000000//! PKCS#1 RSA Private Keys. #[cfg(feature = "alloc")] pub(crate) mod other_prime_info; use crate::{Error, Result, RsaPublicKey, Version}; use core::fmt; use der::{ asn1::UintRef, Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Tag, Writer, }; #[cfg(feature = "alloc")] use {self::other_prime_info::OtherPrimeInfo, alloc::vec::Vec, der::SecretDocument}; #[cfg(feature = "pem")] use der::pem::PemLabel; /// PKCS#1 RSA Private Keys as defined in [RFC 8017 Appendix 1.2]. /// /// ASN.1 structure containing a serialized RSA private key: /// /// ```text /// RSAPrivateKey ::= SEQUENCE { /// version Version, /// modulus INTEGER, -- n /// publicExponent INTEGER, -- e /// privateExponent INTEGER, -- d /// prime1 INTEGER, -- p /// prime2 INTEGER, -- q /// exponent1 INTEGER, -- d mod (p-1) /// exponent2 INTEGER, -- d mod (q-1) /// coefficient INTEGER, -- (inverse of q) mod p /// otherPrimeInfos OtherPrimeInfos OPTIONAL /// } /// ``` /// /// Note: the `version` field is selected automatically based on the absence or /// presence of the `other_prime_infos` field. /// /// [RFC 8017 Appendix 1.2]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.1.2 #[derive(Clone)] pub struct RsaPrivateKey<'a> { /// `n`: RSA modulus. pub modulus: UintRef<'a>, /// `e`: RSA public exponent. pub public_exponent: UintRef<'a>, /// `d`: RSA private exponent. pub private_exponent: UintRef<'a>, /// `p`: first prime factor of `n`. pub prime1: UintRef<'a>, /// `q`: Second prime factor of `n`. pub prime2: UintRef<'a>, /// First exponent: `d mod (p-1)`. pub exponent1: UintRef<'a>, /// Second exponent: `d mod (q-1)`. pub exponent2: UintRef<'a>, /// CRT coefficient: `(inverse of q) mod p`. pub coefficient: UintRef<'a>, /// Additional primes `r_3`, ..., `r_u`, in order, if this is a multi-prime /// RSA key (i.e. `version` is `multi`). pub other_prime_infos: Option>, } impl<'a> RsaPrivateKey<'a> { /// Get the public key that corresponds to this [`RsaPrivateKey`]. pub fn public_key(&self) -> RsaPublicKey<'a> { RsaPublicKey { modulus: self.modulus, public_exponent: self.public_exponent, } } /// Get the [`Version`] for this key. /// /// Determined by the presence or absence of the /// [`RsaPrivateKey::other_prime_infos`] field. pub fn version(&self) -> Version { if self.other_prime_infos.is_some() { Version::Multi } else { Version::TwoPrime } } } impl<'a> DecodeValue<'a> for RsaPrivateKey<'a> { fn decode_value>(reader: &mut R, header: Header) -> der::Result { reader.read_nested(header.length, |reader| { let version = Version::decode(reader)?; let result = Self { modulus: reader.decode()?, public_exponent: reader.decode()?, private_exponent: reader.decode()?, prime1: reader.decode()?, prime2: reader.decode()?, exponent1: reader.decode()?, exponent2: reader.decode()?, coefficient: reader.decode()?, other_prime_infos: reader.decode()?, }; // Ensure version is set correctly for two-prime vs multi-prime key. if version.is_multi() != result.other_prime_infos.is_some() { return Err(reader.error(der::ErrorKind::Value { tag: Tag::Integer })); } Ok(result) }) } } impl EncodeValue for RsaPrivateKey<'_> { fn value_len(&self) -> der::Result { self.version().encoded_len()? + self.modulus.encoded_len()? + self.public_exponent.encoded_len()? + self.private_exponent.encoded_len()? + self.prime1.encoded_len()? + self.prime2.encoded_len()? + self.exponent1.encoded_len()? + self.exponent2.encoded_len()? + self.coefficient.encoded_len()? + self.other_prime_infos.encoded_len()? } fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { self.version().encode(writer)?; self.modulus.encode(writer)?; self.public_exponent.encode(writer)?; self.private_exponent.encode(writer)?; self.prime1.encode(writer)?; self.prime2.encode(writer)?; self.exponent1.encode(writer)?; self.exponent2.encode(writer)?; self.coefficient.encode(writer)?; self.other_prime_infos.encode(writer)?; Ok(()) } } impl<'a> Sequence<'a> for RsaPrivateKey<'a> {} impl<'a> From> for RsaPublicKey<'a> { fn from(private_key: RsaPrivateKey<'a>) -> RsaPublicKey<'a> { private_key.public_key() } } impl<'a> From<&RsaPrivateKey<'a>> for RsaPublicKey<'a> { fn from(private_key: &RsaPrivateKey<'a>) -> RsaPublicKey<'a> { private_key.public_key() } } impl<'a> TryFrom<&'a [u8]> for RsaPrivateKey<'a> { type Error = Error; fn try_from(bytes: &'a [u8]) -> Result { Ok(Self::from_der(bytes)?) } } impl fmt::Debug for RsaPrivateKey<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RsaPrivateKey") .field("version", &self.version()) .field("modulus", &self.modulus) .field("public_exponent", &self.public_exponent) .finish_non_exhaustive() } } #[cfg(feature = "alloc")] impl TryFrom> for SecretDocument { type Error = Error; fn try_from(private_key: RsaPrivateKey<'_>) -> Result { SecretDocument::try_from(&private_key) } } #[cfg(feature = "alloc")] impl TryFrom<&RsaPrivateKey<'_>> for SecretDocument { type Error = Error; fn try_from(private_key: &RsaPrivateKey<'_>) -> Result { Ok(Self::encode_msg(private_key)?) } } #[cfg(feature = "pem")] impl PemLabel for RsaPrivateKey<'_> { const PEM_LABEL: &'static str = "RSA PRIVATE KEY"; } /// Placeholder struct for `OtherPrimeInfos` in the no-`alloc` case. /// /// This type is unconstructable by design, but supports the same traits. #[cfg(not(feature = "alloc"))] #[derive(Clone)] #[non_exhaustive] pub struct OtherPrimeInfos<'a> { _lifetime: core::marker::PhantomData<&'a ()>, } #[cfg(not(feature = "alloc"))] impl<'a> DecodeValue<'a> for OtherPrimeInfos<'a> { fn decode_value>(reader: &mut R, _header: Header) -> der::Result { // Placeholder decoder that always returns an error. // Uses `Tag::Integer` to signal an unsupported version. Err(reader.error(der::ErrorKind::Value { tag: Tag::Integer })) } } #[cfg(not(feature = "alloc"))] impl EncodeValue for OtherPrimeInfos<'_> { fn value_len(&self) -> der::Result { // Placeholder decoder that always returns an error. // Uses `Tag::Integer` to signal an unsupported version. Err(der::ErrorKind::Value { tag: Tag::Integer }.into()) } fn encode_value(&self, _writer: &mut impl Writer) -> der::Result<()> { // Placeholder decoder that always returns an error. // Uses `Tag::Integer` to signal an unsupported version. Err(der::ErrorKind::Value { tag: Tag::Integer }.into()) } } #[cfg(not(feature = "alloc"))] impl<'a> der::FixedTag for OtherPrimeInfos<'a> { const TAG: Tag = Tag::Sequence; } /// Additional RSA prime info in a multi-prime RSA key. #[cfg(feature = "alloc")] pub type OtherPrimeInfos<'a> = Vec>; pkcs1-0.7.5/src/public_key.rs000064400000000000000000000043471046102023000141510ustar 00000000000000//! PKCS#1 RSA Public Keys. use crate::{Error, Result}; use der::{ asn1::UintRef, Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Writer, }; #[cfg(feature = "alloc")] use der::Document; #[cfg(feature = "pem")] use der::pem::PemLabel; /// PKCS#1 RSA Public Keys as defined in [RFC 8017 Appendix 1.1]. /// /// ASN.1 structure containing a serialized RSA public key: /// /// ```text /// RSAPublicKey ::= SEQUENCE { /// modulus INTEGER, -- n /// publicExponent INTEGER -- e /// } /// ``` /// /// [RFC 8017 Appendix 1.1]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.1.1 #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct RsaPublicKey<'a> { /// `n`: RSA modulus pub modulus: UintRef<'a>, /// `e`: RSA public exponent pub public_exponent: UintRef<'a>, } impl<'a> DecodeValue<'a> for RsaPublicKey<'a> { fn decode_value>(reader: &mut R, header: Header) -> der::Result { reader.read_nested(header.length, |reader| { Ok(Self { modulus: reader.decode()?, public_exponent: reader.decode()?, }) }) } } impl EncodeValue for RsaPublicKey<'_> { fn value_len(&self) -> der::Result { self.modulus.encoded_len()? + self.public_exponent.encoded_len()? } fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { self.modulus.encode(writer)?; self.public_exponent.encode(writer)?; Ok(()) } } impl<'a> Sequence<'a> for RsaPublicKey<'a> {} impl<'a> TryFrom<&'a [u8]> for RsaPublicKey<'a> { type Error = Error; fn try_from(bytes: &'a [u8]) -> Result { Ok(Self::from_der(bytes)?) } } #[cfg(feature = "alloc")] impl TryFrom> for Document { type Error = Error; fn try_from(spki: RsaPublicKey<'_>) -> Result { Self::try_from(&spki) } } #[cfg(feature = "alloc")] impl TryFrom<&RsaPublicKey<'_>> for Document { type Error = Error; fn try_from(spki: &RsaPublicKey<'_>) -> Result { Ok(Self::encode_msg(spki)?) } } #[cfg(feature = "pem")] impl PemLabel for RsaPublicKey<'_> { const PEM_LABEL: &'static str = "RSA PUBLIC KEY"; } pkcs1-0.7.5/src/traits.rs000064400000000000000000000160001046102023000133160ustar 00000000000000//! Traits for parsing objects from PKCS#1 encoded documents use crate::Result; #[cfg(feature = "alloc")] use der::{Document, SecretDocument}; #[cfg(feature = "pem")] use { crate::LineEnding, alloc::string::String, der::{pem::PemLabel, zeroize::Zeroizing}, }; #[cfg(feature = "pkcs8")] use { crate::{ALGORITHM_ID, ALGORITHM_OID}, der::asn1::BitStringRef, }; #[cfg(feature = "std")] use std::path::Path; #[cfg(all(feature = "alloc", feature = "pkcs8"))] use der::Decode; #[cfg(all(feature = "alloc", any(feature = "pem", feature = "pkcs8")))] use crate::{RsaPrivateKey, RsaPublicKey}; /// Parse an [`RsaPrivateKey`] from a PKCS#1-encoded document. pub trait DecodeRsaPrivateKey: Sized { /// Deserialize PKCS#1 private key from ASN.1 DER-encoded data /// (binary format). fn from_pkcs1_der(bytes: &[u8]) -> Result; /// Deserialize PKCS#1-encoded private key from PEM. /// /// Keys in this format begin with the following: /// /// ```text /// -----BEGIN RSA PRIVATE KEY----- /// ``` #[cfg(feature = "pem")] fn from_pkcs1_pem(s: &str) -> Result { let (label, doc) = SecretDocument::from_pem(s)?; RsaPrivateKey::validate_pem_label(label)?; Self::from_pkcs1_der(doc.as_bytes()) } /// Load PKCS#1 private key from an ASN.1 DER-encoded file on the local /// filesystem (binary format). #[cfg(feature = "std")] fn read_pkcs1_der_file(path: impl AsRef) -> Result { Self::from_pkcs1_der(SecretDocument::read_der_file(path)?.as_bytes()) } /// Load PKCS#1 private key from a PEM-encoded file on the local filesystem. #[cfg(all(feature = "pem", feature = "std"))] fn read_pkcs1_pem_file(path: impl AsRef) -> Result { let (label, doc) = SecretDocument::read_pem_file(path)?; RsaPrivateKey::validate_pem_label(&label)?; Self::from_pkcs1_der(doc.as_bytes()) } } /// Parse a [`RsaPublicKey`] from a PKCS#1-encoded document. pub trait DecodeRsaPublicKey: Sized { /// Deserialize object from ASN.1 DER-encoded [`RsaPublicKey`] /// (binary format). fn from_pkcs1_der(bytes: &[u8]) -> Result; /// Deserialize PEM-encoded [`RsaPublicKey`]. /// /// Keys in this format begin with the following: /// /// ```text /// -----BEGIN RSA PUBLIC KEY----- /// ``` #[cfg(feature = "pem")] fn from_pkcs1_pem(s: &str) -> Result { let (label, doc) = Document::from_pem(s)?; RsaPublicKey::validate_pem_label(label)?; Self::from_pkcs1_der(doc.as_bytes()) } /// Load [`RsaPublicKey`] from an ASN.1 DER-encoded file on the local /// filesystem (binary format). #[cfg(feature = "std")] fn read_pkcs1_der_file(path: impl AsRef) -> Result { let doc = Document::read_der_file(path)?; Self::from_pkcs1_der(doc.as_bytes()) } /// Load [`RsaPublicKey`] from a PEM-encoded file on the local filesystem. #[cfg(all(feature = "pem", feature = "std"))] fn read_pkcs1_pem_file(path: impl AsRef) -> Result { let (label, doc) = Document::read_pem_file(path)?; RsaPublicKey::validate_pem_label(&label)?; Self::from_pkcs1_der(doc.as_bytes()) } } /// Serialize a [`RsaPrivateKey`] to a PKCS#1 encoded document. #[cfg(feature = "alloc")] pub trait EncodeRsaPrivateKey { /// Serialize a [`SecretDocument`] containing a PKCS#1-encoded private key. fn to_pkcs1_der(&self) -> Result; /// Serialize this private key as PEM-encoded PKCS#1 with the given [`LineEnding`]. #[cfg(feature = "pem")] fn to_pkcs1_pem(&self, line_ending: LineEnding) -> Result> { let doc = self.to_pkcs1_der()?; Ok(doc.to_pem(RsaPrivateKey::PEM_LABEL, line_ending)?) } /// Write ASN.1 DER-encoded PKCS#1 private key to the given path. #[cfg(feature = "std")] fn write_pkcs1_der_file(&self, path: impl AsRef) -> Result<()> { Ok(self.to_pkcs1_der()?.write_der_file(path)?) } /// Write ASN.1 DER-encoded PKCS#1 private key to the given path. #[cfg(all(feature = "pem", feature = "std"))] fn write_pkcs1_pem_file(&self, path: impl AsRef, line_ending: LineEnding) -> Result<()> { let doc = self.to_pkcs1_der()?; Ok(doc.write_pem_file(path, RsaPrivateKey::PEM_LABEL, line_ending)?) } } /// Serialize a [`RsaPublicKey`] to a PKCS#1-encoded document. #[cfg(feature = "alloc")] pub trait EncodeRsaPublicKey { /// Serialize a [`Document`] containing a PKCS#1-encoded public key. fn to_pkcs1_der(&self) -> Result; /// Serialize this public key as PEM-encoded PKCS#1 with the given line ending. #[cfg(feature = "pem")] fn to_pkcs1_pem(&self, line_ending: LineEnding) -> Result { let doc = self.to_pkcs1_der()?; Ok(doc.to_pem(RsaPublicKey::PEM_LABEL, line_ending)?) } /// Write ASN.1 DER-encoded public key to the given path. #[cfg(feature = "std")] fn write_pkcs1_der_file(&self, path: impl AsRef) -> Result<()> { Ok(self.to_pkcs1_der()?.write_der_file(path)?) } /// Write ASN.1 DER-encoded public key to the given path. #[cfg(all(feature = "pem", feature = "std"))] fn write_pkcs1_pem_file(&self, path: impl AsRef, line_ending: LineEnding) -> Result<()> { let doc = self.to_pkcs1_der()?; Ok(doc.write_pem_file(path, RsaPublicKey::PEM_LABEL, line_ending)?) } } #[cfg(feature = "pkcs8")] impl DecodeRsaPrivateKey for T where T: for<'a> TryFrom, Error = pkcs8::Error>, { fn from_pkcs1_der(private_key: &[u8]) -> Result { Ok(Self::try_from(pkcs8::PrivateKeyInfo { algorithm: ALGORITHM_ID, private_key, public_key: None, })?) } } #[cfg(feature = "pkcs8")] impl DecodeRsaPublicKey for T where T: for<'a> TryFrom, Error = pkcs8::spki::Error>, { fn from_pkcs1_der(public_key: &[u8]) -> Result { Ok(Self::try_from(pkcs8::SubjectPublicKeyInfoRef { algorithm: ALGORITHM_ID, subject_public_key: BitStringRef::from_bytes(public_key)?, })?) } } #[cfg(all(feature = "alloc", feature = "pkcs8"))] impl EncodeRsaPrivateKey for T { fn to_pkcs1_der(&self) -> Result { let pkcs8_doc = self.to_pkcs8_der()?; let pkcs8_key = pkcs8::PrivateKeyInfo::from_der(pkcs8_doc.as_bytes())?; pkcs8_key.algorithm.assert_algorithm_oid(ALGORITHM_OID)?; RsaPrivateKey::from_der(pkcs8_key.private_key)?.try_into() } } #[cfg(all(feature = "alloc", feature = "pkcs8"))] impl EncodeRsaPublicKey for T { fn to_pkcs1_der(&self) -> Result { let doc = self.to_public_key_der()?; let spki = pkcs8::SubjectPublicKeyInfoRef::from_der(doc.as_bytes())?; spki.algorithm.assert_algorithm_oid(ALGORITHM_OID)?; RsaPublicKey::from_der(spki.subject_public_key.raw_bytes())?.try_into() } } pkcs1-0.7.5/src/version.rs000064400000000000000000000035241046102023000135040ustar 00000000000000//! PKCS#1 version identifier. use crate::Error; use der::{Decode, Encode, FixedTag, Reader, Tag, Writer}; /// Version identifier for PKCS#1 documents as defined in /// [RFC 8017 Appendix 1.2]. /// /// > version is the version number, for compatibility with future /// > revisions of this document. It SHALL be 0 for this version of the /// > document, unless multi-prime is used; in which case, it SHALL be 1. /// /// ```text /// Version ::= INTEGER { two-prime(0), multi(1) } /// (CONSTRAINED BY /// {-- version must be multi if otherPrimeInfos present --}) /// ``` /// /// [RFC 8017 Appendix 1.2]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.1.2 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[repr(u8)] pub enum Version { /// Denotes a `two-prime` key TwoPrime = 0, /// Denotes a `multi` (i.e. multi-prime) key Multi = 1, } impl Version { /// Is this a multi-prime RSA key? pub fn is_multi(self) -> bool { self == Self::Multi } } impl From for u8 { fn from(version: Version) -> Self { version as u8 } } impl TryFrom for Version { type Error = Error; fn try_from(byte: u8) -> Result { match byte { 0 => Ok(Version::TwoPrime), 1 => Ok(Version::Multi), _ => Err(Error::Version), } } } impl<'a> Decode<'a> for Version { fn decode>(decoder: &mut R) -> der::Result { Version::try_from(u8::decode(decoder)?).map_err(|_| Self::TAG.value_error()) } } impl Encode for Version { fn encoded_len(&self) -> der::Result { der::Length::ONE.for_tlv() } fn encode(&self, writer: &mut impl Writer) -> der::Result<()> { u8::from(*self).encode(writer) } } impl FixedTag for Version { const TAG: Tag = Tag::Integer; } pkcs1-0.7.5/tests/examples/rsa2048-priv-3prime.der000064400000000000000000000023341046102023000176120ustar 000000000000000FH D=yqUO~_[ێTHiZ2tK_:[.ćTFA UM"0:I&?G}0eqaWOơ} &L wH,(0)lkpþܰ n7QctF,$ҵk?g-0@! WYtHd0DƾOxpZ s+?3ŇzX]B6 }oǞVXb9,{hD(Lh~$][p 갻}.5NG#]Fװ҄Lcڜy3ծ#~lRvaՓhc EX/n^ VA㰶c7T7dBujG''<ϻ_G*AdPN9nkw0يCӕqqNQkCd j@̮FV~9S֭+MQ#TO"7no <&"e/_/ XT:!M k%;]qiɘ V6"|-sa\4P3U|vȏ"r]OG7dV_| !!?ZصOz)QLN>cTZ4VU>mъyQ>@ (1$u'WB Mnvlp;,T`a%5T{i VLR٩ tFyll>căIqs!> '(dkuqX;:JV[_s[S#"J5RJdv.0 0VuS/&2aT0h78ǟ:`!} iJ=)ѩTƨHUs΂e$Q1rpNYiV/A,N9HiXd}[.iK?x+ :G  c8/+;P}yU9"l1~AY;hѠI]J"WCҀ$&,0>x(|R90 s ƒG^#>j`pkcs1-0.7.5/tests/examples/rsa2048-priv-3prime.pem000064400000000000000000000033241046102023000176210ustar 00000000000000-----BEGIN RSA PRIVATE KEY----- MIIE2AIBAQKCAQEA6L9GSA2RROk9DnlxVU9+9F+yW4OhBpQW247HxlTrSJxpWjJ0 7ktfOgjjW6bR/y7Eh85URkHqDAmUzFVNIgEwjjrGSRMmGD9HfTDxZQAYALOHcb+W 9p3m1GGm4viAVxBPzdbGobaef5WifawMuuOcwfkmTAnf7qaEd0gsKBYTMBK6KaDW F/psa3D6w77csCDLH26jN1FjmI5/jJR0tUYsJNK1a8A/ntAC5Dx2Sx57BcMex9jp FYLOwJQvOW2rlPMWLRqqBB2pnO6QuB/0CLt1t7IzsZ005QTiWMHXdHBuTF/CsR+X yeTO6sNF+MV8PTcC9z/Jj37taIgSvptWBhjCRQIDAQABAoIBAFGtpmVs1XkgfPvS ZJJytnPeDYKOG/lqCOd+IN+aN4Og2Fv97wkdTEraiadFUNbDu9aI8wxA33jf9+cJ XGs9jaOsPp+wZ6MEufrWLTCrqsC8QCEMAldZo3QDSGQwivbkRMa+6k/qEtt4qXBa DwyLcys/1zPFh3qHHsxY+rJdQjbQyR8gfW/HntVWhlhiOYTvmSyF6nv/x/jBg2jm RCiRmLZM82jA/e/6fiS2XYlbcB+K9wrqsLt9LhTENU4Vvkcj7Ihd8UbXsMbShEwU 32Od2px5M//71a4jCLKpzn5sUuN2YQa4/vjVk7iEkbztaGMgReDi+4iaWO0v8otu XiCCuwECVgfqQeOwtvpjN9jSVLIfBsI3/apkQrOydWpHmycnPOzPu19HKqXZQeEd oarrF2RQ/AROpjnvbmt3tTDZikOs8tOVcXFO7VFrv0OnB55kDKRq5kDMrka1AlYH fpIQOZRT8fnWrYYrTYPuhlH5I1S8TyKxpTdu02/oDc/d9zzusyaXImW1ysIeL1/y Lwnm6grzWFQABNbR7zqCviFNIGsl+Y8PO6+M1PJdcWmsyZgJqQJWAjYimMJ8LXNh XDRQM8BVfBh2yI/gzyJyifJd2E+vRx83ZASXVuVf8cz8qaurynySHYX4DcHnISG+ P1rYtdXxtspPevApgJFRTE6z4z5jBeFUWhCWNO0CVgCDD/1VwaE+bX/R2NGKeRHJ UT5AwKAgk9Eo5TGH9iQXFXUnV51C1ccLTYFuuXYQbHCB8B47LMZU6WAa9IXg3tFh paq8JTWx56j1vddUEL57aemo198JAlYDtUxSGZYE2akgsberlfC0dLpGeWzEbD5j xINJkHG/rcDScyHr1T4JJx8oZGt1kMlxAvnkWKk7OgJKA1Zbyv+hX3PAW7+WU74j IkoeNVJKmJVkHHb9LjCCAQswggEHAlYD7HVTL7DSyhQmMmGOpphUjYSJ/jCoaNY3 odU4lcefFqY622DbIX3cDZVpSj2V0CnRqaLfVI7RBbLGqEhVc57bw86CkGUAJB1R ijFy+NRw+t1OHf5ZaQJWA6EVCKPlL6RBLO+O806/Of5IaQdYZH3MH1suiQ9pvIpL qcc/eJErBH8AA4rrGgaYl9kL0P06uLZHnZ8MgRXYC7i67GO5OH8vKzvi71Cf1/0C 9H2jxXkCVTnqImyr+zF+QaVZO5Fo0aASSZO0XZzRSiK9FVfNy0PSgCSsJu0shTC1 PpuTqHj0KIB8UoLruBE5n5EwF83yFJAT2Azfc/YJ1saSR163oSPQ6T5qYPw= -----END RSA PRIVATE KEY----- pkcs1-0.7.5/tests/examples/rsa2048-priv.der000064400000000000000000000022471046102023000164200ustar 000000000000000,Q_>BCp&3H3cGOo6:])9 K9AOG8,v=Syr~ _'^|KOYp("ܼʻ|CɂrEX2&mt:큒шLG9fܗǬE = |W_SOWN0ǻțxRUϰ'ȟN<򈎓2A֕ܐN> _pX%?^)\m8Pa☗[/~̃btd!^"Jip 6Mϻ.?i*gz?^R喎d|n@d-XO_HeQpOVzcd(m%UU+Ovd?x~eĪн'` \J^2uٗ,n}ѓ_n`a+\|ɜ=:$ãt vj}x T%M|LEL eY$۫5Rhn@mcdsva$-N*ep6~naF~eB%<~\1znZnX3ֻ"ܾ׏Nخ܆G<8ᄆCaнj3y@_&4;k-gu~@To$#jFSg`m\> 7Gb6IhSjNi "ߧ@u Rvd{xWwˋ"& O;ӪŐd1_āVv"!BC'h  cnUHSCp]hWɽe xa~.H$ m`T{d??6cI~4/.&ӡ4jֹw NbM]fi%]1|j}5M%B (kMB5XCQ { m>s.I *li@)q2u8׾LƹۥOV4Ĝ'}Fxcnj|hr1Xz˯OQqE/J|r0mcuZH.Qx.(tV$ol?S>1mɘ<*pkcs1-0.7.5/tests/examples/rsa2048-priv.pem000064400000000000000000000032131046102023000164210ustar 00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAtsQsUV8QpqrygsY+2+JCQ6Fw8/omM71IM2N/R8pPbzbgOl0p 78MZGsgPOQ2HSznjD0FPzsH8oO2B5Uftws04LHb2HJAYlz25+lN5cqfHAfa3fgmC 38FfwBkn7l582UtPWZ/wcBOnyCgb3yLcvJrXyrt8QxHJgvWO23ITrUVYszImbXQ6 7YGS0YhMrbixRzmo2tpm3JcIBtnHrEUMsT0NfFdfsZhTT8YbxBvA8FdODgEwx7u/ vf3J9qbi4+Kv8cvqyJuleIRSjVXPsIMnoejIn04APPKIjpMyQdnWlby7rNyQtE4+ CV+jcFjqJbE/Xilcvqxt6DirjFCvYeKYl1uHLwIDAQABAoIBAH7Mg2LA7bB0EWQh XiL3SrnZG6BpAHAM9jaQ5RFNjua9z7suP5YUaSpnegg/FopeUuWWjmQHudl8bg5A ZPgtoLdYoU8XubfUH19I4o1lUXBPVuaeeqn6Yw/HZCjAbSXkVdz8VbesK092ZD/e 0/4V/3irsn5lrMSq0L322yfvYKaRDFxKCF7UMnWrGcHZl6Msbv/OffLRk19uYB7t 4WGhK1zCfKIfgdLJnD0eoI6Q4wU6sJvvpyTe8NDDo8HpdAwNn3YSahSewKp9gHgg VIQlTZUdsHxM+R+2RUwJZYj9WSTbq+s1nKICUmjQBPnWbrPW963BE5utQPFt3mOe EWRzdsECgYEA3MBhJC1Okq+u5yrFE8plufdwNvm9fg5uYUYafvdlQiXsFTx+XDGm FXpuWhP/bheOh1jByzPZ1rvjF57xiZjkIuzcvtePTs/b5fT82K7CydDchkc8qb0W 2dI40h+13e++sUPKYdC9aqjZHzOgl3kOlkDbyRCF3F8mNDujE49rLWcCgYEA0/MU dX5A6VSDb5K+JCNq8vDaBKNGU8GAr2fpYAhtk/3mXLI+/Z0JN0di9ZgeNhhJr2jN 11OU/2pOButpsgnkIo2y36cOQPf5dQpSgXZke3iNDld3osuLIuPNJn/3C087AtOq +w4YxZClZLAxiLCqX8SBVrB2IiFCQ70SJ++n8vkCgYEAzmi3rBsNEA1jblVIh1PF wJhD/bOQ4nBd92iUV8m9jZdl4wl4YX4u/IBI9MMkIG24YIe2VOl7s9Rk5+4/jNg/ 4QQ2998Y6aljxOZJEdZ+3jQELy4m49OhrTRq2ta5t/Z3CMsJTmLe6f9NXWZpr5iK 8iVdHOjtMXxqfYaR2jVNEtsCgYAl9uWUQiAoa037v0I1wO5YQ9IZgJGJUSDWynsg C4JtPs5zji4ASY+sCipsqWnH8MPKGrC8QClxMr51ONe+30yw78a5jvfbpU9Wqpmq vOU0xJwnlH1GeMUcY8eMfOFocjG0yOtYeubvBIDLr0/AFzz9WHp+Z69RX7m53nUR GDlyKQKBgDGZVAbUBiB8rerqNbONBAxfipoa4IJ+ntBrFT2DtoIZNbSzaoK+nVbH kbWMJycaV5PVOh1lfAiZeWCxQz5RcZh/RS8USnxyMG1j4dP/wLcbdasI8uRaSC6Y hFHL5HjhLrIo0HRWySS2b2ztBI2FP1M+MaaGFPHDzm2OyZg85yr3 -----END RSA PRIVATE KEY----- pkcs1-0.7.5/tests/examples/rsa2048-pub.der000064400000000000000000000004161046102023000162220ustar 000000000000000 ,Q_>BCp&3H3cGOo6:])9 K9AOG8,v=Syr~ _'^|KOYp("ܼʻ|CɂrEX2&mt:큒шLG9fܗǬE = |W_SOWN0ǻțxRUϰ'ȟN<򈎓2A֕ܐN> _pX%?^)\m8Pa☗[/pkcs1-0.7.5/tests/examples/rsa2048-pub.pem000064400000000000000000000006521046102023000162330ustar 00000000000000-----BEGIN RSA PUBLIC KEY----- MIIBCgKCAQEAtsQsUV8QpqrygsY+2+JCQ6Fw8/omM71IM2N/R8pPbzbgOl0p78MZ GsgPOQ2HSznjD0FPzsH8oO2B5Uftws04LHb2HJAYlz25+lN5cqfHAfa3fgmC38Ff wBkn7l582UtPWZ/wcBOnyCgb3yLcvJrXyrt8QxHJgvWO23ITrUVYszImbXQ67YGS 0YhMrbixRzmo2tpm3JcIBtnHrEUMsT0NfFdfsZhTT8YbxBvA8FdODgEwx7u/vf3J 9qbi4+Kv8cvqyJuleIRSjVXPsIMnoejIn04APPKIjpMyQdnWlby7rNyQtE4+CV+j cFjqJbE/Xilcvqxt6DirjFCvYeKYl1uHLwIDAQAB -----END RSA PUBLIC KEY----- pkcs1-0.7.5/tests/examples/rsa4096-priv.der000064400000000000000000000044551046102023000164300ustar 000000000000000 )Era~I[0?}?v^T =ٓ @t6cX(t߃!c@wJLu.f7j"8gf,~"jߨbJ˜%cd8 ^k r#Qw9kHuJԧRB% ;6[! lk?v,@aHrl'>pZ6[(sF#)ypx@8aLRQ⥌uN%.#Kbb4l`p8WocA)6ssDEG @`HY..%T5?`!;JEY喝Y¿~>`Dd_6П$=xp{HuPn!wP  9J BAPw ]q Cb@gå m?,ڔCOsy|cw#&(᤮myIsoM}f[,H uQ {#"f@Ü /#MWV'D6kF1'9[~,V*_PWBcoo(cR-[W,'M:.LiF5ibYG幖C4t*EͲqaƍS:ϗ5@` e]ش^QEa"*&d>wW㹏2%Ip߄SDko]^?w'HpVxP&@db%0QNθle8EU/d"3PU_@Srףa.hE`ѧyޖ5$K0ɽ[::3̃ړƒnT$_{⮪d3'$e H4Dk҆"Iis!ÂGQD|k٨IVN'`,[!']D3uWk6Ii3| S suT1!:yB[f[qD2u`c[w%mw-MK a:yS0GD'^7jJHnrgɡ'=j>{Myuc# fSaM1Um%HA-1[!#ǟ]9VS̏eatg$@9nw!+J؞EսYRw 6o.{|܏{Em[<bhlHڰI6Ɓ"F_6}J_'aG)^.\>sDeW,b4FI~Vrp\egfMY2)CBtpc<9R_YT_RԆ+,6TϨ=*R3FvF}_}z״A_Rc$J?QȕHܶ0l4Ԡml{aVw]ۈvuwQ Ὴs\ɏ-w =䍞r Sch WWEWRtF^i,GdZap{2.mlKe$)G@nE@.KnvvOd*v hbu\fc*8@QI;ƠEwUF<֧ow_TYj8BP2*rD4Wt^tP",`qH4}$=i6F8 %~ådq OnDf!%&ch UW7ulĬKZ#ƀ:H?orKZ K)uN g,wCm o Fb24NJE}TO;C9/%//fQAaz ?#MhHE+ʩ@H:go?!'I cyjDM zg*}묜DYitCmsO*-Z'-aDqɘ$0ӝ)PC|^f\yY~c,XޛP!c+ѳU|H5f%]>Xls($$W^ (,4$hr I8)5*g_ ټ <%$yƓm(6^= 6j>HrL$C>;cK8W-r(Szdy:‡*Rh 3-Tٍn kFwgB!= z5P(s-k)gxqp'"^\pºr&}(/7ɍ6pkcs1-0.7.5/tests/examples/rsa4096-priv.pem000064400000000000000000000062531046102023000164350ustar 00000000000000-----BEGIN RSA PRIVATE KEY----- MIIJKQIBAAKCAgEAp6dFcoEeomF+Sehb1zDd4w8QP32I7j92XlQNPdmTu7C6FAAC hZ0LQIl0NmN/WLgo6nTfgyFjQHf5nUqi1UyjdYUu9ZdmHTcTzh7ztP1qjiICOORn ZoosfuOGHSISrmoevd+oi2LfEPa8957/SsKY+yVj3xuHZDga+bH7DM0IXgJrCtn2 chojUXfQOWtIdUrUp1JCJQqHO/L25+48dd1hPjZbpPMhCmzGa5Ci+j92LKaIQIe2 v4Fh6xRIGfD1cvIfbI4nPnDUWjZbiygZznNGE8wjsBMpoXkB8XB4QDhh9UxSoFHi pYx1wtnYAJG7mAihBsH37LQDThUFi+7HJcX5GdYuqiNLYmKNNGxgu5GecIUdqzhX Hm8O12NBKfmU6jaP7nNz397AREXrykf6IO0VQKhgyUi6vJjaWRyh3i4uJVQO+bfL NT9gITuBSkXTWe+puBHu/wjGWZO/ioXCv+qqftXmtD4YrmBEZM5flhUBNufQn4sk +tQ9eHARjPp7wkh1UG67wyG5d+CGGupQEoYgEh8LOUqc3QpCQRoTUMB3DZddcbAK kENiQMlnoMOlwgoPbed/Pyyv2pTtAUPB9uNPc+DKwnnu63xjdyOisCbIKALhpK66 qIRt+Y55GUmHc+DU8xmVb03jqtAO+5oUfWazrBoB01ss+0jUALDnqA3JdVECAwEA AQKCAgEAn+MJeyMiuQ+rZgbAF6CV6+ZAw5wQC87gLyOPoU2v846eV1aPESftRDYS a5BGMbEn7Dlbs+4SfrgsiNJWKn+1X+2NFFC35OLS839XQmNvzG8omWNSLVtXBggs rfoBwO6ZtNDpJ006mS4Gl0y+AWlGhjVpYqwZWf2b1EfluZaMBUPfG/E0dCrzRc2y +h+TcbDUz2HGjRbWU9jpmdT9OhbPl4o1qkDoYM3OCWVd2LTPGdQUGx6SrV5RqOSl wn+nRWEdkOSdDpKCIiq28SZkPhx3V4gW/OO5jzIdJUnylKRw34RTRGvzb5hd8l7Y /en98wc/sncn30jp4fxwVrx4llCQt4UBJkBkYsglMFHvhONO48POuPlsZYw4vkVV jS9k4p0iM1BVX8Hvoo7B9K+1ukCA8JqGzcNTjBrXyXLm16NhLmhFupr73xnwkGDR p3neljXi0vjgxRC6JMbESzDJvfr4W+kXrsXUOvqxqjrdM8yD2pPKxpIY9qNutH8Z nVQkyV/Z7Xsei+KuqmQzsickExbCDueSZQzrSL/WNERrGdKGtOoXIkmNoaNpcyEO w4JHUaWAjZqu9ZxEnhmlB3z+yhJr2ajdSZZWHU4ns2Cf+CxbGyHmJ4RdRJYbM7h1 1cT6n/NX72vjNklp4TN8kbKaB7mpE83kDOLVUwyQDnN1FoXmVDECggEBANAhOnlC W2ZbcZEYRIiT7DJ1YA9j2/hbd/To6Z7zAvboJZYEj23Kdy3mu/ESTbhLCv5hsDqG BKsAee1T8zBHl60Bs4xE/ielpF43hIOoBLVqSpZ/SPAahm5yHmfkyaEEivaJJ/qk PWqF2T579wdNunl1Y/yr4SMJt2ZTxtthTcIxzFVtnyWsSEGgLTHN8wFbISMH+dDH n+tdOVbOU8yPoWUb5gdh8Z90ZySJ6vnyFUCfOZVud6ghg/H3K7L+3fG5+/xK2J6k RYCd29W9WVJ3mQwL6TZvuy7PewV8wcPcj7d7+EVtB7vJWzwYFfSOYrgUaMPU2dls D0jasEmTvo2R7eUCggEBAM42xoEFIqvl1kZfNusTfaO56kpfHSfGYUcp645eLly4 jj7xpHOiGUS2ZVez3CzkYuS/NEbLSZADflZysXBcuugbZbr5Z6Jm3Bjv6A9Nu/4a WQYyBc4pQ8rfQhzOdK9wY/0ag688Oa+EUl9ZvcH/VIFfUq/R6NSGKyw2VPbPqD3A jiqdUrn4M8ZGr3aURn38X31617RBiV/Lf/vtUmMksBVKFYI/UQfIlUjt3LYdpTCM bMg01KDBbfpsodZ7YaZWd+sXGc0SXQ7w24gC+3bPwXV3vLJRCuKU4b+KkXOiuFwW prUIyY8tdwt/PeSNnnIMU+JjaAtX5xCUEAFXRVcGUv0CggEAdItGzQPlXmmyLEdk iP4b8x1azwNh965we4m42DLH5C6WbWzcS+Rl3CQp9ZIER0BuRYe6QOsuzfqUS9sI gG52doBPZCp2DwloAwIfiAGbsWJ1pdRcqWaRBGOOtyqb5ThAAFFJO8agRXfx8FVG PKa/1qdvd9tfVFlqgzhCUDIqcqWj/+pEhbn1NBpXdF4YxxeadJ1QvCIsYIVxSDR9 JD0BaTa4FkY4IMvzvbglBhUS5X7DpfOXuWQbGHEJ3U9uRJ+ahOn8ZskhyiWbJhLD Y7Ro1SAOVVc3f7za7HWxotVs/JfErEujWvojxoDOOoVIrj9vcslLu74QyQD8WhcL Swb+KQKCAQB1yk4LBp7uZ8PEwMCC+MgsjJbq0ne575RDbQuTb/K1neoKxEa2kmIy oKk0tpVOw0pF9X3r7lTfwU8aHDuEvkM5L+UlLy9mUbDpQahhjXqTxAMUCeDNCT8j E/IUuE1opR9IRSvxHcqpmkDfHEjLFojzuTpnGdUQCG+Cuqo/rRAh7eqHJwRJHCCe 4mN5rWqyrkTxTQkHeuP4Zyp9AeusnBlEn+O3WWl0s7uqQ8xt7nMcTyoYFi1aggLL J+Atvp5hwESRccmYHSQw053ijCmNjVCpQ7LyfF5mXLqyiXlZ/xml6H5jLFjNwx+b 3pvBAK//31DPIQ8eY6CmFJ0r1ujRs9gVAoIBAQCMVXxINei0BmYGpdwlXbw+tfFY bHMomIyOJCQD+Vde+w0oASwGNLckF2itciBJOCkG1jWvyx0qBb3/yAX+ZwOJt/qQ 1l+Ur7wgCNm8DTzO5CXfxyQCBQYDyfV57oUQ7MaTrG3TKDa24V49xSA2ahukr8kd Pkik1nJMpCRD9IA+OxJjSwQ4Vy2OE7xy8agoU7jZ/KYZnXqQq2TZ5595OsKH+aGQ EQgqUmjyCTMtVNmNbhkDCQf9nmuC7xJGd7oIrWeXpEIhPQl6NRxQoIko3XMtaymm z2cG2vXyD3j4cXD7J5QDxSIbXlxwwrqg5ppy4NHzJn29jJvd/yivqS83yY02 -----END RSA PRIVATE KEY----- pkcs1-0.7.5/tests/examples/rsa4096-pub.der000064400000000000000000000010161046102023000162240ustar 000000000000000 Era~I[0?}?v^T =ٓ @t6cX(t߃!c@wJLu.f7j"8gf,~"jߨbJ˜%cd8 ^k r#Qw9kHuJԧRB% ;6[! lk?v,@aHrl'>pZ6[(sF#)ypx@8aLRQ⥌uN%.#Kbb4l`p8WocA)6ssDEG @`HY..%T5?`!;JEY喝Y¿~>`Dd_6П$=xp{HuPn!wP  9J BAPw ]q Cb@gå m?,ڔCOsy|cw#&(᤮myIsoM}f[,H uQpkcs1-0.7.5/tests/examples/rsa4096-pub.pem000064400000000000000000000014071046102023000162370ustar 00000000000000-----BEGIN RSA PUBLIC KEY----- MIICCgKCAgEAp6dFcoEeomF+Sehb1zDd4w8QP32I7j92XlQNPdmTu7C6FAAChZ0L QIl0NmN/WLgo6nTfgyFjQHf5nUqi1UyjdYUu9ZdmHTcTzh7ztP1qjiICOORnZoos fuOGHSISrmoevd+oi2LfEPa8957/SsKY+yVj3xuHZDga+bH7DM0IXgJrCtn2choj UXfQOWtIdUrUp1JCJQqHO/L25+48dd1hPjZbpPMhCmzGa5Ci+j92LKaIQIe2v4Fh 6xRIGfD1cvIfbI4nPnDUWjZbiygZznNGE8wjsBMpoXkB8XB4QDhh9UxSoFHipYx1 wtnYAJG7mAihBsH37LQDThUFi+7HJcX5GdYuqiNLYmKNNGxgu5GecIUdqzhXHm8O 12NBKfmU6jaP7nNz397AREXrykf6IO0VQKhgyUi6vJjaWRyh3i4uJVQO+bfLNT9g ITuBSkXTWe+puBHu/wjGWZO/ioXCv+qqftXmtD4YrmBEZM5flhUBNufQn4sk+tQ9 eHARjPp7wkh1UG67wyG5d+CGGupQEoYgEh8LOUqc3QpCQRoTUMB3DZddcbAKkENi QMlnoMOlwgoPbed/Pyyv2pTtAUPB9uNPc+DKwnnu63xjdyOisCbIKALhpK66qIRt +Y55GUmHc+DU8xmVb03jqtAO+5oUfWazrBoB01ss+0jUALDnqA3JdVECAwEAAQ== -----END RSA PUBLIC KEY----- pkcs1-0.7.5/tests/params.rs000064400000000000000000000140071046102023000136530ustar 00000000000000//! PKCS#1 algorithm params tests use const_oid::db; use der::{ asn1::{AnyRef, ObjectIdentifier, OctetStringRef}, oid::AssociatedOid, Encode, }; use hex_literal::hex; use pkcs1::{RsaOaepParams, RsaPssParams, TrailerField}; /// Default PSS parameters using all default values (SHA1, MGF1) const RSA_PSS_PARAMETERS_DEFAULTS: &[u8] = &hex!("3000"); /// Example PSS parameters using SHA256 instead of SHA1 const RSA_PSS_PARAMETERS_SHA2_256: &[u8] = &hex!("3034a00f300d06096086480165030402010500a11c301a06092a864886f70d010108300d06096086480165030402010500a203020120"); /// Default OAEP parameters using all default values (SHA1, MGF1, Empty) const RSA_OAEP_PARAMETERS_DEFAULTS: &[u8] = &hex!("3000"); /// Example OAEP parameters using SHA256 instead of SHA1 const RSA_OAEP_PARAMETERS_SHA2_256: &[u8] = &hex!("302fa00f300d06096086480165030402010500a11c301a06092a864886f70d010108300d06096086480165030402010500"); struct Sha1Mock {} impl AssociatedOid for Sha1Mock { const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.14.3.2.26"); } struct Sha256Mock {} impl AssociatedOid for Sha256Mock { const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.1"); } #[test] fn decode_pss_param() { let param = RsaPssParams::try_from(RSA_PSS_PARAMETERS_SHA2_256).unwrap(); assert!(param .hash .assert_algorithm_oid(db::rfc5912::ID_SHA_256) .is_ok()); assert_eq!(param.hash.parameters, Some(AnyRef::NULL)); assert!(param .mask_gen .assert_algorithm_oid(db::rfc5912::ID_MGF_1) .is_ok()); assert!(param .mask_gen .parameters .unwrap() .assert_algorithm_oid(db::rfc5912::ID_SHA_256) .is_ok()); assert_eq!(param.salt_len, 32); assert_eq!(param.trailer_field, TrailerField::BC); } #[test] fn encode_pss_param() { let mut buf = [0_u8; 256]; let param = RsaPssParams::try_from(RSA_PSS_PARAMETERS_SHA2_256).unwrap(); assert_eq!( param.encode_to_slice(&mut buf).unwrap(), RSA_PSS_PARAMETERS_SHA2_256 ); } #[test] fn decode_pss_param_default() { let param = RsaPssParams::try_from(RSA_PSS_PARAMETERS_DEFAULTS).unwrap(); assert!(param .hash .assert_algorithm_oid(db::rfc5912::ID_SHA_1) .is_ok()); assert_eq!(param.hash.parameters, Some(AnyRef::NULL)); assert!(param .mask_gen .assert_algorithm_oid(db::rfc5912::ID_MGF_1) .is_ok()); assert!(param .mask_gen .parameters .unwrap() .assert_algorithm_oid(db::rfc5912::ID_SHA_1) .is_ok()); assert_eq!( param.mask_gen.parameters.unwrap().parameters, Some(AnyRef::NULL) ); assert_eq!(param.salt_len, 20); assert_eq!(param.trailer_field, TrailerField::BC); assert_eq!(param, Default::default()) } #[test] fn encode_pss_param_default() { let mut buf = [0_u8; 256]; assert_eq!( RsaPssParams::default().encode_to_slice(&mut buf).unwrap(), RSA_PSS_PARAMETERS_DEFAULTS ); } #[test] fn new_pss_param() { let mut buf = [0_u8; 256]; let param = RsaPssParams::new::(20); assert_eq!( param.encode_to_slice(&mut buf).unwrap(), RSA_PSS_PARAMETERS_DEFAULTS ); let param = RsaPssParams::new::(32); assert_eq!( param.encode_to_slice(&mut buf).unwrap(), RSA_PSS_PARAMETERS_SHA2_256 ); } #[test] fn decode_oaep_param() { let param = RsaOaepParams::try_from(RSA_OAEP_PARAMETERS_SHA2_256).unwrap(); assert!(param .hash .assert_algorithm_oid(db::rfc5912::ID_SHA_256) .is_ok()); assert_eq!(param.hash.parameters, Some(AnyRef::NULL)); assert!(param .mask_gen .assert_algorithm_oid(db::rfc5912::ID_MGF_1) .is_ok()); assert!(param .mask_gen .parameters .unwrap() .assert_algorithm_oid(db::rfc5912::ID_SHA_256) .is_ok()); assert!(param .p_source .assert_algorithm_oid(db::rfc5912::ID_P_SPECIFIED) .is_ok()); assert!(param .p_source .parameters_any() .unwrap() .decode_as::>() .unwrap() .is_empty(),); } #[test] fn encode_oaep_param() { let mut buf = [0_u8; 256]; let param = RsaOaepParams::try_from(RSA_OAEP_PARAMETERS_SHA2_256).unwrap(); assert_eq!( param.encode_to_slice(&mut buf).unwrap(), RSA_OAEP_PARAMETERS_SHA2_256 ); } #[test] fn decode_oaep_param_default() { let param = RsaOaepParams::try_from(RSA_OAEP_PARAMETERS_DEFAULTS).unwrap(); assert!(param .hash .assert_algorithm_oid(db::rfc5912::ID_SHA_1) .is_ok()); assert_eq!(param.hash.parameters, Some(AnyRef::NULL)); assert!(param .mask_gen .assert_algorithm_oid(db::rfc5912::ID_MGF_1) .is_ok()); assert!(param .mask_gen .parameters .unwrap() .assert_algorithm_oid(db::rfc5912::ID_SHA_1) .is_ok()); assert_eq!( param.mask_gen.parameters.unwrap().parameters, Some(AnyRef::NULL) ); assert!(param .p_source .assert_algorithm_oid(db::rfc5912::ID_P_SPECIFIED) .is_ok()); assert!(param .p_source .parameters_any() .unwrap() .decode_as::>() .unwrap() .is_empty(),); assert_eq!(param, Default::default()) } #[test] fn encode_oaep_param_default() { let mut buf = [0_u8; 256]; assert_eq!( RsaOaepParams::default().encode_to_slice(&mut buf).unwrap(), RSA_OAEP_PARAMETERS_DEFAULTS ); } #[test] fn new_oaep_param() { let mut buf = [0_u8; 256]; let param = RsaOaepParams::new::(); assert_eq!( param.encode_to_slice(&mut buf).unwrap(), RSA_OAEP_PARAMETERS_DEFAULTS ); let param = RsaOaepParams::new::(); println!("{:02x?}", param.encode_to_slice(&mut buf).unwrap()); assert_eq!( param.encode_to_slice(&mut buf).unwrap(), RSA_OAEP_PARAMETERS_SHA2_256 ); } pkcs1-0.7.5/tests/private_key.rs000064400000000000000000000323751046102023000147220ustar 00000000000000//! PKCS#1 private key tests use hex_literal::hex; use pkcs1::{RsaPrivateKey, Version}; /// RSA-2048 PKCS#1 private key encoded as ASN.1 DER. /// /// Note: this key is extracted from the corresponding `rsa2048-priv.der` /// example key in the `pkcs8` crate. const RSA_2048_DER_EXAMPLE: &[u8] = include_bytes!("examples/rsa2048-priv.der"); /// RSA-4096 PKCS#1 private key encoded as ASN.1 DER const RSA_4096_DER_EXAMPLE: &[u8] = include_bytes!("examples/rsa4096-priv.der"); /// RSA-2048 PKCS#1 private key with 3 primes encoded as ASN.1 DER const RSA_2048_MULTI_PRIME_DER_EXAMPLE: &[u8] = include_bytes!("examples/rsa2048-priv-3prime.der"); #[test] fn decode_rsa2048_der() { let key = RsaPrivateKey::try_from(RSA_2048_DER_EXAMPLE).unwrap(); assert_eq!(key.version(), Version::TwoPrime); // Extracted using: // $ openssl asn1parse -in tests/examples/rsa2048-priv.pem assert_eq!(key.modulus.as_bytes(), hex!("B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C76F61C9018973DB9FA537972A7C701F6B77E0982DFC15FC01927EE5E7CD94B4F599FF07013A7C8281BDF22DCBC9AD7CABB7C4311C982F58EDB7213AD4558B332266D743AED8192D1884CADB8B14739A8DADA66DC970806D9C7AC450CB13D0D7C575FB198534FC61BC41BC0F0574E0E0130C7BBBFBDFDC9F6A6E2E3E2AFF1CBEAC89BA57884528D55CFB08327A1E8C89F4E003CF2888E933241D9D695BCBBACDC90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F")); assert_eq!(key.public_exponent.as_bytes(), hex!("010001")); assert_eq!(key.private_exponent.as_bytes(), hex!("7ECC8362C0EDB0741164215E22F74AB9D91BA06900700CF63690E5114D8EE6BDCFBB2E3F9614692A677A083F168A5E52E5968E6407B9D97C6E0E4064F82DA0B758A14F17B9B7D41F5F48E28D6551704F56E69E7AA9FA630FC76428C06D25E455DCFC55B7AC2B4F76643FDED3FE15FF78ABB27E65ACC4AAD0BDF6DB27EF60A6910C5C4A085ED43275AB19C1D997A32C6EFFCE7DF2D1935F6E601EEDE161A12B5CC27CA21F81D2C99C3D1EA08E90E3053AB09BEFA724DEF0D0C3A3C1E9740C0D9F76126A149EC0AA7D8078205484254D951DB07C4CF91FB6454C096588FD5924DBABEB359CA2025268D004F9D66EB3D6F7ADC1139BAD40F16DDE639E11647376C1")); assert_eq!(key.prime1.as_bytes(), hex!("DCC061242D4E92AFAEE72AC513CA65B9F77036F9BD7E0E6E61461A7EF7654225EC153C7E5C31A6157A6E5A13FF6E178E8758C1CB33D9D6BBE3179EF18998E422ECDCBED78F4ECFDBE5F4FCD8AEC2C9D0DC86473CA9BD16D9D238D21FB5DDEFBEB143CA61D0BD6AA8D91F33A097790E9640DBC91085DC5F26343BA3138F6B2D67")); assert_eq!(key.prime2.as_bytes(), hex!("D3F314757E40E954836F92BE24236AF2F0DA04A34653C180AF67E960086D93FDE65CB23EFD9D09374762F5981E361849AF68CDD75394FF6A4E06EB69B209E4228DB2DFA70E40F7F9750A528176647B788D0E5777A2CB8B22E3CD267FF70B4F3B02D3AAFB0E18C590A564B03188B0AA5FC48156B07622214243BD1227EFA7F2F9")); assert_eq!(key.exponent1.as_bytes(), hex!("CE68B7AC1B0D100D636E55488753C5C09843FDB390E2705DF7689457C9BD8D9765E30978617E2EFC8048F4C324206DB86087B654E97BB3D464E7EE3F8CD83FE10436F7DF18E9A963C4E64911D67EDE34042F2E26E3D3A1AD346ADAD6B9B7F67708CB094E62DEE9FF4D5D6669AF988AF2255D1CE8ED317C6A7D8691DA354D12DB")); assert_eq!(key.exponent2.as_bytes(), hex!("25F6E5944220286B4DFBBF4235C0EE5843D2198091895120D6CA7B200B826D3ECE738E2E00498FAC0A2A6CA969C7F0C3CA1AB0BC40297132BE7538D7BEDF4CB0EFC6B98EF7DBA54F56AA99AABCE534C49C27947D4678C51C63C78C7CE1687231B4C8EB587AE6EF0480CBAF4FC0173CFD587A7E67AF515FB9B9DE751118397229")); assert_eq!(key.coefficient.as_bytes(), hex!("31995406D406207CADEAEA35B38D040C5F8A9A1AE0827E9ED06B153D83B6821935B4B36A82BE9D56C791B58C27271A5793D53A1D657C08997960B1433E5171987F452F144A7C72306D63E1D3FFC0B71B75AB08F2E45A482E988451CBE478E12EB228D07456C924B66F6CED048D853F533E31A68614F1C3CE6D8EC9983CE72AF7")); assert!(key.other_prime_infos.is_none()); } #[test] fn decode_rsa4096_der() { let key = RsaPrivateKey::try_from(RSA_4096_DER_EXAMPLE).unwrap(); assert_eq!(key.version(), Version::TwoPrime); // Extracted using: // $ openssl asn1parse -in tests/examples/rsa4096-priv.pem assert_eq!(key.modulus.as_bytes(), hex!("A7A74572811EA2617E49E85BD730DDE30F103F7D88EE3F765E540D3DD993BBB0BA140002859D0B40897436637F58B828EA74DF8321634077F99D4AA2D54CA375852EF597661D3713CE1EF3B4FD6A8E220238E467668A2C7EE3861D2212AE6A1EBDDFA88B62DF10F6BCF79EFF4AC298FB2563DF1B8764381AF9B1FB0CCD085E026B0AD9F6721A235177D0396B48754AD4A75242250A873BF2F6E7EE3C75DD613E365BA4F3210A6CC66B90A2FA3F762CA6884087B6BF8161EB144819F0F572F21F6C8E273E70D45A365B8B2819CE734613CC23B01329A17901F17078403861F54C52A051E2A58C75C2D9D80091BB9808A106C1F7ECB4034E15058BEEC725C5F919D62EAA234B62628D346C60BB919E70851DAB38571E6F0ED7634129F994EA368FEE7373DFDEC04445EBCA47FA20ED1540A860C948BABC98DA591CA1DE2E2E25540EF9B7CB353F60213B814A45D359EFA9B811EEFF08C65993BF8A85C2BFEAAA7ED5E6B43E18AE604464CE5F96150136E7D09F8B24FAD43D7870118CFA7BC24875506EBBC321B977E0861AEA50128620121F0B394A9CDD0A42411A1350C0770D975D71B00A90436240C967A0C3A5C20A0F6DE77F3F2CAFDA94ED0143C1F6E34F73E0CAC279EEEB7C637723A2B026C82802E1A4AEBAA8846DF98E7919498773E0D4F319956F4DE3AAD00EFB9A147D66B3AC1A01D35B2CFB48D400B0E7A80DC97551")); assert_eq!(key.public_exponent.as_bytes(), hex!("010001")); assert_eq!(key.private_exponent.as_bytes(), hex!("9FE3097B2322B90FAB6606C017A095EBE640C39C100BCEE02F238FA14DAFF38E9E57568F1127ED4436126B904631B127EC395BB3EE127EB82C88D2562A7FB55FED8D1450B7E4E2D2F37F5742636FCC6F289963522D5B5706082CADFA01C0EE99B4D0E9274D3A992E06974CBE01694686356962AC1959FD9BD447E5B9968C0543DF1BF134742AF345CDB2FA1F9371B0D4CF61C68D16D653D8E999D4FD3A16CF978A35AA40E860CDCE09655DD8B4CF19D4141B1E92AD5E51A8E4A5C27FA745611D90E49D0E9282222AB6F126643E1C77578816FCE3B98F321D2549F294A470DF8453446BF36F985DF25ED8FDE9FDF3073FB27727DF48E9E1FC7056BC78965090B7850126406462C8253051EF84E34EE3C3CEB8F96C658C38BE45558D2F64E29D223350555FC1EFA28EC1F4AFB5BA4080F09A86CDC3538C1AD7C972E6D7A3612E6845BA9AFBDF19F09060D1A779DE9635E2D2F8E0C510BA24C6C44B30C9BDFAF85BE917AEC5D43AFAB1AA3ADD33CC83DA93CAC69218F6A36EB47F199D5424C95FD9ED7B1E8BE2AEAA6433B227241316C20EE792650CEB48BFD634446B19D286B4EA1722498DA1A36973210EC3824751A5808D9AAEF59C449E19A5077CFECA126BD9A8DD4996561D4E27B3609FF82C5B1B21E627845D44961B33B875D5C4FA9FF357EF6BE3364969E1337C91B29A07B9A913CDE40CE2D5530C900E73751685E65431")); assert_eq!(key.prime1.as_bytes(), hex!("D0213A79425B665B719118448893EC3275600F63DBF85B77F4E8E99EF302F6E82596048F6DCA772DE6BBF1124DB84B0AFE61B03A8604AB0079ED53F3304797AD01B38C44FE27A5A45E378483A804B56A4A967F48F01A866E721E67E4C9A1048AF68927FAA43D6A85D93E7BF7074DBA797563FCABE12309B76653C6DB614DC231CC556D9F25AC4841A02D31CDF3015B212307F9D0C79FEB5D3956CE53CC8FA1651BE60761F19F74672489EAF9F215409F39956E77A82183F1F72BB2FEDDF1B9FBFC4AD89EA445809DDBD5BD595277990C0BE9366FBB2ECF7B057CC1C3DC8FB77BF8456D07BBC95B3C1815F48E62B81468C3D4D9D96C0F48DAB04993BE8D91EDE5")); assert_eq!(key.prime2.as_bytes(), hex!("CE36C6810522ABE5D6465F36EB137DA3B9EA4A5F1D27C6614729EB8E5E2E5CB88E3EF1A473A21944B66557B3DC2CE462E4BF3446CB4990037E5672B1705CBAE81B65BAF967A266DC18EFE80F4DBBFE1A59063205CE2943CADF421CCE74AF7063FD1A83AF3C39AF84525F59BDC1FF54815F52AFD1E8D4862B2C3654F6CFA83DC08E2A9D52B9F833C646AF7694467DFC5F7D7AD7B441895FCB7FFBED526324B0154A15823F5107C89548EDDCB61DA5308C6CC834D4A0C16DFA6CA1D67B61A65677EB1719CD125D0EF0DB8802FB76CFC17577BCB2510AE294E1BF8A9173A2B85C16A6B508C98F2D770B7F3DE48D9E720C53E263680B57E7109410015745570652FD")); assert_eq!(key.exponent1.as_bytes(), hex!("748B46CD03E55E69B22C476488FE1BF31D5ACF0361F7AE707B89B8D832C7E42E966D6CDC4BE465DC2429F5920447406E4587BA40EB2ECDFA944BDB08806E7676804F642A760F096803021F88019BB16275A5D45CA9669104638EB72A9BE538400051493BC6A04577F1F055463CA6BFD6A76F77DB5F54596A83384250322A72A5A3FFEA4485B9F5341A57745E18C7179A749D50BC222C60857148347D243D016936B816463820CBF3BDB825061512E57EC3A5F397B9641B187109DD4F6E449F9A84E9FC66C921CA259B2612C363B468D5200E5557377FBCDAEC75B1A2D56CFC97C4AC4BA35AFA23C680CE3A8548AE3F6F72C94BBBBE10C900FC5A170B4B06FE29")); assert_eq!(key.exponent2.as_bytes(), hex!("75CA4E0B069EEE67C3C4C0C082F8C82C8C96EAD277B9EF94436D0B936FF2B59DEA0AC446B6926232A0A934B6954EC34A45F57DEBEE54DFC14F1A1C3B84BE43392FE5252F2F6651B0E941A8618D7A93C4031409E0CD093F2313F214B84D68A51F48452BF11DCAA99A40DF1C48CB1688F3B93A6719D510086F82BAAA3FAD1021EDEA872704491C209EE26379AD6AB2AE44F14D09077AE3F8672A7D01EBAC9C19449FE3B7596974B3BBAA43CC6DEE731C4F2A18162D5A8202CB27E02DBE9E61C0449171C9981D2430D39DE28C298D8D50A943B2F27C5E665CBAB2897959FF19A5E87E632C58CDC31F9BDE9BC100AFFFDF50CF210F1E63A0A6149D2BD6E8D1B3D815")); assert_eq!(key.coefficient.as_bytes(), hex!("8C557C4835E8B4066606A5DC255DBC3EB5F1586C7328988C8E242403F9575EFB0D28012C0634B7241768AD722049382906D635AFCB1D2A05BDFFC805FE670389B7FA90D65F94AFBC2008D9BC0D3CCEE425DFC72402050603C9F579EE8510ECC693AC6DD32836B6E15E3DC520366A1BA4AFC91D3E48A4D6724CA42443F4803E3B12634B0438572D8E13BC72F1A82853B8D9FCA6199D7A90AB64D9E79F793AC287F9A19011082A5268F209332D54D98D6E19030907FD9E6B82EF124677BA08AD6797A442213D097A351C50A08928DD732D6B29A6CF6706DAF5F20F78F87170FB279403C5221B5E5C70C2BAA0E69A72E0D1F3267DBD8C9BDDFF28AFA92F37C98D36")); assert!(key.other_prime_infos.is_none()); } #[cfg(not(feature = "alloc"))] #[test] fn decode_rsa2048_multi_prime_der() { // Multi-prime RSA keys are unsupported when the alloc feature is disabled assert!(RsaPrivateKey::try_from(RSA_2048_MULTI_PRIME_DER_EXAMPLE).is_err()); } #[cfg(feature = "alloc")] #[test] fn decode_rsa2048_multi_prime_der() { let key = RsaPrivateKey::try_from(RSA_2048_MULTI_PRIME_DER_EXAMPLE).unwrap(); assert_eq!(key.version(), Version::Multi); // Extracted using: // $ openssl asn1parse -in tests/examples/rsa2048-priv-3prime.pem assert_eq!(key.modulus.as_bytes(), hex!("E8BF46480D9144E93D0E7971554F7EF45FB25B83A1069416DB8EC7C654EB489C695A3274EE4B5F3A08E35BA6D1FF2EC487CE544641EA0C0994CC554D2201308E3AC6491326183F477D30F165001800B38771BF96F69DE6D461A6E2F88057104FCDD6C6A1B69E7F95A27DAC0CBAE39CC1F9264C09DFEEA68477482C2816133012BA29A0D617FA6C6B70FAC3BEDCB020CB1F6EA3375163988E7F8C9474B5462C24D2B56BC03F9ED002E43C764B1E7B05C31EC7D8E91582CEC0942F396DAB94F3162D1AAA041DA99CEE90B81FF408BB75B7B233B19D34E504E258C1D774706E4C5FC2B11F97C9E4CEEAC345F8C57C3D3702F73FC98F7EED688812BE9B560618C245")); assert_eq!(key.public_exponent.as_bytes(), hex!("010001")); assert_eq!(key.private_exponent.as_bytes(), hex!("51ADA6656CD579207CFBD2649272B673DE0D828E1BF96A08E77E20DF9A3783A0D85BFDEF091D4C4ADA89A74550D6C3BBD688F30C40DF78DFF7E7095C6B3D8DA3AC3E9FB067A304B9FAD62D30ABAAC0BC40210C025759A374034864308AF6E444C6BEEA4FEA12DB78A9705A0F0C8B732B3FD733C5877A871ECC58FAB25D4236D0C91F207D6FC79ED5568658623984EF992C85EA7BFFC7F8C18368E644289198B64CF368C0FDEFFA7E24B65D895B701F8AF70AEAB0BB7D2E14C4354E15BE4723EC885DF146D7B0C6D2844C14DF639DDA9C7933FFFBD5AE2308B2A9CE7E6C52E3766106B8FEF8D593B88491BCED68632045E0E2FB889A58ED2FF28B6E5E2082BB01")); assert_eq!(key.prime1.as_bytes(), hex!("07EA41E3B0B6FA6337D8D254B21F06C237FDAA6442B3B2756A479B27273CECCFBB5F472AA5D941E11DA1AAEB176450FC044EA639EF6E6B77B530D98A43ACF2D39571714EED516BBF43A7079E640CA46AE640CCAE46B5")); assert_eq!(key.prime2.as_bytes(), hex!("077E9210399453F1F9D6AD862B4D83EE8651F92354BC4F22B1A5376ED36FE80DCFDDF73CEEB326972265B5CAC21E2F5FF22F09E6EA0AF358540004D6D1EF3A82BE214D206B25F98F0F3BAF8CD4F25D7169ACC99809A9")); assert_eq!(key.exponent1.as_bytes(), hex!("02362298C27C2D73615C345033C0557C1876C88FE0CF227289F25DD84FAF471F3764049756E55FF1CCFCA9ABABCA7C921D85F80DC1E72121BE3F5AD8B5D5F1B6CA4F7AF0298091514C4EB3E33E6305E1545A109634ED")); assert_eq!(key.exponent2.as_bytes(), hex!("830FFD55C1A13E6D7FD1D8D18A7911C9513E40C0A02093D128E53187F62417157527579D42D5C70B4D816EB976106C7081F01E3B2CC654E9601AF485E0DED161A5AABC2535B1E7A8F5BDD75410BE7B69E9A8D7DF09")); assert_eq!(key.coefficient.as_bytes(), hex!("03B54C52199604D9A920B1B7AB95F0B474BA46796CC46C3E63C483499071BFADC0D27321EBD53E09271F28646B7590C97102F9E458A93B3A024A03565BCAFFA15F73C05BBF9653BE23224A1E35524A9895641C76FD2E")); let other_prime_infos = key.other_prime_infos.unwrap(); assert_eq!(other_prime_infos.len(), 1); assert_eq!(other_prime_infos[0].prime.as_bytes(), hex!("03EC75532FB0D2CA142632618EA698548D8489FE30A868D637A1D53895C79F16A63ADB60DB217DDC0D95694A3D95D029D1A9A2DF548ED105B2C6A84855739EDBC3CE82906500241D518A3172F8D470FADD4E1DFE5969")); assert_eq!(other_prime_infos[0].exponent.as_bytes(), hex!("03A11508A3E52FA4412CEF8EF34EBF39FE48690758647DCC1F5B2E890F69BC8A4BA9C73F78912B047F00038AEB1A069897D90BD0FD3AB8B6479D9F0C8115D80BB8BAEC63B9387F2F2B3BE2EF509FD7FD02F47DA3C579")); assert_eq!(other_prime_infos[0].coefficient.as_bytes(), hex!("39EA226CABFB317E41A5593B9168D1A0124993B45D9CD14A22BD1557CDCB43D28024AC26ED2C8530B53E9B93A878F428807C5282EBB811399F913017CDF2149013D80CDF73F609D6C692475EB7A123D0E93E6A60FC")); } #[test] fn private_key_to_public_key() { let private_key = RsaPrivateKey::try_from(RSA_2048_DER_EXAMPLE).unwrap(); let public_key = private_key.public_key(); // Extracted using: // $ openssl asn1parse -in tests/examples/rsa2048-pub.pem assert_eq!(public_key.modulus.as_bytes(), hex!("B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C76F61C9018973DB9FA537972A7C701F6B77E0982DFC15FC01927EE5E7CD94B4F599FF07013A7C8281BDF22DCBC9AD7CABB7C4311C982F58EDB7213AD4558B332266D743AED8192D1884CADB8B14739A8DADA66DC970806D9C7AC450CB13D0D7C575FB198534FC61BC41BC0F0574E0E0130C7BBBFBDFDC9F6A6E2E3E2AFF1CBEAC89BA57884528D55CFB08327A1E8C89F4E003CF2888E933241D9D695BCBBACDC90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F")); assert_eq!(public_key.public_exponent.as_bytes(), hex!("010001")); } pkcs1-0.7.5/tests/public_key.rs000064400000000000000000000073241046102023000145220ustar 00000000000000//! PKCS#1 public key tests use hex_literal::hex; use pkcs1::RsaPublicKey; /// RSA-2048 PKCS#1 public key encoded as ASN.1 DER. /// /// Note: this key is extracted from the corresponding `rsa2048-priv.der` /// example key in the `pkcs8` crate. const RSA_2048_DER_EXAMPLE: &[u8] = include_bytes!("examples/rsa2048-pub.der"); /// RSA-4096 PKCS#1 public key encoded as ASN.1 DER const RSA_4096_DER_EXAMPLE: &[u8] = include_bytes!("examples/rsa4096-pub.der"); // /// RSA-2048 PKCS#1 public key encoded as PEM // #[cfg(feature = "pem")] // const RSA_2048_PEM_EXAMPLE: &str = include_str!("examples/rsa2048-pub.pem"); // // /// RSA-4096 PKCS#1 public key encoded as PEM // #[cfg(feature = "pem")] // const RSA_4096_PEM_EXAMPLE: &str = include_str!("examples/rsa4096-pub.pem"); #[test] fn decode_rsa2048_der() { let key = RsaPublicKey::try_from(RSA_2048_DER_EXAMPLE).unwrap(); // Extracted using: // $ openssl asn1parse -in tests/examples/rsa2048-pub.pem assert_eq!(key.modulus.as_bytes(), hex!("B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C76F61C9018973DB9FA537972A7C701F6B77E0982DFC15FC01927EE5E7CD94B4F599FF07013A7C8281BDF22DCBC9AD7CABB7C4311C982F58EDB7213AD4558B332266D743AED8192D1884CADB8B14739A8DADA66DC970806D9C7AC450CB13D0D7C575FB198534FC61BC41BC0F0574E0E0130C7BBBFBDFDC9F6A6E2E3E2AFF1CBEAC89BA57884528D55CFB08327A1E8C89F4E003CF2888E933241D9D695BCBBACDC90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F")); assert_eq!(key.public_exponent.as_bytes(), hex!("010001")); } #[test] fn decode_rsa4096_der() { let key = RsaPublicKey::try_from(RSA_4096_DER_EXAMPLE).unwrap(); // Extracted using: // $ openssl asn1parse -in tests/examples/rsa4096-pub.pem assert_eq!(key.modulus.as_bytes(), hex!("A7A74572811EA2617E49E85BD730DDE30F103F7D88EE3F765E540D3DD993BBB0BA140002859D0B40897436637F58B828EA74DF8321634077F99D4AA2D54CA375852EF597661D3713CE1EF3B4FD6A8E220238E467668A2C7EE3861D2212AE6A1EBDDFA88B62DF10F6BCF79EFF4AC298FB2563DF1B8764381AF9B1FB0CCD085E026B0AD9F6721A235177D0396B48754AD4A75242250A873BF2F6E7EE3C75DD613E365BA4F3210A6CC66B90A2FA3F762CA6884087B6BF8161EB144819F0F572F21F6C8E273E70D45A365B8B2819CE734613CC23B01329A17901F17078403861F54C52A051E2A58C75C2D9D80091BB9808A106C1F7ECB4034E15058BEEC725C5F919D62EAA234B62628D346C60BB919E70851DAB38571E6F0ED7634129F994EA368FEE7373DFDEC04445EBCA47FA20ED1540A860C948BABC98DA591CA1DE2E2E25540EF9B7CB353F60213B814A45D359EFA9B811EEFF08C65993BF8A85C2BFEAAA7ED5E6B43E18AE604464CE5F96150136E7D09F8B24FAD43D7870118CFA7BC24875506EBBC321B977E0861AEA50128620121F0B394A9CDD0A42411A1350C0770D975D71B00A90436240C967A0C3A5C20A0F6DE77F3F2CAFDA94ED0143C1F6E34F73E0CAC279EEEB7C637723A2B026C82802E1A4AEBAA8846DF98E7919498773E0D4F319956F4DE3AAD00EFB9A147D66B3AC1A01D35B2CFB48D400B0E7A80DC97551")); assert_eq!(key.public_exponent.as_bytes(), hex!("010001")); } // TODO(tarcieri): test trait-based PEM decoding // #[test] // #[cfg(feature = "pem")] // fn decode_rsa_2048_pem() { // let pkcs1_doc: Document = RSA_2048_PEM_EXAMPLE.parse().unwrap(); // assert_eq!(pkcs1_doc.as_ref(), RSA_2048_DER_EXAMPLE); // // // Ensure `Document` parses successfully // let pk = RsaPublicKey::try_from(RSA_2048_DER_EXAMPLE).unwrap(); // assert_eq!(pkcs1_doc.decode().modulus.as_bytes(), pk.modulus.as_bytes()); // } // // #[test] // #[cfg(feature = "pem")] // fn decode_rsa_4096_pem() { // let pkcs1_doc: Document = RSA_4096_PEM_EXAMPLE.parse().unwrap(); // assert_eq!(pkcs1_doc.as_ref(), RSA_4096_DER_EXAMPLE); // // // Ensure `Document` parses successfully // let pk = RsaPublicKey::try_from(RSA_4096_DER_EXAMPLE).unwrap(); // assert_eq!(pkcs1_doc.decode().modulus.as_bytes(), pk.modulus.as_bytes()); // } pkcs1-0.7.5/tests/traits.rs000064400000000000000000000053711046102023000137020ustar 00000000000000//! Tests for PKCS#1 encoding/decoding traits. #![cfg(any(feature = "pem", feature = "std"))] use der::SecretDocument; use pkcs1::{DecodeRsaPrivateKey, EncodeRsaPrivateKey, Result}; #[cfg(feature = "pem")] use pkcs1::der::pem::LineEnding; #[cfg(feature = "std")] use tempfile::tempdir; #[cfg(all(feature = "pem", feature = "std"))] use std::fs; /// PKCS#1 `RsaPrivateKey` encoded as ASN.1 DER const RSA_2048_PRIV_DER_EXAMPLE: &[u8] = include_bytes!("examples/rsa2048-priv.der"); /// PKCS#1 `RsaPrivateKey` encoded as PEM #[cfg(feature = "pem")] const RSA_2048_PRIV_PEM_EXAMPLE: &str = include_str!("examples/rsa2048-priv.pem"); /// Mock RSA private key type for testing trait impls against. pub struct MockPrivateKey(Vec); impl AsRef<[u8]> for MockPrivateKey { fn as_ref(&self) -> &[u8] { self.0.as_ref() } } impl DecodeRsaPrivateKey for MockPrivateKey { fn from_pkcs1_der(bytes: &[u8]) -> Result { Ok(MockPrivateKey(bytes.to_vec())) } } impl EncodeRsaPrivateKey for MockPrivateKey { fn to_pkcs1_der(&self) -> Result { Ok(SecretDocument::try_from(self.as_ref())?) } } #[cfg(feature = "pem")] #[test] fn from_pkcs1_pem() { let key = MockPrivateKey::from_pkcs1_pem(RSA_2048_PRIV_PEM_EXAMPLE).unwrap(); assert_eq!(key.as_ref(), RSA_2048_PRIV_DER_EXAMPLE); } #[cfg(feature = "std")] #[test] fn read_pkcs1_der_file() { let key = MockPrivateKey::read_pkcs1_der_file("tests/examples/rsa2048-priv.der").unwrap(); assert_eq!(key.as_ref(), RSA_2048_PRIV_DER_EXAMPLE); } #[cfg(all(feature = "pem", feature = "std"))] #[test] fn read_pkcs1_pem_file() { let key = MockPrivateKey::read_pkcs1_pem_file("tests/examples/rsa2048-priv.pem").unwrap(); assert_eq!(key.as_ref(), RSA_2048_PRIV_DER_EXAMPLE); } #[cfg(feature = "pem")] #[test] fn to_pkcs1_pem() { let pem = MockPrivateKey(RSA_2048_PRIV_DER_EXAMPLE.to_vec()) .to_pkcs1_pem(LineEnding::LF) .unwrap(); assert_eq!(&*pem, RSA_2048_PRIV_PEM_EXAMPLE); } #[cfg(feature = "std")] #[test] fn write_pkcs1_der_file() { let dir = tempdir().unwrap(); let path = dir.path().join("example.der"); MockPrivateKey(RSA_2048_PRIV_DER_EXAMPLE.to_vec()) .write_pkcs1_der_file(&path) .unwrap(); let key = MockPrivateKey::read_pkcs1_der_file(&path).unwrap(); assert_eq!(key.as_ref(), RSA_2048_PRIV_DER_EXAMPLE); } #[cfg(all(feature = "pem", feature = "std"))] #[test] fn write_pkcs1_pem_file() { let dir = tempdir().unwrap(); let path = dir.path().join("example.pem"); MockPrivateKey(RSA_2048_PRIV_DER_EXAMPLE.to_vec()) .write_pkcs1_pem_file(&path, LineEnding::LF) .unwrap(); let pem = fs::read_to_string(path).unwrap(); assert_eq!(&pem, RSA_2048_PRIV_PEM_EXAMPLE); }