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