Refactor ring::signature verification API.

Introduce `UnparsedPublicKey`. Remove public use of `untrusted::Input`.
Replace `signature::verify()` with `UnparsedPublicKey::verify()`.
This commit is contained in:
Brian Smith 2019-04-05 12:46:58 -10:00
parent 4a5957c05b
commit 306d163613
6 changed files with 141 additions and 91 deletions

View File

@ -81,12 +81,12 @@ mod tests {
let public_key = test_case.consume_bytes("Q");
let public_key = untrusted::Input::from(&public_key);
let valid = test_case.consume_string("Result") == "P";
let is_valid = test_case.consume_string("Result") == "P";
let curve_ops = public_key_ops_from_curve_name(&curve_name);
let result = parse_uncompressed_point(curve_ops, public_key);
assert_eq!(valid, result.is_ok());
assert_eq!(is_valid, result.is_ok());
// TODO: Verify that we when we re-serialize the parsed (x, y), the
// output is equal to the input.

View File

@ -522,11 +522,11 @@ mod test {
let _ = test_case.consume_bytes("Salt");
let bit_len = test_case.consume_usize_bits("Len");
let expected_result = test_case.consume_string("Result");
let is_valid = test_case.consume_string("Result") == "P";
let actual_result =
encoded.read_all(error::Unspecified, |m| alg.verify(&m_hash, m, bit_len));
assert_eq!(actual_result.is_ok(), expected_result == "P");
assert_eq!(actual_result.is_ok(), is_valid);
Ok(())
},

View File

@ -151,16 +151,13 @@
//! // send them in a protocol message to the peer(s). Here we just get the
//! // public key key directly from the key pair.
//! let peer_public_key_bytes = key_pair.public_key().as_ref();
//! let sig_bytes = sig.as_ref();
//!
//! // Verify the signature of the message using the public key. Normally the
//! // verifier of the message would parse the inputs to `signature::verify`
//! // out of the protocol message(s) sent by the signer.
//! let peer_public_key = untrusted::Input::from(peer_public_key_bytes);
//! let msg = untrusted::Input::from(MESSAGE);
//! let sig = untrusted::Input::from(sig_bytes);
//!
//! signature::verify(&signature::ED25519, peer_public_key, msg, sig)?;
//! // verifier of the message would parse the inputs to this code out of the
//! // protocol message(s) sent by the signer.
//! let peer_public_key =
//! signature::UnparsedPublicKey::new(&signature::ED25519, peer_public_key_bytes);
//! peer_public_key.verify(MESSAGE, sig.as_ref())?;
//!
//! # Ok(())
//! # }
@ -219,15 +216,11 @@
//! .map_err(|_| MyError::OOM)?;
//!
//! // Verify the signature.
//! let public_key_der = read_file(public_key_path)?;
//! let public_key_der = untrusted::Input::from(&public_key_der);
//! let message = untrusted::Input::from(MESSAGE);
//! let signature = untrusted::Input::from(&signature);
//! signature::verify(&signature::RSA_PKCS1_2048_8192_SHA256,
//! public_key_der, message, signature)
//! .map_err(|_| MyError::BadSignature)?;
//!
//! Ok(())
//! let public_key =
//! signature::UnparsedPublicKey::new(&signature::RSA_PKCS1_2048_8192_SHA256,
//! read_file(public_key_path)?);
//! public_key.verify(MESSAGE, &signature)
//! .map_err(|_| MyError::BadSignature)
//! }
//!
//! #[derive(Debug)]
@ -316,9 +309,12 @@ pub use crate::rsa::{
RSA_PSS_SHA512,
};
/// Lower-level verification primitives. Usage of `ring::signature::verify()`
/// is preferred when the public key and signature are encoded in standard
/// formats, as it also handles the parsing.
/// 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;
@ -375,33 +371,57 @@ pub trait VerificationAlgorithm: core::fmt::Debug + Sync + sealed::Sealed {
) -> Result<(), error::Unspecified>;
}
/// Verify the signature `signature` of message `msg` with the public key
/// `public_key` using the algorithm `alg`.
/// An unparsed, possibly malformed, public key for signature verification.
pub struct UnparsedPublicKey<B: AsRef<[u8]>> {
algorithm: &'static VerificationAlgorithm,
bytes: B,
}
impl<B: Copy> Copy for UnparsedPublicKey<B> where B: AsRef<[u8]> {}
impl<B: Clone> Clone for UnparsedPublicKey<B>
where
B: AsRef<[u8]>,
{
fn clone(&self) -> Self {
Self {
algorithm: self.algorithm,
bytes: self.bytes.clone(),
}
}
}
impl<B: AsRef<[u8]>> UnparsedPublicKey<B> {
/// Construct a new `UnparsedPublicKey`.
///
/// No validation of `bytes` is done until `verify()` is called.
#[inline]
pub fn new(algorithm: &'static VerificationAlgorithm, bytes: B) -> Self {
Self { algorithm, bytes }
}
/// Parses the public key and verifies `signature` is a valid signature of
/// `message` using it.
///
/// See the [crate::signature] module-level documentation for examples.
pub fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), error::Unspecified> {
let _ = cpu::features();
self.algorithm.verify(
untrusted::Input::from(self.bytes.as_ref()),
untrusted::Input::from(message),
untrusted::Input::from(signature),
)
}
}
/// Deprecated. Use [UnparsedPublicKey::verify()].
///
/// # Examples
///
/// ## Verify a RSA PKCS#1 signature that uses the SHA-256 digest
///
/// ```
/// use ring::signature;
///
/// enum Error {
/// InvalidSignature,
/// }
///
/// # #[cfg(feature = "use_heap")]
/// fn verify_rsa_pkcs1_sha256(
/// public_key: untrusted::Input, msg: untrusted::Input, sig: untrusted::Input,
/// ) -> Result<(), Error> {
/// signature::verify(&signature::RSA_PKCS1_2048_8192_SHA256, public_key, msg, sig)
/// .map_err(|_| Error::InvalidSignature)
/// }
/// # fn main() { }
/// ```
/// [UnparsedPublicKey::verify()]: UnparsedPublicKey::verify
#[deprecated(note = "Use UnparsedPublicKey::verify")]
pub fn verify(
alg: &VerificationAlgorithm, public_key: untrusted::Input, msg: untrusted::Input,
algorithm: &'static VerificationAlgorithm, public_key: untrusted::Input, msg: untrusted::Input,
signature: untrusted::Input,
) -> Result<(), error::Unspecified> {
let _ = cpu::features();
alg.verify(public_key, msg, signature)
UnparsedPublicKey::new(algorithm, public_key.as_slice_less_safe())
.verify(msg.as_slice_less_safe(), signature.as_slice_less_safe())
}

