summaryrefslogtreecommitdiff
path: root/keystore2/tests/keystore2_client_update_subcomponent_tests.rs
diff options
context:
space:
mode:
Diffstat (limited to 'keystore2/tests/keystore2_client_update_subcomponent_tests.rs')
-rw-r--r--keystore2/tests/keystore2_client_update_subcomponent_tests.rs295
1 files changed, 295 insertions, 0 deletions
diff --git a/keystore2/tests/keystore2_client_update_subcomponent_tests.rs b/keystore2/tests/keystore2_client_update_subcomponent_tests.rs
new file mode 100644
index 00000000..0be092f8
--- /dev/null
+++ b/keystore2/tests/keystore2_client_update_subcomponent_tests.rs
@@ -0,0 +1,295 @@
+// Copyright 2022, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use nix::unistd::{getuid, Gid, Uid};
+use rustutils::users::AID_USER_OFFSET;
+
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+ ErrorCode::ErrorCode, SecurityLevel::SecurityLevel,
+};
+use android_system_keystore2::aidl::android::system::keystore2::{
+ Domain::Domain, KeyDescriptor::KeyDescriptor, KeyPermission::KeyPermission,
+ ResponseCode::ResponseCode,
+};
+
+use keystore2_test_utils::{get_keystore_service, key_generations, key_generations::Error, run_as};
+
+/// Generate a key and update its public certificate and certificate chain. Test should be able to
+/// load the key and able to verify whether its certificate and cert-chain are updated successfully.
+#[test]
+fn keystore2_update_subcomponent_success() {
+ let alias = "update_subcomponent_success_key";
+
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let key_metadata = key_generations::generate_ec_p256_signing_key(
+ &sec_level,
+ Domain::SELINUX,
+ key_generations::SELINUX_SHELL_NAMESPACE,
+ Some(alias.to_string()),
+ None,
+ )
+ .unwrap();
+
+ let other_cert: [u8; 32] = [123; 32];
+ let other_cert_chain: [u8; 32] = [12; 32];
+
+ keystore2
+ .updateSubcomponent(&key_metadata.key, Some(&other_cert), Some(&other_cert_chain))
+ .expect("updateSubcomponent should have succeeded.");
+
+ let key_entry_response = keystore2.getKeyEntry(&key_metadata.key).unwrap();
+ assert_eq!(Some(other_cert.to_vec()), key_entry_response.metadata.certificate);
+ assert_eq!(Some(other_cert_chain.to_vec()), key_entry_response.metadata.certificateChain);
+}
+
+/// Try to update non-existing asymmetric key public cert and certificate chain. Test should fail
+/// to update with error response code `KEY_NOT_FOUND`.
+#[test]
+fn keystore2_update_subcomponent_fail() {
+ let alias = "update_component_failure_key";
+
+ let keystore2 = get_keystore_service();
+
+ let other_cert: [u8; 32] = [123; 32];
+ let other_cert_chain: [u8; 32] = [12; 32];
+
+ let result = key_generations::map_ks_error(keystore2.updateSubcomponent(
+ &KeyDescriptor {
+ domain: Domain::SELINUX,
+ nspace: key_generations::SELINUX_SHELL_NAMESPACE,
+ alias: Some(alias.to_string()),
+ blob: None,
+ },
+ Some(&other_cert),
+ Some(&other_cert_chain),
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+}
+
+/// Try to update non-existing asymmetric key public cert only. Test should fail
+/// to update with error response code `KEY_NOT_FOUND`.
+#[test]
+fn keystore2_update_subcomponent_no_key_entry_cert_fail() {
+ let alias = "update_no_key_entry_cert_only_component_fail_key";
+ let keystore2 = get_keystore_service();
+ let other_cert: [u8; 32] = [123; 32];
+
+ let result = key_generations::map_ks_error(keystore2.updateSubcomponent(
+ &KeyDescriptor {
+ domain: Domain::APP,
+ nspace: -1,
+ alias: Some(alias.to_string()),
+ blob: None,
+ },
+ Some(&other_cert),
+ None,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+}
+
+/// Try to update non existing key with the only given certificate-chain, test should succeed
+/// in creating a new keystore entry with the given certificate-chain.
+#[test]
+fn keystore2_update_subcomponent_no_key_entry_cert_chain_success() {
+ let alias = "update_no_key_entry_cert_chain_only_component_success";
+ let keystore2 = get_keystore_service();
+ let cert_entries =
+ vec![(Domain::SELINUX, key_generations::SELINUX_SHELL_NAMESPACE), (Domain::APP, -1)];
+ let other_cert_chain: [u8; 32] = [12; 32];
+
+ for (domain, nspace) in cert_entries {
+ keystore2
+ .updateSubcomponent(
+ &KeyDescriptor { domain, nspace, alias: Some(alias.to_string()), blob: None },
+ None,
+ Some(&other_cert_chain),
+ )
+ .expect("updateSubcomponent should have succeeded.");
+
+ let key_entry_response = keystore2
+ .getKeyEntry(&KeyDescriptor {
+ domain,
+ nspace,
+ alias: Some(alias.to_string()),
+ blob: None,
+ })
+ .unwrap();
+ assert_eq!(Some(other_cert_chain.to_vec()), key_entry_response.metadata.certificateChain);
+ assert!(key_entry_response.metadata.certificate.is_none(), "Unexpected certificate entry");
+ assert!(key_entry_response.metadata.authorizations.is_empty(), "Unexpected authorizations");
+ assert_eq!(key_entry_response.metadata.keySecurityLevel, SecurityLevel::SOFTWARE);
+
+ keystore2
+ .deleteKey(&KeyDescriptor {
+ domain,
+ nspace,
+ alias: Some(alias.to_string()),
+ blob: None,
+ })
+ .unwrap();
+ }
+}
+
+/// Generate a key and grant it to two users. For one user grant it with only `GET_INFO` access
+/// permission and for another user grant it with GET_INFO and UPDATE access permissions. In a
+/// grantee context where key is granted with only GET_INFO access permission, try to update
+/// key's public certificate and certificate chain. Test should fail to update with error response
+/// code `PERMISSION_DENIED` because grantee does not possess UPDATE access permission for the
+/// specified key. In a grantee context where key is granted with UPDATE and GET_INFO access
+/// permissions, test should be able to update public certificate and cert-chain successfully.
+#[test]
+fn keystore2_update_subcomponent_fails_permission_denied() {
+ static GRANTOR_SU_CTX: &str = "u:r:su:s0";
+ static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+
+ const USER_ID_1: u32 = 99;
+ const APPLICATION_ID: u32 = 10001;
+ static GRANTEE_1_UID: u32 = USER_ID_1 * AID_USER_OFFSET + APPLICATION_ID;
+ static GRANTEE_1_GID: u32 = GRANTEE_1_UID;
+
+ const USER_ID_2: u32 = 98;
+ static GRANTEE_2_UID: u32 = USER_ID_2 * AID_USER_OFFSET + APPLICATION_ID;
+ static GRANTEE_2_GID: u32 = GRANTEE_2_UID;
+
+ // Generate a key and grant it to multiple users with different access permissions.
+ let mut granted_keys = unsafe {
+ run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ let alias = format!("ks_update_subcompo_test_1_{}", getuid());
+ let mut granted_keys = Vec::new();
+
+ let key_metadata = key_generations::generate_ec_p256_signing_key(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias),
+ None,
+ )
+ .unwrap();
+
+ // Grant a key without update permission.
+ let access_vector = KeyPermission::GET_INFO.0;
+ let granted_key = keystore2
+ .grant(&key_metadata.key, GRANTEE_1_UID.try_into().unwrap(), access_vector)
+ .unwrap();
+ assert_eq!(granted_key.domain, Domain::GRANT);
+ granted_keys.push(granted_key.nspace);
+
+ // Grant a key with update permission.
+ let access_vector = KeyPermission::GET_INFO.0 | KeyPermission::UPDATE.0;
+ let granted_key = keystore2
+ .grant(&key_metadata.key, GRANTEE_2_UID.try_into().unwrap(), access_vector)
+ .unwrap();
+ assert_eq!(granted_key.domain, Domain::GRANT);
+ granted_keys.push(granted_key.nspace);
+
+ granted_keys
+ })
+ };
+
+ // Grantee context, try to update the key public certs, permission denied error is expected.
+ let granted_key1_nspace = granted_keys.remove(0);
+ unsafe {
+ run_as::run_as(
+ GRANTEE_CTX,
+ Uid::from_raw(GRANTEE_1_UID),
+ Gid::from_raw(GRANTEE_1_GID),
+ move || {
+ let keystore2 = get_keystore_service();
+
+ let other_cert: [u8; 32] = [123; 32];
+ let other_cert_chain: [u8; 32] = [12; 32];
+
+ let result = key_generations::map_ks_error(keystore2.updateSubcomponent(
+ &KeyDescriptor {
+ domain: Domain::GRANT,
+ nspace: granted_key1_nspace,
+ alias: None,
+ blob: None,
+ },
+ Some(&other_cert),
+ Some(&other_cert_chain),
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+ },
+ )
+ };
+
+ // Grantee context, update granted key public certs. Update should happen successfully.
+ let granted_key2_nspace = granted_keys.remove(0);
+ unsafe {
+ run_as::run_as(
+ GRANTEE_CTX,
+ Uid::from_raw(GRANTEE_2_UID),
+ Gid::from_raw(GRANTEE_2_GID),
+ move || {
+ let keystore2 = get_keystore_service();
+
+ let other_cert: [u8; 32] = [124; 32];
+ let other_cert_chain: [u8; 32] = [13; 32];
+
+ keystore2
+ .updateSubcomponent(
+ &KeyDescriptor {
+ domain: Domain::GRANT,
+ nspace: granted_key2_nspace,
+ alias: None,
+ blob: None,
+ },
+ Some(&other_cert),
+ Some(&other_cert_chain),
+ )
+ .expect("updateSubcomponent should have succeeded.");
+
+ let key_entry_response = keystore2
+ .getKeyEntry(&KeyDescriptor {
+ domain: Domain::GRANT,
+ nspace: granted_key2_nspace,
+ alias: None,
+ blob: None,
+ })
+ .unwrap();
+ assert_eq!(Some(other_cert.to_vec()), key_entry_response.metadata.certificate);
+ assert_eq!(
+ Some(other_cert_chain.to_vec()),
+ key_entry_response.metadata.certificateChain
+ );
+ },
+ )
+ };
+}
+
+#[test]
+fn keystore2_get_security_level_success() {
+ let keystore2 = get_keystore_service();
+ assert!(
+ keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).is_ok(),
+ "getSecurityLevel with SecurityLevel::TRUSTED_ENVIRONMENT should have succeeded."
+ );
+}
+
+#[test]
+fn keystore2_get_security_level_failure() {
+ let keystore2 = get_keystore_service();
+ let result = key_generations::map_ks_error(keystore2.getSecurityLevel(SecurityLevel::SOFTWARE));
+
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::HARDWARE_TYPE_UNAVAILABLE), result.unwrap_err());
+}