Merge "Allow virt APEX to use diced and open_dice_cbor"
diff --git a/keystore2/src/database.rs b/keystore2/src/database.rs
index baa3b12..5cdfbe9 100644
--- a/keystore2/src/database.rs
+++ b/keystore2/src/database.rs
@@ -324,7 +324,7 @@
0x41, 0xe3, 0xb9, 0xce, 0x27, 0x58, 0x4e, 0x91, 0xbc, 0xfd, 0xa5, 0x5d, 0x91, 0x85, 0xab, 0x11,
]);
-static EXPIRATION_BUFFER_MS: i64 = 20000;
+static EXPIRATION_BUFFER_MS: i64 = 12 * 60 * 60 * 1000;
/// Indicates how the sensitive part of this key blob is encrypted.
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
diff --git a/keystore2/src/globals.rs b/keystore2/src/globals.rs
index 14b3601..70b78ba 100644
--- a/keystore2/src/globals.rs
+++ b/keystore2/src/globals.rs
@@ -465,12 +465,10 @@
.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)?;
+ map_binder_status_code(binder::get_interface(&service_name)).context(concat!(
+ "In connect_remotely_provisioned_component: Trying to connect to",
+ " RemotelyProvisionedComponent service."
+ ))?;
Ok(rem_prov_hal)
}
diff --git a/keystore2/src/km_compat/km_compat.cpp b/keystore2/src/km_compat/km_compat.cpp
index 6d0630b..d513db0 100644
--- a/keystore2/src/km_compat/km_compat.cpp
+++ b/keystore2/src/km_compat/km_compat.cpp
@@ -574,6 +574,17 @@
auto legacyUpgradeParams = convertKeyParametersToLegacy(in_inUpgradeParams);
V4_0_ErrorCode errorCode;
+ if (prefixedKeyBlobIsSoftKeyMint(in_inKeyBlobToUpgrade)) {
+ auto status = softKeyMintDevice_->upgradeKey(
+ prefixedKeyBlobRemovePrefix(in_inKeyBlobToUpgrade), in_inUpgradeParams, _aidl_return);
+ if (!status.isOk()) {
+ LOG(ERROR) << __func__ << " transaction failed. " << status.getDescription();
+ } else {
+ *_aidl_return = keyBlobPrefix(*_aidl_return, true);
+ }
+ return status;
+ }
+
auto result =
mDevice->upgradeKey(prefixedKeyBlobRemovePrefix(in_inKeyBlobToUpgrade), legacyUpgradeParams,
[&](V4_0_ErrorCode error, const hidl_vec<uint8_t>& upgradedKeyBlob) {
diff --git a/keystore2/src/permission.rs b/keystore2/src/permission.rs
index 22509c4..3cc116b 100644
--- a/keystore2/src/permission.rs
+++ b/keystore2/src/permission.rs
@@ -19,6 +19,7 @@
//! defined by keystore2 and keystore2_key respectively.
use crate::error::Error as KsError;
+use crate::error::ResponseCode;
use android_system_keystore2::aidl::android::system::keystore2::{
Domain::Domain, KeyDescriptor::KeyDescriptor, KeyPermission::KeyPermission,
};
@@ -87,7 +88,9 @@
/// Checked when the caller attempts to use a private or public key.
#[selinux(name = use)]
Use = KeyPermission::USE.0,
- /// Checked when the caller attempts to use device ids for attestation.
+ /// Does nothing, and is not checked. For use of device identifiers,
+ /// the caller must hold the READ_PRIVILEGED_PHONE_STATE Android
+ /// permission.
#[selinux(name = use_dev_id)]
UseDevId = KeyPermission::USE_DEV_ID.0,
}
@@ -388,7 +391,7 @@
tctx
}
_ => {
- return Err(KsError::sys())
+ return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
.context(format!("Unknown domain value: \"{:?}\".", key.domain))
}
};
diff --git a/keystore2/test_utils/key_generations.rs b/keystore2/test_utils/key_generations.rs
index 6398f31..b1405c7 100644
--- a/keystore2/test_utils/key_generations.rs
+++ b/keystore2/test_utils/key_generations.rs
@@ -129,3 +129,42 @@
Err(e) => Err(e),
}
}
+
+/// Generate EC signing key.
+pub fn generate_ec_key<S: IKeystoreSecurityLevel + ?Sized>(
+ sec_level: &S,
+ domain: Domain,
+ nspace: i64,
+ alias: Option<String>,
+ ec_curve: EcCurve,
+ digest: Digest,
+) -> binder::Result<KeyMetadata> {
+ let gen_params = AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::EC)
+ .purpose(KeyPurpose::SIGN)
+ .purpose(KeyPurpose::VERIFY)
+ .digest(digest)
+ .ec_curve(ec_curve);
+
+ let key_metadata = sec_level.generateKey(
+ &KeyDescriptor { domain, nspace, alias, blob: None },
+ None,
+ &gen_params,
+ 0,
+ b"entropy",
+ )?;
+
+ // Must have a public key.
+ assert!(key_metadata.certificate.is_some());
+
+ // Should not have an attestation record.
+ assert!(key_metadata.certificateChain.is_none());
+
+ if domain == Domain::BLOB {
+ assert!(key_metadata.key.blob.is_some());
+ } else {
+ assert!(key_metadata.key.blob.is_none());
+ }
+ Ok(key_metadata)
+}
diff --git a/keystore2/tests/keystore2_client_tests.rs b/keystore2/tests/keystore2_client_tests.rs
index 06268c5..671b4ae 100644
--- a/keystore2/tests/keystore2_client_tests.rs
+++ b/keystore2/tests/keystore2_client_tests.rs
@@ -17,11 +17,13 @@
use serde::{Deserialize, Serialize};
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
- Digest::Digest, ErrorCode::ErrorCode, KeyPurpose::KeyPurpose, SecurityLevel::SecurityLevel,
+ Algorithm::Algorithm, Digest::Digest, EcCurve::EcCurve, ErrorCode::ErrorCode,
+ KeyPurpose::KeyPurpose, SecurityLevel::SecurityLevel,
};
use android_system_keystore2::aidl::android::system::keystore2::{
CreateOperationResponse::CreateOperationResponse, Domain::Domain,
- IKeystoreOperation::IKeystoreOperation, ResponseCode::ResponseCode,
+ IKeystoreOperation::IKeystoreOperation, KeyDescriptor::KeyDescriptor,
+ KeyPermission::KeyPermission, ResponseCode::ResponseCode,
};
use keystore2_test_utils::authorizations;
@@ -69,6 +71,28 @@
)
}
+/// Generate an EC signing key and grant it to the user with given access vector.
+fn generate_ec_key_and_grant_to_user(
+ grantee_uid: i32,
+ access_vector: i32,
+) -> binder::Result<KeyDescriptor> {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ let alias = format!("{}{}", "ks_grant_test_key_1", getuid());
+
+ let key_metadata = key_generations::generate_ec_p256_signing_key(
+ &sec_level,
+ Domain::SELINUX,
+ key_generations::SELINUX_SHELL_NAMESPACE,
+ Some(alias),
+ None,
+ None,
+ )
+ .unwrap();
+
+ keystore2.grant(&key_metadata.key, grantee_uid, access_vector)
+}
+
/// Performs sample signing operation.
fn perform_sample_sign_operation(
op: &binder::Strong<dyn IKeystoreOperation>,
@@ -522,3 +546,739 @@
});
}
}
+
+/// Try to grant a key with permission that does not map to any of the `KeyPermission` values.
+/// An error is expected with values that does not map to set of permissions listed in
+/// `KeyPermission`.
+#[test]
+fn keystore2_grant_key_with_invalid_perm_expecting_syserror() {
+ const USER_ID: u32 = 99;
+ const APPLICATION_ID: u32 = 10001;
+ let grantee_uid = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+ let invalid_access_vector = KeyPermission::CONVERT_STORAGE_KEY_TO_EPHEMERAL.0 << 19;
+
+ let result = key_generations::map_ks_error(generate_ec_key_and_grant_to_user(
+ grantee_uid.try_into().unwrap(),
+ invalid_access_vector,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::SYSTEM_ERROR), result.unwrap_err());
+}
+
+/// Try to grant a key with empty access vector `KeyPermission::NONE`, should be able to grant a
+/// key with empty access vector successfully. In grantee context try to use the granted key, it
+/// should fail to load the key with permission denied error.
+#[test]
+fn keystore2_grant_key_with_perm_none() {
+ static TARGET_SU_CTX: &str = "u:r:su:s0";
+
+ static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+ const USER_ID: u32 = 99;
+ const APPLICATION_ID: u32 = 10001;
+ static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+ static GRANTEE_GID: u32 = GRANTEE_UID;
+
+ let grant_key_nspace = unsafe {
+ run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
+ let empty_access_vector = KeyPermission::NONE.0;
+
+ let grant_key = key_generations::map_ks_error(generate_ec_key_and_grant_to_user(
+ GRANTEE_UID.try_into().unwrap(),
+ empty_access_vector,
+ ))
+ .unwrap();
+
+ assert_eq!(grant_key.domain, Domain::GRANT);
+
+ grant_key.nspace
+ })
+ };
+
+ // In grantee context try to load the key, it should fail to load the granted key as it is
+ // granted with empty access vector.
+ unsafe {
+ run_as::run_as(
+ GRANTEE_CTX,
+ Uid::from_raw(GRANTEE_UID),
+ Gid::from_raw(GRANTEE_GID),
+ move || {
+ let keystore2 = get_keystore_service();
+
+ let result = key_generations::map_ks_error(keystore2.getKeyEntry(&KeyDescriptor {
+ domain: Domain::GRANT,
+ nspace: grant_key_nspace,
+ alias: None,
+ blob: None,
+ }));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+ },
+ )
+ };
+}
+
+/// Grant a key to the user (grantee) with `GET_INFO|USE` key permissions. Verify whether grantee
+/// can succeed in loading the granted key and try to perform simple operation using this granted
+/// key. Grantee should be able to load the key and use the key to perform crypto operation
+/// successfully. Try to delete the granted key in grantee context where it is expected to fail to
+/// delete it as `DELETE` permission is not granted.
+#[test]
+fn keystore2_grant_get_info_use_key_perm() {
+ static TARGET_SU_CTX: &str = "u:r:su:s0";
+
+ static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+ const USER_ID: u32 = 99;
+ const APPLICATION_ID: u32 = 10001;
+ static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+ static GRANTEE_GID: u32 = GRANTEE_UID;
+
+ // Generate a key and grant it to a user with GET_INFO|USE key permissions.
+ let grant_key_nspace = unsafe {
+ run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
+ let access_vector = KeyPermission::GET_INFO.0 | KeyPermission::USE.0;
+ let grant_key = key_generations::map_ks_error(generate_ec_key_and_grant_to_user(
+ GRANTEE_UID.try_into().unwrap(),
+ access_vector,
+ ))
+ .unwrap();
+
+ assert_eq!(grant_key.domain, Domain::GRANT);
+
+ grant_key.nspace
+ })
+ };
+
+ // In grantee context load the key and try to perform crypto operation.
+ unsafe {
+ run_as::run_as(
+ GRANTEE_CTX,
+ Uid::from_raw(GRANTEE_UID),
+ Gid::from_raw(GRANTEE_GID),
+ move || {
+ let keystore2 = get_keystore_service();
+ let sec_level =
+ keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ // Load the granted key.
+ let key_entry_response = keystore2
+ .getKeyEntry(&KeyDescriptor {
+ domain: Domain::GRANT,
+ nspace: grant_key_nspace,
+ alias: None,
+ blob: None,
+ })
+ .unwrap();
+
+ // Perform sample crypto operation using granted key.
+ let op_response = sec_level
+ .createOperation(
+ &key_entry_response.metadata.key,
+ &authorizations::AuthSetBuilder::new()
+ .purpose(KeyPurpose::SIGN)
+ .digest(Digest::SHA_2_256),
+ false,
+ )
+ .unwrap();
+ assert!(op_response.iOperation.is_some());
+ assert_eq!(
+ Ok(()),
+ key_generations::map_ks_error(perform_sample_sign_operation(
+ &op_response.iOperation.unwrap()
+ ))
+ );
+
+ // Try to delete the key, it is expected to be fail with permission denied error.
+ let result = key_generations::map_ks_error(keystore2.deleteKey(&KeyDescriptor {
+ domain: Domain::GRANT,
+ nspace: grant_key_nspace,
+ alias: None,
+ blob: None,
+ }));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+ },
+ )
+ };
+}
+
+/// Try to generate a key with invalid Domain. `INVALID_ARGUMENT` error response is expected.
+#[test]
+fn keystore2_generate_key_invalid_domain() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ let alias = format!("ks_invalid_test_key_{}", getuid());
+
+ let result = key_generations::map_ks_error(key_generations::generate_ec_key(
+ &*sec_level,
+ Domain(99), // Invalid domain.
+ key_generations::SELINUX_SHELL_NAMESPACE,
+ Some(alias),
+ EcCurve::P_256,
+ Digest::SHA_2_256,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::INVALID_ARGUMENT), result.unwrap_err());
+}
+
+/// Try to generate a EC key without providing the curve.
+/// `UNSUPPORTED_EC_CURVE or UNSUPPORTED_KEY_SIZE` error response is expected.
+#[test]
+fn keystore2_generate_ec_key_missing_curve() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ let alias = format!("ks_ec_no_curve_test_key_{}", getuid());
+
+ // Don't provide EC curve.
+ let gen_params = authorizations::AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::EC)
+ .purpose(KeyPurpose::SIGN)
+ .purpose(KeyPurpose::VERIFY)
+ .digest(Digest::SHA_2_256);
+
+ let result = key_generations::map_ks_error(sec_level.generateKey(
+ &KeyDescriptor {
+ domain: Domain::SELINUX,
+ nspace: key_generations::SELINUX_SHELL_NAMESPACE,
+ alias: Some(alias),
+ blob: None,
+ },
+ None,
+ &gen_params,
+ 0,
+ b"entropy",
+ ));
+ assert!(result.is_err());
+ let err = result.unwrap_err();
+ assert!(matches!(
+ err,
+ Error::Km(ErrorCode::UNSUPPORTED_EC_CURVE) | Error::Km(ErrorCode::UNSUPPORTED_KEY_SIZE)
+ ));
+}
+
+/// Try to generate a EC key with curve `CURVE_25519` having `SIGN and AGREE_KEY` purposes.
+/// `INCOMPATIBLE_PURPOSE` error response is expected.
+#[test]
+fn keystore2_generate_ec_key_25519_multi_purpose() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ let alias = format!("ks_ec_no_curve_test_key_{}", getuid());
+
+ // Specify `SIGN and AGREE_KEY` purposes.
+ let gen_params = authorizations::AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::EC)
+ .ec_curve(EcCurve::CURVE_25519)
+ .purpose(KeyPurpose::SIGN)
+ .purpose(KeyPurpose::AGREE_KEY)
+ .digest(Digest::SHA_2_256);
+
+ let result = key_generations::map_ks_error(sec_level.generateKey(
+ &KeyDescriptor {
+ domain: Domain::SELINUX,
+ nspace: key_generations::SELINUX_SHELL_NAMESPACE,
+ alias: Some(alias),
+ blob: None,
+ },
+ None,
+ &gen_params,
+ 0,
+ b"entropy",
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PURPOSE), result.unwrap_err());
+}
+
+/// Generate EC keys with curves EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521 and
+/// various digest modes. Try to create operations using generated keys. Operations with digest
+/// modes `SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512` should be created successfully.
+/// Creation of operations with digest modes NONE and MD5 should fail with an error code
+/// `UNSUPPORTED_DIGEST`.
+#[test]
+fn keystore2_ec_generate_key() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let digests = [
+ Digest::NONE,
+ Digest::MD5,
+ Digest::SHA1,
+ Digest::SHA_2_224,
+ Digest::SHA_2_256,
+ Digest::SHA_2_384,
+ Digest::SHA_2_512,
+ ];
+
+ let ec_curves = [EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521];
+
+ for ec_curve in ec_curves {
+ for digest in digests {
+ let alias = format!("ks_ec_test_key_gen_{}{}{}", getuid(), ec_curve.0, digest.0);
+ let key_metadata = key_generations::generate_ec_key(
+ &*sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ ec_curve,
+ digest,
+ )
+ .unwrap();
+
+ match key_generations::map_ks_error(sec_level.createOperation(
+ &key_metadata.key,
+ &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(digest),
+ false,
+ )) {
+ Ok(op_response) => {
+ assert!(op_response.iOperation.is_some());
+ assert_eq!(
+ Ok(()),
+ key_generations::map_ks_error(perform_sample_sign_operation(
+ &op_response.iOperation.unwrap()
+ ))
+ );
+ }
+ Err(e) => {
+ assert_eq!(e, Error::Km(ErrorCode::UNSUPPORTED_DIGEST));
+ assert!(digest == Digest::NONE || digest == Digest::MD5);
+ }
+ }
+ }
+ }
+}
+
+/// Generate EC key with curve `CURVE_25519` and digest mode NONE. Try to create an operation using
+/// generated key. `CURVE_25519` key should support `Digest::NONE` digest mode and test should be
+/// able to create an operation successfully.
+#[test]
+fn keystore2_ec_25519_generate_key_success() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let alias = format!("ks_ec_25519_none_test_key_gen_{}", getuid());
+ let key_metadata = key_generations::generate_ec_key(
+ &*sec_level,
+ Domain::APP,
+ -1,
+ Some(alias),
+ EcCurve::CURVE_25519,
+ Digest::NONE,
+ )
+ .unwrap();
+
+ let op_response = sec_level
+ .createOperation(
+ &key_metadata.key,
+ &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::NONE),
+ false,
+ )
+ .unwrap();
+ assert!(op_response.iOperation.is_some());
+ assert_eq!(
+ Ok(()),
+ key_generations::map_ks_error(perform_sample_sign_operation(
+ &op_response.iOperation.unwrap()
+ ))
+ );
+}
+
+/// Generate EC keys with curve `CURVE_25519` and digest modes `MD5, SHA1, SHA-2 224, SHA-2 256,
+/// SHA-2 384 and SHA-2 512`. Try to create operations using generated keys. `CURVE_25519` keys
+/// shouldn't support these digest modes. Test should fail to create operations with an error
+/// `UNSUPPORTED_DIGEST`.
+#[test]
+fn keystore2_ec_25519_generate_key_fail() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let digests = [
+ Digest::MD5,
+ Digest::SHA1,
+ Digest::SHA_2_224,
+ Digest::SHA_2_256,
+ Digest::SHA_2_384,
+ Digest::SHA_2_512,
+ ];
+
+ for digest in digests {
+ let alias = format!("ks_ec_25519_test_key_gen_{}{}", getuid(), digest.0);
+ let key_metadata = key_generations::generate_ec_key(
+ &*sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ EcCurve::CURVE_25519,
+ digest,
+ )
+ .unwrap();
+
+ let result = key_generations::map_ks_error(sec_level.createOperation(
+ &key_metadata.key,
+ &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(digest),
+ false,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_DIGEST), result.unwrap_err());
+ }
+}
+
+/// Generate a EC key with `SHA_2_256` digest mode. Try to create an operation with digest mode
+/// other than `SHA_2_256`. Creation of an operation with generated key should fail with
+/// `INCOMPATIBLE_DIGEST` error as there is a mismatch of digest mode in key authorizations.
+#[test]
+fn keystore2_create_op_with_incompatible_key_digest() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let alias = "ks_ec_test_incomp_key_digest";
+ let key_metadata = key_generations::generate_ec_key(
+ &*sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ EcCurve::P_256,
+ Digest::SHA_2_256,
+ )
+ .unwrap();
+
+ let digests =
+ [Digest::NONE, Digest::SHA1, Digest::SHA_2_224, Digest::SHA_2_384, Digest::SHA_2_512];
+
+ for digest in digests {
+ let result = key_generations::map_ks_error(sec_level.createOperation(
+ &key_metadata.key,
+ &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(digest),
+ false,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_DIGEST), result.unwrap_err());
+ }
+}
+
+/// Generate a key in client#1 and try to use it in other client#2.
+/// Client#2 should fail to load the key as the it doesn't own the client#1 generated key.
+#[test]
+fn keystore2_key_owner_validation() {
+ static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+ const USER_ID: u32 = 99;
+ const APPLICATION_ID_1: u32 = 10601;
+
+ let uid1 = USER_ID * AID_USER_OFFSET + APPLICATION_ID_1;
+ let gid1 = USER_ID * AID_USER_OFFSET + APPLICATION_ID_1;
+ let alias = "ks_owner_check_test_key";
+
+ // Client#1: Generate a key and create an operation using generated key.
+ // Wait until the parent notifies to continue. Once the parent notifies, this operation
+ // is expected to be completed successfully.
+ let mut child_handle = execute_op_run_as_child(
+ TARGET_CTX,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ Uid::from_raw(uid1),
+ Gid::from_raw(gid1),
+ ForcedOp(false),
+ );
+
+ // Wait until (client#1) child process notifies us to continue, so that there will be a key
+ // generated by client#1.
+ child_handle.recv();
+
+ // Client#2: This child will try to load the key generated by client#1.
+ const APPLICATION_ID_2: u32 = 10602;
+ let uid2 = USER_ID * AID_USER_OFFSET + APPLICATION_ID_2;
+ let gid2 = USER_ID * AID_USER_OFFSET + APPLICATION_ID_2;
+ unsafe {
+ run_as::run_as(TARGET_CTX, Uid::from_raw(uid2), Gid::from_raw(gid2), move || {
+ let keystore2_inst = get_keystore_service();
+ let result =
+ key_generations::map_ks_error(keystore2_inst.getKeyEntry(&KeyDescriptor {
+ domain: Domain::APP,
+ nspace: -1,
+ alias: Some(alias.to_string()),
+ blob: None,
+ }));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+ });
+ };
+
+ // Notify the child process (client#1) to resume and finish.
+ child_handle.send(&BarrierReached {});
+ assert!(
+ (child_handle.get_result() == TestOutcome::Ok),
+ "Client#1 failed to complete the operation."
+ );
+}
+
+/// Generate EC key with BLOB as domain. Generated key should be returned to caller as key blob.
+/// Verify that `blob` field in the `KeyDescriptor` is not empty and should have the key blob.
+/// Try to use this key for performing a sample operation and the operation should complete
+/// successfully.
+#[test]
+fn keystore2_generate_key_with_blob_domain() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let key_metadata = key_generations::generate_ec_key(
+ &*sec_level,
+ Domain::BLOB,
+ key_generations::SELINUX_SHELL_NAMESPACE,
+ None,
+ EcCurve::P_256,
+ Digest::SHA_2_256,
+ )
+ .unwrap();
+
+ assert!(key_metadata.certificate.is_some());
+ assert!(key_metadata.certificateChain.is_none());
+
+ // Must have the key blob.
+ assert!(key_metadata.key.blob.is_some());
+
+ let op_response = key_generations::map_ks_error(sec_level.createOperation(
+ &key_metadata.key,
+ &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256),
+ false,
+ ))
+ .unwrap();
+ assert!(op_response.iOperation.is_some());
+ assert_eq!(
+ Ok(()),
+ key_generations::map_ks_error(perform_sample_sign_operation(
+ &op_response.iOperation.unwrap()
+ ))
+ );
+
+ // Delete the generated key blob.
+ sec_level.deleteKey(&key_metadata.key).unwrap();
+}
+
+/// Try to generate a key with `Domain::KEY_ID`, test should fail with an error code
+/// `SYSTEM_ERROR`. `Domain::KEY_ID` is not allowed to use for generating a key. Key id is returned
+/// by Keystore2 after a key has been mapped from an alias.
+#[test]
+fn keystore2_generate_key_with_key_id_domain_expect_sys_error() {
+ let alias = "ks_gen_key_id_test_key";
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let result = key_generations::map_ks_error(key_generations::generate_ec_key(
+ &*sec_level,
+ Domain::KEY_ID,
+ key_generations::SELINUX_SHELL_NAMESPACE,
+ Some(alias.to_string()),
+ EcCurve::P_256,
+ Digest::SHA_2_256,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::SYSTEM_ERROR), result.unwrap_err());
+}
+
+/// Generate a key and try to load the generated key using KEY_ID as domain. Create an
+/// operation using key which is loaded with domain as KEY_ID. Test should create an operation
+/// successfully.
+#[test]
+fn keystore2_find_key_with_key_id_as_domain() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ let alias = "ks_key_id_test_key";
+
+ let key_metadata = key_generations::generate_ec_key(
+ &*sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ EcCurve::P_256,
+ Digest::SHA_2_256,
+ )
+ .expect("Failed to generate a EC key.");
+
+ // Try to load the above generated key with KEY_ID as domain.
+ let key_entry_response = keystore2
+ .getKeyEntry(&KeyDescriptor {
+ domain: Domain::KEY_ID,
+ nspace: key_metadata.key.nspace,
+ alias: Some(alias.to_string()),
+ blob: None,
+ })
+ .expect("Error in getKeyEntry to load a key with domain KEY_ID.");
+
+ // Verify above found key is same the one generated.
+ assert_eq!(key_metadata.key, key_entry_response.metadata.key);
+ assert_eq!(key_metadata.certificate, key_entry_response.metadata.certificate);
+ assert_eq!(key_metadata.certificateChain, key_entry_response.metadata.certificateChain);
+ assert_eq!(key_metadata.key.nspace, key_entry_response.metadata.key.nspace);
+
+ // Try to create an operation using above loaded key, operation should be created
+ // successfully.
+ let op_response = sec_level
+ .createOperation(
+ &key_entry_response.metadata.key,
+ &authorizations::AuthSetBuilder::new()
+ .purpose(KeyPurpose::SIGN)
+ .digest(Digest::SHA_2_256),
+ false,
+ )
+ .expect("Error in creation of operation.");
+
+ assert!(op_response.iOperation.is_some());
+ assert_eq!(
+ Ok(()),
+ key_generations::map_ks_error(perform_sample_sign_operation(
+ &op_response.iOperation.unwrap()
+ ))
+ );
+}
+
+/// Generate a key with an alias. Generate another key and bind it to the same alias.
+/// Try to create an operation using previously generated key. Creation of an operation should
+/// fail because previously generated key material is no longer accessible. Test should successfully
+/// create an operation using the rebound key.
+#[test]
+fn keystore2_key_id_alias_rebind_verify_by_alias() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ let alias = format!("ks_key_id_test_alias_rebind_1_{}", getuid());
+
+ let key_metadata = key_generations::generate_ec_key(
+ &*sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ EcCurve::P_256,
+ Digest::SHA_2_256,
+ )
+ .expect("Failed to generate a EC key.");
+
+ // Generate a key with same alias as above generated key, so that alias will be rebound
+ // to this key.
+ let new_key_metadata = key_generations::generate_ec_key(
+ &*sec_level,
+ Domain::APP,
+ -1,
+ Some(alias),
+ EcCurve::P_256,
+ Digest::SHA_2_256,
+ )
+ .expect("Failed to generate a rebound EC key.");
+
+ assert_ne!(key_metadata.key, new_key_metadata.key);
+ assert_ne!(key_metadata.certificate, new_key_metadata.certificate);
+ assert_ne!(key_metadata.key.nspace, new_key_metadata.key.nspace);
+
+ // Try to create an operation using previously generated key_metadata.
+ // It should fail as previously generated key material is no longer remains valid.
+ let result = key_generations::map_ks_error(sec_level.createOperation(
+ &key_metadata.key,
+ &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256),
+ false,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+
+ // Try to create an operation using rebound key, operation should be created
+ // successfully.
+ let op_response = sec_level
+ .createOperation(
+ &new_key_metadata.key,
+ &authorizations::AuthSetBuilder::new()
+ .purpose(KeyPurpose::SIGN)
+ .digest(Digest::SHA_2_256),
+ false,
+ )
+ .expect("Error in creation of operation using rebound key.");
+
+ assert!(op_response.iOperation.is_some());
+ assert_eq!(
+ Ok(()),
+ key_generations::map_ks_error(perform_sample_sign_operation(
+ &op_response.iOperation.unwrap()
+ ))
+ );
+}
+
+/// Generate a key with an alias. Load the generated key with `Domain::KEY_ID`. Generate another
+/// key and bind it to the same alias. Try to create an operation using the key loaded with domain
+/// `KEY_ID`. Creation of an operation should fail because originally loaded key no longer exists.
+/// Test should successfully create an operation using the rebound key.
+#[test]
+fn keystore2_key_id_alias_rebind_verify_by_key_id() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ let alias = format!("ks_key_id_test_alias_rebind_2_{}", getuid());
+
+ let key_metadata = key_generations::generate_ec_key(
+ &*sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ EcCurve::P_256,
+ Digest::SHA_2_256,
+ )
+ .expect("Failed to generate a EC key.");
+
+ // Load the above generated key with KEY_ID as domain.
+ let key_entry_response = keystore2
+ .getKeyEntry(&KeyDescriptor {
+ domain: Domain::KEY_ID,
+ nspace: key_metadata.key.nspace,
+ alias: Some(alias.to_string()),
+ blob: None,
+ })
+ .expect("Error in getKeyEntry to load a key with domain KEY_ID.");
+
+ // Verify above found key is same the one generated.
+ assert_eq!(key_metadata.key, key_entry_response.metadata.key);
+ assert_eq!(key_metadata.certificate, key_entry_response.metadata.certificate);
+ assert_eq!(key_metadata.certificateChain, key_entry_response.metadata.certificateChain);
+ assert_eq!(key_metadata.key.nspace, key_entry_response.metadata.key.nspace);
+
+ // Generate another key with same alias as above generated key, so that alias will be rebound
+ // to this key.
+ let new_key_metadata = key_generations::generate_ec_key(
+ &*sec_level,
+ Domain::APP,
+ -1,
+ Some(alias),
+ EcCurve::P_256,
+ Digest::SHA_2_256,
+ )
+ .expect("Failed to generate a rebound EC key.");
+
+ // Verify that an alias is rebound to a new key.
+ assert_eq!(key_metadata.key.alias, new_key_metadata.key.alias);
+ assert_ne!(key_metadata.key, new_key_metadata.key);
+ assert_ne!(key_metadata.certificate, new_key_metadata.certificate);
+ assert_ne!(key_metadata.key.nspace, new_key_metadata.key.nspace);
+
+ // Try to create an operation using previously loaded key_entry_response.
+ // It should fail as previously generated key material is no longer valid.
+ let result = key_generations::map_ks_error(sec_level.createOperation(
+ &key_entry_response.metadata.key,
+ &authorizations::AuthSetBuilder::new().purpose(KeyPurpose::SIGN).digest(Digest::SHA_2_256),
+ false,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+
+ // Try to create an operation using rebound key, operation should be created
+ // successfully.
+ let op_response = sec_level
+ .createOperation(
+ &new_key_metadata.key,
+ &authorizations::AuthSetBuilder::new()
+ .purpose(KeyPurpose::SIGN)
+ .digest(Digest::SHA_2_256),
+ false,
+ )
+ .expect("Error in creation of operation using rebound key.");
+
+ assert!(op_response.iOperation.is_some());
+ assert_eq!(
+ Ok(()),
+ key_generations::map_ks_error(perform_sample_sign_operation(
+ &op_response.iOperation.unwrap()
+ ))
+ );
+}
diff --git a/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs b/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs
index 48275ae..32ecd03 100644
--- a/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs
+++ b/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs
@@ -85,7 +85,7 @@
.expect("failed to execute pidof keystore2");
let id = String::from_utf8(output.stdout).unwrap();
- let id: String = id.chars().filter(|c| c.is_digit(10)).collect();
+ let id: String = id.chars().filter(|c| c.is_ascii_digit()).collect();
let _status = std::process::Command::new("kill").arg("-9").arg(id).status().unwrap();