View File

@ -141,17 +141,10 @@ fn signature_ecdsa_verify_asn1_test() {
let curve_name = test_case.consume_string("Curve");
let digest_name = test_case.consume_string("Digest");
let msg = test_case.consume_bytes("Msg");
let msg = untrusted::Input::from(&msg);
let public_key = test_case.consume_bytes("Q");
let public_key = untrusted::Input::from(&public_key);
let sig = test_case.consume_bytes("Sig");
let sig = untrusted::Input::from(&sig);
let expected_result = test_case.consume_string("Result");
let is_valid = test_case.consume_string("Result") == "P (0 )";
let alg = match (curve_name.as_str(), digest_name.as_str()) {
("P-256", "SHA256") => &signature::ECDSA_P256_SHA256_ASN1,
@ -163,8 +156,18 @@ fn signature_ecdsa_verify_asn1_test() {
},
};
let actual_result = signature::verify(alg, public_key, msg, sig);
assert_eq!(actual_result.is_ok(), expected_result == "P (0 )");
let actual_result =
signature::UnparsedPublicKey::new(alg, &public_key).verify(&msg, &sig);
assert_eq!(actual_result.is_ok(), is_valid);
#[allow(deprecated)]
let actual_result = signature::verify(
alg,
untrusted::Input::from(&public_key),
untrusted::Input::from(&msg),
untrusted::Input::from(&sig),
);
assert_eq!(actual_result.is_ok(), is_valid);
Ok(())
},
@ -182,14 +185,8 @@ fn signature_ecdsa_verify_fixed_test() {
let digest_name = test_case.consume_string("Digest");
let msg = test_case.consume_bytes("Msg");
let msg = untrusted::Input::from(&msg);
let public_key = test_case.consume_bytes("Q");
let public_key = untrusted::Input::from(&public_key);
let sig = test_case.consume_bytes("Sig");
let sig = untrusted::Input::from(&sig);
let expected_result = test_case.consume_string("Result");
let alg = match (curve_name.as_str(), digest_name.as_str()) {
@ -200,8 +197,20 @@ fn signature_ecdsa_verify_fixed_test() {
},
};
let actual_result = signature::verify(alg, public_key, msg, sig);
assert_eq!(actual_result.is_ok(), expected_result == "P (0 )");
let is_valid = expected_result == "P (0 )";
let actual_result =
signature::UnparsedPublicKey::new(alg, &public_key).verify(&msg, &sig);
assert_eq!(actual_result.is_ok(), is_valid);
#[allow(deprecated)]
let actual_result = signature::verify(
alg,
untrusted::Input::from(&public_key),
untrusted::Input::from(&msg),
untrusted::Input::from(&sig),
);
assert_eq!(actual_result.is_ok(), is_valid);
Ok(())
},

