Merge ICompOsKeyService into ICompOsService

 * Remove the compos_key_main executable and key_service_vm_config.json,
   since the service is now provided by ICompOsService/compsvc.
 * Updated ComosKeyTestCase to use the same VM / service.

Bug: 161471326
Test: ComposHostTestCases

Change-Id: I8efb1158a90a06d0ba123da98c90fc69ff09d738
diff --git a/compos/Android.bp b/compos/Android.bp
index a626103..e29387d 100644
--- a/compos/Android.bp
+++ b/compos/Android.bp
@@ -52,29 +52,3 @@
         "com.android.compos",
     ],
 }
-
-rust_binary {
-    name: "compos_key_main",
-    srcs: ["src/compos_key_main.rs"],
-    edition: "2018",
-    rustlibs: [
-        "authfs_aidl_interface-rust",
-        "compos_aidl_interface-rust",
-        "android.system.keystore2-V1-rust",
-        "android.hardware.security.keymint-V1-rust",
-        "libandroid_logger",
-        "libanyhow",
-        "libbinder_rs",
-        "libbinder_rpc_unstable_bindgen",
-        "libclap",
-        "liblog_rust",
-        "libminijail_rust",
-        "libring",
-        "libscopeguard",
-    ],
-    prefer_rlib: true,
-    shared_libs: [
-        "libbinder_rpc_unstable",
-    ],
-    apex_available: ["com.android.compos"],
-}
diff --git a/compos/aidl/com/android/compos/ICompOsKeyService.aidl b/compos/aidl/com/android/compos/ICompOsKeyService.aidl
deleted file mode 100644
index 7e0fe25..0000000
--- a/compos/aidl/com/android/compos/ICompOsKeyService.aidl
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.compos;
-
-import com.android.compos.CompOsKeyData;
-import com.android.compos.ICompOsService;
-
-/** {@hide} */
-interface ICompOsKeyService {
-    /**
-     * Generate a new public/private key pair suitable for signing CompOs output files.
-     *
-     * @return a certificate for the public key and the encrypted private key
-     */
-    CompOsKeyData generateSigningKey();
-
-    /**
-     * Check that the supplied encrypted private key is valid for signing CompOs output files, and
-     * corresponds to the public key.
-     *
-     * @param keyBlob The encrypted blob containing the private key, as returned by
-     *                generateSigningKey().
-     * @param publicKey The public key, as a DER encoded RSAPublicKey (RFC 3447 Appendix-A.1.1).
-     * @return whether the inputs are valid and correspond to each other.
-     */
-    boolean verifySigningKey(in byte[] keyBlob, in byte[] publicKey);
-
-    /**
-     * Use the supplied encrypted private key to sign some data.
-     *
-     * @param keyBlob The encrypted blob containing the private key, as returned by
-     *                generateSigningKey().
-     * @param data The data to be signed. (Large data sizes may cause failure.)
-     * @return the signature.
-     */
-    // STOPSHIP(b/193241041): We must not expose this from the PVM.
-    byte[] sign(in byte[] keyBlob, in byte[] data);
-
-    /**
-     * Return an instance of ICompOsService that will sign output files with a given encrypted
-     * private key.
-     *
-     * @param keyBlob The encrypted blob containing the private key, as returned by
-     *                generateSigningKey().
-     */
-    ICompOsService getCompOsService(in byte[] keyBlob);
-}
diff --git a/compos/aidl/com/android/compos/ICompOsService.aidl b/compos/aidl/com/android/compos/ICompOsService.aidl
index c9cd9ae..ec4f0f6 100644
--- a/compos/aidl/com/android/compos/ICompOsService.aidl
+++ b/compos/aidl/com/android/compos/ICompOsService.aidl
@@ -16,6 +16,7 @@
 
 package com.android.compos;
 
+import com.android.compos.CompOsKeyData;
 import com.android.compos.Metadata;
 
 /** {@hide} */
@@ -32,4 +33,33 @@
      * @return exit code of the program
      */
     byte execute(in String[] args, in Metadata metadata);
