/* * 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 crate::secure_storage_manager; use hwbcc::{get_bcc, sign_data, HwBccMode, SigningAlgorithm, HWBCC_MAX_RESP_PAYLOAD_LENGTH}; use hwkey::{Hwkey, KdfVersion}; use kmr_common::{crypto, rpc_err, vec_try, Error}; use kmr_ta::device::{ CsrSigningAlgorithm, DiceInfo, PubDiceArtifacts, RetrieveRpcArtifacts, RpcV2Req, }; use kmr_ta::rkp::serialize_cbor; use kmr_wire::{cbor::value::Value, rpc}; // This matches the value of kMasterKeyDerivationData in // trusty/user/app/keymaster/trusty_remote_provisioning_context.cpp const HBK_KEY_DERIVATION_DATA: &[u8] = b"RemoteKeyProvisioningMasterKey"; // SignerName is a string identifier that indicates both the signing authority // as well as the format of the UdsCertChain const SIGNER_NAME: &str = "GSMIRkpSecp384r1"; pub struct TrustyRpc; impl RetrieveRpcArtifacts for TrustyRpc { fn derive_bytes_from_hbk( &self, hkdf: &dyn crypto::Hkdf, context: &[u8], output_len: usize, ) -> Result, 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 { 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 if not exist let uds_certs_data = match secure_storage_manager::read_uds_cert() { Ok(uds_certs) => { let encoded_certs = uds_certs .into_iter() .map(|cert| Value::Bytes(cert.encoded_certificate)) .collect::>(); serialize_cbor(&Value::Map(vec![( Value::Text(SIGNER_NAME.to_string()), Value::Array(encoded_certs), )])) } Err(err) => { log::warn!("Failed to read UDS certificates: {:?}", err); 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( &self, _ec: &dyn crypto::Ec, _data: &[u8], _rpc_v2: Option, ) -> Result, 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( &self, _ec: &dyn crypto::Ec, signing_algorithm: &CsrSigningAlgorithm, payload: &[u8], aad: &[u8], _rpc_v2: Option, ) -> Result, 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()) } }