Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion src/rsa/keypair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
31 changes: 23 additions & 8 deletions tests/rsa_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#![cfg(feature = "alloc")]

use ring::{
digest,
error,
io::der,
rand, rsa,
Expand Down Expand Up @@ -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),
};

Expand All @@ -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(())
},
);
Expand All @@ -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),
};

Expand All @@ -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(())
},
);
Expand Down