diff options
Diffstat (limited to 'keystore2/tests/keystore2_client_update_subcomponent_tests.rs')
-rw-r--r-- | keystore2/tests/keystore2_client_update_subcomponent_tests.rs | 295 |
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()); +} |