Merge "Fix warning for rkp_factory_extraction_tool" into main
diff --git a/OWNERS b/OWNERS
index 6fdb550..b1c1fea 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,11 +1,7 @@
-alanstokes@google.com
 drysdale@google.com
-eranm@google.com
 hasinitg@google.com
 jbires@google.com
 jeffv@google.com
-kroot@google.com
 sethmo@google.com
 swillden@google.com
-trong@google.com
 zeuthen@google.com
diff --git a/keystore2/aidl/Android.bp b/keystore2/aidl/Android.bp
index afc2743..13bf455 100644
--- a/keystore2/aidl/Android.bp
+++ b/keystore2/aidl/Android.bp
@@ -24,8 +24,8 @@
 aidl_interface {
     name: "android.security.authorization",
     srcs: ["android/security/authorization/*.aidl"],
+    defaults: ["android.hardware.security.keymint-latest-defaults"],
     imports: [
-        "android.hardware.security.keymint-V3",
         "android.hardware.security.secureclock-V1",
     ],
     unstable: true,
@@ -63,8 +63,8 @@
 aidl_interface {
     name: "android.security.compat",
     srcs: ["android/security/compat/*.aidl"],
+    defaults: ["android.hardware.security.keymint-latest-defaults"],
     imports: [
-        "android.hardware.security.keymint-V3",
         "android.hardware.security.secureclock-V1",
         "android.hardware.security.sharedsecret-V1",
     ],
@@ -86,8 +86,8 @@
 aidl_interface {
     name: "android.security.maintenance",
     srcs: ["android/security/maintenance/*.aidl"],
-    imports: [
-        "android.system.keystore2-V4",
+    defaults: [
+        "android.system.keystore2-latest-defaults",
     ],
     unstable: true,
     backend: {
@@ -145,8 +145,8 @@
 aidl_interface {
     name: "android.security.metrics",
     srcs: ["android/security/metrics/*.aidl"],
-    imports: [
-        "android.system.keystore2-V4",
+    defaults: [
+        "android.system.keystore2-latest-defaults",
     ],
     unstable: true,
     backend: {
@@ -169,21 +169,21 @@
 java_defaults {
     name: "keystore2_use_latest_aidl_java_static",
     static_libs: [
-        "android.system.keystore2-V4-java-source",
+        "android.system.keystore2-V5-java-source",
     ],
 }
 
 java_defaults {
     name: "keystore2_use_latest_aidl_java_shared",
     libs: [
-        "android.system.keystore2-V4-java-source",
+        "android.system.keystore2-V5-java-source",
     ],
 }
 
 java_defaults {
     name: "keystore2_use_latest_aidl_java",
     libs: [
-        "android.system.keystore2-V4-java",
+        "android.system.keystore2-V5-java",
     ],
 }
 
@@ -193,28 +193,28 @@
 cc_defaults {
     name: "keystore2_use_latest_aidl_ndk_static",
     static_libs: [
-        "android.system.keystore2-V4-ndk",
+        "android.system.keystore2-V5-ndk",
     ],
 }
 
 cc_defaults {
     name: "keystore2_use_latest_aidl_ndk_shared",
     shared_libs: [
-        "android.system.keystore2-V4-ndk",
+        "android.system.keystore2-V5-ndk",
     ],
 }
 
 cc_defaults {
     name: "keystore2_use_latest_aidl_cpp_shared",
     shared_libs: [
-        "android.system.keystore2-V4-cpp",
+        "android.system.keystore2-V5-cpp",
     ],
 }
 
 cc_defaults {
     name: "keystore2_use_latest_aidl_cpp_static",
     static_libs: [
-        "android.system.keystore2-V4-cpp",
+        "android.system.keystore2-V5-cpp",
     ],
 }
 
@@ -224,6 +224,6 @@
 rust_defaults {
     name: "keystore2_use_latest_aidl_rust",
     rustlibs: [
-        "android.system.keystore2-V4-rust",
+        "android.system.keystore2-V5-rust",
     ],
 }
diff --git a/keystore2/android.system.keystore2-service.xml b/keystore2/android.system.keystore2-service.xml
index 4d8a756..35b9cc8 100644
--- a/keystore2/android.system.keystore2-service.xml
+++ b/keystore2/android.system.keystore2-service.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="framework">
     <hal format="aidl">
         <name>android.system.keystore2</name>
-        <version>4</version>
+        <version>5</version>
         <interface>
             <name>IKeystoreService</name>
             <instance>default</instance>
diff --git a/keystore2/src/globals.rs b/keystore2/src/globals.rs
index 39d6f9c..0e8892b 100644
--- a/keystore2/src/globals.rs
+++ b/keystore2/src/globals.rs
@@ -271,17 +271,8 @@
     // If the KeyMint device is back-level, use a wrapper that intercepts and
     // emulates things that are not supported by the hardware.
     let keymint = match hal_version {
-        Some(300) => {
-            // Current KeyMint version: use as-is as v3 Keymint is current version
-            log::info!(
-                "KeyMint device is current version ({:?}) for security level: {:?}",
-                hal_version,
-                security_level
-            );
-            keymint
-        }
-        Some(200) => {
-            // Previous KeyMint version: use as-is as we don't have any software emulation of v3-specific KeyMint features.
+        Some(400) | Some(300) | Some(200) => {
+            // KeyMint v2+: use as-is (we don't have any software emulation of v3 or v4-specific KeyMint features).
             log::info!(
                 "KeyMint device is current version ({:?}) for security level: {:?}",
                 hal_version,
diff --git a/keystore2/src/km_compat.rs b/keystore2/src/km_compat.rs
index 5e3bdfa..95e9294 100644
--- a/keystore2/src/km_compat.rs
+++ b/keystore2/src/km_compat.rs
@@ -214,6 +214,12 @@
     fn sendRootOfTrust(&self, root_of_trust: &[u8]) -> binder::Result<()> {
         self.real.sendRootOfTrust(root_of_trust)
     }
+    fn setAdditionalAttestationInfo(
+        &self,
+        additional_attestation_info: &[KeyParameter],
+    ) -> binder::Result<()> {
+        self.real.setAdditionalAttestationInfo(additional_attestation_info)
+    }
 
     // For methods that emit keyblobs, check whether the underlying real device
     // supports the relevant parameters, and forward to the appropriate device.
diff --git a/keystore2/src/km_compat/km_compat.cpp b/keystore2/src/km_compat/km_compat.cpp
index e9ff1ff..7a6ef4a 100644
--- a/keystore2/src/km_compat/km_compat.cpp
+++ b/keystore2/src/km_compat/km_compat.cpp
@@ -839,6 +839,11 @@
     return convertErrorCode(KMV1::ErrorCode::UNIMPLEMENTED);
 }
 
+ScopedAStatus KeyMintDevice::setAdditionalAttestationInfo(
+    const std::vector<KeyParameter>& /* additionalAttestationInfo */) {
+    return convertErrorCode(KMV1::ErrorCode::UNIMPLEMENTED);
+}
+
 ScopedAStatus KeyMintOperation::updateAad(const std::vector<uint8_t>& input,
                                           const std::optional<HardwareAuthToken>& optAuthToken,
                                           const std::optional<TimeStampToken>& optTimeStampToken) {
diff --git a/keystore2/src/km_compat/km_compat.h b/keystore2/src/km_compat/km_compat.h
index c4bcdaa..71f7fbe 100644
--- a/keystore2/src/km_compat/km_compat.h
+++ b/keystore2/src/km_compat/km_compat.h
@@ -147,6 +147,9 @@
                                  std::vector<uint8_t>* rootOfTrust);
     ScopedAStatus sendRootOfTrust(const std::vector<uint8_t>& rootOfTrust);
 
+    ScopedAStatus
+    setAdditionalAttestationInfo(const std::vector<KeyParameter>& additionalAttestationInfo);
+
     // These are public to allow testing code to use them directly.
     // This class should not be used publicly anyway.
     std::variant<std::vector<Certificate>, KMV1_ErrorCode>
diff --git a/keystore2/src/km_compat/km_compat_type_conversion.h b/keystore2/src/km_compat/km_compat_type_conversion.h
index 5db7e3d..d6a2dcc 100644
--- a/keystore2/src/km_compat/km_compat_type_conversion.h
+++ b/keystore2/src/km_compat/km_compat_type_conversion.h
@@ -750,8 +750,12 @@
     case KMV1::Tag::CERTIFICATE_SUBJECT:
     case KMV1::Tag::CERTIFICATE_NOT_BEFORE:
     case KMV1::Tag::CERTIFICATE_NOT_AFTER:
+        // These tags do not exist in KM < KeyMint 1.
+        break;
     case KMV1::Tag::ATTESTATION_ID_SECOND_IMEI:
-        // These tags do not exist in KM < KeyMint 1.0.
+        // This tag doesn't exist in KM < KeyMint 3.
+    case KMV1::Tag::MODULE_HASH:
+        // This tag doesn't exist in KM < KeyMint 4.
         break;
     case KMV1::Tag::MAX_BOOT_LEVEL:
         // Does not exist in API level 30 or below.
diff --git a/keystore2/src/permission.rs b/keystore2/src/permission.rs
index 7bf17b5..023774f 100644
--- a/keystore2/src/permission.rs
+++ b/keystore2/src/permission.rs
@@ -282,12 +282,19 @@
 ///                      SELinux keystore key backend, and the result is used
 ///                      as target context.
 pub fn check_grant_permission(
+    caller_uid: u32,
     caller_ctx: &CStr,
     access_vec: KeyPermSet,
     key: &KeyDescriptor,
 ) -> anyhow::Result<()> {
     let target_context = match key.domain {
-        Domain::APP => getcon().context("check_grant_permission: getcon failed.")?,
+        Domain::APP => {
+            if caller_uid as i64 != key.nspace {
+                return Err(selinux::Error::perm())
+                    .context("Trying to access key without ownership.");
+            }
+            getcon().context("check_grant_permission: getcon failed.")?
+        }
         Domain::SELINUX => lookup_keystore2_key_context(key.nspace)
             .context("check_grant_permission: Domain::SELINUX: Failed to lookup namespace.")?,
         _ => return Err(KsError::sys()).context(format!("Cannot grant {:?}.", key.domain)),
diff --git a/keystore2/src/permission/tests.rs b/keystore2/src/permission/tests.rs
index c9aebfe..68c9b74 100644
--- a/keystore2/src/permission/tests.rs
+++ b/keystore2/src/permission/tests.rs
@@ -135,11 +135,11 @@
 fn check_grant_permission_app() -> Result<()> {
     let system_server_ctx = Context::new("u:r:system_server:s0")?;
     let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None };
-    check_grant_permission(&system_server_ctx, SYSTEM_SERVER_PERMISSIONS_NO_GRANT, &key)
+    check_grant_permission(0, &system_server_ctx, SYSTEM_SERVER_PERMISSIONS_NO_GRANT, &key)
         .expect("Grant permission check failed.");
 
     // attempts to grant the grant permission must always fail even when privileged.
-    assert_perm_failed!(check_grant_permission(&system_server_ctx, KeyPerm::Grant.into(), &key));
+    assert_perm_failed!(check_grant_permission(0, &system_server_ctx, KeyPerm::Grant.into(), &key));
     Ok(())
 }
 
@@ -153,12 +153,12 @@
         blob: None,
     };
     if is_su {
-        assert!(check_grant_permission(&sctx, NOT_GRANT_PERMS, &key).is_ok());
+        assert!(check_grant_permission(0, &sctx, NOT_GRANT_PERMS, &key).is_ok());
         // attempts to grant the grant permission must always fail even when privileged.
-        assert_perm_failed!(check_grant_permission(&sctx, KeyPerm::Grant.into(), &key));
+        assert_perm_failed!(check_grant_permission(0, &sctx, KeyPerm::Grant.into(), &key));
     } else {
         // unprivileged grant attempts always fail. shell does not have the grant permission.
-        assert_perm_failed!(check_grant_permission(&sctx, UNPRIV_PERMS, &key));
+        assert_perm_failed!(check_grant_permission(0, &sctx, UNPRIV_PERMS, &key));
     }
     Ok(())
 }
diff --git a/keystore2/src/utils.rs b/keystore2/src/utils.rs
index 2b69d1e..c6dc11e 100644
--- a/keystore2/src/utils.rs
+++ b/keystore2/src/utils.rs
@@ -80,6 +80,7 @@
 pub fn check_grant_permission(access_vec: KeyPermSet, key: &KeyDescriptor) -> anyhow::Result<()> {
     ThreadState::with_calling_sid(|calling_sid| {
         permission::check_grant_permission(
+            ThreadState::get_calling_uid(),
             calling_sid
                 .ok_or_else(Error::sys)
                 .context(ks_err!("Cannot check permission without calling_sid."))?,
diff --git a/keystore2/test_utils/Android.bp b/keystore2/test_utils/Android.bp
index d0b5540..57da27f 100644
--- a/keystore2/test_utils/Android.bp
+++ b/keystore2/test_utils/Android.bp
@@ -62,8 +62,8 @@
     static_libs: [
         // Also include static_libs for the NDK variants so that they are available
         // for dependencies.
-        "android.system.keystore2-V4-ndk",
-        "android.hardware.security.keymint-V3-ndk",
+        "android.system.keystore2-V5-ndk",
+        "android.hardware.security.keymint-V4-ndk",
     ],
 }
 
diff --git a/keystore2/tests/Android.bp b/keystore2/tests/Android.bp
index 0406a71..1f3d0b8 100644
--- a/keystore2/tests/Android.bp
+++ b/keystore2/tests/Android.bp
@@ -31,11 +31,12 @@
     static_libs: [
         // Also include static_libs for the NDK variants so that they are available
         // for dependencies.
-        "android.system.keystore2-V4-ndk",
-        "android.hardware.security.keymint-V3-ndk",
+        "android.system.keystore2-V5-ndk",
+        "android.hardware.security.keymint-V4-ndk",
     ],
     srcs: ["keystore2_client_tests.rs"],
     test_suites: [
+        "automotive-sdv-tests",
         "general-tests",
         "vts",
     ],
diff --git a/keystore2/tests/keystore2_client_authorizations_tests.rs b/keystore2/tests/keystore2_client_authorizations_tests.rs
index bd9dab9..504e6ab 100644
--- a/keystore2/tests/keystore2_client_authorizations_tests.rs
+++ b/keystore2/tests/keystore2_client_authorizations_tests.rs
@@ -472,6 +472,13 @@
 #[test]
 fn keystore2_gen_key_auth_max_uses_per_boot() {
     let sl = SecLevel::tee();
+    if sl.is_keymaster() {
+        // Older devices with Keymaster implementation may use the key during generateKey to export
+        // the generated public key (EC Key), leading to an unnecessary increment of the
+        // key-associated counter. This can cause the test to fail, so skipping this test on older
+        // devices to avoid test failure.
+        return;
+    }
     const MAX_USES_COUNT: i32 = 3;
 
     let gen_params = authorizations::AuthSetBuilder::new()
diff --git a/keystore2/tests/keystore2_client_grant_key_tests.rs b/keystore2/tests/keystore2_client_grant_key_tests.rs
index 83d9753..c171ab1 100644
--- a/keystore2/tests/keystore2_client_grant_key_tests.rs
+++ b/keystore2/tests/keystore2_client_grant_key_tests.rs
@@ -204,11 +204,143 @@
     unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
 }
 
+/// Grant an SELINUX key to the user (grantee) with just `GET_INFO` key permissions. Verify whether
+/// grantee can succeed in loading the granted key and try to perform simple operation using this
+/// granted key.
+#[test]
+fn grant_selinux_key_get_info_only() {
+    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 (just) GET_INFO key permissions.
+    let grantor_fn = || {
+        let access_vector = KeyPermission::GET_INFO.0;
+        let grant_key = generate_and_grant_selinux_key(GRANTEE_UID, access_vector).unwrap();
+
+        assert_eq!(grant_key.domain, Domain::GRANT);
+
+        grant_key.nspace
+    };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder on the main thread.
+    let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
+
+    // In grantee context load the key and try to perform crypto operation.
+    let grantee_fn = move || {
+        let sl = SecLevel::tee();
+
+        // Load the granted key.
+        let key_entry_response = get_granted_key(&sl.keystore2, grant_key_nspace)
+            .expect("failed to get info for granted key");
+
+        // Attempt to perform sample crypto operation using granted key, now identified by <KEY_ID,
+        // key_id>.
+        let result = map_ks_error(
+            sl.binder.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::PERMISSION_DENIED), result.unwrap_err());
+
+        // Try to delete the key using a <GRANT, grant_id> descriptor.
+        let result =
+            map_ks_error(sl.keystore2.deleteKey(&granted_key_descriptor(grant_key_nspace)));
+        assert!(result.is_err());
+        assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+
+        // Try to delete the key using a <KEY_ID, key_id> descriptor.
+        let result = map_ks_error(sl.keystore2.deleteKey(&key_entry_response.metadata.key));
+        assert!(result.is_err());
+        assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+    };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder on the main thread.
+    unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
+}
+
+/// Grant an APP key to the user (grantee) with just `GET_INFO` key permissions. Verify whether
+/// grantee can succeed in loading the granted key and try to perform simple operation using this
+/// granted key.
+#[test]
+fn grant_app_key_get_info_only() {
+    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;
+    static ALIAS: &str = "ks_grant_key_info_only";
+
+    // Generate a key and grant it to a user with (just) GET_INFO key permissions.
+    let grantor_fn = || {
+        let sl = SecLevel::tee();
+        let access_vector = KeyPermission::GET_INFO.0;
+        let mut grant_keys = generate_ec_key_and_grant_to_users(
+            &sl,
+            Some(ALIAS.to_string()),
+            vec![GRANTEE_UID.try_into().unwrap()],
+            access_vector,
+        )
+        .unwrap();
+
+        grant_keys.remove(0)
+    };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder on the main thread.
+    let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
+
+    // In grantee context load the key and try to perform crypto operation.
+    let grantee_fn = move || {
+        let sl = SecLevel::tee();
+
+        // Load the granted key.
+        let key_entry_response = get_granted_key(&sl.keystore2, grant_key_nspace)
+            .expect("failed to get info for granted key");
+
+        // Attempt to perform sample crypto operation using granted key, now identified by <KEY_ID,
+        // key_id>.
+        let result = map_ks_error(
+            sl.binder.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::PERMISSION_DENIED), result.unwrap_err());
+
+        // Try to delete the key using a <GRANT, grant_id> descriptor.
+        let result =
+            map_ks_error(sl.keystore2.deleteKey(&granted_key_descriptor(grant_key_nspace)));
+        assert!(result.is_err());
+        assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+
+        // Try to delete the key using a <KEY_ID, key_id> descriptor.
+        let result = map_ks_error(sl.keystore2.deleteKey(&key_entry_response.metadata.key));
+        assert!(result.is_err());
+        assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+    };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder on the main thread.
+    unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
+}
+
 /// Grant an APP key to the user with DELETE access. In grantee context load the key and delete it.
 /// Verify that grantee should succeed in deleting the granted key and in grantor context test
 /// should fail to find the key with error response `KEY_NOT_FOUND`.
 #[test]
-fn grant_delete_key_success() {
+fn grant_app_key_delete_success() {
     const USER_ID: u32 = 99;
     const APPLICATION_ID: u32 = 10001;
     static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
@@ -267,8 +399,12 @@
 /// user from grantee context. Test should make sure second grantee should not have a access to
 /// granted key.
 #[test]
-#[ignore]
-fn grant_granted_key_fails() {
+fn grant_granted_app_key_fails() {
+    const GRANTOR_USER_ID: u32 = 97;
+    const GRANTOR_APPLICATION_ID: u32 = 10003;
+    static GRANTOR_UID: u32 = GRANTOR_USER_ID * AID_USER_OFFSET + GRANTOR_APPLICATION_ID;
+    static GRANTOR_GID: u32 = GRANTOR_UID;
+
     const USER_ID: u32 = 99;
     const APPLICATION_ID: u32 = 10001;
     static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
@@ -296,15 +432,24 @@
     };
     // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
     // `--test-threads=1`), and nothing yet done with binder.
-    let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
+    let grant_key_nspace = unsafe { run_as::run_as_app(GRANTOR_UID, GRANTOR_GID, grantor_fn) };
 
     // Grantee context, load the granted key and try to grant it to `SEC_GRANTEE_UID` grantee.
     let grantee_fn = move || {
         let keystore2 = get_keystore_service();
         let access_vector = KeyPermission::GET_INFO.0;
 
-        let key_entry_response = get_granted_key(&keystore2, grant_key_nspace).unwrap();
+        // Try to grant when identifying the key with <GRANT, grant_nspace>.
+        let result = map_ks_error(keystore2.grant(
+            &granted_key_descriptor(grant_key_nspace),
+            SEC_GRANTEE_UID.try_into().unwrap(),
+            access_vector,
+        ));
+        assert!(result.is_err());
+        assert_eq!(Error::Rc(ResponseCode::SYSTEM_ERROR), result.unwrap_err());
 
+        // Load the key info and try to grant when identifying the key with <KEY_ID, keyid>.
+        let key_entry_response = get_granted_key(&keystore2, grant_key_nspace).unwrap();
         let result = map_ks_error(keystore2.grant(
             &key_entry_response.metadata.key,
             SEC_GRANTEE_UID.try_into().unwrap(),
@@ -331,11 +476,88 @@
     unsafe { run_as::run_as_app(SEC_GRANTEE_UID, SEC_GRANTEE_GID, grantee2_fn) };
 }
 
+/// Grant an APP key to one user, from a normal user. Check that grantee context can load the
+/// granted key, but that a second unrelated context cannot.
+#[test]
+fn grant_app_key_only_to_grantee() {
+    const GRANTOR_USER_ID: u32 = 97;
+    const GRANTOR_APPLICATION_ID: u32 = 10003;
+    static GRANTOR_UID: u32 = GRANTOR_USER_ID * AID_USER_OFFSET + GRANTOR_APPLICATION_ID;
+    static GRANTOR_GID: u32 = GRANTOR_UID;
+
+    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;
+
+    const SEC_USER_ID: u32 = 98;
+    const SEC_APPLICATION_ID: u32 = 10001;
+    static SEC_GRANTEE_UID: u32 = SEC_USER_ID * AID_USER_OFFSET + SEC_APPLICATION_ID;
+    static SEC_GRANTEE_GID: u32 = SEC_GRANTEE_UID;
+
+    // Child function to generate a key and grant it to a user with `GET_INFO` permission.
+    let grantor_fn = || {
+        let sl = SecLevel::tee();
+        let access_vector = KeyPermission::GET_INFO.0;
+        let alias = format!("ks_grant_single_{}", getuid());
+        let mut grant_keys = generate_ec_key_and_grant_to_users(
+            &sl,
+            Some(alias),
+            vec![GRANTEE_UID.try_into().unwrap()],
+            access_vector,
+        )
+        .unwrap();
+
+        grant_keys.remove(0)
+    };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder on the main thread.
+    let grant_key_nspace = unsafe { run_as::run_as_app(GRANTOR_UID, GRANTOR_GID, grantor_fn) };
+
+    // Child function for the grantee context: can load the granted key.
+    let grantee_fn = move || {
+        let keystore2 = get_keystore_service();
+        let rsp = get_granted_key(&keystore2, grant_key_nspace).expect("failed to get granted key");
+
+        // Return the underlying key ID to simulate an ID leak.
+        assert_eq!(rsp.metadata.key.domain, Domain::KEY_ID);
+        rsp.metadata.key.nspace
+    };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder on the main thread.
+    let key_id = unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
+
+    // Second context does not have access to the above granted key, because it's identified
+    // by <uid, grant_nspace> and the implicit uid value is different.  Also, even if the
+    // second context gets hold of the key ID somehow, that also doesn't work.
+    let non_grantee_fn = move || {
+        let keystore2 = get_keystore_service();
+        let result = get_granted_key(&keystore2, grant_key_nspace);
+        assert!(result.is_err());
+        assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+
+        let result = map_ks_error(keystore2.getKeyEntry(&KeyDescriptor {
+            domain: Domain::KEY_ID,
+            nspace: key_id,
+            alias: None,
+            blob: None,
+        }));
+        assert!(result.is_err());
+        assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+    };
+
+    // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+    // `--test-threads=1`), and nothing yet done with binder on the main thread.
+    unsafe { run_as::run_as_app(SEC_GRANTEE_UID, SEC_GRANTEE_GID, non_grantee_fn) };
+}
+
 /// Try to grant an APP key with `GRANT` access. Keystore2 system shouldn't allow to grant a key
 /// with `GRANT` access. Test should fail to grant a key with `PERMISSION_DENIED` error response
 /// code.
 #[test]
-fn grant_key_with_grant_perm_fails() {
+fn grant_app_key_with_grant_perm_fails() {
     let sl = SecLevel::tee();
     let access_vector = KeyPermission::GRANT.0;
     let alias = format!("ks_grant_access_vec_key_{}", getuid());
@@ -381,7 +603,7 @@
 /// Grant an APP key to the user and immediately ungrant the granted key. In grantee context try to load
 /// the key. Grantee should fail to load the ungranted key with `KEY_NOT_FOUND` error response.
 #[test]
-fn ungrant_key_success() {
+fn ungrant_app_key_success() {
     const USER_ID: u32 = 99;
     const APPLICATION_ID: u32 = 10001;
     static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
@@ -436,7 +658,7 @@
 /// key in grantee context. Test should fail to load the granted key in grantee context as the
 /// associated key is deleted from grantor context.
 #[test]
-fn ungrant_deleted_key_fails() {
+fn ungrant_deleted_app_key_fails() {
     const APPLICATION_ID: u32 = 10001;
     const USER_ID: u32 = 99;
     static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
@@ -507,7 +729,7 @@
 /// Grant a key to multiple users. Verify that all grantees should succeed in loading the key and
 /// use it for performing an operation successfully.
 #[test]
-fn grant_key_to_multi_users_success() {
+fn grant_app_key_to_multi_users_success() {
     const APPLICATION_ID: u32 = 10001;
     const USER_ID_1: u32 = 99;
     static GRANTEE_1_UID: u32 = USER_ID_1 * AID_USER_OFFSET + APPLICATION_ID;
@@ -553,7 +775,7 @@
 /// use the key and delete it. Try to load the granted key in another grantee context. Test should
 /// fail to load the granted key with `KEY_NOT_FOUND` error response.
 #[test]
-fn grant_key_to_multi_users_delete_then_key_not_found() {
+fn grant_app_key_to_multi_users_delete_then_key_not_found() {
     const USER_ID_1: u32 = 99;
     const APPLICATION_ID: u32 = 10001;
     static GRANTEE_1_UID: u32 = USER_ID_1 * AID_USER_OFFSET + APPLICATION_ID;