Split rkp_factory_extraction_tool into a library + binary

This way, we can unit test the library in preparation for up-coming
changes that will verify the outputs. This will serve as an extra
layer of checking for factory lines, where they want to be extra
sure that a device is outputing correct information at various stages
of the pipe.

Bug: 239838563
Test: rkp_factory_extraction_lib_test
Change-Id: I018194673820d2b31c18d30057aa533cb4fe090e
diff --git a/provisioner/rkp_factory_extraction_tool.cpp b/provisioner/rkp_factory_extraction_tool.cpp
index 0f45531..ee8d851 100644
--- a/provisioner/rkp_factory_extraction_tool.cpp
+++ b/provisioner/rkp_factory_extraction_tool.cpp
@@ -14,9 +14,6 @@
  * limitations under the License.
  */
 
-#include <string>
-#include <vector>
-
 #include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
 #include <android/binder_manager.h>
 #include <cppbor.h>
@@ -26,20 +23,17 @@
 #include <remote_prov/remote_prov_utils.h>
 #include <sys/random.h>
 
-using aidl::android::hardware::security::keymint::DeviceInfo;
+#include <string>
+#include <vector>
+
+#include "rkp_factory_extraction_lib.h"
+
 using aidl::android::hardware::security::keymint::IRemotelyProvisionedComponent;
-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::generateEekChain;
-using aidl::android::hardware::security::keymint::remote_prov::getProdEekChain;
 using aidl::android::hardware::security::keymint::remote_prov::jsonEncodeCsrWithBuild;
 
 using namespace cppbor;
 using namespace cppcose;
 
-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 {
@@ -51,87 +45,6 @@
 
 constexpr size_t kChallengeSize = 16;
 
-std::string toBase64(const std::vector<uint8_t>& buffer) {
-    size_t base64Length;
-    int rc = EVP_EncodedLength(&base64Length, buffer.size());
-    if (!rc) {
-        std::cerr << "Error getting base64 length. Size overflow?" << std::endl;
-        exit(-1);
-    }
-
-    std::string base64(base64Length, ' ');
-    rc = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(base64.data()), buffer.data(), buffer.size());
-    ++rc;  // Account for NUL, which BoringSSL does not for some reason.
-    if (rc != base64Length) {
-        std::cerr << "Error writing base64. Expected " << base64Length
-                  << " bytes to be written, but " << rc << " bytes were actually written."
-                  << std::endl;
-        exit(-1);
-    }
-    return base64;
-}
-
-std::vector<uint8_t> generateChallenge() {
-    std::vector<uint8_t> challenge(kChallengeSize);
-
-    ssize_t bytesRemaining = static_cast<ssize_t>(challenge.size());
-    uint8_t* writePtr = challenge.data();
-    while (bytesRemaining > 0) {
-        int bytesRead = getrandom(writePtr, bytesRemaining, /*flags=*/0);
-        if (bytesRead < 0) {
-            if (errno == EINTR) {
-                continue;
-            } else {
-                std::cerr << errno << ": " << strerror(errno) << std::endl;
-                exit(-1);
-            }
-        }
-        bytesRemaining -= bytesRead;
-        writePtr += bytesRead;
-    }
-
-    return challenge;
-}
-
-Array composeCertificateRequest(const ProtectedData& protectedData,
-                                const DeviceInfo& verifiedDeviceInfo,
-                                const std::vector<uint8_t>& challenge,
-                                const std::vector<uint8_t>& keysToSignMac) {
-    Array macedKeysToSign = Array()
-                                .add(std::vector<uint8_t>(0))  // empty protected headers as bstr
-                                .add(Map())                    // empty unprotected headers
-                                .add(Null())                   // nil for the payload
-                                .add(keysToSignMac);           // MAC as returned from the HAL
-
-    Array deviceInfo =
-        Array().add(EncodedItem(verifiedDeviceInfo.deviceInfo)).add(Map());  // Empty device info
-
-    Array certificateRequest = Array()
-                                   .add(std::move(deviceInfo))
-                                   .add(challenge)
-                                   .add(EncodedItem(protectedData.protectedData))
-                                   .add(std::move(macedKeysToSign));
-    return certificateRequest;
-}
-
-std::vector<uint8_t> getEekChain(uint32_t curve) {
-    if (FLAGS_test_mode) {
-        const std::vector<uint8_t> kFakeEekId = {'f', 'a', 'k', 'e', 0};
-        auto eekOrErr = generateEekChain(curve, 3 /* chainlength */, kFakeEekId);
-        if (!eekOrErr) {
-            std::cerr << "Failed to generate test EEK somehow: " << eekOrErr.message() << std::endl;
-            exit(-1);
-        }
-        auto [eek, pubkey, privkey] = eekOrErr.moveValue();
-        std::cout << "EEK raw keypair:" << std::endl;
-        std::cout << "  pub:  " << toBase64(pubkey) << std::endl;
-        std::cout << "  priv: " << toBase64(privkey) << std::endl;
-        return eek;
-    }
-
-    return getProdEekChain(curve);
-}
-
 void writeOutput(const std::string instance_name, const Array& csr) {
     if (FLAGS_output_format == kBinaryCsrOutput) {
         auto bytes = csr.encode();
@@ -166,28 +79,14 @@
         exit(-1);
     }
 
-    std::vector<uint8_t> keysToSignMac;
-    std::vector<MacedPublicKey> emptyKeys;
-    DeviceInfo verifiedDeviceInfo;
-    ProtectedData protectedData;
-    RpcHardwareInfo hwInfo;
-    ::ndk::ScopedAStatus status = rkp_service->getHardwareInfo(&hwInfo);
-    if (!status.isOk()) {
-        std::cerr << "Failed to get hardware info for '" << fullName
-                  << "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
+    auto [request, errMsg] = getCsr(name, rkp_service.get());
+    if (!request) {
+        std::cerr << "Unable to build CSR for '" << fullName << ": "
+                  << errMsg.value_or("<Unknown Error>") << std::endl;
         exit(-1);
     }
-    status = rkp_service->generateCertificateRequest(
-        FLAGS_test_mode, emptyKeys, getEekChain(hwInfo.supportedEekCurve), challenge,
-        &verifiedDeviceInfo, &protectedData, &keysToSignMac);
-    if (!status.isOk()) {
-        std::cerr << "Bundle extraction failed for '" << fullName
-                  << "'. Error code: " << status.getServiceSpecificError() << "." << std::endl;
-        exit(-1);
-    }
-    auto request =
-        composeCertificateRequest(protectedData, verifiedDeviceInfo, challenge, keysToSignMac);
-    writeOutput(std::string(name), request);
+
+    writeOutput(std::string(name), *request);
 }
 
 }  // namespace