Expose RSAEncoding in the public API.

Expose `RSAEncoding` in the public API so that users of *ring* can use
it in type signatures. Add an "RSA" prefix to the exported types, since
they will be exported from `ring::signature`. Modify RSA tests to use
only the public API so as to ensure that enough of the API is public.
This commit is contained in:
Brian Smith 2016-11-14 15:58:16 -10:00
parent 5fb1fc8a5e
commit f0f9b00e1a
5 changed files with 104 additions and 65 deletions

View File

@ -19,26 +19,40 @@ use untrusted;
#[cfg(feature = "rsa_signing")]
use rand;
/// The term "Encoding" comes from RFC 3447.
/// An RSA signature encoding as described in [RFC 3447 Section 8].
///
/// [RFC 3447 Section 8]: https://tools.ietf.org/html/rfc3447#section-8
#[cfg(feature = "rsa_signing")]
pub trait Encoding: Sync {
pub trait RSAEncoding: 'static + Sync + ::private::Private {
#[doc(hidden)]
fn encode(&self, msg: &[u8], m_out: &mut [u8], mod_bits: bits::BitLength,
rng: &rand::SecureRandom) -> Result<(), error::Unspecified>;
}
/// The term "Verification" comes from RFC 3447.
pub trait Verification: Sync {
/// Verification of an RSA signature encoding as described in
/// [RFC 3447 Section 8].
///
/// [RFC 3447 Section 8]: https://tools.ietf.org/html/rfc3447#section-8
pub trait RSAVerification: 'static + Sync + ::private::Private {
fn verify(&self, msg: untrusted::Input, m: &mut untrusted::Reader,
mod_bits: bits::BitLength) -> Result<(), error::Unspecified>;
}
/// PKCS#1 1.5 padding as described in [RFC 3447 Section 8.2].
///
/// See "`RSA_PSS_*` Details\" in `ring::signature`'s module-level
/// documentation for more details.
///
/// [RFC 3447 Section 8.2]: https://tools.ietf.org/html/rfc3447#section-8.2
pub struct PKCS1 {
digest_alg: &'static digest::Algorithm,
digestinfo_prefix: &'static [u8],
}
impl ::private::Private for PKCS1 { }
#[cfg(feature ="rsa_signing")]
impl Encoding for PKCS1 {
impl RSAEncoding for PKCS1 {
// Implement padding procedure per EMSA-PKCS1-v1_5,
// https://tools.ietf.org/html/rfc3447#section-9.2.
fn encode(&self, msg: &[u8], m_out: &mut [u8], _mod_bits: bits::BitLength,
@ -68,7 +82,7 @@ impl Encoding for PKCS1 {
}
}
impl Verification for PKCS1 {
impl RSAVerification for PKCS1 {
fn verify(&self, msg: untrusted::Input, m: &mut untrusted::Reader,
_mod_bits: bits::BitLength) -> Result<(), error::Unspecified> {
let em = m;
@ -168,21 +182,25 @@ pkcs1_digestinfo_prefix!(
[ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 ]);
/// PSS padding as described in [RFC 3447 Section 8.1]. The mask generation
/// function is MGF1 using the signature's digest's algorithm.
/// RSA PSS padding as described in [RFC 3447 Section 8.1].
///
/// See "`RSA_PSS_*` Details\" in `ring::signature`'s module-level
/// documentation for more details.
///
/// [RFC 3447 Section 8.1]: https://tools.ietf.org/html/rfc3447#section-8.1
pub struct PSS {
digest_alg: &'static digest::Algorithm,
}
impl ::private::Private for PSS { }
#[cfg(feature = "rsa_signing")]
// Maximum supported length of the salt in bytes.
// In practice, this is constrained by the maximum digest length.
const MAX_SALT_LEN: usize = digest::MAX_OUTPUT_LEN;
#[cfg(feature = "rsa_signing")]
impl Encoding for PSS {
impl RSAEncoding for PSS {
// Implement padding procedure per EMSA-PSS,
// https://tools.ietf.org/html/rfc3447#section-9.1.
fn encode(&self, msg: &[u8], m_out: &mut [u8], mod_bits: bits::BitLength,
@ -250,7 +268,7 @@ impl Encoding for PSS {
}
}
impl Verification for PSS {
impl RSAVerification for PSS {
// RSASSA-PSS-VERIFY from https://tools.ietf.org/html/rfc3447#section-8.1.2
// where steps 1, 2(a), and 2(b) have been done for us.
fn verify(&self, msg: untrusted::Input, m: &mut untrusted::Reader,
@ -437,11 +455,17 @@ macro_rules! rsa_pss_padding {
}
rsa_pss_padding!(RSA_PSS_SHA256, &digest::SHA256,
"PSS padding using SHA-256 for RSA signatures.");
"RSA PSS padding using SHA-256 for RSA signatures.\n\nSee
\"`RSA_PSS_*` Details\" in `ring::signature`'s module-level
documentation for more details.");
rsa_pss_padding!(RSA_PSS_SHA384, &digest::SHA384,
"PSS padding using SHA-384 for RSA signatures.");
"RSA PSS padding using SHA-384 for RSA signatures.\n\nSee
\"`RSA_PSS_*` Details\" in `ring::signature`'s module-level
documentation for more details.");
rsa_pss_padding!(RSA_PSS_SHA512, &digest::SHA512,
"PSS padding using SHA-512 for RSA signatures.");
"RSA PSS padding using SHA-512 for RSA signatures.\n\nSee
\"`RSA_PSS_*` Details\" in `ring::signature`'s module-level
documentation for more details.");
#[cfg(test)]
mod test {

View File

@ -20,8 +20,18 @@ use untrusted;
mod padding;
// `RSA_PKCS1_SHA1` is intentionally not exposed.
pub use self::padding::{RSA_PKCS1_SHA256, RSA_PKCS1_SHA384, RSA_PKCS1_SHA512,
RSA_PSS_SHA256, RSA_PSS_SHA384, RSA_PSS_SHA512};
#[cfg(feature = "rsa_signing")]
pub use self::padding::RSAEncoding;
pub use self::padding::{
RSA_PKCS1_SHA256,
RSA_PKCS1_SHA384,
RSA_PKCS1_SHA512,
RSA_PSS_SHA256,
RSA_PSS_SHA384,
RSA_PSS_SHA512
};
// Maximum RSA modulus size supported for signature verification (in bytes).
@ -29,7 +39,7 @@ const PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN: usize = 8192 / 8;
/// Parameters for RSA verification.
pub struct RSAParameters {
padding_alg: &'static padding::Verification,
padding_alg: &'static padding::RSAVerification,
min_bits: usize,
}

View File

@ -17,7 +17,7 @@
use {bits, bssl, c, der, error};
use rand;
use std;
use super::{BIGNUM, GFp_BN_free, BN_MONT_CTX, GFp_BN_MONT_CTX_free, padding,
use super::{BIGNUM, GFp_BN_free, BN_MONT_CTX, GFp_BN_MONT_CTX_free,
PositiveInteger};
use untrusted;
@ -216,7 +216,7 @@ impl RSASigningState {
/// platforms, it is done less perfectly. To help mitigate the current
/// imperfections, and for defense-in-depth, base blinding is always done.
/// Exponent blinding is not done, but it may be done in the future.
pub fn sign(&mut self, padding_alg: &'static padding::Encoding,
pub fn sign(&mut self, padding_alg: &'static ::signature::RSAEncoding,
rng: &rand::SecureRandom, msg: &[u8], signature: &mut [u8])
-> Result<(), error::Unspecified> {
let mod_bits = self.key_pair.n_bits;
@ -271,16 +271,10 @@ extern {
#[cfg(test)]
mod tests {
use error;
use rand;
// 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 {error, rand, signature, test};
use std;
use test;
use super::*;
use super::super::{
RSA_PKCS1_SHA256, RSA_PKCS1_SHA384, RSA_PKCS1_SHA512,
RSA_PSS_SHA256, RSA_PSS_SHA384, RSA_PSS_SHA512,
};
use untrusted;
extern {
@ -296,9 +290,9 @@ mod tests {
let digest_name = test_case.consume_string("Digest");
let alg = match digest_name.as_ref() {
"SHA256" => &RSA_PKCS1_SHA256,
"SHA384" => &RSA_PKCS1_SHA384,
"SHA512" => &RSA_PKCS1_SHA512,
"SHA256" => &signature::RSA_PKCS1_SHA256,
"SHA384" => &signature::RSA_PKCS1_SHA384,
"SHA512" => &signature::RSA_PKCS1_SHA512,
_ => { panic!("Unsupported digest: {}", digest_name) }
};
@ -308,7 +302,7 @@ mod tests {
let result = test_case.consume_string("Result");
let private_key = untrusted::Input::from(&private_key);
let key_pair = RSAKeyPair::from_der(private_key);
let key_pair = signature::RSAKeyPair::from_der(private_key);
if key_pair.is_err() && result == "Fail-Invalid-Key" {
return Ok(());
}
@ -317,7 +311,8 @@ mod tests {
// XXX: This test is too slow on Android ARM Travis CI builds.
// TODO: re-enable these tests on Android ARM.
let mut signing_state = RSASigningState::new(key_pair).unwrap();
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();
@ -340,26 +335,27 @@ mod tests {
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 = RSAKeyPair::from_der(key_bytes_der).unwrap();
let key_pair = signature::RSAKeyPair::from_der(key_bytes_der).unwrap();
let key_pair = std::sync::Arc::new(key_pair);
let mut signing_state = RSASigningState::new(key_pair).unwrap();
let mut signing_state =
signature::RSASigningState::new(key_pair).unwrap();
// The output buffer is one byte too short.
let mut signature =
vec![0; signing_state.key_pair().public_modulus_len() - 1];
assert!(signing_state.sign(&RSA_PKCS1_SHA256, &rng, MESSAGE,
assert!(signing_state.sign(&signature::RSA_PKCS1_SHA256, &rng, MESSAGE,
&mut signature).is_err());
// The output buffer is the right length.
signature.push(0);
assert!(signing_state.sign(&RSA_PKCS1_SHA256, &rng, MESSAGE,
assert!(signing_state.sign(&signature::RSA_PKCS1_SHA256, &rng, MESSAGE,
&mut signature).is_ok());
// The output buffer is one byte too long.
signature.push(0);
assert!(signing_state.sign(&RSA_PKCS1_SHA256, &rng, MESSAGE,
assert!(signing_state.sign(&signature::RSA_PKCS1_SHA256, &rng, MESSAGE,
&mut signature).is_err());
}
@ -375,11 +371,12 @@ mod tests {
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 = RSAKeyPair::from_der(key_bytes_der).unwrap();
let key_pair = signature::RSAKeyPair::from_der(key_bytes_der).unwrap();
let key_pair = std::sync::Arc::new(key_pair);
let mut signature = vec![0; key_pair.public_modulus_len()];
let mut signing_state = RSASigningState::new(key_pair).unwrap();
let mut signing_state =
signature::RSASigningState::new(key_pair).unwrap();
let blinding_counter = unsafe { GFp_BN_BLINDING_COUNTER };
@ -387,7 +384,8 @@ mod tests {
let prev_counter =
unsafe { (*signing_state.blinding.blinding).counter };
let _ = signing_state.sign(&RSA_PKCS1_SHA256, &rng, MESSAGE, &mut signature);
let _ = signing_state.sign(&signature::RSA_PKCS1_SHA256, &rng,
MESSAGE, &mut signature);
let counter = unsafe { (*signing_state.blinding.blinding).counter };
@ -410,13 +408,14 @@ mod tests {
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 = RSAKeyPair::from_der(key_bytes_der).unwrap();
let key_pair = signature::RSAKeyPair::from_der(key_bytes_der).unwrap();
let key_pair = std::sync::Arc::new(key_pair);
let mut signing_state = RSASigningState::new(key_pair).unwrap();
let mut signing_state =
signature::RSASigningState::new(key_pair).unwrap();
let mut signature =
vec![0; signing_state.key_pair().public_modulus_len()];
let result =
signing_state.sign(&RSA_PKCS1_SHA256, &rng, MESSAGE, &mut signature);
let result = signing_state.sign(&signature::RSA_PKCS1_SHA256, &rng,
MESSAGE, &mut signature);
assert!(result.is_err());
}
@ -448,16 +447,16 @@ mod tests {
let digest_name = test_case.consume_string("Digest");
let alg = match digest_name.as_ref() {
"SHA256" => &RSA_PSS_SHA256,
"SHA384" => &RSA_PSS_SHA384,
"SHA512" => &RSA_PSS_SHA512,
"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 = RSAKeyPair::from_der(private_key);
let key_pair = signature::RSAKeyPair::from_der(private_key);
if key_pair.is_err() && result == "Fail-Invalid-Key" {
return Ok(());
}
@ -469,7 +468,8 @@ mod tests {
let new_rng = DeterministicSalt { salt: &salt, rng: &rng };
let mut signing_state = RSASigningState::new(key_pair).unwrap();
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()));
@ -484,13 +484,13 @@ mod tests {
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 = RSAKeyPair::from_der(key_bytes_der).unwrap();
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 = RSASigningState::new(key_pair).unwrap();
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

@ -141,9 +141,9 @@ extern {
#[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 super::*;
use untrusted;
#[test]
@ -154,10 +154,10 @@ mod tests {
let digest_name = test_case.consume_string("Digest");
let alg = match digest_name.as_ref() {
"SHA1" => &RSA_PKCS1_2048_8192_SHA1,
"SHA256" => &RSA_PKCS1_2048_8192_SHA256,
"SHA384" => &RSA_PKCS1_2048_8192_SHA384,
"SHA512" => &RSA_PKCS1_2048_8192_SHA512,
"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) }
};
@ -199,9 +199,9 @@ mod tests {
let digest_name = test_case.consume_string("Digest");
let alg = match digest_name.as_ref() {
"SHA256" => &RSA_PSS_2048_8192_SHA256,
"SHA384" => &RSA_PSS_2048_8192_SHA384,
"SHA512" => &RSA_PSS_2048_8192_SHA512,
"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) }
};
@ -247,11 +247,10 @@ mod tests {
let msg = test_case.consume_bytes("Msg");
let sig = test_case.consume_bytes("Sig");
let expected = test_case.consume_string("Result");
let result = verify_rsa(&RSA_PKCS1_2048_8192_SHA256,
(untrusted::Input::from(&n),
untrusted::Input::from(&e)),
untrusted::Input::from(&msg),
untrusted::Input::from(&sig));
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

@ -237,6 +237,8 @@ pub use rsa::signing::{RSAKeyPair, RSASigningState};
#[cfg(all(feature = "rsa_signing", feature = "use_heap"))]
pub use rsa::{
RSAEncoding,
// `RSA_PKCS1_SHA1` is intentionally not exposed. At a minimum, we'd need
// to create test vectors for signing with it, which we don't currently
// have. But, it's a bad idea to use SHA-1 anyway, so perhaps we just won't
@ -244,6 +246,10 @@ pub use rsa::{
RSA_PKCS1_SHA256,
RSA_PKCS1_SHA384,
RSA_PKCS1_SHA512,
RSA_PSS_SHA256,
RSA_PSS_SHA384,
RSA_PSS_SHA512,
};
#[cfg(feature = "use_heap")]