[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]