[bssl] Support ECDSA P-384 signature verification

This functionality is required for the verification of DICE
certificate chain in a subsequent cl.

Bug: 314266221
Test: atest libbssl_avf_nostd.test
Change-Id: Idcc3c7e8b22a0c6151490585d0f16474a17e33b9
diff --git a/libs/bssl/error/src/lib.rs b/libs/bssl/error/src/lib.rs
index 000552c..df79104 100644
--- a/libs/bssl/error/src/lib.rs
+++ b/libs/bssl/error/src/lib.rs
@@ -81,6 +81,7 @@
     EVP_AEAD_CTX_new,
     EVP_AEAD_CTX_open,
     EVP_AEAD_CTX_seal,
+    EVP_Digest,
     EVP_MD_CTX_new,
     EVP_PKEY_new,
     EVP_PKEY_new_raw_public_key,
diff --git a/libs/bssl/src/digest.rs b/libs/bssl/src/digest.rs
index 8189584..e986a38 100644
--- a/libs/bssl/src/digest.rs
+++ b/libs/bssl/src/digest.rs
@@ -14,12 +14,18 @@
 
 //! Wrappers of the digest functions in BoringSSL digest.h.
 
-use crate::util::to_call_failed_error;
-use bssl_avf_error::{ApiName, Result};
+use crate::util::{check_int_result, to_call_failed_error};
+use alloc::vec;
+use alloc::vec::Vec;
+use bssl_avf_error::{ApiName, Error, Result};
 use bssl_ffi::{
-    EVP_MD_CTX_free, EVP_MD_CTX_new, EVP_MD_size, EVP_sha256, EVP_sha512, EVP_MD, EVP_MD_CTX,
+    EVP_Digest, EVP_MD_CTX_free, EVP_MD_CTX_new, EVP_MD_size, EVP_sha256, EVP_sha384, EVP_sha512,
+    EVP_MAX_MD_SIZE, EVP_MD, EVP_MD_CTX,
 };
-use core::ptr::NonNull;
+use core::ptr::{self, NonNull};
+use log::error;
+
+const MAX_DIGEST_SIZE: usize = EVP_MAX_MD_SIZE as usize;
 
 /// Message digester wrapping `EVP_MD`.
 #[derive(Clone, Debug)]
@@ -33,7 +39,17 @@
         let p = unsafe { EVP_sha256() };
         // SAFETY: The returned pointer should always be valid and points to a static
         // `EVP_MD`.
-        Self(unsafe { &*p })
+        Self(unsafe { p.as_ref().unwrap() })
+    }
+
+    /// Returns a `Digester` implementing `SHA-384` algorithm.
+    pub fn sha384() -> Self {
+        // SAFETY: This function does not access any Rust variables and simply returns
+        // a pointer to the static variable in BoringSSL.
+        let p = unsafe { EVP_sha384() };
+        // SAFETY: The returned pointer should always be valid and points to a static
+        // `EVP_MD`.
+        Self(unsafe { p.as_ref().unwrap() })
     }
 
     /// Returns a `Digester` implementing `SHA-512` algorithm.
@@ -43,7 +59,7 @@
         let p = unsafe { EVP_sha512() };
         // SAFETY: The returned pointer should always be valid and points to a static
         // `EVP_MD`.
-        Self(unsafe { &*p })
+        Self(unsafe { p.as_ref().unwrap() })
     }
 
     /// Returns the digest size in bytes.
@@ -51,6 +67,39 @@
         // SAFETY: The inner pointer is fetched from EVP_* hash functions in BoringSSL digest.h
         unsafe { EVP_MD_size(self.0) }
     }
+
+    /// Computes the digest of the provided `data`.
+    pub fn digest(&self, data: &[u8]) -> Result<Vec<u8>> {
+        let mut out = vec![0u8; MAX_DIGEST_SIZE];
+        let mut out_size = 0;
+        let engine = ptr::null_mut(); // Use the default engine.
+        let ret =
+            // SAFETY: This function reads `data` and writes to `out` within its bounds.
+            // `out` has `MAX_DIGEST_SIZE` bytes of space for write as required in the
+            // BoringSSL spec.
+            // The digester is a valid pointer to a static `EVP_MD` as it is returned by
+            // BoringSSL API during the construction of this struct.
+            unsafe {
+                EVP_Digest(
+                    data.as_ptr() as *const _,
+                    data.len(),
+                    out.as_mut_ptr(),
+                    &mut out_size,
+                    self.0,
+                    engine,
+                )
+            };
+        check_int_result(ret, ApiName::EVP_Digest)?;
+        let out_size = usize::try_from(out_size).map_err(|e| {
+            error!("Failed to convert digest size to usize: {:?}", e);
+            Error::InternalError
+        })?;
+        if self.size() != out_size {
+            return Err(to_call_failed_error(ApiName::EVP_Digest));
+        }
+        out.truncate(out_size);
+        Ok(out)
+    }
 }
 
 /// Message digester context wrapping `EVP_MD_CTX`.
diff --git a/libs/bssl/tests/eckey_test.rs b/libs/bssl/tests/eckey_test.rs
index 9c503ba..265dee7 100644
--- a/libs/bssl/tests/eckey_test.rs
+++ b/libs/bssl/tests/eckey_test.rs
@@ -82,12 +82,27 @@
 fn ecdsa_p256_signing_and_verification_succeed() -> Result<()> {
     let mut ec_key = EcKey::new_p256()?;
     ec_key.generate_key()?;
-    let digest = sha256(MESSAGE1)?;
+    let digester = Digester::sha256();
+    let digest = digester.digest(MESSAGE1)?;
+    assert_eq!(digest, sha256(MESSAGE1)?);
 
     let signature = ec_key.ecdsa_sign(&digest)?;
     ec_key.ecdsa_verify(&signature, &digest)?;
     let pkey: PKey = ec_key.try_into()?;
-    pkey.verify(&signature, MESSAGE1, Some(Digester::sha256()))
+    pkey.verify(&signature, MESSAGE1, Some(digester))
+}
+
+#[test]
+fn ecdsa_p384_signing_and_verification_succeed() -> Result<()> {
+    let mut ec_key = EcKey::new_p384()?;
+    ec_key.generate_key()?;
+    let digester = Digester::sha384();
+    let digest = digester.digest(MESSAGE1)?;
+
+    let signature = ec_key.ecdsa_sign(&digest)?;
+    ec_key.ecdsa_verify(&signature, &digest)?;
+    let pkey: PKey = ec_key.try_into()?;
+    pkey.verify(&signature, MESSAGE1, Some(digester))
 }
 
 #[test]