Support CompOS Key Service in a VM

Add the ability to start the service in a VM, and to then communicate
with it from the host via RPC Binder. Update command-line syntax.

Also revert my recent client naming change, since one tool that can
handle both host & VM seems better than two different ones.

Bug: 193603140
Test: Manual: start service in VM, connect to it, generate & verify keys.
Change-Id: I3cdb25395537e29bbfaa957eeac0c16ba4de93de
diff --git a/compos/compos_key_cmd/Android.bp b/compos/compos_key_cmd/Android.bp
index 460b96f..00d1035 100644
--- a/compos/compos_key_cmd/Android.bp
+++ b/compos/compos_key_cmd/Android.bp
@@ -14,6 +14,7 @@
     shared_libs: [
         "compos_aidl_interface-ndk_platform",
         "libbase",
+        "libbinder_rpc_unstable",
         "libbinder_ndk",
         "libcrypto",
         "libfsverity",
diff --git a/compos/compos_key_cmd/compos_key_cmd.cpp b/compos/compos_key_cmd/compos_key_cmd.cpp
index 3fe843a..bee9de1 100644
--- a/compos/compos_key_cmd/compos_key_cmd.cpp
+++ b/compos/compos_key_cmd/compos_key_cmd.cpp
@@ -35,6 +35,11 @@
 
 #include "compos_signature.pb.h"
 
+// From frameworks/native/libs/binder/rust/src/binder_rpc_unstable.hpp
+extern "C" {
+AIBinder* RpcClient(unsigned int cid, unsigned int port);
+}
+
 using namespace std::literals;
 
 using aidl::com::android::compos::CompOsKeyData;
@@ -45,6 +50,8 @@
 using android::base::unique_fd;
 using compos::proto::Signature;
 
+const unsigned int kRpcPort = 3142;
+
 static bool writeBytesToFile(const std::vector<uint8_t>& bytes, const std::string& path) {
     std::string str(bytes.begin(), bytes.end());
     return android::base::WriteStringToFile(str, path);
@@ -58,6 +65,12 @@
     return std::vector<uint8_t>(str.begin(), str.end());
 }
 
+static std::shared_ptr<ICompOsKeyService> getService(int cid) {
+    ndk::SpAIBinder binder(cid == 0 ? AServiceManager_getService("android.system.composkeyservice")
+                                    : RpcClient(cid, kRpcPort));
+    return ICompOsKeyService::fromBinder(binder);
+}
+
 static Result<std::vector<uint8_t>> extractRsaPublicKey(
         const std::vector<uint8_t>& der_certificate) {
     auto data = der_certificate.data();
@@ -89,9 +102,9 @@
     return result;
 }
 
-static Result<void> generate(const std::string& blob_file, const std::string& public_key_file) {
-    ndk::SpAIBinder binder(AServiceManager_getService("android.system.composkeyservice"));
-    auto service = ICompOsKeyService::fromBinder(binder);
+static Result<void> generate(int cid, const std::string& blob_file,
+                             const std::string& public_key_file) {
+    auto service = getService(cid);
     if (!service) {
         return Error() << "No service";
     }
@@ -117,9 +130,9 @@
     return {};
 }
 
-static Result<bool> verify(const std::string& blob_file, const std::string& public_key_file) {
-    ndk::SpAIBinder binder(AServiceManager_getService("android.system.composkeyservice"));
-    auto service = ICompOsKeyService::fromBinder(binder);
+static Result<bool> verify(int cid, const std::string& blob_file,
+                           const std::string& public_key_file) {
+    auto service = getService(cid);
     if (!service) {
         return Error() << "No service";
     }
@@ -210,9 +223,9 @@
     return {};
 }
 
-static Result<void> sign(const std::string& blob_file, const std::vector<std::string>& files) {
-    ndk::SpAIBinder binder(AServiceManager_getService("android.system.composkeyservice"));
-    auto service = ICompOsKeyService::fromBinder(binder);
+static Result<void> sign(int cid, const std::string& blob_file,
+                         const std::vector<std::string>& files) {
+    auto service = getService(cid);
     if (!service) {
         return Error() << "No service";
     }
@@ -235,15 +248,26 @@
     // Restrict access to our outputs to the current user.
     umask(077);
 
-    if (argc == 4 && argv[1] == "--generate"sv) {
-        auto result = generate(argv[2], argv[3]);
+    int cid = 0;
+    if (argc >= 3 && argv[1] == "--cid"sv) {
+        cid = atoi(argv[2]);
+        if (cid == 0) {
+            std::cerr << "Invalid cid\n";
+            return 1;
+        }
+        argc -= 2;
+        argv += 2;
+    }
+
+    if (argc == 4 && argv[1] == "generate"sv) {
+        auto result = generate(cid, argv[2], argv[3]);
         if (result.ok()) {
             return 0;
         } else {
             std::cerr << result.error() << '\n';
         }
-    } else if (argc == 4 && argv[1] == "--verify"sv) {
-        auto result = verify(argv[2], argv[3]);
+    } else if (argc == 4 && argv[1] == "verify"sv) {
+        auto result = verify(cid, argv[2], argv[3]);
         if (result.ok()) {
             if (result.value()) {
                 std::cerr << "Key files are valid.\n";
@@ -254,9 +278,9 @@
         } else {
             std::cerr << result.error() << '\n';
         }
-    } else if (argc >= 4 && argv[1] == "--sign"sv) {
+    } else if (argc >= 4 && argv[1] == "sign"sv) {
         const std::vector<std::string> files{&argv[3], &argv[argc]};
-        auto result = sign(argv[2], files);
+        auto result = sign(cid, argv[2], files);
         if (result.ok()) {
             std::cerr << "All signatures generated.\n";
             return 0;
@@ -264,14 +288,15 @@
             std::cerr << result.error() << '\n';
         }
     } else {
-        std::cerr << "Usage: \n"
-                  << "  --generate <blob file> <public key file> Generate new key pair and "
+        std::cerr << "Usage: compos_key_cmd [--cid <cid>] generate|verify|sign\n"
+                  << "  generate <blob file> <public key file> Generate new key pair and "
                      "write\n"
                   << "    the private key blob and public key to the specified files.\n "
-                  << "  --verify <blob file> <public key file> Verify that the content of the\n"
+                  << "  verify <blob file> <public key file> Verify that the content of the\n"
                   << "    specified private key blob and public key files are valid.\n "
-                  << "  --sign <blob file> <files to be signed> Generate signatures for one or\n"
-                  << "    more files using the supplied private key blob.\n";
+                  << "  sign <blob file> <files to be signed> Generate signatures for one or\n"
+                  << "    more files using the supplied private key blob.\n"
+                  << "Specify --cid to connect to a VM rather than the host\n";
     }
     return 1;
 }