Merge "Start the remoteprovisioning service"
diff --git a/keystore2/aidl/android/security/remoteprovisioning/IRemoteProvisioning.aidl b/keystore2/aidl/android/security/remoteprovisioning/IRemoteProvisioning.aidl
index d045345..0d4c30f 100644
--- a/keystore2/aidl/android/security/remoteprovisioning/IRemoteProvisioning.aidl
+++ b/keystore2/aidl/android/security/remoteprovisioning/IRemoteProvisioning.aidl
@@ -16,6 +16,7 @@
package android.security.remoteprovisioning;
+import android.hardware.security.keymint.ProtectedData;
import android.hardware.security.keymint.SecurityLevel;
import android.security.remoteprovisioning.AttestationPoolStatus;
@@ -83,10 +84,13 @@
* @param secLevel The security level to specify which KM instance from which to generate a
* CSR.
*
- * @return A CBOR blob composed of various encrypted/signed elements from the TA in a byte[]
+ * @param protectedData The encrypted CBOR blob generated by the remote provisioner
+ *
+ * @return A CBOR blob composed of various elements required by the server to verify the
+ * request.
*/
byte[] generateCsr(in boolean testMode, in int numCsr, in byte[] eek, in byte[] challenge,
- in SecurityLevel secLevel);
+ in SecurityLevel secLevel, out ProtectedData protectedData);
/**
* This method provides a way for the returned attestation certificate chains to be provisioned
@@ -95,7 +99,10 @@
*
* @param publicKey The raw public key encoded in the leaf certificate.
*
- * @param cert An X.509, DER encoded certificate chain.
+ * @param batchCert The batch certificate corresponding to the attestation key. Separated for
+ * the purpose of making Subject lookup for KM attestation easier.
+ *
+ * @param certs An X.509, DER encoded certificate chain for the attestation key.
*
* @param expirationDate The expiration date on the certificate chain, provided by the caller
* for convenience.
@@ -103,8 +110,8 @@
* @param secLevel The security level representing the KM instance containing the key that this
* chain corresponds to.
*/
- void provisionCertChain(in byte[] publicKey, in byte[] certs, in long expirationDate,
- in SecurityLevel secLevel);
+ void provisionCertChain(in byte[] publicKey, in byte[] batchCert, in byte[] certs,
+ in long expirationDate, in SecurityLevel secLevel);
/**
* This method allows the caller to instruct KeyStore to generate and store a key pair to be
@@ -117,4 +124,13 @@
* @param secLevel The security level to specify which KM instance should generate a key pair.
*/
void generateKeyPair(in boolean is_test_mode, in SecurityLevel secLevel);
+
+ /**
+ * This method returns the SecurityLevels of whichever instances of
+ * IRemotelyProvisionedComponent are running on the device. The RemoteProvisioner app needs to
+ * know which KM instances it should be generating and managing attestation keys for.
+ *
+ * @return The array of security levels.
+ */
+ SecurityLevel[] getSecurityLevels();
}
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index 3217857..f9710f9 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -584,6 +584,7 @@
#[allow(dead_code)]
pub struct CertificateChain {
private_key: ZVec,
+ batch_cert: ZVec,
cert_chain: ZVec,
}
@@ -1551,6 +1552,7 @@
pub fn store_signed_attestation_certificate_chain(
&mut self,
raw_public_key: &[u8],
+ batch_cert: &[u8],
cert_chain: &[u8],
expiration_date: i64,
km_uuid: &Uuid,
@@ -1609,6 +1611,8 @@
None,
)
.context("Failed to insert cert chain")?;
+ Self::set_blob_internal(&tx, key_id, SubComponentType::CERT, Some(batch_cert), None)
+ .context("Failed to insert cert")?;
Ok(()).no_gc()
})
.context("In store_signed_attestation_certificate_chain: ")
@@ -1859,19 +1863,21 @@
|row| Ok((row.get(0)?, row.get(1)?)),
)?
.collect::<rusqlite::Result<Vec<(SubComponentType, Vec<u8>)>>>()
- .context("In retrieve_attestation_key_and_cert_chain: query failed.")?;
+ .context("query failed.")?;
if rows.is_empty() {
return Ok(None).no_gc();
- } else if rows.len() != 2 {
+ } else if rows.len() != 3 {
return Err(KsError::sys()).context(format!(
concat!(
- "In retrieve_attestation_key_and_cert_chain: Expected to get a single attestation",
- "key chain but instead got {}."),
+ "Expected to get a single attestation",
+ "key, cert, and cert chain for a total of 3 entries, but instead got {}."
+ ),
rows.len()
));
}
let mut km_blob: Vec<u8> = Vec::new();
let mut cert_chain_blob: Vec<u8> = Vec::new();
+ let mut batch_cert_blob: Vec<u8> = Vec::new();
for row in rows {
let sub_type: SubComponentType = row.0;
match sub_type {
@@ -1881,15 +1887,20 @@
SubComponentType::CERT_CHAIN => {
cert_chain_blob = row.1;
}
+ SubComponentType::CERT => {
+ batch_cert_blob = row.1;
+ }
_ => Err(KsError::sys()).context("Unknown or incorrect subcomponent type.")?,
}
}
Ok(Some(CertificateChain {
private_key: ZVec::try_from(km_blob)?,
+ batch_cert: ZVec::try_from(batch_cert_blob)?,
cert_chain: ZVec::try_from(cert_chain_blob)?,
}))
.no_gc()
})
+ .context("In retrieve_attestation_key_and_cert_chain:")
}
/// Updates the alias column of the given key id `newid` with the given alias,
@@ -3133,8 +3144,9 @@
db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
assert_eq!(true, chain.is_some());
let cert_chain = chain.unwrap();
- assert_eq!(cert_chain.private_key.to_vec(), loaded_values[2]);
- assert_eq!(cert_chain.cert_chain.to_vec(), loaded_values[1]);
+ assert_eq!(cert_chain.private_key.to_vec(), loaded_values.priv_key);
+ assert_eq!(cert_chain.batch_cert.to_vec(), loaded_values.batch_cert);
+ assert_eq!(cert_chain.cert_chain.to_vec(), loaded_values.cert_chain);
Ok(())
}
@@ -3169,6 +3181,7 @@
let private_key: Vec<u8> = vec![0x04, 0x05, 0x06];
let raw_public_key: Vec<u8> = vec![0x07, 0x08, 0x09];
let cert_chain: Vec<u8> = vec![0x0a, 0x0b, 0x0c];
+ let batch_cert: Vec<u8> = vec![0x0d, 0x0e, 0x0f];
db.create_attestation_key_entry(
&public_key,
&raw_public_key,
@@ -3181,6 +3194,7 @@
assert_eq!(status.total, 4);
db.store_signed_attestation_certificate_chain(
&raw_public_key,
+ &batch_cert,
&cert_chain,
20,
&KEYSTORE_UUID,
@@ -3215,9 +3229,9 @@
.conn
.query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
.expect("Failed to get blob entry row count.");
- // We expect 6 rows here because there are two blobs per attestation key, i.e.,
- // One key and one certificate.
- assert_eq!(blob_entry_row_count, 6);
+ // We expect 9 rows here because there are three blobs per attestation key, i.e.,
+ // one key, one certificate chain, and one certificate.
+ assert_eq!(blob_entry_row_count, 9);
assert_eq!(db.delete_expired_attestation_keys()?, 2);
@@ -3225,8 +3239,9 @@
db.retrieve_attestation_key_and_cert_chain(Domain::APP, namespace, &KEYSTORE_UUID)?;
assert!(cert_chain.is_some());
let value = cert_chain.unwrap();
- assert_eq!(entry_values[1], value.cert_chain.to_vec());
- assert_eq!(entry_values[2], value.private_key.to_vec());
+ assert_eq!(entry_values.batch_cert, value.batch_cert.to_vec());
+ assert_eq!(entry_values.cert_chain, value.cert_chain.to_vec());
+ assert_eq!(entry_values.priv_key, value.private_key.to_vec());
cert_chain = db.retrieve_attestation_key_and_cert_chain(
Domain::APP,
@@ -3248,9 +3263,9 @@
.conn
.query_row("SELECT COUNT(id) FROM persistent.blobentry;", NO_PARAMS, |row| row.get(0))
.expect("Failed to get blob entry row count.");
- // There shound be 2 blob entries left, because we deleted two of the attestation
- // key entries with two blobs each.
- assert_eq!(blob_entry_row_count, 2);
+ // There shound be 3 blob entries left, because we deleted two of the attestation
+ // key entries with three blobs each.
+ assert_eq!(blob_entry_row_count, 3);
Ok(())
}
@@ -4323,30 +4338,33 @@
.collect::<Result<Vec<_>>>()
}
+ struct RemoteProvValues {
+ cert_chain: Vec<u8>,
+ priv_key: Vec<u8>,
+ batch_cert: Vec<u8>,
+ }
+
fn load_attestation_key_pool(
db: &mut KeystoreDB,
expiration_date: i64,
namespace: i64,
base_byte: u8,
- ) -> Result<Vec<Vec<u8>>> {
- let mut chain: Vec<Vec<u8>> = Vec::new();
+ ) -> Result<RemoteProvValues> {
let public_key: Vec<u8> = vec![base_byte, 0x02 * base_byte];
let cert_chain: Vec<u8> = vec![0x03 * base_byte, 0x04 * base_byte];
let priv_key: Vec<u8> = vec![0x05 * base_byte, 0x06 * base_byte];
let raw_public_key: Vec<u8> = vec![0x0b * base_byte, 0x0c * base_byte];
+ let batch_cert: Vec<u8> = vec![base_byte * 0x0d, base_byte * 0x0e];
db.create_attestation_key_entry(&public_key, &raw_public_key, &priv_key, &KEYSTORE_UUID)?;
db.store_signed_attestation_certificate_chain(
&raw_public_key,
+ &batch_cert,
&cert_chain,
expiration_date,
&KEYSTORE_UUID,
)?;
db.assign_attestation_key(Domain::APP, namespace, &KEYSTORE_UUID)?;
- chain.push(public_key);
- chain.push(cert_chain);
- chain.push(priv_key);
- chain.push(raw_public_key);
- Ok(chain)
+ Ok(RemoteProvValues { cert_chain, priv_key, batch_cert })
}
// Note: The parameters and SecurityLevel associations are nonsensical. This
diff --git a/keystore2/src/error.rs b/keystore2/src/error.rs
index 7227f62..d67f5f4 100644
--- a/keystore2/src/error.rs
+++ b/keystore2/src/error.rs
@@ -57,6 +57,10 @@
/// Wraps a Binder status code.
#[error("Binder transaction error {0:?}")]
BinderTransaction(StatusCode),
+ /// Wraps a Remote Provisioning ErrorCode as defined by the IRemotelyProvisionedComponent
+ /// AIDL interface spec.
+ #[error("Error::Rp({0:?})")]
+ Rp(ErrorCode),
}
impl Error {
@@ -101,6 +105,16 @@
})
}
+/// Helper function to map the binder status we get from calls into a RemotelyProvisionedComponent
+/// to a Keystore Error. We don't create an anyhow error here to make
+/// it easier to evaluate service specific errors.
+pub fn map_rem_prov_error<T>(r: BinderResult<T>) -> Result<T, Error> {
+ r.map_err(|s| match s.exception_code() {
+ ExceptionCode::SERVICE_SPECIFIC => Error::Rp(ErrorCode(s.service_specific_error())),
+ e_code => Error::Binder(e_code, 0),
+ })
+}
+
/// This function is similar to map_km_error only that we don't expect
/// any KeyMint error codes, we simply preserve the exception code and optional
/// service specific exception.
@@ -164,6 +178,7 @@
let rc = match root_cause.downcast_ref::<Error>() {
Some(Error::Rc(rcode)) => rcode.0,
Some(Error::Km(ec)) => ec.0,
+ Some(Error::Rp(_)) => ResponseCode::SYSTEM_ERROR.0,
// If an Error::Binder reaches this stage we report a system error.
// The exception code and possible service specific error will be
// printed in the error log above.
diff --git a/keystore2/src/globals.rs b/keystore2/src/globals.rs
index 8cc0106..9668ee3 100644
--- a/keystore2/src/globals.rs
+++ b/keystore2/src/globals.rs
@@ -29,8 +29,8 @@
};
use crate::{enforcements::Enforcements, error::map_km_error};
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
- IKeyMintDevice::IKeyMintDevice, KeyMintHardwareInfo::KeyMintHardwareInfo,
- SecurityLevel::SecurityLevel,
+ IKeyMintDevice::IKeyMintDevice, IRemotelyProvisionedComponent::IRemotelyProvisionedComponent,
+ KeyMintHardwareInfo::KeyMintHardwareInfo, SecurityLevel::SecurityLevel,
};
use android_hardware_security_keymint::binder::{StatusCode, Strong};
use android_security_compat::aidl::android::security::compat::IKeystoreCompatService::IKeystoreCompatService;
@@ -128,6 +128,21 @@
}
}
+#[derive(Default)]
+struct RemotelyProvisionedDevicesMap {
+ devices_by_sec_level: HashMap<SecurityLevel, Asp>,
+}
+
+impl RemotelyProvisionedDevicesMap {
+ fn dev_by_sec_level(&self, sec_level: &SecurityLevel) -> Option<Asp> {
+ self.devices_by_sec_level.get(sec_level).map(|dev| (*dev).clone())
+ }
+
+ fn insert(&mut self, sec_level: SecurityLevel, dev: Asp) {
+ self.devices_by_sec_level.insert(sec_level, dev);
+ }
+}
+
lazy_static! {
/// The path where keystore stores all its keys.
pub static ref DB_PATH: Mutex<PathBuf> = Mutex::new(
@@ -138,6 +153,8 @@
static ref KEY_MINT_DEVICES: Mutex<DevicesMap> = Default::default();
/// Timestamp service.
static ref TIME_STAMP_DEVICE: Mutex<Option<Asp>> = Default::default();
+ /// RemotelyProvisionedComponent HAL devices.
+ static ref REMOTELY_PROVISIONED_COMPONENT_DEVICES: Mutex<RemotelyProvisionedDevicesMap> = Default::default();
/// A single on-demand worker thread that handles deferred tasks with two different
/// priorities.
pub static ref ASYNC_TASK: Arc<AsyncTask> = Default::default();
@@ -276,3 +293,45 @@
Ok(dev)
}
}
+
+static REMOTE_PROVISIONING_HAL_SERVICE_NAME: &str =
+ "android.hardware.security.keymint.IRemotelyProvisionedComponent";
+
+fn connect_remotely_provisioned_component(security_level: &SecurityLevel) -> Result<Asp> {
+ let service_name = match *security_level {
+ SecurityLevel::TRUSTED_ENVIRONMENT => {
+ format!("{}/default", REMOTE_PROVISIONING_HAL_SERVICE_NAME)
+ }
+ SecurityLevel::STRONGBOX => format!("{}/strongbox", REMOTE_PROVISIONING_HAL_SERVICE_NAME),
+ _ => {
+ // Given the integration of IRemotelyProvisionedComponent with KeyMint, it is reasonable
+ // to return HARDWARE_TYPE_UNAVAILABLE as a Km error if it cannot be found.
+ return Err(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE))
+ .context("In connect_remotely_provisioned_component.");
+ }
+ };
+
+ let rem_prov_hal: Strong<dyn IRemotelyProvisionedComponent> =
+ map_binder_status_code(binder::get_interface(&service_name))
+ .context(concat!(
+ "In connect_remotely_provisioned_component: Trying to connect to",
+ " RemotelyProvisionedComponent service."
+ ))
+ .map_err(|e| e)?;
+ Ok(Asp::new(rem_prov_hal.as_binder()))
+}
+
+/// Get a remote provisiong component device for the given security level either from the cache or
+/// by making a new connection. Returns the device.
+pub fn get_remotely_provisioned_component(security_level: &SecurityLevel) -> Result<Asp> {
+ let mut devices_map = REMOTELY_PROVISIONED_COMPONENT_DEVICES.lock().unwrap();
+ if let Some(dev) = devices_map.dev_by_sec_level(&security_level) {
+ Ok(dev)
+ } else {
+ let dev = connect_remotely_provisioned_component(security_level)
+ .context("In get_remotely_provisioned_component.")?;
+ devices_map.insert(*security_level, dev);
+ // Unwrap must succeed because we just inserted it.
+ Ok(devices_map.dev_by_sec_level(security_level).unwrap())
+ }
+}
diff --git a/keystore2/src/keystore2_main.rs b/keystore2/src/keystore2_main.rs
index 30e3e22..9dc59a2 100644
--- a/keystore2/src/keystore2_main.rs
+++ b/keystore2/src/keystore2_main.rs
@@ -17,6 +17,7 @@
use keystore2::apc::ApcManager;
use keystore2::authorization::AuthorizationManager;
use keystore2::globals::ENFORCEMENTS;
+use keystore2::remote_provisioning::RemoteProvisioningService;
use keystore2::service::KeystoreService;
use keystore2::user_manager::UserManager;
use log::{error, info};
@@ -25,6 +26,7 @@
static KS2_SERVICE_NAME: &str = "android.system.keystore2";
static APC_SERVICE_NAME: &str = "android.security.apc";
static AUTHORIZATION_SERVICE_NAME: &str = "android.security.authorization";
+static REMOTE_PROVISIONING_SERVICE_NAME: &str = "android.security.remoteprovisioning";
static USER_MANAGER_SERVICE_NAME: &str = "android.security.usermanager";
/// Keystore 2.0 takes one argument which is a path indicating its designated working directory.
@@ -98,6 +100,20 @@
},
);
+ // Devices with KS2 and KM 1.0 may not have any IRemotelyProvisionedComponent HALs at all. Do
+ // not panic if new_native_binder returns failure because it could not find the TEE HAL.
+ if let Ok(remote_provisioning_service) = RemoteProvisioningService::new_native_binder() {
+ binder::add_service(
+ REMOTE_PROVISIONING_SERVICE_NAME,
+ remote_provisioning_service.as_binder(),
+ )
+ .unwrap_or_else(|e| {
+ panic!(
+ "Failed to register service {} because of {:?}.",
+ REMOTE_PROVISIONING_SERVICE_NAME, e
+ );
+ });
+ }
info!("Successfully registered Keystore 2.0 service.");
info!("Joining thread pool now.");
diff --git a/keystore2/src/remote_provisioning.rs b/keystore2/src/remote_provisioning.rs
index fe38504..d606b6a 100644
--- a/keystore2/src/remote_provisioning.rs
+++ b/keystore2/src/remote_provisioning.rs
@@ -19,28 +19,54 @@
//! certificate chains signed by some root authority and stored in a keystore SQLite
//! DB.
-use android_hardware_security_keymint::aidl::android::hardware::security::keymint::SecurityLevel::SecurityLevel;
+use std::collections::HashMap;
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+ IRemotelyProvisionedComponent::IRemotelyProvisionedComponent, MacedPublicKey::MacedPublicKey,
+ ProtectedData::ProtectedData, SecurityLevel::SecurityLevel,
+};
use android_security_remoteprovisioning::aidl::android::security::remoteprovisioning::{
AttestationPoolStatus::AttestationPoolStatus, IRemoteProvisioning::BnRemoteProvisioning,
IRemoteProvisioning::IRemoteProvisioning,
};
use android_security_remoteprovisioning::binder::Strong;
-use anyhow::Result;
+use anyhow::{Context, Result};
-use crate::error::map_or_log_err;
-use crate::globals::{get_keymint_device, DB};
+use crate::error::{self, map_or_log_err, map_rem_prov_error};
+use crate::globals::{get_keymint_device, get_remotely_provisioned_component, DB};
+use crate::utils::Asp;
/// Implementation of the IRemoteProvisioning service.
+#[derive(Default)]
pub struct RemoteProvisioningService {
- // TODO(b/179222809): Add the remote provisioner hal aidl interface when available
+ device_by_sec_level: HashMap<SecurityLevel, Asp>,
}
impl RemoteProvisioningService {
+ fn get_dev_by_sec_level(
+ &self,
+ sec_level: &SecurityLevel,
+ ) -> Result<Strong<dyn IRemotelyProvisionedComponent>> {
+ if let Some(dev) = self.device_by_sec_level.get(sec_level) {
+ dev.get_interface().context("In get_dev_by_sec_level.")
+ } else {
+ Err(error::Error::sys()).context(concat!(
+ "In get_dev_by_sec_level: Remote instance for requested security level",
+ " not found."
+ ))
+ }
+ }
+
/// Creates a new instance of the remote provisioning service
pub fn new_native_binder() -> Result<Strong<dyn IRemoteProvisioning>> {
- let result = BnRemoteProvisioning::new_binder(Self {});
- Ok(result)
+ let mut result: Self = Default::default();
+ let dev = get_remotely_provisioned_component(&SecurityLevel::TRUSTED_ENVIRONMENT)
+ .context("In new_native_binder: Failed to get TEE Remote Provisioner instance.")?;
+ result.device_by_sec_level.insert(SecurityLevel::TRUSTED_ENVIRONMENT, dev);
+ if let Ok(dev) = get_remotely_provisioned_component(&SecurityLevel::STRONGBOX) {
+ result.device_by_sec_level.insert(SecurityLevel::STRONGBOX, dev);
+ }
+ Ok(BnRemoteProvisioning::new_binder(result))
}
/// Populates the AttestationPoolStatus parcelable with information about how many
@@ -54,6 +80,11 @@
let (_, _, uuid) = get_keymint_device(&sec_level)?;
DB.with::<_, Result<AttestationPoolStatus>>(|db| {
let mut db = db.borrow_mut();
+ // delete_expired_attestation_keys is always safe to call, and will remove anything
+ // older than the date at the time of calling. No work should be done on the
+ // attestation keys unless the pool status is checked first, so this call should be
+ // enough to routinely clean out expired keys.
+ db.delete_expired_attestation_keys()?;
Ok(db.get_attestation_pool_status(expired_by, &uuid)?)
})
}
@@ -68,15 +99,34 @@
/// baked in root of trust in the underlying IRemotelyProvisionedComponent instance.
pub fn generate_csr(
&self,
- _test_mode: bool,
- _num_csr: i32,
- _eek: &[u8],
- _challenge: &[u8],
- _sec_level: SecurityLevel,
+ test_mode: bool,
+ num_csr: i32,
+ eek: &[u8],
+ challenge: &[u8],
+ sec_level: SecurityLevel,
+ protected_data: &mut ProtectedData,
) -> Result<Vec<u8>> {
- // TODO(b/179222809): implement with actual remote provisioner AIDL when available. For now
- // it isnice to have some junk values
- Ok(vec![0, 1, 3, 3])
+ let dev = self.get_dev_by_sec_level(&sec_level)?;
+ let (_, _, uuid) = get_keymint_device(&sec_level)?;
+ let keys_to_sign = DB.with::<_, Result<Vec<MacedPublicKey>>>(|db| {
+ let mut db = db.borrow_mut();
+ Ok(db
+ .fetch_unsigned_attestation_keys(num_csr, &uuid)?
+ .iter()
+ .map(|key| MacedPublicKey { macedKey: key.to_vec() })
+ .collect())
+ })?;
+ let mut mac = Vec::<u8>::with_capacity(32);
+ map_rem_prov_error(dev.generateCertificateRequest(
+ test_mode,
+ &keys_to_sign,
+ eek,
+ challenge,
+ &mut mac,
+ protected_data,
+ ))
+ .context("In generate_csr: Failed to generate csr")?;
+ Ok(mac)
}
/// Provisions a certificate chain for a key whose CSR was included in generate_csr. The
@@ -87,6 +137,7 @@
pub fn provision_cert_chain(
&self,
public_key: &[u8],
+ batch_cert: &[u8],
certs: &[u8],
expiration_date: i64,
sec_level: SecurityLevel,
@@ -96,6 +147,7 @@
let (_, _, uuid) = get_keymint_device(&sec_level)?;
Ok(db.store_signed_attestation_certificate_chain(
public_key,
+ batch_cert,
certs, /* DER encoded certificate chain */
expiration_date,
&uuid,
@@ -107,8 +159,35 @@
/// `is_test_mode` indicates whether or not the returned public key should be marked as being
/// for testing in order to differentiate them from private keys. If the call is successful,
/// the key pair is then added to the database.
- pub fn generate_key_pair(&self, _is_test_mode: bool, _sec_level: SecurityLevel) -> Result<()> {
- Ok(())
+ pub fn generate_key_pair(&self, is_test_mode: bool, sec_level: SecurityLevel) -> Result<()> {
+ let (_, _, uuid) = get_keymint_device(&sec_level)?;
+ let dev = self.get_dev_by_sec_level(&sec_level)?;
+ let mut maced_key = MacedPublicKey { macedKey: Vec::new() };
+ let priv_key =
+ map_rem_prov_error(dev.generateEcdsaP256KeyPair(is_test_mode, &mut maced_key))
+ .context("In generate_key_pair: Failed to generated ECDSA keypair.")?;
+ // TODO(b/180392379): This is a brittle hack that relies on the consistent formatting of
+ // the returned CBOR blob in order to extract the public key.
+ let data = &maced_key.macedKey;
+ if data.len() < 85 {
+ return Err(error::Error::sys()).context(concat!(
+ "In generate_key_pair: CBOR blob returned from",
+ "RemotelyProvisionedComponent is definitely malformatted or empty."
+ ));
+ }
+ let mut raw_key: Vec<u8> = vec![0; 64];
+ raw_key[0..32].clone_from_slice(&data[18..18 + 32]);
+ raw_key[32..64].clone_from_slice(&data[53..53 + 32]);
+ DB.with::<_, Result<()>>(|db| {
+ let mut db = db.borrow_mut();
+ Ok(db.create_attestation_key_entry(&maced_key.macedKey, &raw_key, &priv_key, &uuid)?)
+ })
+ }
+
+ /// Checks the security level of each available IRemotelyProvisionedComponent hal and returns
+ /// all levels in an array to the caller.
+ pub fn get_security_levels(&self) -> Result<Vec<SecurityLevel>> {
+ Ok(self.device_by_sec_level.keys().cloned().collect())
}
}
@@ -132,18 +211,26 @@
eek: &[u8],
challenge: &[u8],
sec_level: SecurityLevel,
+ protected_data: &mut ProtectedData,
) -> binder::public_api::Result<Vec<u8>> {
- map_or_log_err(self.generate_csr(test_mode, num_csr, eek, challenge, sec_level), Ok)
+ map_or_log_err(
+ self.generate_csr(test_mode, num_csr, eek, challenge, sec_level, protected_data),
+ Ok,
+ )
}
fn provisionCertChain(
&self,
public_key: &[u8],
+ batch_cert: &[u8],
certs: &[u8],
expiration_date: i64,
sec_level: SecurityLevel,
) -> binder::public_api::Result<()> {
- map_or_log_err(self.provision_cert_chain(public_key, certs, expiration_date, sec_level), Ok)
+ map_or_log_err(
+ self.provision_cert_chain(public_key, batch_cert, certs, expiration_date, sec_level),
+ Ok,
+ )
}
fn generateKeyPair(
@@ -153,4 +240,8 @@
) -> binder::public_api::Result<()> {
map_or_log_err(self.generate_key_pair(is_test_mode, sec_level), Ok)
}
+
+ fn getSecurityLevels(&self) -> binder::public_api::Result<Vec<SecurityLevel>> {
+ map_or_log_err(self.get_security_levels(), Ok)
+ }
}