Refactor low-level RSA signature verification API.

Replace `(n, e)` tuple with a structure with named `n` and `e` fields
to improve safety. Remove the use of `untrusted`.
This commit is contained in:
Brian Smith 2019-04-05 16:52:56 -10:00
parent d56ca70fd0
commit 9f211157a8
3 changed files with 53 additions and 36 deletions

View File

@ -175,7 +175,7 @@ rsa_params!(
`ring::signature`'s module-level documentation for more details."
);
/// Lower-level API for the verification of RSA signatures.
/// Low-level API for the verification of RSA signatures.
///
/// When the public key is in DER-encoded PKCS#1 ASN.1 format, it is
/// recommended to use `ring::signature::verify()` with
@ -183,16 +183,8 @@ rsa_params!(
/// will handle the parsing in that case. Otherwise, this function can be used
/// to pass in the raw bytes for the public key components as
/// `untrusted::Input` arguments.
///
/// `params` determine what algorithm parameters (padding, digest algorithm,
/// key length range, etc.) are used in the verification. `msg` is the message
/// and `signature` is the signature.
///
/// `n` is the public key modulus and `e` is the public key exponent. Both are
/// interpreted as unsigned big-endian encoded values. Both must be positive
/// and neither may have any leading zeros.
//
// There are a small number of tests that test `verify_rsa` directly, but the
// There are a small number of tests that test this directly, but the
// test coverage for this function mostly depends on the test coverage for the
// `signature::VerificationAlgorithm` implementation for `RsaParameters`. If we
// change that, test coverage for `verify_rsa()` will need to be reconsidered.
@ -200,12 +192,52 @@ rsa_params!(
// testing `verify_rsa` directly, but the testing work for RSA PKCS#1
// verification was done during the implementation of
// `signature::VerificationAlgorithm`, before `verify_rsa` was factored out).
pub fn verify_rsa(
params: &RsaParameters, (n, e): (untrusted::Input, untrusted::Input), msg: untrusted::Input,
signature: untrusted::Input,
) -> Result<(), error::Unspecified> {
let _ = cpu::features();
verify_rsa_(params, (n, e), msg, signature)
#[derive(Debug)]
pub struct RsaPublicKeyComponents<B: AsRef<[u8]> + core::fmt::Debug> {
/// The public modulus, encoded in big-endian bytes without leading zeros.
pub n: B,
/// The public exponent, encoded in big-endian bytes without leading zeros.
/// without leading zeros.
pub e: B,
}
impl<B: Copy> Copy for RsaPublicKeyComponents<B> where B: AsRef<[u8]> + core::fmt::Debug {}
impl<B: Clone> Clone for RsaPublicKeyComponents<B>
where
B: AsRef<[u8]> + core::fmt::Debug,
{
fn clone(&self) -> Self {
Self {
n: self.n.clone(),
e: self.e.clone(),
}
}
}
impl<B> RsaPublicKeyComponents<B>
where
B: AsRef<[u8]> + core::fmt::Debug,
{
/// Verifies that `signature` is a valid signature of `message` using `self`
/// as the public key. `params` determine what algorithm parameters
/// (padding, digest algorithm, key length range, etc.) are used in the
/// verification.
pub fn verify(
&self, params: &RsaParameters, message: &[u8], signature: &[u8],
) -> Result<(), error::Unspecified> {
let _ = cpu::features();
verify_rsa_(
params,
(
untrusted::Input::from(self.n.as_ref()),
untrusted::Input::from(self.e.as_ref()),
),
untrusted::Input::from(message),
untrusted::Input::from(signature),
)
}
}
pub(crate) fn verify_rsa_(

View File

@ -286,9 +286,9 @@ pub use crate::rsa::{
signing::RsaSubjectPublicKey,
verification::{
RSA_PKCS1_2048_8192_SHA1, RSA_PKCS1_2048_8192_SHA256, RSA_PKCS1_2048_8192_SHA384,
RSA_PKCS1_2048_8192_SHA512, RSA_PKCS1_3072_8192_SHA384, RSA_PSS_2048_8192_SHA256,
RSA_PSS_2048_8192_SHA384, RSA_PSS_2048_8192_SHA512,
RsaPublicKeyComponents, RSA_PKCS1_2048_8192_SHA1, RSA_PKCS1_2048_8192_SHA256,
RSA_PKCS1_2048_8192_SHA384, RSA_PKCS1_2048_8192_SHA512, RSA_PKCS1_3072_8192_SHA384,
RSA_PSS_2048_8192_SHA256, RSA_PSS_2048_8192_SHA384, RSA_PSS_2048_8192_SHA512,
},
RsaEncoding,
@ -307,17 +307,6 @@ pub use crate::rsa::{
RSA_PSS_SHA512,
};
/// Lower-level verification primitives.
///
/// Use [UnparsedPublicKey::verify()] instead when the public key is in a
/// standard format.
///
/// [UnparsedPublicKey::verify()]: crate::signature::UnparsedPublicKey
#[cfg(feature = "use_heap")]
pub mod primitive {
pub use crate::rsa::verification::verify_rsa;
}
/// A public key signature returned from a signing operation.
#[derive(Clone, Copy)]
pub struct Signature {

View File

@ -272,12 +272,8 @@ fn test_signature_rsa_primitive_verification() {
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),
);
let public_key = signature::RsaPublicKeyComponents { n: &n, e: &e };
let result = public_key.verify(&signature::RSA_PKCS1_2048_8192_SHA256, &msg, &sig);
assert_eq!(result.is_ok(), expected == "Pass");
Ok(())
},