Add JSON output to the RKP factory tool

The JSON format is suitable for uploading as test data. It also
includes the build fingerprint, which is required by the backend
to associate the CSR with a particular device family.

Bug: 191301285
Test: Manually run the tool with various --output_format flags
Change-Id: I1d787271c52a25df2d16a6d88dd7b278407ff4b7
Merged-In: I1d787271c52a25df2d16a6d88dd7b278407ff4b7
diff --git a/provisioner/rkp_factory_extraction_tool.cpp b/provisioner/rkp_factory_extraction_tool.cpp
index a6c7d72..bf6b9a6 100644
--- a/provisioner/rkp_factory_extraction_tool.cpp
+++ b/provisioner/rkp_factory_extraction_tool.cpp
@@ -37,6 +37,7 @@
 using aidl::android::hardware::security::keymint::ProtectedData;
 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 android::vintf::HalManifest;
 using android::vintf::VintfObject;
@@ -46,12 +47,19 @@
 
 DEFINE_bool(test_mode, false, "If enabled, a fake EEK key/cert are used.");
 
+DEFINE_string(output_format, "csr", "How to format the output. Defaults to 'csr'.");
+
 namespace {
 
 const string kPackage = "android.hardware.security.keymint";
 const string kInterface = "IRemotelyProvisionedComponent";
 const string kFormattedName = kPackage + "." + kInterface + "/";
 
+// Various supported --output_format values.
+constexpr std::string_view kBinaryCsrOutput = "csr";     // Just the raw csr as binary
+constexpr std::string_view kBuildPlusCsr = "build+csr";  // Text-encoded (JSON) build
+                                                         // fingerprint plus CSR.
+
 constexpr size_t kChallengeSize = 16;
 
 std::vector<uint8_t> generateChallenge() {
@@ -71,9 +79,8 @@
     return challenge;
 }
 
-std::vector<uint8_t> composeCertificateRequest(ProtectedData&& protectedData,
-                                               DeviceInfo&& deviceInfo,
-                                               const std::vector<uint8_t>& challenge) {
+Array composeCertificateRequest(ProtectedData&& protectedData, DeviceInfo&& deviceInfo,
+                                const std::vector<uint8_t>& challenge) {
     Array emptyMacedKeysToSign;
     emptyMacedKeysToSign
         .add(std::vector<uint8_t>(0))   // empty protected headers as bstr
@@ -85,7 +92,7 @@
         .add(challenge)
         .add(EncodedItem(std::move(protectedData.protectedData)))
         .add(std::move(emptyMacedKeysToSign));
-    return certificateRequest.encode();
+    return certificateRequest;
 }
 
 int32_t errorMsg(string name) {
@@ -106,6 +113,26 @@
     return getProdEekChain();
 }
 
+void writeOutput(const Array& csr) {
+    if (FLAGS_output_format == kBinaryCsrOutput) {
+        auto bytes = csr.encode();
+        std::copy(bytes.begin(), bytes.end(), std::ostream_iterator<char>(std::cout));
+    } else if (FLAGS_output_format == kBuildPlusCsr) {
+        auto [json, error] = jsonEncodeCsrWithBuild(csr);
+        if (!error.empty()) {
+            std::cerr << "Error JSON encoding the output: " << error;
+            exit(1);
+        }
+        std::cout << json << std::endl;
+    } else {
+        std::cerr << "Unexpected output_format '" << FLAGS_output_format << "'" << std::endl;
+        std::cerr << "Valid formats:" << std::endl;
+        std::cerr << "  " << kBinaryCsrOutput << std::endl;
+        std::cerr << "  " << kBuildPlusCsr << std::endl;
+        exit(1);
+    }
+}
+
 }  // namespace
 
 int main(int argc, char** argv) {
@@ -140,10 +167,8 @@
                 ALOGE("Bundle extraction failed. Error code: %d", status.getServiceSpecificError());
                 return errorMsg(name);
             }
-            std::vector<uint8_t> certificateRequest = composeCertificateRequest(
-                std::move(protectedData), std::move(deviceInfo), challenge);
-            std::copy(certificateRequest.begin(), certificateRequest.end(),
-                      std::ostream_iterator<char>(std::cout));
+            writeOutput(composeCertificateRequest(std::move(protectedData), std::move(deviceInfo),
+                                                  challenge));
         }
     }
 }