Merge "Fixing SetBootParams unittests"
diff --git a/lib.rs b/lib.rs
index 2787e5e..0521dbb 100644
--- a/lib.rs
+++ b/lib.rs
@@ -24,6 +24,7 @@
 mod keymaster_attributes;
 mod keys;
 mod monotonic_clock;
+mod rpc;
 mod secure_deletion_secret_manager;
 mod secure_storage_manager;
 
@@ -32,6 +33,7 @@
 pub use keys::legacy::TrustyLegacyKeyBlobHandler;
 pub use keys::TrustyKeys;
 pub use monotonic_clock::TrustyMonotonicCLock;
+pub use rpc::TrustyRpc;
 pub use secure_deletion_secret_manager::{SharedSddManager, TrustySecureDeletionSecretManager};
 pub use secure_storage_manager::{AttestationIds, CertSignInfo};
 
diff --git a/main.rs b/main.rs
index e9add99..e833072 100644
--- a/main.rs
+++ b/main.rs
@@ -15,7 +15,7 @@
  */
 use keymint::{
     AttestationIds, CertSignInfo, SharedSddManager, TrustyAes, TrustyKeys, TrustyMonotonicCLock,
-    TrustySecureDeletionSecretManager, TrustyStorageKeyWrapper,
+    TrustyRpc, TrustySecureDeletionSecretManager, TrustyStorageKeyWrapper,
 };
 use kmr_common::crypto;
 use kmr_crypto_boring::{
@@ -73,6 +73,7 @@
         sdd_mgr: Some(&mut legacy_sdd_mgr),
         keys: &trusty_keys,
     };
+    let trusty_rpc = TrustyRpc;
     let dev = kmr_ta::device::Implementation {
         keys: &trusty_keys,
         sign_info: &sign_info,
@@ -82,8 +83,7 @@
         sk_wrapper: Some(&key_wrapper),
         tup: &kmr_ta::device::TrustedPresenceUnsupported,
         legacy_key: Some(&mut legacy_key),
-        // TODO (b/253926846) add HWBCC backed implementation
-        rpc: &kmr_ta::device::NoOpRetrieveRpcArtifacts,
+        rpc: &trusty_rpc,
     };
     keymint::handle_port_connections(hw_info, RpcInfo::V3(rpc_info_v3), imp, dev)
         .expect("handle_port_connections returned an error");
