Implemented internal key handling
Implemented key retrieval based on opaque Key Handles containing
key material only retrievable on the server side.
Bug: 284156656
Test: build & run project rust unit tests
Change-Id: I5355315f7c8099ec530c0b470838e5767a68c41b
diff --git a/hwcryptohal/server/bindings.h b/hwcryptohal/server/bindings.h
new file mode 100644
index 0000000..2f91551
--- /dev/null
+++ b/hwcryptohal/server/bindings.h
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+// Definitions on this file will be processed during the Rust build to generate
+// a version of it that can be directly accessed from Rust code
+#include <lib/rng/trusty_rng.h>
diff --git a/hwcryptohal/server/crypto_provider.rs b/hwcryptohal/server/crypto_provider.rs
new file mode 100644
index 0000000..6ac6521
--- /dev/null
+++ b/hwcryptohal/server/crypto_provider.rs
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+//! Module providing access to the cryptographic implementations used by the library.
+
+pub(crate) use crate::platform_functions::PlatformRng as RngImpl;
diff --git a/hwcryptohal/server/ffi_bindings.rs b/hwcryptohal/server/ffi_bindings.rs
new file mode 100644
index 0000000..f792f85
--- /dev/null
+++ b/hwcryptohal/server/ffi_bindings.rs
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+//! FFI declarations.
+
+// Get the bindgen definitions
+#[allow(non_upper_case_globals)]
+#[allow(non_camel_case_types)]
+#[allow(unused)]
+#[allow(deref_nullptr)] // https://github.com/rust-lang/rust-bindgen/issues/1651
+pub(crate) mod sys {
+ include!(env!("BINDGEN_INC_FILE"));
+}
diff --git a/hwcryptohal/server/lib.rs b/hwcryptohal/server/lib.rs
index a07e837..8b47b3d 100644
--- a/hwcryptohal/server/lib.rs
+++ b/hwcryptohal/server/lib.rs
@@ -20,7 +20,11 @@
pub mod hwcrypto_ipc_server;
+mod crypto_provider;
+mod ffi_bindings;
mod hwcrypto_device_key;
+mod opaque_key;
+mod platform_functions;
#[cfg(test)]
mod tests {
diff --git a/hwcryptohal/server/opaque_key.rs b/hwcryptohal/server/opaque_key.rs
new file mode 100644
index 0000000..ba19dbf
--- /dev/null
+++ b/hwcryptohal/server/opaque_key.rs
@@ -0,0 +1,173 @@
+/*
+ * 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");
+ }
+}
diff --git a/hwcryptohal/server/platform_functions.rs b/hwcryptohal/server/platform_functions.rs
new file mode 100644
index 0000000..aa1ee49
--- /dev/null
+++ b/hwcryptohal/server/platform_functions.rs
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+//! Module providing access to platform specific functions used by the library.
+use kmr_common::crypto;
+
+use crate::ffi_bindings;
+
+// Placeholder for function to compare VM identities. Identities will probably be based on DICE,
+// a simple comparison could be done if the DICE chains are unencrypted and the order of fields is
+// always the same.
+#[allow(dead_code)]
+pub(crate) fn compare_vm_identities(vm1_identity: &[u8], vm2_identity: &[u8]) -> bool {
+ (vm1_identity.len() == vm2_identity.len()) && openssl::memcmp::eq(vm1_identity, vm2_identity)
+}
+
+#[derive(Default)]
+pub(crate) struct PlatformRng;
+
+impl crypto::Rng for PlatformRng {
+ fn add_entropy(&mut self, data: &[u8]) {
+ trusty_rng_add_entropy(data);
+ }
+ fn fill_bytes(&mut self, dest: &mut [u8]) {
+ openssl::rand::rand_bytes(dest)
+ .expect("shouldn't happen, function never fails on BoringSSL");
+ }
+}
+
+/// Add entropy to Trusty's RNG.
+pub fn trusty_rng_add_entropy(data: &[u8]) {
+ // Safety: `data` is a valid slice
+ let rc = unsafe { ffi_bindings::sys::trusty_rng_add_entropy(data.as_ptr(), data.len()) };
+ if rc != 0 {
+ panic!("trusty_rng_add_entropy() failed, {}", rc)
+ }
+}
diff --git a/hwcryptohal/server/rules.mk b/hwcryptohal/server/rules.mk
index 64f2d29..a2b8cb9 100644
--- a/hwcryptohal/server/rules.mk
+++ b/hwcryptohal/server/rules.mk
@@ -30,10 +30,19 @@
frameworks/native/libs/binder/trusty/rust/rpcbinder \
trusty/user/app/sample/hwcryptohal/aidl/rust \
trusty/user/app/sample/hwcryptohal/common \
+ trusty/user/base/lib/keymint-rust/boringssl \
+ trusty/user/base/lib/keymint-rust/common \
+ trusty/user/base/lib/openssl-rust \
trusty/user/base/lib/tipc/rust \
trusty/user/base/lib/trusty-sys \
$(call FIND_CRATE,log) \
trusty/user/base/lib/trusty-log \
+ trusty/user/base/lib/trusty-std \
+
+MODULE_BINDGEN_ALLOW_FUNCTIONS := \
+ trusty_rng_.* \
+
+MODULE_BINDGEN_SRC_HEADER := $(LOCAL_DIR)/bindings.h
MODULE_RUST_TESTS := true