View File

@ -47,14 +47,15 @@ fn test_signature_ed25519() {
let public_key = test_case.consume_bytes("PUB");
assert_eq!(32, public_key.len());
let public_key = untrusted::Input::from(&public_key);
let msg = test_case.consume_bytes("MESSAGE");
let expected_sig = test_case.consume_bytes("SIG");
{
let key_pair = Ed25519KeyPair::from_seed_and_public_key(seed, public_key).unwrap();
let key_pair =
Ed25519KeyPair::from_seed_and_public_key(seed, untrusted::Input::from(&public_key))
.unwrap();
let actual_sig = key_pair.sign(&msg);
assert_eq!(&expected_sig[..], actual_sig.as_ref());
}
@ -65,20 +66,29 @@ fn test_signature_ed25519() {
};
let pkcs8 = Ed25519KeyPair::generate_pkcs8(&rng).unwrap();
let key_pair = Ed25519KeyPair::from_pkcs8(untrusted::Input::from(pkcs8.as_ref())).unwrap();
assert_eq!(public_key, *key_pair.public_key().as_ref());
assert_eq!(public_key, key_pair.public_key().as_ref());
// Test Signature generation.
let actual_sig = key_pair.sign(&msg);
assert_eq!(&expected_sig[..], actual_sig.as_ref());
// Test Signature verification.
assert!(signature::verify(
assert!(
signature::UnparsedPublicKey::new(&signature::ED25519, &public_key)
.verify(&msg, &expected_sig)
.is_ok()
);
#[allow(deprecated)]
let actual_result = signature::verify(
&signature::ED25519,
public_key,
untrusted::Input::from(&public_key),
untrusted::Input::from(&msg),
untrusted::Input::from(&expected_sig)
)
.is_ok());
untrusted::Input::from(&expected_sig),
);
assert!(actual_result.is_ok());
Ok(())
});
}

View File

@ -166,12 +166,11 @@ fn test_signature_rsa_pkcs1_verify() {
};
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
assert!(untrusted::Input::from(&public_key)
.read_all(error::Unspecified, |input| der::nested(
input,
der::Tag::Sequence,
@ -185,15 +184,22 @@ fn test_signature_rsa_pkcs1_verify() {
.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 is_valid = test_case.consume_string("Result") == "P";
let expected_result = test_case.consume_string("Result");
let actual_result =
signature::UnparsedPublicKey::new(alg, &public_key).verify(&msg, &sig);
assert_eq!(actual_result.is_ok(), is_valid);
let actual_result = signature::verify(alg, public_key, msg, sig);
assert_eq!(actual_result.is_ok(), expected_result == "P");
// Deprecated API.
#[allow(deprecated)]
let actual_result = signature::verify(
alg,
untrusted::Input::from(&public_key),
untrusted::Input::from(&msg),
untrusted::Input::from(&sig),
);
assert_eq!(actual_result.is_ok(), is_valid);
Ok(())
},
@ -217,12 +223,11 @@ fn test_signature_rsa_pss_verify() {
};
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
assert!(untrusted::Input::from(&public_key)
.read_all(error::Unspecified, |input| der::nested(
input,
der::Tag::Sequence,
@ -236,15 +241,21 @@ fn test_signature_rsa_pss_verify() {
.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 is_valid = test_case.consume_string("Result") == "P";
let expected_result = test_case.consume_string("Result");
let actual_result =
signature::UnparsedPublicKey::new(alg, &public_key).verify(&msg, &sig);
assert_eq!(actual_result.is_ok(), is_valid);
let actual_result = signature::verify(alg, public_key, msg, sig);
assert_eq!(actual_result.is_ok(), expected_result == "P");
#[allow(deprecated)]
let actual_result = signature::verify(
alg,
untrusted::Input::from(&public_key),
untrusted::Input::from(&msg),
untrusted::Input::from(&sig),
);
assert_eq!(actual_result.is_ok(), is_valid);
Ok(())
},