[bssl] Support EC P-384 key in libbssl_avf_nostd

The support of EC P-384 key is required for the verification the
signatures of DiceChainEntry in the service VM.

Test: atest libbssl_avf_nostd.test
Change-Id: I1817a913c6b9be96eed4bc2c86d032f24441386c
diff --git a/libs/bssl/src/ec_key.rs b/libs/bssl/src/ec_key.rs
index a187259..511b133 100644
--- a/libs/bssl/src/ec_key.rs
+++ b/libs/bssl/src/ec_key.rs
@@ -23,14 +23,14 @@
 use bssl_avf_error::{ApiName, Error, Result};
 use bssl_ffi::{
     BN_bin2bn, BN_bn2bin_padded, BN_clear_free, BN_new, CBB_flush, CBB_len, ECDSA_sign, ECDSA_size,
-    ECDSA_verify, EC_GROUP_new_by_curve_name, EC_KEY_check_key, EC_KEY_free, EC_KEY_generate_key,
-    EC_KEY_get0_group, EC_KEY_get0_public_key, EC_KEY_marshal_private_key,
-    EC_KEY_new_by_curve_name, EC_KEY_parse_private_key, EC_KEY_set_public_key_affine_coordinates,
-    EC_POINT_get_affine_coordinates, NID_X9_62_prime256v1, BIGNUM, EC_GROUP, EC_KEY, EC_POINT,
+    ECDSA_verify, EC_GROUP_get_curve_name, EC_GROUP_new_by_curve_name, EC_KEY_check_key,
+    EC_KEY_free, EC_KEY_generate_key, EC_KEY_get0_group, EC_KEY_get0_public_key,
+    EC_KEY_marshal_private_key, EC_KEY_new_by_curve_name, EC_KEY_parse_private_key,
+    EC_KEY_set_public_key_affine_coordinates, EC_POINT_get_affine_coordinates,
+    NID_X9_62_prime256v1, NID_secp384r1, BIGNUM, EC_GROUP, EC_KEY, EC_POINT,
 };
 use ciborium::Value;
 use core::ptr::{self, NonNull};
-use core::result;
 use coset::{
     iana::{self, EnumI64},
     CborSerializable, CoseKey, CoseKeyBuilder, Label,
@@ -40,9 +40,9 @@
 
 const ES256_ALGO: iana::Algorithm = iana::Algorithm::ES256;
 const P256_CURVE: iana::EllipticCurve = iana::EllipticCurve::P_256;
+const P384_CURVE: iana::EllipticCurve = iana::EllipticCurve::P_384;
 const P256_AFFINE_COORDINATE_SIZE: usize = 32;
-
-type Coordinate = [u8; P256_AFFINE_COORDINATE_SIZE];
+const P384_AFFINE_COORDINATE_SIZE: usize = 48;
 
 /// Wrapper of an `EC_KEY` object, representing a public or private EC key.
 pub struct EcKey(pub(crate) NonNull<EC_KEY>);
@@ -67,35 +67,45 @@
             .ok_or(to_call_failed_error(ApiName::EC_KEY_new_by_curve_name))
     }
 
