summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOrlando Arbildo <oarbildo@google.com>2023-09-12 22:27:26 +0000
committerOrlando Arbildo <oarbildo@google.com>2024-04-08 16:57:09 +0000
commit34991a36f2aa778ad56da805bed6f86c453641f3 (patch)
tree5cf458b51bd55249c4c870e8bbb9a95bdf8e85bb
parentf12b41faec5704d1e40b5521d8d13843b135ca7e (diff)
downloadsample-34991a36f2aa778ad56da805bed6f86c453641f3.tar.gz
Implemented key generation for AES and HMAC
First key generation implementation for AES and HMAC key material. Only basic policy checks have been implemented, will expand these in a future commit. Bug: 284177057 Test: build & run project rust unit tests Change-Id: Ia1a1dbc06fcc5104635602f39c04858999d084c1
-rw-r--r--hwcryptohal/server/crypto_provider.rs2
-rw-r--r--hwcryptohal/server/opaque_key.rs201
2 files changed, 193 insertions, 10 deletions
diff --git a/hwcryptohal/server/crypto_provider.rs b/hwcryptohal/server/crypto_provider.rs
index 6ac6521..3f6c593 100644
--- a/hwcryptohal/server/crypto_provider.rs
+++ b/hwcryptohal/server/crypto_provider.rs
@@ -17,3 +17,5 @@
//! Module providing access to the cryptographic implementations used by the library.
pub(crate) use crate::platform_functions::PlatformRng as RngImpl;
+pub(crate) use kmr_crypto_boring::aes::BoringAes as AesImpl;
+pub(crate) use kmr_crypto_boring::hmac::BoringHmac as HmacImpl;
diff --git a/hwcryptohal/server/opaque_key.rs b/hwcryptohal/server/opaque_key.rs
index ba19dbf..c5b2cba 100644
--- a/hwcryptohal/server/opaque_key.rs
+++ b/hwcryptohal/server/opaque_key.rs
@@ -25,11 +25,12 @@ use android_hardware_security_see::aidl::android::hardware::security::see::hwcry
};
use android_hardware_security_see::binder;
use core::fmt;
-use hwcryptohal_common::err::HwCryptoError;
+use hwcryptohal_common::{err::HwCryptoError, hwcrypto_err};
use kmr_common::{
- crypto::{KeyMaterial, Rng},
+ crypto::{self, Aes, CurveType, Hmac, KeyMaterial, OpaqueOr, Rng},
FallibleAllocExt,
};
+use kmr_wire::keymint::EcCurve;
use std::sync::OnceLock;
use crate::crypto_provider;
@@ -107,6 +108,18 @@ impl KeyHeader {
management_key: policy.keyManagementKey,
})
}
+
+ fn get_policy(&self) -> Result<KeyPolicy, HwCryptoError> {
+ let mut key_permissions = Vec::new();
+ key_permissions.try_extend_from_slice(&self.key_permissions[..])?;
+ Ok(KeyPolicy {
+ usage: self.key_usage,
+ keyLifetime: self.key_lifetime,
+ keyPermissions: key_permissions,
+ keyType: self.key_type,
+ keyManagementKey: self.management_key,
+ })
+ }
}
/// `IOpaqueKey` implementation.
@@ -117,18 +130,25 @@ pub struct OpaqueKey {
}
impl OpaqueKey {
- #[allow(dead_code)]
- pub(crate) fn new_opaque_key(
+ pub(crate) fn new_binder(
policy: &KeyPolicy,
key_material: KeyMaterial,
) -> binder::Result<binder::Strong<dyn IOpaqueKey>> {
let key_header = KeyHeader::new(policy)?;
- // TODO: Add checks that the provided `KeyPolicy` is compatible with the `KeyMaterial`
+ check_key_material_with_policy(&key_material, policy)?;
let opaque_key = OpaqueKey { key_header, key_material };
let opaque_keybinder =
BnOpaqueKey::new_binder(opaque_key, binder::BinderFeatures::default());
Ok(opaque_keybinder)
}
+
+ #[allow(unused)]
+ pub(crate) fn generate_opaque_key(
+ policy: &KeyPolicy,
+ ) -> binder::Result<binder::Strong<dyn IOpaqueKey>> {
+ let key_material = generate_key_material(&policy.keyType)?;
+ OpaqueKey::new_binder(policy, key_material)
+ }
}
impl binder::Interface for OpaqueKey {}
@@ -145,10 +165,7 @@ impl IOpaqueKey for OpaqueKey {
}
fn getKeyPolicy(&self) -> binder::Result<KeyPolicy> {
- Err(binder::Status::new_exception_str(
- binder::ExceptionCode::UNSUPPORTED_OPERATION,
- Some("get_key_policy has not been implemented yet"),
- ))
+ Ok(self.key_header.get_policy()?)
}
fn getPublicKey(&self) -> binder::Result<Vec<u8>> {
@@ -159,10 +176,156 @@ impl IOpaqueKey for OpaqueKey {
}
}
+pub(crate) fn check_key_material_with_policy(
+ key_material: &KeyMaterial,
+ policy: &KeyPolicy,
+) -> Result<(), HwCryptoError> {
+ let key_type = &policy.keyType;
+ // `KeyMaterial` doesn't fully describe the cryptographic algorithm as `KeyType` does, so we can
+ // only check if both of them are compatible, not provide a 1:1 mapping
+ match key_material {
+ KeyMaterial::Aes(aes_key) => match aes_key {
+ OpaqueOr::Opaque(_) => Err(hwcrypto_err!(BAD_PARAMETER, "opaque aes key provided")),
+ OpaqueOr::Explicit(aes_key) => match aes_key {
+ crypto::aes::Key::Aes128(km) => match *key_type {
+ KeyType::AES_128_CBC_NO_PADDING
+ | KeyType::AES_128_CBC_PKCS7_PADDING
+ | KeyType::AES_128_CTR
+ | KeyType::AES_128_GCM
+ | KeyType::AES_128_CMAC => Ok(()),
+ _ => Err(hwcrypto_err!(
+ BAD_PARAMETER,
+ "type mismatch: key material {:?} key type: {:?}",
+ km,
+ key_type
+ )),
+ },
+ crypto::aes::Key::Aes192(_) => {
+ Err(hwcrypto_err!(BAD_PARAMETER, "AES keys of length 192 are not supported"))
+ }
+ crypto::aes::Key::Aes256(km) => match *key_type {
+ KeyType::AES_256_CBC_NO_PADDING
+ | KeyType::AES_256_CBC_PKCS7_PADDING
+ | KeyType::AES_256_CTR
+ | KeyType::AES_256_GCM
+ | KeyType::AES_256_CMAC => Ok(()),
+ _ => Err(hwcrypto_err!(
+ BAD_PARAMETER,
+ "type mismatch: key material {:?} key type: {:?}",
+ km,
+ key_type
+ )),
+ },
+ },
+ },
+ KeyMaterial::TripleDes(_) => {
+ Err(hwcrypto_err!(BAD_PARAMETER, "TDES is not currently supported"))
+ }
+ KeyMaterial::Hmac(hmac_key) => match hmac_key {
+ OpaqueOr::Opaque(_) => Err(hwcrypto_err!(BAD_PARAMETER, "opaque HMAC key provided")),
+ OpaqueOr::Explicit(_) => match *key_type {
+ KeyType::HMAC_SHA256 => Ok(()),
+ KeyType::HMAC_SHA512 => Ok(()),
+ _ => Err(hwcrypto_err!(
+ BAD_PARAMETER,
+ "type mismatch for HMAC key key type: {:?}",
+ key_type
+ )),
+ },
+ },
+ KeyMaterial::Rsa(rsa_key) => match rsa_key {
+ OpaqueOr::Opaque(_) => Err(hwcrypto_err!(BAD_PARAMETER, "opaque RSA key provided")),
+ OpaqueOr::Explicit(rsa_key) => {
+ let key_size = rsa_key.size();
+ match (key_size, *key_type) {
+ (2048, KeyType::RSA2048_PSS_SHA256) => Ok(()),
+ (2048, KeyType::RSA2048_PKCS1_5_SHA256) => Ok(()),
+ _ => Err(hwcrypto_err!(
+ BAD_PARAMETER,
+ "type mismatch for RSA key length {} and type: {:?}",
+ key_size,
+ key_type
+ )),
+ }
+ }
+ },
+ KeyMaterial::Ec(curve, curve_type, _) => match (curve, *key_type) {
+ (EcCurve::P256, KeyType::ECC_NIST_P256_SIGN_NO_PADDING) => Ok(()),
+ (EcCurve::P256, KeyType::ECC_NIST_P256_SIGN_SHA256) => Ok(()),
+ (EcCurve::P521, KeyType::ECC_NIST_P521_SIGN_NO_PADDING) => Ok(()),
+ (EcCurve::P521, KeyType::ECC_NIST_P521_SIGN_SHA512) => Ok(()),
+ (EcCurve::Curve25519, _) => match (curve_type, *key_type) {
+ (CurveType::EdDsa, KeyType::ECC_ED25519_SIGN) => Ok(()),
+ _ => Err(hwcrypto_err!(
+ BAD_PARAMETER,
+ "type mismatch for Ec Key curve {:?} and type: {:?}",
+ curve,
+ key_type
+ )),
+ },
+ _ => Err(hwcrypto_err!(
+ BAD_PARAMETER,
+ "type mismatch for Ec Key curve {:?} and type: {:?}",
+ curve,
+ key_type
+ )),
+ },
+ }
+}
+
+// Translating a policy AES `KeyType` into the type understood by the cryptographic backend we are
+// currently used
+// TODO: change this into a `TryFrom` once we refactor `KeyType` to be a newtype.
+fn get_aes_variant(key_type: &KeyType) -> Result<crypto::aes::Variant, HwCryptoError> {
+ match *key_type {
+ KeyType::AES_128_CBC_NO_PADDING
+ | KeyType::AES_128_CBC_PKCS7_PADDING
+ | KeyType::AES_128_CTR
+ | KeyType::AES_128_GCM
+ | KeyType::AES_128_CMAC => Ok(crypto::aes::Variant::Aes128),
+ KeyType::AES_256_CBC_NO_PADDING
+ | KeyType::AES_256_CBC_PKCS7_PADDING
+ | KeyType::AES_256_CTR
+ | KeyType::AES_256_GCM
+ | KeyType::AES_256_CMAC => Ok(crypto::aes::Variant::Aes256),
+ _ => Err(hwcrypto_err!(BAD_PARAMETER, "not an AES key type: {:?}", key_type)),
+ }
+}
+
+// Use the cryptographic backend to create key material based on the policy `KeyType`. Because HMAC
+// keys can have arbitrary sizes, include an optional `key_size_bits` for that case.
+fn generate_key_material(key_type: &KeyType) -> Result<KeyMaterial, HwCryptoError> {
+ let aes = crypto_provider::AesImpl;
+ let hmac = crypto_provider::HmacImpl;
+ let mut rng = crypto_provider::RngImpl::default();
+ match *key_type {
+ KeyType::AES_128_CBC_NO_PADDING
+ | KeyType::AES_128_CBC_PKCS7_PADDING
+ | KeyType::AES_128_CTR
+ | KeyType::AES_128_GCM
+ | KeyType::AES_128_CMAC
+ | KeyType::AES_256_CBC_NO_PADDING
+ | KeyType::AES_256_CBC_PKCS7_PADDING
+ | KeyType::AES_256_CTR
+ | KeyType::AES_256_GCM
+ | KeyType::AES_256_CMAC => {
+ let variant = get_aes_variant(key_type)?;
+ Ok(aes.generate_key(&mut rng, variant, &[])?)
+ }
+ KeyType::HMAC_SHA256 => {
+ Ok(hmac.generate_key(&mut rng, kmr_wire::KeySizeInBits(256), &[])?)
+ }
+ KeyType::HMAC_SHA512 => {
+ Ok(hmac.generate_key(&mut rng, kmr_wire::KeySizeInBits(512), &[])?)
+ }
+ _ => unimplemented!("key material other than AES and HMAC not implemented yet"),
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
- use test::expect_eq;
+ use test::{expect, expect_eq};
#[test]
fn boot_unique_values_match() {
@@ -170,4 +333,22 @@ mod tests {
let boot_value2 = BootUniqueValue::new().expect("couldn't get boot unique value");
expect_eq!(boot_value, boot_value2, "boot unique values should match");
}
+
+ #[test]
+ fn generate_key_material_test() {
+ let usage = KeyUse::ENCRYPT;
+ let key_type = KeyType::AES_256_GCM;
+ let policy = KeyPolicy {
+ usage,
+ keyLifetime: KeyLifetime::EPHEMERAL,
+ keyPermissions: Vec::new(),
+ keyType: key_type,
+ keyManagementKey: false,
+ };
+ let key_material = generate_key_material(&policy.keyType);
+ expect!(key_material.is_ok(), "couldn't retrieve key material");
+ let key_material = key_material.unwrap();
+ let check_result = check_key_material_with_policy(&key_material, &policy);
+ expect!(check_result.is_ok(), "wrong key type");
+ }
}