diff --git a/rpc.rs b/rpc.rs
new file mode 100644
index 0000000..1f853ba
--- /dev/null
+++ b/rpc.rs
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+//! Trusty implementation of `RetrieveRpcArtifacts`. Currently, this supports
+//! only IRPC V3.
+
+use hwbcc::{get_bcc, sign_data, HwBccMode, SigningAlgorithm, HWBCC_MAX_RESP_PAYLOAD_LENGTH};
+use hwkey::{Hwkey, KdfVersion};
+use kmr_common::{crypto, log_unimpl, rpc_err, unimpl, vec_try, Error};
+use kmr_ta::device::{
+    CsrSigningAlgorithm, DiceInfo, PubDiceArtifacts, RetrieveRpcArtifacts, RpcV2Req,
+};
+use kmr_ta::rkp::serialize_cbor;
+use kmr_wire::{cbor::value::Value, coset::AsCborValue, rpc, CborError};
+use log::error;
+
+// This matches the value of kMasterKeyDerivationData in
+// trusty/user/app/keymaster/trusty_remote_provisioning_context.cpp
+const HBK_KEY_DERIVATION_DATA: &'static [u8] = b"RemoteKeyProvisioningMasterKey";
+
+pub struct TrustyRpc;
+
+impl RetrieveRpcArtifacts for TrustyRpc {
+    fn derive_bytes_from_hbk(
+        &self,
+        hkdf: &dyn crypto::Hkdf,
+        context: &[u8],
+        output_len: usize,
+    ) -> Result<Vec<u8>, Error> {
+        let hwkey_session =
+            Hwkey::open().map_err(|e| rpc_err!(Failed, "failed to connect to Hwkey: {:?}", e))?;
+        let mut key_buf = vec_try![0u8; output_len]?;
+        hwkey_session
+            .derive_key_req()
+            .unique_key()
+            .kdf(KdfVersion::Version(1))
+            .derive(HBK_KEY_DERIVATION_DATA, key_buf.as_mut_slice())
+            .map_err(|e| rpc_err!(Failed, "failed to derive hardware backed key: {:?}", e))?;
+        hkdf.hkdf(&[], &key_buf, context, output_len)
+    }
+
+    fn get_dice_info<'a>(&self, _test_mode: rpc::TestMode) -> Result<DiceInfo, Error> {
+        let mut bcc_buf = [0u8; HWBCC_MAX_RESP_PAYLOAD_LENGTH];
+        // Note: Test mode is ignored as this currently supports only IRPC V3.
+        let bcc = get_bcc(HwBccMode::Release, &mut bcc_buf)
+            .map_err(|e| rpc_err!(Failed, "failed to get DICE Info: {:?}", e))?;
+        // Construct `UdsCerts` as an empty CBOR map
+        let uds_certs_data = serialize_cbor(&Value::Map(Vec::new()))?;
+        let pub_dice_artifacts =
+            PubDiceArtifacts { uds_certs: uds_certs_data, dice_cert_chain: bcc.to_vec() };
+        let dice_info = DiceInfo {
+            pub_dice_artifacts,
+            signing_algorithm: CsrSigningAlgorithm::EdDSA,
+            rpc_v2_test_cdi_priv: None,
+        };
+        Ok(dice_info)
+    }
+
+    fn sign_data<'a>(
+        &self,
+        _ec: &dyn crypto::Ec,
+        _data: &[u8],
+        _rpc_v2: Option<RpcV2Req<'a>>,
+    ) -> Result<Vec<u8>, Error> {
+        // This is marked unimplemented because we override `sign_data_in_cose_sign1` below.
+        Err(rpc_err!(Failed, "unimplemented"))
+    }
+
+    fn sign_data_in_cose_sign1<'a>(
+        &self,
+        _ec: &dyn crypto::Ec,
+        signing_algorithm: &CsrSigningAlgorithm,
+        payload: &[u8],
+        aad: &[u8],
+        _rpc_v2: Option<RpcV2Req<'a>>,
+    ) -> Result<Vec<u8>, Error> {
+        match signing_algorithm {
+            CsrSigningAlgorithm::EdDSA => {}
+            _ => {
+                return Err(rpc_err!(
+                    Failed,
+                    "Requested signing algorithm: {:?}, but only ED25519 is supported.",
+                    signing_algorithm
+                ));
+            }
+        }
+
+        let mut cose_sign1_buf = [0u8; HWBCC_MAX_RESP_PAYLOAD_LENGTH];
+        // Note: Test mode is ignored as this currently supports only IRPC V3.
+        let cose_sign1 = sign_data(
+            HwBccMode::Release,
+            SigningAlgorithm::ED25519,
+            payload,
+            aad,
+            &mut cose_sign1_buf,
+        )
+        .map_err(|e| rpc_err!(Failed, "failed to get signed data: {:?}", e))?;
+        Ok(cose_sign1.to_vec())
+    }
+}
diff --git a/rules.mk b/rules.mk
index 276e192..e922a94 100644
--- a/rules.mk
+++ b/rules.mk
@@ -25,6 +25,7 @@
 MODULE_CRATE_NAME := keymint
 
 MODULE_LIBRARY_DEPS += \
+	trusty/user/base/lib/hwbcc/rust \
 	trusty/user/base/lib/hwkey/rust \
 	trusty/user/base/lib/hwwsk/rust \
 	trusty/user/base/lib/keymint-rust/boringssl \