keystore2: Support for RKPD attestation keys
Bug: 261214100
Test: TODO
Change-Id: I2234fb01179aec212811b864d68e5f94772c2538
diff --git a/keystore2/src/attestation_key_utils.rs b/keystore2/src/attestation_key_utils.rs
index 94f3e4c..d01cf86 100644
--- a/keystore2/src/attestation_key_utils.rs
+++ b/keystore2/src/attestation_key_utils.rs
@@ -40,6 +40,10 @@
attestation_key: AttestationKey,
attestation_certs: Certificate,
},
+ RkpdProvisioned {
+ attestation_key: AttestationKey,
+ attestation_certs: Certificate,
+ },
UserGenerated {
key_id_guard: KeyIdGuard,
blob: Vec<u8>,
@@ -48,6 +52,12 @@
},
}
+fn use_rkpd() -> bool {
+ let property_name = "persist.device_config.remote_key_provisioning_native.enable_rkpd";
+ let default_value = false;
+ rustutils::system_properties::read_bool(property_name, default_value).unwrap_or(default_value)
+}
+
/// This function loads and, optionally, assigns the caller's remote provisioned
/// attestation key if a challenge is present. Alternatively, if `attest_key_descriptor` is given,
/// it loads the user generated attestation key from the database.
@@ -64,18 +74,34 @@
params.iter().any(|kp| kp.tag == Tag::DEVICE_UNIQUE_ATTESTATION);
match attest_key_descriptor {
// Do not select an RKP key if DEVICE_UNIQUE_ATTESTATION is present.
- None if challenge_present && !is_device_unique_attestation => rem_prov_state
- .get_remotely_provisioned_attestation_key_and_certs(key, caller_uid, params, db)
- .context(ks_err!("Trying to get remotely provisioned attestation key."))
- .map(|result| {
- result.map(|(key_id_guard, attestation_key, attestation_certs)| {
- AttestationKeyInfo::RemoteProvisioned {
- key_id_guard,
- attestation_key,
- attestation_certs,
- }
- })
- }),
+ None if challenge_present && !is_device_unique_attestation => {
+ if use_rkpd() {
+ rem_prov_state
+ .get_rkpd_attestation_key_and_certs(key, caller_uid, params)
+ .context(ks_err!("Trying to get attestation key from RKPD."))
+ .map(|result| {
+ result.map(|(attestation_key, attestation_certs)| {
+ AttestationKeyInfo::RkpdProvisioned {
+ attestation_key,
+ attestation_certs,
+ }
+ })
+ })
+ } else {
+ rem_prov_state
+ .get_remotely_provisioned_attestation_key_and_certs(key, caller_uid, params, db)
+ .context(ks_err!("Trying to get remotely provisioned attestation key."))
+ .map(|result| {
+ result.map(|(key_id_guard, attestation_key, attestation_certs)| {
+ AttestationKeyInfo::RemoteProvisioned {
+ key_id_guard,
+ attestation_key,
+ attestation_certs,
+ }
+ })
+ })
+ }
+ }
None => Ok(None),
Some(attest_key) => get_user_generated_attestation_key(attest_key, caller_uid, db)
.context(ks_err!("Trying to load attest key"))
diff --git a/keystore2/src/remote_provisioning.rs b/keystore2/src/remote_provisioning.rs
index fec1b92..cb2962a 100644
--- a/keystore2/src/remote_provisioning.rs
+++ b/keystore2/src/remote_provisioning.rs
@@ -53,6 +53,7 @@
use crate::ks_err;
use crate::metrics_store::log_rkp_error_stats;
use crate::permission::KeystorePerm;
+use crate::rkpd_client::get_rkpd_attestation_key;
use crate::utils::{check_keystore_permission, watchdog as wd};
use android_security_metrics::aidl::android::security::metrics::RkpError::RkpError as MetricsRkpError;
@@ -184,7 +185,47 @@
}
}
}
+
+ /// Fetches attestation key and corresponding certificates from RKPD.
+ pub fn get_rkpd_attestation_key_and_certs(
+ &self,
+ key: &KeyDescriptor,
+ caller_uid: u32,
+ params: &[KeyParameter],
+ ) -> Result<Option<(AttestationKey, Certificate)>> {
+ if !self.is_asymmetric_key(params) || key.domain != Domain::APP {
+ Ok(None)
+ } else {
+ match get_rkpd_attestation_key(&self.security_level, caller_uid) {
+ Err(e) => {
+ if self.is_rkp_only() {
+ log::error!("Error occurred: {:?}", e);
+ return Err(e);
+ }
+ log::warn!("Error occurred: {:?}", e);
+ log_rkp_error_stats(
+ MetricsRkpError::FALL_BACK_DURING_HYBRID,
+ &self.security_level,
+ );
+ Ok(None)
+ }
+ Ok(rkpd_key) => Ok(Some((
+ AttestationKey {
+ keyBlob: rkpd_key.keyBlob,
+ attestKeyParams: vec![],
+ // Batch certificate is at the beginning of the certificate chain.
+ issuerSubjectName: parse_subject_from_certificate(
+ &rkpd_key.encodedCertChain,
+ )
+ .context(ks_err!("Failed to parse subject."))?,
+ },
+ Certificate { encodedCertificate: rkpd_key.encodedCertChain },
+ ))),
+ }
+ }
+ }
}
+
/// Implementation of the IRemoteProvisioning service.
#[derive(Default)]
pub struct RemoteProvisioningService {
diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs
index 66fcb26..b928fb0 100644
--- a/keystore2/src/security_level.rs
+++ b/keystore2/src/security_level.rs
@@ -26,6 +26,7 @@
use crate::ks_err;
use crate::metrics_store::log_key_creation_event_stats;
use crate::remote_provisioning::RemProvState;
+use crate::rkpd_client::store_rkpd_attestation_key;
use crate::super_key::{KeyBlob, SuperKeyManager};
use crate::utils::{
check_device_attestation_permissions, check_key_permission,
@@ -616,6 +617,30 @@
result.certificateChain.push(attestation_certs);
result
}),
+ Some(AttestationKeyInfo::RkpdProvisioned { attestation_key, attestation_certs }) => {
+ self.upgrade_rkpd_keyblob_if_required_with(&attestation_key.keyBlob, &[], |blob| {
+ map_km_error({
+ let _wp = self.watch_millis(
+ concat!(
+ "In KeystoreSecurityLevel::generate_key (RkpdProvisioned): ",
+ "calling generate_key.",
+ ),
+ 5000, // Generate can take a little longer.
+ );
+ let dynamic_attest_key = Some(AttestationKey {
+ keyBlob: blob.to_vec(),
+ attestKeyParams: vec![],
+ issuerSubjectName: attestation_key.issuerSubjectName.clone(),
+ });
+ self.keymint.generateKey(¶ms, dynamic_attest_key.as_ref())
+ })
+ })
+ .context("While generating Key with remote provisioned attestation key.")
+ .map(|(mut result, _)| {
+ result.certificateChain.push(attestation_certs);
+ result
+ })
+ }
None => map_km_error({
let _wp = self.watch_millis(
concat!(
@@ -888,6 +913,28 @@
Ok((v, upgraded_blob))
}
+ fn upgrade_rkpd_keyblob_if_required_with<T, F>(
+ &self,
+ key_blob: &[u8],
+ params: &[KeyParameter],
+ f: F,
+ ) -> Result<(T, Option<Vec<u8>>)>
+ where
+ F: Fn(&[u8]) -> Result<T, Error>,
+ {
+ crate::utils::upgrade_keyblob_if_required_with(
+ &*self.keymint,
+ key_blob,
+ params,
+ f,
+ |upgraded_blob| {
+ store_rkpd_attestation_key(&self.security_level, key_blob, upgraded_blob)
+ .context(ks_err!("Failed store_rkpd_attestation_key()."))
+ },
+ )
+ .context(ks_err!())
+ }
+
fn convert_storage_key_to_ephemeral(
&self,
storage_key: &KeyDescriptor,