/* * 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 StorageKeyWrapper trait. use alloc::vec::Vec; use core::ffi::CStr; use kmr_common::{ crypto, crypto::{aes, Aes, KeyMaterial, OpaqueKeyMaterial, OpaqueOr}, get_bool_tag_value, get_opt_tag_value, get_tag_value, km_err, vec_try, vec_try_with_capacity, Error, }; use kmr_crypto_boring::aes::BoringAes; use kmr_ta::device::StorageKeyWrapper; use kmr_wire::{keymint, keymint::ErrorCode, KeySizeInBits}; use log::warn; use tipc::Handle; /// TIPC port used for communication with the `hwwsk` service. const HWWSK_PORT: &[u8] = b"com.android.trusty.hwwsk\0"; /// Create a session for `hwwsk` communication. fn hwwsk_session() -> Result { let port = CStr::from_bytes_with_nul(HWWSK_PORT).expect("HWWSK_PORT was not null terminated"); Handle::connect(port) .map_err(|e| km_err!(SecureHwCommunicationFailed, "failed to connect to hwwsk: {:?}", e)) } /// Storage key wrapper implementation for Trusty. pub struct TrustyStorageKeyWrapper; impl StorageKeyWrapper for TrustyStorageKeyWrapper { fn ephemeral_wrap(&self, key_material: &KeyMaterial) -> Result, Error> { let wrapped_key = match key_material { KeyMaterial::Aes(OpaqueOr::Opaque(key)) => key, _ => { return Err(km_err!( UnsupportedAlgorithm, "only opaque AES storage keys are supported" )) } }; let key = &wrapped_key.0; let session = hwwsk_session()?; let buf = &mut [0u8; hwwsk::HWWSK_MAX_MSG_SIZE as usize]; let wrapped_key_buffer = hwwsk::export_key(&session, buf, key).map_err(|e| { km_err!(SecureHwCommunicationFailed, "hwwsk failed to wrap key: {:?}", e) })?; let mut wrapped_key = vec_try_with_capacity!(wrapped_key_buffer.len())?; wrapped_key.extend_from_slice(wrapped_key_buffer); Ok(wrapped_key) } } /// Wrapper around `BoringAes` implementation that intercepts storage keys. pub struct TrustyAes(BoringAes); impl Default for TrustyAes { fn default() -> Self { Self(BoringAes) } } impl TrustyAes { fn create_storage_key( &self, key: Option, params: &[keymint::KeyParam], ) -> Result { // Storage keys should not work for normal operations. The TA code polices this by watching // for `Tag::StorageKey`; also police here by rejecting keys that have a `Tag::BlockMode` // attached. if get_opt_tag_value!(params, BlockMode)?.is_some() { return Err(km_err!(UnsupportedTag, "don't expect block mode on storage key")); } let key_size = get_tag_value!(params, KeySize, ErrorCode::UnsupportedTag)?; let key_size = key_size.0 as usize; let mut key_flags = hwwsk::KeyFlags::new(); let rollback_resistance = get_bool_tag_value!(params, RollbackResistance)?; if rollback_resistance { key_flags = key_flags.rollback_resistance(); }; let session = hwwsk_session()?; let mut buf = vec_try![0; hwwsk::HWWSK_MAX_MSG_SIZE as usize]?; let key_material: Option<&[u8]> = match key.as_ref() { None => None, Some(aes_key) => Some(match aes_key { aes::Key::Aes128(key) => key, aes::Key::Aes192(key) => key, aes::Key::Aes256(key) => key, }), }; let mut result = match key_material { None => hwwsk::generate_key(&session, &mut buf, key_size, key_flags), Some(key) => hwwsk::import_key(&session, &mut buf, key_size, key_flags, key), }; if result == Err(hwwsk::HwWskError::NotSupported) && rollback_resistance { warn!("failed to generate rollback-resistant storage key, retrying without resistance"); key_flags = hwwsk::KeyFlags::new(); result = match key_material { None => hwwsk::generate_key(&session, &mut buf, key_size, key_flags), Some(key) => hwwsk::import_key(&session, &mut buf, key_size, key_flags, key), }; } let wrapped_key_buffer = result.map_err(|e| km_err!(UnknownError, "hwwsk failed to create key: {:?}", e))?; let mut wrapped_key = vec_try_with_capacity!(wrapped_key_buffer.len())?; wrapped_key.extend_from_slice(wrapped_key_buffer); Ok(crypto::KeyMaterial::Aes(OpaqueOr::Opaque(OpaqueKeyMaterial(wrapped_key)))) } } impl Aes for TrustyAes { fn generate_key( &self, rng: &mut dyn crypto::Rng, variant: aes::Variant, params: &[keymint::KeyParam], ) -> Result { if !get_bool_tag_value!(params, StorageKey)? { // For normal (non-storage) keys, pass on to BoringSSL implementation. return self.0.generate_key(rng, variant, params); } self.create_storage_key(None, params) } fn import_key( &self, data: &[u8], params: &[keymint::KeyParam], ) -> Result<(crypto::KeyMaterial, KeySizeInBits), Error> { if !get_bool_tag_value!(params, StorageKey)? { // For normal (non-storage) keys, pass on to BoringSSL implementation. return self.0.import_key(data, params); } let aes_key = aes::Key::new_from(data)?; let key_size = aes_key.size(); Ok((self.create_storage_key(Some(aes_key), params)?, key_size)) } fn begin( &self, key: OpaqueOr, mode: aes::CipherMode, dir: crypto::SymmetricOperation, ) -> Result, Error> { match key { OpaqueOr::Explicit(_) => self.0.begin(key, mode, dir), OpaqueOr::Opaque(_) => { Err(km_err!(StorageKeyUnsupported, "attempt to use storage key")) } } } fn begin_aead( &self, key: OpaqueOr, mode: aes::GcmMode, dir: crypto::SymmetricOperation, ) -> Result, Error> { match key { OpaqueOr::Explicit(_) => self.0.begin_aead(key, mode, dir), OpaqueOr::Opaque(_) => { Err(km_err!(StorageKeyUnsupported, "attempt to use storage key")) } } } } // Not adding unit tests because we do not have a mock server on AOSP for hwwsk.