diff --git a/src/rsa/keypair.rs b/src/rsa/keypair.rs index f8dc567f30..8e3f529a0c 100644 --- a/src/rsa/keypair.rs +++ b/src/rsa/keypair.rs @@ -575,9 +575,31 @@ impl KeyPair { let m_hash = digest::digest(padding_alg.digest_alg(), msg); + self.sign_digest_less_safe(padding_alg, rng, m_hash, signature) + } + + /// Compute the signature of `digest`. + /// + /// The `digest` algorithm must match that of the signing algorithm. + /// + /// In general, it is not safe to sign an arbitrary digest. Ensure that + /// you only sign digests that you have computed yourself, or that you + /// otherwise know are safe to sign. It could be a bad mistake to sign + /// an attacker-controlled digest. + pub fn sign_digest_less_safe( + &self, + padding_alg: &'static dyn RsaEncoding, + rng: &dyn rand::SecureRandom, + digest: digest::Digest, + signature: &mut [u8] + ) -> Result<(), error::Unspecified> { + if signature.len() != self.public().modulus_len() { + return Err(error::Unspecified); + } + // Use the output buffer as the scratch space for the signature to // reduce the required stack space. - padding_alg.encode(m_hash, signature, self.public().n().len_bits(), rng)?; + padding_alg.encode(digest, signature, self.public().n().len_bits(), rng)?; // RFC 8017 Section 5.1.2: RSADP, using the Chinese Remainder Theorem // with Garner's algorithm. diff --git a/tests/rsa_tests.rs b/tests/rsa_tests.rs index 2935c6fcfc..cf32c20e6a 100644 --- a/tests/rsa_tests.rs +++ b/tests/rsa_tests.rs @@ -15,6 +15,7 @@ #![cfg(feature = "alloc")] use ring::{ + digest, error, io::der, rand, rsa, @@ -61,10 +62,10 @@ fn test_signature_rsa_pkcs1_sign() { assert_eq!(section, ""); let digest_name = test_case.consume_string("Digest"); - let alg = match digest_name.as_ref() { - "SHA256" => &signature::RSA_PKCS1_SHA256, - "SHA384" => &signature::RSA_PKCS1_SHA384, - "SHA512" => &signature::RSA_PKCS1_SHA512, + let (alg, digest_alg) = match digest_name.as_ref() { + "SHA256" => (&signature::RSA_PKCS1_SHA256, &digest::SHA256), + "SHA384" => (&signature::RSA_PKCS1_SHA384, &digest::SHA384), + "SHA512" => (&signature::RSA_PKCS1_SHA512, &digest::SHA512), _ => panic!("Unsupported digest: {}", digest_name), }; @@ -87,6 +88,13 @@ fn test_signature_rsa_pkcs1_sign() { .sign(alg, &rng, &msg, actual.as_mut_slice()) .unwrap(); assert_eq!(actual.as_slice() == &expected[..], result == "Pass"); + + let digest = digest::digest(&digest_alg, &msg); + key_pair + .sign_digest_less_safe(alg, &rng, digest, actual.as_mut_slice()) + .unwrap(); + assert_eq!(actual.as_slice() == &expected[..], result == "Pass"); + Ok(()) }, ); @@ -101,10 +109,10 @@ fn test_signature_rsa_pss_sign() { assert_eq!(section, ""); let digest_name = test_case.consume_string("Digest"); - let alg = match digest_name.as_ref() { - "SHA256" => &signature::RSA_PSS_SHA256, - "SHA384" => &signature::RSA_PSS_SHA384, - "SHA512" => &signature::RSA_PSS_SHA512, + let (alg, digest_alg) = match digest_name.as_ref() { + "SHA256" => (&signature::RSA_PSS_SHA256, &digest::SHA256), + "SHA384" => (&signature::RSA_PSS_SHA384, &digest::SHA384), + "SHA512" => (&signature::RSA_PSS_SHA512, &digest::SHA512), _ => panic!("Unsupported digest: {}", digest_name), }; @@ -124,6 +132,13 @@ fn test_signature_rsa_pss_sign() { let mut actual = vec![0u8; key_pair.public().modulus_len()]; key_pair.sign(alg, &rng, &msg, actual.as_mut_slice())?; assert_eq!(actual.as_slice() == &expected[..], result == "Pass"); + + let digest = digest::digest(&digest_alg, &msg); + key_pair + .sign_digest_less_safe(alg, &rng, digest, actual.as_mut_slice()) + .unwrap(); + assert_eq!(actual.as_slice() == &expected[..], result == "Pass"); + Ok(()) }, );