+
+    /**
+     * Generate a new public/private key pair suitable for signing CompOs output files.
+     *
+     * @return a certificate for the public key and the encrypted private key
+     */
+    CompOsKeyData generateSigningKey();
+
+    /**
+     * Check that the supplied encrypted private key is valid for signing CompOs output files, and
+     * corresponds to the public key.
+     *
+     * @param keyBlob The encrypted blob containing the private key, as returned by
+     *                generateSigningKey().
+     * @param publicKey The public key, as a DER encoded RSAPublicKey (RFC 3447 Appendix-A.1.1).
+     * @return whether the inputs are valid and correspond to each other.
+     */
+    boolean verifySigningKey(in byte[] keyBlob, in byte[] publicKey);
+
+    /**
+     * Use the supplied encrypted private key to sign some data.
+     *
+     * @param keyBlob The encrypted blob containing the private key, as returned by
+     *                generateSigningKey().
+     * @param data The data to be signed. (Large data sizes may cause failure.)
+     * @return the signature.
+     */
+    // STOPSHIP(b/193241041): We must not expose this from the PVM.
+    byte[] sign(in byte[] keyBlob, in byte[] data);
 }
diff --git a/compos/apex/Android.bp b/compos/apex/Android.bp
index 12d2f06..5b21802 100644
--- a/compos/apex/Android.bp
+++ b/compos/apex/Android.bp
@@ -39,7 +39,6 @@
 
     binaries: [
         "compos_key_cmd",
-        "compos_key_main",
         "compsvc",
         "pvm_exec",
     ],
diff --git a/compos/apk/assets/key_service_vm_config.json b/compos/apk/assets/key_service_vm_config.json
deleted file mode 100644
index 3b6b88c..0000000
--- a/compos/apk/assets/key_service_vm_config.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-    "version": 1,
-    "os": {
-        "name": "microdroid"
-    },
-    "task": {
-        "type": "executable",
-        "command": "/apex/com.android.compos/bin/compos_key_main",
-        "args": [
-            "--rpc-binder"
-        ]
-    },
-    "apexes": [
-        {
-            "name": "com.android.compos"
-        }
-    ]
-}
\ No newline at end of file
diff --git a/compos/compos_key_cmd/compos_key_cmd.cpp b/compos/compos_key_cmd/compos_key_cmd.cpp
index 84a0a7c..04ba1d0 100644
--- a/compos/compos_key_cmd/compos_key_cmd.cpp
+++ b/compos/compos_key_cmd/compos_key_cmd.cpp
@@ -16,7 +16,7 @@
 
 #include <aidl/android/system/virtualizationservice/BnVirtualMachineCallback.h>
 #include <aidl/android/system/virtualizationservice/IVirtualizationService.h>
-#include <aidl/com/android/compos/ICompOsKeyService.h>
+#include <aidl/com/android/compos/ICompOsService.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/result.h>
@@ -56,7 +56,7 @@
 using aidl::android::system::virtualizationservice::IVirtualMachineCallback;
 using aidl::android::system::virtualizationservice::VirtualMachineConfig;
 using aidl::com::android::compos::CompOsKeyData;
-using aidl::com::android::compos::ICompOsKeyService;
+using aidl::com::android::compos::ICompOsService;
 using android::base::ErrnoError;
 using android::base::Error;
 using android::base::Result;
@@ -66,7 +66,7 @@
 using ndk::ScopedFileDescriptor;
 using ndk::SharedRefBase;
 
-constexpr unsigned int kRpcPort = 3142;
+constexpr unsigned int kRpcPort = 6432;
 
 constexpr const char* kConfigApkPath =
         "/apex/com.android.compos/app/CompOSPayloadApp/CompOSPayloadApp.apk";
@@ -89,11 +89,11 @@
     return std::vector<uint8_t>(str.begin(), str.end());
 }
 
