Merge "Keystore 2.0: Add keystore2 support to the keystore-engine."
diff --git a/keystore2/TEST_MAPPING b/keystore2/TEST_MAPPING
index d4e20de..99a1e60 100644
--- a/keystore2/TEST_MAPPING
+++ b/keystore2/TEST_MAPPING
@@ -1,7 +1,10 @@
{
"presubmit": [
{
- "name": "keystore2_certificate_test"
+ "name": "keystore2_crypto_test"
+ },
+ {
+ "name": "keystore2_crypto_test_rust"
},
{
"name": "keystore2_test"
diff --git a/keystore2/aidl/Android.bp b/keystore2/aidl/Android.bp
index d529fa9..c92417b 100644
--- a/keystore2/aidl/Android.bp
+++ b/keystore2/aidl/Android.bp
@@ -118,6 +118,9 @@
aidl_interface {
name: "android.security.usermanager",
srcs: [ "android/security/usermanager/*.aidl" ],
+ imports: [
+ "android.system.keystore2",
+ ],
unstable: true,
backend: {
java: {
diff --git a/keystore2/aidl/android/security/usermanager/IKeystoreUserManager.aidl b/keystore2/aidl/android/security/usermanager/IKeystoreUserManager.aidl
index 3690b1c..83edb1a 100644
--- a/keystore2/aidl/android/security/usermanager/IKeystoreUserManager.aidl
+++ b/keystore2/aidl/android/security/usermanager/IKeystoreUserManager.aidl
@@ -14,11 +14,14 @@
package android.security.usermanager;
+import android.system.keystore2.Domain;
+
// TODO: mark the interface with @SensitiveData when the annotation is ready (b/176110256).
/**
* IKeystoreUserManager interface exposes the methods for adding/removing users and changing the
* user's password.
+ * @hide
*/
interface IKeystoreUserManager {
@@ -31,6 +34,7 @@
* user id.
*
* @param userId - Android user id
+ * @hide
*/
void onUserAdded(in int userId);
@@ -42,6 +46,7 @@
* `ResponseCode::SYSTEM_ERROR` - if failed to delete the keys of the user being deleted.
*
* @param userId - Android user id
+ * @hide
*/
void onUserRemoved(in int userId);
@@ -56,6 +61,18 @@
*
* @param userId - Android user id
* @param password - a secret derived from the synthetic password of the user
+ * @hide
*/
void onUserPasswordChanged(in int userId, in @nullable byte[] password);
+
+ /**
+ * This function deletes all keys within a namespace. It mainly gets called when an app gets
+ * removed and all resources of this app need to be cleaned up.
+ *
+ * @param domain - One of Domain.APP or Domain.SELINUX.
+ * @param nspace - The UID of the app that is to be cleared if domain is Domain.APP or
+ * the SEPolicy namespace if domain is Domain.SELINUX.
+ * @hide
+ */
+ void clearNamespace(Domain domain, long nspace);
}
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index db06bff..40860be 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -2522,6 +2522,51 @@
.context("In get_key_km_uuid.")
}
+ /// Delete all artifacts belonging to the namespace given by the domain-namespace tuple.
+ /// This leaves all of the blob entries orphaned for subsequent garbage collection.
+ pub fn unbind_keys_for_namespace(&mut self, domain: Domain, namespace: i64) -> Result<()> {
+ if !(domain == Domain::APP || domain == Domain::SELINUX) {
+ return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
+ .context("In unbind_keys_for_namespace.");
+ }
+ self.with_transaction(TransactionBehavior::Immediate, |tx| {
+ tx.execute(
+ "DELETE FROM persistent.keymetadata
+ WHERE keyentryid IN (
+ SELECT id FROM persistent.keyentry
+ WHERE domain = ? AND namespace = ?
+ );",
+ params![domain.0, namespace],
+ )
+ .context("Trying to delete keymetadata.")?;
+ tx.execute(
+ "DELETE FROM persistent.keyparameter
+ WHERE keyentryid IN (
+ SELECT id FROM persistent.keyentry
+ WHERE domain = ? AND namespace = ?
+ );",
+ params![domain.0, namespace],
+ )
+ .context("Trying to delete keyparameters.")?;
+ tx.execute(
+ "DELETE FROM persistent.grant
+ WHERE keyentryid IN (
+ SELECT id FROM persistent.keyentry
+ WHERE domain = ? AND namespace = ?
+ );",
+ params![domain.0, namespace],
+ )
+ .context("Trying to delete grants.")?;
+ tx.execute(
+ "DELETE FROM persistent.keyentry WHERE domain = ? AND namespace = ?;",
+ params![domain.0, namespace],
+ )
+ .context("Trying to delete keyentry.")?;
+ Ok(()).need_gc()
+ })
+ .context("In unbind_keys_for_namespace")
+ }
+
/// Delete the keys created on behalf of the user, denoted by the user id.
/// Delete all the keys unless 'keep_non_super_encrypted_keys' set to true.
/// Returned boolean is to hint the garbage collector to delete the unbound keys.
diff --git a/keystore2/src/km_compat/Android.bp b/keystore2/src/km_compat/Android.bp
index fa214a7..6b635ff 100644
--- a/keystore2/src/km_compat/Android.bp
+++ b/keystore2/src/km_compat/Android.bp
@@ -119,6 +119,7 @@
"libkeymint_support",
"libkeystore2_crypto",
"libkm_compat",
+ "libkm_compat_service",
"libutils",
],
}
diff --git a/keystore2/src/km_compat/certificate_test.cpp b/keystore2/src/km_compat/certificate_test.cpp
index de1d60a..06cb0cb 100644
--- a/keystore2/src/km_compat/certificate_test.cpp
+++ b/keystore2/src/km_compat/certificate_test.cpp
@@ -23,6 +23,7 @@
#include <aidl/android/hardware/security/keymint/BlockMode.h>
#include <aidl/android/hardware/security/keymint/Digest.h>
#include <aidl/android/hardware/security/keymint/PaddingMode.h>
+#include <android/binder_manager.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
@@ -39,16 +40,29 @@
using ::aidl::android::hardware::security::keymint::PaddingMode;
using ::aidl::android::hardware::security::keymint::SecurityLevel;
using ::aidl::android::hardware::security::keymint::Tag;
+using ::aidl::android::security::compat::IKeystoreCompatService;
namespace KMV1 = ::aidl::android::hardware::security::keymint;
-static std::variant<std::vector<Certificate>, ScopedAStatus>
-getCertificate(const std::vector<KeyParameter>& keyParams) {
- static std::shared_ptr<KeyMintDevice> device =
- KeyMintDevice::createKeyMintDevice(SecurityLevel::TRUSTED_ENVIRONMENT);
+extern "C" int32_t addKeyMintDeviceService();
+
+static std::variant<std::shared_ptr<IKeyMintDevice>, ScopedAStatus> getDevice() {
+ addKeyMintDeviceService();
+ std::shared_ptr<IKeyMintDevice> device;
+ auto service = IKeystoreCompatService::fromBinder(
+ ndk::SpAIBinder(AServiceManager_getService("android.security.compat")));
+ if (!service) {
+ return ScopedAStatus::fromStatus(STATUS_NAME_NOT_FOUND);
+ }
+ service->getKeyMintDevice(SecurityLevel::TRUSTED_ENVIRONMENT, &device);
if (!device) {
return ScopedAStatus::fromStatus(STATUS_NAME_NOT_FOUND);
}
+ return device;
+}
+
+static std::variant<std::vector<Certificate>, ScopedAStatus>
+getCertificate(std::shared_ptr<IKeyMintDevice> device, const std::vector<KeyParameter>& keyParams) {
KeyCreationResult creationResult;
auto status = device->generateKey(keyParams, std::nullopt /* attest_key */, &creationResult);
if (!status.isOk()) {
@@ -76,6 +90,8 @@
KMV1::makeKeyParameter(KMV1::TAG_ALGORITHM, Algorithm::RSA),
KMV1::makeKeyParameter(KMV1::TAG_KEY_SIZE, 2048),
KMV1::makeKeyParameter(KMV1::TAG_RSA_PUBLIC_EXPONENT, 65537),
+ KMV1::makeKeyParameter(KMV1::TAG_CERTIFICATE_NOT_BEFORE, 0),
+ KMV1::makeKeyParameter(KMV1::TAG_CERTIFICATE_NOT_AFTER, 253402300799000),
});
keyParams.insert(keyParams.end(), extraParams.begin(), extraParams.end());
return keyParams;
@@ -87,10 +103,12 @@
KMV1::makeKeyParameter(KMV1::TAG_PADDING, PaddingMode::RSA_PSS),
KMV1::makeKeyParameter(KMV1::TAG_NO_AUTH_REQUIRED),
KMV1::makeKeyParameter(KMV1::TAG_PURPOSE, KeyPurpose::SIGN),
- KMV1::makeKeyParameter(KMV1::TAG_PURPOSE, KeyPurpose::ENCRYPT),
});
- auto result = getCertificate(keyParams);
- ensureCertChainSize(result, 1);
+ auto device = getDevice();
+ if (std::holds_alternative<std::shared_ptr<IKeyMintDevice>>(device)) {
+ auto result = getCertificate(std::get<std::shared_ptr<IKeyMintDevice>>(device), keyParams);
+ ensureCertChainSize(result, 1);
+ }
}
TEST(CertificateTest, TestAES) {
@@ -101,8 +119,11 @@
KMV1::makeKeyParameter(KMV1::TAG_PADDING, PaddingMode::NONE),
KMV1::makeKeyParameter(KMV1::TAG_PURPOSE, KeyPurpose::ENCRYPT),
};
- auto result = getCertificate(keyParams);
- ensureCertChainSize(result, 0);
+ auto device = getDevice();
+ if (std::holds_alternative<std::shared_ptr<IKeyMintDevice>>(device)) {
+ auto result = getCertificate(std::get<std::shared_ptr<IKeyMintDevice>>(device), keyParams);
+ ensureCertChainSize(result, 0);
+ }
}
TEST(CertificateTest, TestAttestation) {
@@ -111,9 +132,12 @@
KMV1::makeKeyParameter(KMV1::TAG_ATTESTATION_CHALLENGE, 42),
KMV1::makeKeyParameter(KMV1::TAG_ATTESTATION_APPLICATION_ID, 42),
});
- auto result = getCertificate(keyParams);
- ensureCertChainSize(result, 3);
- verify(std::get<std::vector<Certificate>>(result).back());
+ auto device = getDevice();
+ if (std::holds_alternative<std::shared_ptr<IKeyMintDevice>>(device)) {
+ auto result = getCertificate(std::get<std::shared_ptr<IKeyMintDevice>>(device), keyParams);
+ ensureCertChainSize(result, 3);
+ verify(std::get<std::vector<Certificate>>(result).back());
+ }
}
TEST(CertificateTest, TestRSAKeygenNoEncryptNoAuthRequired) {
@@ -123,9 +147,12 @@
KMV1::makeKeyParameter(KMV1::TAG_NO_AUTH_REQUIRED, true),
KMV1::makeKeyParameter(KMV1::TAG_PURPOSE, KeyPurpose::SIGN),
});
- auto result = getCertificate(keyParams);
- ensureCertChainSize(result, 1);
- verify(std::get<std::vector<Certificate>>(result)[0]);
+ auto device = getDevice();
+ if (std::holds_alternative<std::shared_ptr<IKeyMintDevice>>(device)) {
+ auto result = getCertificate(std::get<std::shared_ptr<IKeyMintDevice>>(device), keyParams);
+ ensureCertChainSize(result, 1);
+ verify(std::get<std::vector<Certificate>>(result)[0]);
+ }
}
TEST(CertificateTest, TestRSAKeygenNoEncryptAuthRequired) {
@@ -134,6 +161,9 @@
KMV1::makeKeyParameter(KMV1::TAG_PADDING, PaddingMode::RSA_PSS),
KMV1::makeKeyParameter(KMV1::TAG_PURPOSE, KeyPurpose::SIGN),
});
- auto result = getCertificate(keyParams);
- ensureCertChainSize(result, 1);
+ auto device = getDevice();
+ if (std::holds_alternative<std::shared_ptr<IKeyMintDevice>>(device)) {
+ auto result = getCertificate(std::get<std::shared_ptr<IKeyMintDevice>>(device), keyParams);
+ ensureCertChainSize(result, 1);
+ }
}
diff --git a/keystore2/src/km_compat/km_compat.cpp b/keystore2/src/km_compat/km_compat.cpp
index 812f513..b25cb0c 100644
--- a/keystore2/src/km_compat/km_compat.cpp
+++ b/keystore2/src/km_compat/km_compat.cpp
@@ -226,7 +226,9 @@
if (securityLevel == KeyMintSecurityLevel::SOFTWARE) {
// If the security level of the backend is `software` we expect the hardware enforced list
// to be empty. Log a warning otherwise.
- CHECK(legacyKc.hardwareEnforced.size() == 0);
+ if (legacyKc.hardwareEnforced.size() != 0) {
+ LOG(WARNING) << "Unexpected hardware enforced parameters.";
+ }
return {keystoreEnforced};
}
@@ -1118,11 +1120,11 @@
// Constructors and helpers.
KeyMintDevice::KeyMintDevice(sp<Keymaster> device, KeyMintSecurityLevel securityLevel)
- : mDevice(device) {
+ : mDevice(device), securityLevel_(securityLevel) {
if (securityLevel == KeyMintSecurityLevel::STRONGBOX) {
- mOperationSlots.setNumFreeSlots(3);
+ setNumFreeSlots(3);
} else {
- mOperationSlots.setNumFreeSlots(15);
+ setNumFreeSlots(15);
}
}
diff --git a/keystore2/src/km_compat/lib.rs b/keystore2/src/km_compat/lib.rs
index 9be329f..22ddc31 100644
--- a/keystore2/src/km_compat/lib.rs
+++ b/keystore2/src/km_compat/lib.rs
@@ -324,8 +324,14 @@
fn test_secure_clock() {
add_keymint_device_service();
let compat_service: binder::Strong<dyn IKeystoreCompatService> =
- binder::get_interface(COMPAT_NAME).unwrap();
- let secure_clock = compat_service.getSecureClock().unwrap();
+ match binder::get_interface(COMPAT_NAME) {
+ Ok(cs) => cs,
+ _ => return,
+ };
+ let secure_clock = match compat_service.getSecureClock() {
+ Ok(sc) => sc,
+ _ => return,
+ };
let challenge = 42;
let result = secure_clock.generateTimeStamp(challenge);
@@ -339,9 +345,15 @@
fn test_shared_secret() {
add_keymint_device_service();
let compat_service: binder::Strong<dyn IKeystoreCompatService> =
- binder::get_interface(COMPAT_NAME).unwrap();
- let shared_secret =
- compat_service.getSharedSecret(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ match binder::get_interface(COMPAT_NAME) {
+ Ok(cs) => cs,
+ _ => return,
+ };
+ let shared_secret = match compat_service.getSharedSecret(SecurityLevel::TRUSTED_ENVIRONMENT)
+ {
+ Ok(ss) => ss,
+ _ => return,
+ };
let result = shared_secret.getSharedSecretParameters();
assert!(result.is_ok(), "{:?}", result);
diff --git a/keystore2/src/km_compat/slot_test.cpp b/keystore2/src/km_compat/slot_test.cpp
index 72d944c..37e7b36 100644
--- a/keystore2/src/km_compat/slot_test.cpp
+++ b/keystore2/src/km_compat/slot_test.cpp
@@ -140,20 +140,20 @@
ASSERT_EQ(std::get<ScopedAStatus>(result).getServiceSpecificError(),
static_cast<int32_t>(ErrorCode::TOO_MANY_OPERATIONS));
- // Generating a certificate with signWith also uses a slot.
+ // Generating a certificate with signWith uses a slot but falls back to not using one.
auto kps = std::vector<KeyParameter>({
KMV1::makeKeyParameter(KMV1::TAG_ALGORITHM, Algorithm::RSA),
KMV1::makeKeyParameter(KMV1::TAG_KEY_SIZE, 2048),
KMV1::makeKeyParameter(KMV1::TAG_RSA_PUBLIC_EXPONENT, 65537),
KMV1::makeKeyParameter(KMV1::TAG_DIGEST, Digest::SHA_2_256),
KMV1::makeKeyParameter(KMV1::TAG_PURPOSE, KeyPurpose::SIGN),
+ KMV1::makeKeyParameter(KMV1::TAG_CERTIFICATE_NOT_BEFORE, 0),
+ KMV1::makeKeyParameter(KMV1::TAG_CERTIFICATE_NOT_AFTER, 253402300799000),
KMV1::makeKeyParameter(KMV1::TAG_NO_AUTH_REQUIRED, true),
});
KeyCreationResult creationResult;
status = device->generateKey(kps, std::nullopt /* attest_key */, &creationResult);
- ASSERT_TRUE(!status.isOk());
- ASSERT_EQ(status.getServiceSpecificError(),
- static_cast<int32_t>(ErrorCode::TOO_MANY_OPERATIONS));
+ ASSERT_TRUE(status.isOk());
// But generating a certificate with signCert does not use a slot.
kps.pop_back();
status = device->generateKey(kps, std::nullopt /* attest_key */, &creationResult);
diff --git a/keystore2/src/legacy_migrator.rs b/keystore2/src/legacy_migrator.rs
index 9ffe86c..1ae8719 100644
--- a/keystore2/src/legacy_migrator.rs
+++ b/keystore2/src/legacy_migrator.rs
@@ -362,11 +362,18 @@
}
}
- /// Deletes all keys belonging to the given uid, migrating them into the database
+ /// Deletes all keys belonging to the given namespace, migrating them into the database
/// for subsequent garbage collection if necessary.
- pub fn bulk_delete_uid(&self, uid: u32, keep_non_super_encrypted_keys: bool) -> Result<()> {
+ pub fn bulk_delete_uid(&self, domain: Domain, nspace: i64) -> Result<()> {
+ let uid = match (domain, nspace) {
+ (Domain::APP, nspace) => nspace as u32,
+ (Domain::SELINUX, Self::WIFI_NAMESPACE) => Self::AID_WIFI,
+ // Nothing to do.
+ _ => return Ok(()),
+ };
+
let result = self.do_serialized(move |migrator_state| {
- migrator_state.bulk_delete(BulkDeleteRequest::Uid(uid), keep_non_super_encrypted_keys)
+ migrator_state.bulk_delete(BulkDeleteRequest::Uid(uid), false)
});
result.unwrap_or(Ok(()))
diff --git a/keystore2/src/user_manager.rs b/keystore2/src/user_manager.rs
index 8e09144..3c393c5 100644
--- a/keystore2/src/user_manager.rs
+++ b/keystore2/src/user_manager.rs
@@ -24,6 +24,7 @@
BnKeystoreUserManager, IKeystoreUserManager,
};
use android_security_usermanager::binder::{Interface, Result as BinderResult};
+use android_system_keystore2::aidl::android::system::keystore2::Domain::Domain;
use android_system_keystore2::aidl::android::system::keystore2::ResponseCode::ResponseCode;
use anyhow::{Context, Result};
use binder::{IBinder, Strong};
@@ -85,6 +86,17 @@
})
.context("In add_or_remove_user: Trying to delete keys from db.")
}
+
+ fn clear_namespace(domain: Domain, nspace: i64) -> Result<()> {
+ // Permission check. Must return on error. Do not touch the '?'.
+ check_keystore_permission(KeystorePerm::clear_uid()).context("In clear_namespace.")?;
+
+ LEGACY_MIGRATOR
+ .bulk_delete_uid(domain, nspace)
+ .context("In clear_namespace: Trying to delete legacy keys.")?;
+ DB.with(|db| db.borrow_mut().unbind_keys_for_namespace(domain, nspace))
+ .context("In clear_namespace: Trying to delete keys from db.")
+ }
}
impl Interface for UserManager {}
@@ -101,4 +113,8 @@
fn onUserRemoved(&self, user_id: i32) -> BinderResult<()> {
map_or_log_err(Self::add_or_remove_user(user_id), Ok)
}
+
+ fn clearNamespace(&self, domain: Domain, nspace: i64) -> BinderResult<()> {
+ map_or_log_err(Self::clear_namespace(domain, nspace), Ok)
+ }
}
diff --git a/ondevice-signing/Keymaster.cpp b/ondevice-signing/Keymaster.cpp
index d43828a..267dec8 100644
--- a/ondevice-signing/Keymaster.cpp
+++ b/ondevice-signing/Keymaster.cpp
@@ -68,7 +68,7 @@
mDevice = devToUse;
- return true;
+ return mDevice != nullptr;
}
std::optional<Keymaster> Keymaster::getInstance() {
diff --git a/ondevice-signing/odsign_main.cpp b/ondevice-signing/odsign_main.cpp
index b019bb9..3baba68 100644
--- a/ondevice-signing/odsign_main.cpp
+++ b/ondevice-signing/odsign_main.cpp
@@ -50,6 +50,7 @@
Result<void> addCertToFsVerityKeyring(const std::string& path) {
const char* const argv[] = {kFsVerityInitPath, "--load-extra-key", "fsv_ods"};
+ // NOLINTNEXTLINE(android-cloexec-open): Deliberately not O_CLOEXEC
int fd = open(path.c_str(), O_RDONLY);
pid_t pid = fork();
if (pid == 0) {