Merge "Keystore 2.0 certificate utils: Set time by string." into sc-dev
diff --git a/keystore2/src/globals.rs b/keystore2/src/globals.rs
index 89114a6..9ce2b46 100644
--- a/keystore2/src/globals.rs
+++ b/keystore2/src/globals.rs
@@ -216,9 +216,12 @@
}
};
- let keymint = if let Some(service_name) = service_name {
- map_binder_status_code(binder::get_interface(&service_name))
- .context("In connect_keymint: Trying to connect to genuine KeyMint service.")
+ let (keymint, hal_version) = if let Some(service_name) = service_name {
+ (
+ map_binder_status_code(binder::get_interface(&service_name))
+ .context("In connect_keymint: Trying to connect to genuine KeyMint service.")?,
+ Some(100i32), // The HAL version code for KeyMint V1 is 100.
+ )
} else {
// This is a no-op if it was called before.
keystore2_km_compat::add_keymint_device_service();
@@ -226,21 +229,35 @@
let keystore_compat_service: Strong<dyn IKeystoreCompatService> =
map_binder_status_code(binder::get_interface("android.security.compat"))
.context("In connect_keymint: Trying to connect to compat service.")?;
- map_binder_status(keystore_compat_service.getKeyMintDevice(*security_level))
- .map_err(|e| match e {
- Error::BinderTransaction(StatusCode::NAME_NOT_FOUND) => {
- Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE)
- }
- e => e,
- })
- .context("In connect_keymint: Trying to get Legacy wrapper.")
- }?;
+ (
+ map_binder_status(keystore_compat_service.getKeyMintDevice(*security_level))
+ .map_err(|e| match e {
+ Error::BinderTransaction(StatusCode::NAME_NOT_FOUND) => {
+ Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE)
+ }
+ e => e,
+ })
+ .context("In connect_keymint: Trying to get Legacy wrapper.")?,
+ None,
+ )
+ };
let wp = wd::watch_millis("In connect_keymint: calling getHardwareInfo()", 500);
- let hw_info = map_km_error(keymint.getHardwareInfo())
+ let mut hw_info = map_km_error(keymint.getHardwareInfo())
.context("In connect_keymint: Failed to get hardware info.")?;
drop(wp);
+ // The legacy wrapper sets hw_info.versionNumber to the underlying HAL version like so:
+ // 10 * <major> + <minor>, e.g., KM 3.0 = 30. So 30, 40, and 41 are the only viable values.
+ // For KeyMint the versionNumber is implementation defined and thus completely meaningless
+ // to Keystore 2.0. So at this point the versionNumber field is set to the HAL version, so
+ // that higher levels have a meaningful guide as to which feature set to expect from the
+ // implementation. As of this writing the only meaningful version number is 100 for KeyMint V1,
+ // and future AIDL versions should follow the pattern <AIDL version> * 100.
+ if let Some(hal_version) = hal_version {
+ hw_info.versionNumber = hal_version;
+ }
+
Ok((Asp::new(keymint.as_binder()), hw_info))
}
diff --git a/keystore2/src/km_compat/km_compat.cpp b/keystore2/src/km_compat/km_compat.cpp
index 19576aa..f6f8bfe 100644
--- a/keystore2/src/km_compat/km_compat.cpp
+++ b/keystore2/src/km_compat/km_compat.cpp
@@ -1395,8 +1395,7 @@
if (!device) {
return ScopedAStatus::fromStatus(STATUS_NAME_NOT_FOUND);
}
- bool inserted = false;
- std::tie(i, inserted) = mDeviceCache.insert({in_securityLevel, std::move(device)});
+ i = mDeviceCache.insert(i, {in_securityLevel, std::move(device)});
}
*_aidl_return = i->second;
return ScopedAStatus::ok();
@@ -1404,14 +1403,15 @@
ScopedAStatus KeystoreCompatService::getSharedSecret(KeyMintSecurityLevel in_securityLevel,
std::shared_ptr<ISharedSecret>* _aidl_return) {
- if (!mSharedSecret) {
+ auto i = mSharedSecretCache.find(in_securityLevel);
+ if (i == mSharedSecretCache.end()) {
auto secret = SharedSecret::createSharedSecret(in_securityLevel);
if (!secret) {
return ScopedAStatus::fromStatus(STATUS_NAME_NOT_FOUND);
}
- mSharedSecret = std::move(secret);
+ i = mSharedSecretCache.insert(i, {in_securityLevel, std::move(secret)});
}
- *_aidl_return = mSharedSecret;
+ *_aidl_return = i->second;
return ScopedAStatus::ok();
}
diff --git a/keystore2/src/km_compat/km_compat.h b/keystore2/src/km_compat/km_compat.h
index 09c9157..2d892da 100644
--- a/keystore2/src/km_compat/km_compat.h
+++ b/keystore2/src/km_compat/km_compat.h
@@ -197,7 +197,7 @@
class KeystoreCompatService : public BnKeystoreCompatService {
private:
std::unordered_map<KeyMintSecurityLevel, std::shared_ptr<IKeyMintDevice>> mDeviceCache;
- std::shared_ptr<ISharedSecret> mSharedSecret;
+ std::unordered_map<KeyMintSecurityLevel, std::shared_ptr<ISharedSecret>> mSharedSecretCache;
std::shared_ptr<ISecureClock> mSecureClock;
public:
diff --git a/keystore2/src/shared_secret_negotiation.rs b/keystore2/src/shared_secret_negotiation.rs
index fb55f33..64bc2c3 100644
--- a/keystore2/src/shared_secret_negotiation.rs
+++ b/keystore2/src/shared_secret_negotiation.rs
@@ -24,6 +24,7 @@
use anyhow::{Context, Result};
use keystore2_vintf::{get_aidl_instances, get_hidl_instances};
use std::fmt::{self, Display, Formatter};
+use std::time::Duration;
/// This function initiates the shared secret negotiation. It starts a thread and then returns
/// immediately. The thread consults the vintf manifest to enumerate expected negotiation
@@ -109,7 +110,11 @@
/// Lists participants.
fn list_participants() -> Result<Vec<SharedSecretParticipant>> {
- Ok([(4, 0), (4, 1)]
+ // 4.1 implementation always also register as 4.0. So only the highest version of each
+ // "default" and "strongbox" makes the cut.
+ let mut legacy_default_found: bool = false;
+ let mut legacy_strongbox_found: bool = false;
+ Ok([(4, 1), (4, 0)]
.iter()
.map(|(ma, mi)| {
get_hidl_instances(KEYMASTER_PACKAGE_NAME, *ma, *mi, KEYMASTER_INTERFACE_NAME)
@@ -119,7 +124,24 @@
instances
.into_iter()
.filter_map(|name| {
- filter_map_legacy_km_instances(name.to_string(), (*ma, *mi))
+ filter_map_legacy_km_instances(name.to_string(), (*ma, *mi)).and_then(
+ |sp| {
+ if let SharedSecretParticipant::Hidl {
+ is_strongbox: true,
+ ..
+ } = &sp
+ {
+ if !legacy_strongbox_found {
+ legacy_strongbox_found = true;
+ return Some(sp);
+ }
+ } else if !legacy_default_found {
+ legacy_default_found = true;
+ return Some(sp);
+ }
+ None
+ },
+ )
})
.collect::<Vec<SharedSecretParticipant>>()
})
@@ -215,7 +237,7 @@
if participants.is_empty() {
break;
}
- std::thread::sleep(std::time::Duration::from_millis(1000));
+ std::thread::sleep(Duration::from_millis(1000));
}
connected_participants
}
@@ -237,7 +259,7 @@
Err(e) => {
log::warn!("{:?}", e);
log::warn!("Retrying in one second.");
- std::thread::sleep(std::time::Duration::from_millis(1000));
+ std::thread::sleep(Duration::from_millis(1000));
}
Ok(params) => break params,
}
@@ -246,20 +268,28 @@
params.sort_unstable();
// Phase 2: Send the sorted sharing parameters to all participants.
- participants
- .into_iter()
- .try_fold(None, |acc, (s, p)| {
- match (acc, map_binder_status(s.computeSharedSecret(¶ms))) {
- (None, Ok(new_sum)) => Ok(Some(new_sum)),
- (Some(old_sum), Ok(new_sum)) => {
- if old_sum == new_sum {
- Ok(Some(old_sum))
- } else {
- Err(SharedSecretError::Checksum(p))
- }
+ let negotiation_result = participants.into_iter().try_fold(None, |acc, (s, p)| {
+ match (acc, map_binder_status(s.computeSharedSecret(¶ms))) {
+ (None, Ok(new_sum)) => Ok(Some(new_sum)),
+ (Some(old_sum), Ok(new_sum)) => {
+ if old_sum == new_sum {
+ Ok(Some(old_sum))
+ } else {
+ Err(SharedSecretError::Checksum(p))
}
- (_, Err(e)) => Err(SharedSecretError::Computation { e, p }),
}
- })
- .expect("Fatal: Shared secret computation failed.");
+ (_, Err(e)) => Err(SharedSecretError::Computation { e, p }),
+ }
+ });
+
+ if let Err(e) = negotiation_result {
+ log::error!("In negotiate_shared_secret: {:?}.", e);
+ if let SharedSecretError::Checksum(_) = e {
+ log::error!(concat!(
+ "This means that this device is NOT PROVISIONED CORRECTLY.\n",
+ "User authorization and other security functions will not work\n",
+ "as expected. Please contact your OEM for instructions.",
+ ));
+ }
+ }
}