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 //! This is the implementation for the remote provisioning AIDL interface between
16 //! the network providers for remote provisioning and the system. This interface
17 //! allows the caller to prompt the Remote Provisioning HAL to generate keys and
18 //! CBOR blobs that can be ferried to a provisioning server that will return
19 //! certificate chains signed by some root authority and stored in a keystore SQLite
20 //! DB.
21
22 use std::collections::HashMap;
23
24 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
25 Algorithm::Algorithm, AttestationKey::AttestationKey, Certificate::Certificate,
26 DeviceInfo::DeviceInfo, IRemotelyProvisionedComponent::IRemotelyProvisionedComponent,
27 KeyParameter::KeyParameter, KeyParameterValue::KeyParameterValue,
28 MacedPublicKey::MacedPublicKey, ProtectedData::ProtectedData, SecurityLevel::SecurityLevel,
29 Tag::Tag,
30 };
31 use android_security_remoteprovisioning::aidl::android::security::remoteprovisioning::{
32 AttestationPoolStatus::AttestationPoolStatus, IRemoteProvisioning::BnRemoteProvisioning,
33 IRemoteProvisioning::IRemoteProvisioning, ImplInfo::ImplInfo,
34 };
35 use android_security_remoteprovisioning::binder::{BinderFeatures, Strong};
36 use android_system_keystore2::aidl::android::system::keystore2::{
37 Domain::Domain, KeyDescriptor::KeyDescriptor,
38 };
39 use anyhow::{Context, Result};
40 use keystore2_crypto::parse_subject_from_certificate;
41 use std::sync::atomic::{AtomicBool, Ordering};
42
43 use crate::database::{CertificateChain, KeystoreDB, Uuid};
44 use crate::error::{self, map_or_log_err, map_rem_prov_error, Error};
45 use crate::globals::{get_keymint_device, get_remotely_provisioned_component, DB};
46 use crate::metrics_store::log_rkp_error_stats;
47 use crate::utils::{watchdog as wd, Asp};
48 use android_security_metrics::aidl::android::security::metrics::RkpError::RkpError as MetricsRkpError;
49
50 /// Contains helper functions to check if remote provisioning is enabled on the system and, if so,
51 /// to assign and retrieve attestation keys and certificate chains.
52 #[derive(Default)]
53 pub struct RemProvState {
54 security_level: SecurityLevel,
55 km_uuid: Uuid,
56 is_hal_present: AtomicBool,
57 }
58
59 impl RemProvState {
60 /// Creates a RemProvState struct.
new(security_level: SecurityLevel, km_uuid: Uuid) -> Self61 pub fn new(security_level: SecurityLevel, km_uuid: Uuid) -> Self {
62 Self { security_level, km_uuid, is_hal_present: AtomicBool::new(true) }
63 }
64
65 /// Checks if remote provisioning is enabled and partially caches the result. On a hybrid system
66 /// remote provisioning can flip from being disabled to enabled depending on responses from the
67 /// server, so unfortunately caching the presence or absence of the HAL is not enough to fully
68 /// make decisions about the state of remote provisioning during runtime.
check_rem_prov_enabled(&self, db: &mut KeystoreDB) -> Result<bool>69 fn check_rem_prov_enabled(&self, db: &mut KeystoreDB) -> Result<bool> {
70 if !self.is_hal_present.load(Ordering::Relaxed)
71 || get_remotely_provisioned_component(&self.security_level).is_err()
72 {
73 self.is_hal_present.store(false, Ordering::Relaxed);
74 return Ok(false);
75 }
76 // To check if remote provisioning is enabled on a system that supports both remote
77 // provisioning and factory provisioned keys, we only need to check if there are any
78 // keys at all generated to indicate if the app has gotten the signal to begin filling
79 // the key pool from the server.
80 let pool_status = db
81 .get_attestation_pool_status(0 /* date */, &self.km_uuid)
82 .context("In check_rem_prov_enabled: failed to get attestation pool status.")?;
83 Ok(pool_status.total != 0)
84 }
85
86 /// Fetches a remote provisioning attestation key and certificate chain inside of the
87 /// returned `CertificateChain` struct if one exists for the given caller_uid. If one has not
88 /// been assigned, this function will assign it. If there are no signed attestation keys
89 /// available to be assigned, it will return the ResponseCode `OUT_OF_KEYS`
get_rem_prov_attest_key( &self, key: &KeyDescriptor, caller_uid: u32, db: &mut KeystoreDB, ) -> Result<Option<CertificateChain>>90 fn get_rem_prov_attest_key(
91 &self,
92 key: &KeyDescriptor,
93 caller_uid: u32,
94 db: &mut KeystoreDB,
95 ) -> Result<Option<CertificateChain>> {
96 match key.domain {
97 Domain::APP => {
98 // Attempt to get an Attestation Key once. If it fails, then the app doesn't
99 // have a valid chain assigned to it. The helper function will return None after
100 // attempting to assign a key. An error will be thrown if the pool is simply out
101 // of usable keys. Then another attempt to fetch the just-assigned key will be
102 // made. If this fails too, something is very wrong.
103 self.get_rem_prov_attest_key_helper(key, caller_uid, db)
104 .context("In get_rem_prov_attest_key: Failed to get a key")?
105 .map_or_else(
106 || self.get_rem_prov_attest_key_helper(key, caller_uid, db),
107 |v| Ok(Some(v)),
108 )
109 .context(concat!(
110 "In get_rem_prov_attest_key: Failed to get a key after",
111 "attempting to assign one."
112 ))?
113 .map_or_else(
114 || {
115 Err(Error::sys()).context(concat!(
116 "In get_rem_prov_attest_key: Attempted to assign a ",
117 "key and failed silently. Something is very wrong."
118 ))
119 },
120 |cert_chain| Ok(Some(cert_chain)),
121 )
122 }
123 _ => Ok(None),
124 }
125 }
126
127 /// Returns None if an AttestationKey fails to be assigned. Errors if no keys are available.
get_rem_prov_attest_key_helper( &self, key: &KeyDescriptor, caller_uid: u32, db: &mut KeystoreDB, ) -> Result<Option<CertificateChain>>128 fn get_rem_prov_attest_key_helper(
129 &self,
130 key: &KeyDescriptor,
131 caller_uid: u32,
132 db: &mut KeystoreDB,
133 ) -> Result<Option<CertificateChain>> {
134 let cert_chain = db
135 .retrieve_attestation_key_and_cert_chain(key.domain, caller_uid as i64, &self.km_uuid)
136 .context("In get_rem_prov_attest_key_helper: Failed to retrieve a key + cert chain")?;
137 match cert_chain {
138 Some(cert_chain) => Ok(Some(cert_chain)),
139 // Either this app needs to be assigned a key, or the pool is empty. An error will
140 // be thrown if there is no key available to assign. This will indicate that the app
141 // should be nudged to provision more keys so keystore can retry.
142 None => {
143 db.assign_attestation_key(key.domain, caller_uid as i64, &self.km_uuid)
144 .context("In get_rem_prov_attest_key_helper: Failed to assign a key")?;
145 Ok(None)
146 }
147 }
148 }
149
is_asymmetric_key(&self, params: &[KeyParameter]) -> bool150 fn is_asymmetric_key(&self, params: &[KeyParameter]) -> bool {
151 params.iter().any(|kp| {
152 matches!(
153 kp,
154 KeyParameter {
155 tag: Tag::ALGORITHM,
156 value: KeyParameterValue::Algorithm(Algorithm::RSA)
157 } | KeyParameter {
158 tag: Tag::ALGORITHM,
159 value: KeyParameterValue::Algorithm(Algorithm::EC)
160 }
161 )
162 })
163 }
164
165 /// Checks to see (1) if the key in question should be attested to based on the algorithm and
166 /// (2) if remote provisioning is present and enabled on the system. If these conditions are
167 /// met, it makes an attempt to fetch the attestation key assigned to the `caller_uid`.
168 ///
169 /// It returns the ResponseCode `OUT_OF_KEYS` if there is not one key currently assigned to the
170 /// `caller_uid` and there are none available to assign.
get_remotely_provisioned_attestation_key_and_certs( &self, key: &KeyDescriptor, caller_uid: u32, params: &[KeyParameter], db: &mut KeystoreDB, ) -> Result<Option<(AttestationKey, Certificate)>>171 pub fn get_remotely_provisioned_attestation_key_and_certs(
172 &self,
173 key: &KeyDescriptor,
174 caller_uid: u32,
175 params: &[KeyParameter],
176 db: &mut KeystoreDB,
177 ) -> Result<Option<(AttestationKey, Certificate)>> {
178 if !self.is_asymmetric_key(params) || !self.check_rem_prov_enabled(db)? {
179 // There is no remote provisioning component for this security level on the
180 // device. Return None so the underlying KM instance knows to use its
181 // factory provisioned key instead. Alternatively, it's not an asymmetric key
182 // and therefore will not be attested.
183 Ok(None)
184 } else {
185 match self.get_rem_prov_attest_key(&key, caller_uid, db) {
186 Err(e) => {
187 log::error!(
188 concat!(
189 "In get_remote_provisioning_key_and_certs: Failed to get ",
190 "attestation key. {:?}"
191 ),
192 e
193 );
194 log_rkp_error_stats(MetricsRkpError::FALL_BACK_DURING_HYBRID);
195 Ok(None)
196 }
197 Ok(v) => match v {
198 Some(cert_chain) => Ok(Some((
199 AttestationKey {
200 keyBlob: cert_chain.private_key.to_vec(),
201 attestKeyParams: vec![],
202 issuerSubjectName: parse_subject_from_certificate(
203 &cert_chain.batch_cert,
204 )
205 .context(concat!(
206 "In get_remote_provisioning_key_and_certs: Failed to ",
207 "parse subject."
208 ))?,
209 },
210 Certificate { encodedCertificate: cert_chain.cert_chain },
211 ))),
212 None => Ok(None),
213 },
214 }
215 }
216 }
217 }
218 /// Implementation of the IRemoteProvisioning service.
219 #[derive(Default)]
220 pub struct RemoteProvisioningService {
221 device_by_sec_level: HashMap<SecurityLevel, Asp>,
222 curve_by_sec_level: HashMap<SecurityLevel, i32>,
223 }
224
225 impl RemoteProvisioningService {
get_dev_by_sec_level( &self, sec_level: &SecurityLevel, ) -> Result<Strong<dyn IRemotelyProvisionedComponent>>226 fn get_dev_by_sec_level(
227 &self,
228 sec_level: &SecurityLevel,
229 ) -> Result<Strong<dyn IRemotelyProvisionedComponent>> {
230 if let Some(dev) = self.device_by_sec_level.get(sec_level) {
231 dev.get_interface().context("In get_dev_by_sec_level.")
232 } else {
233 Err(error::Error::sys()).context(concat!(
234 "In get_dev_by_sec_level: Remote instance for requested security level",
235 " not found."
236 ))
237 }
238 }
239
240 /// Creates a new instance of the remote provisioning service
new_native_binder() -> Result<Strong<dyn IRemoteProvisioning>>241 pub fn new_native_binder() -> Result<Strong<dyn IRemoteProvisioning>> {
242 let mut result: Self = Default::default();
243 let dev = get_remotely_provisioned_component(&SecurityLevel::TRUSTED_ENVIRONMENT)
244 .context("In new_native_binder: Failed to get TEE Remote Provisioner instance.")?;
245 let rkp_tee_dev: Strong<dyn IRemotelyProvisionedComponent> = dev.get_interface()?;
246 result.curve_by_sec_level.insert(
247 SecurityLevel::TRUSTED_ENVIRONMENT,
248 rkp_tee_dev
249 .getHardwareInfo()
250 .context("In new_native_binder: Failed to get hardware info for the TEE.")?
251 .supportedEekCurve,
252 );
253 result.device_by_sec_level.insert(SecurityLevel::TRUSTED_ENVIRONMENT, dev);
254 if let Ok(dev) = get_remotely_provisioned_component(&SecurityLevel::STRONGBOX) {
255 let rkp_sb_dev: Strong<dyn IRemotelyProvisionedComponent> = dev.get_interface()?;
256 result.curve_by_sec_level.insert(
257 SecurityLevel::STRONGBOX,
258 rkp_sb_dev
259 .getHardwareInfo()
260 .context("In new_native_binder: Failed to get hardware info for StrongBox.")?
261 .supportedEekCurve,
262 );
263 result.device_by_sec_level.insert(SecurityLevel::STRONGBOX, dev);
264 }
265 Ok(BnRemoteProvisioning::new_binder(result, BinderFeatures::default()))
266 }
267
268 /// Generates a CBOR blob which will be assembled by the calling code into a larger
269 /// CBOR blob intended for delivery to a provisioning serever. This blob will contain
270 /// `num_csr` certificate signing requests for attestation keys generated in the TEE,
271 /// along with a server provided `eek` and `challenge`. The endpoint encryption key will
272 /// be used to encrypt the sensitive contents being transmitted to the server, and the
273 /// challenge will ensure freshness. A `test_mode` flag will instruct the remote provisioning
274 /// HAL if it is okay to accept EEKs that aren't signed by something that chains back to the
275 /// baked in root of trust in the underlying IRemotelyProvisionedComponent instance.
276 #[allow(clippy::too_many_arguments)]
generate_csr( &self, test_mode: bool, num_csr: i32, eek: &[u8], challenge: &[u8], sec_level: SecurityLevel, protected_data: &mut ProtectedData, device_info: &mut DeviceInfo, ) -> Result<Vec<u8>>277 pub fn generate_csr(
278 &self,
279 test_mode: bool,
280 num_csr: i32,
281 eek: &[u8],
282 challenge: &[u8],
283 sec_level: SecurityLevel,
284 protected_data: &mut ProtectedData,
285 device_info: &mut DeviceInfo,
286 ) -> Result<Vec<u8>> {
287 let dev = self.get_dev_by_sec_level(&sec_level)?;
288 let (_, _, uuid) = get_keymint_device(&sec_level)?;
289 let keys_to_sign = DB.with::<_, Result<Vec<MacedPublicKey>>>(|db| {
290 let mut db = db.borrow_mut();
291 Ok(db
292 .fetch_unsigned_attestation_keys(num_csr, &uuid)?
293 .iter()
294 .map(|key| MacedPublicKey { macedKey: key.to_vec() })
295 .collect())
296 })?;
297 let mut mac = map_rem_prov_error(dev.generateCertificateRequest(
298 test_mode,
299 &keys_to_sign,
300 eek,
301 challenge,
302 device_info,
303 protected_data,
304 ))
305 .context("In generate_csr: Failed to generate csr")?;
306 // TODO(b/180392379): Replace this manual CBOR generation with the cbor-serde crate as well.
307 // This generates an array consisting of the mac and the public key Maps.
308 // Just generate the actual MacedPublicKeys structure when the crate is
309 // available.
310 let mut cose_mac_0: Vec<u8> = vec![
311 (0b100_00000 | (keys_to_sign.len() + 1)) as u8,
312 0b010_11000, // mac
313 (mac.len() as u8),
314 ];
315 cose_mac_0.append(&mut mac);
316 // If this is a test mode key, there is an extra 6 bytes added as an additional entry in
317 // the COSE_Key struct to denote that.
318 let test_mode_entry_shift = if test_mode { 0 } else { 6 };
319 let byte_dist_mac0_payload = 8;
320 let cose_key_size = 83 - test_mode_entry_shift;
321 for maced_public_key in keys_to_sign {
322 if maced_public_key.macedKey.len() > cose_key_size + byte_dist_mac0_payload {
323 cose_mac_0.extend_from_slice(
324 &maced_public_key.macedKey
325 [byte_dist_mac0_payload..cose_key_size + byte_dist_mac0_payload],
326 );
327 }
328 }
329 Ok(cose_mac_0)
330 }
331
332 /// Provisions a certificate chain for a key whose CSR was included in generate_csr. The
333 /// `public_key` is used to index into the SQL database in order to insert the `certs` blob
334 /// which represents a PEM encoded X.509 certificate chain. The `expiration_date` is provided
335 /// as a convenience from the caller to avoid having to parse the certificates semantically
336 /// here.
provision_cert_chain( &self, public_key: &[u8], batch_cert: &[u8], certs: &[u8], expiration_date: i64, sec_level: SecurityLevel, ) -> Result<()>337 pub fn provision_cert_chain(
338 &self,
339 public_key: &[u8],
340 batch_cert: &[u8],
341 certs: &[u8],
342 expiration_date: i64,
343 sec_level: SecurityLevel,
344 ) -> Result<()> {
345 DB.with::<_, Result<()>>(|db| {
346 let mut db = db.borrow_mut();
347 let (_, _, uuid) = get_keymint_device(&sec_level)?;
348 db.store_signed_attestation_certificate_chain(
349 public_key,
350 batch_cert,
351 certs, /* DER encoded certificate chain */
352 expiration_date,
353 &uuid,
354 )
355 })
356 }
357
358 /// Submits a request to the Remote Provisioner HAL to generate a signing key pair.
359 /// `is_test_mode` indicates whether or not the returned public key should be marked as being
360 /// for testing in order to differentiate them from private keys. If the call is successful,
361 /// the key pair is then added to the database.
generate_key_pair(&self, is_test_mode: bool, sec_level: SecurityLevel) -> Result<()>362 pub fn generate_key_pair(&self, is_test_mode: bool, sec_level: SecurityLevel) -> Result<()> {
363 let (_, _, uuid) = get_keymint_device(&sec_level)?;
364 let dev = self.get_dev_by_sec_level(&sec_level)?;
365 let mut maced_key = MacedPublicKey { macedKey: Vec::new() };
366 let priv_key =
367 map_rem_prov_error(dev.generateEcdsaP256KeyPair(is_test_mode, &mut maced_key))
368 .context("In generate_key_pair: Failed to generated ECDSA keypair.")?;
369 // TODO(b/180392379): This is a brittle hack that relies on the consistent formatting of
370 // the returned CBOR blob in order to extract the public key.
371 let data = &maced_key.macedKey;
372 if data.len() < 85 {
373 return Err(error::Error::sys()).context(concat!(
374 "In generate_key_pair: CBOR blob returned from",
375 "RemotelyProvisionedComponent is definitely malformatted or empty."
376 ));
377 }
378 let mut raw_key: Vec<u8> = vec![0; 64];
379 raw_key[0..32].clone_from_slice(&data[18..18 + 32]);
380 raw_key[32..64].clone_from_slice(&data[53..53 + 32]);
381 DB.with::<_, Result<()>>(|db| {
382 let mut db = db.borrow_mut();
383 db.create_attestation_key_entry(&maced_key.macedKey, &raw_key, &priv_key, &uuid)
384 })
385 }
386
387 /// Checks the security level of each available IRemotelyProvisionedComponent hal and returns
388 /// all levels in an array to the caller.
get_implementation_info(&self) -> Result<Vec<ImplInfo>>389 pub fn get_implementation_info(&self) -> Result<Vec<ImplInfo>> {
390 Ok(self
391 .curve_by_sec_level
392 .iter()
393 .map(|(sec_level, curve)| ImplInfo { secLevel: *sec_level, supportedCurve: *curve })
394 .collect())
395 }
396
397 /// Deletes all attestation keys generated by the IRemotelyProvisionedComponent from the device,
398 /// regardless of what state of the attestation key lifecycle they were in.
delete_all_keys(&self) -> Result<i64>399 pub fn delete_all_keys(&self) -> Result<i64> {
400 DB.with::<_, Result<i64>>(|db| {
401 let mut db = db.borrow_mut();
402 db.delete_all_attestation_keys()
403 })
404 }
405 }
406
407 /// Populates the AttestationPoolStatus parcelable with information about how many
408 /// certs will be expiring by the date provided in `expired_by` along with how many
409 /// keys have not yet been assigned.
get_pool_status(expired_by: i64, sec_level: SecurityLevel) -> Result<AttestationPoolStatus>410 pub fn get_pool_status(expired_by: i64, sec_level: SecurityLevel) -> Result<AttestationPoolStatus> {
411 let (_, _, uuid) = get_keymint_device(&sec_level)?;
412 DB.with::<_, Result<AttestationPoolStatus>>(|db| {
413 let mut db = db.borrow_mut();
414 // delete_expired_attestation_keys is always safe to call, and will remove anything
415 // older than the date at the time of calling. No work should be done on the
416 // attestation keys unless the pool status is checked first, so this call should be
417 // enough to routinely clean out expired keys.
418 db.delete_expired_attestation_keys()?;
419 db.get_attestation_pool_status(expired_by, &uuid)
420 })
421 }
422
423 impl binder::Interface for RemoteProvisioningService {}
424
425 // Implementation of IRemoteProvisioning. See AIDL spec at
426 // :aidl/android/security/remoteprovisioning/IRemoteProvisioning.aidl
427 impl IRemoteProvisioning for RemoteProvisioningService {
getPoolStatus( &self, expired_by: i64, sec_level: SecurityLevel, ) -> binder::public_api::Result<AttestationPoolStatus>428 fn getPoolStatus(
429 &self,
430 expired_by: i64,
431 sec_level: SecurityLevel,
432 ) -> binder::public_api::Result<AttestationPoolStatus> {
433 let _wp = wd::watch_millis("IRemoteProvisioning::getPoolStatus", 500);
434 map_or_log_err(get_pool_status(expired_by, sec_level), Ok)
435 }
436
generateCsr( &self, test_mode: bool, num_csr: i32, eek: &[u8], challenge: &[u8], sec_level: SecurityLevel, protected_data: &mut ProtectedData, device_info: &mut DeviceInfo, ) -> binder::public_api::Result<Vec<u8>>437 fn generateCsr(
438 &self,
439 test_mode: bool,
440 num_csr: i32,
441 eek: &[u8],
442 challenge: &[u8],
443 sec_level: SecurityLevel,
444 protected_data: &mut ProtectedData,
445 device_info: &mut DeviceInfo,
446 ) -> binder::public_api::Result<Vec<u8>> {
447 let _wp = wd::watch_millis("IRemoteProvisioning::generateCsr", 500);
448 map_or_log_err(
449 self.generate_csr(
450 test_mode,
451 num_csr,
452 eek,
453 challenge,
454 sec_level,
455 protected_data,
456 device_info,
457 ),
458 Ok,
459 )
460 }
461
provisionCertChain( &self, public_key: &[u8], batch_cert: &[u8], certs: &[u8], expiration_date: i64, sec_level: SecurityLevel, ) -> binder::public_api::Result<()>462 fn provisionCertChain(
463 &self,
464 public_key: &[u8],
465 batch_cert: &[u8],
466 certs: &[u8],
467 expiration_date: i64,
468 sec_level: SecurityLevel,
469 ) -> binder::public_api::Result<()> {
470 let _wp = wd::watch_millis("IRemoteProvisioning::provisionCertChain", 500);
471 map_or_log_err(
472 self.provision_cert_chain(public_key, batch_cert, certs, expiration_date, sec_level),
473 Ok,
474 )
475 }
476
generateKeyPair( &self, is_test_mode: bool, sec_level: SecurityLevel, ) -> binder::public_api::Result<()>477 fn generateKeyPair(
478 &self,
479 is_test_mode: bool,
480 sec_level: SecurityLevel,
481 ) -> binder::public_api::Result<()> {
482 let _wp = wd::watch_millis("IRemoteProvisioning::generateKeyPair", 500);
483 map_or_log_err(self.generate_key_pair(is_test_mode, sec_level), Ok)
484 }
485
getImplementationInfo(&self) -> binder::public_api::Result<Vec<ImplInfo>>486 fn getImplementationInfo(&self) -> binder::public_api::Result<Vec<ImplInfo>> {
487 let _wp = wd::watch_millis("IRemoteProvisioning::getSecurityLevels", 500);
488 map_or_log_err(self.get_implementation_info(), Ok)
489 }
490
deleteAllKeys(&self) -> binder::public_api::Result<i64>491 fn deleteAllKeys(&self) -> binder::public_api::Result<i64> {
492 let _wp = wd::watch_millis("IRemoteProvisioning::deleteAllKeys", 500);
493 map_or_log_err(self.delete_all_keys(), Ok)
494 }
495 }
496