+    /// Creates a new EC P-384 key pair.
+    pub fn new_p384() -> Result<Self> {
+        // SAFETY: The returned pointer is checked below.
+        let ec_key = unsafe {
+            EC_KEY_new_by_curve_name(NID_secp384r1) // EC P-384 CURVE Nid
+        };
+        NonNull::new(ec_key)
+            .map(Self)
+            .ok_or(to_call_failed_error(ApiName::EC_KEY_new_by_curve_name))
+    }
+
     /// Constructs an `EcKey` instance from the provided COSE_Key encoded public key slice.
     pub fn from_cose_public_key(cose_key: &[u8]) -> Result<Self> {
         let cose_key = CoseKey::from_slice(cose_key).map_err(|e| {
             error!("Failed to deserialize COSE_Key: {e:?}");
             Error::CoseKeyDecodingFailed
         })?;
-        if cose_key.alg != Some(coset::Algorithm::Assigned(ES256_ALGO)) {
-            error!(
-                "Only ES256 algorithm is supported. Algo type in the COSE Key: {:?}",
-                cose_key.alg
-            );
-            return Err(Error::Unimplemented);
-        }
-        let crv = get_label_value(&cose_key, Label::Int(iana::Ec2KeyParameter::Crv.to_i64()))?;
-        if &Value::from(P256_CURVE.to_i64()) != crv {
-            error!("Only EC P-256 curve is supported. Curve type in the COSE Key: {crv:?}");
-            return Err(Error::Unimplemented);
-        }
-
+        let ec_key =
+            match get_label_value(&cose_key, Label::Int(iana::Ec2KeyParameter::Crv.to_i64()))? {
+                crv if crv == &Value::from(P256_CURVE.to_i64()) => EcKey::new_p256()?,
+                crv if crv == &Value::from(P384_CURVE.to_i64()) => EcKey::new_p384()?,
+                crv => {
+                    error!(
+                        "Only EC P-256 and P-384 curves are supported. \
+                         Curve type in the COSE Key: {crv:?}"
+                    );
+                    return Err(Error::Unimplemented);
+                }
+            };
         let x = get_label_value_as_bytes(&cose_key, Label::Int(iana::Ec2KeyParameter::X.to_i64()))?;
         let y = get_label_value_as_bytes(&cose_key, Label::Int(iana::Ec2KeyParameter::Y.to_i64()))?;
 
-        check_p256_affine_coordinate_size(x)?;
-        check_p256_affine_coordinate_size(y)?;
+        let group = ec_key.ec_group()?;
+        group.check_affine_coordinate_size(x)?;
+        group.check_affine_coordinate_size(y)?;
 
         let x = BigNum::from_slice(x)?;
         let y = BigNum::from_slice(y)?;
 
-        let ec_key = EcKey::new_p256()?;
         // SAFETY: All the parameters are checked non-null and initialized.
         // The function only reads the coordinates x and y within their bounds.
         let ret = unsafe {
@@ -193,14 +203,13 @@
     /// Returns the `CoseKey` for the public key.
     pub fn cose_public_key(&self) -> Result<CoseKey> {
         let (x, y) = self.public_key_coordinates()?;
-        let key = CoseKeyBuilder::new_ec2_pub_key(P256_CURVE, x.to_vec(), y.to_vec())
-            .algorithm(ES256_ALGO)
-            .build();
+        let curve = self.ec_group()?.coset_curve()?;
+        let key = CoseKeyBuilder::new_ec2_pub_key(curve, x, y).algorithm(ES256_ALGO).build();
         Ok(key)
     }
 
     /// Returns the x and y coordinates of the public key.
-    fn public_key_coordinates(&self) -> Result<(Coordinate, Coordinate)> {
+    fn public_key_coordinates(&self) -> Result<(Vec<u8>, Vec<u8>)> {
         let ec_group = self.ec_group()?;
         let ec_point = self.public_key_ec_point()?;
         let mut x = BigNum::new()?;
@@ -209,10 +218,17 @@
         // SAFETY: All the parameters are checked non-null and initialized when needed.
         // The last parameter `ctx` is generated when needed inside the function.
         let ret = unsafe {
-            EC_POINT_get_affine_coordinates(ec_group, ec_point, x.as_mut_ptr(), y.as_mut_ptr(), ctx)
+            EC_POINT_get_affine_coordinates(
+                ec_group.as_ref(),
+                ec_point,
+                x.as_mut_ptr(),
+                y.as_mut_ptr(),
+                ctx,
+            )
         };
         check_int_result(ret, ApiName::EC_POINT_get_affine_coordinates)?;
-        Ok((x.try_into()?, y.try_into()?))
+        let len = ec_group.affine_coordinate_size()?;
+        Ok((x.to_padded_vec(len)?, y.to_padded_vec(len)?))
     }
 
     /// Returns a pointer to the public key point inside `EC_KEY`. The memory region pointed
@@ -231,7 +247,7 @@
 
     /// Returns a pointer to the `EC_GROUP` object inside `EC_KEY`. The memory region pointed
     /// by the pointer is owned by the `EC_KEY`.
-    fn ec_group(&self) -> Result<*const EC_GROUP> {
+    fn ec_group(&self) -> Result<EcGroup<'_>> {
         let group =
            // SAFETY: It is safe since the key pair has been generated and stored in the
            // `EC_KEY` pointer.
@@ -239,7 +255,9 @@
         if group.is_null() {
             Err(to_call_failed_error(ApiName::EC_KEY_get0_group))
         } else {
-            Ok(group)
+            // SAFETY: The pointer should be valid and points to an initialized `EC_GROUP`
+            // since it is read from a valid `EC_KEY`.
+            Ok(EcGroup(unsafe { &*group }))
         }
     }
 
@@ -302,16 +320,59 @@
     Ok(&key.params.iter().find(|(k, _)| k == &label).ok_or(Error::CoseKeyDecodingFailed)?.1)
 }
 
-fn check_p256_affine_coordinate_size(coordinate: &[u8]) -> Result<()> {
-    if P256_AFFINE_COORDINATE_SIZE == coordinate.len() {
-        Ok(())
-    } else {
-        error!(
-            "The size of the affine coordinate '{}' does not match the expected size '{}'",
-            coordinate.len(),
-            P256_AFFINE_COORDINATE_SIZE
-        );
-        Err(Error::CoseKeyDecodingFailed)
+/// Wrapper of an `EC_GROUP` reference.
+struct EcGroup<'a>(&'a EC_GROUP);
+
+impl<'a> EcGroup<'a> {
+    /// Returns the NID that identifies the EC group of the key.
+    fn curve_nid(&self) -> i32 {
+        // SAFETY: It is safe since the inner pointer is valid and points to an initialized
+        // instance of `EC_GROUP`.
+        unsafe { EC_GROUP_get_curve_name(self.as_ref()) }
+    }
+
+    fn coset_curve(&self) -> Result<iana::EllipticCurve> {
+        #[allow(non_upper_case_globals)]
+        match self.curve_nid() {
+            NID_X9_62_prime256v1 => Ok(P256_CURVE),
+            NID_secp384r1 => Ok(P384_CURVE),
+            name => {
+                error!("Unsupported curve NID: {}", name);
+                Err(Error::Unimplemented)
+            }
+        }
+    }
+
+    fn affine_coordinate_size(&self) -> Result<usize> {
+        #[allow(non_upper_case_globals)]
+        match self.curve_nid() {
+            NID_X9_62_prime256v1 => Ok(P256_AFFINE_COORDINATE_SIZE),
+            NID_secp384r1 => Ok(P384_AFFINE_COORDINATE_SIZE),
+            name => {
+                error!("Unsupported curve NID: {}", name);
+                Err(Error::Unimplemented)
+            }
+        }
+    }
+
+    fn check_affine_coordinate_size(&self, coordinate: &[u8]) -> Result<()> {
+        let expected_len = self.affine_coordinate_size()?;
+        if expected_len == coordinate.len() {
+            Ok(())
+        } else {
+            error!(
+                "The size of the affine coordinate '{}' does not match the expected size '{}'",
+                coordinate.len(),
+                expected_len
+            );
+            Err(Error::CoseKeyDecodingFailed)
+        }
+    }
+}
+
+impl<'a> AsRef<EC_GROUP> for EcGroup<'a> {
+    fn as_ref(&self) -> &EC_GROUP {
+        self.0
     }
 }
 
@@ -355,6 +416,16 @@
         NonNull::new(bn).map(Self).ok_or(to_call_failed_error(ApiName::BN_new))
     }
 
+    /// Converts the `BigNum` to a big-endian integer. The integer is padded with leading zeros up
+    /// to size `len`. The conversion fails if `len` is smaller than the size of the integer.
+    fn to_padded_vec(&self, len: usize) -> Result<Vec<u8>> {
+        let mut num = vec![0u8; len];
+        // SAFETY: The `BIGNUM` pointer has been created with `BN_new`.
+        let ret = unsafe { BN_bn2bin_padded(num.as_mut_ptr(), num.len(), self.0.as_ptr()) };
+        check_int_result(ret, ApiName::BN_bn2bin_padded)?;
+        Ok(num)
+    }
+
     fn as_mut_ptr(&mut self) -> *mut BIGNUM {
         self.0.as_ptr()
     }
@@ -367,19 +438,3 @@
         unsafe { self.0.as_ref() }
     }
 }
