diff --git a/Cargo.toml b/Cargo.toml index e8a05d9e..4d92c4fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ num-integer = { version = "0.1.39", default-features = false } num-iter = { version = "0.1.37", default-features = false } rand_core = { version = "0.6.4", default-features = false } byteorder = { version = "1.3.1", default-features = false } +const-oid = { version = "0.9", default-features = false } subtle = { version = "2.1.1", default-features = false } digest = { version = "0.10.5", default-features = false, features = ["alloc", "oid"] } pkcs1 = { version = "0.7.1", default-features = false, features = ["alloc", "pkcs8"] } @@ -52,10 +53,16 @@ std = ["digest/std", "pkcs1/std", "pkcs8/std", "rand_core/std", "signature/std"] pem = ["pkcs1/pem", "pkcs8/pem"] pkcs5 = ["pkcs8/encryption"] getrandom = ["rand_core/getrandom"] +algorithm-identifier = ["pkcs1/pkcs8"] [package.metadata.docs.rs] -features = ["std", "pem", "serde", "expose-internals", "sha2"] +features = ["std", "pem", "serde", "expose-internals", "sha2", "algorithm-identifier"] rustdoc-args = ["--cfg", "docsrs"] [profile.dev] opt-level = 2 + +[patch.crates-io] +pkcs1 = { git = "https://github.com/RustCrypto/formats" } +pkcs8 = { git = "https://github.com/RustCrypto/formats" } +spki = { git = "https://github.com/RustCrypto/formats" } diff --git a/src/pkcs1v15.rs b/src/pkcs1v15.rs index 5d9bac41..ecd11016 100644 --- a/src/pkcs1v15.rs +++ b/src/pkcs1v15.rs @@ -21,6 +21,15 @@ use signature::{ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; use zeroize::Zeroizing; +#[cfg(feature = "algorithm-identifier")] +use const_oid::{db::rfc5912, ObjectIdentifier}; +#[cfg(feature = "algorithm-identifier")] +use pkcs8::spki::{ + der::{referenced::RefToOwned, AnyRef}, + AlgorithmIdentifierOwned, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier, + DynSignatureAlgorithmIdentifier, +}; + use crate::dummy_rng::DummyRng; use crate::errors::{Error, Result}; use crate::key::{self, PrivateKey, PublicKey}; @@ -436,6 +445,16 @@ where } } +#[cfg(feature = "algorithm-identifier")] +impl AssociatedAlgorithmIdentifier for SigningKey +where + D: Digest, +{ + type Params = AnyRef<'static>; + + const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID; +} + impl From for SigningKey where D: Digest, @@ -606,6 +625,16 @@ where } } +#[cfg(feature = "algorithm-identifier")] +impl AssociatedAlgorithmIdentifier for VerifyingKey +where + D: Digest, +{ + type Params = AnyRef<'static>; + + const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID; +} + impl From for VerifyingKey where D: Digest, @@ -709,6 +738,42 @@ where } } +#[cfg(feature = "algorithm-identifier")] +impl DynSignatureAlgorithmIdentifier for VerifyingKey +where + D: Digest + AssociatedOid, +{ + fn signature_algorithm_identifier(&self) -> AlgorithmIdentifierOwned { + AlgorithmIdentifierOwned { + oid: match pkcs1v15_oid_for_digest(D::OID) { + Some(oid) => oid, + None => panic!("no RFC5754 RSA OID defined for Digest"), + }, + parameters: Some(AnyRef::NULL.ref_to_owned()), + } + } +} + +#[cfg(feature = "algorithm-identifier")] +const SHA224_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.4"); +#[cfg(feature = "algorithm-identifier")] +const SHA256_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.1"); +#[cfg(feature = "algorithm-identifier")] +const SHA384_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.2"); +#[cfg(feature = "algorithm-identifier")] +const SHA512_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.3"); + +#[cfg(feature = "algorithm-identifier")] +const fn pkcs1v15_oid_for_digest(digest_oid: ObjectIdentifier) -> Option { + match digest_oid { + SHA224_OID => Some(rfc5912::SHA_224_WITH_RSA_ENCRYPTION), + SHA256_OID => Some(rfc5912::SHA_256_WITH_RSA_ENCRYPTION), + SHA384_OID => Some(rfc5912::SHA_384_WITH_RSA_ENCRYPTION), + SHA512_OID => Some(rfc5912::SHA_512_WITH_RSA_ENCRYPTION), + _ => None, + } +} + /// Encryption key for PKCS#1 v1.5 encryption as described in [RFC8017 § 7.2]. /// /// [RFC8017 § 7.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.2 diff --git a/src/pss.rs b/src/pss.rs index 5111a4a3..7766b661 100644 --- a/src/pss.rs +++ b/src/pss.rs @@ -23,6 +23,18 @@ use signature::{ }; use subtle::ConstantTimeEq; +#[cfg(feature = "algorithm-identifier")] +use const_oid::{AssociatedOid, ObjectIdentifier}; +#[cfg(feature = "algorithm-identifier")] +use pkcs1::RsaPssParams; +#[cfg(feature = "algorithm-identifier")] +use pkcs8::der::{Decode, Encode}; +#[cfg(feature = "algorithm-identifier")] +use pkcs8::spki::{ + der::AnyRef, AlgorithmIdentifier, AlgorithmIdentifierOwned, AlgorithmIdentifierRef, + AssociatedAlgorithmIdentifier, DynSignatureAlgorithmIdentifier, +}; + use crate::algorithms::{mgf1_xor, mgf1_xor_digest}; use crate::errors::{Error, Result}; use crate::key::{PrivateKey, PublicKey}; @@ -689,6 +701,64 @@ where } } +#[cfg(feature = "algorithm-identifier")] +fn get_pss_signature_algo_id(salt_len: Option) -> AlgorithmIdentifierOwned +where + D: Digest + AssociatedOid, +{ + const ID_MGF_1: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.8"); + const ID_RSASSA_PSS: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.10"); + + let salt_len = salt_len.map_or(RsaPssParams::SALT_LEN_DEFAULT, |l| l as u8); + + /* + * We do not expect that any of this functions fails, unless the library is broken, so it + * is safe to use unwrap() + */ + let pss_params = RsaPssParams { + hash: AlgorithmIdentifierRef { + oid: D::OID, + parameters: None, + }, + mask_gen: AlgorithmIdentifier { + oid: ID_MGF_1, + parameters: Some(AlgorithmIdentifierRef { + oid: D::OID, + parameters: None, + }), + }, + salt_len, + trailer_field: Default::default(), + } + .to_der() + .unwrap(); + + AlgorithmIdentifierOwned { + oid: ID_RSASSA_PSS, + parameters: Some(pkcs8::der::Any::from_der(&pss_params).unwrap()), + } +} + +#[cfg(feature = "algorithm-identifier")] +impl AssociatedAlgorithmIdentifier for SigningKey +where + D: Digest, +{ + type Params = AnyRef<'static>; + + const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID; +} + +#[cfg(feature = "algorithm-identifier")] +impl DynSignatureAlgorithmIdentifier for SigningKey +where + D: Digest + AssociatedOid, +{ + fn signature_algorithm_identifier(&self) -> AlgorithmIdentifierOwned { + get_pss_signature_algo_id::(self.salt_len) + } +} + impl From for SigningKey where D: Digest, @@ -825,6 +895,26 @@ where } } +#[cfg(feature = "algorithm-identifier")] +impl AssociatedAlgorithmIdentifier for BlindedSigningKey +where + D: Digest, +{ + type Params = AnyRef<'static>; + + const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID; +} + +#[cfg(feature = "algorithm-identifier")] +impl DynSignatureAlgorithmIdentifier for BlindedSigningKey +where + D: Digest + AssociatedOid, +{ + fn signature_algorithm_identifier(&self) -> AlgorithmIdentifierOwned { + get_pss_signature_algo_id::(self.salt_len) + } +} + impl From for BlindedSigningKey where D: Digest, @@ -958,6 +1048,16 @@ where } } +#[cfg(feature = "algorithm-identifier")] +impl AssociatedAlgorithmIdentifier for VerifyingKey +where + D: Digest, +{ + type Params = AnyRef<'static>; + + const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID; +} + impl From for VerifyingKey where D: Digest,