David Drysdale | c97eb9e | 2022-01-26 13:03:48 -0800 | [diff] [blame] | 1 | // Copyright 2020, The Android Open Source Project |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | //! Provide a wrapper around a KeyMint device that allows up-level features to |
| 16 | //! be emulated on back-level devices. |
| 17 | |
Shaquille Johnson | 9da2e1c | 2022-09-19 12:39:01 +0000 | [diff] [blame] | 18 | use crate::ks_err; |
David Drysdale | c97eb9e | 2022-01-26 13:03:48 -0800 | [diff] [blame] | 19 | use crate::error::{map_binder_status, map_binder_status_code, map_or_log_err, Error, ErrorCode}; |
| 20 | use android_hardware_security_keymint::binder::{BinderFeatures, StatusCode, Strong}; |
| 21 | use android_hardware_security_secureclock::aidl::android::hardware::security::secureclock::TimeStampToken::TimeStampToken; |
| 22 | use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{ |
| 23 | AttestationKey::AttestationKey, BeginResult::BeginResult, EcCurve::EcCurve, |
| 24 | HardwareAuthToken::HardwareAuthToken, IKeyMintDevice::BnKeyMintDevice, |
| 25 | IKeyMintDevice::IKeyMintDevice, KeyCharacteristics::KeyCharacteristics, |
| 26 | KeyCreationResult::KeyCreationResult, KeyFormat::KeyFormat, |
| 27 | KeyMintHardwareInfo::KeyMintHardwareInfo, KeyParameter::KeyParameter, |
| 28 | KeyParameterValue::KeyParameterValue, KeyPurpose::KeyPurpose, SecurityLevel::SecurityLevel, |
| 29 | Tag::Tag, |
| 30 | }; |
| 31 | use android_security_compat::aidl::android::security::compat::IKeystoreCompatService::IKeystoreCompatService; |
| 32 | use anyhow::Context; |
| 33 | use keystore2_crypto::{hmac_sha256, HMAC_SHA256_LEN}; |
| 34 | |
David Drysdale | 5accbaa | 2023-04-12 18:47:10 +0100 | [diff] [blame] | 35 | /// Magic prefix used by the km_compat C++ code to mark a key that is owned by an |
| 36 | /// underlying Keymaster hardware device that has been wrapped by km_compat. (The |
| 37 | /// final zero byte indicates that the blob is not software emulated.) |
| 38 | pub const KEYMASTER_BLOB_HW_PREFIX: &[u8] = b"pKMblob\x00"; |
| 39 | |
David Drysdale | 746e1be | 2023-07-05 17:39:57 +0100 | [diff] [blame] | 40 | /// Magic prefix used by the km_compat C++ code to mark a key that is owned by an |
| 41 | /// software emulation device that has been wrapped by km_compat. (The final one |
| 42 | /// byte indicates that the blob is software emulated.) |
| 43 | pub const KEYMASTER_BLOB_SW_PREFIX: &[u8] = b"pKMblob\x01"; |
| 44 | |
David Drysdale | c97eb9e | 2022-01-26 13:03:48 -0800 | [diff] [blame] | 45 | /// Key data associated with key generation/import. |
| 46 | #[derive(Debug, PartialEq, Eq)] |
| 47 | pub enum KeyImportData<'a> { |
| 48 | None, |
| 49 | Pkcs8(&'a [u8]), |
| 50 | Raw(&'a [u8]), |
| 51 | } |
| 52 | |
| 53 | impl<'a> KeyImportData<'a> { |
| 54 | /// Translate import parameters into a `KeyImportData` instance. |
| 55 | fn new(key_format: KeyFormat, key_data: &'a [u8]) -> binder::Result<Self> { |
| 56 | match key_format { |
| 57 | KeyFormat::PKCS8 => Ok(KeyImportData::Pkcs8(key_data)), |
| 58 | KeyFormat::RAW => Ok(KeyImportData::Raw(key_data)), |
| 59 | _ => Err(binder::Status::new_service_specific_error( |
| 60 | ErrorCode::UNSUPPORTED_KEY_FORMAT.0, |
| 61 | None, |
| 62 | )), |
| 63 | } |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | /// A key blob that may be software-emulated or may be directly produced by an |
| 68 | /// underlying device. In either variant the inner data is the keyblob itself, |
| 69 | /// as seen by the relevant device. |
| 70 | #[derive(Debug, PartialEq, Eq)] |
| 71 | pub enum KeyBlob<'a> { |
| 72 | Raw(&'a [u8]), |
| 73 | Wrapped(&'a [u8]), |
| 74 | } |
| 75 | |
| 76 | /// Trait for detecting that software emulation of a current-version KeyMint |
| 77 | /// feature is required for a back-level KeyMint implementation. |
| 78 | pub trait EmulationDetector: Send + Sync { |
| 79 | /// Indicate whether software emulation is required for key |
| 80 | /// generation/import using the provided parameters. |
| 81 | fn emulation_required(&self, params: &[KeyParameter], import_data: &KeyImportData) -> bool; |
| 82 | } |
| 83 | |
| 84 | const KEYBLOB_PREFIX: &[u8] = b"SoftKeyMintForV1Blob"; |
| 85 | const KEYBLOB_HMAC_KEY: &[u8] = b"SoftKeyMintForV1HMACKey"; |
| 86 | |
| 87 | /// Wrap the provided keyblob: |
| 88 | /// - prefix it with an identifier specific to this wrapper |
| 89 | /// - suffix it with an HMAC tag, using the [`KEYBLOB_HMAC_KEY`] and `keyblob`. |
| 90 | fn wrap_keyblob(keyblob: &[u8]) -> anyhow::Result<Vec<u8>> { |
| 91 | let mut result = Vec::with_capacity(KEYBLOB_PREFIX.len() + keyblob.len() + HMAC_SHA256_LEN); |
| 92 | result.extend_from_slice(KEYBLOB_PREFIX); |
| 93 | result.extend_from_slice(keyblob); |
| 94 | let tag = hmac_sha256(KEYBLOB_HMAC_KEY, keyblob) |
Shaquille Johnson | 9da2e1c | 2022-09-19 12:39:01 +0000 | [diff] [blame] | 95 | .context(ks_err!("failed to calculate HMAC-SHA256"))?; |
David Drysdale | c97eb9e | 2022-01-26 13:03:48 -0800 | [diff] [blame] | 96 | result.extend_from_slice(&tag); |
| 97 | Ok(result) |
| 98 | } |
| 99 | |
| 100 | /// Return an unwrapped version of the provided `keyblob`, which may or may |
| 101 | /// not be associated with the software emulation. |
David Drysdale | 746e1be | 2023-07-05 17:39:57 +0100 | [diff] [blame] | 102 | pub fn unwrap_keyblob(keyblob: &[u8]) -> KeyBlob { |
David Drysdale | c97eb9e | 2022-01-26 13:03:48 -0800 | [diff] [blame] | 103 | if !keyblob.starts_with(KEYBLOB_PREFIX) { |
| 104 | return KeyBlob::Raw(keyblob); |
| 105 | } |
| 106 | let without_prefix = &keyblob[KEYBLOB_PREFIX.len()..]; |
| 107 | if without_prefix.len() < HMAC_SHA256_LEN { |
| 108 | return KeyBlob::Raw(keyblob); |
| 109 | } |
| 110 | let (inner_keyblob, want_tag) = without_prefix.split_at(without_prefix.len() - HMAC_SHA256_LEN); |
| 111 | let got_tag = match hmac_sha256(KEYBLOB_HMAC_KEY, inner_keyblob) { |
| 112 | Ok(tag) => tag, |
| 113 | Err(e) => { |
| 114 | log::error!("Error calculating HMAC-SHA256 for keyblob unwrap: {:?}", e); |
| 115 | return KeyBlob::Raw(keyblob); |
| 116 | } |
| 117 | }; |
| 118 | // Comparison does not need to be constant-time here. |
| 119 | if want_tag == got_tag { |
| 120 | KeyBlob::Wrapped(inner_keyblob) |
| 121 | } else { |
| 122 | KeyBlob::Raw(keyblob) |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | /// Wrapper around a real device that implements a back-level version of |
| 127 | /// `IKeyMintDevice` |
| 128 | pub struct BacklevelKeyMintWrapper<T: EmulationDetector> { |
| 129 | /// The `real` device implements some earlier version of `IKeyMintDevice` |
| 130 | real: Strong<dyn IKeyMintDevice>, |
| 131 | /// The `soft`ware device implements the current version of `IKeyMintDevice` |
| 132 | soft: Strong<dyn IKeyMintDevice>, |
| 133 | /// Detector for operations that are not supported by the earlier version of |
| 134 | /// `IKeyMintDevice`. Or possibly a large flightless bird, who can tell. |
| 135 | emu: T, |
| 136 | } |
| 137 | |
| 138 | impl<T> BacklevelKeyMintWrapper<T> |
| 139 | where |
| 140 | T: EmulationDetector + 'static, |
| 141 | { |
| 142 | /// Create a wrapper around the provided back-level KeyMint device, so that |
| 143 | /// software emulation can be performed for any current-version features not |
| 144 | /// provided by the real device. |
| 145 | pub fn wrap( |
| 146 | emu: T, |
| 147 | real: Strong<dyn IKeyMintDevice>, |
| 148 | ) -> anyhow::Result<Strong<dyn IKeyMintDevice>> { |
| 149 | // This is a no-op if it was called before. |
| 150 | keystore2_km_compat::add_keymint_device_service(); |
| 151 | |
Shaquille Johnson | 9da2e1c | 2022-09-19 12:39:01 +0000 | [diff] [blame] | 152 | let keystore_compat_service: Strong<dyn IKeystoreCompatService> = |
| 153 | map_binder_status_code(binder::get_interface("android.security.compat")) |
| 154 | .context(ks_err!("Trying to connect to compat service."))?; |
David Drysdale | c97eb9e | 2022-01-26 13:03:48 -0800 | [diff] [blame] | 155 | let soft = |
| 156 | map_binder_status(keystore_compat_service.getKeyMintDevice(SecurityLevel::SOFTWARE)) |
| 157 | .map_err(|e| match e { |
| 158 | Error::BinderTransaction(StatusCode::NAME_NOT_FOUND) => { |
| 159 | Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE) |
| 160 | } |
| 161 | e => e, |
| 162 | }) |
Shaquille Johnson | 9da2e1c | 2022-09-19 12:39:01 +0000 | [diff] [blame] | 163 | .context(ks_err!("Trying to get software device."))?; |
David Drysdale | c97eb9e | 2022-01-26 13:03:48 -0800 | [diff] [blame] | 164 | |
| 165 | Ok(BnKeyMintDevice::new_binder( |
| 166 | Self { real, soft, emu }, |
| 167 | BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() }, |
| 168 | )) |
| 169 | } |
| 170 | } |
| 171 | |
Orlando Arbildo | 9ee036a | 2023-10-31 00:15:22 +0000 | [diff] [blame] | 172 | impl<T> binder::Interface for BacklevelKeyMintWrapper<T> where T: EmulationDetector + 'static {} |
David Drysdale | c97eb9e | 2022-01-26 13:03:48 -0800 | [diff] [blame] | 173 | |
| 174 | impl<T> IKeyMintDevice for BacklevelKeyMintWrapper<T> |
| 175 | where |
| 176 | T: EmulationDetector + 'static, |
| 177 | { |
| 178 | // For methods that don't involve keyblobs, forward to either the real |
| 179 | // device, or to both real & emulated devices. |
| 180 | fn getHardwareInfo(&self) -> binder::Result<KeyMintHardwareInfo> { |
| 181 | self.real.getHardwareInfo() |
| 182 | } |
| 183 | fn addRngEntropy(&self, data: &[u8]) -> binder::Result<()> { |
| 184 | self.real.addRngEntropy(data) |
| 185 | } |
| 186 | fn deleteAllKeys(&self) -> binder::Result<()> { |
| 187 | self.real.deleteAllKeys() |
| 188 | } |
| 189 | fn destroyAttestationIds(&self) -> binder::Result<()> { |
| 190 | self.real.destroyAttestationIds() |
| 191 | } |
| 192 | fn deviceLocked( |
| 193 | &self, |
| 194 | password_only: bool, |
| 195 | timestamp_token: Option<&TimeStampToken>, |
| 196 | ) -> binder::Result<()> { |
| 197 | // Propagate to both real and software devices, but only pay attention |
| 198 | // to the result from the real device. |
| 199 | let _ = self.soft.deviceLocked(password_only, timestamp_token); |
| 200 | self.real.deviceLocked(password_only, timestamp_token) |
| 201 | } |
| 202 | fn earlyBootEnded(&self) -> binder::Result<()> { |
| 203 | // Propagate to both real and software devices, but only pay attention |
| 204 | // to the result from the real device. |
| 205 | let _ = self.soft.earlyBootEnded(); |
| 206 | self.real.earlyBootEnded() |
| 207 | } |
David Drysdale | c0ed986 | 2023-07-05 07:11:39 +0100 | [diff] [blame] | 208 | fn getRootOfTrustChallenge(&self) -> binder::Result<[u8; 16]> { |
| 209 | self.real.getRootOfTrustChallenge() |
| 210 | } |
| 211 | fn getRootOfTrust(&self, challenge: &[u8; 16]) -> binder::Result<Vec<u8>> { |
| 212 | self.real.getRootOfTrust(challenge) |
| 213 | } |
| 214 | fn sendRootOfTrust(&self, root_of_trust: &[u8]) -> binder::Result<()> { |
| 215 | self.real.sendRootOfTrust(root_of_trust) |
| 216 | } |
David Drysdale | c97eb9e | 2022-01-26 13:03:48 -0800 | [diff] [blame] | 217 | |
| 218 | // For methods that emit keyblobs, check whether the underlying real device |
| 219 | // supports the relevant parameters, and forward to the appropriate device. |
| 220 | // If the emulated device is used, ensure that the created keyblob gets |
| 221 | // prefixed so we can recognize it in future. |
| 222 | fn generateKey( |
| 223 | &self, |
| 224 | key_params: &[KeyParameter], |
| 225 | attestation_key: Option<&AttestationKey>, |
| 226 | ) -> binder::Result<KeyCreationResult> { |
| 227 | if self.emu.emulation_required(key_params, &KeyImportData::None) { |
| 228 | let mut result = self.soft.generateKey(key_params, attestation_key)?; |
| 229 | result.keyBlob = map_or_log_err(wrap_keyblob(&result.keyBlob), Ok)?; |
| 230 | Ok(result) |
| 231 | } else { |
| 232 | self.real.generateKey(key_params, attestation_key) |
| 233 | } |
| 234 | } |
| 235 | fn importKey( |
| 236 | &self, |
| 237 | key_params: &[KeyParameter], |
| 238 | key_format: KeyFormat, |
| 239 | key_data: &[u8], |
| 240 | attestation_key: Option<&AttestationKey>, |
| 241 | ) -> binder::Result<KeyCreationResult> { |
| 242 | if self.emu.emulation_required(key_params, &KeyImportData::new(key_format, key_data)?) { |
| 243 | let mut result = |
| 244 | self.soft.importKey(key_params, key_format, key_data, attestation_key)?; |
| 245 | result.keyBlob = map_or_log_err(wrap_keyblob(&result.keyBlob), Ok)?; |
| 246 | Ok(result) |
| 247 | } else { |
| 248 | self.real.importKey(key_params, key_format, key_data, attestation_key) |
| 249 | } |
| 250 | } |
| 251 | fn importWrappedKey( |
| 252 | &self, |
| 253 | wrapped_key_data: &[u8], |
| 254 | wrapping_key_blob: &[u8], |
| 255 | masking_key: &[u8], |
| 256 | unwrapping_params: &[KeyParameter], |
| 257 | password_sid: i64, |
| 258 | biometric_sid: i64, |
| 259 | ) -> binder::Result<KeyCreationResult> { |
| 260 | // A wrapped key cannot be software-emulated, as the wrapping key is |
| 261 | // likely hardware-bound. |
| 262 | self.real.importWrappedKey( |
| 263 | wrapped_key_data, |
| 264 | wrapping_key_blob, |
| 265 | masking_key, |
| 266 | unwrapping_params, |
| 267 | password_sid, |
| 268 | biometric_sid, |
| 269 | ) |
| 270 | } |
| 271 | |
| 272 | // For methods that use keyblobs, determine which device to forward the |
| 273 | // operation to based on whether the keyblob is appropriately prefixed. |
| 274 | fn upgradeKey( |
| 275 | &self, |
| 276 | keyblob_to_upgrade: &[u8], |
| 277 | upgrade_params: &[KeyParameter], |
| 278 | ) -> binder::Result<Vec<u8>> { |
| 279 | match unwrap_keyblob(keyblob_to_upgrade) { |
| 280 | KeyBlob::Raw(keyblob) => self.real.upgradeKey(keyblob, upgrade_params), |
| 281 | KeyBlob::Wrapped(keyblob) => { |
| 282 | // Re-wrap the upgraded keyblob. |
| 283 | let upgraded_keyblob = self.soft.upgradeKey(keyblob, upgrade_params)?; |
| 284 | map_or_log_err(wrap_keyblob(&upgraded_keyblob), Ok) |
| 285 | } |
| 286 | } |
| 287 | } |
| 288 | fn deleteKey(&self, keyblob: &[u8]) -> binder::Result<()> { |
| 289 | match unwrap_keyblob(keyblob) { |
| 290 | KeyBlob::Raw(keyblob) => self.real.deleteKey(keyblob), |
| 291 | KeyBlob::Wrapped(keyblob) => { |
| 292 | // Forward to the software implementation for completeness, but |
| 293 | // this should always be a no-op. |
| 294 | self.soft.deleteKey(keyblob) |
| 295 | } |
| 296 | } |
| 297 | } |
| 298 | fn begin( |
| 299 | &self, |
| 300 | purpose: KeyPurpose, |
| 301 | keyblob: &[u8], |
| 302 | params: &[KeyParameter], |
| 303 | auth_token: Option<&HardwareAuthToken>, |
| 304 | ) -> binder::Result<BeginResult> { |
| 305 | match unwrap_keyblob(keyblob) { |
| 306 | KeyBlob::Raw(keyblob) => self.real.begin(purpose, keyblob, params, auth_token), |
| 307 | KeyBlob::Wrapped(keyblob) => self.soft.begin(purpose, keyblob, params, auth_token), |
| 308 | } |
| 309 | } |
| 310 | fn getKeyCharacteristics( |
| 311 | &self, |
| 312 | keyblob: &[u8], |
| 313 | app_id: &[u8], |
| 314 | app_data: &[u8], |
| 315 | ) -> binder::Result<Vec<KeyCharacteristics>> { |
| 316 | match unwrap_keyblob(keyblob) { |
| 317 | KeyBlob::Raw(keyblob) => self.real.getKeyCharacteristics(keyblob, app_id, app_data), |
| 318 | KeyBlob::Wrapped(keyblob) => self.soft.getKeyCharacteristics(keyblob, app_id, app_data), |
| 319 | } |
| 320 | } |
David Drysdale | c97eb9e | 2022-01-26 13:03:48 -0800 | [diff] [blame] | 321 | fn convertStorageKeyToEphemeral(&self, storage_keyblob: &[u8]) -> binder::Result<Vec<u8>> { |
| 322 | // Storage keys should never be associated with a software emulated device. |
| 323 | self.real.convertStorageKeyToEphemeral(storage_keyblob) |
| 324 | } |
| 325 | } |
| 326 | |
| 327 | /// Detector for current features that are not implemented by KeyMint V1. |
| 328 | #[derive(Debug)] |
| 329 | pub struct KeyMintV1 { |
| 330 | sec_level: SecurityLevel, |
| 331 | } |
| 332 | |
| 333 | impl KeyMintV1 { |
| 334 | pub fn new(sec_level: SecurityLevel) -> Self { |
| 335 | Self { sec_level } |
| 336 | } |
| 337 | } |
| 338 | |
| 339 | impl EmulationDetector for KeyMintV1 { |
| 340 | fn emulation_required(&self, params: &[KeyParameter], _import_data: &KeyImportData) -> bool { |
| 341 | // No current difference from KeyMint v1 for STRONGBOX (it doesn't |
| 342 | // support curve 25519). |
| 343 | if self.sec_level == SecurityLevel::STRONGBOX { |
| 344 | return false; |
| 345 | } |
| 346 | |
| 347 | // KeyMint V1 does not support the use of curve 25519, so hunt for that |
| 348 | // in the parameters. |
| 349 | if params.iter().any(|p| { |
| 350 | p.tag == Tag::EC_CURVE && p.value == KeyParameterValue::EcCurve(EcCurve::CURVE_25519) |
| 351 | }) { |
| 352 | return true; |
| 353 | } |
| 354 | // In theory, if the `import_data` is `KeyImportData::Pkcs8` we could |
| 355 | // check the imported keymaterial for the Ed25519 / X25519 OIDs in the |
| 356 | // PKCS8 keydata, and use that to decide to route to software. However, |
| 357 | // the KeyMint spec doesn't require that so don't attempt to parse the |
| 358 | // key material here. |
| 359 | false |
| 360 | } |
| 361 | } |
| 362 | |
| 363 | /// Detector for current features that are not implemented by KeyMaster, via the |
| 364 | /// km_compat wrapper. |
| 365 | #[derive(Debug)] |
| 366 | pub struct Keymaster { |
| 367 | v1: KeyMintV1, |
| 368 | } |
| 369 | |
| 370 | /// TODO(b/216434270): This could be used this to replace the emulation routing |
| 371 | /// in the km_compat C++ code, and allow support for imported ECDH keys along |
| 372 | /// the way. Would need to figure out what would happen to existing emulated |
| 373 | /// keys though. |
| 374 | #[allow(dead_code)] |
| 375 | impl Keymaster { |
| 376 | pub fn new(sec_level: SecurityLevel) -> Self { |
| 377 | Self { v1: KeyMintV1::new(sec_level) } |
| 378 | } |
| 379 | } |
| 380 | |
| 381 | impl EmulationDetector for Keymaster { |
| 382 | fn emulation_required(&self, params: &[KeyParameter], import_data: &KeyImportData) -> bool { |
| 383 | // The km_compat wrapper on top of Keymaster emulates the KeyMint V1 |
| 384 | // interface, so any feature from > v1 needs to be emulated. |
| 385 | if self.v1.emulation_required(params, import_data) { |
| 386 | return true; |
| 387 | } |
| 388 | |
| 389 | // Keymaster does not support ECDH (KeyPurpose::AGREE_KEY), so hunt for |
| 390 | // that in the parameters. |
| 391 | if params.iter().any(|p| { |
| 392 | p.tag == Tag::PURPOSE && p.value == KeyParameterValue::KeyPurpose(KeyPurpose::AGREE_KEY) |
| 393 | }) { |
| 394 | return true; |
| 395 | } |
| 396 | false |
| 397 | } |
| 398 | } |
| 399 | |
| 400 | #[cfg(test)] |
| 401 | mod tests { |
| 402 | use super::*; |
| 403 | |
| 404 | #[test] |
| 405 | fn test_key_import_data() { |
| 406 | let data = vec![1, 2, 3]; |
| 407 | assert_eq!(KeyImportData::new(KeyFormat::PKCS8, &data), Ok(KeyImportData::Pkcs8(&data))); |
| 408 | assert_eq!(KeyImportData::new(KeyFormat::RAW, &data), Ok(KeyImportData::Raw(&data))); |
| 409 | assert!(KeyImportData::new(KeyFormat::X509, &data).is_err()); |
| 410 | } |
| 411 | |
| 412 | #[test] |
| 413 | fn test_wrap_keyblob() { |
| 414 | let keyblob = vec![1, 2, 3]; |
| 415 | let wrapped = wrap_keyblob(&keyblob).unwrap(); |
| 416 | assert_eq!(&wrapped[..KEYBLOB_PREFIX.len()], KEYBLOB_PREFIX); |
| 417 | assert_eq!(&wrapped[KEYBLOB_PREFIX.len()..KEYBLOB_PREFIX.len() + keyblob.len()], &keyblob); |
| 418 | assert_eq!(unwrap_keyblob(&keyblob), KeyBlob::Raw(&keyblob)); |
| 419 | assert_eq!(unwrap_keyblob(&wrapped), KeyBlob::Wrapped(&keyblob)); |
| 420 | |
| 421 | let mut corrupt_prefix = wrapped.clone(); |
| 422 | corrupt_prefix[0] ^= 0x01; |
| 423 | assert_eq!(unwrap_keyblob(&corrupt_prefix), KeyBlob::Raw(&corrupt_prefix)); |
| 424 | |
| 425 | let mut corrupt_suffix = wrapped.clone(); |
| 426 | corrupt_suffix[wrapped.len() - 1] ^= 0x01; |
| 427 | assert_eq!(unwrap_keyblob(&corrupt_suffix), KeyBlob::Raw(&corrupt_suffix)); |
| 428 | |
| 429 | let too_short = &wrapped[..wrapped.len() - 4]; |
| 430 | assert_eq!(unwrap_keyblob(too_short), KeyBlob::Raw(too_short)); |
| 431 | } |
| 432 | |
| 433 | #[test] |
| 434 | fn test_keymintv1_emulation_required() { |
| 435 | let tests = vec![ |
| 436 | (SecurityLevel::TRUSTED_ENVIRONMENT, vec![], false), |
| 437 | ( |
| 438 | SecurityLevel::TRUSTED_ENVIRONMENT, |
| 439 | vec![ |
| 440 | KeyParameter { |
| 441 | tag: Tag::PURPOSE, |
| 442 | value: KeyParameterValue::KeyPurpose(KeyPurpose::SIGN), |
| 443 | }, |
| 444 | KeyParameter { |
| 445 | tag: Tag::PURPOSE, |
| 446 | value: KeyParameterValue::KeyPurpose(KeyPurpose::VERIFY), |
| 447 | }, |
| 448 | ], |
| 449 | false, |
| 450 | ), |
| 451 | ( |
| 452 | SecurityLevel::TRUSTED_ENVIRONMENT, |
| 453 | vec![KeyParameter { |
| 454 | tag: Tag::PURPOSE, |
| 455 | value: KeyParameterValue::KeyPurpose(KeyPurpose::AGREE_KEY), |
| 456 | }], |
| 457 | false, |
| 458 | ), |
| 459 | ( |
| 460 | SecurityLevel::TRUSTED_ENVIRONMENT, |
| 461 | vec![ |
| 462 | KeyParameter { |
| 463 | tag: Tag::PURPOSE, |
| 464 | value: KeyParameterValue::KeyPurpose(KeyPurpose::AGREE_KEY), |
| 465 | }, |
| 466 | KeyParameter { |
| 467 | tag: Tag::EC_CURVE, |
| 468 | value: KeyParameterValue::EcCurve(EcCurve::P_256), |
| 469 | }, |
| 470 | ], |
| 471 | false, |
| 472 | ), |
| 473 | ( |
| 474 | SecurityLevel::TRUSTED_ENVIRONMENT, |
| 475 | vec![ |
| 476 | KeyParameter { |
| 477 | tag: Tag::PURPOSE, |
| 478 | value: KeyParameterValue::KeyPurpose(KeyPurpose::AGREE_KEY), |
| 479 | }, |
| 480 | KeyParameter { |
| 481 | tag: Tag::EC_CURVE, |
| 482 | value: KeyParameterValue::EcCurve(EcCurve::CURVE_25519), |
| 483 | }, |
| 484 | ], |
| 485 | true, |
| 486 | ), |
| 487 | ( |
| 488 | SecurityLevel::STRONGBOX, |
| 489 | vec![ |
| 490 | KeyParameter { |
| 491 | tag: Tag::PURPOSE, |
| 492 | value: KeyParameterValue::KeyPurpose(KeyPurpose::AGREE_KEY), |
| 493 | }, |
| 494 | KeyParameter { |
| 495 | tag: Tag::EC_CURVE, |
| 496 | value: KeyParameterValue::EcCurve(EcCurve::CURVE_25519), |
| 497 | }, |
| 498 | ], |
| 499 | false, |
| 500 | ), |
| 501 | ]; |
| 502 | for (sec_level, params, want) in tests { |
| 503 | let v1 = KeyMintV1::new(sec_level); |
| 504 | let got = v1.emulation_required(¶ms, &KeyImportData::None); |
| 505 | assert_eq!(got, want, "emulation_required({:?})={}, want {}", params, got, want); |
| 506 | } |
| 507 | } |
| 508 | |
| 509 | #[test] |
| 510 | fn test_keymaster_emulation_required() { |
| 511 | let tests = vec![ |
| 512 | (SecurityLevel::TRUSTED_ENVIRONMENT, vec![], false), |
| 513 | ( |
| 514 | SecurityLevel::TRUSTED_ENVIRONMENT, |
| 515 | vec![ |
| 516 | KeyParameter { |
| 517 | tag: Tag::PURPOSE, |
| 518 | value: KeyParameterValue::KeyPurpose(KeyPurpose::SIGN), |
| 519 | }, |
| 520 | KeyParameter { |
| 521 | tag: Tag::PURPOSE, |
| 522 | value: KeyParameterValue::KeyPurpose(KeyPurpose::VERIFY), |
| 523 | }, |
| 524 | ], |
| 525 | false, |
| 526 | ), |
| 527 | ( |
| 528 | SecurityLevel::TRUSTED_ENVIRONMENT, |
| 529 | vec![KeyParameter { |
| 530 | tag: Tag::PURPOSE, |
| 531 | value: KeyParameterValue::KeyPurpose(KeyPurpose::AGREE_KEY), |
| 532 | }], |
| 533 | true, |
| 534 | ), |
| 535 | ( |
| 536 | SecurityLevel::TRUSTED_ENVIRONMENT, |
| 537 | vec![ |
| 538 | KeyParameter { |
| 539 | tag: Tag::PURPOSE, |
| 540 | value: KeyParameterValue::KeyPurpose(KeyPurpose::AGREE_KEY), |
| 541 | }, |
| 542 | KeyParameter { |
| 543 | tag: Tag::EC_CURVE, |
| 544 | value: KeyParameterValue::EcCurve(EcCurve::P_256), |
| 545 | }, |
| 546 | ], |
| 547 | true, |
| 548 | ), |
| 549 | ( |
| 550 | SecurityLevel::TRUSTED_ENVIRONMENT, |
| 551 | vec![ |
| 552 | KeyParameter { |
| 553 | tag: Tag::PURPOSE, |
| 554 | value: KeyParameterValue::KeyPurpose(KeyPurpose::AGREE_KEY), |
| 555 | }, |
| 556 | KeyParameter { |
| 557 | tag: Tag::EC_CURVE, |
| 558 | value: KeyParameterValue::EcCurve(EcCurve::CURVE_25519), |
| 559 | }, |
| 560 | ], |
| 561 | true, |
| 562 | ), |
| 563 | ( |
| 564 | SecurityLevel::STRONGBOX, |
| 565 | vec![ |
| 566 | KeyParameter { |
| 567 | tag: Tag::PURPOSE, |
| 568 | value: KeyParameterValue::KeyPurpose(KeyPurpose::AGREE_KEY), |
| 569 | }, |
| 570 | KeyParameter { |
| 571 | tag: Tag::EC_CURVE, |
| 572 | value: KeyParameterValue::EcCurve(EcCurve::CURVE_25519), |
| 573 | }, |
| 574 | ], |
| 575 | true, |
| 576 | ), |
| 577 | ( |
| 578 | SecurityLevel::STRONGBOX, |
| 579 | vec![ |
| 580 | KeyParameter { |
| 581 | tag: Tag::PURPOSE, |
| 582 | value: KeyParameterValue::KeyPurpose(KeyPurpose::SIGN), |
| 583 | }, |
| 584 | KeyParameter { |
| 585 | tag: Tag::EC_CURVE, |
| 586 | value: KeyParameterValue::EcCurve(EcCurve::CURVE_25519), |
| 587 | }, |
| 588 | ], |
| 589 | false, |
| 590 | ), |
| 591 | ]; |
| 592 | for (sec_level, params, want) in tests { |
| 593 | let v0 = Keymaster::new(sec_level); |
| 594 | let got = v0.emulation_required(¶ms, &KeyImportData::None); |
| 595 | assert_eq!(got, want, "emulation_required({:?})={}, want {}", params, got, want); |
| 596 | } |
| 597 | } |
| 598 | } |