-
-/// Converts the `BigNum` to a big-endian integer. The integer is padded with leading zeros up to
-/// size `N`. The conversion fails if `N` is smaller thanthe size of the integer.
-impl<const N: usize> TryFrom<BigNum> for [u8; N] {
-    type Error = Error;
-
-    fn try_from(bn: BigNum) -> result::Result<Self, Self::Error> {
-        let mut num = [0u8; N];
-        // SAFETY: The `BIGNUM` pointer has been created with `BN_new`.
-        let ret = unsafe { BN_bn2bin_padded(num.as_mut_ptr(), num.len(), bn.0.as_ptr()) };
-        check_int_result(ret, ApiName::BN_bn2bin_padded)?;
-        Ok(num)
-    }
-}
-
-// TODO(b/301068421): Unit tests the EcKey.
diff --git a/libs/bssl/tests/eckey_test.rs b/libs/bssl/tests/eckey_test.rs
index 968af63..2eb908a 100644
--- a/libs/bssl/tests/eckey_test.rs
+++ b/libs/bssl/tests/eckey_test.rs
@@ -57,8 +57,18 @@
 }
 
 #[test]
-fn cose_public_key_serialization() -> Result<()> {
+fn p256_cose_public_key_serialization() -> Result<()> {
     let mut ec_key = EcKey::new_p256()?;
+    check_cose_public_key_serialization(&mut ec_key)
+}
+
+#[test]
+fn p384_cose_public_key_serialization() -> Result<()> {
+    let mut ec_key = EcKey::new_p384()?;
+    check_cose_public_key_serialization(&mut ec_key)
+}
+
+fn check_cose_public_key_serialization(ec_key: &mut EcKey) -> Result<()> {
     ec_key.generate_key()?;
     let cose_key = ec_key.cose_public_key()?;
     let cose_key_data = cose_key.clone().to_vec().unwrap();