diff options
author | Orlando Arbildo <oarbildo@google.com> | 2023-09-12 22:27:26 +0000 |
---|---|---|
committer | Orlando Arbildo <oarbildo@google.com> | 2024-04-08 16:57:09 +0000 |
commit | 34991a36f2aa778ad56da805bed6f86c453641f3 (patch) | |
tree | 5cf458b51bd55249c4c870e8bbb9a95bdf8e85bb | |
parent | f12b41faec5704d1e40b5521d8d13843b135ca7e (diff) | |
download | sample-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.rs | 2 | ||||
-rw-r--r-- | hwcryptohal/server/opaque_key.rs | 201 |
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"); + } } |