Orlando Arbildo | e682781 | 2022-11-02 17:21:17 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2022 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | //! Trusty implementation of StorageKeyWrapper trait. |
| 17 | use alloc::vec::Vec; |
| 18 | use hwwsk; |
| 19 | use kmr_common::{ |
David Drysdale | 7166ff6 | 2022-12-16 12:27:23 +0000 | [diff] [blame] | 20 | crypto, |
| 21 | crypto::{aes, Aes, KeyMaterial, OpaqueKeyMaterial, OpaqueOr}, |
| 22 | get_bool_tag_value, get_opt_tag_value, get_tag_value, km_err, vec_try, vec_try_with_capacity, |
| 23 | Error, |
Orlando Arbildo | e682781 | 2022-11-02 17:21:17 +0000 | [diff] [blame] | 24 | }; |
David Drysdale | 7166ff6 | 2022-12-16 12:27:23 +0000 | [diff] [blame] | 25 | use kmr_crypto_boring::aes::BoringAes; |
Orlando Arbildo | e682781 | 2022-11-02 17:21:17 +0000 | [diff] [blame] | 26 | use kmr_ta::device::StorageKeyWrapper; |
David Drysdale | 7166ff6 | 2022-12-16 12:27:23 +0000 | [diff] [blame] | 27 | use kmr_wire::{keymint, keymint::ErrorCode, KeySizeInBits}; |
| 28 | use log::warn; |
Orlando Arbildo | e682781 | 2022-11-02 17:21:17 +0000 | [diff] [blame] | 29 | use tipc::Handle; |
| 30 | use trusty_std::ffi::CStr; |
| 31 | |
David Drysdale | 6470210 | 2022-12-14 12:23:16 +0000 | [diff] [blame^] | 32 | /// TIPC port used for communication with the `hwwsk` service. |
Orlando Arbildo | e682781 | 2022-11-02 17:21:17 +0000 | [diff] [blame] | 33 | const HWWSK_PORT: &'static [u8] = b"com.android.trusty.hwwsk\0"; |
| 34 | |
David Drysdale | 7166ff6 | 2022-12-16 12:27:23 +0000 | [diff] [blame] | 35 | /// Create a session for `hwwsk` communication. |
| 36 | fn hwwsk_session() -> Result<Handle, Error> { |
| 37 | let port = CStr::from_bytes_with_nul(HWWSK_PORT).expect("HWWSK_PORT was not null terminated"); |
| 38 | Handle::connect(port) |
| 39 | .map_err(|e| km_err!(SecureHwCommunicationFailed, "failed to connect to hwwsk: {:?}", e)) |
| 40 | } |
| 41 | |
| 42 | /// Storage key wrapper implementation for Trusty. |
Orlando Arbildo | e682781 | 2022-11-02 17:21:17 +0000 | [diff] [blame] | 43 | pub struct TrustyStorageKeyWrapper; |
| 44 | |
| 45 | impl StorageKeyWrapper for TrustyStorageKeyWrapper { |
| 46 | fn ephemeral_wrap(&self, key_material: &KeyMaterial) -> Result<Vec<u8>, Error> { |
David Drysdale | 7166ff6 | 2022-12-16 12:27:23 +0000 | [diff] [blame] | 47 | let wrapped_key = match key_material { |
| 48 | KeyMaterial::Aes(OpaqueOr::Opaque(key)) => key, |
| 49 | _ => { |
| 50 | return Err(km_err!( |
| 51 | UnsupportedAlgorithm, |
| 52 | "only opaque AES storage keys are supported" |
| 53 | )) |
| 54 | } |
Orlando Arbildo | e682781 | 2022-11-02 17:21:17 +0000 | [diff] [blame] | 55 | }; |
David Drysdale | 7166ff6 | 2022-12-16 12:27:23 +0000 | [diff] [blame] | 56 | let key = &wrapped_key.0; |
| 57 | let session = hwwsk_session()?; |
Orlando Arbildo | e682781 | 2022-11-02 17:21:17 +0000 | [diff] [blame] | 58 | let buf = &mut [0u8; hwwsk::HWWSK_MAX_MSG_SIZE as usize]; |
David Drysdale | 7166ff6 | 2022-12-16 12:27:23 +0000 | [diff] [blame] | 59 | let wrapped_key_buffer = hwwsk::export_key(&session, buf, key).map_err(|e| { |
| 60 | km_err!(SecureHwCommunicationFailed, "hwwsk failed to wrap key: {:?}", e) |
| 61 | })?; |
Orlando Arbildo | e682781 | 2022-11-02 17:21:17 +0000 | [diff] [blame] | 62 | let mut wrapped_key = vec_try_with_capacity!(wrapped_key_buffer.len())?; |
| 63 | wrapped_key.extend_from_slice(wrapped_key_buffer); |
| 64 | Ok(wrapped_key) |
| 65 | } |
| 66 | } |
| 67 | |
David Drysdale | 7166ff6 | 2022-12-16 12:27:23 +0000 | [diff] [blame] | 68 | /// Wrapper around `BoringAes` implementation that intercepts storage keys. |
| 69 | pub struct TrustyAes(BoringAes); |
| 70 | |
| 71 | impl Default for TrustyAes { |
| 72 | fn default() -> Self { |
| 73 | Self(BoringAes) |
| 74 | } |
| 75 | } |
| 76 | impl TrustyAes { |
| 77 | fn create_storage_key( |
| 78 | &self, |
| 79 | key: Option<aes::Key>, |
| 80 | params: &[keymint::KeyParam], |
| 81 | ) -> Result<crypto::KeyMaterial, Error> { |
| 82 | // Storage keys should not work for normal operations. The TA code polices this by watching |
| 83 | // for `Tag::StorageKey`; also police here by rejecting keys that have a `Tag::BlockMode` |
| 84 | // attached. |
| 85 | if get_opt_tag_value!(params, BlockMode)?.is_some() { |
| 86 | return Err(km_err!(UnsupportedTag, "don't expect block mode on storage key")); |
| 87 | } |
| 88 | let key_size = get_tag_value!(params, KeySize, ErrorCode::UnsupportedTag)?; |
| 89 | let key_size = key_size.0 as usize; |
| 90 | let mut key_flags = hwwsk::KeyFlags::new(); |
| 91 | let rollback_resistance = get_bool_tag_value!(params, RollbackResistance)?; |
| 92 | if rollback_resistance { |
| 93 | key_flags = key_flags.rollback_resistance(); |
| 94 | }; |
| 95 | |
| 96 | let session = hwwsk_session()?; |
| 97 | let mut buf = vec_try![0; hwwsk::HWWSK_MAX_MSG_SIZE as usize]?; |
| 98 | let key_material: Option<&[u8]> = match key.as_ref() { |
| 99 | None => None, |
| 100 | Some(aes_key) => Some(match aes_key { |
| 101 | aes::Key::Aes128(key) => key, |
| 102 | aes::Key::Aes192(key) => key, |
| 103 | aes::Key::Aes256(key) => key, |
| 104 | }), |
| 105 | }; |
| 106 | let mut result = match key_material { |
| 107 | None => hwwsk::generate_key(&session, &mut buf, key_size, key_flags), |
| 108 | Some(key) => hwwsk::import_key(&session, &mut buf, key_size, key_flags, key), |
| 109 | }; |
| 110 | if result == Err(hwwsk::HwWskError::NotSupported) && rollback_resistance { |
| 111 | warn!("failed to generate rollback-resistant storage key, retrying without resistance"); |
| 112 | key_flags = hwwsk::KeyFlags::new(); |
| 113 | result = match key_material { |
| 114 | None => hwwsk::generate_key(&session, &mut buf, key_size, key_flags), |
| 115 | Some(key) => hwwsk::import_key(&session, &mut buf, key_size, key_flags, key), |
| 116 | }; |
| 117 | } |
| 118 | |
| 119 | let wrapped_key_buffer = |
| 120 | result.map_err(|e| km_err!(UnknownError, "hwwsk failed to create key: {:?}", e))?; |
| 121 | |
| 122 | let mut wrapped_key = vec_try_with_capacity!(wrapped_key_buffer.len())?; |
| 123 | wrapped_key.extend_from_slice(wrapped_key_buffer); |
| 124 | Ok(crypto::KeyMaterial::Aes(OpaqueOr::Opaque(OpaqueKeyMaterial(wrapped_key)))) |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | impl Aes for TrustyAes { |
| 129 | fn generate_key( |
| 130 | &self, |
| 131 | rng: &mut dyn crypto::Rng, |
| 132 | variant: aes::Variant, |
| 133 | params: &[keymint::KeyParam], |
| 134 | ) -> Result<crypto::KeyMaterial, Error> { |
| 135 | if !get_bool_tag_value!(params, StorageKey)? { |
| 136 | // For normal (non-storage) keys, pass on to BoringSSL implementation. |
| 137 | return self.0.generate_key(rng, variant, params); |
| 138 | } |
| 139 | self.create_storage_key(None, params) |
| 140 | } |
| 141 | |
| 142 | fn import_key( |
| 143 | &self, |
| 144 | data: &[u8], |
| 145 | params: &[keymint::KeyParam], |
| 146 | ) -> Result<(crypto::KeyMaterial, KeySizeInBits), Error> { |
| 147 | if !get_bool_tag_value!(params, StorageKey)? { |
| 148 | // For normal (non-storage) keys, pass on to BoringSSL implementation. |
| 149 | return self.0.import_key(data, params); |
| 150 | } |
| 151 | |
| 152 | let aes_key = aes::Key::new_from(data)?; |
| 153 | let key_size = aes_key.size(); |
| 154 | Ok((self.create_storage_key(Some(aes_key), params)?, key_size)) |
| 155 | } |
| 156 | |
| 157 | fn begin( |
| 158 | &self, |
| 159 | key: OpaqueOr<aes::Key>, |
| 160 | mode: aes::CipherMode, |
| 161 | dir: crypto::SymmetricOperation, |
| 162 | ) -> Result<Box<dyn crypto::EmittingOperation>, Error> { |
| 163 | match key { |
| 164 | OpaqueOr::Explicit(_) => self.0.begin(key, mode, dir), |
| 165 | OpaqueOr::Opaque(_) => { |
| 166 | Err(km_err!(StorageKeyUnsupported, "attempt to use storage key")) |
| 167 | } |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | fn begin_aead( |
| 172 | &self, |
| 173 | key: OpaqueOr<aes::Key>, |
| 174 | mode: aes::GcmMode, |
| 175 | dir: crypto::SymmetricOperation, |
| 176 | ) -> Result<Box<dyn crypto::AadOperation>, Error> { |
| 177 | match key { |
| 178 | OpaqueOr::Explicit(_) => self.0.begin_aead(key, mode, dir), |
| 179 | OpaqueOr::Opaque(_) => { |
| 180 | Err(km_err!(StorageKeyUnsupported, "attempt to use storage key")) |
| 181 | } |
| 182 | } |
| 183 | } |
| 184 | } |
| 185 | |
Orlando Arbildo | e682781 | 2022-11-02 17:21:17 +0000 | [diff] [blame] | 186 | // Not adding unit tests because we do not have a mock server on AOSP for hwwsk. |