Snap for 12342105 from 9eb56108c8579325c10e5962ee2956c5bcf43d4c to 24Q4-release
Change-Id: Iaf83af803767b278a8f9463f8f6e7676f36cc5e6
diff --git a/keystore2/tests/keystore2_client_operation_tests.rs b/keystore2/tests/keystore2_client_operation_tests.rs
index 02cf260..5f640ef 100644
--- a/keystore2/tests/keystore2_client_operation_tests.rs
+++ b/keystore2/tests/keystore2_client_operation_tests.rs
@@ -28,6 +28,10 @@
};
use nix::unistd::{getuid, Gid, Uid};
use rustutils::users::AID_USER_OFFSET;
+use std::sync::{
+ atomic::{AtomicBool, Ordering},
+ Arc,
+};
use std::thread;
use std::thread::JoinHandle;
@@ -461,3 +465,120 @@
assert!(result1 || result2);
}
+
+/// Create an operation and use it for performing sign operation. After completing the operation
+/// try to abort the operation. Test should fail to abort already finalized operation with error
+/// code `INVALID_OPERATION_HANDLE`.
+#[test]
+fn keystore2_abort_finalized_op_fail_test() {
+ let op_response = create_signing_operation(
+ ForcedOp(false),
+ KeyPurpose::SIGN,
+ Digest::SHA_2_256,
+ Domain::APP,
+ -1,
+ Some("ks_op_abort_fail_test_key".to_string()),
+ )
+ .unwrap();
+
+ let op: binder::Strong<dyn IKeystoreOperation> = op_response.iOperation.unwrap();
+ perform_sample_sign_operation(&op).unwrap();
+ let result = key_generations::map_ks_error(op.abort());
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::INVALID_OPERATION_HANDLE), result.unwrap_err());
+}
+
+/// Create an operation and use it for performing sign operation. Before finishing the operation
+/// try to abort the operation. Test should successfully abort the operation. After aborting try to
+/// use the operation handle, test should fail to use already aborted operation handle with error
+/// code `INVALID_OPERATION_HANDLE`.
+#[test]
+fn keystore2_op_abort_success_test() {
+ let op_response = create_signing_operation(
+ ForcedOp(false),
+ KeyPurpose::SIGN,
+ Digest::SHA_2_256,
+ Domain::APP,
+ -1,
+ Some("ks_op_abort_success_key".to_string()),
+ )
+ .unwrap();
+
+ let op: binder::Strong<dyn IKeystoreOperation> = op_response.iOperation.unwrap();
+ op.update(b"my message").unwrap();
+ let result = key_generations::map_ks_error(op.abort());
+ assert!(result.is_ok());
+
+ // Try to use the op handle after abort.
+ let result = key_generations::map_ks_error(op.finish(None, None));
+ assert!(result.is_err());
+ assert_eq!(Error::Km(ErrorCode::INVALID_OPERATION_HANDLE), result.unwrap_err());
+}
+
+/// Executes an operation in a thread. Performs an `update` operation repeatedly till the user
+/// interrupts it or encounters any error other than `OPERATION_BUSY`.
+/// Return `false` in case of any error other than `OPERATION_BUSY`, otherwise it returns true.
+fn perform_abort_op_busy_in_thread(
+ op: binder::Strong<dyn IKeystoreOperation>,
+ should_exit_clone: Arc<AtomicBool>,
+) -> JoinHandle<bool> {
+ thread::spawn(move || {
+ loop {
+ if should_exit_clone.load(Ordering::Relaxed) {
+ // Caller requested to exit the thread.
+ return true;
+ }
+
+ match key_generations::map_ks_error(op.update(b"my message")) {
+ Ok(_) => continue,
+ Err(Error::Rc(ResponseCode::OPERATION_BUSY)) => continue,
+ Err(_) => return false,
+ }
+ }
+ })
+}
+
+/// Create an operation and try to use same operation handle in multiple threads to perform
+/// operations. Test tries to abort the operation and expects `abort` call to fail with the error
+/// response `OPERATION_BUSY` as multiple threads try to access the same operation handle
+/// simultaneously. Test tries to simulate `OPERATION_BUSY` error response from `abort` api.
+#[test]
+fn keystore2_op_abort_fails_with_operation_busy_error_test() {
+ loop {
+ let op_response = create_signing_operation(
+ ForcedOp(false),
+ KeyPurpose::SIGN,
+ Digest::SHA_2_256,
+ Domain::APP,
+ -1,
+ Some("op_abort_busy_alias_test_key".to_string()),
+ )
+ .unwrap();
+ let op: binder::Strong<dyn IKeystoreOperation> = op_response.iOperation.unwrap();
+
+ let should_exit = Arc::new(AtomicBool::new(false));
+
+ let update_t_handle1 = perform_abort_op_busy_in_thread(op.clone(), should_exit.clone());
+ let update_t_handle2 = perform_abort_op_busy_in_thread(op.clone(), should_exit.clone());
+
+ // Attempt to abort the operation and anticipate an 'OPERATION_BUSY' error, as multiple
+ // threads are concurrently accessing the same operation handle.
+ let result = match op.abort() {
+ Ok(_) => 0, // Operation successfully aborted.
+ Err(e) => e.service_specific_error(),
+ };
+
+ // Notify threads to stop performing `update` operation.
+ should_exit.store(true, Ordering::Relaxed);
+
+ let _update_op_result = update_t_handle1.join().unwrap();
+ let _update_op_result2 = update_t_handle2.join().unwrap();
+
+ if result == ResponseCode::OPERATION_BUSY.0 {
+ // The abort call failed with an OPERATION_BUSY error, as anticipated, due to multiple
+ // threads competing for access to the same operation handle.
+ return;
+ }
+ assert_eq!(result, 0);
+ }
+}
diff --git a/provisioner/rkp_factory_extraction_lib.cpp b/provisioner/rkp_factory_extraction_lib.cpp
index ec70d08..2c2614d 100644
--- a/provisioner/rkp_factory_extraction_lib.cpp
+++ b/provisioner/rkp_factory_extraction_lib.cpp
@@ -224,7 +224,8 @@
}
CborResult<cppbor::Array> getCsrV3(std::string_view componentName,
- IRemotelyProvisionedComponent* irpc, bool selfTest) {
+ IRemotelyProvisionedComponent* irpc, bool selfTest,
+ bool allowDegenerate) {
std::vector<uint8_t> csr;
std::vector<MacedPublicKey> emptyKeys;
const std::vector<uint8_t> challenge = generateChallenge();
@@ -237,7 +238,8 @@
}
if (selfTest) {
- auto result = verifyFactoryCsr(/*keysToSign=*/cppbor::Array(), csr, irpc, challenge);
+ auto result =
+ verifyFactoryCsr(/*keysToSign=*/cppbor::Array(), csr, irpc, challenge, allowDegenerate);
if (!result) {
std::cerr << "Self test failed for IRemotelyProvisionedComponent '" << componentName
<< "'. Error message: '" << result.message() << "'." << std::endl;
@@ -249,7 +251,7 @@
}
CborResult<Array> getCsr(std::string_view componentName, IRemotelyProvisionedComponent* irpc,
- bool selfTest) {
+ bool selfTest, bool allowDegenerate) {
RpcHardwareInfo hwInfo;
auto status = irpc->getHardwareInfo(&hwInfo);
if (!status.isOk()) {
@@ -264,7 +266,7 @@
}
return getCsrV1(componentName, irpc);
} else {
- return getCsrV3(componentName, irpc, selfTest);
+ return getCsrV3(componentName, irpc, selfTest, allowDegenerate);
}
}
diff --git a/provisioner/rkp_factory_extraction_lib.h b/provisioner/rkp_factory_extraction_lib.h
index 93c498a..94bd751 100644
--- a/provisioner/rkp_factory_extraction_lib.h
+++ b/provisioner/rkp_factory_extraction_lib.h
@@ -47,7 +47,7 @@
CborResult<cppbor::Array>
getCsr(std::string_view componentName,
aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent* irpc,
- bool selfTest);
+ bool selfTest, bool allowDegenerate);
// Generates a test certificate chain and validates it, exiting the process on error.
void selfTestGetCsr(
diff --git a/provisioner/rkp_factory_extraction_lib_test.cpp b/provisioner/rkp_factory_extraction_lib_test.cpp
index 3fe88da..247c508 100644
--- a/provisioner/rkp_factory_extraction_lib_test.cpp
+++ b/provisioner/rkp_factory_extraction_lib_test.cpp
@@ -181,7 +181,7 @@
Return(ByMove(ScopedAStatus::ok())))); //
auto [csr, csrErrMsg] = getCsr("mock component name", mockRpc.get(),
- /*selfTest=*/false);
+ /*selfTest=*/false, /*allowDegenerate=*/true);
ASSERT_THAT(csr, NotNull()) << csrErrMsg;
ASSERT_THAT(csr->asArray(), Pointee(Property(&Array::size, Eq(4))));
@@ -251,7 +251,7 @@
Return(ByMove(ScopedAStatus::ok()))));
auto [csr, csrErrMsg] = getCsr("mock component name", mockRpc.get(),
- /*selfTest=*/false);
+ /*selfTest=*/false, /*allowDegenerate=*/true);
ASSERT_THAT(csr, NotNull()) << csrErrMsg;
ASSERT_THAT(csr, Pointee(Property(&Array::size, Eq(5))));
diff --git a/provisioner/rkp_factory_extraction_tool.cpp b/provisioner/rkp_factory_extraction_tool.cpp
index 1cb1144..c0f6beb 100644
--- a/provisioner/rkp_factory_extraction_tool.cpp
+++ b/provisioner/rkp_factory_extraction_tool.cpp
@@ -43,6 +43,8 @@
"If true, this tool performs a self-test, validating the payload for correctness. "
"This checks that the device on the factory line is producing valid output "
"before attempting to upload the output to the device info service.");
+DEFINE_bool(allow_degenerate, true,
+ "If true, self_test validation will allow degenerate DICE chains in the CSR.");
DEFINE_string(serialno_prop, "ro.serialno",
"The property of getting serial number. Defaults to 'ro.serialno'.");
@@ -83,7 +85,7 @@
if (std::string(name) == "avf" && !isRemoteProvisioningSupported(irpc)) {
return;
}
- auto [request, errMsg] = getCsr(name, irpc, FLAGS_self_test);
+ auto [request, errMsg] = getCsr(name, irpc, FLAGS_self_test, FLAGS_allow_degenerate);
auto fullName = getFullServiceName(descriptor, name);
if (!request) {
std::cerr << "Unable to build CSR for '" << fullName << ": " << errMsg << std::endl;