• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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