Refactor ring::signature
verification API.
Introduce `UnparsedPublicKey`. Remove public use of `untrusted::Input`. Replace `signature::verify()` with `UnparsedPublicKey::verify()`.
This commit is contained in:
parent
4a5957c05b
commit
306d163613
@ -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.
|
||||
|
@ -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(())
|
||||
},
|
||||
|
110
src/signature.rs
110
src/signature.rs
@ -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())
|
||||
}
|
||||
|
@ -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(())
|
||||
},
|
||||
|
@ -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(())
|
||||
});
|
||||
}
|
||||
|
@ -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(())
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user