-static std::shared_ptr<ICompOsKeyService> getService(int cid) {
+static std::shared_ptr<ICompOsService> getService(int cid) {
     LOG(INFO) << "Connecting to cid " << cid;
     ndk::SpAIBinder binder(cid == 0 ? AServiceManager_getService("android.system.composkeyservice")
                                     : RpcClient(cid, kRpcPort));
-    return ICompOsKeyService::fromBinder(binder);
+    return ICompOsService::fromBinder(binder);
 }
 
 namespace {
@@ -337,7 +337,7 @@
     return result;
 }
 
-static Result<void> signFile(ICompOsKeyService* service, const std::vector<uint8_t>& key_blob,
+static Result<void> signFile(ICompOsService* service, const std::vector<uint8_t>& key_blob,
                              const std::string& file) {
     unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC)));
     if (!fd.ok()) {
diff --git a/compos/src/compos_key_main.rs b/compos/src/compos_key_main.rs
deleted file mode 100644
index ea5005d..0000000
--- a/compos/src/compos_key_main.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2021, The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! Run the CompOS key management service, either in the host using normal Binder or in the
-//! VM using RPC Binder.
-
-mod compilation;
-mod compos_key_service;
-mod compsvc;
-mod signer;
-
-use crate::compos_key_service::KeystoreNamespace;
-use anyhow::{bail, Context, Result};
-use binder::unstable_api::AsNative;
-use compos_aidl_interface::binder::{add_service, ProcessState};
-use log::{info, Level};
-
-const LOG_TAG: &str = "CompOsKeyService";
-const OUR_SERVICE_NAME: &str = "android.system.composkeyservice";
-const OUR_VSOCK_PORT: u32 = 3142;
-
-fn main() -> Result<()> {
-    android_logger::init_once(
-        android_logger::Config::default().with_tag(LOG_TAG).with_min_level(Level::Info),
-    );
-
-    let matches = clap::App::new("compos_key_main")
-        .arg(clap::Arg::with_name("rpc_binder").long("rpc-binder"))
-        .get_matches();
-
-    let rpc_binder = matches.is_present("rpc_binder");
-
-    let key_namespace =
-        if rpc_binder { KeystoreNamespace::VmPayload } else { KeystoreNamespace::Odsign };
-    let mut service = compos_key_service::new(key_namespace)?.as_binder();
-
-    if rpc_binder {
-        info!("Starting RPC service");
-        // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
-        // Plus the binder objects are threadsafe.
-        let retval = unsafe {
-            binder_rpc_unstable_bindgen::RunRpcServer(
-                service.as_native_mut() as *mut binder_rpc_unstable_bindgen::AIBinder,
-                OUR_VSOCK_PORT,
-            )
-        };
-        if retval {
-            info!("RPC server has shut down gracefully");
-        } else {
-            bail!("Premature termination of RPC server");
-        }
-    } else {
-        info!("Starting binder service");
-        add_service(OUR_SERVICE_NAME, service).context("Adding service failed")?;
-        info!("It's alive!");
-
-        ProcessState::join_thread_pool();
-    }
-
-    Ok(())
-}
diff --git a/compos/src/compos_key_service.rs b/compos/src/compos_key_service.rs
index dd28faa..92b04f2 100644
--- a/compos/src/compos_key_service.rs
+++ b/compos/src/compos_key_service.rs
@@ -16,8 +16,6 @@
 //! access to Keystore in the VM, but not persistent storage; instead the host stores the key
 //! on our behalf via this service.
 
-use crate::compsvc;
-use crate::signer::Signer;
 use android_hardware_security_keymint::aidl::android::hardware::security::keymint::{
     Algorithm::Algorithm, Digest::Digest, KeyParameter::KeyParameter,
     KeyParameterValue::KeyParameterValue, KeyPurpose::KeyPurpose, PaddingMode::PaddingMode,
@@ -27,20 +25,12 @@
     Domain::Domain, IKeystoreSecurityLevel::IKeystoreSecurityLevel,
     IKeystoreService::IKeystoreService, KeyDescriptor::KeyDescriptor,
 };
+use android_system_keystore2::binder::{wait_for_interface, Strong};
 use anyhow::{anyhow, Context, Result};
-use compos_aidl_interface::aidl::com::android::compos::{
-    CompOsKeyData::CompOsKeyData,
-    ICompOsKeyService::{BnCompOsKeyService, ICompOsKeyService},
-    ICompOsService::ICompOsService,
-};
-use compos_aidl_interface::binder::{
-    self, wait_for_interface, BinderFeatures, ExceptionCode, Interface, Status, Strong,
-};
-use log::warn;
+use compos_aidl_interface::aidl::com::android::compos::CompOsKeyData::CompOsKeyData;
 use ring::rand::{SecureRandom, SystemRandom};
 use ring::signature;
 use scopeguard::ScopeGuard;
-use std::ffi::CString;
 
 /// Keystore2 namespace IDs, used for access control to keys.
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -52,14 +42,6 @@
     VmPayload = 140,
 }
 
-/// Constructs a binder object that implements ICompOsKeyService. namespace is the Keystore2 namespace to
-/// use for the keys.
-#[allow(dead_code)] // for compsvc
-pub fn new(namespace: KeystoreNamespace) -> Result<Strong<dyn ICompOsKeyService>> {
-    let service = CompOsKeyService::new(namespace)?;
-    Ok(BnCompOsKeyService::new_binder(service, BinderFeatures::default()))
-}
-
 const KEYSTORE_SERVICE_NAME: &str = "android.system.keystore2.IKeystoreService/default";
 const PURPOSE_SIGN: KeyParameter =
     KeyParameter { tag: Tag::PURPOSE, value: KeyParameterValue::KeyPurpose(KeyPurpose::SIGN) };
