Move RSA signing & verification functional tests to tests/.

This commit is contained in:
Brian Smith 2017-05-13 12:15:31 -10:00
parent 5716cc981c
commit e52904256b
9 changed files with 243 additions and 249 deletions

View File

@ -121,12 +121,7 @@ include = [
"src/rsa/padding.rs",
"src/rsa/random.rs",
"src/rsa/rsa.rs",
"src/rsa/rsa_pkcs1_sign_tests.txt",
"src/rsa/rsa_pkcs1_verify_tests.txt",
"src/rsa/rsa_primitive_verify_tests.txt",
"src/rsa/rsa_pss_padding_tests.txt",
"src/rsa/rsa_pss_sign_tests.txt",
"src/rsa/rsa_pss_verify_tests.txt",
"src/rsa/signature_rsa_example_private_key.der",
"src/rsa/signature_rsa_example_public_key.der",
"src/rsa/signing.rs",
@ -240,12 +235,17 @@ include = [
"tests/ed25519_tests.txt",
"tests/ed25519_from_pkcs8_tests.txt",
"tests/ed25519_from_pkcs8_unchecked_tests.txt",
"tests/rsa_tests.rs",
"tests/pkcs8_test_ecPublicKey_p256.pk8",
"tests/pkcs8_test_ecPublicKey_p256_RSAPrivateKey.pk8",
"tests/pkcs8_test_rsaEncryption_2048_e3.pk8",
"tests/pkcs8_test_rsaEncryption_2048_e65537.pk8",
"tests/pkcs8_test_rsaEncryption_3072_e65537.pk8",
"tests/rsa_pkcs1_sign_tests.txt",
"tests/rsa_pkcs1_verify_tests.txt",
"tests/rsa_primitive_verify_tests.txt",
"tests/rsa_pss_sign_tests.txt",
"tests/rsa_pss_verify_tests.txt",
"tests/rsa_tests.rs",
"third-party/NIST/README.md",
"third-party/NIST/sha256sums.txt",
"third-party/NIST/SHAVS/SHA1LongMsg.rsp",

View File

@ -644,54 +644,11 @@ mod tests {
// We intentionally avoid `use super::*` so that we are sure to use only
// the public API; this ensures that enough of the API is public.
use core;
use {error, rand, signature, test};
use {rand, signature, test};
use std;
use super::super::blinding;
use untrusted;
#[test]
fn test_signature_rsa_pkcs1_sign() {
let rng = rand::SystemRandom::new();
test::from_file("src/rsa/rsa_pkcs1_sign_tests.txt",
|section, test_case| {
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,
_ => { panic!("Unsupported digest: {}", digest_name) }
};
let private_key = test_case.consume_bytes("Key");
let msg = test_case.consume_bytes("Msg");
let expected = test_case.consume_bytes("Sig");
let result = test_case.consume_string("Result");
let private_key = untrusted::Input::from(&private_key);
let key_pair = signature::RSAKeyPair::from_der(private_key);
if result == "Fail-Invalid-Key" {
assert!(key_pair.is_err());
return Ok(());
}
let key_pair = key_pair.unwrap();
let key_pair = std::sync::Arc::new(key_pair);
// XXX: This test is too slow on Android ARM Travis CI builds.
// TODO: re-enable these tests on Android ARM.
let mut signing_state =
signature::RSASigningState::new(key_pair).unwrap();
let mut actual: std::vec::Vec<u8> =
vec![0; signing_state.key_pair().public_modulus_len()];
signing_state.sign(alg, &rng, &msg, actual.as_mut_slice()).unwrap();
assert_eq!(actual.as_slice() == &expected[..], result == "Pass");
Ok(())
});
}
// `RSAKeyPair::sign` requires that the output buffer is the same length as
// the public key modulus. Test what happens when it isn't the same length.
#[test]
@ -753,7 +710,7 @@ mod tests {
MESSAGE, &mut signature);
let remaining = signing_state.blinding.remaining();
assert_eq!((remaining + 1) % blinding::REMAINING_MAX,
prev_remaining);
prev_remaining);
}
}
@ -798,80 +755,4 @@ mod tests {
assert!(result.is_err());
}
#[cfg(feature = "rsa_signing")]
#[test]
fn test_signature_rsa_pss_sign() {
// Outputs the same value whenever a certain length is requested (the
// same as the length of the salt). Otherwise, the rng is used.
struct DeterministicSalt<'a> {
salt: &'a [u8],
rng: &'a rand::SecureRandom
}
impl<'a> rand::SecureRandom for DeterministicSalt<'a> {
fn fill(&self, dest: &mut [u8]) -> Result<(), error::Unspecified> {
let dest_len = dest.len();
if dest_len != self.salt.len() {
try!(self.rng.fill(dest));
} else {
dest.copy_from_slice(&self.salt);
}
Ok(())
}
}
let rng = rand::SystemRandom::new();
test::from_file("src/rsa/rsa_pss_sign_tests.txt", |section, test_case| {
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,
_ => { panic!("Unsupported digest: {}", digest_name) }
};
let result = test_case.consume_string("Result");
let private_key = test_case.consume_bytes("Key");
let private_key = untrusted::Input::from(&private_key);
let key_pair = signature::RSAKeyPair::from_der(private_key);
if key_pair.is_err() && result == "Fail-Invalid-Key" {
return Ok(());
}
let key_pair = key_pair.unwrap();
let key_pair = std::sync::Arc::new(key_pair);
let msg = test_case.consume_bytes("Msg");
let salt = test_case.consume_bytes("Salt");
let expected = test_case.consume_bytes("Sig");
let new_rng = DeterministicSalt { salt: &salt, rng: &rng };
let mut signing_state =
signature::RSASigningState::new(key_pair).unwrap();
let mut actual: std::vec::Vec<u8> =
vec![0; signing_state.key_pair().public_modulus_len()];
try!(signing_state.sign(alg, &new_rng, &msg, actual.as_mut_slice()));
assert_eq!(actual.as_slice() == &expected[..], result == "Pass");
Ok(())
});
}
#[test]
fn test_sync_and_send() {
const PRIVATE_KEY_DER: &'static [u8] =
include_bytes!("signature_rsa_example_private_key.der");
let key_bytes_der = untrusted::Input::from(PRIVATE_KEY_DER);
let key_pair = signature::RSAKeyPair::from_der(key_bytes_der).unwrap();
let key_pair = std::sync::Arc::new(key_pair);
let _: &Send = &key_pair;
let _: &Sync = &key_pair;
let signing_state = signature::RSASigningState::new(key_pair).unwrap();
let _: &Send = &signing_state;
// TODO: Test that signing_state is NOT Sync; i.e.
// `let _: &Sync = &signing_state;` must fail
}
}

