Add self test to rkp_factory_extraction_tool

Self test mode gets a test CSR and validates it.

Test: rkp_factory_extraction_tool --self_test
Test: atest VtsHalRemotelyProvisionedComponentTargetTest
Bug: 239839050
Change-Id: Ib4b0221ffcf56b60ded1ac2a1f85eddb77729cbf
diff --git a/provisioner/rkp_factory_extraction_lib.cpp b/provisioner/rkp_factory_extraction_lib.cpp
index 831adba..77d032b 100644
--- a/provisioner/rkp_factory_extraction_lib.cpp
+++ b/provisioner/rkp_factory_extraction_lib.cpp
@@ -41,9 +41,12 @@
 using aidl::android::hardware::security::keymint::MacedPublicKey;
 using aidl::android::hardware::security::keymint::ProtectedData;
 using aidl::android::hardware::security::keymint::RpcHardwareInfo;
+using aidl::android::hardware::security::keymint::remote_prov::EekChain;
+using aidl::android::hardware::security::keymint::remote_prov::generateEekChain;
 using aidl::android::hardware::security::keymint::remote_prov::getProdEekChain;
 using aidl::android::hardware::security::keymint::remote_prov::jsonEncodeCsrWithBuild;
-using aidl::android::hardware::security::keymint::remote_prov::parseAndValidateDeviceInfo;
+using aidl::android::hardware::security::keymint::remote_prov::parseAndValidateFactoryDeviceInfo;
+using aidl::android::hardware::security::keymint::remote_prov::verifyFactoryProtectedData;
 
 using namespace cppbor;
 using namespace cppcose;
@@ -106,7 +109,7 @@
                                 .add(keysToSignMac);            // MAC as returned from the HAL
 
     ErrMsgOr<std::unique_ptr<Map>> parsedVerifiedDeviceInfo =
-        parseAndValidateDeviceInfo(verifiedDeviceInfo.deviceInfo, provisionable);
+        parseAndValidateFactoryDeviceInfo(verifiedDeviceInfo.deviceInfo, provisionable);
     if (!parsedVerifiedDeviceInfo) {
         return {nullptr, parsedVerifiedDeviceInfo.moveMessage()};
     }
@@ -154,3 +157,39 @@
     return composeCertificateRequest(protectedData, verifiedDeviceInfo, challenge, keysToSignMac,
                                      irpc);
 }
+
+void selfTestGetCsr(std::string_view componentName, IRemotelyProvisionedComponent* irpc) {
+    std::vector<uint8_t> keysToSignMac;
+    std::vector<MacedPublicKey> emptyKeys;
+    DeviceInfo verifiedDeviceInfo;
+    ProtectedData protectedData;
+    RpcHardwareInfo hwInfo;
+    ::ndk::ScopedAStatus status = irpc->getHardwareInfo(&hwInfo);
+    if (!status.isOk()) {
+        std::cerr << "Failed to get hardware info for '" << componentName
+                  << "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
+        exit(-1);
+    }
+
+    const std::vector<uint8_t> eekId = {0, 1, 2, 3, 4, 5, 6, 7};
+    ErrMsgOr<EekChain> eekChain = generateEekChain(hwInfo.supportedEekCurve, /*length=*/3, eekId);
+    if (!eekChain) {
+        std::cerr << "Error generating test EEK certificate chain: " << eekChain.message();
+        exit(-1);
+    }
+    const std::vector<uint8_t> challenge = generateChallenge();
+    status = irpc->generateCertificateRequest(
+        /*test_mode=*/true, emptyKeys, eekChain->chain, challenge, &verifiedDeviceInfo,
+        &protectedData, &keysToSignMac);
+    if (!status.isOk()) {
+        std::cerr << "Error generating test cert chain for '" << componentName
+                  << "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
+        exit(-1);
+    }
+
+    auto result = verifyFactoryProtectedData(verifiedDeviceInfo, /*keysToSign=*/{}, keysToSignMac,
+                                             protectedData, *eekChain, eekId,
+                                             hwInfo.supportedEekCurve, irpc, challenge);
+
+    std::cout << "Self test successful." << std::endl;
+}
\ No newline at end of file
diff --git a/provisioner/rkp_factory_extraction_lib.h b/provisioner/rkp_factory_extraction_lib.h
index 808ce7c..a803582 100644
--- a/provisioner/rkp_factory_extraction_lib.h
+++ b/provisioner/rkp_factory_extraction_lib.h
@@ -45,4 +45,9 @@
 // what went wrong.
 CborResult<cppbor::Array>
 getCsr(std::string_view componentName,
-       aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent* irpc);
\ No newline at end of file
+       aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent* irpc);
+
+// Generates a test certificate chain and validates it, exiting the process on error.
+void selfTestGetCsr(
+    std::string_view componentName,
+    aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent* irpc);
\ No newline at end of file
diff --git a/provisioner/rkp_factory_extraction_tool.cpp b/provisioner/rkp_factory_extraction_tool.cpp
index 502d931..0fe7d74 100644
--- a/provisioner/rkp_factory_extraction_tool.cpp
+++ b/provisioner/rkp_factory_extraction_tool.cpp
@@ -34,7 +34,11 @@
 using namespace cppbor;
 using namespace cppcose;
 
-DEFINE_string(output_format, "csr", "How to format the output. Defaults to 'csr'.");
+DEFINE_string(output_format, "build+csr", "How to format the output. Defaults to 'build+csr'.");
+DEFINE_bool(self_test, false,
+            "If true, the tool does not output CSR data, but instead performs a self-test, "
+            "validating a test payload for correctness. This may be used to verify a device on the "
+            "factory line before attempting to upload the output to the device info service.");
 
 namespace {
 
@@ -79,13 +83,17 @@
         exit(-1);
     }
 
-    auto [request, errMsg] = getCsr(name, rkp_service.get());
-    if (!request) {
-        std::cerr << "Unable to build CSR for '" << fullName << ": " << errMsg << std::endl;
-        exit(-1);
-    }
+    if (FLAGS_self_test) {
+        selfTestGetCsr(name, rkp_service.get());
+    } else {
+        auto [request, errMsg] = getCsr(name, rkp_service.get());
+        if (!request) {
+            std::cerr << "Unable to build CSR for '" << fullName << ": " << errMsg << std::endl;
+            exit(-1);
+        }
 
-    writeOutput(std::string(name), *request);
+        writeOutput(std::string(name), *request);
+    }
 }
 
 }  // namespace