@@ -89,58 +71,13 @@
     security_level: Strong<dyn IKeystoreSecurityLevel>,
 }
 
-impl Interface for CompOsKeyService {}
-
-impl ICompOsKeyService for CompOsKeyService {
-    fn generateSigningKey(&self) -> binder::Result<CompOsKeyData> {
-        self.do_generate()
-            .map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_STATE, e.to_string()))
-    }
-
-    fn verifySigningKey(&self, key_blob: &[u8], public_key: &[u8]) -> binder::Result<bool> {
-        Ok(if let Err(e) = self.do_verify(key_blob, public_key) {
-            warn!("Signing key verification failed: {}", e.to_string());
-            false
-        } else {
-            true
-        })
-    }
-
-    fn sign(&self, key_blob: &[u8], data: &[u8]) -> binder::Result<Vec<u8>> {
-        self.do_sign(key_blob, data)
-            .map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_STATE, e.to_string()))
-    }
-
-    fn getCompOsService(&self, key_blob: &[u8]) -> binder::Result<Strong<dyn ICompOsService>> {
-        let signer =
-            Box::new(CompOsSigner { key_blob: key_blob.to_owned(), key_service: self.clone() });
-        let rpc_binder = true; // don't care
-        compsvc::new_binder(rpc_binder, Some(signer))
-            .map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_STATE, e.to_string()))
-    }
-}
-
-/// Constructs a new Binder error `Status` with the given `ExceptionCode` and message.
-fn new_binder_exception<T: AsRef<str>>(exception: ExceptionCode, message: T) -> Status {
-    Status::new_exception(exception, CString::new(message.as_ref()).ok().as_deref())
-}
-
-struct CompOsSigner {
-    key_blob: Vec<u8>,
-    key_service: CompOsKeyService,
-}
-
-impl Signer for CompOsSigner {
-    fn sign(&self, data: &[u8]) -> Result<Vec<u8>> {
-        self.key_service.do_sign(&self.key_blob, data)
-    }
-}
-
 impl CompOsKeyService {
-    pub fn new(namespace: KeystoreNamespace) -> Result<Self> {
+    pub fn new(rpc_binder: bool) -> Result<Self> {
         let keystore_service = wait_for_interface::<dyn IKeystoreService>(KEYSTORE_SERVICE_NAME)
             .context("No Keystore service")?;
 
+        let namespace =
+            if rpc_binder { KeystoreNamespace::VmPayload } else { KeystoreNamespace::Odsign };
         Ok(CompOsKeyService {
             namespace,
             random: SystemRandom::new(),
@@ -150,7 +87,7 @@
         })
     }
 
-    fn do_generate(&self) -> Result<CompOsKeyData> {
+    pub fn do_generate(&self) -> Result<CompOsKeyData> {
         let key_descriptor = KeyDescriptor { nspace: self.namespace as i64, ..BLOB_KEY_DESCRIPTOR };
         let key_parameters =
             [PURPOSE_SIGN, ALGORITHM, PADDING, DIGEST, KEY_SIZE, EXPONENT, NO_AUTH_REQUIRED];
@@ -170,7 +107,7 @@
         }
     }
 
-    fn do_verify(&self, key_blob: &[u8], public_key: &[u8]) -> Result<()> {
+    pub fn do_verify(&self, key_blob: &[u8], public_key: &[u8]) -> Result<()> {
         let mut data = [0u8; 32];
         self.random.fill(&mut data).context("No random data")?;
 
@@ -183,7 +120,7 @@
         Ok(())
     }
 
-    fn do_sign(&self, key_blob: &[u8], data: &[u8]) -> Result<Vec<u8>> {
+    pub fn do_sign(&self, key_blob: &[u8], data: &[u8]) -> Result<Vec<u8>> {
         let key_descriptor = KeyDescriptor {
             nspace: self.namespace as i64,
             blob: Some(key_blob.to_vec()),
diff --git a/compos/src/compsvc.rs b/compos/src/compsvc.rs
index b69b053..b5edd98 100644
--- a/compos/src/compsvc.rs
+++ b/compos/src/compsvc.rs
@@ -19,17 +19,18 @@
 //! actual compiler.
 
 use anyhow::Result;
+use log::warn;
 use std::ffi::CString;
 use std::path::PathBuf;
 
 use crate::compilation::compile;
-use crate::compos_key_service::{CompOsKeyService, KeystoreNamespace};
-use crate::signer::Signer;
+use crate::compos_key_service::CompOsKeyService;
 use authfs_aidl_interface::aidl::com::android::virt::fs::IAuthFsService::IAuthFsService;
-use compos_aidl_interface::aidl::com::android::compos::ICompOsService::{
-    BnCompOsService, ICompOsService,
+use compos_aidl_interface::aidl::com::android::compos::{
+    CompOsKeyData::CompOsKeyData,
+    ICompOsService::{BnCompOsService, ICompOsService},
+    Metadata::Metadata,
 };
-use compos_aidl_interface::aidl::com::android::compos::Metadata::Metadata;
 use compos_aidl_interface::binder::{
     BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Status, Strong,
 };
@@ -38,23 +39,16 @@
 const DEX2OAT_PATH: &str = "/apex/com.android.art/bin/dex2oat64";
 
 /// Constructs a binder object that implements ICompOsService.
-pub fn new_binder(
-    rpc_binder: bool,
-    signer: Option<Box<dyn Signer>>,
-) -> Result<Strong<dyn ICompOsService>> {
-    let namespace =
-        if rpc_binder { KeystoreNamespace::VmPayload } else { KeystoreNamespace::Odsign };
-    let key_service = CompOsKeyService::new(namespace)?;
-
-    let service = CompOsService { dex2oat_path: PathBuf::from(DEX2OAT_PATH), signer, key_service };
+pub fn new_binder(rpc_binder: bool) -> Result<Strong<dyn ICompOsService>> {
+    let service = CompOsService {
+        dex2oat_path: PathBuf::from(DEX2OAT_PATH),
+        key_service: CompOsKeyService::new(rpc_binder)?,
+    };
     Ok(BnCompOsService::new_binder(service, BinderFeatures::default()))
 }
 
 struct CompOsService {
     dex2oat_path: PathBuf,
-    #[allow(dead_code)] // TODO: Make use of this
-    signer: Option<Box<dyn Signer>>,
-    #[allow(dead_code)] // TODO: Make use of this
     key_service: CompOsKeyService,
 }
 
@@ -70,6 +64,27 @@
             )
         })
     }
+
+    fn generateSigningKey(&self) -> BinderResult<CompOsKeyData> {
+        self.key_service
+            .do_generate()
+            .map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_STATE, e.to_string()))
+    }
+
+    fn verifySigningKey(&self, key_blob: &[u8], public_key: &[u8]) -> BinderResult<bool> {
+        Ok(if let Err(e) = self.key_service.do_verify(key_blob, public_key) {
+            warn!("Signing key verification failed: {}", e.to_string());
+            false
+        } else {
+            true
+        })
+    }
+
+    fn sign(&self, key_blob: &[u8], data: &[u8]) -> BinderResult<Vec<u8>> {
+        self.key_service
+            .do_sign(key_blob, data)
+            .map_err(|e| new_binder_exception(ExceptionCode::ILLEGAL_STATE, e.to_string()))
+    }
 }
 
 fn get_authfs_service() -> BinderResult<Strong<dyn IAuthFsService>> {
diff --git a/compos/src/compsvc_main.rs b/compos/src/compsvc_main.rs
index 5c5da22..48e37b6 100644
--- a/compos/src/compsvc_main.rs
+++ b/compos/src/compsvc_main.rs
@@ -49,7 +49,7 @@
     );
 
     let config = parse_args()?;
-    let mut service = compsvc::new_binder(config.rpc_binder, /* signer */ None)?.as_binder();
+    let mut service = compsvc::new_binder(config.rpc_binder)?.as_binder();
     if config.rpc_binder {
         debug!("compsvc is starting as a rpc service.");
         // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
diff --git a/compos/tests/java/android/compos/test/ComposKeyTestCase.java b/compos/tests/java/android/compos/test/ComposKeyTestCase.java
index 654dc0b..6ef82f7 100644
--- a/compos/tests/java/android/compos/test/ComposKeyTestCase.java
+++ b/compos/tests/java/android/compos/test/ComposKeyTestCase.java
@@ -131,7 +131,7 @@
                         getBuild(),
                         apkName,
                         packageName,
-                        "assets/key_service_vm_config.json",
+                        "assets/vm_config.json",
                         /* debug */ true);
         adbConnectToMicrodroid(getDevice(), mCid);
     }
@@ -145,6 +145,6 @@
     }
 
     private boolean isServiceRunning() {
-        return tryRunOnMicrodroid("pidof compos_key_main") != null;
+        return tryRunOnMicrodroid("pidof compsvc") != null;
     }
 }