1 //! Functionality for converting legacy keyblob formats. 2 3 use alloc::vec::Vec; 4 use kmr_common::keyblob::{ 5 legacy, SecureDeletionData, SecureDeletionSecretManager, SecureDeletionSlot, 6 }; 7 use kmr_common::{ 8 crypto, 9 crypto::{aes, OpaqueKeyMaterial, OpaqueOr}, 10 explicit, get_bool_tag_value, get_opt_tag_value, get_tag_value, keyblob, km_err, tag, 11 try_to_vec, vec_try, Error, FallibleAllocExt, 12 }; 13 use kmr_ta::device; 14 use kmr_wire::{ 15 keymint, 16 keymint::{Algorithm, BootInfo, EcCurve, ErrorCode, KeyParam, KeyPurpose, SecurityLevel}, 17 KeySizeInBits, 18 }; 19 use log::error; 20 21 /// Prefix for KEK derivation input when secure deletion not supported. 22 const AES_GCM_DESCRIPTOR_V1: &[u8] = b"AES-256-GCM-HKDF-SHA-256, version 1\0"; 23 /// Prefix for KEK derivation input when secure deletion supported. 24 const AES_GCM_DESCRIPTOR_V2: &[u8] = b"AES-256-GCM-HKDF-SHA-256, version 2\0"; 25 26 /// Slot number used to indicate that a key has no per-key secure deletion data. 27 const NO_SDD_SLOT_IDX: u32 = 0; 28 29 /// Legacy key handler that detects and converts `EncryptedKeyBlob` instances from 30 /// the previous Trusty implementation of KeyMint/Keymaster. 31 pub struct TrustyLegacyKeyBlobHandler { 32 pub aes: Box<dyn crypto::Aes>, 33 pub hkdf: Box<dyn crypto::Hkdf>, 34 pub sdd_mgr: Option<Box<dyn SecureDeletionSecretManager>>, 35 pub keys: Box<dyn device::RetrieveKeyMaterial>, 36 } 37 38 impl TrustyLegacyKeyBlobHandler { 39 /// Build the derivation information needed for KEK derivation that is compatible with the 40 /// previous C++ implementation. build_derivation_info( &self, encrypted_keyblob: &legacy::EncryptedKeyBlob, hidden: &[KeyParam], sdd_info: Option<(SecureDeletionData, u32)>, ) -> Result<Vec<u8>, Error>41 fn build_derivation_info( 42 &self, 43 encrypted_keyblob: &legacy::EncryptedKeyBlob, 44 hidden: &[KeyParam], 45 sdd_info: Option<(SecureDeletionData, u32)>, 46 ) -> Result<Vec<u8>, Error> { 47 let mut info = if sdd_info.is_some() { 48 try_to_vec(AES_GCM_DESCRIPTOR_V2)? 49 } else { 50 try_to_vec(AES_GCM_DESCRIPTOR_V1)? 51 }; 52 info.try_extend_from_slice(&tag::legacy::serialize(hidden)?)?; 53 info.try_extend_from_slice(&tag::legacy::serialize(&encrypted_keyblob.hw_enforced)?)?; 54 info.try_extend_from_slice(&tag::legacy::serialize(&encrypted_keyblob.sw_enforced)?)?; 55 if let Some((sdd_data, slot)) = sdd_info { 56 info.try_extend_from_slice( 57 &(sdd_data.factory_reset_secret.len() as u32).to_ne_bytes(), 58 )?; 59 info.try_extend_from_slice(&sdd_data.factory_reset_secret)?; 60 61 // If the slot is zero, the per-key secret is empty. 62 let secret: &[u8] = if slot == 0 { &[] } else { &sdd_data.secure_deletion_secret }; 63 info.try_extend_from_slice(&(secret.len() as u32).to_ne_bytes())?; 64 info.try_extend_from_slice(secret)?; 65 66 info.try_extend_from_slice(&slot.to_ne_bytes())?; 67 } 68 Ok(info) 69 } 70 71 /// Derive the key encryption key for a keyblob. derive_kek( &self, root_kek: &OpaqueOr<kmr_common::crypto::hmac::Key>, encrypted_keyblob: &legacy::EncryptedKeyBlob, hidden: &[KeyParam], sdd_data: Option<(SecureDeletionData, u32)>, ) -> Result<crypto::aes::Key, Error>72 fn derive_kek( 73 &self, 74 root_kek: &OpaqueOr<kmr_common::crypto::hmac::Key>, 75 encrypted_keyblob: &legacy::EncryptedKeyBlob, 76 hidden: &[KeyParam], 77 sdd_data: Option<(SecureDeletionData, u32)>, 78 ) -> Result<crypto::aes::Key, Error> { 79 let info = self.build_derivation_info(encrypted_keyblob, hidden, sdd_data)?; 80 // Trusty uses explicit keys for legacy keyblobs. 81 let raw_key = self.hkdf.hkdf(&[], &explicit!(root_kek)?.0, &info, 256 / 8)?; 82 let aes_key = crypto::aes::Key::Aes256( 83 raw_key.try_into().map_err(|_e| km_err!(UnknownError, "unexpected HKDF output len"))?, 84 ); 85 Ok(aes_key) 86 } 87 88 /// Convert a keyblob from the legacy C++ format to the current format. convert_key( &self, keyblob: &[u8], params: &[KeyParam], root_of_trust: &BootInfo, sec_level: SecurityLevel, ) -> Result<keyblob::PlaintextKeyBlob, Error>89 fn convert_key( 90 &self, 91 keyblob: &[u8], 92 params: &[KeyParam], 93 root_of_trust: &BootInfo, 94 sec_level: SecurityLevel, 95 ) -> Result<keyblob::PlaintextKeyBlob, Error> { 96 let encrypted_keyblob = legacy::EncryptedKeyBlob::deserialize(keyblob)?; 97 98 // Find the secure deletion data (if any) for the key. 99 let sdd_info = match ( 100 encrypted_keyblob.format.requires_secure_deletion(), 101 &self.sdd_mgr, 102 encrypted_keyblob.key_slot, 103 ) { 104 (true, Some(sdd_mgr), None) | (true, Some(sdd_mgr), Some(NO_SDD_SLOT_IDX)) => { 105 // Zero slot index implies that just the factory reset secret is populated. 106 let sdd_data = sdd_mgr.get_factory_reset_secret()?; 107 Some((sdd_data, NO_SDD_SLOT_IDX)) 108 } 109 (true, Some(sdd_mgr), Some(slot_idx)) => { 110 let slot = SecureDeletionSlot(slot_idx); 111 let sdd_data = sdd_mgr.get_secret(slot)?; 112 113 Some((sdd_data, slot_idx)) 114 } 115 (true, None, _) => { 116 return Err(km_err!( 117 InvalidKeyBlob, 118 "keyblob requires secure deletion but no implementation available", 119 )) 120 } 121 (false, _, Some(slot)) => { 122 return Err(km_err!( 123 InvalidKeyBlob, 124 "unexpected SDD slot {} for format {:?}", 125 slot, 126 encrypted_keyblob.format 127 )) 128 } 129 (false, _, None) => None, 130 }; 131 132 // Convert the key characteristics to current form. 133 let mut characteristics = vec_try![keymint::KeyCharacteristics { 134 security_level: sec_level, 135 authorizations: try_to_vec(&encrypted_keyblob.hw_enforced)?, 136 }]?; 137 if !encrypted_keyblob.sw_enforced.is_empty() { 138 characteristics.try_push(keymint::KeyCharacteristics { 139 security_level: keymint::SecurityLevel::Keystore, 140 authorizations: try_to_vec(&encrypted_keyblob.sw_enforced)?, 141 })?; 142 } 143 144 // Derive the KEK, using hidden inputs from params and root-of-trust. 145 let rots = &[ 146 &root_of_trust.verified_boot_key[..], 147 &(root_of_trust.verified_boot_state as u32).to_ne_bytes(), 148 &[if root_of_trust.device_boot_locked { 0x01u8 } else { 0x00u8 }], 149 ]; 150 let hidden_params = legacy::hidden(params, rots)?; 151 152 let rollback_version = match encrypted_keyblob.addl_info { 153 Some(v) => Some( 154 hwkey::OsRollbackVersion::try_from(v) 155 .map_err(|e| km_err!(InvalidKeyBlob, "unexpected addl_info={} : {:?}", v, e))?, 156 ), 157 None => None, 158 }; 159 let kek_context = super::TrustyKekContext::new( 160 encrypted_keyblob.format.is_versioned(), 161 encrypted_keyblob.kdf_version.map(hwkey::KdfVersion::from), 162 rollback_version, 163 )? 164 .to_raw()?; 165 166 let root_kek = self.keys.root_kek(&kek_context)?; 167 let aes_key = self.derive_kek(&root_kek, &encrypted_keyblob, &hidden_params, sdd_info)?; 168 169 // Key material is encrypted with AES-GCM; decrypt it. 170 let nonce: [u8; aes::GCM_NONCE_SIZE] = encrypted_keyblob 171 .nonce 172 .try_into() 173 .map_err(|_e| km_err!(InvalidKeyBlob, "unexpected nonce len",))?; 174 let mode = match encrypted_keyblob.tag.len() { 175 12 => crypto::aes::GcmMode::GcmTag12 { nonce }, 176 13 => crypto::aes::GcmMode::GcmTag13 { nonce }, 177 14 => crypto::aes::GcmMode::GcmTag14 { nonce }, 178 15 => crypto::aes::GcmMode::GcmTag15 { nonce }, 179 16 => crypto::aes::GcmMode::GcmTag16 { nonce }, 180 l => return Err(km_err!(InvalidKeyBlob, "unexpected AES-GCM tag length {}", l)), 181 }; 182 let mut op = 183 self.aes.begin_aead(aes_key.into(), mode, crypto::SymmetricOperation::Decrypt)?; 184 let mut raw_key_material = op.update(&encrypted_keyblob.ciphertext)?; 185 raw_key_material.try_extend_from_slice(&op.update(&encrypted_keyblob.tag)?)?; 186 raw_key_material.try_extend_from_slice(&op.finish()?)?; 187 if raw_key_material.len() != encrypted_keyblob.ciphertext.len() { 188 return Err(km_err!( 189 UnknownError, 190 "deciphered len {} != encrypted len {}", 191 raw_key_material.len(), 192 encrypted_keyblob.ciphertext.len() 193 )); 194 } 195 196 // Convert the key material into current form. 197 let chars = &encrypted_keyblob.hw_enforced; 198 let key_material = match get_tag_value!(chars, Algorithm, ErrorCode::InvalidKeyBlob)? { 199 // Symmetric keys have the key material stored as raw bytes. 200 Algorithm::Aes => { 201 // Special case: an AES key might be a storage key. 202 if get_bool_tag_value!(chars, StorageKey)? { 203 // Storage key is opaque data. 204 crypto::KeyMaterial::Aes(OpaqueOr::Opaque(OpaqueKeyMaterial(raw_key_material))) 205 } else { 206 // Normal case: expect explicit AES key material. 207 crypto::KeyMaterial::Aes(crypto::aes::Key::new(raw_key_material)?.into()) 208 } 209 } 210 Algorithm::TripleDes => { 211 crypto::KeyMaterial::TripleDes(crypto::des::Key::new(raw_key_material)?.into()) 212 } 213 Algorithm::Hmac => { 214 crypto::KeyMaterial::Hmac(crypto::hmac::Key::new(raw_key_material).into()) 215 } 216 217 // RSA keys have key material stored as a PKCS#1 `RSAPrivateKey` structure, DER-encoded, 218 // as decoded by the BoringSSL `RSA_parse_private_key()` function. This matches the 219 // internal form of a [`crypto::rsa::Key`]. 220 Algorithm::Rsa => crypto::KeyMaterial::Rsa(crypto::rsa::Key(raw_key_material).into()), 221 222 Algorithm::Ec => { 223 // Determine the EC curve, allowing for old keys that don't include `EC_CURVE` tag. 224 let ec_curve = match get_opt_tag_value!(chars, EcCurve)? { 225 Some(c) => *c, 226 None => match get_tag_value!(chars, KeySize, ErrorCode::InvalidKeyBlob)? { 227 KeySizeInBits(224) => EcCurve::P224, 228 KeySizeInBits(384) => EcCurve::P384, 229 KeySizeInBits(256) => { 230 return Err(km_err!(InvalidKeyBlob, "key size 256 ambiguous for EC")) 231 } 232 KeySizeInBits(521) => EcCurve::P521, 233 sz => return Err(km_err!(InvalidKeyBlob, "key size {:?} invalid", sz)), 234 }, 235 }; 236 match ec_curve { 237 // NIST curve EC keys are stored as an `ECPrivateKey` structure, DER-encoded, as 238 // decoded by the BoringSSL `EC_KEY_parse_private_key()` function. This matches 239 // the internal form of a [`crypto::ec::NistKey`]. 240 EcCurve::P224 => crypto::KeyMaterial::Ec( 241 ec_curve, 242 crypto::CurveType::Nist, 243 crypto::ec::Key::P224(crypto::ec::NistKey(raw_key_material)).into(), 244 ), 245 EcCurve::P256 => crypto::KeyMaterial::Ec( 246 ec_curve, 247 crypto::CurveType::Nist, 248 crypto::ec::Key::P256(crypto::ec::NistKey(raw_key_material)).into(), 249 ), 250 EcCurve::P384 => crypto::KeyMaterial::Ec( 251 ec_curve, 252 crypto::CurveType::Nist, 253 crypto::ec::Key::P384(crypto::ec::NistKey(raw_key_material)).into(), 254 ), 255 EcCurve::P521 => crypto::KeyMaterial::Ec( 256 ec_curve, 257 crypto::CurveType::Nist, 258 crypto::ec::Key::P521(crypto::ec::NistKey(raw_key_material)).into(), 259 ), 260 EcCurve::Curve25519 => { 261 let key = crypto::ec::import_pkcs8_key(&raw_key_material)?; 262 if let crypto::KeyMaterial::Ec(EcCurve::Curve25519, curve_type, _ec_key) = 263 &key 264 { 265 match curve_type { 266 crypto::CurveType::Nist => { 267 return Err(km_err!( 268 InvalidKeyBlob, 269 "unexpected NIST key with curve25519" 270 )) 271 } 272 crypto::CurveType::Xdh => { 273 if tag::primary_purpose(chars)? != KeyPurpose::AgreeKey { 274 return Err(km_err!( 275 InvalidKeyBlob, 276 "purpose not AGREE_KEY for X25519 key" 277 )); 278 } 279 } 280 crypto::CurveType::EdDsa => { 281 if tag::primary_purpose(chars)? == KeyPurpose::AgreeKey { 282 return Err(km_err!( 283 InvalidKeyBlob, 284 "AGREE_KEY purpose for non-XDH 25519 key" 285 )); 286 } 287 } 288 } 289 } else { 290 return Err(km_err!( 291 InvalidKeyBlob, 292 "curve25519 key with wrong contents" 293 )); 294 } 295 key 296 } 297 } 298 } 299 }; 300 301 Ok(keyblob::PlaintextKeyBlob { characteristics, key_material }) 302 } 303 } 304 305 impl keyblob::LegacyKeyHandler for TrustyLegacyKeyBlobHandler { convert_legacy_key( &self, keyblob: &[u8], params: &[KeyParam], root_of_trust: &BootInfo, sec_level: SecurityLevel, ) -> Result<keyblob::PlaintextKeyBlob, Error>306 fn convert_legacy_key( 307 &self, 308 keyblob: &[u8], 309 params: &[KeyParam], 310 root_of_trust: &BootInfo, 311 sec_level: SecurityLevel, 312 ) -> Result<keyblob::PlaintextKeyBlob, Error> { 313 self.convert_key(keyblob, params, root_of_trust, sec_level) 314 } 315 delete_legacy_key(&mut self, keyblob: &[u8]) -> Result<(), Error>316 fn delete_legacy_key(&mut self, keyblob: &[u8]) -> Result<(), Error> { 317 let encrypted_keyblob = legacy::EncryptedKeyBlob::deserialize(keyblob)?; 318 if let Some(slot) = encrypted_keyblob.key_slot { 319 if slot != NO_SDD_SLOT_IDX { 320 if !encrypted_keyblob.format.requires_secure_deletion() { 321 return Err(km_err!( 322 UnknownError, 323 "legacy keyblob of non-SDD format {:?} has non-empty SDD slot {:?}!", 324 encrypted_keyblob.format, 325 slot 326 )); 327 } 328 if let Some(sdd_mgr) = self.sdd_mgr.as_mut() { 329 if let Err(e) = sdd_mgr.delete_secret(SecureDeletionSlot(slot)) { 330 error!("failed to delete SDD slot {:?} for legacy key: {:?}", slot, e); 331 } 332 } else { 333 error!("legacy key has SDD slot {:?} but no SDD mgr available!", slot); 334 } 335 } 336 } 337 Ok(()) 338 } 339 } 340