Merge "[rkp_factory_extraction_tool] adding requireUdsCerts flag" into main
diff --git a/keystore2/Android.bp b/keystore2/Android.bp
index 88b674e..4da0b6a 100644
--- a/keystore2/Android.bp
+++ b/keystore2/Android.bp
@@ -13,6 +13,7 @@
// limitations under the License.
package {
+ default_team: "trendy_team_android_hardware_backed_security",
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "system_security_license"
@@ -59,6 +60,7 @@
"liblibc",
"liblog_rust",
"libmessage_macro",
+ "libpostprocessor_client",
"librand",
"librkpd_client",
"librustutils",
diff --git a/keystore2/aidl/Android.bp b/keystore2/aidl/Android.bp
index ae3fb18..afc2743 100644
--- a/keystore2/aidl/Android.bp
+++ b/keystore2/aidl/Android.bp
@@ -123,6 +123,26 @@
}
aidl_interface {
+ name: "android.security.postprocessor",
+ srcs: ["android/security/postprocessor/*.aidl"],
+ unstable: true,
+ backend: {
+ java: {
+ enabled: false,
+ },
+ cpp: {
+ enabled: false,
+ },
+ ndk: {
+ enabled: false,
+ },
+ rust: {
+ enabled: true,
+ },
+ },
+}
+
+aidl_interface {
name: "android.security.metrics",
srcs: ["android/security/metrics/*.aidl"],
imports: [
diff --git a/keystore2/aidl/android/security/postprocessor/CertificateChain.aidl b/keystore2/aidl/android/security/postprocessor/CertificateChain.aidl
new file mode 100644
index 0000000..8d9daad
--- /dev/null
+++ b/keystore2/aidl/android/security/postprocessor/CertificateChain.aidl
@@ -0,0 +1,34 @@
+// Copyright 2024, 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.
+
+package android.security.postprocessor;
+
+/**
+ * General parcelable for holding the encoded certificates to be used in Keystore. This parcelable
+ * is returned by `IKeystoreCertificatePostProcessor::processKeystoreCertificates`.
+ * @hide
+ */
+@RustDerive(Clone=true)
+parcelable CertificateChain {
+ /**
+ * Holds the DER-encoded representation of the leaf certificate.
+ */
+ byte[] leafCertificate;
+ /**
+ * Holds a byte array containing the concatenation of all the remaining elements of the
+ * certificate chain with root certificate as the last with each certificate represented in
+ * DER-encoded format.
+ */
+ byte[] remainingChain;
+}
diff --git a/keystore2/aidl/android/security/postprocessor/IKeystoreCertificatePostProcessor.aidl b/keystore2/aidl/android/security/postprocessor/IKeystoreCertificatePostProcessor.aidl
new file mode 100644
index 0000000..0ceaacb
--- /dev/null
+++ b/keystore2/aidl/android/security/postprocessor/IKeystoreCertificatePostProcessor.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+package android.security.postprocessor;
+
+import android.security.postprocessor.CertificateChain;
+
+interface IKeystoreCertificatePostProcessor {
+ /**
+ * Allows implementing services to process the keystore certificates after the certificate
+ * chain has been generated.
+ *
+ * certificateChain holds the chain associated with a newly generated Keystore asymmetric
+ * keypair, where the leafCertificate is the certificate for the public key of generated key.
+ * The remaining attestation certificates are stored as a concatenated byte array of the
+ * encoded certificates with root certificate as the last element.
+ *
+ * Successful calls would get the processed certificate chain which then replaces the original
+ * certificate chain. In case of any failures/exceptions, keystore would fallback to the
+ * original certificate chain.
+ *
+ * @hide
+ */
+ CertificateChain processKeystoreCertificates(in CertificateChain certificateChain);
+}
diff --git a/keystore2/postprocessor_client/Android.bp b/keystore2/postprocessor_client/Android.bp
new file mode 100644
index 0000000..7f0194a
--- /dev/null
+++ b/keystore2/postprocessor_client/Android.bp
@@ -0,0 +1,47 @@
+//
+// Copyright 2024, 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.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "system_security_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["system_security_license"],
+}
+
+rust_defaults {
+ name: "libpostprocessor_client_defaults",
+ crate_name: "postprocessor_client",
+ srcs: ["src/lib.rs"],
+ rustlibs: [
+ "android.security.postprocessor-rust",
+ "libanyhow",
+ "libbinder_rs",
+ "liblog_rust",
+ "libmessage_macro",
+ "libthiserror",
+ ],
+ defaults: [
+ "keymint_use_latest_hal_aidl_rust",
+ ],
+}
+
+rust_library {
+ name: "libpostprocessor_client",
+ defaults: [
+ "libpostprocessor_client_defaults",
+ ],
+}
diff --git a/keystore2/postprocessor_client/src/lib.rs b/keystore2/postprocessor_client/src/lib.rs
new file mode 100644
index 0000000..8b347f9
--- /dev/null
+++ b/keystore2/postprocessor_client/src/lib.rs
@@ -0,0 +1,109 @@
+// Copyright 2024, 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.
+
+//! Helper wrapper around PostProcessor interface.
+
+use android_hardware_security_keymint::aidl::android::hardware::security::keymint::Certificate::Certificate;
+use android_security_postprocessor::aidl::android::security::postprocessor::{
+ CertificateChain::CertificateChain,
+ IKeystoreCertificatePostProcessor::IKeystoreCertificatePostProcessor,
+};
+use anyhow::{Context, Result};
+use binder::{StatusCode, Strong};
+use log::{error, info, warn};
+use message_macro::source_location_msg;
+use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::mpsc;
+use std::thread;
+use std::time::Duration;
+
+/// Errors occurred during the interaction with Certificate Processor
+#[derive(Debug, Clone, Copy, thiserror::Error, PartialEq, Eq)]
+#[error("Binder transaction error {0:?}")]
+pub struct Error(pub StatusCode);
+
+static CERT_PROCESSOR_FAILURE: AtomicBool = AtomicBool::new(false);
+
+fn send_certificate_chain_to_processor(
+ attestation_chain: CertificateChain,
+) -> Result<CertificateChain> {
+ let cert_processing_server: Strong<dyn IKeystoreCertificatePostProcessor> = wait_for_interface(
+ "rkp_cert_processor.service".to_string(),
+ )
+ .context(source_location_msg!("While trying to connect to the post processor service."))?;
+ cert_processing_server
+ .processKeystoreCertificates(&attestation_chain)
+ .context(source_location_msg!("While trying to post process certificates."))
+}
+
+/// Processes the keystore certificates after the certificate chain has been generated by Keystore.
+/// More details about this function provided in IKeystoreCertificatePostProcessor.aidl
+pub fn process_certificate_chain(
+ mut certificates: Vec<Certificate>,
+ attestation_certs: Vec<u8>,
+) -> Vec<Certificate> {
+ // If no certificates are provided from keymint, return the original chain.
+ if certificates.is_empty() {
+ error!("No leaf certificate provided.");
+ return vec![Certificate { encodedCertificate: attestation_certs }];
+ }
+
+ if certificates.len() > 1 {
+ warn!("dropping {} unexpected extra certificates after the leaf", certificates.len() - 1);
+ }
+
+ let attestation_chain = CertificateChain {
+ leafCertificate: certificates[0].encodedCertificate.clone(),
+ remainingChain: attestation_certs.clone(),
+ };
+ let result = send_certificate_chain_to_processor(attestation_chain);
+ match result {
+ Ok(certificate_chain) => {
+ info!("Post processing successful. Replacing certificates.");
+ vec![
+ Certificate { encodedCertificate: certificate_chain.leafCertificate },
+ Certificate { encodedCertificate: certificate_chain.remainingChain },
+ ]
+ }
+ Err(err) => {
+ error!("Failed to replace certificates ({err:#?}), falling back to original chain.");
+ certificates.push(Certificate { encodedCertificate: attestation_certs });
+ certificates
+ }
+ }
+}
+
+fn wait_for_interface(
+ service_name: String,
+) -> Result<Strong<dyn IKeystoreCertificatePostProcessor>> {
+ if CERT_PROCESSOR_FAILURE.load(Ordering::Relaxed) {
+ return Err(Error(StatusCode::INVALID_OPERATION).into());
+ }
+ let (sender, receiver) = mpsc::channel();
+ let _t = thread::spawn(move || {
+ if let Err(e) = sender.send(binder::wait_for_interface(&service_name)) {
+ error!("failed to send result of wait_for_interface({service_name}), likely due to timeout: {e:?}");
+ }
+ });
+
+ match receiver.recv_timeout(Duration::from_secs(5)) {
+ Ok(service_binder) => Ok(service_binder?),
+ Err(e) => {
+ error!("Timed out while connecting to post processor service: {e:#?}");
+ // Cert processor has failed. Retry only after reboot.
+ CERT_PROCESSOR_FAILURE.store(true, Ordering::Relaxed);
+ Err(e.into())
+ }
+ }
+}
diff --git a/keystore2/src/error.rs b/keystore2/src/error.rs
index 5e80266..d57ba0c 100644
--- a/keystore2/src/error.rs
+++ b/keystore2/src/error.rs
@@ -34,6 +34,7 @@
ExceptionCode, Result as BinderResult, Status as BinderStatus, StatusCode,
};
use keystore2_selinux as selinux;
+use postprocessor_client::Error as PostProcessorError;
use rkpd_client::Error as RkpdError;
use std::cmp::PartialEq;
use std::ffi::CString;
@@ -103,6 +104,14 @@
}
}
+impl From<PostProcessorError> for Error {
+ fn from(e: PostProcessorError) -> Self {
+ match e {
+ PostProcessorError(s) => Error::BinderTransaction(s),
+ }
+ }
+}
+
/// Maps an `rkpd_client::Error` that is wrapped with an `anyhow::Error` to a keystore2 `Error`.
pub fn wrapped_rkpd_error_to_ks_error(e: &anyhow::Error) -> Error {
match e.downcast_ref::<RkpdError>() {
diff --git a/keystore2/src/security_level.rs b/keystore2/src/security_level.rs
index 89c0e97..233f2ae 100644
--- a/keystore2/src/security_level.rs
+++ b/keystore2/src/security_level.rs
@@ -64,7 +64,9 @@
KeyMetadata::KeyMetadata, KeyParameters::KeyParameters, ResponseCode::ResponseCode,
};
use anyhow::{anyhow, Context, Result};
+use postprocessor_client::process_certificate_chain;
use rkpd_client::store_rkpd_attestation_key;
+use rustutils::system_properties::read_bool;
use std::convert::TryInto;
use std::time::SystemTime;
@@ -632,14 +634,30 @@
log_security_safe_params(¶ms)
))
.map(|(mut result, _)| {
- // The `certificateChain` in a `KeyCreationResult` should normally have one
- // `Certificate` for each certificate in the chain. To avoid having to
- // unnecessarily parse the RKP chain (which is concatenated DER-encoded certs),
- // stuff the whole concatenated chain into a single `Certificate`.
- // This is untangled by `store_new_key()`.
- result
- .certificateChain
- .push(Certificate { encodedCertificate: attestation_certs });
+ if read_bool("remote_provisioning.use_cert_processor", false).unwrap_or(false) {
+ let _wp = self.watch_millis(
+ concat!(
+ "KeystoreSecurityLevel::generate_key (RkpdProvisioned): ",
+ "calling KeystorePostProcessor::process_certificate_chain",
+ ),
+ 1000, // Post processing may take a little while due to network call.
+ );
+ // process_certificate_chain would either replace the certificate chain if
+ // post-processing is successful or it would fallback to the original chain
+ // on failure. In either case, we should get back the certificate chain
+ // that is fit for storing with the newly generated key.
+ result.certificateChain =
+ process_certificate_chain(result.certificateChain, attestation_certs);
+ } else {
+ // The `certificateChain` in a `KeyCreationResult` should normally have one
+ // `Certificate` for each certificate in the chain. To avoid having to
+ // unnecessarily parse the RKP chain (which is concatenated DER-encoded
+ // certs), stuff the whole concatenated chain into a single `Certificate`.
+ // This is untangled by `store_new_key()`.
+ result
+ .certificateChain
+ .push(Certificate { encodedCertificate: attestation_certs });
+ }
result
})
}
diff --git a/keystore2/test_utils/run_as.rs b/keystore2/test_utils/run_as.rs
index 14a72be..d4fd06c 100644
--- a/keystore2/test_utils/run_as.rs
+++ b/keystore2/test_utils/run_as.rs
@@ -422,6 +422,50 @@
}
}
+/// Run the given closure in a new process running with the root identity.
+///
+/// # Safety
+/// run_as runs the given closure in the client branch of fork. And it uses non
+/// async signal safe API. This means that calling this function in a multi threaded program
+/// yields undefined behavior in the child. As of this writing, it is safe to call this function
+/// from a Rust device test, because every test itself is spawned as a separate process.
+///
+/// # Safety Binder
+/// It is okay for the closure to use binder services, however, this does not work
+/// if the parent initialized libbinder already. So do not use binder outside of the closure
+/// in your test.
+pub unsafe fn run_as_root<F, R>(f: F) -> R
+where
+ R: Serialize + DeserializeOwned,
+ F: 'static + Send + FnOnce() -> R,
+{
+ // SAFETY: Our caller guarantees that the process only has a single thread.
+ unsafe { run_as("u:r:su:s0", Uid::from_raw(0), Gid::from_raw(0), f) }
+}
+
+/// Run the given closure in a new `untrusted_app` process running with the given `uid` and `gid`.
+///
+/// # Safety
+/// run_as runs the given closure in the client branch of fork. And it uses non
+/// async signal safe API. This means that calling this function in a multi threaded program
+/// yields undefined behavior in the child. As of this writing, it is safe to call this function
+/// from a Rust device test, because every test itself is spawned as a separate process.
+///
+/// # Safety Binder
+/// It is okay for the closure to use binder services, however, this does not work
+/// if the parent initialized libbinder already. So do not use binder outside of the closure
+/// in your test.
+pub unsafe fn run_as_app<F, R>(uid: u32, gid: u32, f: F) -> R
+where
+ R: Serialize + DeserializeOwned,
+ F: 'static + Send + FnOnce() -> R,
+{
+ // SAFETY: Our caller guarantees that the process only has a single thread.
+ unsafe {
+ run_as("u:r:untrusted_app:s0:c91,c256,c10,c20", Uid::from_raw(uid), Gid::from_raw(gid), f)
+ }
+}
+
/// Run the given closure in a new process running with the new identity given as
/// `uid`, `gid`, and `se_context`.
///
diff --git a/keystore2/tests/keystore2_client_attest_key_tests.rs b/keystore2/tests/keystore2_client_attest_key_tests.rs
index 033036b..02dfd3f 100644
--- a/keystore2/tests/keystore2_client_attest_key_tests.rs
+++ b/keystore2/tests/keystore2_client_attest_key_tests.rs
@@ -33,7 +33,7 @@
use keystore2_test_utils::{
authorizations, key_generations, key_generations::Error, run_as, SecLevel,
};
-use nix::unistd::{getuid, Gid, Uid};
+use nix::unistd::getuid;
use rustutils::users::AID_USER_OFFSET;
/// Generate RSA and EC attestation keys and use them for signing RSA-signing keys.
@@ -655,47 +655,47 @@
/// should return error response code - `GET_ATTESTATION_APPLICATION_ID_FAILED`.
#[test]
fn keystore2_generate_attested_key_fail_to_get_aaid() {
- static APP_USER_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
const USER_ID: u32 = 99;
const APPLICATION_ID: u32 = 19901;
static APP_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
static APP_GID: u32 = APP_UID;
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(APP_USER_CTX, Uid::from_raw(APP_UID), Gid::from_raw(APP_GID), || {
- skip_test_if_no_app_attest_key_feature!();
- let sl = SecLevel::tee();
- if sl.keystore2.getInterfaceVersion().unwrap() < 4 {
- // `GET_ATTESTATION_APPLICATION_ID_FAILED` is supported on devices with
- // `IKeystoreService` version >= 4.
- return;
- }
- let att_challenge: &[u8] = b"foo";
- let alias = format!("ks_attest_rsa_encrypt_key_aaid_fail{}", getuid());
+ let gen_key_fn = || {
+ skip_test_if_no_app_attest_key_feature!();
+ let sl = SecLevel::tee();
+ if sl.keystore2.getInterfaceVersion().unwrap() < 4 {
+ // `GET_ATTESTATION_APPLICATION_ID_FAILED` is supported on devices with
+ // `IKeystoreService` version >= 4.
+ return;
+ }
+ let att_challenge: &[u8] = b"foo";
+ let alias = format!("ks_attest_rsa_encrypt_key_aaid_fail{}", getuid());
- let result = key_generations::map_ks_error(key_generations::generate_rsa_key(
- &sl,
- Domain::APP,
- -1,
- Some(alias),
- &key_generations::KeyParams {
- key_size: 2048,
- purpose: vec![KeyPurpose::ATTEST_KEY],
- padding: Some(PaddingMode::RSA_PKCS1_1_5_SIGN),
- digest: Some(Digest::SHA_2_256),
- mgf_digest: None,
- block_mode: None,
- att_challenge: Some(att_challenge.to_vec()),
- },
- None,
- ));
+ let result = key_generations::map_ks_error(key_generations::generate_rsa_key(
+ &sl,
+ Domain::APP,
+ -1,
+ Some(alias),
+ &key_generations::KeyParams {
+ key_size: 2048,
+ purpose: vec![KeyPurpose::ATTEST_KEY],
+ padding: Some(PaddingMode::RSA_PKCS1_1_5_SIGN),
+ digest: Some(Digest::SHA_2_256),
+ mgf_digest: None,
+ block_mode: None,
+ att_challenge: Some(att_challenge.to_vec()),
+ },
+ None,
+ ));
- assert!(result.is_err());
- assert_eq!(
- result.unwrap_err(),
- Error::Rc(ResponseCode::GET_ATTESTATION_APPLICATION_ID_FAILED)
- );
- })
+ assert!(result.is_err());
+ assert_eq!(
+ result.unwrap_err(),
+ Error::Rc(ResponseCode::GET_ATTESTATION_APPLICATION_ID_FAILED)
+ );
};
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(APP_UID, APP_GID, gen_key_fn) };
}
diff --git a/keystore2/tests/keystore2_client_authorizations_tests.rs b/keystore2/tests/keystore2_client_authorizations_tests.rs
index 4e83f73..bd9dab9 100644
--- a/keystore2/tests/keystore2_client_authorizations_tests.rs
+++ b/keystore2/tests/keystore2_client_authorizations_tests.rs
@@ -13,7 +13,7 @@
// limitations under the License.
use crate::keystore2_client_test_utils::{
- app_attest_key_feature_exists, delete_app_key,
+ app_attest_key_feature_exists, delete_app_key, get_vsr_api_level,
perform_sample_asym_sign_verify_op, perform_sample_hmac_sign_verify_op,
perform_sample_sym_key_decrypt_op, perform_sample_sym_key_encrypt_op,
verify_certificate_serial_num, verify_certificate_subject_name, SAMPLE_PLAIN_TEXT,
@@ -638,6 +638,11 @@
#[test]
fn keystore2_gen_key_auth_app_data_app_id_test_success() {
let sl = SecLevel::tee();
+ if sl.is_keymaster() && get_vsr_api_level() < 35 {
+ // `APPLICATION_DATA` key-parameter is causing the error on older devices, so skipping this
+ // test to run on older devices.
+ return;
+ }
let gen_params = authorizations::AuthSetBuilder::new()
.no_auth_required()
@@ -669,6 +674,11 @@
#[test]
fn keystore2_op_auth_invalid_app_data_app_id_test_fail() {
let sl = SecLevel::tee();
+ if sl.is_keymaster() && get_vsr_api_level() < 35 {
+ // `APPLICATION_DATA` key-parameter is causing the error on older devices, so skipping this
+ // test to run on older devices.
+ return;
+ }
let gen_params = authorizations::AuthSetBuilder::new()
.no_auth_required()
@@ -701,6 +711,11 @@
#[test]
fn keystore2_op_auth_missing_app_data_test_fail() {
let sl = SecLevel::tee();
+ if sl.is_keymaster() && get_vsr_api_level() < 35 {
+ // `APPLICATION_DATA` key-parameter is causing the error on older devices, so skipping this
+ // test to run on older devices.
+ return;
+ }
let gen_params = authorizations::AuthSetBuilder::new()
.no_auth_required()
@@ -733,6 +748,11 @@
#[test]
fn keystore2_op_auth_missing_app_id_test_fail() {
let sl = SecLevel::tee();
+ if sl.is_keymaster() && get_vsr_api_level() < 35 {
+ // `APPLICATION_DATA` key-parameter is causing the error on older devices, so skipping this
+ // test to run on older devices.
+ return;
+ }
let gen_params = authorizations::AuthSetBuilder::new()
.no_auth_required()
@@ -766,6 +786,11 @@
fn keystore2_gen_attested_key_auth_app_id_app_data_test_success() {
skip_test_if_no_app_attest_key_feature!();
let sl = SecLevel::tee();
+ if sl.is_keymaster() && get_vsr_api_level() < 35 {
+ // `APPLICATION_DATA` key-parameter is causing the error on older devices, so skipping this
+ // test to run on older devices.
+ return;
+ }
// Generate attestation key.
let attest_gen_params = authorizations::AuthSetBuilder::new()
@@ -822,6 +847,11 @@
fn keystore2_gen_attestation_key_with_auth_app_id_app_data_test_fail() {
skip_test_if_no_app_attest_key_feature!();
let sl = SecLevel::tee();
+ if sl.is_keymaster() && get_vsr_api_level() < 35 {
+ // `APPLICATION_DATA` key-parameter is causing the error on older devices, so skipping this
+ // test to run on older devices.
+ return;
+ }
// Generate attestation key.
let attest_gen_params = authorizations::AuthSetBuilder::new()
diff --git a/keystore2/tests/keystore2_client_ec_key_tests.rs b/keystore2/tests/keystore2_client_ec_key_tests.rs
index 8aa9bc4..526a339 100644
--- a/keystore2/tests/keystore2_client_ec_key_tests.rs
+++ b/keystore2/tests/keystore2_client_ec_key_tests.rs
@@ -425,7 +425,9 @@
// 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.
- // SAFETY: The test is run in a separate process with no other threads.
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
let mut child_handle = unsafe {
execute_op_run_as_child(
TARGET_CTX,
@@ -446,20 +448,23 @@
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;
- // SAFETY: The test is run in a separate process with no other threads.
+
+ let get_key_fn = 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());
+ };
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
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());
- });
+ run_as::run_as_app(uid2, gid2, get_key_fn);
};
// Notify the child process (client#1) to resume and finish.
diff --git a/keystore2/tests/keystore2_client_grant_key_tests.rs b/keystore2/tests/keystore2_client_grant_key_tests.rs
index 89569f5..5391d20 100644
--- a/keystore2/tests/keystore2_client_grant_key_tests.rs
+++ b/keystore2/tests/keystore2_client_grant_key_tests.rs
@@ -25,7 +25,7 @@
use keystore2_test_utils::{
authorizations, get_keystore_service, key_generations, key_generations::Error, run_as, SecLevel,
};
-use nix::unistd::{getuid, Gid, Uid};
+use nix::unistd::getuid;
use rustutils::users::AID_USER_OFFSET;
/// Generate an EC signing key and grant it to the user with given access vector.
@@ -100,53 +100,47 @@
/// 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;
- // SAFETY: The test is run in a separate process with no other threads.
- 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 grantor_fn = || {
+ 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();
+ 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);
+ assert_eq!(grant_key.domain, Domain::GRANT);
- grant_key.nspace
- })
+ grant_key.nspace
};
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
+
// In grantee context try to load the key, it should fail to load the granted key as it is
// granted with empty access vector.
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(
- GRANTEE_CTX,
- Uid::from_raw(GRANTEE_UID),
- Gid::from_raw(GRANTEE_GID),
- move || {
- let keystore2 = get_keystore_service();
+ let grantee_fn = 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());
- },
- )
+ 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());
};
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
}
/// Grant a key to the user (grantee) with `GET_INFO|USE` key permissions. Verify whether grantee
@@ -156,84 +150,77 @@
/// 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.
- // SAFETY: The test is run in a separate process with no other threads.
- 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();
+ let grantor_fn = || {
+ 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);
+ assert_eq!(grant_key.domain, Domain::GRANT);
- grant_key.nspace
- })
+ grant_key.nspace
};
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
+
// In grantee context load the key and try to perform crypto operation.
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(
- GRANTEE_CTX,
- Uid::from_raw(GRANTEE_UID),
- Gid::from_raw(GRANTEE_GID),
- move || {
- let sl = SecLevel::tee();
+ let grantee_fn = move || {
+ let sl = SecLevel::tee();
- // Load the granted key.
- let key_entry_response = sl
- .keystore2
- .getKeyEntry(&KeyDescriptor {
- domain: Domain::GRANT,
- nspace: grant_key_nspace,
- alias: None,
- blob: None,
- })
- .unwrap();
+ // Load the granted key.
+ let key_entry_response = sl
+ .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 = sl
- .binder
- .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()
- ))
- );
+ // Perform sample crypto operation using granted key.
+ let op_response = sl
+ .binder
+ .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(sl.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 delete the key, it is expected to be fail with permission denied error.
+ let result = key_generations::map_ks_error(sl.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());
};
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
}
/// Grant a key to the user with DELETE access. In grantee context load the key and delete it.
@@ -241,8 +228,6 @@
/// should fail to find the key with error response `KEY_NOT_FOUND`.
#[test]
fn keystore2_grant_delete_key_success() {
- static GRANTOR_SU_CTX: &str = "u:r:su:s0";
- static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
const USER_ID: u32 = 99;
const APPLICATION_ID: u32 = 10001;
static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
@@ -250,60 +235,57 @@
static ALIAS: &str = "ks_grant_key_delete_success";
// Generate a key and grant it to a user with DELETE permission.
- // SAFETY: The test is run in a separate process with no other threads.
- let grant_key_nspace = unsafe {
- run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
- let sl = SecLevel::tee();
- let access_vector = KeyPermission::DELETE.0;
- let mut grant_keys = generate_ec_key_and_grant_to_users(
- &sl,
- Some(ALIAS.to_string()),
- vec![GRANTEE_UID.try_into().unwrap()],
- access_vector,
- )
- .unwrap();
+ let grantor_fn = || {
+ let sl = SecLevel::tee();
+ let access_vector = KeyPermission::DELETE.0;
+ let mut grant_keys = generate_ec_key_and_grant_to_users(
+ &sl,
+ Some(ALIAS.to_string()),
+ vec![GRANTEE_UID.try_into().unwrap()],
+ access_vector,
+ )
+ .unwrap();
- grant_keys.remove(0)
- })
+ grant_keys.remove(0)
};
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
+
// Grantee context, delete the key.
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(
- GRANTEE_CTX,
- Uid::from_raw(GRANTEE_UID),
- Gid::from_raw(GRANTEE_GID),
- move || {
- let keystore2 = get_keystore_service();
- keystore2
- .deleteKey(&KeyDescriptor {
- domain: Domain::GRANT,
- nspace: grant_key_nspace,
- alias: None,
- blob: None,
- })
- .unwrap();
- },
- )
+ let grantee_fn = move || {
+ let keystore2 = get_keystore_service();
+ keystore2
+ .deleteKey(&KeyDescriptor {
+ domain: Domain::GRANT,
+ nspace: grant_key_nspace,
+ alias: None,
+ blob: None,
+ })
+ .unwrap();
};
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
+
// Verify whether key got deleted in grantor's context.
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), 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());
- })
+ let grantor_fn = 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());
};
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_root(grantor_fn) };
}
/// Grant a key to the user. In grantee context load the granted key and try to grant it to second
@@ -313,8 +295,6 @@
#[test]
#[ignore]
fn keystore2_grant_key_fails_with_permission_denied() {
- static GRANTOR_SU_CTX: &str = "u:r:su:s0";
- static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
const USER_ID: u32 = 99;
const APPLICATION_ID: u32 = 10001;
static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
@@ -326,77 +306,69 @@
static SEC_GRANTEE_GID: u32 = SEC_GRANTEE_UID;
// Generate a key and grant it to a user with GET_INFO permission.
- // SAFETY: The test is run in a separate process with no other threads.
- let grant_key_nspace = unsafe {
- run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
- let sl = SecLevel::tee();
- let access_vector = KeyPermission::GET_INFO.0;
- let alias = format!("ks_grant_perm_denied_key_{}", getuid());
- let mut grant_keys = generate_ec_key_and_grant_to_users(
- &sl,
- Some(alias),
- vec![GRANTEE_UID.try_into().unwrap()],
- access_vector,
- )
- .unwrap();
+ let grantor_fn = || {
+ let sl = SecLevel::tee();
+ let access_vector = KeyPermission::GET_INFO.0;
+ let alias = format!("ks_grant_perm_denied_key_{}", getuid());
+ let mut grant_keys = generate_ec_key_and_grant_to_users(
+ &sl,
+ Some(alias),
+ vec![GRANTEE_UID.try_into().unwrap()],
+ access_vector,
+ )
+ .unwrap();
- grant_keys.remove(0)
- })
+ grant_keys.remove(0)
};
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
// Grantee context, load the granted key and try to grant it to `SEC_GRANTEE_UID` grantee.
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(
- GRANTEE_CTX,
- Uid::from_raw(GRANTEE_UID),
- Gid::from_raw(GRANTEE_GID),
- move || {
- let keystore2 = get_keystore_service();
- let access_vector = KeyPermission::GET_INFO.0;
+ let grantee_fn = move || {
+ let keystore2 = get_keystore_service();
+ let access_vector = KeyPermission::GET_INFO.0;
- let key_entry_response = keystore2
- .getKeyEntry(&KeyDescriptor {
- domain: Domain::GRANT,
- nspace: grant_key_nspace,
- alias: None,
- blob: None,
- })
- .unwrap();
+ let key_entry_response = keystore2
+ .getKeyEntry(&KeyDescriptor {
+ domain: Domain::GRANT,
+ nspace: grant_key_nspace,
+ alias: None,
+ blob: None,
+ })
+ .unwrap();
- let result = key_generations::map_ks_error(keystore2.grant(
- &key_entry_response.metadata.key,
- SEC_GRANTEE_UID.try_into().unwrap(),
- access_vector,
- ));
- assert!(result.is_err());
- assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
- },
- )
+ let result = key_generations::map_ks_error(keystore2.grant(
+ &key_entry_response.metadata.key,
+ SEC_GRANTEE_UID.try_into().unwrap(),
+ access_vector,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
};
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
+
// Make sure second grantee shouldn't have access to the above granted key.
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(
- GRANTEE_CTX,
- Uid::from_raw(SEC_GRANTEE_UID),
- Gid::from_raw(SEC_GRANTEE_GID),
- move || {
- let keystore2 = get_keystore_service();
+ let grantee2_fn = 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,
- }));
+ 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::KEY_NOT_FOUND), result.unwrap_err());
- },
- )
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
};
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(SEC_GRANTEE_UID, SEC_GRANTEE_GID, grantee2_fn) };
}
/// Try to grant a key with `GRANT` access. Keystore2 system shouldn't allow to grant a key with
@@ -449,67 +421,57 @@
/// the key. Grantee should fail to load the ungranted key with `KEY_NOT_FOUND` error response.
#[test]
fn keystore2_ungrant_key_success() {
- static GRANTOR_SU_CTX: &str = "u:r:su:s0";
- static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
const USER_ID: 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 permission.
- // SAFETY: The test is run in a separate process with no other threads.
- let grant_key_nspace = unsafe {
- run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
- let sl = SecLevel::tee();
- let alias = format!("ks_ungrant_test_key_1{}", getuid());
- let access_vector = KeyPermission::GET_INFO.0;
- let mut grant_keys = generate_ec_key_and_grant_to_users(
- &sl,
- Some(alias.to_string()),
- vec![GRANTEE_UID.try_into().unwrap()],
- access_vector,
+ let grantor_fn = || {
+ let sl = SecLevel::tee();
+ let alias = format!("ks_ungrant_test_key_1{}", getuid());
+ let access_vector = KeyPermission::GET_INFO.0;
+ let mut grant_keys = generate_ec_key_and_grant_to_users(
+ &sl,
+ Some(alias.to_string()),
+ vec![GRANTEE_UID.try_into().unwrap()],
+ access_vector,
+ )
+ .unwrap();
+
+ let grant_key_nspace = grant_keys.remove(0);
+
+ // Ungrant above granted key.
+ sl.keystore2
+ .ungrant(
+ &KeyDescriptor { domain: Domain::APP, nspace: -1, alias: Some(alias), blob: None },
+ GRANTEE_UID.try_into().unwrap(),
)
.unwrap();
- let grant_key_nspace = grant_keys.remove(0);
-
- // Ungrant above granted key.
- sl.keystore2
- .ungrant(
- &KeyDescriptor {
- domain: Domain::APP,
- nspace: -1,
- alias: Some(alias),
- blob: None,
- },
- GRANTEE_UID.try_into().unwrap(),
- )
- .unwrap();
-
- grant_key_nspace
- })
+ grant_key_nspace
};
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
+
// Grantee context, try to load the ungranted key.
- // SAFETY: The test is run in a separate process with no other threads.
- 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::KEY_NOT_FOUND), result.unwrap_err());
- },
- )
+ let grantee_fn = 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::KEY_NOT_FOUND), result.unwrap_err());
};
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
}
/// Generate a key, grant it to the user and then delete the granted key. Try to ungrant
@@ -519,93 +481,84 @@
/// associated key is deleted from grantor context.
#[test]
fn keystore2_ungrant_fails_with_non_existing_key_expect_key_not_found_error() {
- static GRANTOR_SU_CTX: &str = "u:r:su:s0";
- static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-
const APPLICATION_ID: u32 = 10001;
const USER_ID: u32 = 99;
static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
static GRANTEE_GID: u32 = GRANTEE_UID;
- // SAFETY: The test is run in a separate process with no other threads.
- let grant_key_nspace = unsafe {
- run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
- let sl = SecLevel::tee();
- let alias = format!("{}{}", "ks_grant_delete_ungrant_test_key_1", getuid());
+ let grantor_fn = || {
+ let sl = SecLevel::tee();
+ let alias = format!("{}{}", "ks_grant_delete_ungrant_test_key_1", getuid());
- let key_metadata = key_generations::generate_ec_p256_signing_key(
- &sl,
- Domain::SELINUX,
- key_generations::SELINUX_SHELL_NAMESPACE,
- Some(alias.to_string()),
- None,
- )
+ let key_metadata = key_generations::generate_ec_p256_signing_key(
+ &sl,
+ Domain::SELINUX,
+ key_generations::SELINUX_SHELL_NAMESPACE,
+ Some(alias.to_string()),
+ None,
+ )
+ .unwrap();
+
+ let access_vector = KeyPermission::GET_INFO.0;
+ let grant_key = sl
+ .keystore2
+ .grant(&key_metadata.key, GRANTEE_UID.try_into().unwrap(), access_vector)
.unwrap();
+ assert_eq!(grant_key.domain, Domain::GRANT);
- let access_vector = KeyPermission::GET_INFO.0;
- let grant_key = sl
- .keystore2
- .grant(&key_metadata.key, GRANTEE_UID.try_into().unwrap(), access_vector)
- .unwrap();
- assert_eq!(grant_key.domain, Domain::GRANT);
+ // Delete above granted key.
+ sl.keystore2.deleteKey(&key_metadata.key).unwrap();
- // Delete above granted key.
- sl.keystore2.deleteKey(&key_metadata.key).unwrap();
+ // Try to ungrant above granted key.
+ let result = key_generations::map_ks_error(
+ sl.keystore2.ungrant(&key_metadata.key, GRANTEE_UID.try_into().unwrap()),
+ );
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
- // Try to ungrant above granted key.
- let result = key_generations::map_ks_error(
- sl.keystore2.ungrant(&key_metadata.key, GRANTEE_UID.try_into().unwrap()),
- );
- assert!(result.is_err());
- assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
+ // Generate a new key with the same alias and try to access the earlier granted key
+ // in grantee context.
+ let result = key_generations::generate_ec_p256_signing_key(
+ &sl,
+ Domain::SELINUX,
+ key_generations::SELINUX_SHELL_NAMESPACE,
+ Some(alias),
+ None,
+ );
+ assert!(result.is_ok());
- // Generate a new key with the same alias and try to access the earlier granted key
- // in grantee context.
- let result = key_generations::generate_ec_p256_signing_key(
- &sl,
- Domain::SELINUX,
- key_generations::SELINUX_SHELL_NAMESPACE,
- Some(alias),
- None,
- );
- assert!(result.is_ok());
-
- grant_key.nspace
- })
+ grant_key.nspace
};
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
+
// Make sure grant did not persist, try to access the earlier granted key in grantee context.
// Grantee context should fail to load the granted key as its associated key is deleted in
// grantor context.
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(
- GRANTEE_CTX,
- Uid::from_raw(GRANTEE_UID),
- Gid::from_raw(GRANTEE_GID),
- move || {
- let keystore2 = get_keystore_service();
+ let grantee_fn = 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::KEY_NOT_FOUND), result.unwrap_err());
- },
- )
+ 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::KEY_NOT_FOUND), result.unwrap_err());
};
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
}
/// Grant a key to multiple users. Verify that all grantees should succeed in loading the key and
/// use it for performing an operation successfully.
#[test]
fn keystore2_grant_key_to_multi_users_success() {
- static GRANTOR_SU_CTX: &str = "u:r:su:s0";
- static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-
const APPLICATION_ID: u32 = 10001;
const USER_ID_1: u32 = 99;
static GRANTEE_1_UID: u32 = USER_ID_1 * AID_USER_OFFSET + APPLICATION_ID;
@@ -616,46 +569,42 @@
static GRANTEE_2_GID: u32 = GRANTEE_2_UID;
// Generate a key and grant it to multiple users with GET_INFO|USE permissions.
- // SAFETY: The test is run in a separate process with no other threads.
- let mut grant_keys = unsafe {
- run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
- let sl = SecLevel::tee();
- let alias = format!("ks_grant_test_key_2{}", getuid());
- let access_vector = KeyPermission::GET_INFO.0 | KeyPermission::USE.0;
+ let grantor_fn = || {
+ let sl = SecLevel::tee();
+ let alias = format!("ks_grant_test_key_2{}", getuid());
+ let access_vector = KeyPermission::GET_INFO.0 | KeyPermission::USE.0;
- generate_ec_key_and_grant_to_users(
- &sl,
- Some(alias),
- vec![GRANTEE_1_UID.try_into().unwrap(), GRANTEE_2_UID.try_into().unwrap()],
- access_vector,
- )
- .unwrap()
- })
+ generate_ec_key_and_grant_to_users(
+ &sl,
+ Some(alias),
+ vec![GRANTEE_1_UID.try_into().unwrap(), GRANTEE_2_UID.try_into().unwrap()],
+ access_vector,
+ )
+ .unwrap()
};
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ let mut grant_keys = unsafe { run_as::run_as_root(grantor_fn) };
+
for (grantee_uid, grantee_gid) in
&[(GRANTEE_1_UID, GRANTEE_1_GID), (GRANTEE_2_UID, GRANTEE_2_GID)]
{
let grant_key_nspace = grant_keys.remove(0);
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(
- GRANTEE_CTX,
- Uid::from_raw(*grantee_uid),
- Gid::from_raw(*grantee_gid),
- move || {
- let sl = SecLevel::tee();
+ let grantee_fn = move || {
+ let sl = SecLevel::tee();
- assert_eq!(
- Ok(()),
- key_generations::map_ks_error(load_grant_key_and_perform_sign_operation(
- &sl,
- grant_key_nspace
- ))
- );
- },
- )
+ assert_eq!(
+ Ok(()),
+ key_generations::map_ks_error(load_grant_key_and_perform_sign_operation(
+ &sl,
+ grant_key_nspace
+ ))
+ );
};
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(*grantee_uid, *grantee_gid, grantee_fn) };
}
}
@@ -664,9 +613,6 @@
/// fail to load the granted key with `KEY_NOT_FOUND` error response.
#[test]
fn keystore2_grant_key_to_multi_users_delete_fails_with_key_not_found_error() {
- static GRANTOR_SU_CTX: &str = "u:r:su:s0";
- static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-
const USER_ID_1: u32 = 99;
const APPLICATION_ID: u32 = 10001;
static GRANTEE_1_UID: u32 = USER_ID_1 * AID_USER_OFFSET + APPLICATION_ID;
@@ -677,76 +623,69 @@
static GRANTEE_2_GID: u32 = GRANTEE_2_UID;
// Generate a key and grant it to multiple users with GET_INFO permission.
- // SAFETY: The test is run in a separate process with no other threads.
- let mut grant_keys = unsafe {
- run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
- let sl = SecLevel::tee();
- let alias = format!("ks_grant_test_key_2{}", getuid());
- let access_vector =
- KeyPermission::GET_INFO.0 | KeyPermission::USE.0 | KeyPermission::DELETE.0;
+ let grantor_fn = || {
+ let sl = SecLevel::tee();
+ let alias = format!("ks_grant_test_key_2{}", getuid());
+ let access_vector =
+ KeyPermission::GET_INFO.0 | KeyPermission::USE.0 | KeyPermission::DELETE.0;
- generate_ec_key_and_grant_to_users(
- &sl,
- Some(alias),
- vec![GRANTEE_1_UID.try_into().unwrap(), GRANTEE_2_UID.try_into().unwrap()],
- access_vector,
- )
- .unwrap()
- })
+ generate_ec_key_and_grant_to_users(
+ &sl,
+ Some(alias),
+ vec![GRANTEE_1_UID.try_into().unwrap(), GRANTEE_2_UID.try_into().unwrap()],
+ access_vector,
+ )
+ .unwrap()
};
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ let mut grant_keys = unsafe { run_as::run_as_root(grantor_fn) };
+
// Grantee #1 context
let grant_key1_nspace = grant_keys.remove(0);
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(
- GRANTEE_CTX,
- Uid::from_raw(GRANTEE_1_UID),
- Gid::from_raw(GRANTEE_1_GID),
- move || {
- let sl = SecLevel::tee();
+ let grantee1_fn = move || {
+ let sl = SecLevel::tee();
- assert_eq!(
- Ok(()),
- key_generations::map_ks_error(load_grant_key_and_perform_sign_operation(
- &sl,
- grant_key1_nspace
- ))
- );
+ assert_eq!(
+ Ok(()),
+ key_generations::map_ks_error(load_grant_key_and_perform_sign_operation(
+ &sl,
+ grant_key1_nspace
+ ))
+ );
- // Delete the granted key.
- sl.keystore2
- .deleteKey(&KeyDescriptor {
- domain: Domain::GRANT,
- nspace: grant_key1_nspace,
- alias: None,
- blob: None,
- })
- .unwrap();
- },
- )
+ // Delete the granted key.
+ sl.keystore2
+ .deleteKey(&KeyDescriptor {
+ domain: Domain::GRANT,
+ nspace: grant_key1_nspace,
+ alias: None,
+ blob: None,
+ })
+ .unwrap();
};
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(GRANTEE_1_UID, GRANTEE_1_GID, grantee1_fn) };
+
// Grantee #2 context
let grant_key2_nspace = grant_keys.remove(0);
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(
- GRANTEE_CTX,
- Uid::from_raw(GRANTEE_2_UID),
- Gid::from_raw(GRANTEE_2_GID),
- move || {
- let keystore2 = get_keystore_service();
+ let grantee2_fn = move || {
+ let keystore2 = get_keystore_service();
- let result = key_generations::map_ks_error(keystore2.getKeyEntry(&KeyDescriptor {
- domain: Domain::GRANT,
- nspace: grant_key2_nspace,
- alias: None,
- blob: None,
- }));
- assert!(result.is_err());
- assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
- },
- )
+ let result = key_generations::map_ks_error(keystore2.getKeyEntry(&KeyDescriptor {
+ domain: Domain::GRANT,
+ nspace: grant_key2_nspace,
+ alias: None,
+ blob: None,
+ }));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::KEY_NOT_FOUND), result.unwrap_err());
};
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(GRANTEE_2_UID, GRANTEE_2_GID, grantee2_fn) };
}
diff --git a/keystore2/tests/keystore2_client_keystore_engine_tests.rs b/keystore2/tests/keystore2_client_keystore_engine_tests.rs
index 01f8917..a4d7f2c 100644
--- a/keystore2/tests/keystore2_client_keystore_engine_tests.rs
+++ b/keystore2/tests/keystore2_client_keystore_engine_tests.rs
@@ -24,7 +24,6 @@
use keystore2_test_utils::{
authorizations::AuthSetBuilder, get_keystore_service, run_as, SecLevel,
};
-use nix::unistd::{Gid, Uid};
use openssl::x509::X509;
use rustutils::users::AID_USER_OFFSET;
@@ -152,80 +151,65 @@
}
#[test]
-fn keystore2_perofrm_crypto_op_using_keystore2_engine_rsa_key_success() {
- static TARGET_SU_CTX: &str = "u:r:su:s0";
-
- static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+fn keystore2_perform_crypto_op_using_keystore2_engine_rsa_key_success() {
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|DELETE key permissions.
- // SAFETY: The test is run in a separate process with no other threads.
- let grant_key_nspace = unsafe {
- run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
- let sl = SecLevel::tee();
- let alias = "keystore2_engine_rsa_key";
- generate_key_and_grant_to_user(&sl, alias, GRANTEE_UID, Algorithm::RSA).unwrap()
- })
+ let grantor_fn = || {
+ let sl = SecLevel::tee();
+ let alias = "keystore2_engine_rsa_key";
+ generate_key_and_grant_to_user(&sl, alias, GRANTEE_UID, Algorithm::RSA).unwrap()
};
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
+
// In grantee context load the key and try to perform crypto operation.
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(
- GRANTEE_CTX,
- Uid::from_raw(GRANTEE_UID),
- Gid::from_raw(GRANTEE_GID),
- move || {
- let keystore2 = get_keystore_service();
- perform_crypto_op_using_granted_key(&keystore2, grant_key_nspace);
- },
- )
+ let grantee_fn = move || {
+ let keystore2 = get_keystore_service();
+ perform_crypto_op_using_granted_key(&keystore2, grant_key_nspace);
};
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
}
#[test]
-fn keystore2_perofrm_crypto_op_using_keystore2_engine_ec_key_success() {
- static TARGET_SU_CTX: &str = "u:r:su:s0";
-
- static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+fn keystore2_perform_crypto_op_using_keystore2_engine_ec_key_success() {
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|DELETE key permissions.
- // SAFETY: The test is run in a separate process with no other threads.
- let grant_key_nspace = unsafe {
- run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
- let sl = SecLevel::tee();
- let alias = "keystore2_engine_ec_test_key";
- generate_key_and_grant_to_user(&sl, alias, GRANTEE_UID, Algorithm::EC).unwrap()
- })
+ let grantor_fn = || {
+ let sl = SecLevel::tee();
+ let alias = "keystore2_engine_ec_test_key";
+ generate_key_and_grant_to_user(&sl, alias, GRANTEE_UID, Algorithm::EC).unwrap()
};
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
+
// In grantee context load the key and try to perform crypto operation.
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(
- GRANTEE_CTX,
- Uid::from_raw(GRANTEE_UID),
- Gid::from_raw(GRANTEE_GID),
- move || {
- let keystore2 = get_keystore_service();
- perform_crypto_op_using_granted_key(&keystore2, grant_key_nspace);
- },
- )
+ let grantee_fn = move || {
+ let keystore2 = get_keystore_service();
+ perform_crypto_op_using_granted_key(&keystore2, grant_key_nspace);
};
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
}
#[test]
-fn keystore2_perofrm_crypto_op_using_keystore2_engine_pem_pub_key_success() {
- static TARGET_SU_CTX: &str = "u:r:su:s0";
-
- static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+fn keystore2_perform_crypto_op_using_keystore2_engine_pem_pub_key_success() {
const USER_ID: u32 = 99;
const APPLICATION_ID: u32 = 10001;
static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
@@ -233,46 +217,43 @@
// Generate a key and re-encode it's certificate as PEM and update it and
// grant it to a user with GET_INFO|USE|DELETE key permissions.
- // SAFETY: The test is run in a separate process with no other threads.
- let grant_key_nspace = unsafe {
- run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
- let sl = SecLevel::tee();
- let alias = "keystore2_engine_rsa_pem_pub_key";
- let grant_key_nspace =
- generate_key_and_grant_to_user(&sl, alias, GRANTEE_UID, Algorithm::RSA).unwrap();
+ let grantor_fn = || {
+ let sl = SecLevel::tee();
+ let alias = "keystore2_engine_rsa_pem_pub_key";
+ let grant_key_nspace =
+ generate_key_and_grant_to_user(&sl, alias, GRANTEE_UID, Algorithm::RSA).unwrap();
- // Update certificate with encodeed PEM data.
- let key_entry_response = sl
- .keystore2
- .getKeyEntry(&KeyDescriptor {
- domain: Domain::APP,
- nspace: -1,
- alias: Some(alias.to_string()),
- blob: None,
- })
- .unwrap();
- let cert_bytes = key_entry_response.metadata.certificate.as_ref().unwrap();
- let cert = X509::from_der(cert_bytes.as_ref()).unwrap();
- let cert_pem = cert.to_pem().unwrap();
- sl.keystore2
- .updateSubcomponent(&key_entry_response.metadata.key, Some(&cert_pem), None)
- .expect("updateSubcomponent failed.");
+ // Update certificate with encodeed PEM data.
+ let key_entry_response = sl
+ .keystore2
+ .getKeyEntry(&KeyDescriptor {
+ domain: Domain::APP,
+ nspace: -1,
+ alias: Some(alias.to_string()),
+ blob: None,
+ })
+ .unwrap();
+ let cert_bytes = key_entry_response.metadata.certificate.as_ref().unwrap();
+ let cert = X509::from_der(cert_bytes.as_ref()).unwrap();
+ let cert_pem = cert.to_pem().unwrap();
+ sl.keystore2
+ .updateSubcomponent(&key_entry_response.metadata.key, Some(&cert_pem), None)
+ .expect("updateSubcomponent failed.");
- grant_key_nspace
- })
+ grant_key_nspace
};
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ let grant_key_nspace = unsafe { run_as::run_as_root(grantor_fn) };
+
// In grantee context load the key and try to perform crypto operation.
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(
- GRANTEE_CTX,
- Uid::from_raw(GRANTEE_UID),
- Gid::from_raw(GRANTEE_GID),
- move || {
- let keystore2 = get_keystore_service();
- perform_crypto_op_using_granted_key(&keystore2, grant_key_nspace);
- },
- )
+ let grantee_fn = move || {
+ let keystore2 = get_keystore_service();
+ perform_crypto_op_using_granted_key(&keystore2, grant_key_nspace);
};
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, grantee_fn) };
}
diff --git a/keystore2/tests/keystore2_client_list_entries_tests.rs b/keystore2/tests/keystore2_client_list_entries_tests.rs
index 539dac2..bb1d6cf 100644
--- a/keystore2/tests/keystore2_client_list_entries_tests.rs
+++ b/keystore2/tests/keystore2_client_list_entries_tests.rs
@@ -20,7 +20,7 @@
use keystore2_test_utils::{
get_keystore_service, key_generations, key_generations::Error, run_as, SecLevel,
};
-use nix::unistd::{getuid, Gid, Uid};
+use nix::unistd::getuid;
use rustutils::users::AID_USER_OFFSET;
use std::collections::HashSet;
use std::fmt::Write;
@@ -51,103 +51,97 @@
/// context. GRANT keys shouldn't be part of this list.
#[test]
fn keystore2_list_entries_success() {
- static GRANTOR_SU_CTX: &str = "u:r:su:s0";
- static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-
const USER_ID: u32 = 91;
const APPLICATION_ID: u32 = 10006;
static GRANTEE_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
static GRANTEE_GID: u32 = GRANTEE_UID;
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
- let sl = SecLevel::tee();
+ let gen_key_fn = || {
+ let sl = SecLevel::tee();
- let alias = format!("list_entries_grant_key1_{}", getuid());
+ let alias = format!("list_entries_grant_key1_{}", getuid());
- // Make sure there is no key exist with this `alias` in `SELINUX` domain and
- // `SELINUX_SHELL_NAMESPACE` namespace.
- if key_alias_exists(
- &sl.keystore2,
- Domain::SELINUX,
- key_generations::SELINUX_SHELL_NAMESPACE,
- alias.to_string(),
- ) {
- sl.keystore2
- .deleteKey(&KeyDescriptor {
- domain: Domain::SELINUX,
- nspace: key_generations::SELINUX_SHELL_NAMESPACE,
- alias: Some(alias.to_string()),
- blob: None,
- })
- .unwrap();
- }
-
- // Generate a key with above defined `alias`.
- let key_metadata = key_generations::generate_ec_p256_signing_key(
- &sl,
- Domain::SELINUX,
- key_generations::SELINUX_SHELL_NAMESPACE,
- Some(alias.to_string()),
- None,
- )
- .unwrap();
-
- // Verify that above generated key entry is listed with domain SELINUX and
- // namespace SELINUX_SHELL_NAMESPACE
- assert!(key_alias_exists(
- &sl.keystore2,
- Domain::SELINUX,
- key_generations::SELINUX_SHELL_NAMESPACE,
- alias,
- ));
-
- // Grant a key with GET_INFO permission.
- let access_vector = KeyPermission::GET_INFO.0;
+ // Make sure there is no key exist with this `alias` in `SELINUX` domain and
+ // `SELINUX_SHELL_NAMESPACE` namespace.
+ if key_alias_exists(
+ &sl.keystore2,
+ Domain::SELINUX,
+ key_generations::SELINUX_SHELL_NAMESPACE,
+ alias.to_string(),
+ ) {
sl.keystore2
- .grant(&key_metadata.key, GRANTEE_UID.try_into().unwrap(), access_vector)
+ .deleteKey(&KeyDescriptor {
+ domain: Domain::SELINUX,
+ nspace: key_generations::SELINUX_SHELL_NAMESPACE,
+ alias: Some(alias.to_string()),
+ blob: None,
+ })
.unwrap();
- })
+ }
+
+ // Generate a key with above defined `alias`.
+ let key_metadata = key_generations::generate_ec_p256_signing_key(
+ &sl,
+ Domain::SELINUX,
+ key_generations::SELINUX_SHELL_NAMESPACE,
+ Some(alias.to_string()),
+ None,
+ )
+ .unwrap();
+
+ // Verify that above generated key entry is listed with domain SELINUX and
+ // namespace SELINUX_SHELL_NAMESPACE
+ assert!(key_alias_exists(
+ &sl.keystore2,
+ Domain::SELINUX,
+ key_generations::SELINUX_SHELL_NAMESPACE,
+ alias,
+ ));
+
+ // Grant a key with GET_INFO permission.
+ let access_vector = KeyPermission::GET_INFO.0;
+ sl.keystore2
+ .grant(&key_metadata.key, GRANTEE_UID.try_into().unwrap(), access_vector)
+ .unwrap();
};
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_root(gen_key_fn) };
+
// In user context validate list of key entries associated with it.
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(
- GRANTEE_CTX,
- Uid::from_raw(GRANTEE_UID),
- Gid::from_raw(GRANTEE_GID),
- move || {
- let sl = SecLevel::tee();
- let alias = format!("list_entries_success_key{}", getuid());
+ let list_keys_fn = move || {
+ let sl = SecLevel::tee();
+ let alias = format!("list_entries_success_key{}", getuid());
- let key_metadata = key_generations::generate_ec_p256_signing_key(
- &sl,
- Domain::APP,
- -1,
- Some(alias.to_string()),
- None,
- )
- .unwrap();
-
- // Make sure there is only one key entry exist and that should be the same key
- // generated in this user context. Granted key shouldn't be included in this list.
- let key_descriptors = sl.keystore2.listEntries(Domain::APP, -1).unwrap();
- assert_eq!(1, key_descriptors.len());
-
- let key = key_descriptors.first().unwrap();
- assert_eq!(key.alias, Some(alias));
- assert_eq!(key.nspace, GRANTEE_UID.try_into().unwrap());
- assert_eq!(key.domain, Domain::APP);
-
- sl.keystore2.deleteKey(&key_metadata.key).unwrap();
-
- let key_descriptors = sl.keystore2.listEntries(Domain::APP, -1).unwrap();
- assert_eq!(0, key_descriptors.len());
- },
+ let key_metadata = key_generations::generate_ec_p256_signing_key(
+ &sl,
+ Domain::APP,
+ -1,
+ Some(alias.to_string()),
+ None,
)
+ .unwrap();
+
+ // Make sure there is only one existing key entry and that should be the same key
+ // generated in this user context. Granted key shouldn't be included in this list.
+ let key_descriptors = sl.keystore2.listEntries(Domain::APP, -1).unwrap();
+ assert_eq!(1, key_descriptors.len());
+
+ let key = key_descriptors.first().unwrap();
+ assert_eq!(key.alias, Some(alias));
+ assert_eq!(key.nspace, GRANTEE_UID.try_into().unwrap());
+ assert_eq!(key.domain, Domain::APP);
+
+ sl.keystore2.deleteKey(&key_metadata.key).unwrap();
+
+ let key_descriptors = sl.keystore2.listEntries(Domain::APP, -1).unwrap();
+ assert_eq!(0, key_descriptors.len());
};
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(GRANTEE_UID, GRANTEE_GID, list_keys_fn) };
}
/// Try to list the key entries with domain SELINUX from user context where user doesn't possesses
@@ -157,20 +151,19 @@
fn keystore2_list_entries_fails_perm_denied() {
let auid = 91 * AID_USER_OFFSET + 10001;
let agid = 91 * AID_USER_OFFSET + 10001;
- static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+ let list_keys_fn = move || {
+ let keystore2 = get_keystore_service();
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(TARGET_CTX, Uid::from_raw(auid), Gid::from_raw(agid), move || {
- let keystore2 = get_keystore_service();
-
- let result = key_generations::map_ks_error(
- keystore2.listEntries(Domain::SELINUX, key_generations::SELINUX_SHELL_NAMESPACE),
- );
- assert!(result.is_err());
- assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
- })
+ let result = key_generations::map_ks_error(
+ keystore2.listEntries(Domain::SELINUX, key_generations::SELINUX_SHELL_NAMESPACE),
+ );
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
};
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(auid, agid, list_keys_fn) };
}
/// Try to list key entries with domain BLOB. Test should fail with error repose code
@@ -190,64 +183,63 @@
/// of all the entries in the keystore.
#[test]
fn keystore2_list_entries_with_long_aliases_success() {
- static CLIENT_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-
const USER_ID: u32 = 92;
const APPLICATION_ID: u32 = 10002;
static CLIENT_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
static CLIENT_GID: u32 = CLIENT_UID;
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
- let sl = SecLevel::tee();
+ let import_keys_fn = || {
+ let sl = SecLevel::tee();
- // Make sure there are no keystore entries exist before adding new entries.
+ // Make sure there are no keystore entries exist before adding new entries.
+ let key_descriptors = sl.keystore2.listEntries(Domain::APP, -1).unwrap();
+ if !key_descriptors.is_empty() {
+ key_descriptors.into_iter().map(|key| key.alias.unwrap()).for_each(|alias| {
+ delete_app_key(&sl.keystore2, &alias).unwrap();
+ });
+ }
+
+ let mut imported_key_aliases = HashSet::new();
+
+ // Import 100 keys with aliases of length 6000.
+ for count in 1..101 {
+ let mut alias = String::new();
+ write!(alias, "{}_{}", "X".repeat(6000), count).unwrap();
+ imported_key_aliases.insert(alias.clone());
+
+ let result = key_generations::import_aes_key(&sl, Domain::APP, -1, Some(alias));
+ assert!(result.is_ok());
+ }
+
+ // b/222287335 Limiting Keystore `listEntries` API to return subset of the Keystore
+ // entries to avoid running out of binder buffer space.
+ // To verify that all the imported key aliases are present in Keystore,
+ // - get the list of entries from Keystore
+ // - check whether the retrieved key entries list is a subset of imported key aliases
+ // - delete this subset of keystore entries from Keystore as well as from imported
+ // list of key aliases
+ // - continue above steps till it cleanup all the imported keystore entries.
+ while !imported_key_aliases.is_empty() {
let key_descriptors = sl.keystore2.listEntries(Domain::APP, -1).unwrap();
- if !key_descriptors.is_empty() {
- key_descriptors.into_iter().map(|key| key.alias.unwrap()).for_each(|alias| {
- delete_app_key(&sl.keystore2, &alias).unwrap();
- });
- }
- let mut imported_key_aliases = HashSet::new();
+ // Check retrieved key entries list is a subset of imported keys list.
+ assert!(key_descriptors
+ .iter()
+ .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
- // Import 100 keys with aliases of length 6000.
- for count in 1..101 {
- let mut alias = String::new();
- write!(alias, "{}_{}", "X".repeat(6000), count).unwrap();
- imported_key_aliases.insert(alias.clone());
+ // Delete the listed key entries from Keystore as well as from imported keys list.
+ key_descriptors.into_iter().map(|key| key.alias.unwrap()).for_each(|alias| {
+ delete_app_key(&sl.keystore2, &alias).unwrap();
+ assert!(imported_key_aliases.remove(&alias));
+ });
+ }
- let result = key_generations::import_aes_key(&sl, Domain::APP, -1, Some(alias));
- assert!(result.is_ok());
- }
-
- // b/222287335 Limiting Keystore `listEntries` API to return subset of the Keystore
- // entries to avoid running out of binder buffer space.
- // To verify that all the imported key aliases are present in Keystore,
- // - get the list of entries from Keystore
- // - check whether the retrieved key entries list is a subset of imported key aliases
- // - delete this subset of keystore entries from Keystore as well as from imported
- // list of key aliases
- // - continue above steps till it cleanup all the imported keystore entries.
- while !imported_key_aliases.is_empty() {
- let key_descriptors = sl.keystore2.listEntries(Domain::APP, -1).unwrap();
-
- // Check retrieved key entries list is a subset of imported keys list.
- assert!(key_descriptors
- .iter()
- .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
-
- // Delete the listed key entries from Keystore as well as from imported keys list.
- key_descriptors.into_iter().map(|key| key.alias.unwrap()).for_each(|alias| {
- delete_app_key(&sl.keystore2, &alias).unwrap();
- assert!(imported_key_aliases.remove(&alias));
- });
- }
-
- assert!(imported_key_aliases.is_empty());
- })
+ assert!(imported_key_aliases.is_empty());
};
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(CLIENT_UID, CLIENT_GID, import_keys_fn) };
}
/// Import large number of Keystore entries with long aliases such that the
@@ -255,58 +247,57 @@
/// Try to list aliases of all the entries in the keystore using `listEntriesBatched` API.
#[test]
fn keystore2_list_entries_batched_with_long_aliases_success() {
- static CLIENT_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-
const USER_ID: u32 = 92;
const APPLICATION_ID: u32 = 10002;
static CLIENT_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
static CLIENT_GID: u32 = CLIENT_UID;
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
- let sl = SecLevel::tee();
+ let import_keys_fn = || {
+ let sl = SecLevel::tee();
- // Make sure there are no keystore entries exist before adding new entries.
- delete_all_entries(&sl.keystore2);
+ // Make sure there are no keystore entries exist before adding new entries.
+ delete_all_entries(&sl.keystore2);
- // Import 100 keys with aliases of length 6000.
- let mut imported_key_aliases =
- key_generations::import_aes_keys(&sl, "X".repeat(6000), 1..101).unwrap();
- assert_eq!(
- sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
- 100,
- "Error while importing keys"
- );
+ // Import 100 keys with aliases of length 6000.
+ let mut imported_key_aliases =
+ key_generations::import_aes_keys(&sl, "X".repeat(6000), 1..101).unwrap();
+ assert_eq!(
+ sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+ 100,
+ "Error while importing keys"
+ );
- let mut start_past_alias = None;
- let mut alias;
- while !imported_key_aliases.is_empty() {
- let key_descriptors =
- sl.keystore2.listEntriesBatched(Domain::APP, -1, start_past_alias).unwrap();
+ let mut start_past_alias = None;
+ let mut alias;
+ while !imported_key_aliases.is_empty() {
+ let key_descriptors =
+ sl.keystore2.listEntriesBatched(Domain::APP, -1, start_past_alias).unwrap();
- // Check retrieved key entries list is a subset of imported keys list.
- assert!(key_descriptors
- .iter()
- .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
+ // Check retrieved key entries list is a subset of imported keys list.
+ assert!(key_descriptors
+ .iter()
+ .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
- alias = key_descriptors.last().unwrap().alias.clone().unwrap();
- start_past_alias = Some(alias.as_ref());
- // Delete the listed key entries from imported keys list.
- key_descriptors.into_iter().map(|key| key.alias.unwrap()).for_each(|alias| {
- assert!(imported_key_aliases.remove(&alias));
- });
- }
+ alias = key_descriptors.last().unwrap().alias.clone().unwrap();
+ start_past_alias = Some(alias.as_ref());
+ // Delete the listed key entries from imported keys list.
+ key_descriptors.into_iter().map(|key| key.alias.unwrap()).for_each(|alias| {
+ assert!(imported_key_aliases.remove(&alias));
+ });
+ }
- assert!(imported_key_aliases.is_empty());
- delete_all_entries(&sl.keystore2);
- assert_eq!(
- sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
- 0,
- "Error while doing cleanup"
- );
- })
+ assert!(imported_key_aliases.is_empty());
+ delete_all_entries(&sl.keystore2);
+ assert_eq!(
+ sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+ 0,
+ "Error while doing cleanup"
+ );
};
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(CLIENT_UID, CLIENT_GID, import_keys_fn) };
}
/// Import keys from multiple processes with same user context and try to list the keystore entries
@@ -321,128 +312,127 @@
/// `startingPastAlias` as None. It should list all the keys imported in process-1 and process-2.
#[test]
fn keystore2_list_entries_batched_with_multi_procs_success() {
- static CLIENT_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-
const USER_ID: u32 = 92;
const APPLICATION_ID: u32 = 10002;
static CLIENT_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
static CLIENT_GID: u32 = CLIENT_UID;
static ALIAS_PREFIX: &str = "key_test_batch_list";
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
- let sl = SecLevel::tee();
+ let import_keys_fn = || {
+ let sl = SecLevel::tee();
- // Make sure there are no keystore entries exist before adding new entries.
- delete_all_entries(&sl.keystore2);
+ // Make sure there are no keystore entries exist before adding new entries.
+ delete_all_entries(&sl.keystore2);
- // Import 3 keys with below aliases -
- // [key_test_batch_list_1, key_test_batch_list_2, key_test_batch_list_3]
- let imported_key_aliases =
- key_generations::import_aes_keys(&sl, ALIAS_PREFIX.to_string(), 1..4).unwrap();
- assert_eq!(
- sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
- 3,
- "Error while importing keys"
- );
+ // Import 3 keys with below aliases -
+ // [key_test_batch_list_1, key_test_batch_list_2, key_test_batch_list_3]
+ let imported_key_aliases =
+ key_generations::import_aes_keys(&sl, ALIAS_PREFIX.to_string(), 1..4).unwrap();
+ assert_eq!(
+ sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+ 3,
+ "Error while importing keys"
+ );
- // List all entries in keystore for this user-id.
- let key_descriptors = sl.keystore2.listEntriesBatched(Domain::APP, -1, None).unwrap();
- assert_eq!(key_descriptors.len(), 3);
+ // List all entries in keystore for this user-id.
+ let key_descriptors = sl.keystore2.listEntriesBatched(Domain::APP, -1, None).unwrap();
+ assert_eq!(key_descriptors.len(), 3);
- // Makes sure all listed aliases are matching with imported keys aliases.
- assert!(key_descriptors
- .iter()
- .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
- })
+ // Makes sure all listed aliases are matching with imported keys aliases.
+ assert!(key_descriptors
+ .iter()
+ .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
};
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
- let sl = SecLevel::tee();
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(CLIENT_UID, CLIENT_GID, import_keys_fn) };
- // Import another 5 keys with below aliases -
- // [ key_test_batch_list_4, key_test_batch_list_5, key_test_batch_list_6,
- // key_test_batch_list_7, key_test_batch_list_8 ]
- let mut imported_key_aliases =
- key_generations::import_aes_keys(&sl, ALIAS_PREFIX.to_string(), 4..9).unwrap();
+ let import_more_fn = || {
+ let sl = SecLevel::tee();
- // Above context already 3 keys are imported, in this context 5 keys are imported,
- // total 8 keystore entries are expected to be present in Keystore for this user-id.
- assert_eq!(
- sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
- 8,
- "Error while importing keys"
- );
+ // Import another 5 keys with below aliases -
+ // [ key_test_batch_list_4, key_test_batch_list_5, key_test_batch_list_6,
+ // key_test_batch_list_7, key_test_batch_list_8 ]
+ let mut imported_key_aliases =
+ key_generations::import_aes_keys(&sl, ALIAS_PREFIX.to_string(), 4..9).unwrap();
- // List keystore entries with `start_past_alias` as "key_test_batch_list_3".
- // `listEntriesBatched` should list all the keystore entries with
- // alias > "key_test_batch_list_3".
- let key_descriptors = sl
- .keystore2
- .listEntriesBatched(Domain::APP, -1, Some("key_test_batch_list_3"))
- .unwrap();
- assert_eq!(key_descriptors.len(), 5);
+ // Above context already 3 keys are imported, in this context 5 keys are imported,
+ // total 8 keystore entries are expected to be present in Keystore for this user-id.
+ assert_eq!(
+ sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+ 8,
+ "Error while importing keys"
+ );
- // Make sure above listed aliases are matching with imported keys aliases.
- assert!(key_descriptors
- .iter()
- .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
+ // List keystore entries with `start_past_alias` as "key_test_batch_list_3".
+ // `listEntriesBatched` should list all the keystore entries with
+ // alias > "key_test_batch_list_3".
+ let key_descriptors = sl
+ .keystore2
+ .listEntriesBatched(Domain::APP, -1, Some("key_test_batch_list_3"))
+ .unwrap();
+ assert_eq!(key_descriptors.len(), 5);
- // List all keystore entries with `start_past_alias` as `None`.
- // `listEntriesBatched` should list all the keystore entries.
- let key_descriptors = sl.keystore2.listEntriesBatched(Domain::APP, -1, None).unwrap();
- assert_eq!(key_descriptors.len(), 8);
+ // Make sure above listed aliases are matching with imported keys aliases.
+ assert!(key_descriptors
+ .iter()
+ .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
- // Include previously imported keys aliases as well
- imported_key_aliases.insert(ALIAS_PREFIX.to_owned() + "_1");
- imported_key_aliases.insert(ALIAS_PREFIX.to_owned() + "_2");
- imported_key_aliases.insert(ALIAS_PREFIX.to_owned() + "_3");
+ // List all keystore entries with `start_past_alias` as `None`.
+ // `listEntriesBatched` should list all the keystore entries.
+ let key_descriptors = sl.keystore2.listEntriesBatched(Domain::APP, -1, None).unwrap();
+ assert_eq!(key_descriptors.len(), 8);
- // Make sure all the above listed aliases are matching with imported keys aliases.
- assert!(key_descriptors
- .iter()
- .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
+ // Include previously imported keys aliases as well
+ imported_key_aliases.insert(ALIAS_PREFIX.to_owned() + "_1");
+ imported_key_aliases.insert(ALIAS_PREFIX.to_owned() + "_2");
+ imported_key_aliases.insert(ALIAS_PREFIX.to_owned() + "_3");
- delete_all_entries(&sl.keystore2);
- assert_eq!(
- sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
- 0,
- "Error while doing cleanup"
- );
- })
+ // Make sure all the above listed aliases are matching with imported keys aliases.
+ assert!(key_descriptors
+ .iter()
+ .all(|key| imported_key_aliases.contains(key.alias.as_ref().unwrap())));
+
+ delete_all_entries(&sl.keystore2);
+ assert_eq!(
+ sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+ 0,
+ "Error while doing cleanup"
+ );
};
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(CLIENT_UID, CLIENT_GID, import_more_fn) };
}
#[test]
fn keystore2_list_entries_batched_with_empty_keystore_success() {
- static CLIENT_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-
const USER_ID: u32 = 92;
const APPLICATION_ID: u32 = 10002;
static CLIENT_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
static CLIENT_GID: u32 = CLIENT_UID;
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
- let keystore2 = get_keystore_service();
+ let list_keys_fn = || {
+ let keystore2 = get_keystore_service();
- // Make sure there are no keystore entries exist before adding new entries.
- delete_all_entries(&keystore2);
+ // Make sure there are no keystore entries exist before adding new entries.
+ delete_all_entries(&keystore2);
- // List all entries in keystore for this user-id, pass startingPastAlias = None
- let key_descriptors = keystore2.listEntriesBatched(Domain::APP, -1, None).unwrap();
- assert_eq!(key_descriptors.len(), 0);
+ // List all entries in keystore for this user-id, pass startingPastAlias = None
+ let key_descriptors = keystore2.listEntriesBatched(Domain::APP, -1, None).unwrap();
+ assert_eq!(key_descriptors.len(), 0);
- // List all entries in keystore for this user-id, pass startingPastAlias = <random value>
- let key_descriptors =
- keystore2.listEntriesBatched(Domain::APP, -1, Some("startingPastAlias")).unwrap();
- assert_eq!(key_descriptors.len(), 0);
- })
+ // List all entries in keystore for this user-id, pass startingPastAlias = <random value>
+ let key_descriptors =
+ keystore2.listEntriesBatched(Domain::APP, -1, Some("startingPastAlias")).unwrap();
+ assert_eq!(key_descriptors.len(), 0);
};
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(CLIENT_UID, CLIENT_GID, list_keys_fn) };
}
/// Import a key with SELINUX as domain, list aliases using `listEntriesBatched`.
@@ -502,140 +492,135 @@
#[test]
fn keystore2_list_entries_batched_validate_count_and_order_success() {
- static CLIENT_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-
const USER_ID: u32 = 92;
const APPLICATION_ID: u32 = 10002;
static CLIENT_UID: u32 = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
static CLIENT_GID: u32 = CLIENT_UID;
static ALIAS_PREFIX: &str = "key_test_batch_list";
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(CLIENT_CTX, Uid::from_raw(CLIENT_UID), Gid::from_raw(CLIENT_GID), || {
- let sl = SecLevel::tee();
+ let list_keys_fn = || {
+ let sl = SecLevel::tee();
- // Make sure there are no keystore entries exist before adding new entries.
- delete_all_entries(&sl.keystore2);
+ // Make sure there are no keystore entries exist before adding new entries.
+ delete_all_entries(&sl.keystore2);
- // Import keys with below mentioned aliases -
- // [
- // key_test_batch_list_1,
- // key_test_batch_list_2,
- // key_test_batch_list_3,
- // key_test_batch_list_4,
- // key_test_batch_list_5,
- // key_test_batch_list_10,
- // key_test_batch_list_11,
- // key_test_batch_list_12,
- // key_test_batch_list_21,
- // key_test_batch_list_22,
- // ]
- let _imported_key_aliases =
- key_generations::import_aes_keys(&sl, ALIAS_PREFIX.to_string(), 1..6).unwrap();
- assert_eq!(
- sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
- 5,
- "Error while importing keys"
- );
- let _imported_key_aliases =
- key_generations::import_aes_keys(&sl, ALIAS_PREFIX.to_string(), 10..13).unwrap();
- assert_eq!(
- sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
- 8,
- "Error while importing keys"
- );
- let _imported_key_aliases =
- key_generations::import_aes_keys(&sl, ALIAS_PREFIX.to_string(), 21..23).unwrap();
- assert_eq!(
- sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
- 10,
- "Error while importing keys"
- );
+ // Import keys with below mentioned aliases -
+ // [
+ // key_test_batch_list_1,
+ // key_test_batch_list_2,
+ // key_test_batch_list_3,
+ // key_test_batch_list_4,
+ // key_test_batch_list_5,
+ // key_test_batch_list_10,
+ // key_test_batch_list_11,
+ // key_test_batch_list_12,
+ // key_test_batch_list_21,
+ // key_test_batch_list_22,
+ // ]
+ let _imported_key_aliases =
+ key_generations::import_aes_keys(&sl, ALIAS_PREFIX.to_string(), 1..6).unwrap();
+ assert_eq!(
+ sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+ 5,
+ "Error while importing keys"
+ );
+ let _imported_key_aliases =
+ key_generations::import_aes_keys(&sl, ALIAS_PREFIX.to_string(), 10..13).unwrap();
+ assert_eq!(
+ sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+ 8,
+ "Error while importing keys"
+ );
+ let _imported_key_aliases =
+ key_generations::import_aes_keys(&sl, ALIAS_PREFIX.to_string(), 21..23).unwrap();
+ assert_eq!(
+ sl.keystore2.getNumberOfEntries(Domain::APP, -1).unwrap(),
+ 10,
+ "Error while importing keys"
+ );
- // List the aliases using given `startingPastAlias` and verify the listed
- // aliases with the expected list of aliases.
- verify_aliases(
- &sl.keystore2,
- Some(format!("{}{}", ALIAS_PREFIX, "_5").as_str()),
- vec![],
- );
+ // List the aliases using given `startingPastAlias` and verify the listed
+ // aliases with the expected list of aliases.
+ verify_aliases(&sl.keystore2, Some(format!("{}{}", ALIAS_PREFIX, "_5").as_str()), vec![]);
- verify_aliases(
- &sl.keystore2,
- Some(format!("{}{}", ALIAS_PREFIX, "_4").as_str()),
- vec![ALIAS_PREFIX.to_owned() + "_5"],
- );
+ verify_aliases(
+ &sl.keystore2,
+ Some(format!("{}{}", ALIAS_PREFIX, "_4").as_str()),
+ vec![ALIAS_PREFIX.to_owned() + "_5"],
+ );
- verify_aliases(
- &sl.keystore2,
- Some(format!("{}{}", ALIAS_PREFIX, "_3").as_str()),
- vec![ALIAS_PREFIX.to_owned() + "_4", ALIAS_PREFIX.to_owned() + "_5"],
- );
+ verify_aliases(
+ &sl.keystore2,
+ Some(format!("{}{}", ALIAS_PREFIX, "_3").as_str()),
+ vec![ALIAS_PREFIX.to_owned() + "_4", ALIAS_PREFIX.to_owned() + "_5"],
+ );
- verify_aliases(
- &sl.keystore2,
- Some(format!("{}{}", ALIAS_PREFIX, "_2").as_str()),
- vec![
- ALIAS_PREFIX.to_owned() + "_21",
- ALIAS_PREFIX.to_owned() + "_22",
- ALIAS_PREFIX.to_owned() + "_3",
- ALIAS_PREFIX.to_owned() + "_4",
- ALIAS_PREFIX.to_owned() + "_5",
- ],
- );
+ verify_aliases(
+ &sl.keystore2,
+ Some(format!("{}{}", ALIAS_PREFIX, "_2").as_str()),
+ vec![
+ ALIAS_PREFIX.to_owned() + "_21",
+ ALIAS_PREFIX.to_owned() + "_22",
+ ALIAS_PREFIX.to_owned() + "_3",
+ ALIAS_PREFIX.to_owned() + "_4",
+ ALIAS_PREFIX.to_owned() + "_5",
+ ],
+ );
- verify_aliases(
- &sl.keystore2,
- Some(format!("{}{}", ALIAS_PREFIX, "_1").as_str()),
- vec![
- ALIAS_PREFIX.to_owned() + "_10",
- ALIAS_PREFIX.to_owned() + "_11",
- ALIAS_PREFIX.to_owned() + "_12",
- ALIAS_PREFIX.to_owned() + "_2",
- ALIAS_PREFIX.to_owned() + "_21",
- ALIAS_PREFIX.to_owned() + "_22",
- ALIAS_PREFIX.to_owned() + "_3",
- ALIAS_PREFIX.to_owned() + "_4",
- ALIAS_PREFIX.to_owned() + "_5",
- ],
- );
+ verify_aliases(
+ &sl.keystore2,
+ Some(format!("{}{}", ALIAS_PREFIX, "_1").as_str()),
+ vec![
+ ALIAS_PREFIX.to_owned() + "_10",
+ ALIAS_PREFIX.to_owned() + "_11",
+ ALIAS_PREFIX.to_owned() + "_12",
+ ALIAS_PREFIX.to_owned() + "_2",
+ ALIAS_PREFIX.to_owned() + "_21",
+ ALIAS_PREFIX.to_owned() + "_22",
+ ALIAS_PREFIX.to_owned() + "_3",
+ ALIAS_PREFIX.to_owned() + "_4",
+ ALIAS_PREFIX.to_owned() + "_5",
+ ],
+ );
- verify_aliases(
- &sl.keystore2,
- Some(ALIAS_PREFIX),
- vec![
- ALIAS_PREFIX.to_owned() + "_1",
- ALIAS_PREFIX.to_owned() + "_10",
- ALIAS_PREFIX.to_owned() + "_11",
- ALIAS_PREFIX.to_owned() + "_12",
- ALIAS_PREFIX.to_owned() + "_2",
- ALIAS_PREFIX.to_owned() + "_21",
- ALIAS_PREFIX.to_owned() + "_22",
- ALIAS_PREFIX.to_owned() + "_3",
- ALIAS_PREFIX.to_owned() + "_4",
- ALIAS_PREFIX.to_owned() + "_5",
- ],
- );
+ verify_aliases(
+ &sl.keystore2,
+ Some(ALIAS_PREFIX),
+ vec![
+ ALIAS_PREFIX.to_owned() + "_1",
+ ALIAS_PREFIX.to_owned() + "_10",
+ ALIAS_PREFIX.to_owned() + "_11",
+ ALIAS_PREFIX.to_owned() + "_12",
+ ALIAS_PREFIX.to_owned() + "_2",
+ ALIAS_PREFIX.to_owned() + "_21",
+ ALIAS_PREFIX.to_owned() + "_22",
+ ALIAS_PREFIX.to_owned() + "_3",
+ ALIAS_PREFIX.to_owned() + "_4",
+ ALIAS_PREFIX.to_owned() + "_5",
+ ],
+ );
- verify_aliases(
- &sl.keystore2,
- None,
- vec![
- ALIAS_PREFIX.to_owned() + "_1",
- ALIAS_PREFIX.to_owned() + "_10",
- ALIAS_PREFIX.to_owned() + "_11",
- ALIAS_PREFIX.to_owned() + "_12",
- ALIAS_PREFIX.to_owned() + "_2",
- ALIAS_PREFIX.to_owned() + "_21",
- ALIAS_PREFIX.to_owned() + "_22",
- ALIAS_PREFIX.to_owned() + "_3",
- ALIAS_PREFIX.to_owned() + "_4",
- ALIAS_PREFIX.to_owned() + "_5",
- ],
- );
- })
+ verify_aliases(
+ &sl.keystore2,
+ None,
+ vec![
+ ALIAS_PREFIX.to_owned() + "_1",
+ ALIAS_PREFIX.to_owned() + "_10",
+ ALIAS_PREFIX.to_owned() + "_11",
+ ALIAS_PREFIX.to_owned() + "_12",
+ ALIAS_PREFIX.to_owned() + "_2",
+ ALIAS_PREFIX.to_owned() + "_21",
+ ALIAS_PREFIX.to_owned() + "_22",
+ ALIAS_PREFIX.to_owned() + "_3",
+ ALIAS_PREFIX.to_owned() + "_4",
+ ALIAS_PREFIX.to_owned() + "_5",
+ ],
+ );
};
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(CLIENT_UID, CLIENT_GID, list_keys_fn) };
}
/// Try to list the key entries with domain SELINUX from user context where user doesn't possesses
@@ -645,22 +630,21 @@
fn keystore2_list_entries_batched_fails_perm_denied() {
let auid = 91 * AID_USER_OFFSET + 10001;
let agid = 91 * AID_USER_OFFSET + 10001;
- static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+ let list_keys_fn = move || {
+ let keystore2 = get_keystore_service();
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(TARGET_CTX, Uid::from_raw(auid), Gid::from_raw(agid), move || {
- let keystore2 = get_keystore_service();
-
- let result = key_generations::map_ks_error(keystore2.listEntriesBatched(
- Domain::SELINUX,
- key_generations::SELINUX_SHELL_NAMESPACE,
- None,
- ));
- assert!(result.is_err());
- assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
- })
+ let result = key_generations::map_ks_error(keystore2.listEntriesBatched(
+ Domain::SELINUX,
+ key_generations::SELINUX_SHELL_NAMESPACE,
+ None,
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
};
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(auid, agid, list_keys_fn) };
}
/// Try to list key entries with domain BLOB. Test should fail with error response code
@@ -685,21 +669,19 @@
fn keystore2_get_number_of_entries_fails_perm_denied() {
let auid = 91 * AID_USER_OFFSET + 10001;
let agid = 91 * AID_USER_OFFSET + 10001;
- static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
+ let get_num_fn = move || {
+ let keystore2 = get_keystore_service();
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(TARGET_CTX, Uid::from_raw(auid), Gid::from_raw(agid), move || {
- let keystore2 = get_keystore_service();
-
- let result = key_generations::map_ks_error(
- keystore2
- .getNumberOfEntries(Domain::SELINUX, key_generations::SELINUX_SHELL_NAMESPACE),
- );
- assert!(result.is_err());
- assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
- })
+ let result = key_generations::map_ks_error(
+ keystore2.getNumberOfEntries(Domain::SELINUX, key_generations::SELINUX_SHELL_NAMESPACE),
+ );
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
};
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(auid, agid, get_num_fn) };
}
/// Try to get number of key entries with domain BLOB. Test should fail with error response code
diff --git a/keystore2/tests/keystore2_client_operation_tests.rs b/keystore2/tests/keystore2_client_operation_tests.rs
index 5f640ef..1f8396e 100644
--- a/keystore2/tests/keystore2_client_operation_tests.rs
+++ b/keystore2/tests/keystore2_client_operation_tests.rs
@@ -40,7 +40,8 @@
///
/// # Safety
///
-/// Must be called from a process with no other threads.
+/// Must only be called from a single-threaded process (e.g. as enforced by `AndroidTest.xml`
+/// setting `--test-threads=1`).
pub unsafe fn create_operations(
target_ctx: &'static str,
forced_op: ForcedOp,
@@ -50,7 +51,7 @@
let base_gid = 99 * AID_USER_OFFSET + 10001;
let base_uid = 99 * AID_USER_OFFSET + 10001;
(0..max_ops)
- // SAFETY: The caller guarantees that there are no other threads.
+ // Safety: The caller guarantees that there are no other threads.
.map(|i| unsafe {
execute_op_run_as_child(
target_ctx,
@@ -93,7 +94,8 @@
const MAX_OPS: i32 = 100;
static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
- // SAFETY: The test is run in a separate process with no other threads.
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
let mut child_handles = unsafe { create_operations(TARGET_CTX, ForcedOp(false), MAX_OPS) };
// Wait until all child procs notifies us to continue,
@@ -127,7 +129,8 @@
static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
// Create regular operations.
- // SAFETY: The test is run in a separate process with no other threads.
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
let mut child_handles = unsafe { create_operations(TARGET_CTX, ForcedOp(false), MAX_OPS) };
// Wait until all child procs notifies us to continue, so that there are enough
@@ -139,28 +142,31 @@
// Create a forced operation.
let auid = 99 * AID_USER_OFFSET + 10604;
let agid = 99 * AID_USER_OFFSET + 10604;
- // SAFETY: The test is run in a separate process with no other threads.
+ let force_op_fn = 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.");
+ };
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
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.");
- },
+ force_op_fn,
);
};
@@ -212,7 +218,9 @@
// 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());
- // SAFETY: The test is run in a separate process with no other threads.
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
let mut first_op_handle = unsafe {
execute_op_run_as_child(
key_generations::TARGET_SU_CTX,
@@ -231,7 +239,8 @@
// Create MAX_OPS number of forced operations.
let mut child_handles =
- // SAFETY: The test is run in a separate process with no other threads.
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
unsafe { 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
@@ -295,7 +304,9 @@
// 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());
- // SAFETY: The test is run in a separate process with no other threads.
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
let mut child_handle = unsafe {
execute_op_run_as_child(
TARGET_CTX,
@@ -393,21 +404,24 @@
let gid = USER_ID * AID_USER_OFFSET + APPLICATION_ID;
for context in TARGET_CTXS.iter() {
- // SAFETY: The test is run in a separate process with no other threads.
+ let forced_op_fn = 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());
+ };
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
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());
- });
+ run_as::run_as(context, Uid::from_raw(uid), Gid::from_raw(gid), forced_op_fn);
}
}
}
@@ -416,27 +430,29 @@
/// 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";
+ static TARGET_VOLD_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;
+ let forced_op_fn = 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.");
+ };
- // SAFETY: The test is run in a separate process with no other threads.
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
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.");
- });
+ run_as::run_as(TARGET_VOLD_CTX, Uid::from_raw(uid), Gid::from_raw(gid), forced_op_fn);
}
}
diff --git a/keystore2/tests/keystore2_client_test_utils.rs b/keystore2/tests/keystore2_client_test_utils.rs
index 9029b97..831fc85 100644
--- a/keystore2/tests/keystore2_client_test_utils.rs
+++ b/keystore2/tests/keystore2_client_test_utils.rs
@@ -25,7 +25,11 @@
};
use binder::wait_for_interface;
use keystore2_test_utils::{
- authorizations, key_generations, key_generations::Error, run_as, SecLevel,
+ authorizations, key_generations,
+ key_generations::Error,
+ run_as,
+ run_as::{ChannelReader, ChannelWriter},
+ SecLevel,
};
use nix::unistd::{Gid, Uid};
use openssl::bn::BigNum;
@@ -305,7 +309,8 @@
///
/// # Safety
///
-/// Must only be called from a single-threaded process.
+/// Must only be called from a single-threaded process (e.g. as enforced by `AndroidTest.xml`
+/// setting `--test-threads=1`).
pub unsafe fn execute_op_run_as_child(
target_ctx: &'static str,
domain: Domain,
@@ -315,41 +320,44 @@
agid: Gid,
forced_op: ForcedOp,
) -> run_as::ChildHandle<TestOutcome, BarrierReached> {
- // SAFETY: The caller guarantees that there are no other threads.
- 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 child_fn = move |reader: &mut ChannelReader<BarrierReached>,
+ writer: &mut ChannelWriter<BarrierReached>| {
+ 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();
+ // 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),
+ // 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.")
+ Ok(_) => TestOutcome::OtherErr,
+ Err(Error::Rc(ResponseCode::BACKEND_BUSY)) => TestOutcome::BackendBusy,
+ _ => TestOutcome::OtherErr,
+ }
+ };
+
+ // Safety: The caller guarantees that there are no other threads.
+ unsafe {
+ run_as::run_as_child(target_ctx, auid, agid, child_fn)
+ .expect("Failed to create an operation.")
}
}
diff --git a/keystore2/tests/keystore2_client_update_subcomponent_tests.rs b/keystore2/tests/keystore2_client_update_subcomponent_tests.rs
index e25e52a..0e38298 100644
--- a/keystore2/tests/keystore2_client_update_subcomponent_tests.rs
+++ b/keystore2/tests/keystore2_client_update_subcomponent_tests.rs
@@ -22,7 +22,7 @@
use keystore2_test_utils::{
get_keystore_service, key_generations, key_generations::Error, run_as, SecLevel,
};
-use nix::unistd::{getuid, Gid, Uid};
+use nix::unistd::getuid;
use rustutils::users::AID_USER_OFFSET;
/// Generate a key and update its public certificate and certificate chain. Test should be able to
@@ -153,9 +153,6 @@
/// permissions, test should be able to update public certificate and cert-chain successfully.
#[test]
fn keystore2_update_subcomponent_fails_permission_denied() {
- static GRANTOR_SU_CTX: &str = "u:r:su:s0";
- static GRANTEE_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
-
const USER_ID_1: u32 = 99;
const APPLICATION_ID: u32 = 10001;
static GRANTEE_1_UID: u32 = USER_ID_1 * AID_USER_OFFSET + APPLICATION_ID;
@@ -166,117 +163,102 @@
static GRANTEE_2_GID: u32 = GRANTEE_2_UID;
// Generate a key and grant it to multiple users with different access permissions.
- // SAFETY: The test is run in a separate process with no other threads.
- let mut granted_keys = unsafe {
- run_as::run_as(GRANTOR_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
- let sl = SecLevel::tee();
- let alias = format!("ks_update_subcompo_test_1_{}", getuid());
- let mut granted_keys = Vec::new();
+ let grantor_fn = || {
+ let sl = SecLevel::tee();
+ let alias = format!("ks_update_subcompo_test_1_{}", getuid());
+ let mut granted_keys = Vec::new();
- let key_metadata = key_generations::generate_ec_p256_signing_key(
- &sl,
- Domain::APP,
- -1,
- Some(alias),
- None,
- )
+ let key_metadata =
+ key_generations::generate_ec_p256_signing_key(&sl, Domain::APP, -1, Some(alias), None)
+ .unwrap();
+
+ // Grant a key without update permission.
+ let access_vector = KeyPermission::GET_INFO.0;
+ let granted_key = sl
+ .keystore2
+ .grant(&key_metadata.key, GRANTEE_1_UID.try_into().unwrap(), access_vector)
.unwrap();
+ assert_eq!(granted_key.domain, Domain::GRANT);
+ granted_keys.push(granted_key.nspace);
- // Grant a key without update permission.
- let access_vector = KeyPermission::GET_INFO.0;
- let granted_key = sl
- .keystore2
- .grant(&key_metadata.key, GRANTEE_1_UID.try_into().unwrap(), access_vector)
- .unwrap();
- assert_eq!(granted_key.domain, Domain::GRANT);
- granted_keys.push(granted_key.nspace);
+ // Grant a key with update permission.
+ let access_vector = KeyPermission::GET_INFO.0 | KeyPermission::UPDATE.0;
+ let granted_key = sl
+ .keystore2
+ .grant(&key_metadata.key, GRANTEE_2_UID.try_into().unwrap(), access_vector)
+ .unwrap();
+ assert_eq!(granted_key.domain, Domain::GRANT);
+ granted_keys.push(granted_key.nspace);
- // Grant a key with update permission.
- let access_vector = KeyPermission::GET_INFO.0 | KeyPermission::UPDATE.0;
- let granted_key = sl
- .keystore2
- .grant(&key_metadata.key, GRANTEE_2_UID.try_into().unwrap(), access_vector)
- .unwrap();
- assert_eq!(granted_key.domain, Domain::GRANT);
- granted_keys.push(granted_key.nspace);
-
- granted_keys
- })
+ granted_keys
};
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ let mut granted_keys = unsafe { run_as::run_as_root(grantor_fn) };
+
// Grantee context, try to update the key public certs, permission denied error is expected.
let granted_key1_nspace = granted_keys.remove(0);
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(
- GRANTEE_CTX,
- Uid::from_raw(GRANTEE_1_UID),
- Gid::from_raw(GRANTEE_1_GID),
- move || {
- let keystore2 = get_keystore_service();
+ let grantee1_fn = move || {
+ let keystore2 = get_keystore_service();
- let other_cert: [u8; 32] = [123; 32];
- let other_cert_chain: [u8; 32] = [12; 32];
+ let other_cert: [u8; 32] = [123; 32];
+ let other_cert_chain: [u8; 32] = [12; 32];
- let result = key_generations::map_ks_error(keystore2.updateSubcomponent(
- &KeyDescriptor {
- domain: Domain::GRANT,
- nspace: granted_key1_nspace,
- alias: None,
- blob: None,
- },
- Some(&other_cert),
- Some(&other_cert_chain),
- ));
- assert!(result.is_err());
- assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
+ let result = key_generations::map_ks_error(keystore2.updateSubcomponent(
+ &KeyDescriptor {
+ domain: Domain::GRANT,
+ nspace: granted_key1_nspace,
+ alias: None,
+ blob: None,
},
- )
+ Some(&other_cert),
+ Some(&other_cert_chain),
+ ));
+ assert!(result.is_err());
+ assert_eq!(Error::Rc(ResponseCode::PERMISSION_DENIED), result.unwrap_err());
};
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(GRANTEE_1_UID, GRANTEE_1_GID, grantee1_fn) };
+
// Grantee context, update granted key public certs. Update should happen successfully.
let granted_key2_nspace = granted_keys.remove(0);
- // SAFETY: The test is run in a separate process with no other threads.
- unsafe {
- run_as::run_as(
- GRANTEE_CTX,
- Uid::from_raw(GRANTEE_2_UID),
- Gid::from_raw(GRANTEE_2_GID),
- move || {
- let keystore2 = get_keystore_service();
+ let grantee2_fn = move || {
+ let keystore2 = get_keystore_service();
- let other_cert: [u8; 32] = [124; 32];
- let other_cert_chain: [u8; 32] = [13; 32];
+ let other_cert: [u8; 32] = [124; 32];
+ let other_cert_chain: [u8; 32] = [13; 32];
- keystore2
- .updateSubcomponent(
- &KeyDescriptor {
- domain: Domain::GRANT,
- nspace: granted_key2_nspace,
- alias: None,
- blob: None,
- },
- Some(&other_cert),
- Some(&other_cert_chain),
- )
- .expect("updateSubcomponent should have succeeded.");
+ keystore2
+ .updateSubcomponent(
+ &KeyDescriptor {
+ domain: Domain::GRANT,
+ nspace: granted_key2_nspace,
+ alias: None,
+ blob: None,
+ },
+ Some(&other_cert),
+ Some(&other_cert_chain),
+ )
+ .expect("updateSubcomponent should have succeeded.");
- let key_entry_response = keystore2
- .getKeyEntry(&KeyDescriptor {
- domain: Domain::GRANT,
- nspace: granted_key2_nspace,
- alias: None,
- blob: None,
- })
- .unwrap();
- assert_eq!(Some(other_cert.to_vec()), key_entry_response.metadata.certificate);
- assert_eq!(
- Some(other_cert_chain.to_vec()),
- key_entry_response.metadata.certificateChain
- );
- },
- )
+ let key_entry_response = keystore2
+ .getKeyEntry(&KeyDescriptor {
+ domain: Domain::GRANT,
+ nspace: granted_key2_nspace,
+ alias: None,
+ blob: None,
+ })
+ .unwrap();
+ assert_eq!(Some(other_cert.to_vec()), key_entry_response.metadata.certificate);
+ assert_eq!(Some(other_cert_chain.to_vec()), key_entry_response.metadata.certificateChain);
};
+
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(GRANTEE_2_UID, GRANTEE_2_GID, grantee2_fn) };
}
#[test]
diff --git a/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs b/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs
index 11a4c0b..d71f463 100644
--- a/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs
+++ b/keystore2/tests/legacy_blobs/keystore2_legacy_blob_tests.rs
@@ -27,7 +27,7 @@
use keystore2::utils::AesGcm;
use keystore2_crypto::{Password, ZVec};
use keystore2_test_utils::{get_keystore_service, key_generations, run_as, SecLevel};
-use nix::unistd::{getuid, Gid, Uid};
+use nix::unistd::getuid;
use rustutils::users::AID_USER_OFFSET;
use serde::{Deserialize, Serialize};
use std::ops::Deref;
@@ -128,8 +128,6 @@
fn keystore2_encrypted_characteristics() -> anyhow::Result<()> {
let auid = 99 * AID_USER_OFFSET + 10001;
let agid = 99 * AID_USER_OFFSET + 10001;
- static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
- static TARGET_SU_CTX: &str = "u:r:su:s0";
// Cleanup user directory if it exists
let path_buf = PathBuf::from("/data/misc/keystore/user_99");
@@ -137,205 +135,202 @@
std::fs::remove_dir_all(path_buf.as_path()).unwrap();
}
- // Safety: run_as must be called from a single threaded process.
- // This device test is run as a separate single threaded process.
- let mut gen_key_result = unsafe {
- run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
- // Remove user if already exist.
- let maint_service = get_maintenance();
- match maint_service.onUserRemoved(99) {
- Ok(_) => {
- println!("User was existed, deleted successfully");
- }
- Err(e) => {
- println!("onUserRemoved error: {:#?}", e);
- }
+ let gen_key_fn = || {
+ // Remove user if already exist.
+ let maint_service = get_maintenance();
+ match maint_service.onUserRemoved(99) {
+ Ok(_) => {
+ println!("User did exist, deleted successfully");
}
- let sl = SecLevel::tee();
+ Err(e) => {
+ println!("onUserRemoved error: {:#?}", e);
+ }
+ }
+ let sl = SecLevel::tee();
- // Generate Key BLOB and prepare legacy keystore blob files.
- let att_challenge: Option<&[u8]> = if rkp_only() { None } else { Some(b"foo") };
- let key_metadata = key_generations::generate_ec_p256_signing_key(
- &sl,
- Domain::BLOB,
- SELINUX_SHELL_NAMESPACE,
- None,
- att_challenge,
+ // Generate Key BLOB and prepare legacy keystore blob files.
+ let att_challenge: Option<&[u8]> = if rkp_only() { None } else { Some(b"foo") };
+ let key_metadata = key_generations::generate_ec_p256_signing_key(
+ &sl,
+ Domain::BLOB,
+ SELINUX_SHELL_NAMESPACE,
+ None,
+ att_challenge,
+ )
+ .expect("Failed to generate key blob");
+
+ // Create keystore file layout for user_99.
+ let pw: Password = PASSWORD.into();
+ let pw_key = TestKey(pw.derive_key_pbkdf2(SUPERKEY_SALT, 32).unwrap());
+ let super_key =
+ TestKey(pw_key.decrypt(SUPERKEY_PAYLOAD, SUPERKEY_IV, SUPERKEY_TAG).unwrap());
+
+ let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
+ if !path_buf.as_path().is_dir() {
+ std::fs::create_dir(path_buf.as_path()).unwrap();
+ }
+ path_buf.push(".masterkey");
+ if !path_buf.as_path().is_file() {
+ std::fs::write(path_buf.as_path(), SUPERKEY).unwrap();
+ }
+
+ let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
+ path_buf.push("9910001_USRPKEY_authbound");
+ if !path_buf.as_path().is_file() {
+ make_encrypted_key_file(
+ path_buf.as_path(),
+ &super_key,
+ &key_metadata.key.blob.unwrap(),
)
- .expect("Failed to generate key blob");
+ .unwrap();
+ }
- // Create keystore file layout for user_99.
- let pw: Password = PASSWORD.into();
- let pw_key = TestKey(pw.derive_key_pbkdf2(SUPERKEY_SALT, 32).unwrap());
- let super_key =
- TestKey(pw_key.decrypt(SUPERKEY_PAYLOAD, SUPERKEY_IV, SUPERKEY_TAG).unwrap());
-
- let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
- if !path_buf.as_path().is_dir() {
- std::fs::create_dir(path_buf.as_path()).unwrap();
- }
- path_buf.push(".masterkey");
- if !path_buf.as_path().is_file() {
- std::fs::write(path_buf.as_path(), SUPERKEY).unwrap();
- }
-
- let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
- path_buf.push("9910001_USRPKEY_authbound");
- if !path_buf.as_path().is_file() {
- make_encrypted_key_file(
- path_buf.as_path(),
- &super_key,
- &key_metadata.key.blob.unwrap(),
- )
+ let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
+ path_buf.push(".9910001_chr_USRPKEY_authbound");
+ if !path_buf.as_path().is_file() {
+ make_encrypted_characteristics_file(path_buf.as_path(), &super_key, KEY_PARAMETERS)
.unwrap();
- }
+ }
+ let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
+ path_buf.push("9910001_USRCERT_authbound");
+ if !path_buf.as_path().is_file() {
+ make_cert_blob_file(path_buf.as_path(), key_metadata.certificate.as_ref().unwrap())
+ .unwrap();
+ }
+
+ if let Some(chain) = key_metadata.certificateChain.as_ref() {
let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
- path_buf.push(".9910001_chr_USRPKEY_authbound");
+ path_buf.push("9910001_CACERT_authbound");
if !path_buf.as_path().is_file() {
- make_encrypted_characteristics_file(path_buf.as_path(), &super_key, KEY_PARAMETERS)
- .unwrap();
+ make_cert_blob_file(path_buf.as_path(), chain).unwrap();
}
+ }
- let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
- path_buf.push("9910001_USRCERT_authbound");
- if !path_buf.as_path().is_file() {
- make_cert_blob_file(path_buf.as_path(), key_metadata.certificate.as_ref().unwrap())
- .unwrap();
+ // Keystore2 disables the legacy importer when it finds the legacy database empty.
+ // However, if the device boots with an empty legacy database, the optimization kicks in
+ // and keystore2 never checks the legacy file system layout.
+ // So, restart keystore2 service to detect populated legacy database.
+ keystore2_restart_service();
+
+ let auth_service = get_authorization();
+ match auth_service.onDeviceUnlocked(99, Some(PASSWORD)) {
+ Ok(result) => {
+ println!("Unlock Result: {:?}", result);
}
-
- if let Some(chain) = key_metadata.certificateChain.as_ref() {
- let mut path_buf = PathBuf::from("/data/misc/keystore/user_99");
- path_buf.push("9910001_CACERT_authbound");
- if !path_buf.as_path().is_file() {
- make_cert_blob_file(path_buf.as_path(), chain).unwrap();
- }
+ Err(e) => {
+ panic!("Unlock should have succeeded: {:?}", e);
}
+ }
- // Keystore2 disables the legacy importer when it finds the legacy database empty.
- // However, if the device boots with an empty legacy database, the optimization kicks in
- // and keystore2 never checks the legacy file system layout.
- // So, restart keystore2 service to detect populated legacy database.
- keystore2_restart_service();
+ let mut key_params: Vec<KsKeyparameter> = Vec::new();
+ for param in key_metadata.authorizations {
+ let key_param = KsKeyparameter::new(param.keyParameter.into(), param.securityLevel);
+ key_params.push(key_param);
+ }
- let auth_service = get_authorization();
- match auth_service.onDeviceUnlocked(99, Some(PASSWORD)) {
- Ok(result) => {
- println!("Unlock Result: {:?}", result);
- }
- Err(e) => {
- panic!("Unlock should have succeeded: {:?}", e);
- }
- }
-
- let mut key_params: Vec<KsKeyparameter> = Vec::new();
- for param in key_metadata.authorizations {
- let key_param = KsKeyparameter::new(param.keyParameter.into(), param.securityLevel);
- key_params.push(key_param);
- }
-
- KeygenResult {
- cert: key_metadata.certificate.unwrap(),
- cert_chain: key_metadata.certificateChain.unwrap_or_default(),
- key_parameters: key_params,
- }
- })
+ KeygenResult {
+ cert: key_metadata.certificate.unwrap(),
+ cert_chain: key_metadata.certificateChain.unwrap_or_default(),
+ key_parameters: key_params,
+ }
};
- // Safety: run_as must be called from a single threaded process.
- // This device test is run as a separate single threaded process.
- unsafe {
- run_as::run_as(TARGET_CTX, Uid::from_raw(auid), Gid::from_raw(agid), move || {
- println!("UID: {}", getuid());
- println!("Android User ID: {}", rustutils::users::multiuser_get_user_id(9910001));
- println!("Android app ID: {}", rustutils::users::multiuser_get_app_id(9910001));
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ let mut gen_key_result = unsafe { run_as::run_as_root(gen_key_fn) };
- let test_alias = "authbound";
- let keystore2 = get_keystore_service();
+ let use_key_fn = move || {
+ println!("UID: {}", getuid());
+ println!("Android User ID: {}", rustutils::users::multiuser_get_user_id(9910001));
+ println!("Android app ID: {}", rustutils::users::multiuser_get_app_id(9910001));
- match keystore2.getKeyEntry(&KeyDescriptor {
- domain: Domain::APP,
- nspace: SELINUX_SHELL_NAMESPACE,
- alias: Some(test_alias.to_string()),
- blob: None,
- }) {
- Ok(key_entry_response) => {
- assert_eq!(
- key_entry_response.metadata.certificate.unwrap(),
- gen_key_result.cert
- );
- assert_eq!(
- key_entry_response.metadata.certificateChain.unwrap_or_default(),
- gen_key_result.cert_chain
- );
- assert_eq!(key_entry_response.metadata.key.domain, Domain::KEY_ID);
- assert_ne!(key_entry_response.metadata.key.nspace, 0);
- assert_eq!(
- key_entry_response.metadata.keySecurityLevel,
- SecurityLevel::SecurityLevel::TRUSTED_ENVIRONMENT
- );
+ let test_alias = "authbound";
+ let keystore2 = get_keystore_service();
- // Preapare KsKeyParameter list from getKeEntry response Authorizations.
- let mut key_params: Vec<KsKeyparameter> = Vec::new();
- for param in key_entry_response.metadata.authorizations {
- let key_param =
- KsKeyparameter::new(param.keyParameter.into(), param.securityLevel);
- key_params.push(key_param);
- }
+ match keystore2.getKeyEntry(&KeyDescriptor {
+ domain: Domain::APP,
+ nspace: SELINUX_SHELL_NAMESPACE,
+ alias: Some(test_alias.to_string()),
+ blob: None,
+ }) {
+ Ok(key_entry_response) => {
+ assert_eq!(key_entry_response.metadata.certificate.unwrap(), gen_key_result.cert);
+ assert_eq!(
+ key_entry_response.metadata.certificateChain.unwrap_or_default(),
+ gen_key_result.cert_chain
+ );
+ assert_eq!(key_entry_response.metadata.key.domain, Domain::KEY_ID);
+ assert_ne!(key_entry_response.metadata.key.nspace, 0);
+ assert_eq!(
+ key_entry_response.metadata.keySecurityLevel,
+ SecurityLevel::SecurityLevel::TRUSTED_ENVIRONMENT
+ );
- // Combine keyparameters from gen_key_result and keyparameters
- // from legacy key-char file.
- let mut legacy_file_key_params: Vec<KsKeyparameter> = Vec::new();
- match structured_test_params() {
- LegacyKeyCharacteristics::File(legacy_key_params) => {
- for param in &legacy_key_params {
- let mut present_in_gen_params = false;
- for gen_param in &gen_key_result.key_parameters {
- if param.get_tag() == gen_param.get_tag() {
- present_in_gen_params = true;
- }
- }
- if !present_in_gen_params {
- legacy_file_key_params.push(param.clone());
+ // Preapare KsKeyParameter list from getKeEntry response Authorizations.
+ let mut key_params: Vec<KsKeyparameter> = Vec::new();
+ for param in key_entry_response.metadata.authorizations {
+ let key_param =
+ KsKeyparameter::new(param.keyParameter.into(), param.securityLevel);
+ key_params.push(key_param);
+ }
+
+ // Combine keyparameters from gen_key_result and keyparameters
+ // from legacy key-char file.
+ let mut legacy_file_key_params: Vec<KsKeyparameter> = Vec::new();
+ match structured_test_params() {
+ LegacyKeyCharacteristics::File(legacy_key_params) => {
+ for param in &legacy_key_params {
+ let mut present_in_gen_params = false;
+ for gen_param in &gen_key_result.key_parameters {
+ if param.get_tag() == gen_param.get_tag() {
+ present_in_gen_params = true;
}
}
- }
- _ => {
- panic!("Expecting file characteristics");
+ if !present_in_gen_params {
+ legacy_file_key_params.push(param.clone());
+ }
}
}
-
- // Remove Key-Params which have security levels other than TRUSTED_ENVIRONMENT
- gen_key_result.key_parameters.retain(|in_element| {
- *in_element.security_level()
- == SecurityLevel::SecurityLevel::TRUSTED_ENVIRONMENT
- });
-
- println!("GetKeyEntry response key params: {:#?}", key_params);
- println!("Generated key params: {:#?}", gen_key_result.key_parameters);
-
- gen_key_result.key_parameters.append(&mut legacy_file_key_params);
-
- println!("Combined key params: {:#?}", gen_key_result.key_parameters);
-
- // Validate all keyparameters present in getKeyEntry response.
- for param in &key_params {
- gen_key_result.key_parameters.retain(|in_element| *in_element != *param);
+ _ => {
+ panic!("Expecting file characteristics");
}
+ }
- println!(
- "GetKeyEntry response unmatched key params: {:#?}",
- gen_key_result.key_parameters
- );
- assert_eq!(gen_key_result.key_parameters.len(), 0);
+ // Remove Key-Params which have security levels other than TRUSTED_ENVIRONMENT
+ gen_key_result.key_parameters.retain(|in_element| {
+ *in_element.security_level()
+ == SecurityLevel::SecurityLevel::TRUSTED_ENVIRONMENT
+ });
+
+ println!("GetKeyEntry response key params: {:#?}", key_params);
+ println!("Generated key params: {:#?}", gen_key_result.key_parameters);
+
+ gen_key_result.key_parameters.append(&mut legacy_file_key_params);
+
+ println!("Combined key params: {:#?}", gen_key_result.key_parameters);
+
+ // Validate all keyparameters present in getKeyEntry response.
+ for param in &key_params {
+ gen_key_result.key_parameters.retain(|in_element| *in_element != *param);
}
- Err(s) => {
- panic!("getKeyEntry should have succeeded. {:?}", s);
- }
- };
- })
+
+ println!(
+ "GetKeyEntry response unmatched key params: {:#?}",
+ gen_key_result.key_parameters
+ );
+ assert_eq!(gen_key_result.key_parameters.len(), 0);
+ }
+ Err(s) => {
+ panic!("getKeyEntry should have succeeded. {:?}", s);
+ }
+ };
};
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(auid, agid, use_key_fn) };
+
// Make sure keystore2 clean up imported legacy db.
let path_buf = PathBuf::from("/data/misc/keystore/user_99");
if path_buf.as_path().is_dir() {
@@ -367,7 +362,7 @@
/// 6. To load and import the legacy key using its alias.
/// 7. After successful key import validate the user cert and cert-chain with initially
/// generated blobs.
-/// 8. Validate imported key perameters. Imported key parameters list should be the combination
+/// 8. Validate imported key parameters. Imported key parameters list should be the combination
/// of the key-parameters in characteristics file and the characteristics according to
/// the augmentation rules. There might be duplicate entries with different values for the
/// parameters like OS_VERSION, OS_VERSION, BOOT_PATCHLEVEL, VENDOR_PATCHLEVEL etc.
@@ -376,8 +371,6 @@
fn keystore2_encrypted_certificates() -> anyhow::Result<()> {
let auid = 98 * AID_USER_OFFSET + 10001;
let agid = 98 * AID_USER_OFFSET + 10001;
- static TARGET_CTX: &str = "u:r:untrusted_app:s0:c91,c256,c10,c20";
- static TARGET_SU_CTX: &str = "u:r:su:s0";
// Cleanup user directory if it exists
let path_buf = PathBuf::from("/data/misc/keystore/user_98");
@@ -385,177 +378,171 @@
std::fs::remove_dir_all(path_buf.as_path()).unwrap();
}
- // Safety: run_as must be called from a single threaded process.
- // This device test is run as a separate single threaded process.
- let gen_key_result = unsafe {
- run_as::run_as(TARGET_SU_CTX, Uid::from_raw(0), Gid::from_raw(0), || {
- // Remove user if already exist.
- let maint_service = get_maintenance();
- match maint_service.onUserRemoved(98) {
- Ok(_) => {
- println!("User was existed, deleted successfully");
- }
- Err(e) => {
- println!("onUserRemoved error: {:#?}", e);
- }
+ let gen_key_fn = || {
+ // Remove user if already exist.
+ let maint_service = get_maintenance();
+ match maint_service.onUserRemoved(98) {
+ Ok(_) => {
+ println!("User did exist, deleted successfully");
}
+ Err(e) => {
+ println!("onUserRemoved error: {:#?}", e);
+ }
+ }
- let sl = SecLevel::tee();
- // Generate Key BLOB and prepare legacy keystore blob files.
- let att_challenge: Option<&[u8]> = if rkp_only() { None } else { Some(b"foo") };
- let key_metadata = key_generations::generate_ec_p256_signing_key(
- &sl,
- Domain::BLOB,
- SELINUX_SHELL_NAMESPACE,
- None,
- att_challenge,
+ let sl = SecLevel::tee();
+ // Generate Key BLOB and prepare legacy keystore blob files.
+ let att_challenge: Option<&[u8]> = if rkp_only() { None } else { Some(b"foo") };
+ let key_metadata = key_generations::generate_ec_p256_signing_key(
+ &sl,
+ Domain::BLOB,
+ SELINUX_SHELL_NAMESPACE,
+ None,
+ att_challenge,
+ )
+ .expect("Failed to generate key blob");
+
+ // Create keystore file layout for user_98.
+ let pw: Password = PASSWORD.into();
+ let pw_key = TestKey(pw.derive_key_pbkdf2(SUPERKEY_SALT, 32).unwrap());
+ let super_key =
+ TestKey(pw_key.decrypt(SUPERKEY_PAYLOAD, SUPERKEY_IV, SUPERKEY_TAG).unwrap());
+
+ let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
+ if !path_buf.as_path().is_dir() {
+ std::fs::create_dir(path_buf.as_path()).unwrap();
+ }
+ path_buf.push(".masterkey");
+ if !path_buf.as_path().is_file() {
+ std::fs::write(path_buf.as_path(), SUPERKEY).unwrap();
+ }
+
+ let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
+ path_buf.push("9810001_USRPKEY_authboundcertenc");
+ if !path_buf.as_path().is_file() {
+ make_encrypted_key_file(
+ path_buf.as_path(),
+ &super_key,
+ &key_metadata.key.blob.unwrap(),
)
- .expect("Failed to generate key blob");
+ .unwrap();
+ }
- // Create keystore file layout for user_98.
- let pw: Password = PASSWORD.into();
- let pw_key = TestKey(pw.derive_key_pbkdf2(SUPERKEY_SALT, 32).unwrap());
- let super_key =
- TestKey(pw_key.decrypt(SUPERKEY_PAYLOAD, SUPERKEY_IV, SUPERKEY_TAG).unwrap());
+ let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
+ path_buf.push(".9810001_chr_USRPKEY_authboundcertenc");
+ if !path_buf.as_path().is_file() {
+ std::fs::write(path_buf.as_path(), USRPKEY_AUTHBOUND_CHR).unwrap();
+ }
+ let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
+ path_buf.push("9810001_USRCERT_authboundcertenc");
+ if !path_buf.as_path().is_file() {
+ make_encrypted_usr_cert_file(
+ path_buf.as_path(),
+ &super_key,
+ key_metadata.certificate.as_ref().unwrap(),
+ )
+ .unwrap();
+ }
+
+ if let Some(chain) = key_metadata.certificateChain.as_ref() {
let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
- if !path_buf.as_path().is_dir() {
- std::fs::create_dir(path_buf.as_path()).unwrap();
- }
- path_buf.push(".masterkey");
+ path_buf.push("9810001_CACERT_authboundcertenc");
if !path_buf.as_path().is_file() {
- std::fs::write(path_buf.as_path(), SUPERKEY).unwrap();
+ make_encrypted_ca_cert_file(path_buf.as_path(), &super_key, chain).unwrap();
}
+ }
- let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
- path_buf.push("9810001_USRPKEY_authboundcertenc");
- if !path_buf.as_path().is_file() {
- make_encrypted_key_file(
- path_buf.as_path(),
- &super_key,
- &key_metadata.key.blob.unwrap(),
- )
- .unwrap();
+ // Keystore2 disables the legacy importer when it finds the legacy database empty.
+ // However, if the device boots with an empty legacy database, the optimization kicks in
+ // and keystore2 never checks the legacy file system layout.
+ // So, restart keystore2 service to detect populated legacy database.
+ keystore2_restart_service();
+
+ let auth_service = get_authorization();
+ match auth_service.onDeviceUnlocked(98, Some(PASSWORD)) {
+ Ok(result) => {
+ println!("Unlock Result: {:?}", result);
}
-
- let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
- path_buf.push(".9810001_chr_USRPKEY_authboundcertenc");
- if !path_buf.as_path().is_file() {
- std::fs::write(path_buf.as_path(), USRPKEY_AUTHBOUND_CHR).unwrap();
+ Err(e) => {
+ panic!("Unlock should have succeeded: {:?}", e);
}
+ }
- let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
- path_buf.push("9810001_USRCERT_authboundcertenc");
- if !path_buf.as_path().is_file() {
- make_encrypted_usr_cert_file(
- path_buf.as_path(),
- &super_key,
- key_metadata.certificate.as_ref().unwrap(),
- )
- .unwrap();
- }
+ let mut key_params: Vec<KsKeyparameter> = Vec::new();
+ for param in key_metadata.authorizations {
+ let key_param = KsKeyparameter::new(param.keyParameter.into(), param.securityLevel);
+ key_params.push(key_param);
+ }
- if let Some(chain) = key_metadata.certificateChain.as_ref() {
- let mut path_buf = PathBuf::from("/data/misc/keystore/user_98");
- path_buf.push("9810001_CACERT_authboundcertenc");
- if !path_buf.as_path().is_file() {
- make_encrypted_ca_cert_file(path_buf.as_path(), &super_key, chain).unwrap();
- }
- }
-
- // Keystore2 disables the legacy importer when it finds the legacy database empty.
- // However, if the device boots with an empty legacy database, the optimization kicks in
- // and keystore2 never checks the legacy file system layout.
- // So, restart keystore2 service to detect populated legacy database.
- keystore2_restart_service();
-
- let auth_service = get_authorization();
- match auth_service.onDeviceUnlocked(98, Some(PASSWORD)) {
- Ok(result) => {
- println!("Unlock Result: {:?}", result);
- }
- Err(e) => {
- panic!("Unlock should have succeeded: {:?}", e);
- }
- }
-
- let mut key_params: Vec<KsKeyparameter> = Vec::new();
- for param in key_metadata.authorizations {
- let key_param = KsKeyparameter::new(param.keyParameter.into(), param.securityLevel);
- key_params.push(key_param);
- }
-
- KeygenResult {
- cert: key_metadata.certificate.unwrap(),
- cert_chain: key_metadata.certificateChain.unwrap_or_default(),
- key_parameters: key_params,
- }
- })
+ KeygenResult {
+ cert: key_metadata.certificate.unwrap(),
+ cert_chain: key_metadata.certificateChain.unwrap_or_default(),
+ key_parameters: key_params,
+ }
};
- // Safety: run_as must be called from a single threaded process.
- // This device test is run as a separate single threaded process.
- unsafe {
- run_as::run_as(TARGET_CTX, Uid::from_raw(auid), Gid::from_raw(agid), move || {
- println!("UID: {}", getuid());
- println!("Android User ID: {}", rustutils::users::multiuser_get_user_id(9810001));
- println!("Android app ID: {}", rustutils::users::multiuser_get_app_id(9810001));
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ let gen_key_result = unsafe { run_as::run_as_root(gen_key_fn) };
- let test_alias = "authboundcertenc";
- let keystore2 = get_keystore_service();
+ let use_key_fn = move || {
+ println!("UID: {}", getuid());
+ println!("Android User ID: {}", rustutils::users::multiuser_get_user_id(9810001));
+ println!("Android app ID: {}", rustutils::users::multiuser_get_app_id(9810001));
- match keystore2.getKeyEntry(&KeyDescriptor {
- domain: Domain::APP,
- nspace: SELINUX_SHELL_NAMESPACE,
- alias: Some(test_alias.to_string()),
- blob: None,
- }) {
- Ok(key_entry_response) => {
- assert_eq!(
- key_entry_response.metadata.certificate.unwrap(),
- gen_key_result.cert
- );
- assert_eq!(
- key_entry_response.metadata.certificateChain.unwrap_or_default(),
- gen_key_result.cert_chain
- );
+ let test_alias = "authboundcertenc";
+ let keystore2 = get_keystore_service();
- // Preapare KsKeyParameter list from getKeEntry response Authorizations.
- let mut key_params: Vec<KsKeyparameter> = Vec::new();
- for param in key_entry_response.metadata.authorizations {
- let key_param =
- KsKeyparameter::new(param.keyParameter.into(), param.securityLevel);
- key_params.push(key_param);
+ match keystore2.getKeyEntry(&KeyDescriptor {
+ domain: Domain::APP,
+ nspace: SELINUX_SHELL_NAMESPACE,
+ alias: Some(test_alias.to_string()),
+ blob: None,
+ }) {
+ Ok(key_entry_response) => {
+ assert_eq!(key_entry_response.metadata.certificate.unwrap(), gen_key_result.cert);
+ assert_eq!(
+ key_entry_response.metadata.certificateChain.unwrap_or_default(),
+ gen_key_result.cert_chain
+ );
+
+ // Preapare KsKeyParameter list from getKeEntry response Authorizations.
+ let mut key_params: Vec<KsKeyparameter> = Vec::new();
+ for param in key_entry_response.metadata.authorizations {
+ let key_param =
+ KsKeyparameter::new(param.keyParameter.into(), param.securityLevel);
+ key_params.push(key_param);
+ }
+
+ println!("GetKeyEntry response key params: {:#?}", key_params);
+ println!("Generated key params: {:#?}", gen_key_result.key_parameters);
+ match structured_test_params_cache() {
+ LegacyKeyCharacteristics::Cache(legacy_key_params) => {
+ println!("Legacy key-char cache: {:#?}", legacy_key_params);
+ // Validate all keyparameters present in getKeyEntry response.
+ for param in &legacy_key_params {
+ key_params.retain(|in_element| *in_element != *param);
+ }
+
+ println!("GetKeyEntry response unmatched key params: {:#?}", key_params);
+ assert_eq!(key_params.len(), 0);
}
-
- println!("GetKeyEntry response key params: {:#?}", key_params);
- println!("Generated key params: {:#?}", gen_key_result.key_parameters);
- match structured_test_params_cache() {
- LegacyKeyCharacteristics::Cache(legacy_key_params) => {
- println!("Legacy key-char cache: {:#?}", legacy_key_params);
- // Validate all keyparameters present in getKeyEntry response.
- for param in &legacy_key_params {
- key_params.retain(|in_element| *in_element != *param);
- }
-
- println!(
- "GetKeyEntry response unmatched key params: {:#?}",
- key_params
- );
- assert_eq!(key_params.len(), 0);
- }
- _ => {
- panic!("Expecting file characteristics");
- }
+ _ => {
+ panic!("Expecting file characteristics");
}
}
- Err(s) => {
- panic!("getKeyEntry should have succeeded. {:?}", s);
- }
- };
- })
+ }
+ Err(s) => {
+ panic!("getKeyEntry should have succeeded. {:?}", s);
+ }
+ };
};
+ // Safety: only one thread at this point (enforced by `AndroidTest.xml` setting
+ // `--test-threads=1`), and nothing yet done with binder.
+ unsafe { run_as::run_as_app(auid, agid, use_key_fn) };
+
// Make sure keystore2 clean up imported legacy db.
let path_buf = PathBuf::from("/data/misc/keystore/user_98");
if path_buf.as_path().is_dir() {