Restructured keystore2 client tests.
Separated out the tests based on functionalities and created a separate
modules without modifying the existing test cases.
Bug: 194359114
Test: atest keystore2_client_test
Change-Id: Ifc93b3ce69817469d1d5f01844c623f5209e2b62
diff --git a/keystore2/tests/keystore2_client_aes_key_tests.rs b/keystore2/tests/keystore2_client_aes_key_tests.rs
new file mode 100644
index 0000000..989d047
--- /dev/null
+++ b/keystore2/tests/keystore2_client_aes_key_tests.rs
@@ -0,0 +1,466 @@
+// 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 android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+ Algorithm::Algorithm, BlockMode::BlockMode, ErrorCode::ErrorCode, KeyPurpose::KeyPurpose,
+ PaddingMode::PaddingMode, SecurityLevel::SecurityLevel,
+};
+
+use android_system_keystore2::aidl::android::system::keystore2::{
+ Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel, KeyDescriptor::KeyDescriptor,
+};
+
+use keystore2_test_utils::{
+ authorizations, get_keystore_service, key_generations, key_generations::Error,
+};
+
+use crate::keystore2_client_test_utils::{
+ perform_sample_sym_key_decrypt_op, perform_sample_sym_key_encrypt_op, SAMPLE_PLAIN_TEXT,
+};
+
+/// Generate a AES key. Create encrypt and decrypt operations using the generated key.
+fn create_aes_key_and_operation(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+ key_size: i32,
+ padding_mode: PaddingMode,
+ block_mode: BlockMode,
+ mac_len: Option<i32>,
+ min_mac_len: Option<i32>,
+ nonce: &mut Option<Vec<u8>>,
+) -> Result<(), binder::Status> {
+ let alias = format!("ks_aes_test_key_{}{}{}", key_size, block_mode.0, padding_mode.0);
+
+ let key_metadata = key_generations::generate_aes_key(
+ sec_level,
+ key_size,
+ &alias,
+ &padding_mode,
+ &block_mode,
+ min_mac_len,
+ )?;
+
+ let cipher_text = perform_sample_sym_key_encrypt_op(
+ sec_level,
+ padding_mode,
+ block_mode,
+ nonce,
+ mac_len,
+ &key_metadata.key,
+ )?;
+
+ assert!(cipher_text.is_some());
+
+ let plain_text = perform_sample_sym_key_decrypt_op(
+ sec_level,
+ &cipher_text.unwrap(),
+ padding_mode,
+ block_mode,
+ nonce,
+ mac_len,
+ &key_metadata.key,
+ )
+ .unwrap();
+ assert!(plain_text.is_some());
+ assert_eq!(plain_text.unwrap(), SAMPLE_PLAIN_TEXT.to_vec());
+ Ok(())
+}
+
+/// Generate AES keys with various block modes and paddings.
+/// - Block Modes: ECB, CBC
+/// - Padding Modes: NONE, PKCS7
+/// Test should generate keys and perform operation successfully.
+#[test]
+fn keystore2_aes_ecb_cbc_generate_key() {
+ let keystore2 = get_keystore_service();
+ let key_sizes = [128, 256];
+ let block_modes = [BlockMode::ECB, BlockMode::CBC];
+ let padding_modes = [PaddingMode::PKCS7, PaddingMode::NONE];
+
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ for key_size in key_sizes {
+ for block_mode in block_modes {
+ for padding_mode in padding_modes {
+ assert_eq!(
+ Ok(()),
+ create_aes_key_and_operation(
+ &sec_level,
+ key_size,
+ padding_mode,
+ block_mode,
+ None,
+ None,
+ &mut None,
+ )
+ );
+ }
+ }
+ }
+}
+
+/// Generate AES keys with -
+/// - Block Modes: `CTR, GCM`
+/// - Padding Modes: `NONE`
+/// Test should generate keys and perform operation successfully.
+#[test]
+fn keystore2_aes_ctr_gcm_generate_key_success() {
+ let keystore2 = get_keystore_service();
+ let key_sizes = [128, 256];
+ let key_params = [(BlockMode::CTR, None, None), (BlockMode::GCM, Some(128), Some(128))];
+
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ for key_size in key_sizes {
+ for (block_mode, mac_len, min_mac_len) in key_params {
+ let result = key_generations::map_ks_error(create_aes_key_and_operation(
+ &sec_level,
+ key_size,
+ PaddingMode::NONE,
+ block_mode,
+ mac_len,
+ min_mac_len,
+ &mut None,
+ ));
+
+ assert_eq!(Ok(()), result);
+ } // End of block mode.
+ } // End of key size.
+}
+
+/// Generate AES keys with -
+/// - Block Modes: `CTR, GCM`
+/// - Padding Modes: `PKCS7`
+/// Try to create an operation using generated keys, test should fail to create an operation
+/// with an error code `INCOMPATIBLE_PADDING_MODE`.
+#[test]
+fn keystore2_aes_ctr_gcm_generate_key_fails_incompatible() {
+ let keystore2 = get_keystore_service();
+ let key_sizes = [128, 256];
+ let key_params = [(BlockMode::CTR, None, None), (BlockMode::GCM, Some(128), Some(128))];
+
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ for key_size in key_sizes {
+ for (block_mode, mac_len, min_mac_len) in key_params {
+ let result = key_generations::map_ks_error(create_aes_key_and_operation(
+ &sec_level,
+ key_size,
+ PaddingMode::PKCS7,
+ block_mode,
+ mac_len,
+ min_mac_len,
+ &mut None,
+ ));
+
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PADDING_MODE), result.unwrap_err());
+ } // End of block mode.
+ } // End of key size.
+}
+
+/// Try to generate AES key with invalid key size. Test should fail to generate a key with
+/// an error code `UNSUPPORTED_KEY_SIZE`.
+#[test]
+fn keystore2_aes_key_fails_unsupported_key_size() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ let alias = "aes_key_test_invalid_1";
+
+ let result = key_generations::map_ks_error(key_generations::generate_aes_key(
+ &sec_level,
+ 1024,
+ alias,
+ &PaddingMode::NONE,
+ &BlockMode::ECB,
+ None,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_KEY_SIZE), result.unwrap_err());
+}
+
+/// Try to generate AES key with GCM block mode without providing `MIN_MAC_LENGTH`.
+/// Test should fail to generate a key with an error code `MISSING_MIN_MAC_LENGTH`.
+#[test]
+fn keystore2_aes_gcm_key_fails_missing_min_mac_len() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ let alias = "aes_key_test_invalid_1";
+
+ let result = key_generations::map_ks_error(key_generations::generate_aes_key(
+ &sec_level,
+ 128,
+ alias,
+ &PaddingMode::NONE,
+ &BlockMode::GCM,
+ None,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::MISSING_MIN_MAC_LENGTH), result.unwrap_err());
+}
+
+/// Try to create an operation using AES key with multiple block modes. Test should fail to create
+/// an operation with `UNSUPPORTED_BLOCK_MODE` error code.
+#[test]
+fn keystore2_aes_key_op_fails_multi_block_modes() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ let alias = "aes_key_test_invalid_1";
+
+ let gen_params = authorizations::AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::AES)
+ .purpose(KeyPurpose::ENCRYPT)
+ .purpose(KeyPurpose::DECRYPT)
+ .key_size(128)
+ .block_mode(BlockMode::ECB)
+ .block_mode(BlockMode::CBC)
+ .padding_mode(PaddingMode::NONE);
+
+ let key_metadata = sec_level
+ .generateKey(
+ &KeyDescriptor {
+ domain: Domain::APP,
+ nspace: -1,
+ alias: Some(alias.to_string()),
+ blob: None,
+ },
+ None,
+ &gen_params,
+ 0,
+ b"entropy",
+ )
+ .unwrap();
+
+ let op_params = authorizations::AuthSetBuilder::new()
+ .purpose(KeyPurpose::ENCRYPT)
+ .block_mode(BlockMode::ECB)
+ .block_mode(BlockMode::CBC)
+ .padding_mode(PaddingMode::NONE);
+
+ let result = key_generations::map_ks_error(sec_level.createOperation(
+ &key_metadata.key,
+ &op_params,
+ false,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_BLOCK_MODE), result.unwrap_err());
+}
+
+/// Try to create an operation using AES key with multiple padding modes. Test should fail to create
+/// an operation with `UNSUPPORTED_PADDING_MODE` error code.
+#[test]
+fn keystore2_aes_key_op_fails_multi_padding_modes() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ let alias = "aes_key_test_invalid_1";
+
+ let gen_params = authorizations::AuthSetBuilder::new()
+ .no_auth_required()
+ .algorithm(Algorithm::AES)
+ .purpose(KeyPurpose::ENCRYPT)
+ .purpose(KeyPurpose::DECRYPT)
+ .key_size(128)
+ .block_mode(BlockMode::ECB)
+ .padding_mode(PaddingMode::PKCS7)
+ .padding_mode(PaddingMode::NONE);
+
+ let key_metadata = sec_level
+ .generateKey(
+ &KeyDescriptor {
+ domain: Domain::APP,
+ nspace: -1,
+ alias: Some(alias.to_string()),
+ blob: None,
+ },
+ None,
+ &gen_params,
+ 0,
+ b"entropy",
+ )
+ .unwrap();
+
+ let op_params = authorizations::AuthSetBuilder::new()
+ .purpose(KeyPurpose::ENCRYPT)
+ .block_mode(BlockMode::ECB)
+ .padding_mode(PaddingMode::PKCS7)
+ .padding_mode(PaddingMode::NONE);
+
+ let result = key_generations::map_ks_error(sec_level.createOperation(
+ &key_metadata.key,
+ &op_params,
+ false,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_PADDING_MODE), result.unwrap_err());
+}
+
+/// Generate a AES-ECB key with unpadded mode. Try to create an operation using generated key
+/// with PKCS7 padding mode. Test should fail to create an Operation with
+/// `INCOMPATIBLE_PADDING_MODE` error code.
+#[test]
+fn keystore2_aes_key_op_fails_incompatible_padding() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ let alias = "aes_key_test_invalid_1";
+
+ let key_metadata = key_generations::generate_aes_key(
+ &sec_level,
+ 128,
+ alias,
+ &PaddingMode::NONE,
+ &BlockMode::ECB,
+ None,
+ )
+ .unwrap();
+
+ let result = key_generations::map_ks_error(perform_sample_sym_key_encrypt_op(
+ &sec_level,
+ PaddingMode::PKCS7,
+ BlockMode::ECB,
+ &mut None,
+ None,
+ &key_metadata.key,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PADDING_MODE), result.unwrap_err());
+}
+
+/// Generate a AES-ECB key with unpadded mode. Try to create an operation using generated key
+/// with CBC block mode. Test should fail to create an Operation with
+/// `INCOMPATIBLE_BLOCK_MODE` error code.
+#[test]
+fn keystore2_aes_key_op_fails_incompatible_blockmode() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ let alias = "aes_key_test_invalid_1";
+
+ let key_metadata = key_generations::generate_aes_key(
+ &sec_level,
+ 128,
+ alias,
+ &PaddingMode::NONE,
+ &BlockMode::ECB,
+ None,
+ )
+ .unwrap();
+
+ let result = key_generations::map_ks_error(perform_sample_sym_key_encrypt_op(
+ &sec_level,
+ PaddingMode::NONE,
+ BlockMode::CBC,
+ &mut None,
+ None,
+ &key_metadata.key,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_BLOCK_MODE), result.unwrap_err());
+}
+
+/// Generate a AES-GCM key with `MIN_MAC_LENGTH`. Try to create an operation using this
+/// generated key without providing `MAC_LENGTH`. Test should fail to create an operation with
+/// `MISSING_MAC_LENGTH` error code.
+#[test]
+fn keystore2_aes_gcm_op_fails_missing_mac_len() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ let mac_len = None;
+ let min_mac_len = Some(128);
+
+ let result = key_generations::map_ks_error(create_aes_key_and_operation(
+ &sec_level,
+ 128,
+ PaddingMode::NONE,
+ BlockMode::GCM,
+ mac_len,
+ min_mac_len,
+ &mut None,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::MISSING_MAC_LENGTH), result.unwrap_err());
+}
+
+/// Generate a AES-GCM key with `MIN_MAC_LENGTH`. Try to create an operation using this
+/// generated key and provide `MAC_LENGTH` < key's `MIN_MAC_LENGTH`. Test should fail to create
+/// an operation with `INVALID_MAC_LENGTH` error code.
+#[test]
+fn keystore2_aes_gcm_op_fails_invalid_mac_len() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ let mac_len = Some(96);
+ let min_mac_len = Some(104);
+
+ let result = key_generations::map_ks_error(create_aes_key_and_operation(
+ &sec_level,
+ 128,
+ PaddingMode::NONE,
+ BlockMode::GCM,
+ mac_len,
+ min_mac_len,
+ &mut None,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::INVALID_MAC_LENGTH), result.unwrap_err());
+}
+
+/// Generate a AES-GCM key with `MIN_MAC_LENGTH`. Try to create an operation using this
+/// generated key and provide `MAC_LENGTH` > 128. Test should fail to create an operation with
+/// `UNSUPPORTED_MAC_LENGTH` error code.
+#[test]
+fn keystore2_aes_gcm_op_fails_unsupported_mac_len() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let result = key_generations::map_ks_error(create_aes_key_and_operation(
+ &sec_level,
+ 128,
+ PaddingMode::NONE,
+ BlockMode::GCM,
+ Some(256),
+ Some(128),
+ &mut None,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_MAC_LENGTH), result.unwrap_err());
+}
+
+/// Generate a AES-CBC-PKCS7 key without `CALLER_NONCE` authorization. Try to set nonce while
+/// creating an operation using this generated key. Test should fail to create an operation with
+/// `CALLER_NONCE_PROHIBITED` error code.
+#[test]
+fn keystore2_aes_key_op_fails_nonce_prohibited() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ let alias = "aes_key_test_nonce_1";
+ let mut nonce = Some(vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
+
+ let key_metadata = key_generations::generate_aes_key(
+ &sec_level,
+ 128,
+ alias,
+ &PaddingMode::PKCS7,
+ &BlockMode::CBC,
+ None,
+ )
+ .unwrap();
+
+ let result = key_generations::map_ks_error(perform_sample_sym_key_encrypt_op(
+ &sec_level,
+ PaddingMode::NONE,
+ BlockMode::CBC,
+ &mut nonce,
+ None,
+ &key_metadata.key,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::CALLER_NONCE_PROHIBITED), result.unwrap_err());
+}
diff --git a/keystore2/tests/keystore2_client_ec_key_tests.rs b/keystore2/tests/keystore2_client_ec_key_tests.rs
new file mode 100644
index 0000000..60bcddf
--- /dev/null
+++ b/keystore2/tests/keystore2_client_ec_key_tests.rs
@@ -0,0 +1,412 @@
+// 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::{
+ Algorithm::Algorithm, Digest::Digest, EcCurve::EcCurve, ErrorCode::ErrorCode,
+ KeyPurpose::KeyPurpose, SecurityLevel::SecurityLevel,
+};
+use android_system_keystore2::aidl::android::system::keystore2::{
+ Domain::Domain, KeyDescriptor::KeyDescriptor, ResponseCode::ResponseCode,
+};
+
+use keystore2_test_utils::{
+ authorizations, get_keystore_service, key_generations, key_generations::Error, run_as,
+};
+
+use crate::keystore2_client_test_utils::{
+ execute_op_run_as_child, perform_sample_sign_operation, BarrierReached, ForcedOp, TestOutcome,
+};
+
+/// This test will try to load the key with Domain::BLOB.
+/// INVALID_ARGUMENT error is expected.
+#[test]
+fn keystore2_get_key_entry_blob_fail() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ // Generate a key with domain as BLOB.
+ let key_metadata = key_generations::generate_ec_p256_signing_key(
+ &sec_level,
+ Domain::BLOB,
+ key_generations::SELINUX_SHELL_NAMESPACE,
+ None,
+ None,
+ None,
+ )
+ .unwrap();
+
+ // Try to load the key using above generated KeyDescriptor.
+ let result = key_generations::map_ks_error(keystore2.getKeyEntry(&key_metadata.key));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::INVALID_ARGUMENT), result.unwrap_err());
+
+ // Delete the generated key blob.
+ sec_level.deleteKey(&key_metadata.key).unwrap();
+}
+
+/// 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();
+}
diff --git a/keystore2/tests/keystore2_client_grant_key_tests.rs b/keystore2/tests/keystore2_client_grant_key_tests.rs
new file mode 100644
index 0000000..827a0de
--- /dev/null
+++ b/keystore2/tests/keystore2_client_grant_key_tests.rs
@@ -0,0 +1,206 @@
+// 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::{
+ Digest::Digest, KeyPurpose::KeyPurpose, SecurityLevel::SecurityLevel,
+};
+use android_system_keystore2::aidl::android::system::keystore2::{
+ Domain::Domain, KeyDescriptor::KeyDescriptor, KeyPermission::KeyPermission,
+ ResponseCode::ResponseCode,
+};
+
+use keystore2_test_utils::{
+ authorizations, get_keystore_service, key_generations, key_generations::Error, run_as,
+};
+
+use crate::keystore2_client_test_utils::perform_sample_sign_operation;
+
+/// 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)
+}
+
+/// 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());
+ },
+ )
+ };
+}
diff --git a/keystore2/tests/keystore2_client_key_id_domain_tests.rs b/keystore2/tests/keystore2_client_key_id_domain_tests.rs
new file mode 100644
index 0000000..2a1d990
--- /dev/null
+++ b/keystore2/tests/keystore2_client_key_id_domain_tests.rs
@@ -0,0 +1,257 @@
+// 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;
+
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+ Digest::Digest, EcCurve::EcCurve, KeyPurpose::KeyPurpose, SecurityLevel::SecurityLevel,
+};
+use android_system_keystore2::aidl::android::system::keystore2::{
+ Domain::Domain, KeyDescriptor::KeyDescriptor, ResponseCode::ResponseCode,
+};
+
+use keystore2_test_utils::{
+ authorizations, get_keystore_service, key_generations, key_generations::Error,
+};
+
+use crate::keystore2_client_test_utils::perform_sample_sign_operation;
+
+/// 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/keystore2_client_operation_tests.rs b/keystore2/tests/keystore2_client_operation_tests.rs
new file mode 100644
index 0000000..d8b85f6
--- /dev/null
+++ b/keystore2/tests/keystore2_client_operation_tests.rs
@@ -0,0 +1,404 @@
+// 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::{
+ Digest::Digest, ErrorCode::ErrorCode, KeyPurpose::KeyPurpose, SecurityLevel::SecurityLevel,
+};
+use android_system_keystore2::aidl::android::system::keystore2::{
+ CreateOperationResponse::CreateOperationResponse, Domain::Domain, ResponseCode::ResponseCode,
+};
+
+use keystore2_test_utils::{
+ authorizations, get_keystore_service, key_generations, key_generations::Error, run_as,
+};
+
+use crate::keystore2_client_test_utils::{
+ create_signing_operation, execute_op_run_as_child, perform_sample_sign_operation,
+ BarrierReached, ForcedOp, TestOutcome,
+};
+
+/// Create `max_ops` number child processes with the given context and perform an operation under each
+/// child process.
+pub fn create_operations(
+ target_ctx: &'static str,
+ forced_op: ForcedOp,
+ max_ops: i32,
+) -> Vec<run_as::ChildHandle<TestOutcome, BarrierReached>> {
+ let alias = format!("ks_op_test_key_{}", getuid());
+ let base_gid = 99 * AID_USER_OFFSET + 10001;
+ let base_uid = 99 * AID_USER_OFFSET + 10001;
+ (0..max_ops)
+ .into_iter()
+ .map(|i| {
+ execute_op_run_as_child(
+ target_ctx,
+ Domain::APP,
+ key_generations::SELINUX_SHELL_NAMESPACE,
+ Some(alias.to_string()),
+ Uid::from_raw(base_uid + (i as u32)),
+ Gid::from_raw(base_gid + (i as u32)),
+ forced_op,
+ )
+ })
+ .collect()
+}
+
+/// This test verifies that backend service throws BACKEND_BUSY error when all
+/// operations slots are full. This test creates operations in child processes and
+/// collects the status of operations performed in each child proc and determines
+/// whether any child proc exited with error status.
+#[test]
+fn keystore2_backend_busy_test() {
+ const MAX_OPS: i32 = 100;
+ static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+
+ let mut child_handles = create_operations(TARGET_CTX, ForcedOp(false), MAX_OPS);
+
+ // Wait until all child procs notifies us to continue,
+ // so that there are definitely enough operations outstanding to trigger a BACKEND_BUSY.
+ for ch in child_handles.iter_mut() {
+ ch.recv();
+ }
+ // Notify each child to resume and finish.
+ for ch in child_handles.iter_mut() {
+ ch.send(&BarrierReached {});
+ }
+
+ // Collect the result and validate whether backend busy has occurred.
+ let mut busy_count = 0;
+ for ch in child_handles.into_iter() {
+ if ch.get_result() == TestOutcome::BackendBusy {
+ busy_count += 1;
+ }
+ }
+ assert!(busy_count > 0)
+}
+
+/// This test confirms that forced operation is having high pruning power.
+/// 1. Initially create regular operations such that there are enough operations outstanding
+/// to trigger BACKEND_BUSY.
+/// 2. Then, create a forced operation. System should be able to prune one of the regular
+/// operations and create a slot for forced operation successfully.
+#[test]
+fn keystore2_forced_op_after_backendbusy_test() {
+ const MAX_OPS: i32 = 100;
+ static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+
+ // Create regular operations.
+ let mut child_handles = create_operations(TARGET_CTX, ForcedOp(false), MAX_OPS);
+
+ // Wait until all child procs notifies us to continue, so that there are enough
+ // operations outstanding to trigger a BACKEND_BUSY.
+ for ch in child_handles.iter_mut() {
+ ch.recv();
+ }
+
+ // Create a forced operation.
+ let auid = 99 * AID_USER_OFFSET + 10604;
+ let agid = 99 * AID_USER_OFFSET + 10604;
+ unsafe {
+ run_as::run_as(
+ key_generations::TARGET_VOLD_CTX,
+ Uid::from_raw(auid),
+ Gid::from_raw(agid),
+ move || {
+ let alias = format!("ks_prune_forced_op_key_{}", getuid());
+
+ // To make room for this forced op, system should be able to prune one of the
+ // above created regular operations and create a slot for this forced operation
+ // successfully.
+ create_signing_operation(
+ ForcedOp(true),
+ KeyPurpose::SIGN,
+ Digest::SHA_2_256,
+ Domain::SELINUX,
+ 100,
+ Some(alias),
+ )
+ .expect("Client failed to create forced operation after BACKEND_BUSY state.");
+ },
+ );
+ };
+
+ // Notify each child to resume and finish.
+ for ch in child_handles.iter_mut() {
+ ch.send(&BarrierReached {});
+ }
+
+ // Collect the results of above created regular operations.
+ let mut pruned_count = 0;
+ let mut busy_count = 0;
+ let mut _other_err = 0;
+ for ch in child_handles.into_iter() {
+ match ch.get_result() {
+ TestOutcome::BackendBusy => {
+ busy_count += 1;
+ }
+ TestOutcome::InvalidHandle => {
+ pruned_count += 1;
+ }
+ _ => {
+ _other_err += 1;
+ }
+ }
+ }
+ // Verify that there should be at least one backend busy has occurred while creating
+ // above regular operations.
+ assert!(busy_count > 0);
+
+ // Verify that there should be at least one pruned operation which should have failed while
+ // performing operation.
+ assert!(pruned_count > 0);
+}
+
+/// This test confirms that forced operations can't be pruned.
+/// 1. Creates an initial forced operation and tries to complete the operation after BACKEND_BUSY
+/// error is triggered.
+/// 2. Create MAX_OPS number of forced operations so that definitely enough number of operations
+/// outstanding to trigger a BACKEND_BUSY.
+/// 3. Try to use initially created forced operation (in step #1) and able to perform the
+/// operation successfully. This confirms that none of the later forced operations evicted the
+/// initial forced operation.
+#[test]
+fn keystore2_max_forced_ops_test() {
+ const MAX_OPS: i32 = 100;
+ let auid = 99 * AID_USER_OFFSET + 10205;
+ let agid = 99 * AID_USER_OFFSET + 10205;
+
+ // Create initial forced operation in a child process
+ // and wait for the parent to notify to perform operation.
+ let alias = format!("ks_forced_op_key_{}", getuid());
+ let mut first_op_handle = execute_op_run_as_child(
+ key_generations::TARGET_SU_CTX,
+ Domain::SELINUX,
+ key_generations::SELINUX_SHELL_NAMESPACE,
+ Some(alias),
+ Uid::from_raw(auid),
+ Gid::from_raw(agid),
+ ForcedOp(true),
+ );
+
+ // Wait until above child proc notifies us to continue, so that there is definitely a forced
+ // operation outstanding to perform a operation.
+ first_op_handle.recv();
+
+ // Create MAX_OPS number of forced operations.
+ let mut child_handles =
+ create_operations(key_generations::TARGET_SU_CTX, ForcedOp(true), MAX_OPS);
+
+ // Wait until all child procs notifies us to continue, so that there are enough operations
+ // outstanding to trigger a BACKEND_BUSY.
+ for ch in child_handles.iter_mut() {
+ ch.recv();
+ }
+
+ // Notify initial created forced operation to continue performing the operations.
+ first_op_handle.send(&BarrierReached {});
+
+ // Collect initially created forced operation result and is expected to complete operation
+ // successfully.
+ let first_op_result = first_op_handle.get_result();
+ assert_eq!(first_op_result, TestOutcome::Ok);
+
+ // Notify each child to resume and finish.
+ for ch in child_handles.iter_mut() {
+ ch.send(&BarrierReached {});
+ }
+
+ // Collect the result and validate whether backend busy has occurred with MAX_OPS number
+ // of forced operations.
+ let busy_count = child_handles
+ .into_iter()
+ .map(|ch| ch.get_result())
+ .filter(|r| *r == TestOutcome::BackendBusy)
+ .count();
+ assert!(busy_count > 0);
+}
+
+/// This test will verify the use case with the same owner(UID) requesting `n` number of operations.
+/// This test confirms that when all operation slots are full and a new operation is requested,
+/// an operation which is least recently used and lived longest will be pruned to make a room
+/// for a new operation. Pruning strategy should prevent the operations of the other owners(UID)
+/// from being pruned.
+///
+/// 1. Create an operation in a child process with `untrusted_app` context and wait for parent
+/// notification to complete the operation.
+/// 2. Let parent process create `n` number of operations such that there are enough operations
+/// outstanding to trigger cannibalizing their own sibling operations.
+/// 3. Sequentially try to use above created `n` number of operations and also add a new operation,
+/// so that it should trigger cannibalizing one of their own sibling operations.
+/// 3.1 While trying to use these pruned operations an `INVALID_OPERATION_HANDLE` error is
+/// expected as they are already pruned.
+/// 4. Notify the child process to resume and complete the operation. It is expected to complete the
+/// operation successfully.
+/// 5. Try to use the latest operation of parent. It is expected to complete the operation
+/// successfully.
+#[test]
+fn keystore2_ops_prune_test() {
+ const MAX_OPS: usize = 40; // This should be at least 32 with sec_level TEE.
+
+ static TARGET_CTX: &str = "u:r:untrusted_app:s0";
+ const USER_ID: u32 = 99;
+ const APPLICATION_ID: u32 = 10601;
+
+ let uid = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+ let gid = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+
+ // Create an operation in an untrusted_app context. Wait until the parent notifies to continue.
+ // Once the parent notifies, this operation is expected to be completed successfully.
+ let alias = format!("ks_reg_op_key_{}", getuid());
+ let mut child_handle = execute_op_run_as_child(
+ TARGET_CTX,
+ Domain::APP,
+ -1,
+ Some(alias),
+ Uid::from_raw(uid),
+ Gid::from_raw(gid),
+ ForcedOp(false),
+ );
+
+ // Wait until child process notifies us to continue, so that an operation from child process is
+ // outstanding to complete the operation.
+ child_handle.recv();
+
+ // Generate a key to use in below operations.
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ let alias = format!("ks_prune_op_test_key_{}", 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();
+
+ // Create multiple operations in this process to trigger cannibalizing sibling operations.
+ let mut ops: Vec<binder::Result<CreateOperationResponse>> = (0..MAX_OPS)
+ .into_iter()
+ .map(|_| {
+ sec_level.createOperation(
+ &key_metadata.key,
+ &authorizations::AuthSetBuilder::new()
+ .purpose(KeyPurpose::SIGN)
+ .digest(Digest::SHA_2_256),
+ false,
+ )
+ })
+ .collect();
+
+ // Sequentially try to use operation handles created above and also add a new operation.
+ for vec_index in 0..MAX_OPS {
+ match &ops[vec_index] {
+ Ok(CreateOperationResponse { iOperation: Some(op), .. }) => {
+ // Older operation handle is pruned, if we try to use that an error is expected.
+ assert_eq!(
+ Err(Error::Km(ErrorCode::INVALID_OPERATION_HANDLE)),
+ key_generations::map_ks_error(op.update(b"my message"))
+ );
+ }
+ _ => panic!("Operation should have created successfully."),
+ }
+
+ // Create a new operation, it should trigger to cannibalize one of their own sibling
+ // operations.
+ ops.push(
+ sec_level.createOperation(
+ &key_metadata.key,
+ &authorizations::AuthSetBuilder::new()
+ .purpose(KeyPurpose::SIGN)
+ .digest(Digest::SHA_2_256),
+ false,
+ ),
+ );
+ }
+
+ // Notify child process to continue the operation.
+ child_handle.send(&BarrierReached {});
+ assert!((child_handle.get_result() == TestOutcome::Ok), "Failed to perform an operation");
+
+ // Try to use the latest operation created by parent, should be able to use it successfully.
+ match ops.last() {
+ Some(Ok(CreateOperationResponse { iOperation: Some(op), .. })) => {
+ assert_eq!(Ok(()), key_generations::map_ks_error(perform_sample_sign_operation(op)));
+ }
+ _ => panic!("Operation should have created successfully."),
+ }
+}
+
+/// Try to create forced operations with various contexts -
+/// - untrusted_app
+/// - system_server
+/// - priv_app
+/// `PERMISSION_DENIED` error response is expected.
+#[test]
+fn keystore2_forced_op_perm_denied_test() {
+ static TARGET_CTXS: &[&str] =
+ &["u:r:untrusted_app:s0", "u:r:system_server:s0", "u:r:priv_app:s0"];
+ const USER_ID: u32 = 99;
+ const APPLICATION_ID: u32 = 10601;
+
+ let uid = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+ let gid = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+
+ for context in TARGET_CTXS.iter() {
+ unsafe {
+ run_as::run_as(context, Uid::from_raw(uid), Gid::from_raw(gid), move || {
+ let alias = format!("ks_app_forced_op_test_key_{}", getuid());
+ let result = key_generations::map_ks_error(create_signing_operation(
+ ForcedOp(true),
+ KeyPurpose::SIGN,
+ Digest::SHA_2_256,
+ Domain::APP,
+ -1,
+ Some(alias),
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+ });
+ }
+ }
+}
+
+/// Try to create a forced operation with `vold` context.
+/// Should be able to create forced operation with `vold` context successfully.
+#[test]
+fn keystore2_forced_op_success_test() {
+ static TARGET_CTX: &str = "u:r:vold:s0";
+ const USER_ID: u32 = 99;
+ const APPLICATION_ID: u32 = 10601;
+
+ let uid = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+ let gid = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
+
+ unsafe {
+ run_as::run_as(TARGET_CTX, Uid::from_raw(uid), Gid::from_raw(gid), move || {
+ let alias = format!("ks_vold_forced_op_key_{}", getuid());
+ create_signing_operation(
+ ForcedOp(true),
+ KeyPurpose::SIGN,
+ Digest::SHA_2_256,
+ Domain::SELINUX,
+ key_generations::SELINUX_VOLD_NAMESPACE,
+ Some(alias),
+ )
+ .expect("Client with vold context failed to create forced operation.");
+ });
+ }
+}
diff --git a/keystore2/tests/keystore2_client_rsa_key_tests.rs b/keystore2/tests/keystore2_client_rsa_key_tests.rs
new file mode 100644
index 0000000..aa822b9
--- /dev/null
+++ b/keystore2/tests/keystore2_client_rsa_key_tests.rs
@@ -0,0 +1,848 @@
+// 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;
+
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+ BlockMode::BlockMode, Digest::Digest, ErrorCode::ErrorCode, KeyPurpose::KeyPurpose,
+ PaddingMode::PaddingMode, SecurityLevel::SecurityLevel,
+};
+use android_system_keystore2::aidl::android::system::keystore2::{
+ CreateOperationResponse::CreateOperationResponse, Domain::Domain,
+ IKeystoreSecurityLevel::IKeystoreSecurityLevel,
+};
+
+use keystore2_test_utils::{
+ authorizations, get_keystore_service, key_generations, key_generations::Error,
+};
+
+use crate::keystore2_client_test_utils::{perform_sample_sign_operation, ForcedOp};
+
+/// Generate a RSA key and create an operation using the generated key.
+fn create_rsa_key_and_operation(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+ domain: Domain,
+ nspace: i64,
+ alias: Option<String>,
+ key_params: &key_generations::KeyParams,
+ op_purpose: KeyPurpose,
+ forced_op: ForcedOp,
+) -> binder::Result<CreateOperationResponse> {
+ let key_metadata =
+ key_generations::generate_rsa_key(sec_level, domain, nspace, alias, key_params, None)?;
+
+ let mut op_params = authorizations::AuthSetBuilder::new().purpose(op_purpose);
+
+ if let Some(value) = key_params.digest {
+ op_params = op_params.digest(value)
+ }
+ if let Some(value) = key_params.padding {
+ op_params = op_params.padding_mode(value);
+ }
+ if let Some(value) = key_params.mgf_digest {
+ op_params = op_params.mgf_digest(value);
+ }
+ if let Some(value) = key_params.block_mode {
+ op_params = op_params.block_mode(value)
+ }
+
+ sec_level.createOperation(&key_metadata.key, &op_params, forced_op.0)
+}
+
+/// Generate RSA signing keys with -
+/// Padding mode: RSA_PKCS1_1_5_SIGN
+/// Digest modes: `NONE, MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
+/// Create operations with these generated keys. Test should create operations successfully.
+#[test]
+fn keystore2_rsa_generate_signing_key_padding_pkcs1_1_5() {
+ 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 key_sizes = [2048, 3072, 4096];
+
+ for key_size in key_sizes {
+ for digest in digests {
+ let alias = format!("ks_rsa_key_test_{}{}{}", getuid(), key_size, digest.0);
+ let op_response = create_rsa_key_and_operation(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ &key_generations::KeyParams {
+ key_size,
+ purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
+ padding: Some(PaddingMode::RSA_PKCS1_1_5_SIGN),
+ digest: Some(digest),
+ mgf_digest: None,
+ block_mode: None,
+ att_challenge: None,
+ att_app_id: None,
+ },
+ KeyPurpose::SIGN,
+ ForcedOp(false),
+ )
+ .unwrap();
+
+ assert!(op_response.iOperation.is_some());
+ assert_eq!(
+ Ok(()),
+ key_generations::map_ks_error(perform_sample_sign_operation(
+ &op_response.iOperation.unwrap()
+ ))
+ );
+ } // End of digests.
+ } // End of key-sizes.
+}
+
+/// Generate RSA signing keys with -
+/// Padding mode: RSA_PSS
+/// Digest modes: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
+/// Create operations with these generated keys. Test should create operations successfully.
+#[test]
+fn keystore2_rsa_generate_signing_key_padding_pss_success() {
+ 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,
+ ];
+
+ let key_sizes = [2048, 3072, 4096];
+
+ for key_size in key_sizes {
+ for digest in digests {
+ let alias = format!("ks_rsa_key_test_{}{}{}", getuid(), key_size, digest.0);
+ let op_response = create_rsa_key_and_operation(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ &key_generations::KeyParams {
+ key_size,
+ purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
+ padding: Some(PaddingMode::RSA_PSS),
+ digest: Some(digest),
+ mgf_digest: None,
+ block_mode: None,
+ att_challenge: None,
+ att_app_id: None,
+ },
+ KeyPurpose::SIGN,
+ ForcedOp(false),
+ )
+ .unwrap();
+
+ assert!(op_response.iOperation.is_some());
+ assert_eq!(
+ Ok(()),
+ key_generations::map_ks_error(perform_sample_sign_operation(
+ &op_response.iOperation.unwrap()
+ ))
+ );
+ } // End of digests.
+ } // End of key-sizes.
+}
+
+/// Generate RSA signing key with -
+/// Padding mode: RSA_PSS
+/// Digest mode: `NONE`.
+/// Try to create an operation with this generated key. Test should fail to create an operation with
+/// `INCOMPATIBLE_DIGEST` error code.
+#[test]
+fn keystore2_rsa_generate_signing_key_padding_pss_fail() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let key_sizes = [2048, 3072, 4096];
+
+ for key_size in key_sizes {
+ let alias = format!("ks_rsa_pss_none_key_test_{}{}", getuid(), key_size);
+ let result = key_generations::map_ks_error(create_rsa_key_and_operation(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ &key_generations::KeyParams {
+ key_size,
+ purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
+ padding: Some(PaddingMode::RSA_PSS),
+ digest: Some(Digest::NONE),
+ mgf_digest: None,
+ block_mode: None,
+ att_challenge: None,
+ att_app_id: None,
+ },
+ KeyPurpose::SIGN,
+ ForcedOp(false),
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_DIGEST), result.unwrap_err());
+ }
+}
+
+/// Generate RSA signing key with -
+/// Padding mode: `NONE`
+/// Digest mode `NONE`
+/// Try to create an operation with this generated key. Test should create an operation successfully.
+#[test]
+fn keystore2_rsa_generate_signing_key_padding_none_success() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let key_sizes = [2048, 3072, 4096];
+
+ for key_size in key_sizes {
+ let alias = format!("ks_rsa_pad_none_key_test_{}{}", getuid(), key_size);
+ let op_response = create_rsa_key_and_operation(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ &key_generations::KeyParams {
+ key_size,
+ purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
+ padding: Some(PaddingMode::NONE),
+ digest: Some(Digest::NONE),
+ mgf_digest: None,
+ block_mode: None,
+ att_challenge: None,
+ att_app_id: None,
+ },
+ KeyPurpose::SIGN,
+ ForcedOp(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 RSA signing keys with -
+/// Padding mode: `NONE`
+/// Digest modes: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
+/// Create operations with these generated keys. Test should fail to create operations with
+/// an error code `UNKNOWN_ERROR`.
+#[test]
+fn keystore2_rsa_generate_signing_key_padding_none_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,
+ ];
+
+ let key_sizes = [2048, 3072, 4096];
+
+ for key_size in key_sizes {
+ for digest in digests {
+ let alias = format!("ks_rsa_key_test_{}{}{}", getuid(), key_size, digest.0);
+ let result = key_generations::map_ks_error(create_rsa_key_and_operation(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ &key_generations::KeyParams {
+ key_size,
+ purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
+ padding: Some(PaddingMode::NONE),
+ digest: Some(digest),
+ mgf_digest: None,
+ block_mode: None,
+ att_challenge: None,
+ att_app_id: None,
+ },
+ KeyPurpose::SIGN,
+ ForcedOp(false),
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::UNKNOWN_ERROR), result.unwrap_err());
+ }
+ }
+}
+
+/// Generate RSA keys with -
+/// Padding Mode: `RSA_OAEP`
+/// Digest modes: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
+/// mgf-digests: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
+/// Create a decrypt operations using generated keys. Test should create operations successfully.
+#[test]
+fn keystore2_rsa_generate_key_with_oaep_padding_success() {
+ 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,
+ ];
+
+ let mgf_digests = [
+ Digest::MD5,
+ Digest::SHA1,
+ Digest::SHA_2_224,
+ Digest::SHA_2_256,
+ Digest::SHA_2_384,
+ Digest::SHA_2_512,
+ ];
+
+ let key_sizes = [2048, 3072, 4096];
+
+ for key_size in key_sizes {
+ for digest in digests {
+ for mgf_digest in mgf_digests {
+ let alias =
+ format!("ks_rsa_key_pair_oaep_test_{}{}{}", getuid(), key_size, digest.0);
+ let result = create_rsa_key_and_operation(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ &key_generations::KeyParams {
+ key_size,
+ purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
+ padding: Some(PaddingMode::RSA_OAEP),
+ digest: Some(digest),
+ mgf_digest: Some(mgf_digest),
+ block_mode: Some(BlockMode::ECB),
+ att_challenge: None,
+ att_app_id: None,
+ },
+ KeyPurpose::DECRYPT,
+ ForcedOp(false),
+ );
+ assert!(result.is_ok());
+ } // End of mgf-digests.
+ } // End of digests.
+ } // End of key-sizes.
+}
+
+/// Generate RSA keys with -
+/// Padding mode: `RSA_OAEP`
+/// Digest modes: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
+/// Create a decrypt operations using generated keys. Test should create operations successfully.
+#[test]
+fn keystore2_rsa_generate_key_with_oaep_padding_and_digests_success() {
+ 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,
+ ];
+
+ let key_sizes = [2048, 3072, 4096];
+
+ for key_size in key_sizes {
+ for digest in digests {
+ let alias = format!("ks_rsa_key_pair_oaep_test_{}{}{}", getuid(), key_size, digest.0);
+ let result = create_rsa_key_and_operation(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ &key_generations::KeyParams {
+ key_size,
+ purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
+ padding: Some(PaddingMode::RSA_OAEP),
+ digest: Some(digest),
+ mgf_digest: None,
+ block_mode: Some(BlockMode::ECB),
+ att_challenge: None,
+ att_app_id: None,
+ },
+ KeyPurpose::DECRYPT,
+ ForcedOp(false),
+ );
+ assert!(result.is_ok());
+ } // End of digests.
+ } // End of key-sizes.
+}
+
+/// Generate RSA encryption key with -
+/// Digest mode: `NONE`
+/// Padding mode: `RSA_OAEP`
+/// Try to create an operation using generated key. Test should fail to create an operation
+/// with an error code `INCOMPATIBLE_DIGEST`.
+#[test]
+fn keystore2_rsa_generate_key_with_oaep_padding_fail() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let key_sizes = [2048, 3072, 4096];
+
+ for key_size in key_sizes {
+ let alias = format!("ks_rsa_key_padding_{}{}", getuid(), key_size);
+ let result = key_generations::map_ks_error(create_rsa_key_and_operation(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ &key_generations::KeyParams {
+ key_size,
+ purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
+ padding: Some(PaddingMode::RSA_OAEP),
+ digest: Some(Digest::NONE),
+ mgf_digest: None,
+ block_mode: None,
+ att_challenge: None,
+ att_app_id: None,
+ },
+ KeyPurpose::DECRYPT,
+ ForcedOp(false),
+ ));
+
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_DIGEST), result.unwrap_err());
+ }
+}
+
+/// Generate RSA encryption keys with various digest mode and padding mode combinations.
+/// Digest modes: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
+/// Padding modes: `NONE, RSA_PKCS1_1_5_ENCRYPT`
+/// Try to create operations using generated keys, test should create operations successfully.
+#[test]
+fn keystore2_rsa_generate_keys_with_digest_paddings() {
+ 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 paddings = [PaddingMode::NONE, PaddingMode::RSA_PKCS1_1_5_ENCRYPT];
+
+ let key_sizes = [2048, 3072, 4096];
+
+ for key_size in key_sizes {
+ for digest in digests {
+ for padding in paddings {
+ let alias = format!("ks_rsa_key_padding_{}{}{}", getuid(), key_size, digest.0);
+ let result = key_generations::map_ks_error(create_rsa_key_and_operation(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ &key_generations::KeyParams {
+ key_size,
+ purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
+ padding: Some(padding),
+ digest: Some(digest),
+ mgf_digest: None,
+ block_mode: None,
+ att_challenge: None,
+ att_app_id: None,
+ },
+ KeyPurpose::DECRYPT,
+ ForcedOp(false),
+ ));
+
+ assert!(result.is_ok());
+ } // End of paddings.
+ } // End of digests.
+ } // End of key-sizes.
+}
+
+/// Generate RSA encryption keys with only padding modes.
+/// Padding modes: `NONE, RSA_PKCS1_1_5_ENCRYPT`
+/// Try to create operations using generated keys, test should create operations successfully.
+#[test]
+fn keystore2_rsa_generate_keys_with_paddings() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let paddings = [PaddingMode::NONE, PaddingMode::RSA_PKCS1_1_5_ENCRYPT];
+
+ let key_sizes = [2048, 3072, 4096];
+
+ for key_size in key_sizes {
+ for padding in paddings {
+ let alias = format!("ks_rsa_key_padding_{}{}", getuid(), key_size);
+ let result = create_rsa_key_and_operation(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ &key_generations::KeyParams {
+ key_size,
+ purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
+ padding: Some(padding),
+ digest: None,
+ mgf_digest: None,
+ block_mode: None,
+ att_challenge: None,
+ att_app_id: None,
+ },
+ KeyPurpose::DECRYPT,
+ ForcedOp(false),
+ );
+ assert!(result.is_ok());
+ } // End of paddings.
+ } // End of key-sizes.
+}
+
+/// Generate RSA keys without padding and digest modes. Try to create decrypt operation without
+/// digest and padding. Creation of an operation should fail with an error code
+/// `UNSUPPORTED_PADDING_MODE`.
+#[test]
+fn keystore2_rsa_generate_keys() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let key_sizes = [2048, 3072, 4096];
+
+ for key_size in key_sizes {
+ let alias = format!("ks_rsa_key_test_{}{}", getuid(), key_size);
+ let result = key_generations::map_ks_error(create_rsa_key_and_operation(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ &key_generations::KeyParams {
+ key_size,
+ purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
+ padding: None,
+ digest: None,
+ mgf_digest: None,
+ block_mode: None,
+ att_challenge: None,
+ att_app_id: None,
+ },
+ KeyPurpose::DECRYPT,
+ ForcedOp(false),
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_PADDING_MODE), result.unwrap_err());
+ }
+}
+
+/// Generate a RSA encryption key. Try to create a signing operation with it, an error
+/// `INCOMPATIBLE_PURPOSE` is expected as the generated key doesn't support sign operation.
+#[test]
+fn keystore2_rsa_encrypt_key_op_invalid_purpose() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let alias = "ks_rsa_test_key_1";
+ let result = key_generations::map_ks_error(create_rsa_key_and_operation(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ &key_generations::KeyParams {
+ key_size: 2048,
+ purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
+ padding: Some(PaddingMode::RSA_PKCS1_1_5_ENCRYPT),
+ digest: Some(Digest::SHA_2_256),
+ mgf_digest: None,
+ block_mode: None,
+ att_challenge: None,
+ att_app_id: None,
+ },
+ KeyPurpose::SIGN,
+ ForcedOp(false),
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PURPOSE), result.unwrap_err());
+}
+
+/// Generate a RSA signing key. Try to create a decrypt operation with it, an error
+/// `INCOMPATIBLE_PURPOSE` is expected as the generated key doesn't support decrypt operation.
+#[test]
+fn keystore2_rsa_sign_key_op_invalid_purpose() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let alias = "ks_rsa_test_key_2";
+ let result = key_generations::map_ks_error(create_rsa_key_and_operation(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ &key_generations::KeyParams {
+ key_size: 2048,
+ purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
+ padding: Some(PaddingMode::RSA_PKCS1_1_5_SIGN),
+ digest: Some(Digest::SHA_2_256),
+ mgf_digest: None,
+ block_mode: None,
+ att_challenge: None,
+ att_app_id: None,
+ },
+ KeyPurpose::DECRYPT,
+ ForcedOp(false),
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PURPOSE), result.unwrap_err());
+}
+
+/// Generate a RSA key with SIGN and AGREE_KEY purposes. Try to perform an operation using the
+/// generated key, an error `UNSUPPORTED_PURPOSE` is expected as RSA doesn't support AGREE_KEY.
+#[test]
+fn keystore2_rsa_key_unsupported_purpose() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let alias = "ks_rsa_key_test_3";
+ let result = key_generations::map_ks_error(create_rsa_key_and_operation(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ &key_generations::KeyParams {
+ key_size: 2048,
+ purpose: vec![KeyPurpose::AGREE_KEY],
+ padding: Some(PaddingMode::RSA_PKCS1_1_5_SIGN),
+ digest: Some(Digest::SHA_2_256),
+ mgf_digest: None,
+ block_mode: None,
+ att_challenge: None,
+ att_app_id: None,
+ },
+ KeyPurpose::AGREE_KEY,
+ ForcedOp(false),
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_PURPOSE), result.unwrap_err());
+}
+
+/// Generate a RSA encrypt key with padding mode supported for signing. Try to create an operation
+/// using generated key, an error `UNSUPPORTED_PADDING_MODE` is expected with unsupported padding
+/// mode.
+#[test]
+fn keystore2_rsa_encrypt_key_unsupported_padding() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ let paddings = [PaddingMode::RSA_PKCS1_1_5_SIGN, PaddingMode::RSA_PSS];
+
+ for padding in paddings {
+ let alias = format!("ks_rsa_key_test_4_{}{}", getuid(), padding.0);
+ let result = key_generations::map_ks_error(create_rsa_key_and_operation(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ &key_generations::KeyParams {
+ key_size: 2048,
+ purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
+ padding: Some(padding),
+ digest: Some(Digest::SHA_2_256),
+ mgf_digest: None,
+ block_mode: None,
+ att_challenge: None,
+ att_app_id: None,
+ },
+ KeyPurpose::DECRYPT,
+ ForcedOp(false),
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_PADDING_MODE), result.unwrap_err());
+ }
+}
+
+/// Generate a RSA signing key with padding mode supported for encryption. Try to create an
+/// operation using generated key, an error `UNSUPPORTED_PADDING_MODE` is expected with
+/// unsupported padding mode.
+#[test]
+fn keystore2_rsa_signing_key_unsupported_padding() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+ let paddings = [PaddingMode::RSA_PKCS1_1_5_ENCRYPT, PaddingMode::RSA_OAEP];
+
+ for padding in paddings {
+ let alias = format!("ks_rsa_key_test_4_{}{}", getuid(), padding.0);
+ let result = key_generations::map_ks_error(create_rsa_key_and_operation(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ &key_generations::KeyParams {
+ key_size: 2048,
+ purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
+ padding: Some(padding),
+ digest: Some(Digest::SHA_2_256),
+ mgf_digest: None,
+ block_mode: None,
+ att_challenge: None,
+ att_app_id: None,
+ },
+ KeyPurpose::SIGN,
+ ForcedOp(false),
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_PADDING_MODE), result.unwrap_err());
+ }
+}
+
+/// Generate a RSA encryption key. Try to perform encrypt operation using the generated
+/// key, an error `UNSUPPORTED_PURPOSE` is expected as encrypt operation is not supported
+/// with RSA key.
+#[test]
+fn keystore2_rsa_key_unsupported_op() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let alias = "ks_rsa_key_test_5";
+ let result = key_generations::map_ks_error(create_rsa_key_and_operation(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ &key_generations::KeyParams {
+ key_size: 2048,
+ purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
+ padding: Some(PaddingMode::RSA_PKCS1_1_5_ENCRYPT),
+ digest: Some(Digest::SHA_2_256),
+ mgf_digest: None,
+ block_mode: None,
+ att_challenge: None,
+ att_app_id: None,
+ },
+ KeyPurpose::ENCRYPT,
+ ForcedOp(false),
+ ));
+
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_PURPOSE), result.unwrap_err());
+}
+
+/// Generate a RSA key with encrypt, sign and verify purpose. Try to perform decrypt operation
+/// using the generated key, an error `INCOMPATIBLE_PURPOSE` is expected as the key is not
+/// generated with decrypt purpose.
+#[test]
+fn keystore2_rsa_key_missing_purpose() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let alias = "ks_rsa_key_test_6";
+ let result = key_generations::map_ks_error(create_rsa_key_and_operation(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ &key_generations::KeyParams {
+ key_size: 2048,
+ purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::SIGN, KeyPurpose::VERIFY],
+ padding: Some(PaddingMode::RSA_PKCS1_1_5_ENCRYPT),
+ digest: Some(Digest::SHA_2_256),
+ mgf_digest: None,
+ block_mode: None,
+ att_challenge: None,
+ att_app_id: None,
+ },
+ KeyPurpose::DECRYPT,
+ ForcedOp(false),
+ ));
+
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PURPOSE), result.unwrap_err());
+}
+
+/// Generate RSA encryption keys with OAEP padding mode and without digest mode. Try to create an
+/// operation with generated key, unsupported digest error is expected.
+#[test]
+fn keystore2_rsa_gen_keys_with_oaep_paddings_without_digest() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let alias = "ks_rsa_key_padding_fail";
+ let result = key_generations::map_ks_error(create_rsa_key_and_operation(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ &key_generations::KeyParams {
+ key_size: 2048,
+ purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
+ padding: Some(PaddingMode::RSA_OAEP),
+ digest: None,
+ mgf_digest: None,
+ block_mode: None,
+ att_challenge: None,
+ att_app_id: None,
+ },
+ KeyPurpose::DECRYPT,
+ ForcedOp(false),
+ ));
+
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_DIGEST), result.unwrap_err());
+}
+
+/// Generate RSA keys with unsupported key size, an error `UNSUPPORTED_KEY_SIZE` is expected.
+#[test]
+fn keystore2_rsa_gen_keys_unsupported_size() {
+ let keystore2 = get_keystore_service();
+ let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
+
+ let alias = "ks_rsa_key_padding_fail";
+ let result = key_generations::map_ks_error(key_generations::generate_rsa_key(
+ &sec_level,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ &key_generations::KeyParams {
+ key_size: 5120,
+ purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::SIGN, KeyPurpose::VERIFY],
+ padding: Some(PaddingMode::RSA_PKCS1_1_5_ENCRYPT),
+ digest: Some(Digest::SHA_2_256),
+ mgf_digest: None,
+ block_mode: None,
+ att_challenge: None,
+ att_app_id: None,
+ },
+ None,
+ ));
+
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_KEY_SIZE), result.unwrap_err());
+}
diff --git a/keystore2/tests/keystore2_client_test_utils.rs b/keystore2/tests/keystore2_client_test_utils.rs
new file mode 100644
index 0000000..075912d
--- /dev/null
+++ b/keystore2/tests/keystore2_client_test_utils.rs
@@ -0,0 +1,203 @@
+// 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::{Gid, Uid};
+use serde::{Deserialize, Serialize};
+
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
+ BlockMode::BlockMode, Digest::Digest, ErrorCode::ErrorCode,
+ KeyParameterValue::KeyParameterValue, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
+ SecurityLevel::SecurityLevel, Tag::Tag,
+};
+use android_system_keystore2::aidl::android::system::keystore2::{
+ CreateOperationResponse::CreateOperationResponse, Domain::Domain,
+ IKeystoreOperation::IKeystoreOperation, IKeystoreSecurityLevel::IKeystoreSecurityLevel,
+ KeyDescriptor::KeyDescriptor, KeyParameters::KeyParameters, ResponseCode::ResponseCode,
+};
+
+use keystore2_test_utils::{
+ authorizations, get_keystore_service, key_generations, key_generations::Error, run_as,
+};
+
+/// This enum is used to communicate between parent and child processes.
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+pub enum TestOutcome {
+ Ok,
+ BackendBusy,
+ InvalidHandle,
+ OtherErr,
+}
+
+/// This is used to notify the child or parent process that the expected state is reched.
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+pub struct BarrierReached;
+
+/// Forced operation.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct ForcedOp(pub bool);
+
+/// Sample plain text input for encrypt operation.
+pub const SAMPLE_PLAIN_TEXT: &[u8] = b"my message 11111";
+
+/// Generate a EC_P256 key using given domain, namespace and alias.
+/// Create an operation using the generated key and perform sample signing operation.
+pub fn create_signing_operation(
+ forced_op: ForcedOp,
+ op_purpose: KeyPurpose,
+ op_digest: Digest,
+ domain: Domain,
+ nspace: i64,
+ alias: Option<String>,
+) -> binder::Result<CreateOperationResponse> {
+ 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, nspace, alias, None, None,
+ )
+ .unwrap();
+
+ sec_level.createOperation(
+ &key_metadata.key,
+ &authorizations::AuthSetBuilder::new().purpose(op_purpose).digest(op_digest),
+ forced_op.0,
+ )
+}
+
+/// Performs sample signing operation.
+pub fn perform_sample_sign_operation(
+ op: &binder::Strong<dyn IKeystoreOperation>,
+) -> Result<(), binder::Status> {
+ op.update(b"my message")?;
+ let sig = op.finish(None, None)?;
+ assert!(sig.is_some());
+ Ok(())
+}
+
+/// Create new operation on child proc and perform simple operation after parent notification.
+pub fn execute_op_run_as_child(
+ target_ctx: &'static str,
+ domain: Domain,
+ nspace: i64,
+ alias: Option<String>,
+ auid: Uid,
+ agid: Gid,
+ forced_op: ForcedOp,
+) -> run_as::ChildHandle<TestOutcome, BarrierReached> {
+ unsafe {
+ run_as::run_as_child(target_ctx, auid, agid, move |reader, writer| {
+ let result = key_generations::map_ks_error(create_signing_operation(
+ forced_op,
+ KeyPurpose::SIGN,
+ Digest::SHA_2_256,
+ domain,
+ nspace,
+ alias,
+ ));
+
+ // Let the parent know that an operation has been started, then
+ // wait until the parent notifies us to continue, so the operation
+ // remains open.
+ writer.send(&BarrierReached {});
+ reader.recv();
+
+ // Continue performing the operation after parent notifies.
+ match &result {
+ Ok(CreateOperationResponse { iOperation: Some(op), .. }) => {
+ match key_generations::map_ks_error(perform_sample_sign_operation(op)) {
+ Ok(()) => TestOutcome::Ok,
+ Err(Error::Km(ErrorCode::INVALID_OPERATION_HANDLE)) => {
+ TestOutcome::InvalidHandle
+ }
+ Err(e) => panic!("Error in performing op: {:#?}", e),
+ }
+ }
+ Ok(_) => TestOutcome::OtherErr,
+ Err(Error::Rc(ResponseCode::BACKEND_BUSY)) => TestOutcome::BackendBusy,
+ _ => TestOutcome::OtherErr,
+ }
+ })
+ .expect("Failed to create an operation.")
+ }
+}
+
+/// Get NONCE value from given key parameters list.
+pub fn get_op_nonce(parameters: &KeyParameters) -> Option<Vec<u8>> {
+ for key_param in ¶meters.keyParameter {
+ if key_param.tag == Tag::NONCE {
+ if let KeyParameterValue::Blob(val) = &key_param.value {
+ return Some(val.clone());
+ }
+ }
+ }
+ None
+}
+
+/// This performs sample encryption operation with given symmetric key (AES/3DES).
+pub fn perform_sample_sym_key_encrypt_op(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+ padding_mode: PaddingMode,
+ block_mode: BlockMode,
+ nonce: &mut Option<Vec<u8>>,
+ mac_len: Option<i32>,
+ key: &KeyDescriptor,
+) -> binder::Result<Option<Vec<u8>>> {
+ let mut op_params = authorizations::AuthSetBuilder::new()
+ .purpose(KeyPurpose::ENCRYPT)
+ .padding_mode(padding_mode)
+ .block_mode(block_mode);
+ if let Some(value) = nonce {
+ op_params = op_params.nonce(value.to_vec());
+ }
+
+ if let Some(val) = mac_len {
+ op_params = op_params.mac_length(val);
+ }
+
+ let op_response = sec_level.createOperation(key, &op_params, false)?;
+ assert!(op_response.iOperation.is_some());
+ let op = op_response.iOperation.unwrap();
+ if op_response.parameters.is_some() && nonce.is_none() {
+ *nonce = get_op_nonce(&op_response.parameters.unwrap());
+ }
+ op.finish(Some(SAMPLE_PLAIN_TEXT), None)
+}
+
+/// This performs sample decryption operation with given symmetric key (AES/3DES).
+pub fn perform_sample_sym_key_decrypt_op(
+ sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
+ input: &[u8],
+ padding_mode: PaddingMode,
+ block_mode: BlockMode,
+ nonce: &mut Option<Vec<u8>>,
+ mac_len: Option<i32>,
+ key: &KeyDescriptor,
+) -> binder::Result<Option<Vec<u8>>> {
+ let mut op_params = authorizations::AuthSetBuilder::new()
+ .purpose(KeyPurpose::DECRYPT)
+ .padding_mode(padding_mode)
+ .block_mode(block_mode);
+ if let Some(value) = nonce {
+ op_params = op_params.nonce(value.to_vec());
+ }
+
+ if let Some(val) = mac_len {
+ op_params = op_params.mac_length(val);
+ }
+
+ let op_response = sec_level.createOperation(key, &op_params, false)?;
+ assert!(op_response.iOperation.is_some());
+ let op = op_response.iOperation.unwrap();
+ op.finish(Some(input), None)
+}
diff --git a/keystore2/tests/keystore2_client_tests.rs b/keystore2/tests/keystore2_client_tests.rs
index e612561..3fb3e15 100644
--- a/keystore2/tests/keystore2_client_tests.rs
+++ b/keystore2/tests/keystore2_client_tests.rs
@@ -12,2602 +12,10 @@
// 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 serde::{Deserialize, Serialize};
-
-use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
- Algorithm::Algorithm, BlockMode::BlockMode, Digest::Digest, EcCurve::EcCurve,
- ErrorCode::ErrorCode, KeyParameterValue::KeyParameterValue, KeyPurpose::KeyPurpose,
- PaddingMode::PaddingMode, SecurityLevel::SecurityLevel, Tag::Tag,
-};
-use android_system_keystore2::aidl::android::system::keystore2::{
- CreateOperationResponse::CreateOperationResponse, Domain::Domain,
- IKeystoreOperation::IKeystoreOperation, IKeystoreSecurityLevel::IKeystoreSecurityLevel,
- KeyDescriptor::KeyDescriptor, KeyParameters::KeyParameters, KeyPermission::KeyPermission,
- ResponseCode::ResponseCode,
-};
-
-use keystore2_test_utils::authorizations;
-use keystore2_test_utils::get_keystore_service;
-use keystore2_test_utils::key_generations;
-use keystore2_test_utils::key_generations::Error;
-use keystore2_test_utils::run_as;
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
-enum TestOutcome {
- Ok,
- BackendBusy,
- InvalidHandle,
- OtherErr,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
-struct BarrierReached;
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-struct ForcedOp(pub bool);
-
-/// Sample plain text input for encrypt operation.
-pub const SAMPLE_PLAIN_TEXT: &[u8] = b"my message 11111";
-
-/// Generate a EC_P256 key using given domain, namespace and alias.
-/// Create an operation using the generated key and perform sample signing operation.
-fn create_signing_operation(
- forced_op: ForcedOp,
- op_purpose: KeyPurpose,
- op_digest: Digest,
- domain: Domain,
- nspace: i64,
- alias: Option<String>,
-) -> binder::Result<CreateOperationResponse> {
- 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, nspace, alias, None, None,
- )
- .unwrap();
-
- sec_level.createOperation(
- &key_metadata.key,
- &authorizations::AuthSetBuilder::new().purpose(op_purpose).digest(op_digest),
- forced_op.0,
- )
-}
-
-/// 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>,
-) -> Result<(), binder::Status> {
- op.update(b"my message")?;
- let sig = op.finish(None, None)?;
- assert!(sig.is_some());
- Ok(())
-}
-
-/// Generate a RSA key and create an operation using the generated key.
-fn create_rsa_key_and_operation(
- sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
- domain: Domain,
- nspace: i64,
- alias: Option<String>,
- key_params: &key_generations::KeyParams,
- op_purpose: KeyPurpose,
- forced_op: ForcedOp,
-) -> binder::Result<CreateOperationResponse> {
- let key_metadata =
- key_generations::generate_rsa_key(sec_level, domain, nspace, alias, key_params, None)?;
-
- let mut op_params = authorizations::AuthSetBuilder::new().purpose(op_purpose);
-
- if let Some(value) = key_params.digest {
- op_params = op_params.digest(value)
- }
- if let Some(value) = key_params.padding {
- op_params = op_params.padding_mode(value);
- }
- if let Some(value) = key_params.mgf_digest {
- op_params = op_params.mgf_digest(value);
- }
- if let Some(value) = key_params.block_mode {
- op_params = op_params.block_mode(value)
- }
-
- sec_level.createOperation(&key_metadata.key, &op_params, forced_op.0)
-}
-
-/// Get NONCE value from given key parameters list.
-fn get_op_nonce(parameters: &KeyParameters) -> Option<Vec<u8>> {
- for key_param in ¶meters.keyParameter {
- if key_param.tag == Tag::NONCE {
- if let KeyParameterValue::Blob(val) = &key_param.value {
- return Some(val.clone());
- }
- }
- }
- None
-}
-
-/// This performs sample encryption operation with given symmetric key (AES/3DES).
-fn perform_sample_sym_key_encrypt_op(
- sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
- padding_mode: PaddingMode,
- block_mode: BlockMode,
- nonce: &mut Option<Vec<u8>>,
- mac_len: Option<i32>,
- key: &KeyDescriptor,
-) -> binder::Result<Option<Vec<u8>>> {
- let mut op_params = authorizations::AuthSetBuilder::new()
- .purpose(KeyPurpose::ENCRYPT)
- .padding_mode(padding_mode)
- .block_mode(block_mode);
- if let Some(value) = nonce {
- op_params = op_params.nonce(value.to_vec());
- }
-
- if let Some(val) = mac_len {
- op_params = op_params.mac_length(val);
- }
-
- let op_response = sec_level.createOperation(key, &op_params, false)?;
- assert!(op_response.iOperation.is_some());
- let op = op_response.iOperation.unwrap();
- if op_response.parameters.is_some() && nonce.is_none() {
- *nonce = get_op_nonce(&op_response.parameters.unwrap());
- }
- op.finish(Some(SAMPLE_PLAIN_TEXT), None)
-}
-
-/// This performs sample decryption operation with given symmetric key (AES/3DES).
-fn perform_sample_sym_key_decrypt_op(
- sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
- input: &[u8],
- padding_mode: PaddingMode,
- block_mode: BlockMode,
- nonce: &mut Option<Vec<u8>>,
- mac_len: Option<i32>,
- key: &KeyDescriptor,
-) -> binder::Result<Option<Vec<u8>>> {
- let mut op_params = authorizations::AuthSetBuilder::new()
- .purpose(KeyPurpose::DECRYPT)
- .padding_mode(padding_mode)
- .block_mode(block_mode);
- if let Some(value) = nonce {
- op_params = op_params.nonce(value.to_vec());
- }
-
- if let Some(val) = mac_len {
- op_params = op_params.mac_length(val);
- }
-
- let op_response = sec_level.createOperation(key, &op_params, false)?;
- assert!(op_response.iOperation.is_some());
- let op = op_response.iOperation.unwrap();
- op.finish(Some(input), None)
-}
-
-/// Generate a AES key. Create encrypt and decrypt operations using the generated key.
-fn create_aes_key_and_operation(
- sec_level: &binder::Strong<dyn IKeystoreSecurityLevel>,
- key_size: i32,
- padding_mode: PaddingMode,
- block_mode: BlockMode,
- mac_len: Option<i32>,
- min_mac_len: Option<i32>,
- nonce: &mut Option<Vec<u8>>,
-) -> Result<(), binder::Status> {
- let alias = format!("ks_aes_test_key_{}{}{}", key_size, block_mode.0, padding_mode.0);
-
- let key_metadata = key_generations::generate_aes_key(
- sec_level,
- key_size,
- &alias,
- &padding_mode,
- &block_mode,
- min_mac_len,
- )?;
-
- let cipher_text = perform_sample_sym_key_encrypt_op(
- sec_level,
- padding_mode,
- block_mode,
- nonce,
- mac_len,
- &key_metadata.key,
- )?;
-
- assert!(cipher_text.is_some());
-
- let plain_text = perform_sample_sym_key_decrypt_op(
- sec_level,
- &cipher_text.unwrap(),
- padding_mode,
- block_mode,
- nonce,
- mac_len,
- &key_metadata.key,
- )
- .unwrap();
- assert!(plain_text.is_some());
- assert_eq!(plain_text.unwrap(), SAMPLE_PLAIN_TEXT.to_vec());
- Ok(())
-}
-
-/// Create new operation on child proc and perform simple operation after parent notification.
-fn execute_op_run_as_child(
- target_ctx: &'static str,
- domain: Domain,
- nspace: i64,
- alias: Option<String>,
- auid: Uid,
- agid: Gid,
- forced_op: ForcedOp,
-) -> run_as::ChildHandle<TestOutcome, BarrierReached> {
- unsafe {
- run_as::run_as_child(target_ctx, auid, agid, move |reader, writer| {
- let result = key_generations::map_ks_error(create_signing_operation(
- forced_op,
- KeyPurpose::SIGN,
- Digest::SHA_2_256,
- domain,
- nspace,
- alias,
- ));
-
- // Let the parent know that an operation has been started, then
- // wait until the parent notifies us to continue, so the operation
- // remains open.
- writer.send(&BarrierReached {});
- reader.recv();
-
- // Continue performing the operation after parent notifies.
- match &result {
- Ok(CreateOperationResponse { iOperation: Some(op), .. }) => {
- match key_generations::map_ks_error(perform_sample_sign_operation(op)) {
- Ok(()) => TestOutcome::Ok,
- Err(Error::Km(ErrorCode::INVALID_OPERATION_HANDLE)) => {
- TestOutcome::InvalidHandle
- }
- Err(e) => panic!("Error in performing op: {:#?}", e),
- }
- }
- Ok(_) => TestOutcome::OtherErr,
- Err(Error::Rc(ResponseCode::BACKEND_BUSY)) => TestOutcome::BackendBusy,
- _ => TestOutcome::OtherErr,
- }
- })
- .expect("Failed to create an operation.")
- }
-}
-
-fn create_operations(
- target_ctx: &'static str,
- forced_op: ForcedOp,
- max_ops: i32,
-) -> Vec<run_as::ChildHandle<TestOutcome, BarrierReached>> {
- let alias = format!("ks_op_test_key_{}", getuid());
- let base_gid = 99 * AID_USER_OFFSET + 10001;
- let base_uid = 99 * AID_USER_OFFSET + 10001;
- (0..max_ops)
- .into_iter()
- .map(|i| {
- execute_op_run_as_child(
- target_ctx,
- Domain::APP,
- key_generations::SELINUX_SHELL_NAMESPACE,
- Some(alias.to_string()),
- Uid::from_raw(base_uid + (i as u32)),
- Gid::from_raw(base_gid + (i as u32)),
- forced_op,
- )
- })
- .collect()
-}
-
-/// This test verifies that backend service throws BACKEND_BUSY error when all
-/// operations slots are full. This test creates operations in child processes and
-/// collects the status of operations performed in each child proc and determines
-/// whether any child proc exited with error status.
-#[test]
-fn keystore2_backend_busy_test() {
- const MAX_OPS: i32 = 100;
- static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-
- let mut child_handles = create_operations(TARGET_CTX, ForcedOp(false), MAX_OPS);
-
- // Wait until all child procs notifies us to continue,
- // so that there are definitely enough operations outstanding to trigger a BACKEND_BUSY.
- for ch in child_handles.iter_mut() {
- ch.recv();
- }
- // Notify each child to resume and finish.
- for ch in child_handles.iter_mut() {
- ch.send(&BarrierReached {});
- }
-
- // Collect the result and validate whether backend busy has occurred.
- let mut busy_count = 0;
- for ch in child_handles.into_iter() {
- if ch.get_result() == TestOutcome::BackendBusy {
- busy_count += 1;
- }
- }
- assert!(busy_count > 0)
-}
-
-/// This test confirms that forced operation is having high pruning power.
-/// 1. Initially create regular operations such that there are enough operations outstanding
-/// to trigger BACKEND_BUSY.
-/// 2. Then, create a forced operation. System should be able to prune one of the regular
-/// operations and create a slot for forced operation successfully.
-#[test]
-fn keystore2_forced_op_after_backendbusy_test() {
- const MAX_OPS: i32 = 100;
- static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-
- // Create regular operations.
- let mut child_handles = create_operations(TARGET_CTX, ForcedOp(false), MAX_OPS);
-
- // Wait until all child procs notifies us to continue, so that there are enough
- // operations outstanding to trigger a BACKEND_BUSY.
- for ch in child_handles.iter_mut() {
- ch.recv();
- }
-
- // Create a forced operation.
- let auid = 99 * AID_USER_OFFSET + 10604;
- let agid = 99 * AID_USER_OFFSET + 10604;
- unsafe {
- run_as::run_as(
- key_generations::TARGET_VOLD_CTX,
- Uid::from_raw(auid),
- Gid::from_raw(agid),
- move || {
- let alias = format!("ks_prune_forced_op_key_{}", getuid());
-
- // To make room for this forced op, system should be able to prune one of the
- // above created regular operations and create a slot for this forced operation
- // successfully.
- create_signing_operation(
- ForcedOp(true),
- KeyPurpose::SIGN,
- Digest::SHA_2_256,
- Domain::SELINUX,
- 100,
- Some(alias),
- )
- .expect("Client failed to create forced operation after BACKEND_BUSY state.");
- },
- );
- };
-
- // Notify each child to resume and finish.
- for ch in child_handles.iter_mut() {
- ch.send(&BarrierReached {});
- }
-
- // Collect the results of above created regular operations.
- let mut pruned_count = 0;
- let mut busy_count = 0;
- let mut _other_err = 0;
- for ch in child_handles.into_iter() {
- match ch.get_result() {
- TestOutcome::BackendBusy => {
- busy_count += 1;
- }
- TestOutcome::InvalidHandle => {
- pruned_count += 1;
- }
- _ => {
- _other_err += 1;
- }
- }
- }
- // Verify that there should be at least one backend busy has occurred while creating
- // above regular operations.
- assert!(busy_count > 0);
-
- // Verify that there should be at least one pruned operation which should have failed while
- // performing operation.
- assert!(pruned_count > 0);
-}
-
-/// This test confirms that forced operations can't be pruned.
-/// 1. Creates an initial forced operation and tries to complete the operation after BACKEND_BUSY
-/// error is triggered.
-/// 2. Create MAX_OPS number of forced operations so that definitely enough number of operations
-/// outstanding to trigger a BACKEND_BUSY.
-/// 3. Try to use initially created forced operation (in step #1) and able to perform the
-/// operation successfully. This confirms that none of the later forced operations evicted the
-/// initial forced operation.
-#[test]
-fn keystore2_max_forced_ops_test() {
- const MAX_OPS: i32 = 100;
- let auid = 99 * AID_USER_OFFSET + 10205;
- let agid = 99 * AID_USER_OFFSET + 10205;
-
- // Create initial forced operation in a child process
- // and wait for the parent to notify to perform operation.
- let alias = format!("ks_forced_op_key_{}", getuid());
- let mut first_op_handle = execute_op_run_as_child(
- key_generations::TARGET_SU_CTX,
- Domain::SELINUX,
- key_generations::SELINUX_SHELL_NAMESPACE,
- Some(alias),
- Uid::from_raw(auid),
- Gid::from_raw(agid),
- ForcedOp(true),
- );
-
- // Wait until above child proc notifies us to continue, so that there is definitely a forced
- // operation outstanding to perform a operation.
- first_op_handle.recv();
-
- // Create MAX_OPS number of forced operations.
- let mut child_handles =
- create_operations(key_generations::TARGET_SU_CTX, ForcedOp(true), MAX_OPS);
-
- // Wait until all child procs notifies us to continue, so that there are enough operations
- // outstanding to trigger a BACKEND_BUSY.
- for ch in child_handles.iter_mut() {
- ch.recv();
- }
-
- // Notify initial created forced operation to continue performing the operations.
- first_op_handle.send(&BarrierReached {});
-
- // Collect initially created forced operation result and is expected to complete operation
- // successfully.
- let first_op_result = first_op_handle.get_result();
- assert_eq!(first_op_result, TestOutcome::Ok);
-
- // Notify each child to resume and finish.
- for ch in child_handles.iter_mut() {
- ch.send(&BarrierReached {});
- }
-
- // Collect the result and validate whether backend busy has occurred with MAX_OPS number
- // of forced operations.
- let busy_count = child_handles
- .into_iter()
- .map(|ch| ch.get_result())
- .filter(|r| *r == TestOutcome::BackendBusy)
- .count();
- assert!(busy_count > 0);
-}
-
-/// This test will verify the use case with the same owner(UID) requesting `n` number of operations.
-/// This test confirms that when all operation slots are full and a new operation is requested,
-/// an operation which is least recently used and lived longest will be pruned to make a room
-/// for a new operation. Pruning strategy should prevent the operations of the other owners(UID)
-/// from being pruned.
-///
-/// 1. Create an operation in a child process with `untrusted_app` context and wait for parent
-/// notification to complete the operation.
-/// 2. Let parent process create `n` number of operations such that there are enough operations
-/// outstanding to trigger cannibalizing their own sibling operations.
-/// 3. Sequentially try to use above created `n` number of operations and also add a new operation,
-/// so that it should trigger cannibalizing one of their own sibling operations.
-/// 3.1 While trying to use these pruned operations an `INVALID_OPERATION_HANDLE` error is
-/// expected as they are already pruned.
-/// 4. Notify the child process to resume and complete the operation. It is expected to complete the
-/// operation successfully.
-/// 5. Try to use the latest operation of parent. It is expected to complete the operation
-/// successfully.
-#[test]
-fn keystore2_ops_prune_test() {
- const MAX_OPS: usize = 40; // This should be at least 32 with sec_level TEE.
-
- static TARGET_CTX: &str = "u:r:untrusted_app:s0";
- const USER_ID: u32 = 99;
- const APPLICATION_ID: u32 = 10601;
-
- let uid = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
- let gid = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
-
- // Create an operation in an untrusted_app context. Wait until the parent notifies to continue.
- // Once the parent notifies, this operation is expected to be completed successfully.
- let alias = format!("ks_reg_op_key_{}", getuid());
- let mut child_handle = execute_op_run_as_child(
- TARGET_CTX,
- Domain::APP,
- -1,
- Some(alias),
- Uid::from_raw(uid),
- Gid::from_raw(gid),
- ForcedOp(false),
- );
-
- // Wait until child process notifies us to continue, so that an operation from child process is
- // outstanding to complete the operation.
- child_handle.recv();
-
- // Generate a key to use in below operations.
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
- let alias = format!("ks_prune_op_test_key_{}", 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();
-
- // Create multiple operations in this process to trigger cannibalizing sibling operations.
- let mut ops: Vec<binder::Result<CreateOperationResponse>> = (0..MAX_OPS)
- .into_iter()
- .map(|_| {
- sec_level.createOperation(
- &key_metadata.key,
- &authorizations::AuthSetBuilder::new()
- .purpose(KeyPurpose::SIGN)
- .digest(Digest::SHA_2_256),
- false,
- )
- })
- .collect();
-
- // Sequentially try to use operation handles created above and also add a new operation.
- for vec_index in 0..MAX_OPS {
- match &ops[vec_index] {
- Ok(CreateOperationResponse { iOperation: Some(op), .. }) => {
- // Older operation handle is pruned, if we try to use that an error is expected.
- assert_eq!(
- Err(Error::Km(ErrorCode::INVALID_OPERATION_HANDLE)),
- key_generations::map_ks_error(op.update(b"my message"))
- );
- }
- _ => panic!("Operation should have created successfully."),
- }
-
- // Create a new operation, it should trigger to cannibalize one of their own sibling
- // operations.
- ops.push(
- sec_level.createOperation(
- &key_metadata.key,
- &authorizations::AuthSetBuilder::new()
- .purpose(KeyPurpose::SIGN)
- .digest(Digest::SHA_2_256),
- false,
- ),
- );
- }
-
- // Notify child process to continue the operation.
- child_handle.send(&BarrierReached {});
- assert!((child_handle.get_result() == TestOutcome::Ok), "Failed to perform an operation");
-
- // Try to use the latest operation created by parent, should be able to use it successfully.
- match ops.last() {
- Some(Ok(CreateOperationResponse { iOperation: Some(op), .. })) => {
- assert_eq!(Ok(()), key_generations::map_ks_error(perform_sample_sign_operation(op)));
- }
- _ => panic!("Operation should have created successfully."),
- }
-}
-
-/// This test will try to load the key with Domain::BLOB.
-/// INVALID_ARGUMENT error is expected.
-#[test]
-fn keystore2_get_key_entry_blob_fail() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
- // Generate a key with domain as BLOB.
- let key_metadata = key_generations::generate_ec_p256_signing_key(
- &sec_level,
- Domain::BLOB,
- key_generations::SELINUX_SHELL_NAMESPACE,
- None,
- None,
- None,
- )
- .unwrap();
-
- // Try to load the key using above generated KeyDescriptor.
- let result = key_generations::map_ks_error(keystore2.getKeyEntry(&key_metadata.key));
- assert!(result.is_err());
- assert_eq!(Error::Rc(ResponseCode::INVALID_ARGUMENT), result.unwrap_err());
-
- // Delete the generated key blob.
- sec_level.deleteKey(&key_metadata.key).unwrap();
-}
-
-/// Try to create forced operations with various contexts -
-/// - untrusted_app
-/// - system_server
-/// - priv_app
-/// `PERMISSION_DENIED` error response is expected.
-#[test]
-fn keystore2_forced_op_perm_denied_test() {
- static TARGET_CTXS: &[&str] =
- &["u:r:untrusted_app:s0", "u:r:system_server:s0", "u:r:priv_app:s0"];
- const USER_ID: u32 = 99;
- const APPLICATION_ID: u32 = 10601;
-
- let uid = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
- let gid = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
-
- for context in TARGET_CTXS.iter() {
- unsafe {
- run_as::run_as(context, Uid::from_raw(uid), Gid::from_raw(gid), move || {
- let alias = format!("ks_app_forced_op_test_key_{}", getuid());
- let result = key_generations::map_ks_error(create_signing_operation(
- ForcedOp(true),
- KeyPurpose::SIGN,
- Digest::SHA_2_256,
- Domain::APP,
- -1,
- Some(alias),
- ));
- assert!(result.is_err());
- assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
- });
- }
- }
-}
-
-/// Try to create a forced operation with `vold` context.
-/// Should be able to create forced operation with `vold` context successfully.
-#[test]
-fn keystore2_forced_op_success_test() {
- static TARGET_CTX: &str = "u:r:vold:s0";
- const USER_ID: u32 = 99;
- const APPLICATION_ID: u32 = 10601;
-
- let uid = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
- let gid = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
-
- unsafe {
- run_as::run_as(TARGET_CTX, Uid::from_raw(uid), Gid::from_raw(gid), move || {
- let alias = format!("ks_vold_forced_op_key_{}", getuid());
- create_signing_operation(
- ForcedOp(true),
- KeyPurpose::SIGN,
- Digest::SHA_2_256,
- Domain::SELINUX,
- key_generations::SELINUX_VOLD_NAMESPACE,
- Some(alias),
- )
- .expect("Client with vold context failed to create forced operation.");
- });
- }
-}
-
-/// 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()
- ))
- );
-}
-
-/// Generate RSA signing keys with -
-/// Padding mode: RSA_PKCS1_1_5_SIGN
-/// Digest modes: `NONE, MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
-/// Create operations with these generated keys. Test should create operations successfully.
-#[test]
-fn keystore2_rsa_generate_signing_key_padding_pkcs1_1_5() {
- 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 key_sizes = [2048, 3072, 4096];
-
- for key_size in key_sizes {
- for digest in digests {
- let alias = format!("ks_rsa_key_test_{}{}{}", getuid(), key_size, digest.0);
- let op_response = create_rsa_key_and_operation(
- &sec_level,
- Domain::APP,
- -1,
- Some(alias.to_string()),
- &key_generations::KeyParams {
- key_size,
- purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
- padding: Some(PaddingMode::RSA_PKCS1_1_5_SIGN),
- digest: Some(digest),
- mgf_digest: None,
- block_mode: None,
- att_challenge: None,
- att_app_id: None,
- },
- KeyPurpose::SIGN,
- ForcedOp(false),
- )
- .unwrap();
-
- assert!(op_response.iOperation.is_some());
- assert_eq!(
- Ok(()),
- key_generations::map_ks_error(perform_sample_sign_operation(
- &op_response.iOperation.unwrap()
- ))
- );
- } // End of digests.
- } // End of key-sizes.
-}
-
-/// Generate RSA signing keys with -
-/// Padding mode: RSA_PSS
-/// Digest modes: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
-/// Create operations with these generated keys. Test should create operations successfully.
-#[test]
-fn keystore2_rsa_generate_signing_key_padding_pss_success() {
- 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,
- ];
-
- let key_sizes = [2048, 3072, 4096];
-
- for key_size in key_sizes {
- for digest in digests {
- let alias = format!("ks_rsa_key_test_{}{}{}", getuid(), key_size, digest.0);
- let op_response = create_rsa_key_and_operation(
- &sec_level,
- Domain::APP,
- -1,
- Some(alias.to_string()),
- &key_generations::KeyParams {
- key_size,
- purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
- padding: Some(PaddingMode::RSA_PSS),
- digest: Some(digest),
- mgf_digest: None,
- block_mode: None,
- att_challenge: None,
- att_app_id: None,
- },
- KeyPurpose::SIGN,
- ForcedOp(false),
- )
- .unwrap();
-
- assert!(op_response.iOperation.is_some());
- assert_eq!(
- Ok(()),
- key_generations::map_ks_error(perform_sample_sign_operation(
- &op_response.iOperation.unwrap()
- ))
- );
- } // End of digests.
- } // End of key-sizes.
-}
-
-/// Generate RSA signing key with -
-/// Padding mode: RSA_PSS
-/// Digest mode: `NONE`.
-/// Try to create an operation with this generated key. Test should fail to create an operation with
-/// `INCOMPATIBLE_DIGEST` error code.
-#[test]
-fn keystore2_rsa_generate_signing_key_padding_pss_fail() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
- let key_sizes = [2048, 3072, 4096];
-
- for key_size in key_sizes {
- let alias = format!("ks_rsa_pss_none_key_test_{}{}", getuid(), key_size);
- let result = key_generations::map_ks_error(create_rsa_key_and_operation(
- &sec_level,
- Domain::APP,
- -1,
- Some(alias.to_string()),
- &key_generations::KeyParams {
- key_size,
- purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
- padding: Some(PaddingMode::RSA_PSS),
- digest: Some(Digest::NONE),
- mgf_digest: None,
- block_mode: None,
- att_challenge: None,
- att_app_id: None,
- },
- KeyPurpose::SIGN,
- ForcedOp(false),
- ));
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_DIGEST), result.unwrap_err());
- }
-}
-
-/// Generate RSA signing key with -
-/// Padding mode: `NONE`
-/// Digest mode `NONE`
-/// Try to create an operation with this generated key. Test should create an operation successfully.
-#[test]
-fn keystore2_rsa_generate_signing_key_padding_none_success() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
- let key_sizes = [2048, 3072, 4096];
-
- for key_size in key_sizes {
- let alias = format!("ks_rsa_pad_none_key_test_{}{}", getuid(), key_size);
- let op_response = create_rsa_key_and_operation(
- &sec_level,
- Domain::APP,
- -1,
- Some(alias.to_string()),
- &key_generations::KeyParams {
- key_size,
- purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
- padding: Some(PaddingMode::NONE),
- digest: Some(Digest::NONE),
- mgf_digest: None,
- block_mode: None,
- att_challenge: None,
- att_app_id: None,
- },
- KeyPurpose::SIGN,
- ForcedOp(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 RSA signing keys with -
-/// Padding mode: `NONE`
-/// Digest modes: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
-/// Create operations with these generated keys. Test should fail to create operations with
-/// an error code `UNKNOWN_ERROR`.
-#[test]
-fn keystore2_rsa_generate_signing_key_padding_none_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,
- ];
-
- let key_sizes = [2048, 3072, 4096];
-
- for key_size in key_sizes {
- for digest in digests {
- let alias = format!("ks_rsa_key_test_{}{}{}", getuid(), key_size, digest.0);
- let result = key_generations::map_ks_error(create_rsa_key_and_operation(
- &sec_level,
- Domain::APP,
- -1,
- Some(alias.to_string()),
- &key_generations::KeyParams {
- key_size,
- purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
- padding: Some(PaddingMode::NONE),
- digest: Some(digest),
- mgf_digest: None,
- block_mode: None,
- att_challenge: None,
- att_app_id: None,
- },
- KeyPurpose::SIGN,
- ForcedOp(false),
- ));
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::UNKNOWN_ERROR), result.unwrap_err());
- }
- }
-}
-
-/// Generate RSA keys with -
-/// Padding Mode: `RSA_OAEP`
-/// Digest modes: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
-/// mgf-digests: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
-/// Create a decrypt operations using generated keys. Test should create operations successfully.
-#[test]
-fn keystore2_rsa_generate_key_with_oaep_padding_success() {
- 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,
- ];
-
- let mgf_digests = [
- Digest::MD5,
- Digest::SHA1,
- Digest::SHA_2_224,
- Digest::SHA_2_256,
- Digest::SHA_2_384,
- Digest::SHA_2_512,
- ];
-
- let key_sizes = [2048, 3072, 4096];
-
- for key_size in key_sizes {
- for digest in digests {
- for mgf_digest in mgf_digests {
- let alias =
- format!("ks_rsa_key_pair_oaep_test_{}{}{}", getuid(), key_size, digest.0);
- let result = create_rsa_key_and_operation(
- &sec_level,
- Domain::APP,
- -1,
- Some(alias.to_string()),
- &key_generations::KeyParams {
- key_size,
- purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
- padding: Some(PaddingMode::RSA_OAEP),
- digest: Some(digest),
- mgf_digest: Some(mgf_digest),
- block_mode: Some(BlockMode::ECB),
- att_challenge: None,
- att_app_id: None,
- },
- KeyPurpose::DECRYPT,
- ForcedOp(false),
- );
- assert!(result.is_ok());
- } // End of mgf-digests.
- } // End of digests.
- } // End of key-sizes.
-}
-
-/// Generate RSA keys with -
-/// Padding mode: `RSA_OAEP`
-/// Digest modes: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
-/// Create a decrypt operations using generated keys. Test should create operations successfully.
-#[test]
-fn keystore2_rsa_generate_key_with_oaep_padding_and_digests_success() {
- 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,
- ];
-
- let key_sizes = [2048, 3072, 4096];
-
- for key_size in key_sizes {
- for digest in digests {
- let alias = format!("ks_rsa_key_pair_oaep_test_{}{}{}", getuid(), key_size, digest.0);
- let result = create_rsa_key_and_operation(
- &sec_level,
- Domain::APP,
- -1,
- Some(alias.to_string()),
- &key_generations::KeyParams {
- key_size,
- purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
- padding: Some(PaddingMode::RSA_OAEP),
- digest: Some(digest),
- mgf_digest: None,
- block_mode: Some(BlockMode::ECB),
- att_challenge: None,
- att_app_id: None,
- },
- KeyPurpose::DECRYPT,
- ForcedOp(false),
- );
- assert!(result.is_ok());
- } // End of digests.
- } // End of key-sizes.
-}
-
-/// Generate RSA encryption key with -
-/// Digest mode: `NONE`
-/// Padding mode: `RSA_OAEP`
-/// Try to create an operation using generated key. Test should fail to create an operation
-/// with an error code `INCOMPATIBLE_DIGEST`.
-#[test]
-fn keystore2_rsa_generate_key_with_oaep_padding_fail() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
- let key_sizes = [2048, 3072, 4096];
-
- for key_size in key_sizes {
- let alias = format!("ks_rsa_key_padding_{}{}", getuid(), key_size);
- let result = key_generations::map_ks_error(create_rsa_key_and_operation(
- &sec_level,
- Domain::APP,
- -1,
- Some(alias.to_string()),
- &key_generations::KeyParams {
- key_size,
- purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
- padding: Some(PaddingMode::RSA_OAEP),
- digest: Some(Digest::NONE),
- mgf_digest: None,
- block_mode: None,
- att_challenge: None,
- att_app_id: None,
- },
- KeyPurpose::DECRYPT,
- ForcedOp(false),
- ));
-
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_DIGEST), result.unwrap_err());
- }
-}
-
-/// Generate RSA encryption keys with various digest mode and padding mode combinations.
-/// Digest modes: `MD5, SHA1, SHA-2 224, SHA-2 256, SHA-2 384 and SHA-2 512`
-/// Padding modes: `NONE, RSA_PKCS1_1_5_ENCRYPT`
-/// Try to create operations using generated keys, test should create operations successfully.
-#[test]
-fn keystore2_rsa_generate_keys_with_digest_paddings() {
- 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 paddings = [PaddingMode::NONE, PaddingMode::RSA_PKCS1_1_5_ENCRYPT];
-
- let key_sizes = [2048, 3072, 4096];
-
- for key_size in key_sizes {
- for digest in digests {
- for padding in paddings {
- let alias = format!("ks_rsa_key_padding_{}{}{}", getuid(), key_size, digest.0);
- let result = key_generations::map_ks_error(create_rsa_key_and_operation(
- &sec_level,
- Domain::APP,
- -1,
- Some(alias.to_string()),
- &key_generations::KeyParams {
- key_size,
- purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
- padding: Some(padding),
- digest: Some(digest),
- mgf_digest: None,
- block_mode: None,
- att_challenge: None,
- att_app_id: None,
- },
- KeyPurpose::DECRYPT,
- ForcedOp(false),
- ));
-
- assert!(result.is_ok());
- } // End of paddings.
- } // End of digests.
- } // End of key-sizes.
-}
-
-/// Generate RSA encryption keys with only padding modes.
-/// Padding modes: `NONE, RSA_PKCS1_1_5_ENCRYPT`
-/// Try to create operations using generated keys, test should create operations successfully.
-#[test]
-fn keystore2_rsa_generate_keys_with_paddings() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
- let paddings = [PaddingMode::NONE, PaddingMode::RSA_PKCS1_1_5_ENCRYPT];
-
- let key_sizes = [2048, 3072, 4096];
-
- for key_size in key_sizes {
- for padding in paddings {
- let alias = format!("ks_rsa_key_padding_{}{}", getuid(), key_size);
- let result = create_rsa_key_and_operation(
- &sec_level,
- Domain::APP,
- -1,
- Some(alias.to_string()),
- &key_generations::KeyParams {
- key_size,
- purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
- padding: Some(padding),
- digest: None,
- mgf_digest: None,
- block_mode: None,
- att_challenge: None,
- att_app_id: None,
- },
- KeyPurpose::DECRYPT,
- ForcedOp(false),
- );
- assert!(result.is_ok());
- } // End of paddings.
- } // End of key-sizes.
-}
-
-/// Generate RSA keys without padding and digest modes. Try to create decrypt operation without
-/// digest and padding. Creation of an operation should fail with an error code
-/// `UNSUPPORTED_PADDING_MODE`.
-#[test]
-fn keystore2_rsa_generate_keys() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
- let key_sizes = [2048, 3072, 4096];
-
- for key_size in key_sizes {
- let alias = format!("ks_rsa_key_test_{}{}", getuid(), key_size);
- let result = key_generations::map_ks_error(create_rsa_key_and_operation(
- &sec_level,
- Domain::APP,
- -1,
- Some(alias.to_string()),
- &key_generations::KeyParams {
- key_size,
- purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
- padding: None,
- digest: None,
- mgf_digest: None,
- block_mode: None,
- att_challenge: None,
- att_app_id: None,
- },
- KeyPurpose::DECRYPT,
- ForcedOp(false),
- ));
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_PADDING_MODE), result.unwrap_err());
- }
-}
-
-/// Generate a RSA encryption key. Try to create a signing operation with it, an error
-/// `INCOMPATIBLE_PURPOSE` is expected as the generated key doesn't support sign operation.
-#[test]
-fn keystore2_rsa_encrypt_key_op_invalid_purpose() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
- let alias = "ks_rsa_test_key_1";
- let result = key_generations::map_ks_error(create_rsa_key_and_operation(
- &sec_level,
- Domain::APP,
- -1,
- Some(alias.to_string()),
- &key_generations::KeyParams {
- key_size: 2048,
- purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
- padding: Some(PaddingMode::RSA_PKCS1_1_5_ENCRYPT),
- digest: Some(Digest::SHA_2_256),
- mgf_digest: None,
- block_mode: None,
- att_challenge: None,
- att_app_id: None,
- },
- KeyPurpose::SIGN,
- ForcedOp(false),
- ));
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PURPOSE), result.unwrap_err());
-}
-
-/// Generate a RSA signing key. Try to create a decrypt operation with it, an error
-/// `INCOMPATIBLE_PURPOSE` is expected as the generated key doesn't support decrypt operation.
-#[test]
-fn keystore2_rsa_sign_key_op_invalid_purpose() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
- let alias = "ks_rsa_test_key_2";
- let result = key_generations::map_ks_error(create_rsa_key_and_operation(
- &sec_level,
- Domain::APP,
- -1,
- Some(alias.to_string()),
- &key_generations::KeyParams {
- key_size: 2048,
- purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
- padding: Some(PaddingMode::RSA_PKCS1_1_5_SIGN),
- digest: Some(Digest::SHA_2_256),
- mgf_digest: None,
- block_mode: None,
- att_challenge: None,
- att_app_id: None,
- },
- KeyPurpose::DECRYPT,
- ForcedOp(false),
- ));
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PURPOSE), result.unwrap_err());
-}
-
-/// Generate a RSA key with SIGN and AGREE_KEY purposes. Try to perform an operation using the
-/// generated key, an error `UNSUPPORTED_PURPOSE` is expected as RSA doesn't support AGREE_KEY.
-#[test]
-fn keystore2_rsa_key_unsupported_purpose() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
- let alias = "ks_rsa_key_test_3";
- let result = key_generations::map_ks_error(create_rsa_key_and_operation(
- &sec_level,
- Domain::APP,
- -1,
- Some(alias.to_string()),
- &key_generations::KeyParams {
- key_size: 2048,
- purpose: vec![KeyPurpose::AGREE_KEY],
- padding: Some(PaddingMode::RSA_PKCS1_1_5_SIGN),
- digest: Some(Digest::SHA_2_256),
- mgf_digest: None,
- block_mode: None,
- att_challenge: None,
- att_app_id: None,
- },
- KeyPurpose::AGREE_KEY,
- ForcedOp(false),
- ));
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_PURPOSE), result.unwrap_err());
-}
-
-/// Generate a RSA encrypt key with padding mode supported for signing. Try to create an operation
-/// using generated key, an error `UNSUPPORTED_PADDING_MODE` is expected with unsupported padding
-/// mode.
-#[test]
-fn keystore2_rsa_encrypt_key_unsupported_padding() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
- let paddings = [PaddingMode::RSA_PKCS1_1_5_SIGN, PaddingMode::RSA_PSS];
-
- for padding in paddings {
- let alias = format!("ks_rsa_key_test_4_{}{}", getuid(), padding.0);
- let result = key_generations::map_ks_error(create_rsa_key_and_operation(
- &sec_level,
- Domain::APP,
- -1,
- Some(alias.to_string()),
- &key_generations::KeyParams {
- key_size: 2048,
- purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
- padding: Some(padding),
- digest: Some(Digest::SHA_2_256),
- mgf_digest: None,
- block_mode: None,
- att_challenge: None,
- att_app_id: None,
- },
- KeyPurpose::DECRYPT,
- ForcedOp(false),
- ));
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_PADDING_MODE), result.unwrap_err());
- }
-}
-
-/// Generate a RSA signing key with padding mode supported for encryption. Try to create an
-/// operation using generated key, an error `UNSUPPORTED_PADDING_MODE` is expected with
-/// unsupported padding mode.
-#[test]
-fn keystore2_rsa_signing_key_unsupported_padding() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
- let paddings = [PaddingMode::RSA_PKCS1_1_5_ENCRYPT, PaddingMode::RSA_OAEP];
-
- for padding in paddings {
- let alias = format!("ks_rsa_key_test_4_{}{}", getuid(), padding.0);
- let result = key_generations::map_ks_error(create_rsa_key_and_operation(
- &sec_level,
- Domain::APP,
- -1,
- Some(alias.to_string()),
- &key_generations::KeyParams {
- key_size: 2048,
- purpose: vec![KeyPurpose::SIGN, KeyPurpose::VERIFY],
- padding: Some(padding),
- digest: Some(Digest::SHA_2_256),
- mgf_digest: None,
- block_mode: None,
- att_challenge: None,
- att_app_id: None,
- },
- KeyPurpose::SIGN,
- ForcedOp(false),
- ));
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_PADDING_MODE), result.unwrap_err());
- }
-}
-
-/// Generate a RSA encryption key. Try to perform encrypt operation using the generated
-/// key, an error `UNSUPPORTED_PURPOSE` is expected as encrypt operation is not supported
-/// with RSA key.
-#[test]
-fn keystore2_rsa_key_unsupported_op() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
- let alias = "ks_rsa_key_test_5";
- let result = key_generations::map_ks_error(create_rsa_key_and_operation(
- &sec_level,
- Domain::APP,
- -1,
- Some(alias.to_string()),
- &key_generations::KeyParams {
- key_size: 2048,
- purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
- padding: Some(PaddingMode::RSA_PKCS1_1_5_ENCRYPT),
- digest: Some(Digest::SHA_2_256),
- mgf_digest: None,
- block_mode: None,
- att_challenge: None,
- att_app_id: None,
- },
- KeyPurpose::ENCRYPT,
- ForcedOp(false),
- ));
-
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_PURPOSE), result.unwrap_err());
-}
-
-/// Generate a RSA key with encrypt, sign and verify purpose. Try to perform decrypt operation
-/// using the generated key, an error `INCOMPATIBLE_PURPOSE` is expected as the key is not
-/// generated with decrypt purpose.
-#[test]
-fn keystore2_rsa_key_missing_purpose() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
- let alias = "ks_rsa_key_test_6";
- let result = key_generations::map_ks_error(create_rsa_key_and_operation(
- &sec_level,
- Domain::APP,
- -1,
- Some(alias.to_string()),
- &key_generations::KeyParams {
- key_size: 2048,
- purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::SIGN, KeyPurpose::VERIFY],
- padding: Some(PaddingMode::RSA_PKCS1_1_5_ENCRYPT),
- digest: Some(Digest::SHA_2_256),
- mgf_digest: None,
- block_mode: None,
- att_challenge: None,
- att_app_id: None,
- },
- KeyPurpose::DECRYPT,
- ForcedOp(false),
- ));
-
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PURPOSE), result.unwrap_err());
-}
-
-/// Generate RSA encryption keys with OAEP padding mode and without digest mode. Try to create an
-/// operation with generated key, unsupported digest error is expected.
-#[test]
-fn keystore2_rsa_gen_keys_with_oaep_paddings_without_digest() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
- let alias = "ks_rsa_key_padding_fail";
- let result = key_generations::map_ks_error(create_rsa_key_and_operation(
- &sec_level,
- Domain::APP,
- -1,
- Some(alias.to_string()),
- &key_generations::KeyParams {
- key_size: 2048,
- purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::DECRYPT],
- padding: Some(PaddingMode::RSA_OAEP),
- digest: None,
- mgf_digest: None,
- block_mode: None,
- att_challenge: None,
- att_app_id: None,
- },
- KeyPurpose::DECRYPT,
- ForcedOp(false),
- ));
-
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_DIGEST), result.unwrap_err());
-}
-
-/// Generate RSA keys with unsupported key size, an error `UNSUPPORTED_KEY_SIZE` is expected.
-#[test]
-fn keystore2_rsa_gen_keys_unsupported_size() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
- let alias = "ks_rsa_key_padding_fail";
- let result = key_generations::map_ks_error(key_generations::generate_rsa_key(
- &sec_level,
- Domain::APP,
- -1,
- Some(alias.to_string()),
- &key_generations::KeyParams {
- key_size: 5120,
- purpose: vec![KeyPurpose::ENCRYPT, KeyPurpose::SIGN, KeyPurpose::VERIFY],
- padding: Some(PaddingMode::RSA_PKCS1_1_5_ENCRYPT),
- digest: Some(Digest::SHA_2_256),
- mgf_digest: None,
- block_mode: None,
- att_challenge: None,
- att_app_id: None,
- },
- None,
- ));
-
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_KEY_SIZE), result.unwrap_err());
-}
-
-/// Generate AES keys with various block modes and paddings.
-/// - Block Modes: ECB, CBC
-/// - Padding Modes: NONE, PKCS7
-/// Test should generate keys and perform operation successfully.
-#[test]
-fn keystore2_aes_ecb_cbc_generate_key() {
- let keystore2 = get_keystore_service();
- let key_sizes = [128, 256];
- let block_modes = [BlockMode::ECB, BlockMode::CBC];
- let padding_modes = [PaddingMode::PKCS7, PaddingMode::NONE];
-
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
- for key_size in key_sizes {
- for block_mode in block_modes {
- for padding_mode in padding_modes {
- assert_eq!(
- Ok(()),
- create_aes_key_and_operation(
- &sec_level,
- key_size,
- padding_mode,
- block_mode,
- None,
- None,
- &mut None,
- )
- );
- }
- }
- }
-}
-
-/// Generate AES keys with -
-/// - Block Modes: `CTR, GCM`
-/// - Padding Modes: `NONE`
-/// Test should generate keys and perform operation successfully.
-#[test]
-fn keystore2_aes_ctr_gcm_generate_key_success() {
- let keystore2 = get_keystore_service();
- let key_sizes = [128, 256];
- let key_params = [(BlockMode::CTR, None, None), (BlockMode::GCM, Some(128), Some(128))];
-
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
- for key_size in key_sizes {
- for (block_mode, mac_len, min_mac_len) in key_params {
- let result = key_generations::map_ks_error(create_aes_key_and_operation(
- &sec_level,
- key_size,
- PaddingMode::NONE,
- block_mode,
- mac_len,
- min_mac_len,
- &mut None,
- ));
-
- assert_eq!(Ok(()), result);
- } // End of block mode.
- } // End of key size.
-}
-
-/// Generate AES keys with -
-/// - Block Modes: `CTR, GCM`
-/// - Padding Modes: `PKCS7`
-/// Try to create an operation using generated keys, test should fail to create an operation
-/// with an error code `INCOMPATIBLE_PADDING_MODE`.
-#[test]
-fn keystore2_aes_ctr_gcm_generate_key_fails_incompatible() {
- let keystore2 = get_keystore_service();
- let key_sizes = [128, 256];
- let key_params = [(BlockMode::CTR, None, None), (BlockMode::GCM, Some(128), Some(128))];
-
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
- for key_size in key_sizes {
- for (block_mode, mac_len, min_mac_len) in key_params {
- let result = key_generations::map_ks_error(create_aes_key_and_operation(
- &sec_level,
- key_size,
- PaddingMode::PKCS7,
- block_mode,
- mac_len,
- min_mac_len,
- &mut None,
- ));
-
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PADDING_MODE), result.unwrap_err());
- } // End of block mode.
- } // End of key size.
-}
-
-/// Try to generate AES key with invalid key size. Test should fail to generate a key with
-/// an error code `UNSUPPORTED_KEY_SIZE`.
-#[test]
-fn keystore2_aes_key_fails_unsupported_key_size() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
- let alias = "aes_key_test_invalid_1";
-
- let result = key_generations::map_ks_error(key_generations::generate_aes_key(
- &sec_level,
- 1024,
- alias,
- &PaddingMode::NONE,
- &BlockMode::ECB,
- None,
- ));
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_KEY_SIZE), result.unwrap_err());
-}
-
-/// Try to generate AES key with GCM block mode without providing `MIN_MAC_LENGTH`.
-/// Test should fail to generate a key with an error code `MISSING_MIN_MAC_LENGTH`.
-#[test]
-fn keystore2_aes_gcm_key_fails_missing_min_mac_len() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
- let alias = "aes_key_test_invalid_1";
-
- let result = key_generations::map_ks_error(key_generations::generate_aes_key(
- &sec_level,
- 128,
- alias,
- &PaddingMode::NONE,
- &BlockMode::GCM,
- None,
- ));
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::MISSING_MIN_MAC_LENGTH), result.unwrap_err());
-}
-
-/// Try to create an operation using AES key with multiple block modes. Test should fail to create
-/// an operation with `UNSUPPORTED_BLOCK_MODE` error code.
-#[test]
-fn keystore2_aes_key_op_fails_multi_block_modes() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
- let alias = "aes_key_test_invalid_1";
-
- let gen_params = authorizations::AuthSetBuilder::new()
- .no_auth_required()
- .algorithm(Algorithm::AES)
- .purpose(KeyPurpose::ENCRYPT)
- .purpose(KeyPurpose::DECRYPT)
- .key_size(128)
- .block_mode(BlockMode::ECB)
- .block_mode(BlockMode::CBC)
- .padding_mode(PaddingMode::NONE);
-
- let key_metadata = sec_level
- .generateKey(
- &KeyDescriptor {
- domain: Domain::APP,
- nspace: -1,
- alias: Some(alias.to_string()),
- blob: None,
- },
- None,
- &gen_params,
- 0,
- b"entropy",
- )
- .unwrap();
-
- let op_params = authorizations::AuthSetBuilder::new()
- .purpose(KeyPurpose::ENCRYPT)
- .block_mode(BlockMode::ECB)
- .block_mode(BlockMode::CBC)
- .padding_mode(PaddingMode::NONE);
-
- let result = key_generations::map_ks_error(sec_level.createOperation(
- &key_metadata.key,
- &op_params,
- false,
- ));
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_BLOCK_MODE), result.unwrap_err());
-}
-
-/// Try to create an operation using AES key with multiple padding modes. Test should fail to create
-/// an operation with `UNSUPPORTED_PADDING_MODE` error code.
-#[test]
-fn keystore2_aes_key_op_fails_multi_padding_modes() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
- let alias = "aes_key_test_invalid_1";
-
- let gen_params = authorizations::AuthSetBuilder::new()
- .no_auth_required()
- .algorithm(Algorithm::AES)
- .purpose(KeyPurpose::ENCRYPT)
- .purpose(KeyPurpose::DECRYPT)
- .key_size(128)
- .block_mode(BlockMode::ECB)
- .padding_mode(PaddingMode::PKCS7)
- .padding_mode(PaddingMode::NONE);
-
- let key_metadata = sec_level
- .generateKey(
- &KeyDescriptor {
- domain: Domain::APP,
- nspace: -1,
- alias: Some(alias.to_string()),
- blob: None,
- },
- None,
- &gen_params,
- 0,
- b"entropy",
- )
- .unwrap();
-
- let op_params = authorizations::AuthSetBuilder::new()
- .purpose(KeyPurpose::ENCRYPT)
- .block_mode(BlockMode::ECB)
- .padding_mode(PaddingMode::PKCS7)
- .padding_mode(PaddingMode::NONE);
-
- let result = key_generations::map_ks_error(sec_level.createOperation(
- &key_metadata.key,
- &op_params,
- false,
- ));
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_PADDING_MODE), result.unwrap_err());
-}
-
-/// Generate a AES-ECB key with unpadded mode. Try to create an operation using generated key
-/// with PKCS7 padding mode. Test should fail to create an Operation with
-/// `INCOMPATIBLE_PADDING_MODE` error code.
-#[test]
-fn keystore2_aes_key_op_fails_incompatible_padding() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
- let alias = "aes_key_test_invalid_1";
-
- let key_metadata = key_generations::generate_aes_key(
- &sec_level,
- 128,
- alias,
- &PaddingMode::NONE,
- &BlockMode::ECB,
- None,
- )
- .unwrap();
-
- let result = key_generations::map_ks_error(perform_sample_sym_key_encrypt_op(
- &sec_level,
- PaddingMode::PKCS7,
- BlockMode::ECB,
- &mut None,
- None,
- &key_metadata.key,
- ));
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_PADDING_MODE), result.unwrap_err());
-}
-
-/// Generate a AES-ECB key with unpadded mode. Try to create an operation using generated key
-/// with CBC block mode. Test should fail to create an Operation with
-/// `INCOMPATIBLE_BLOCK_MODE` error code.
-#[test]
-fn keystore2_aes_key_op_fails_incompatible_blockmode() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
- let alias = "aes_key_test_invalid_1";
-
- let key_metadata = key_generations::generate_aes_key(
- &sec_level,
- 128,
- alias,
- &PaddingMode::NONE,
- &BlockMode::ECB,
- None,
- )
- .unwrap();
-
- let result = key_generations::map_ks_error(perform_sample_sym_key_encrypt_op(
- &sec_level,
- PaddingMode::NONE,
- BlockMode::CBC,
- &mut None,
- None,
- &key_metadata.key,
- ));
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::INCOMPATIBLE_BLOCK_MODE), result.unwrap_err());
-}
-
-/// Generate a AES-GCM key with `MIN_MAC_LENGTH`. Try to create an operation using this
-/// generated key without providing `MAC_LENGTH`. Test should fail to create an operation with
-/// `MISSING_MAC_LENGTH` error code.
-#[test]
-fn keystore2_aes_gcm_op_fails_missing_mac_len() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
- let mac_len = None;
- let min_mac_len = Some(128);
-
- let result = key_generations::map_ks_error(create_aes_key_and_operation(
- &sec_level,
- 128,
- PaddingMode::NONE,
- BlockMode::GCM,
- mac_len,
- min_mac_len,
- &mut None,
- ));
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::MISSING_MAC_LENGTH), result.unwrap_err());
-}
-
-/// Generate a AES-GCM key with `MIN_MAC_LENGTH`. Try to create an operation using this
-/// generated key and provide `MAC_LENGTH` < key's `MIN_MAC_LENGTH`. Test should fail to create
-/// an operation with `INVALID_MAC_LENGTH` error code.
-#[test]
-fn keystore2_aes_gcm_op_fails_invalid_mac_len() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
- let mac_len = Some(96);
- let min_mac_len = Some(104);
-
- let result = key_generations::map_ks_error(create_aes_key_and_operation(
- &sec_level,
- 128,
- PaddingMode::NONE,
- BlockMode::GCM,
- mac_len,
- min_mac_len,
- &mut None,
- ));
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::INVALID_MAC_LENGTH), result.unwrap_err());
-}
-
-/// Generate a AES-GCM key with `MIN_MAC_LENGTH`. Try to create an operation using this
-/// generated key and provide `MAC_LENGTH` > 128. Test should fail to create an operation with
-/// `UNSUPPORTED_MAC_LENGTH` error code.
-#[test]
-fn keystore2_aes_gcm_op_fails_unsupported_mac_len() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
-
- let result = key_generations::map_ks_error(create_aes_key_and_operation(
- &sec_level,
- 128,
- PaddingMode::NONE,
- BlockMode::GCM,
- Some(256),
- Some(128),
- &mut None,
- ));
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::UNSUPPORTED_MAC_LENGTH), result.unwrap_err());
-}
-
-/// Generate a AES-CBC-PKCS7 key without `CALLER_NONCE` authorization. Try to set nonce while
-/// creating an operation using this generated key. Test should fail to create an operation with
-/// `CALLER_NONCE_PROHIBITED` error code.
-#[test]
-fn keystore2_aes_key_op_fails_nonce_prohibited() {
- let keystore2 = get_keystore_service();
- let sec_level = keystore2.getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT).unwrap();
- let alias = "aes_key_test_nonce_1";
- let mut nonce = Some(vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
-
- let key_metadata = key_generations::generate_aes_key(
- &sec_level,
- 128,
- alias,
- &PaddingMode::PKCS7,
- &BlockMode::CBC,
- None,
- )
- .unwrap();
-
- let result = key_generations::map_ks_error(perform_sample_sym_key_encrypt_op(
- &sec_level,
- PaddingMode::NONE,
- BlockMode::CBC,
- &mut nonce,
- None,
- &key_metadata.key,
- ));
- assert!(result.is_err());
- assert_eq!(Error::Km(ErrorCode::CALLER_NONCE_PROHIBITED), result.unwrap_err());
-}
+pub mod keystore2_client_aes_key_tests;
+pub mod keystore2_client_ec_key_tests;
+pub mod keystore2_client_grant_key_tests;
+pub mod keystore2_client_key_id_domain_tests;
+pub mod keystore2_client_operation_tests;
+pub mod keystore2_client_rsa_key_tests;
+pub mod keystore2_client_test_utils;