[bssl] Support ED25519/X25519 public key types for EVP_PKEY
These ED25519 key type will be needed in DICE certificate
verification later.
Bug: 310931749
Test: atest libbssl_avf_nostd.test
Change-Id: I9dda103f3f46f781dec6f0062cdbf29d3078559f
diff --git a/libs/bssl/src/evp.rs b/libs/bssl/src/evp.rs
index 5362925..330f317 100644
--- a/libs/bssl/src/evp.rs
+++ b/libs/bssl/src/evp.rs
@@ -15,22 +15,24 @@
//! Wrappers of the EVP functions in BoringSSL evp.h.
use crate::cbb::CbbFixed;
+use crate::digest::{Digester, DigesterContext};
use crate::ec_key::EcKey;
use crate::util::{check_int_result, to_call_failed_error};
use alloc::vec::Vec;
use bssl_avf_error::{ApiName, Result};
use bssl_ffi::{
- CBB_flush, CBB_len, EVP_PKEY_free, EVP_PKEY_new, EVP_PKEY_set1_EC_KEY, EVP_marshal_public_key,
- EVP_PKEY,
+ CBB_flush, CBB_len, EVP_DigestVerify, EVP_DigestVerifyInit, EVP_PKEY_free, EVP_PKEY_new,
+ EVP_PKEY_new_raw_public_key, EVP_PKEY_set1_EC_KEY, EVP_marshal_public_key, EVP_PKEY,
+ EVP_PKEY_ED25519, EVP_PKEY_X25519,
};
-use core::ptr::NonNull;
+use core::ptr::{self, NonNull};
/// Wrapper of an `EVP_PKEY` object, representing a public or private key.
pub struct PKey {
pkey: NonNull<EVP_PKEY>,
- /// Since this struct owns the inner key, the inner key remains valid as
+ /// If this struct owns the inner EC key, the inner EC key should remain valid as
/// long as the pointer to `EVP_PKEY` is valid.
- _inner_key: EcKey,
+ _inner_ec_key: Option<EcKey>,
}
impl Drop for PKey {
@@ -53,14 +55,14 @@
fn try_from(key: EcKey) -> Result<Self> {
let pkey = new_pkey()?;
- // SAFETY: The function only sets the inner key of the initialized and
+ // SAFETY: The function only sets the inner EC key of the initialized and
// non-null `EVP_PKEY` to point to the given `EC_KEY`. It only reads from
// and writes to the initialized `EVP_PKEY`.
// Since this struct owns the inner key, the inner key remains valid as
// long as `EVP_PKEY` is valid.
let ret = unsafe { EVP_PKEY_set1_EC_KEY(pkey.as_ptr(), key.0.as_ptr()) };
check_int_result(ret, ApiName::EVP_PKEY_set1_EC_KEY)?;
- Ok(Self { pkey, _inner_key: key })
+ Ok(Self { pkey, _inner_ec_key: Some(key) })
}
}
@@ -87,4 +89,89 @@
let len = unsafe { CBB_len(cbb.as_ref()) };
Ok(buf.get(0..len).ok_or(to_call_failed_error(ApiName::CBB_len))?.to_vec())
}
+
+ /// This function takes a raw public key data slice and creates a `PKey` instance wrapping
+ /// a freshly allocated `EVP_PKEY` object from it.
+ ///
+ /// The lifetime of the returned instance is not tied to the lifetime of the raw public
+ /// key slice because the raw data is copied into the `EVP_PKEY` object.
+ ///
+ /// Currently the only supported raw formats are X25519 and Ed25519, where the formats
+ /// are specified in RFC 7748 and RFC 8032 respectively.
+ pub fn new_raw_public_key(raw_public_key: &[u8], type_: PKeyType) -> Result<Self> {
+ let engine = ptr::null_mut(); // Engine is not used.
+ let pkey =
+ // SAFETY: The function only reads from the given raw public key within its bounds.
+ // The returned pointer is checked below.
+ unsafe {
+ EVP_PKEY_new_raw_public_key(
+ type_.0,
+ engine,
+ raw_public_key.as_ptr(),
+ raw_public_key.len(),
+ )
+ };
+ let pkey =
+ NonNull::new(pkey).ok_or(to_call_failed_error(ApiName::EVP_PKEY_new_raw_public_key))?;
+ Ok(Self { pkey, _inner_ec_key: None })
+ }
+
+ /// Verifies the given `signature` of the `message` using the current public key.
+ ///
+ /// The `message` will be hashed using the given `digester` before verification.
+ ///
+ /// For algorithms like Ed25519 that do not use pre-hashed inputs, the `digester` should
+ /// be `None`.
+ pub fn verify(
+ &self,
+ signature: &[u8],
+ message: &[u8],
+ digester: Option<Digester>,
+ ) -> Result<()> {
+ let mut digester_context = DigesterContext::new()?;
+ // The `EVP_PKEY_CTX` is set to null as this function does not collect the context
+ // during the verification.
+ let pkey_context = ptr::null_mut();
+ let engine = ptr::null_mut(); // Use the default engine.
+ let ret =
+ // SAFETY: All the non-null parameters passed to this function have been properly
+ // initialized as required in the BoringSSL spec.
+ unsafe {
+ EVP_DigestVerifyInit(
+ digester_context.as_mut_ptr(),
+ pkey_context,
+ digester.map_or(ptr::null(), |d| d.0),
+ engine,
+ self.pkey.as_ptr(),
+ )
+ };
+ check_int_result(ret, ApiName::EVP_DigestVerifyInit)?;
+
+ // SAFETY: The function only reads from the given slices within their bounds.
+ // The `EVP_MD_CTX` is successfully initialized before this call.
+ let ret = unsafe {
+ EVP_DigestVerify(
+ digester_context.as_mut_ptr(),
+ signature.as_ptr(),
+ signature.len(),
+ message.as_ptr(),
+ message.len(),
+ )
+ };
+ check_int_result(ret, ApiName::EVP_DigestVerify)
+ }
+}
+
+/// Type of the keys supported by `PKey`.
+///
+/// It is a wrapper of the `EVP_PKEY_*` macros defined BoringSSL evp.h, which are the
+/// NID values of the corresponding keys.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct PKeyType(i32);
+
+impl PKeyType {
+ /// EVP_PKEY_X25519 / NID_X25519
+ pub const X25519: PKeyType = PKeyType(EVP_PKEY_X25519);
+ /// EVP_PKEY_ED25519 / NID_ED25519
+ pub const ED25519: PKeyType = PKeyType(EVP_PKEY_ED25519);
}