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:
parent
5fb1fc8a5e
commit
f0f9b00e1a
@ -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 {
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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(())
|
||||
})
|
||||
|
@ -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")]
|
||||
|
Loading…
x
Reference in New Issue
Block a user