View File

@ -159,122 +159,3 @@ pub fn verify_rsa(params: &RSAParameters,
untrusted::Input::from(decoded).read_all(
error::Unspecified, |m| params.padding_alg.verify(&m_hash, m, n_bits))
}
#[cfg(test)]
mod tests {
// We intentionally avoid `use super::*` so that we are sure to use only
// the public API; this ensures that enough of the API is public.
use {der, error, signature, test};
use untrusted;
#[test]
fn test_signature_rsa_pkcs1_verify() {
test::from_file("src/rsa/rsa_pkcs1_verify_tests.txt",
|section, test_case| {
assert_eq!(section, "");
let digest_name = test_case.consume_string("Digest");
let alg = match digest_name.as_ref() {
"SHA1" => &signature::RSA_PKCS1_2048_8192_SHA1,
"SHA256" => &signature::RSA_PKCS1_2048_8192_SHA256,
"SHA384" => &signature::RSA_PKCS1_2048_8192_SHA384,
"SHA512" => &signature::RSA_PKCS1_2048_8192_SHA512,
_ => { panic!("Unsupported digest: {}", digest_name) }
};
let public_key = test_case.consume_bytes("Key");
let public_key = untrusted::Input::from(&public_key);
// Sanity check that we correctly DER-encoded the originally-
// provided separate (n, e) components. When we add test vectors
// for improperly-encoded signatures, we'll have to revisit this.
assert!(public_key.read_all(error::Unspecified, |input| {
der::nested(input, der::Tag::Sequence, error::Unspecified,
|input| {
let _ = try!(der::positive_integer(input));
let _ = try!(der::positive_integer(input));
Ok(())
})
}).is_ok());
let msg = test_case.consume_bytes("Msg");
let msg = untrusted::Input::from(&msg);
let sig = test_case.consume_bytes("Sig");
let sig = untrusted::Input::from(&sig);
let expected_result = test_case.consume_string("Result");
let actual_result = signature::verify(alg, public_key, msg, sig);
assert_eq!(actual_result.is_ok(), expected_result == "P");
Ok(())
});
}
#[test]
fn test_signature_rsa_pss_verify() {
test::from_file("src/rsa/rsa_pss_verify_tests.txt",
|section, test_case| {
assert_eq!(section, "");
let digest_name = test_case.consume_string("Digest");
let alg = match digest_name.as_ref() {
"SHA256" => &signature::RSA_PSS_2048_8192_SHA256,
"SHA384" => &signature::RSA_PSS_2048_8192_SHA384,
"SHA512" => &signature::RSA_PSS_2048_8192_SHA512,
_ => { panic!("Unsupported digest: {}", digest_name) }
};
let public_key = test_case.consume_bytes("Key");
let public_key = untrusted::Input::from(&public_key);
// Sanity check that we correctly DER-encoded the originally-
// provided separate (n, e) components. When we add test vectors
// for improperly-encoded signatures, we'll have to revisit this.
assert!(public_key.read_all(error::Unspecified, |input| {
der::nested(input, der::Tag::Sequence, error::Unspecified,
|input| {
let _ = try!(der::positive_integer(input));
let _ = try!(der::positive_integer(input));
Ok(())
})
}).is_ok());
let msg = test_case.consume_bytes("Msg");
let msg = untrusted::Input::from(&msg);
let sig = test_case.consume_bytes("Sig");
let sig = untrusted::Input::from(&sig);
let expected_result = test_case.consume_string("Result");
let actual_result = signature::verify(alg, public_key, msg, sig);
assert_eq!(actual_result.is_ok(), expected_result == "P");
Ok(())
});
}
// Test for `primitive::verify()`. Read public key parts from a file
// and use them to verify a signature.
#[test]
fn test_signature_rsa_primitive_verification() {
test::from_file("src/rsa/rsa_primitive_verify_tests.txt",
|section, test_case| {
assert_eq!(section, "");
let n = test_case.consume_bytes("n");
let e = test_case.consume_bytes("e");
let msg = test_case.consume_bytes("Msg");
let sig = test_case.consume_bytes("Sig");
let expected = test_case.consume_string("Result");
let result = signature::primitive::verify_rsa(
&signature::RSA_PKCS1_2048_8192_SHA256,
(untrusted::Input::from(&n), untrusted::Input::from(&e)),
untrusted::Input::from(&msg), untrusted::Input::from(&sig));
assert_eq!(result.is_ok(), expected == "Pass");
Ok(())
})
}
}

