blob: ba19dbf8e848c55de2ba7376a0dd26f3a3d73127 [file] [log] [blame]
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//! Implementation of the `IOpaqueKey` AIDL interface. It is used as a handle to key material
use android_hardware_security_see::aidl::android::hardware::security::see::hwcrypto::types::{
KeyLifetime::KeyLifetime, KeyPermissions::KeyPermissions, KeyType::KeyType, KeyUse::KeyUse,
};
use android_hardware_security_see::aidl::android::hardware::security::see::hwcrypto::{
IOpaqueKey::{BnOpaqueKey, IOpaqueKey},
KeyPolicy::KeyPolicy,
};
use android_hardware_security_see::binder;
use core::fmt;
use hwcryptohal_common::err::HwCryptoError;
use kmr_common::{
crypto::{KeyMaterial, Rng},
FallibleAllocExt,
};
use std::sync::OnceLock;
use crate::crypto_provider;
/// Number of bytes of unique value used to check if a key was created on current HWCrypto boot.
const UNIQUE_VALUE_SIZEOF: usize = 32;
/// Struct to wrap boot unique counter. It is used to tag objects to the current boot.
#[derive(Clone)]
struct BootUniqueValue([u8; UNIQUE_VALUE_SIZEOF]);
impl fmt::Debug for BootUniqueValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[BootUniqueValue size: {}; data redacted]", UNIQUE_VALUE_SIZEOF)
}
}
impl PartialEq for BootUniqueValue {
fn eq(&self, other: &Self) -> bool {
openssl::memcmp::eq(&self.0, &other.0)
}
}
impl Eq for BootUniqueValue {}
impl BootUniqueValue {
fn new() -> Result<BootUniqueValue, HwCryptoError> {
get_boot_unique_value()
}
}
// Boot unique value is lazily initialized on the first call to retrieve it
static BOOT_UNIQUE_VALUE: OnceLock<BootUniqueValue> = OnceLock::new();
/// Retrieves boot unique value used to check if the key material was created on this boot. It
/// lazily initializes it.
fn get_boot_unique_value() -> Result<BootUniqueValue, HwCryptoError> {
// The function returns a `Result` even if it is currently infallible to allow replacing its
// current implementation with one that can fail when trying to retrieve a random number.
// If the RNG changes to a fallible one we could use `get_or_try_init`.
let boot_unique_value = BOOT_UNIQUE_VALUE.get_or_init(|| {
let mut rng = crypto_provider::RngImpl::default();
let mut new_boot_unique_value = BootUniqueValue([0u8; UNIQUE_VALUE_SIZEOF]);
rng.fill_bytes(&mut new_boot_unique_value.0[..]);
new_boot_unique_value
});
Ok(boot_unique_value.clone())
}
/// Header for a `ClearKey` which contains the key policy along with some data needed to manipulate
/// the key.
#[derive(Debug)]
#[allow(dead_code)]
pub(crate) struct KeyHeader {
boot_unique_value: BootUniqueValue,
expiration_time: Option<u64>,
key_lifetime: KeyLifetime,
key_permissions: Vec<KeyPermissions>,
key_usage: KeyUse,
key_type: KeyType,
management_key: bool,
}
impl KeyHeader {
fn new(policy: &KeyPolicy) -> Result<Self, HwCryptoError> {
let mut key_permissions = Vec::new();
key_permissions.try_extend_from_slice(&policy.keyPermissions[..])?;
Ok(Self {
boot_unique_value: BootUniqueValue::new()?,
expiration_time: None,
key_lifetime: policy.keyLifetime,
key_permissions,
key_usage: policy.usage,
key_type: policy.keyType,
management_key: policy.keyManagementKey,
})
}
}
/// `IOpaqueKey` implementation.
#[allow(dead_code)]
pub struct OpaqueKey {
pub(crate) key_header: KeyHeader,
pub(crate) key_material: KeyMaterial,
}
impl OpaqueKey {
#[allow(dead_code)]
pub(crate) fn new_opaque_key(
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`
let opaque_key = OpaqueKey { key_header, key_material };
let opaque_keybinder =
BnOpaqueKey::new_binder(opaque_key, binder::BinderFeatures::default());
Ok(opaque_keybinder)
}
}
impl binder::Interface for OpaqueKey {}
impl IOpaqueKey for OpaqueKey {
fn exportWrappedKey(
&self,
_wrapping_key: &binder::Strong<dyn IOpaqueKey>,
) -> binder::Result<Vec<u8>> {
Err(binder::Status::new_exception_str(
binder::ExceptionCode::UNSUPPORTED_OPERATION,
Some("export_wrapped_key has not been implemented yet"),
))
}
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"),
))
}
fn getPublicKey(&self) -> binder::Result<Vec<u8>> {
Err(binder::Status::new_exception_str(
binder::ExceptionCode::UNSUPPORTED_OPERATION,
Some("get_public_key has not been implemented yet"),
))
}
}
#[cfg(test)]
mod tests {
use super::*;
use test::expect_eq;
#[test]
fn boot_unique_values_match() {
let boot_value = BootUniqueValue::new().expect("couldn't get boot unique value");
let boot_value2 = BootUniqueValue::new().expect("couldn't get boot unique value");
expect_eq!(boot_value, boot_value2, "boot unique values should match");
}
}