1 //! Traits representing access to device-specific information and functionality. 2 3 use crate::coset::{iana, AsCborValue, CoseSign1Builder, HeaderBuilder}; 4 use alloc::{boxed::Box, vec::Vec}; 5 use kmr_common::{ 6 crypto, crypto::aes, crypto::hmac, crypto::KeyMaterial, crypto::OpaqueOr, keyblob, log_unimpl, 7 unimpl, Error, 8 }; 9 use kmr_wire::{keymint, rpc, secureclock::TimeStampToken, CborError}; 10 use log::error; 11 12 use crate::rkp::serialize_cbor; 13 14 /// Context used to derive the hardware backed key for computing HMAC in 15 /// IRemotelyProvisionedComponent. 16 pub const RPC_HMAC_KEY_CONTEXT: &[u8] = b"Key to MAC public keys"; 17 18 /// Length (in bytes) of the HMAC key used in IRemotelyProvisionedComponent. 19 pub const RPC_HMAC_KEY_LEN: usize = 32; 20 21 /// Combined collection of trait implementations that must be provided. 22 pub struct Implementation<'a> { 23 /// Retrieval of root key material. 24 pub keys: &'a dyn RetrieveKeyMaterial, 25 26 /// Retrieval of attestation certificate signing information. 27 pub sign_info: &'a dyn RetrieveCertSigningInfo, 28 29 /// Retrieval of attestation ID information. 30 pub attest_ids: Option<&'a mut dyn RetrieveAttestationIds>, 31 32 /// Secure deletion secret manager. If not available, rollback-resistant 33 /// keys will not be supported. 34 pub sdd_mgr: Option<&'a mut dyn keyblob::SecureDeletionSecretManager>, 35 36 /// Retrieval of bootloader status. 37 pub bootloader: &'a dyn BootloaderStatus, 38 39 /// Storage key wrapping. If not available `convertStorageKeyToEphemeral()` will not be 40 /// supported 41 pub sk_wrapper: Option<&'a dyn StorageKeyWrapper>, 42 43 /// Trusted user presence indicator. 44 pub tup: &'a dyn TrustedUserPresence, 45 46 /// Legacy key conversion handling. 47 pub legacy_key: Option<&'a mut dyn keyblob::LegacyKeyHandler>, 48 49 /// Retrieval of artifacts related to the device implementation of IRemotelyProvisionedComponent 50 /// (IRPC) HAL. 51 pub rpc: &'a dyn RetrieveRpcArtifacts, 52 } 53 54 /// Functionality related to retrieval of device-specific key material, and its subsequent use. 55 /// The caller is generally expected to drop the key material as soon as it is done with it. 56 pub trait RetrieveKeyMaterial { 57 /// Retrieve the root key used for derivation of a per-keyblob key encryption key (KEK), passing 58 /// in any opaque context. root_kek(&self, context: &[u8]) -> Result<OpaqueOr<hmac::Key>, Error>59 fn root_kek(&self, context: &[u8]) -> Result<OpaqueOr<hmac::Key>, Error>; 60 61 /// Retrieve any opaque (but non-confidential) context needed for future calls to [`root_kek`]. 62 /// Context should not include confidential data (it will be stored in the clear). kek_context(&self) -> Result<Vec<u8>, Error>63 fn kek_context(&self) -> Result<Vec<u8>, Error> { 64 // Default implementation is to have an empty KEK retrieval context. 65 Ok(Vec::new()) 66 } 67 68 /// Retrieve the key agreement key used for shared secret negotiation. kak(&self) -> Result<OpaqueOr<aes::Key>, Error>69 fn kak(&self) -> Result<OpaqueOr<aes::Key>, Error>; 70 71 /// Install the device HMAC agreed by shared secret negotiation into hardware (optional). hmac_key_agreed(&self, _key: &crypto::hmac::Key) -> Option<Box<dyn DeviceHmac>>72 fn hmac_key_agreed(&self, _key: &crypto::hmac::Key) -> Option<Box<dyn DeviceHmac>> { 73 // By default, use a software implementation that holds the key in memory. 74 None 75 } 76 77 /// Retrieve the hardware backed secret used for UNIQUE_ID generation. unique_id_hbk(&self, ckdf: &dyn crypto::Ckdf) -> Result<crypto::hmac::Key, Error>78 fn unique_id_hbk(&self, ckdf: &dyn crypto::Ckdf) -> Result<crypto::hmac::Key, Error> { 79 // By default, use CKDF on the key agreement secret to derive a key. 80 let unique_id_label = b"UniqueID HBK 32B"; 81 ckdf.ckdf(&self.kak()?, unique_id_label, &[], 32).map(crypto::hmac::Key::new) 82 } 83 84 /// Build the HMAC input for a [`TimeStampToken`]. The default implementation produces 85 /// data that matches the `ISecureClock` AIDL specification; this method should only be 86 /// overridden for back-compatibility reasons. timestamp_token_mac_input(&self, token: &TimeStampToken) -> Result<Vec<u8>, Error>87 fn timestamp_token_mac_input(&self, token: &TimeStampToken) -> Result<Vec<u8>, Error> { 88 crate::clock::timestamp_token_mac_input(token) 89 } 90 } 91 92 /// Device HMAC calculation. 93 pub trait DeviceHmac { 94 /// Calculate the HMAC over the data using the agreed device HMAC key. hmac(&self, imp: &dyn crypto::Hmac, data: &[u8]) -> Result<Vec<u8>, Error>95 fn hmac(&self, imp: &dyn crypto::Hmac, data: &[u8]) -> Result<Vec<u8>, Error>; 96 97 /// Returns the key used for HMAC'ing data if available get_hmac_key(&self) -> Option<crypto::hmac::Key>98 fn get_hmac_key(&self) -> Option<crypto::hmac::Key> { 99 // By default we assume that the implementation cannot return a key 100 None 101 } 102 } 103 104 /// Identification of which attestation signing key is required. 105 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] 106 pub enum SigningKey { 107 /// Use a batch key that is shared across multiple devices (to prevent the keys being used as 108 /// device identifiers). 109 Batch, 110 /// Use a device-unique key for signing. Only supported for StrongBox. 111 DeviceUnique, 112 } 113 114 /// Indication of preferred attestation signing algorithm. 115 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] 116 pub enum SigningAlgorithm { 117 Ec, 118 Rsa, 119 } 120 121 /// Indication of required signing key. 122 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] 123 pub struct SigningKeyType { 124 pub which: SigningKey, 125 /// Indicates what is going to be signed, to allow implementations to (optionally) use EC / RSA 126 /// signing keys for EC / RSA keys respectively. 127 pub algo_hint: SigningAlgorithm, 128 } 129 130 /// Retrieval of attestation certificate signing information. The caller is expected to drop key 131 /// material after use, but may cache public key material. 132 pub trait RetrieveCertSigningInfo { 133 /// Return the signing key material for the specified `key_type`. The `algo_hint` parameter 134 /// indicates what is going to be signed, to allow implementations to (optionally) use EC / RSA 135 /// signing keys for EC /RSA keys respectively. signing_key(&self, key_type: SigningKeyType) -> Result<KeyMaterial, Error>136 fn signing_key(&self, key_type: SigningKeyType) -> Result<KeyMaterial, Error>; 137 138 /// Return the certificate chain associated with the specified signing key, where: 139 /// - `chain[0]` holds the public key that corresponds to `signing_key`, and which is signed 140 /// by... 141 /// - the keypair described by the second entry `chain[1]`, which in turn is signed by... 142 /// - ... 143 /// - the final certificate in the chain should be a self-signed cert holding a Google root. cert_chain(&self, key_type: SigningKeyType) -> Result<Vec<keymint::Certificate>, Error>144 fn cert_chain(&self, key_type: SigningKeyType) -> Result<Vec<keymint::Certificate>, Error>; 145 } 146 147 /// Retrieval of attestation ID information. This information will not change (so the caller can 148 /// cache this information after first invocation). 149 pub trait RetrieveAttestationIds { 150 /// Return the attestation IDs associated with the device, if available. get(&self) -> Result<crate::AttestationIdInfo, Error>151 fn get(&self) -> Result<crate::AttestationIdInfo, Error>; 152 153 /// Destroy all attestation IDs associated with the device. destroy_all(&mut self) -> Result<(), Error>154 fn destroy_all(&mut self) -> Result<(), Error>; 155 } 156 157 /// Bootloader status. 158 pub trait BootloaderStatus { 159 /// Indication of whether bootloader processing is complete done(&self) -> bool160 fn done(&self) -> bool { 161 // By default assume that the bootloader is done before KeyMint starts. 162 true 163 } 164 } 165 166 /// The trait that represents the device specific integration points required for the 167 /// implementation of IRemotelyProvisionedComponent (IRPC) HAL. 168 /// Note: The devices only supporting IRPC V3+ may ignore the optional IRPC V2 specific types in 169 /// the method signatures. 170 /// TODO (b/258069484): Add smoke tests to this device trait. 171 pub trait RetrieveRpcArtifacts { 172 // Retrieve secret bytes (of the given output length) derived from a hardware backed key. 173 // For a given context, the output is deterministic. derive_bytes_from_hbk( &self, hkdf: &dyn crypto::Hkdf, context: &[u8], output_len: usize, ) -> Result<Vec<u8>, Error>174 fn derive_bytes_from_hbk( 175 &self, 176 hkdf: &dyn crypto::Hkdf, 177 context: &[u8], 178 output_len: usize, 179 ) -> Result<Vec<u8>, Error>; 180 181 // Compute HMAC_SHA256 over the given input using a key derived from hardware. compute_hmac_sha256( &self, hmac: &dyn crypto::Hmac, hkdf: &dyn crypto::Hkdf, input: &[u8], ) -> Result<Vec<u8>, Error>182 fn compute_hmac_sha256( 183 &self, 184 hmac: &dyn crypto::Hmac, 185 hkdf: &dyn crypto::Hkdf, 186 input: &[u8], 187 ) -> Result<Vec<u8>, Error> { 188 let secret = self.derive_bytes_from_hbk(hkdf, RPC_HMAC_KEY_CONTEXT, RPC_HMAC_KEY_LEN)?; 189 crypto::hmac_sha256(hmac, &secret, input) 190 } 191 192 // Retrieve the information about the DICE chain belonging to the IRPC HAL implementation. get_dice_info(&self, test_mode: rpc::TestMode) -> Result<DiceInfo, Error>193 fn get_dice_info(&self, test_mode: rpc::TestMode) -> Result<DiceInfo, Error>; 194 195 // Sign the input data with the CDI leaf private key of the IRPC HAL implementation. In IRPC V2, 196 // the `data` to be signed is the [`SignedMac_structure`] in ProtectedData.aidl, when signing 197 // the ephemeral MAC key used to authenticate the public keys. In IRPC V3, the `data` to be 198 // signed is the [`SignedDataSigStruct`]. 199 // If a particular implementation would like to return the signature in a COSE_Sign1 message, 200 // they can mark this unimplemented and override the default implementation in the 201 // `sign_data_in_cose_sign1` method below. sign_data( &self, ec: &dyn crypto::Ec, data: &[u8], rpc_v2: Option<RpcV2Req>, ) -> Result<Vec<u8>, Error>202 fn sign_data( 203 &self, 204 ec: &dyn crypto::Ec, 205 data: &[u8], 206 rpc_v2: Option<RpcV2Req>, 207 ) -> Result<Vec<u8>, Error>; 208 209 // Sign the payload and return a COSE_Sign1 message. In IRPC V2, the `payload` is the MAC Key. 210 // In IRPC V3, the `payload` is the `Data` that the `SignedData` is parameterized with (i.e. a 211 // CBOR array containing `challenge` and `CsrPayload`). sign_data_in_cose_sign1( &self, ec: &dyn crypto::Ec, signing_algorithm: &CsrSigningAlgorithm, payload: &[u8], _aad: &[u8], _rpc_v2: Option<RpcV2Req>, ) -> Result<Vec<u8>, Error>212 fn sign_data_in_cose_sign1( 213 &self, 214 ec: &dyn crypto::Ec, 215 signing_algorithm: &CsrSigningAlgorithm, 216 payload: &[u8], 217 _aad: &[u8], 218 _rpc_v2: Option<RpcV2Req>, 219 ) -> Result<Vec<u8>, Error> { 220 let cose_sign_algorithm = match signing_algorithm { 221 CsrSigningAlgorithm::ES256 => iana::Algorithm::ES256, 222 CsrSigningAlgorithm::ES384 => iana::Algorithm::ES384, 223 CsrSigningAlgorithm::EdDSA => iana::Algorithm::EdDSA, 224 }; 225 // Construct `SignedData` 226 let protected = HeaderBuilder::new().algorithm(cose_sign_algorithm).build(); 227 let signed_data = CoseSign1Builder::new() 228 .protected(protected) 229 .payload(payload.to_vec()) 230 .try_create_signature(&[], |input| self.sign_data(ec, input, None))? 231 .build(); 232 let signed_data_cbor = signed_data.to_cbor_value().map_err(CborError::from)?; 233 serialize_cbor(&signed_data_cbor) 234 } 235 } 236 237 /// Information about the DICE chain belonging to the implementation of the IRPC HAL. 238 #[derive(Clone)] 239 pub struct DiceInfo { 240 pub pub_dice_artifacts: PubDiceArtifacts, 241 pub signing_algorithm: CsrSigningAlgorithm, 242 // This is only relevant for IRPC HAL V2 when `test_mode` is true. This is ignored in all other 243 // cases. The optional test CDI private key may be set here, if the device implementers 244 // do not want to cache the test CDI private key across the calls to the `get_dice_info` and 245 //`sign_data` methods when creating the CSR. 246 pub rpc_v2_test_cdi_priv: Option<RpcV2TestCDIPriv>, 247 } 248 249 /// Algorithm used to sign with the CDI leaf private key. 250 #[derive(Clone, Copy, Debug)] 251 pub enum CsrSigningAlgorithm { 252 ES256, 253 ES384, 254 EdDSA, 255 } 256 257 #[derive(Clone, Debug)] 258 pub struct PubDiceArtifacts { 259 // Certificates for the UDS Pub encoded in CBOR as per [`AdditionalDKSignatures`] structure in 260 // ProtectedData.aidl for IRPC HAL version 2 and as per [`UdsCerts`] structure in IRPC HAL 261 // version 3. 262 pub uds_certs: Vec<u8>, 263 // UDS Pub and the DICE certificates encoded in CBOR/COSE as per the [`Bcc`] structure 264 // defined in ProtectedData.aidl for IRPC HAL version 2 and as per [`DiceCertChain`] structure 265 // in IRPC HAL version 3. 266 pub dice_cert_chain: Vec<u8>, 267 } 268 269 // Enum distinguishing the two modes of operation for IRPC HAL V2, allowing an optional context 270 // information to be passed in for the test mode. 271 pub enum RpcV2Req<'a> { 272 Production, 273 // An opaque blob may be passed in for the test mode, if it was returned by the TA in 274 // `RkpV2TestCDIPriv.context` in order to link the two requests: `get_dice_info` and `sign_data` 275 // related to the same CSR. 276 Test(&'a [u8]), 277 } 278 279 // Struct encapsulating the optional CDI private key and the optional opaque context that may be 280 // returned with `DiceInfo` in IRPC V2 test mode. 281 #[derive(Clone)] 282 pub struct RpcV2TestCDIPriv { 283 pub test_cdi_priv: Option<OpaqueOr<crypto::ec::Key>>, 284 // An optional opaque blob set by the TA, if the TA wants a mechanism to relate the 285 // two requests: `get_dice_info` and `sign_data` related to the same CSR. 286 pub context: Vec<u8>, 287 } 288 289 /// Marker implementation for implementations that do not support `BOOTLOADER_ONLY` keys, which 290 /// always indicates that bootloader processing is complete. 291 pub struct BootloaderDone; 292 impl BootloaderStatus for BootloaderDone {} 293 294 /// Trusted user presence indicator. 295 pub trait TrustedUserPresence { 296 /// Indication of whether user presence is detected, via a mechanism in the current secure 297 /// environment. available(&self) -> bool298 fn available(&self) -> bool { 299 // By default assume that trusted user presence is not supported. 300 false 301 } 302 } 303 304 /// Marker implementation to indicate that trusted user presence is not supported. 305 pub struct TrustedPresenceUnsupported; 306 impl TrustedUserPresence for TrustedPresenceUnsupported {} 307 308 /// Storage key wrapping. 309 pub trait StorageKeyWrapper { 310 /// Wrap the provided key material using an ephemeral storage key. ephemeral_wrap(&self, key_material: &KeyMaterial) -> Result<Vec<u8>, Error>311 fn ephemeral_wrap(&self, key_material: &KeyMaterial) -> Result<Vec<u8>, Error>; 312 } 313 314 // No-op implementations for the non-optional device traits. These implementations are only 315 // intended for convenience during the process of porting the KeyMint code to a new environment. 316 pub struct NoOpRetrieveKeyMaterial; 317 impl RetrieveKeyMaterial for NoOpRetrieveKeyMaterial { root_kek(&self, _context: &[u8]) -> Result<OpaqueOr<hmac::Key>, Error>318 fn root_kek(&self, _context: &[u8]) -> Result<OpaqueOr<hmac::Key>, Error> { 319 unimpl!(); 320 } 321 kak(&self) -> Result<OpaqueOr<aes::Key>, Error>322 fn kak(&self) -> Result<OpaqueOr<aes::Key>, Error> { 323 unimpl!(); 324 } 325 } 326 327 pub struct NoOpRetrieveCertSigningInfo; 328 impl RetrieveCertSigningInfo for NoOpRetrieveCertSigningInfo { signing_key(&self, _key_type: SigningKeyType) -> Result<KeyMaterial, Error>329 fn signing_key(&self, _key_type: SigningKeyType) -> Result<KeyMaterial, Error> { 330 unimpl!(); 331 } 332 cert_chain(&self, _key_type: SigningKeyType) -> Result<Vec<keymint::Certificate>, Error>333 fn cert_chain(&self, _key_type: SigningKeyType) -> Result<Vec<keymint::Certificate>, Error> { 334 unimpl!(); 335 } 336 } 337 338 pub struct NoOpRetrieveRpcArtifacts; 339 impl RetrieveRpcArtifacts for NoOpRetrieveRpcArtifacts { derive_bytes_from_hbk( &self, _hkdf: &dyn crypto::Hkdf, _context: &[u8], _output_len: usize, ) -> Result<Vec<u8>, Error>340 fn derive_bytes_from_hbk( 341 &self, 342 _hkdf: &dyn crypto::Hkdf, 343 _context: &[u8], 344 _output_len: usize, 345 ) -> Result<Vec<u8>, Error> { 346 unimpl!(); 347 } 348 get_dice_info<'a>(&self, _test_mode: rpc::TestMode) -> Result<DiceInfo, Error>349 fn get_dice_info<'a>(&self, _test_mode: rpc::TestMode) -> Result<DiceInfo, Error> { 350 unimpl!(); 351 } 352 sign_data( &self, _ec: &dyn crypto::Ec, _data: &[u8], _rpc_v2: Option<RpcV2Req>, ) -> Result<Vec<u8>, Error>353 fn sign_data( 354 &self, 355 _ec: &dyn crypto::Ec, 356 _data: &[u8], 357 _rpc_v2: Option<RpcV2Req>, 358 ) -> Result<Vec<u8>, Error> { 359 unimpl!(); 360 } 361 } 362