From 3262afcb039ca41a550bff96838e1e29756f1dbe Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Tue, 19 Dec 2023 11:09:05 +0000 Subject: Revert^2 "Upgrade pkcs1 to 0.7.5" e49e8188d66ac28ec1390732a013da41d2ef938f Change-Id: Iacccd02175b7650795fb5c580310684afc01eeef --- .cargo_vcs_info.json | 2 +- Android.bp | 10 +- CHANGELOG.md | 52 ++++++ Cargo.toml | 24 ++- Cargo.toml.orig | 20 +-- LICENSE-MIT | 2 +- METADATA | 21 ++- README.md | 4 +- src/lib.rs | 20 ++- src/params.rs | 314 +++++++++++++++++++++++------------- src/private_key.rs | 93 +++++++---- src/private_key/other_prime_info.rs | 29 ++-- src/public_key.rs | 29 ++-- src/traits.rs | 53 +++--- src/version.rs | 2 +- tests/params.rs | 137 ++++++++++------ 16 files changed, 513 insertions(+), 299 deletions(-) diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 8acf345..5350233 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "40fbcf36aa1d1e20685424576da37b7df0279d3b" + "sha1": "750ae946d284810f582a9c9ad428549561b1ee03" }, "path_in_vcs": "pkcs1" } \ No newline at end of file diff --git a/Android.bp b/Android.bp index ce274cc..51289d5 100644 --- a/Android.bp +++ b/Android.bp @@ -35,19 +35,16 @@ rust_library_host { name: "libpkcs1", crate_name: "pkcs1", cargo_env_compat: true, - cargo_pkg_version: "0.4.1", + cargo_pkg_version: "0.7.5", srcs: ["src/lib.rs"], edition: "2021", features: [ "alloc", - "pkcs8", "zeroize", ], rustlibs: [ "libder", - "libpkcs8", "libspki", - "libzeroize", ], } @@ -55,19 +52,16 @@ rust_library_rlib { name: "libpkcs1_nostd", crate_name: "pkcs1", cargo_env_compat: true, - cargo_pkg_version: "0.4.1", + cargo_pkg_version: "0.7.5", srcs: ["src/lib.rs"], edition: "2021", features: [ "alloc", - "pkcs8", "zeroize", ], rustlibs: [ "libder_nostd", - "libpkcs8_nostd", "libspki_nostd", - "libzeroize_nostd", ], apex_available: [ "//apex_available:platform", diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e95122..e6b79c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,58 @@ 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]) diff --git a/Cargo.toml b/Cargo.toml index b73c625..4365648 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.57" +rust-version = "1.60" name = "pkcs1" -version = "0.4.1" +version = "0.7.5" authors = ["RustCrypto Developers"] description = """ Pure Rust implementation of Public-Key Cryptography Standards (PKCS) #1: @@ -45,28 +45,23 @@ rustdoc-args = [ ] [dependencies.der] -version = "0.6" +version = "0.7" features = ["oid"] [dependencies.pkcs8] -version = "0.9" +version = "0.10" optional = true default-features = false [dependencies.spki] -version = "0.6" - -[dependencies.zeroize] -version = "1" -optional = true -default-features = false +version = "0.7" [dev-dependencies.const-oid] version = "0.9" features = ["db"] [dev-dependencies.hex-literal] -version = "0.3" +version = "0.4" [dev-dependencies.tempfile] version = "3" @@ -74,15 +69,16 @@ version = "3" [features] alloc = [ "der/alloc", - "pkcs8/alloc", - "zeroize/alloc", + "zeroize", + "pkcs8?/alloc", ] pem = [ "alloc", "der/pem", - "pkcs8/pem", + "pkcs8?/pem", ] std = [ "der/std", "alloc", ] +zeroize = ["der/zeroize"] diff --git a/Cargo.toml.orig b/Cargo.toml.orig index fb1fa3f..cdc15b4 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "pkcs1" -version = "0.4.1" +version = "0.7.5" description = """ Pure Rust implementation of Public-Key Cryptography Standards (PKCS) #1: RSA Cryptography Specifications Version 2.2 (RFC 8017) @@ -12,24 +12,24 @@ categories = ["cryptography", "data-structures", "encoding", "no-std", "parser-i keywords = ["crypto", "key", "pem", "pkcs", "rsa"] readme = "README.md" edition = "2021" -rust-version = "1.57" +rust-version = "1.60" [dependencies] -der = { version = "0.6", features = ["oid"], path = "../der" } -spki = { version = "0.6", path = "../spki" } +der = { version = "0.7", features = ["oid"] } +spki = { version = "0.7" } # optional dependencies -pkcs8 = { version = "0.9", optional = true, default-features = false, path = "../pkcs8" } -zeroize = { version = "1", optional = true, default-features = false } +pkcs8 = { version = "0.10", optional = true, default-features = false } [dev-dependencies] -hex-literal = "0.3" +const-oid = { version = "0.9", features = ["db"] } # TODO: path = "../const-oid" +hex-literal = "0.4" tempfile = "3" -const-oid = { version = "0.9", path = "../const-oid", features = ["db"] } [features] -alloc = ["der/alloc", "pkcs8/alloc", "zeroize/alloc"] -pem = ["alloc", "der/pem", "pkcs8/pem"] +zeroize = ["der/zeroize"] +alloc = ["der/alloc", "zeroize", "pkcs8?/alloc"] +pem = ["alloc", "der/pem", "pkcs8?/pem"] std = ["der/std", "alloc"] [package.metadata.docs.rs] diff --git a/LICENSE-MIT b/LICENSE-MIT index 68ddaa3..3294d74 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,4 +1,4 @@ -Copyright (c) 2021-2022 The RustCrypto Project Developers +Copyright (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 diff --git a/METADATA b/METADATA index 51c2998..434f1c5 100644 --- a/METADATA +++ b/METADATA @@ -1,23 +1,20 @@ # This project was upgraded with external_updater. # Usage: tools/external_updater/updater.sh update rust/crates/pkcs1 -# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md +# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md name: "pkcs1" description: "Pure Rust implementation of Public-Key Cryptography Standards (PKCS) #1: RSA Cryptography Specifications Version 2.2 (RFC 8017)." third_party { - url { - type: HOMEPAGE - value: "https://crates.io/crates/pkcs1" - } - url { - type: ARCHIVE - value: "https://static.crates.io/crates/pkcs1/pkcs1-0.4.1.crate" - } - version: "0.4.1" license_type: NOTICE last_upgrade_date { - year: 2022 + year: 2023 month: 12 - day: 13 + day: 15 + } + homepage: "https://crates.io/crates/pkcs1" + identifier { + type: "Archive" + value: "https://static.crates.io/crates/pkcs1/pkcs1-0.7.5.crate" + version: "0.7.5" } } diff --git a/README.md b/README.md index 8342e20..597a1b2 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ PEM encoded RSA public keys begin with: ## Minimum Supported Rust Version -This crate requires **Rust 1.57** at a minimum. +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. @@ -58,7 +58,7 @@ dual licensed as above, without any additional terms or conditions. [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.57+-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 diff --git a/src/lib.rs b/src/lib.rs index 9176c8d..e389cab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,12 +1,19 @@ #![no_std] -#![cfg_attr(docsrs, feature(doc_cfg))] +#![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, clippy::unwrap_used)] -#![warn(missing_docs, rust_2018_idioms, unused_qualifications)] +#![forbid(unsafe_code)] +#![warn( + clippy::mod_module_files, + clippy::unwrap_used, + missing_docs, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications +)] /// Local Android change: Use std to allow building as a dylib. #[cfg(android_dylib)] @@ -26,7 +33,7 @@ mod version; pub use der::{ self, - asn1::{ObjectIdentifier, UIntRef}, + asn1::{ObjectIdentifier, UintRef}, }; pub use crate::{ @@ -45,18 +52,15 @@ pub use crate::{ }; #[cfg(feature = "pem")] -#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] pub use der::pem::{self, LineEnding}; /// `rsaEncryption` Object Identifier (OID) #[cfg(feature = "pkcs8")] -#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))] pub const ALGORITHM_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.1"); /// `AlgorithmIdentifier` for RSA. #[cfg(feature = "pkcs8")] -#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))] -pub const ALGORITHM_ID: pkcs8::AlgorithmIdentifier<'static> = pkcs8::AlgorithmIdentifier { +pub const ALGORITHM_ID: pkcs8::AlgorithmIdentifierRef<'static> = pkcs8::AlgorithmIdentifierRef { oid: ALGORITHM_OID, parameters: Some(der::asn1::AnyRef::NULL), }; diff --git a/src/params.rs b/src/params.rs index e803473..74a1ee4 100644 --- a/src/params.rs +++ b/src/params.rs @@ -1,27 +1,23 @@ //! PKCS#1 RSA parameters. use crate::{Error, Result}; -use der::asn1::{AnyRef, ObjectIdentifier}; use der::{ - asn1::ContextSpecificRef, Decode, DecodeValue, Encode, EncodeValue, FixedTag, Reader, Sequence, - Tag, TagMode, TagNumber, Writer, + asn1::{AnyRef, ContextSpecificRef, ObjectIdentifier}, + oid::AssociatedOid, + Decode, DecodeValue, Encode, EncodeValue, FixedTag, Length, Reader, Sequence, Tag, TagMode, + TagNumber, Writer, }; -use spki::AlgorithmIdentifier; +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"); -// TODO(tarcieri): make `AlgorithmIdentifier` generic around params; use `OID_SHA_1` -const SEQ_OID_SHA_1_DER: &[u8] = &[0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a]; - -const SHA_1_AI: AlgorithmIdentifier<'_> = AlgorithmIdentifier { +const SHA_1_AI: AlgorithmIdentifierRef<'_> = AlgorithmIdentifierRef { oid: OID_SHA_1, - parameters: None, + parameters: Some(AnyRef::NULL), }; -const SALT_LEN_DEFAULT: u8 = 20; - /// `TrailerField` as defined in [RFC 8017 Appendix 2.3]. /// ```text /// TrailerField ::= INTEGER { trailerFieldBC(1) } @@ -50,11 +46,11 @@ impl<'a> DecodeValue<'a> for TrailerField { } impl EncodeValue for TrailerField { - fn value_len(&self) -> der::Result { - Ok(der::Length::ONE) + fn value_len(&self) -> der::Result { + Ok(Length::ONE) } - fn encode_value(&self, writer: &mut dyn Writer) -> der::Result<()> { + fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { (*self as u8).encode_value(writer) } } @@ -81,10 +77,10 @@ impl FixedTag for TrailerField { #[derive(Clone, Debug, Eq, PartialEq)] pub struct RsaPssParams<'a> { /// Hash Algorithm - pub hash: AlgorithmIdentifier<'a>, + pub hash: AlgorithmIdentifierRef<'a>, /// Mask Generation Function (MGF) - pub mask_gen: AlgorithmIdentifier<'a>, + pub mask_gen: AlgorithmIdentifier>, /// Salt length pub salt_len: u8, @@ -93,12 +89,89 @@ pub struct RsaPssParams<'a> { 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: SALT_LEN_DEFAULT, + salt_len: RsaPssParams::SALT_LEN_DEFAULT, trailer_field: Default::default(), } } @@ -116,7 +189,7 @@ impl<'a> DecodeValue<'a> for RsaPssParams<'a> { .unwrap_or_else(default_mgf1_sha1), salt_len: reader .context_specific(TagNumber::N2, TagMode::Explicit)? - .unwrap_or(SALT_LEN_DEFAULT), + .unwrap_or(RsaPssParams::SALT_LEN_DEFAULT), trailer_field: reader .context_specific(TagNumber::N3, TagMode::Explicit)? .unwrap_or_default(), @@ -125,52 +198,25 @@ impl<'a> DecodeValue<'a> for RsaPssParams<'a> { } } -impl<'a> Sequence<'a> for RsaPssParams<'a> { - fn fields(&self, f: F) -> der::Result - where - F: FnOnce(&[&dyn Encode]) -> der::Result, - { - f(&[ - &if self.hash == SHA_1_AI { - None - } else { - Some(ContextSpecificRef { - tag_number: TagNumber::N0, - tag_mode: TagMode::Explicit, - value: &self.hash, - }) - }, - &if self.mask_gen == default_mgf1_sha1() { - None - } else { - Some(ContextSpecificRef { - tag_number: TagNumber::N1, - tag_mode: TagMode::Explicit, - value: &self.mask_gen, - }) - }, - &if self.salt_len == SALT_LEN_DEFAULT { - None - } else { - Some(ContextSpecificRef { - tag_number: TagNumber::N2, - tag_mode: TagMode::Explicit, - value: &self.salt_len, - }) - }, - &if self.trailer_field == TrailerField::default() { - None - } else { - Some(ContextSpecificRef { - tag_number: TagNumber::N3, - tag_mode: TagMode::Explicit, - value: &self.trailer_field, - }) - }, - ]) +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; @@ -180,13 +226,10 @@ impl<'a> TryFrom<&'a [u8]> for RsaPssParams<'a> { } /// Default Mask Generation Function (MGF): SHA-1. -fn default_mgf1_sha1<'a>() -> AlgorithmIdentifier<'a> { - AlgorithmIdentifier { +fn default_mgf1_sha1<'a>() -> AlgorithmIdentifier> { + AlgorithmIdentifier::> { oid: OID_MGF_1, - parameters: Some( - AnyRef::new(Tag::Sequence, SEQ_OID_SHA_1_DER) - .expect("error creating default MGF1 params"), - ), + parameters: Some(SHA_1_AI), } } @@ -208,13 +251,84 @@ fn default_mgf1_sha1<'a>() -> AlgorithmIdentifier<'a> { #[derive(Clone, Debug, Eq, PartialEq)] pub struct RsaOaepParams<'a> { /// Hash Algorithm - pub hash: AlgorithmIdentifier<'a>, + pub hash: AlgorithmIdentifierRef<'a>, /// Mask Generation Function (MGF) - pub mask_gen: AlgorithmIdentifier<'a>, + pub mask_gen: AlgorithmIdentifier>, /// The source (and possibly the value) of the label L - pub p_source: AlgorithmIdentifier<'a>, + 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> { @@ -245,43 +359,23 @@ impl<'a> DecodeValue<'a> for RsaOaepParams<'a> { } } -impl<'a> Sequence<'a> for RsaOaepParams<'a> { - fn fields(&self, f: F) -> der::Result - where - F: FnOnce(&[&dyn Encode]) -> der::Result, - { - f(&[ - &if self.hash == SHA_1_AI { - None - } else { - Some(ContextSpecificRef { - tag_number: TagNumber::N0, - tag_mode: TagMode::Explicit, - value: &self.hash, - }) - }, - &if self.mask_gen == default_mgf1_sha1() { - None - } else { - Some(ContextSpecificRef { - tag_number: TagNumber::N1, - tag_mode: TagMode::Explicit, - value: &self.mask_gen, - }) - }, - &if self.p_source == default_pempty_string() { - None - } else { - Some(ContextSpecificRef { - tag_number: TagNumber::N2, - tag_mode: TagMode::Explicit, - value: &self.p_source, - }) - }, - ]) +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; @@ -290,12 +384,16 @@ impl<'a> TryFrom<&'a [u8]> for RsaOaepParams<'a> { } } -/// Default Source Algorithm, empty string -fn default_pempty_string<'a>() -> AlgorithmIdentifier<'a> { - AlgorithmIdentifier { +fn pspecicied_algorithm_identifier(label: &impl AsRef<[u8]>) -> AlgorithmIdentifierRef<'_> { + AlgorithmIdentifierRef { oid: OID_PSPECIFIED, parameters: Some( - AnyRef::new(Tag::OctetString, &[]).expect("error creating default OAEP params"), + 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(&[]) +} diff --git a/src/private_key.rs b/src/private_key.rs index 043ed02..b913c47 100644 --- a/src/private_key.rs +++ b/src/private_key.rs @@ -5,7 +5,10 @@ pub(crate) mod other_prime_info; use crate::{Error, Result, RsaPublicKey, Version}; use core::fmt; -use der::{asn1::UIntRef, Decode, DecodeValue, Encode, Header, Reader, Sequence, Tag}; +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}; @@ -39,28 +42,28 @@ use der::pem::PemLabel; #[derive(Clone)] pub struct RsaPrivateKey<'a> { /// `n`: RSA modulus. - pub modulus: UIntRef<'a>, + pub modulus: UintRef<'a>, /// `e`: RSA public exponent. - pub public_exponent: UIntRef<'a>, + pub public_exponent: UintRef<'a>, /// `d`: RSA private exponent. - pub private_exponent: UIntRef<'a>, + pub private_exponent: UintRef<'a>, /// `p`: first prime factor of `n`. - pub prime1: UIntRef<'a>, + pub prime1: UintRef<'a>, /// `q`: Second prime factor of `n`. - pub prime2: UIntRef<'a>, + pub prime2: UintRef<'a>, /// First exponent: `d mod (p-1)`. - pub exponent1: UIntRef<'a>, + pub exponent1: UintRef<'a>, /// Second exponent: `d mod (q-1)`. - pub exponent2: UIntRef<'a>, + pub exponent2: UintRef<'a>, /// CRT coefficient: `(inverse of q) mod p`. - pub coefficient: UIntRef<'a>, + 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`). @@ -116,27 +119,37 @@ impl<'a> DecodeValue<'a> for RsaPrivateKey<'a> { } } -impl<'a> Sequence<'a> for RsaPrivateKey<'a> { - fn fields(&self, f: F) -> der::Result - where - F: FnOnce(&[&dyn Encode]) -> der::Result, - { - f(&[ - &self.version(), - &self.modulus, - &self.public_exponent, - &self.private_exponent, - &self.prime1, - &self.prime2, - &self.exponent1, - &self.exponent2, - &self.coefficient, - #[cfg(feature = "alloc")] - &self.other_prime_infos, - ]) +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() @@ -168,7 +181,6 @@ impl fmt::Debug for RsaPrivateKey<'_> { } #[cfg(feature = "alloc")] -#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] impl TryFrom> for SecretDocument { type Error = Error; @@ -178,7 +190,6 @@ impl TryFrom> for SecretDocument { } #[cfg(feature = "alloc")] -#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] impl TryFrom<&RsaPrivateKey<'_>> for SecretDocument { type Error = Error; @@ -188,12 +199,13 @@ impl TryFrom<&RsaPrivateKey<'_>> for SecretDocument { } #[cfg(feature = "pem")] -#[cfg_attr(docsrs, doc(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] @@ -202,14 +214,29 @@ pub struct OtherPrimeInfos<'a> { } #[cfg(not(feature = "alloc"))] -impl<'a> Decode<'a> for OtherPrimeInfos<'a> { - fn decode>(reader: &mut R) -> der::Result { +impl<'a> DecodeValue<'a> for OtherPrimeInfos<'a> { + fn decode_value>(reader: &mut R, _header: Header) -> der::Result { // Placeholder decoder that always returns an error. - // Use `Tag::Integer` to signal an unsupported version. + // 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; diff --git a/src/private_key/other_prime_info.rs b/src/private_key/other_prime_info.rs index 8980aa1..35194a5 100644 --- a/src/private_key/other_prime_info.rs +++ b/src/private_key/other_prime_info.rs @@ -1,6 +1,8 @@ //! PKCS#1 OtherPrimeInfo support. -use der::{asn1::UIntRef, DecodeValue, Encode, Header, Reader, Sequence}; +use der::{ + asn1::UintRef, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Writer, +}; /// PKCS#1 OtherPrimeInfo as defined in [RFC 8017 Appendix 1.2]. /// @@ -16,16 +18,15 @@ use der::{asn1::UIntRef, DecodeValue, Encode, Header, Reader, Sequence}; /// /// [RFC 8017 Appendix 1.2]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.1.2 #[derive(Clone)] -#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] pub struct OtherPrimeInfo<'a> { /// Prime factor `r_i` of `n`, where `i` >= 3. - pub prime: UIntRef<'a>, + pub prime: UintRef<'a>, /// Exponent: `d_i = d mod (r_i - 1)`. - pub exponent: UIntRef<'a>, + pub exponent: UintRef<'a>, /// CRT coefficient: `t_i = (r_1 * r_2 * ... * r_(i-1))^(-1) mod r_i`. - pub coefficient: UIntRef<'a>, + pub coefficient: UintRef<'a>, } impl<'a> DecodeValue<'a> for OtherPrimeInfo<'a> { @@ -40,11 +41,17 @@ impl<'a> DecodeValue<'a> for OtherPrimeInfo<'a> { } } -impl<'a> Sequence<'a> for OtherPrimeInfo<'a> { - fn fields(&self, f: F) -> der::Result - where - F: FnOnce(&[&dyn Encode]) -> der::Result, - { - f(&[&self.prime, &self.exponent, &self.coefficient]) +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> {} diff --git a/src/public_key.rs b/src/public_key.rs index b6b8c87..3281744 100644 --- a/src/public_key.rs +++ b/src/public_key.rs @@ -1,7 +1,10 @@ //! PKCS#1 RSA Public Keys. use crate::{Error, Result}; -use der::{asn1::UIntRef, Decode, DecodeValue, Encode, Header, Reader, Sequence}; +use der::{ + asn1::UintRef, Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, + Writer, +}; #[cfg(feature = "alloc")] use der::Document; @@ -24,10 +27,10 @@ use der::pem::PemLabel; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct RsaPublicKey<'a> { /// `n`: RSA modulus - pub modulus: UIntRef<'a>, + pub modulus: UintRef<'a>, /// `e`: RSA public exponent - pub public_exponent: UIntRef<'a>, + pub public_exponent: UintRef<'a>, } impl<'a> DecodeValue<'a> for RsaPublicKey<'a> { @@ -41,15 +44,20 @@ impl<'a> DecodeValue<'a> for RsaPublicKey<'a> { } } -impl<'a> Sequence<'a> for RsaPublicKey<'a> { - fn fields(&self, f: F) -> der::Result - where - F: FnOnce(&[&dyn Encode]) -> der::Result, - { - f(&[&self.modulus, &self.public_exponent]) +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; @@ -59,7 +67,6 @@ impl<'a> TryFrom<&'a [u8]> for RsaPublicKey<'a> { } #[cfg(feature = "alloc")] -#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] impl TryFrom> for Document { type Error = Error; @@ -69,7 +76,6 @@ impl TryFrom> for Document { } #[cfg(feature = "alloc")] -#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] impl TryFrom<&RsaPublicKey<'_>> for Document { type Error = Error; @@ -79,7 +85,6 @@ impl TryFrom<&RsaPublicKey<'_>> for Document { } #[cfg(feature = "pem")] -#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] impl PemLabel for RsaPublicKey<'_> { const PEM_LABEL: &'static str = "RSA PUBLIC KEY"; } diff --git a/src/traits.rs b/src/traits.rs index c70820c..cd3d04e 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -3,10 +3,7 @@ use crate::Result; #[cfg(feature = "alloc")] -use { - crate::{RsaPrivateKey, RsaPublicKey}, - der::SecretDocument, -}; +use der::{Document, SecretDocument}; #[cfg(feature = "pem")] use { @@ -16,13 +13,19 @@ use { }; #[cfg(feature = "pkcs8")] -use crate::{ALGORITHM_ID, ALGORITHM_OID}; +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, Document}; +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 { @@ -38,7 +41,6 @@ pub trait DecodeRsaPrivateKey: Sized { /// -----BEGIN RSA PRIVATE KEY----- /// ``` #[cfg(feature = "pem")] - #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] fn from_pkcs1_pem(s: &str) -> Result { let (label, doc) = SecretDocument::from_pem(s)?; RsaPrivateKey::validate_pem_label(label)?; @@ -48,15 +50,12 @@ pub trait DecodeRsaPrivateKey: Sized { /// Load PKCS#1 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_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"))] - #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] - #[cfg_attr(docsrs, doc(cfg(feature = "std")))] fn read_pkcs1_pem_file(path: impl AsRef) -> Result { let (label, doc) = SecretDocument::read_pem_file(path)?; RsaPrivateKey::validate_pem_label(&label)?; @@ -78,7 +77,6 @@ pub trait DecodeRsaPublicKey: Sized { /// -----BEGIN RSA PUBLIC KEY----- /// ``` #[cfg(feature = "pem")] - #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] fn from_pkcs1_pem(s: &str) -> Result { let (label, doc) = Document::from_pem(s)?; RsaPublicKey::validate_pem_label(label)?; @@ -88,7 +86,6 @@ pub trait DecodeRsaPublicKey: Sized { /// Load [`RsaPublicKey`] 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_pkcs1_der_file(path: impl AsRef) -> Result { let doc = Document::read_der_file(path)?; Self::from_pkcs1_der(doc.as_bytes()) @@ -96,8 +93,6 @@ pub trait DecodeRsaPublicKey: Sized { /// Load [`RsaPublicKey`] 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_pkcs1_pem_file(path: impl AsRef) -> Result { let (label, doc) = Document::read_pem_file(path)?; RsaPublicKey::validate_pem_label(&label)?; @@ -107,14 +102,12 @@ pub trait DecodeRsaPublicKey: Sized { /// Serialize a [`RsaPrivateKey`] to a PKCS#1 encoded document. #[cfg(feature = "alloc")] -#[cfg_attr(docsrs, doc(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")] - #[cfg_attr(docsrs, doc(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)?) @@ -122,14 +115,12 @@ pub trait EncodeRsaPrivateKey { /// Write ASN.1 DER-encoded PKCS#1 private key to the given path. #[cfg(feature = "std")] - #[cfg_attr(docsrs, doc(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"))] - #[cfg_attr(docsrs, doc(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)?) @@ -138,14 +129,12 @@ pub trait EncodeRsaPrivateKey { /// Serialize a [`RsaPublicKey`] to a PKCS#1-encoded document. #[cfg(feature = "alloc")] -#[cfg_attr(docsrs, doc(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")] - #[cfg_attr(docsrs, doc(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)?) @@ -153,14 +142,12 @@ pub trait EncodeRsaPublicKey { /// Write ASN.1 DER-encoded public key to the given path. #[cfg(feature = "std")] - #[cfg_attr(docsrs, doc(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"))] - #[cfg_attr(docsrs, doc(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)?) @@ -168,8 +155,10 @@ pub trait EncodeRsaPublicKey { } #[cfg(feature = "pkcs8")] -#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))] -impl DecodeRsaPrivateKey for T { +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, @@ -180,18 +169,19 @@ impl DecodeRsaPrivateKey for T { } #[cfg(feature = "pkcs8")] -#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))] -impl DecodeRsaPublicKey for T { +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::SubjectPublicKeyInfo { + Ok(Self::try_from(pkcs8::SubjectPublicKeyInfoRef { algorithm: ALGORITHM_ID, - subject_public_key: public_key, + subject_public_key: BitStringRef::from_bytes(public_key)?, })?) } } #[cfg(all(feature = "alloc", feature = "pkcs8"))] -#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "pkcs8"))))] impl EncodeRsaPrivateKey for T { fn to_pkcs1_der(&self) -> Result { let pkcs8_doc = self.to_pkcs8_der()?; @@ -202,12 +192,11 @@ impl EncodeRsaPrivateKey for T { } #[cfg(all(feature = "alloc", feature = "pkcs8"))] -#[cfg_attr(docsrs, doc(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::SubjectPublicKeyInfo::from_der(doc.as_bytes())?; + let spki = pkcs8::SubjectPublicKeyInfoRef::from_der(doc.as_bytes())?; spki.algorithm.assert_algorithm_oid(ALGORITHM_OID)?; - RsaPublicKey::from_der(spki.subject_public_key)?.try_into() + RsaPublicKey::from_der(spki.subject_public_key.raw_bytes())?.try_into() } } diff --git a/src/version.rs b/src/version.rs index 6b253e8..2fdb198 100644 --- a/src/version.rs +++ b/src/version.rs @@ -62,7 +62,7 @@ impl Encode for Version { der::Length::ONE.for_tlv() } - fn encode(&self, writer: &mut dyn Writer) -> der::Result<()> { + fn encode(&self, writer: &mut impl Writer) -> der::Result<()> { u8::from(*self).encode(writer) } } diff --git a/tests/params.rs b/tests/params.rs index 6954934..d47fbb5 100644 --- a/tests/params.rs +++ b/tests/params.rs @@ -2,8 +2,9 @@ use const_oid::db; use der::{ - asn1::{ObjectIdentifier, OctetStringRef}, - Decode, Encode, + asn1::{AnyRef, ObjectIdentifier, OctetStringRef}, + oid::AssociatedOid, + Encode, }; use hex_literal::hex; use pkcs1::{RsaOaepParams, RsaPssParams, TrailerField}; @@ -11,12 +12,22 @@ 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!("3030a00d300b0609608648016503040201a11a301806092a864886f70d010108300b0609608648016503040201a203020120"); +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 and 'abc' as label -const RSA_OAEP_PARAMETERS_SHA2_256: &[u8] = &hex!("303fa00d300b0609608648016503040201a11a301806092a864886f70d010108300b0609608648016503040201a212301006092a864886f70d0101090403abcdef"); +/// 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() { @@ -26,20 +37,17 @@ fn decode_pss_param() { .hash .assert_algorithm_oid(db::rfc5912::ID_SHA_256) .is_ok()); - assert_eq!(param.hash.parameters, None); + assert_eq!(param.hash.parameters, Some(AnyRef::NULL)); assert!(param .mask_gen .assert_algorithm_oid(db::rfc5912::ID_MGF_1) .is_ok()); - assert_eq!( - param - .mask_gen - .parameters_any() - .unwrap() - .sequence(|reader| Ok(ObjectIdentifier::decode(reader)?)) - .unwrap(), - db::rfc5912::ID_SHA_256 - ); + 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); } @@ -62,19 +70,20 @@ fn decode_pss_param_default() { .hash .assert_algorithm_oid(db::rfc5912::ID_SHA_1) .is_ok()); - assert_eq!(param.hash.parameters, None); + 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_any() - .unwrap() - .sequence(|reader| Ok(ObjectIdentifier::decode(reader)?)) - .unwrap(), - db::rfc5912::ID_SHA_1 + param.mask_gen.parameters.unwrap().parameters, + Some(AnyRef::NULL) ); assert_eq!(param.salt_len, 20); assert_eq!(param.trailer_field, TrailerField::BC); @@ -90,6 +99,23 @@ fn encode_pss_param_default() { ); } +#[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(); @@ -98,28 +124,28 @@ fn decode_oaep_param() { .hash .assert_algorithm_oid(db::rfc5912::ID_SHA_256) .is_ok()); - assert_eq!(param.hash.parameters, None); + assert_eq!(param.hash.parameters, Some(AnyRef::NULL)); assert!(param .mask_gen .assert_algorithm_oid(db::rfc5912::ID_MGF_1) .is_ok()); - assert_eq!( - param - .mask_gen - .parameters_any() - .unwrap() - .sequence(|reader| Ok(ObjectIdentifier::decode(reader)?)) - .unwrap(), - db::rfc5912::ID_SHA_256 - ); + 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_eq!( - param.p_source.parameters_any().unwrap().octet_string(), - OctetStringRef::new(&[0xab, 0xcd, 0xef]) - ); + assert!(param + .p_source + .parameters_any() + .unwrap() + .decode_as::>() + .unwrap() + .is_empty(),); } #[test] @@ -140,19 +166,20 @@ fn decode_oaep_param_default() { .hash .assert_algorithm_oid(db::rfc5912::ID_SHA_1) .is_ok()); - assert_eq!(param.hash.parameters, None); + 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_any() - .unwrap() - .sequence(|reader| Ok(ObjectIdentifier::decode(reader)?)) - .unwrap(), - db::rfc5912::ID_SHA_1 + param.mask_gen.parameters.unwrap().parameters, + Some(AnyRef::NULL) ); assert!(param .p_source @@ -162,7 +189,7 @@ fn decode_oaep_param_default() { .p_source .parameters_any() .unwrap() - .octet_string() + .decode_as::>() .unwrap() .is_empty(),); assert_eq!(param, Default::default()) @@ -176,3 +203,21 @@ fn encode_oaep_param_default() { 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 + ); +} -- cgit v1.2.3