View File

@ -12,13 +12,16 @@
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#![cfg(feature = "rsa_signing")]
extern crate ring;
extern crate untrusted;
use ring::signature;
use ring::{der, error, signature, test};
#[cfg(feature = "rsa_signing")]
use ring::rand;
#[cfg(feature = "rsa_signing")]
#[test]
fn test_rsa_key_pair_from_pkcs8_rsa_encryption_2048() {
const INPUT: &'static [u8] =
@ -27,6 +30,7 @@ fn test_rsa_key_pair_from_pkcs8_rsa_encryption_2048() {
untrusted::Input::from(INPUT)).is_ok());
}
#[cfg(feature = "rsa_signing")]
#[test]
fn test_rsa_key_pair_from_pkcs8_rsa_encryption_3072() {
const INPUT: &'static [u8] =
@ -35,6 +39,7 @@ fn test_rsa_key_pair_from_pkcs8_rsa_encryption_3072() {
untrusted::Input::from(INPUT)).is_ok());
}
#[cfg(feature = "rsa_signing")]
#[test]
fn test_rsa_key_pair_from_pkcs8_rsa_encryption_invalid_e3() {
const INPUT: &'static [u8] =
@ -43,6 +48,7 @@ fn test_rsa_key_pair_from_pkcs8_rsa_encryption_invalid_e3() {
untrusted::Input::from(INPUT)).is_err());
}
#[cfg(feature = "rsa_signing")]
#[test]
fn test_rsa_key_pair_from_pkcs8_rsa_encryption_2048_truncated() {
const INPUT: &'static [u8] =
@ -51,6 +57,7 @@ fn test_rsa_key_pair_from_pkcs8_rsa_encryption_2048_truncated() {
untrusted::Input::from(&INPUT[..(INPUT.len() - 1)])).is_err());
}
#[cfg(feature = "rsa_signing")]
#[test]
fn test_rsa_key_pair_from_pkcs8_ecc() {
// The input is a valid P-256 private key, which isn't a valid RSA key.
@ -60,6 +67,7 @@ fn test_rsa_key_pair_from_pkcs8_ecc() {
untrusted::Input::from(INPUT)).is_err());
}
#[cfg(feature = "rsa_signing")]
#[test]
fn test_rsa_key_pair_from_pkcs8_rsa_encryption_ecc() {
// The input's algorithm ID is rsaEncryption, but it contains a P-256
@ -70,6 +78,7 @@ fn test_rsa_key_pair_from_pkcs8_rsa_encryption_ecc() {
untrusted::Input::from(INPUT)).is_err());
}
#[cfg(feature = "rsa_signing")]
#[test]
fn test_rsa_key_pair_from_pkcs8_ecc_rsa_private_key() {
// The input contains an RSAPrivateKey, but marked as an ecPublicKey w/
@ -80,3 +89,226 @@ fn test_rsa_key_pair_from_pkcs8_ecc_rsa_private_key() {
untrusted::Input::from(INPUT)).is_err());
}
#[cfg(feature = "rsa_signing")]
#[test]
fn test_signature_rsa_pkcs1_sign() {
let rng = rand::SystemRandom::new();
test::from_file("tests/rsa_pkcs1_sign_tests.txt", |section, test_case| {
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,
_ => { panic!("Unsupported digest: {}", digest_name) }
};
let private_key = test_case.consume_bytes("Key");
let msg = test_case.consume_bytes("Msg");
let expected = test_case.consume_bytes("Sig");
let result = test_case.consume_string("Result");
let private_key = untrusted::Input::from(&private_key);
let key_pair = signature::RSAKeyPair::from_der(private_key);
if result == "Fail-Invalid-Key" {
assert!(key_pair.is_err());
return Ok(());
}
let key_pair = key_pair.unwrap();
let key_pair = std::sync::Arc::new(key_pair);
// XXX: This test is too slow on Android ARM Travis CI builds.
// TODO: re-enable these tests on Android ARM.
let mut signing_state =
signature::RSASigningState::new(key_pair).unwrap();
let mut actual: std::vec::Vec<u8> =
vec![0; signing_state.key_pair().public_modulus_len()];
signing_state.sign(alg, &rng, &msg, actual.as_mut_slice()).unwrap();
assert_eq!(actual.as_slice() == &expected[..], result == "Pass");
Ok(())
});
}
#[cfg(feature = "rsa_signing")]
#[test]
fn test_signature_rsa_pss_sign() {
// Outputs the same value whenever a certain length is requested (the same
// as the length of the salt). Otherwise, the rng is used.
struct DeterministicSalt<'a> {
salt: &'a [u8],
rng: &'a rand::SecureRandom
}
impl<'a> rand::SecureRandom for DeterministicSalt<'a> {
fn fill(&self, dest: &mut [u8]) -> Result<(), error::Unspecified> {
let dest_len = dest.len();
if dest_len != self.salt.len() {
try!(self.rng.fill(dest));
} else {
dest.copy_from_slice(&self.salt);
}
Ok(())
}
}
let rng = rand::SystemRandom::new();
test::from_file("tests/rsa_pss_sign_tests.txt", |section, test_case| {
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,
_ => { panic!("Unsupported digest: {}", digest_name) }
};
let result = test_case.consume_string("Result");
let private_key = test_case.consume_bytes("Key");
let private_key = untrusted::Input::from(&private_key);
let key_pair = signature::RSAKeyPair::from_der(private_key);
if key_pair.is_err() && result == "Fail-Invalid-Key" {
return Ok(());
}
let key_pair = key_pair.unwrap();
let key_pair = std::sync::Arc::new(key_pair);
let msg = test_case.consume_bytes("Msg");
let salt = test_case.consume_bytes("Salt");
let expected = test_case.consume_bytes("Sig");
let new_rng = DeterministicSalt { salt: &salt, rng: &rng };
let mut signing_state =
signature::RSASigningState::new(key_pair).unwrap();
let mut actual: std::vec::Vec<u8> =
vec![0; signing_state.key_pair().public_modulus_len()];
try!(signing_state.sign(alg, &new_rng, &msg, actual.as_mut_slice()));
assert_eq!(actual.as_slice() == &expected[..], result == "Pass");
Ok(())
});
}
#[cfg(feature = "rsa_signing")]
#[test]
fn test_rsa_key_pair_sync_and_send() {
const PRIVATE_KEY_DER: &'static [u8] =
include_bytes!("../src/rsa/signature_rsa_example_private_key.der");
let key_bytes_der = untrusted::Input::from(PRIVATE_KEY_DER);
let key_pair = signature::RSAKeyPair::from_der(key_bytes_der).unwrap();
let key_pair = std::sync::Arc::new(key_pair);
let _: &Send = &key_pair;
let _: &Sync = &key_pair;
let signing_state = signature::RSASigningState::new(key_pair).unwrap();
let _: &Send = &signing_state;
// TODO: Test that signing_state is NOT Sync; i.e.
// `let _: &Sync = &signing_state;` must fail
}
#[test]
fn test_signature_rsa_pkcs1_verify() {
test::from_file("tests/rsa_pkcs1_verify_tests.txt", |section, test_case| {
assert_eq!(section, "");
let digest_name = test_case.consume_string("Digest");
let alg = match digest_name.as_ref() {
"SHA1" => &signature::RSA_PKCS1_2048_8192_SHA1,
"SHA256" => &signature::RSA_PKCS1_2048_8192_SHA256,
"SHA384" => &signature::RSA_PKCS1_2048_8192_SHA384,
"SHA512" => &signature::RSA_PKCS1_2048_8192_SHA512,
_ => { panic!("Unsupported digest: {}", digest_name) }
};
let public_key = test_case.consume_bytes("Key");
let public_key = untrusted::Input::from(&public_key);
// Sanity check that we correctly DER-encoded the originally-
// provided separate (n, e) components. When we add test vectors
// for improperly-encoded signatures, we'll have to revisit this.
assert!(public_key.read_all(error::Unspecified, |input| {
der::nested(input, der::Tag::Sequence, error::Unspecified, |input| {
let _ = try!(der::positive_integer(input));
let _ = try!(der::positive_integer(input));
Ok(())
})
}).is_ok());
let msg = test_case.consume_bytes("Msg");
let msg = untrusted::Input::from(&msg);
let sig = test_case.consume_bytes("Sig");
let sig = untrusted::Input::from(&sig);
let expected_result = test_case.consume_string("Result");
let actual_result = signature::verify(alg, public_key, msg, sig);
assert_eq!(actual_result.is_ok(), expected_result == "P");
Ok(())
});
}
#[test]
fn test_signature_rsa_pss_verify() {
test::from_file("tests/rsa_pss_verify_tests.txt", |section, test_case| {
assert_eq!(section, "");
let digest_name = test_case.consume_string("Digest");
let alg = match digest_name.as_ref() {
"SHA256" => &signature::RSA_PSS_2048_8192_SHA256,
"SHA384" => &signature::RSA_PSS_2048_8192_SHA384,
"SHA512" => &signature::RSA_PSS_2048_8192_SHA512,
_ => { panic!("Unsupported digest: {}", digest_name) }
};
let public_key = test_case.consume_bytes("Key");
let public_key = untrusted::Input::from(&public_key);
// Sanity check that we correctly DER-encoded the originally-
// provided separate (n, e) components. When we add test vectors
// for improperly-encoded signatures, we'll have to revisit this.
assert!(public_key.read_all(error::Unspecified, |input| {
der::nested(input, der::Tag::Sequence, error::Unspecified, |input| {
let _ = try!(der::positive_integer(input));
let _ = try!(der::positive_integer(input));
Ok(())
})
}).is_ok());
let msg = test_case.consume_bytes("Msg");
let msg = untrusted::Input::from(&msg);
let sig = test_case.consume_bytes("Sig");
let sig = untrusted::Input::from(&sig);
let expected_result = test_case.consume_string("Result");
let actual_result = signature::verify(alg, public_key, msg, sig);
assert_eq!(actual_result.is_ok(), expected_result == "P");
Ok(())
});
}
// Test for `primitive::verify()`. Read public key parts from a file
// and use them to verify a signature.
#[test]
fn test_signature_rsa_primitive_verification() {
test::from_file("tests/rsa_primitive_verify_tests.txt",
|section, test_case| {
assert_eq!(section, "");
let n = test_case.consume_bytes("n");
let e = test_case.consume_bytes("e");
let msg = test_case.consume_bytes("Msg");
let sig = test_case.consume_bytes("Sig");
let expected = test_case.consume_string("Result");
let result = signature::primitive::verify_rsa(
&signature::RSA_PKCS1_2048_8192_SHA256,
(untrusted::Input::from(&n), untrusted::Input::from(&e)),
untrusted::Input::from(&msg), untrusted::Input::from(&sig));
assert_eq!(result.is_ok(), expected == "Pass");
Ok(())
})
}