Check that caller has correct permissions when attesting device IDs
+ ran rustfmt to satisfy upload hooks.
Bug: 181114803
Test: atest keystore2_test
Test: atest KeyAttestationTest
Test: Disable all userspace permission checks, generate key setting
AttestationUtils.ID_TYPE_SERIAL, ensure it fails with message "Caller
does not have the permission to attest device identifiers"
Change-Id: Ia458e2b3d850c6a48424de8baceec162cd83e60d
diff --git a/keystore2/src/utils.rs b/keystore2/src/utils.rs
index 8e161b7..2748025 100644
--- a/keystore2/src/utils.rs
+++ b/keystore2/src/utils.rs
@@ -15,12 +15,13 @@
//! This module implements utility functions used by the Keystore 2.0 service
//! implementation.
-use crate::error::Error;
+use crate::error::{map_binder_status, Error, ErrorCode};
use crate::permission;
use crate::permission::{KeyPerm, KeyPermSet, KeystorePerm};
use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
- KeyCharacteristics::KeyCharacteristics,
+ KeyCharacteristics::KeyCharacteristics, Tag::Tag,
};
+use android_os_permissions_aidl::aidl::android::os::IPermissionController;
use android_security_apc::aidl::android::security::apc::{
IProtectedConfirmation::{FLAG_UI_OPTION_INVERTED, FLAG_UI_OPTION_MAGNIFIED},
ResponseCode::ResponseCode as ApcResponseCode,
@@ -88,6 +89,34 @@
})
}
+/// This function checks whether a given tag corresponds to the access of device identifiers.
+pub fn is_device_id_attestation_tag(tag: Tag) -> bool {
+ matches!(tag, Tag::ATTESTATION_ID_IMEI | Tag::ATTESTATION_ID_MEID | Tag::ATTESTATION_ID_SERIAL)
+}
+
+/// This function checks whether the calling app has the Android permissions needed to attest device
+/// identifiers. It throws an error if the permissions cannot be verified, or if the caller doesn't
+/// have the right permissions, and returns silently otherwise.
+pub fn check_device_attestation_permissions() -> anyhow::Result<()> {
+ let permission_controller: binder::Strong<dyn IPermissionController::IPermissionController> =
+ binder::get_interface("permission")?;
+
+ let binder_result = permission_controller.checkPermission(
+ "android.permission.READ_PRIVILEGED_PHONE_STATE",
+ ThreadState::get_calling_pid(),
+ ThreadState::get_calling_uid() as i32,
+ );
+ let has_permissions = map_binder_status(binder_result)
+ .context("In check_device_attestation_permissions: checkPermission failed")?;
+ match has_permissions {
+ true => Ok(()),
+ false => Err(Error::Km(ErrorCode::CANNOT_ATTEST_IDS)).context(concat!(
+ "In check_device_attestation_permissions: ",
+ "caller does not have the permission to attest device IDs"
+ )),
+ }
+}
+
/// Thread safe wrapper around SpIBinder. It is safe to have SpIBinder smart pointers to the
/// same object in multiple threads, but cloning a SpIBinder is not thread safe.
/// Keystore frequently hands out binder tokens to the security level interface. If this
@@ -193,3 +222,21 @@
pub fn uid_to_android_user(uid: u32) -> u32 {
uid / AID_USER_OFFSET
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use anyhow::Result;
+
+ #[test]
+ fn check_device_attestation_permissions_test() -> Result<()> {
+ check_device_attestation_permissions().or_else(|error| {
+ match error.root_cause().downcast_ref::<Error>() {
+ // Expected: the context for this test might not be allowed to attest device IDs.
+ Some(Error::Km(ErrorCode::CANNOT_ATTEST_IDS)) => Ok(()),
+ // Other errors are unexpected
+ _ => Err(error),
+ }
+ })
+ }
+}