bssl-crypto: support ECDSA verification of already-hashed messages.

Sometimes an ECDSA key is used with the "wrong" hash function. This
change adds a function which allows callers to still verify those
signatures.

Change-Id: I2cc8b9c06c53bbfca51e23ab97302c35c6a02dd9
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/98687
Presubmit-BoringSSL-Verified: boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com <boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Adam Langley <agl@google.com>
Reviewed-by: Xiangfei Ding <xfding@google.com>
Commit-Queue: Adam Langley <agl@google.com>
diff --git a/rust/bssl-crypto/src/ecdsa.rs b/rust/bssl-crypto/src/ecdsa.rs
index 568db33..c103247 100644
--- a/rust/bssl-crypto/src/ecdsa.rs
+++ b/rust/bssl-crypto/src/ecdsa.rs
@@ -100,12 +100,32 @@
     /// produce the digest if the curve of this public key is P-384.
     pub fn verify(&self, signed_msg: &[u8], signature: &[u8]) -> Result<(), InvalidSignatureError> {
         let digest = C::hash(signed_msg);
+        self.verify_already_hashed(&digest, signature)
+    }
+
+    /// Verify `signature` as a valid ASN.1-based signature of `hashed_msg` with
+    /// this public key. `hashed_msg` must already have been hashed with a
+    /// secure hash function: passing unhashed data here breaks the security
+    /// properties of the signature scheme. If you have unhashed data, use
+    /// `verify` instead.
+    ///
+    /// This function exists because sometimes the "wrong" hash function is used
+    /// with a key. A key should not be used with different hash functions and
+    /// there is an obvious correspondence between NIST's standard elliptic
+    /// curves and the SHA-2 family of hash functions that implicitly defines
+    /// the correct hash function to use with a given key. But, if mistakes have
+    /// been made, this function is here for you.
+    pub fn verify_already_hashed(
+        &self,
+        hashed_msg: &[u8],
+        signature: &[u8],
+    ) -> Result<(), InvalidSignatureError> {
         let result = self.point.with_point_as_ec_key(|ec_key| unsafe {
             // Safety: `ec_key` is valid per `with_point_as_ec_key`.
             bssl_sys::ECDSA_verify(
                 /*type=*/ 0,
-                digest.as_slice().as_ffi_ptr(),
-                digest.len(),
+                hashed_msg.as_ffi_ptr(),
+                hashed_msg.len(),
                 signature.as_ffi_ptr(),
                 signature.len(),
                 ec_key,
@@ -373,10 +393,18 @@
         )
         .unwrap();
         assert!(public_key.verify(signed_message, sig.as_slice()).is_ok());
+        let mut digest = C::hash(signed_message);
+        assert!(public_key
+            .verify_already_hashed(digest.as_slice(), sig.as_slice())
+            .is_ok());
         assert!(public_key
             .verify_p1363(signed_message, sig_p1363.as_slice())
             .is_ok());
 
+        digest[0] ^= 1;
+        assert!(public_key
+            .verify_already_hashed(digest.as_slice(), sig.as_slice())
+            .is_err());
         sig[10] ^= 1;
         assert!(public_key.verify(signed_message, sig.as_slice()).is_err());
         sig_p1363[10] ^= 1;