Add a remote keymint HAL.

Based on files from here:
https://android.googlesource.com/platform/system/keymaster/+/5592969/ng/
https://android.googlesource.com/platform/hardware/interfaces/+/8bfd260/security/keymint/aidl/default/
https://android.googlesource.com/device/google/cuttlefish/+/8577c21/guest/hals/keymaster/remote/

The keymint code is copied over with s/AndroidKeymaster/RemoteKeymaster/
and the RemoteKeymaster code is copied from the Keymaster 4.1
implementation.

Bug: 182928606
Test: m android.hardware.security.keymint-service.remote
Change-Id: If99b44eac253447637d3682cec3d13d7750d3c5b
diff --git a/guest/hals/keymint/OWNERS b/guest/hals/keymint/OWNERS
new file mode 100644
index 0000000..fb015cb
--- /dev/null
+++ b/guest/hals/keymint/OWNERS
@@ -0,0 +1 @@
+include platform/system/keymaster:/OWNERS
diff --git a/guest/hals/keymint/remote/Android.bp b/guest/hals/keymint/remote/Android.bp
new file mode 100644
index 0000000..59c73a4
--- /dev/null
+++ b/guest/hals/keymint/remote/Android.bp
@@ -0,0 +1,56 @@
+//
+// Copyright (C) 2020 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.
+
+cc_binary {
+    name: "android.hardware.security.keymint-service.remote",
+    relative_install_path: "hw",
+    init_rc: ["android.hardware.security.keymint-service.remote.rc"],
+    vintf_fragments: [
+        "android.hardware.security.keymint-service.remote.xml",
+        "android.hardware.security.sharedsecret-service.remote.xml",
+        "android.hardware.security.secureclock-service.remote.xml",
+    ],
+    vendor: true,
+    cflags: [
+        "-Wall",
+        "-Wextra",
+    ],
+    shared_libs: [
+        "android.hardware.security.keymint-V1-ndk_platform",
+        "android.hardware.security.sharedsecret-V1-ndk_platform",
+        "android.hardware.security.secureclock-V1-ndk_platform",
+        "libbase",
+        "libbinder_ndk",
+        "libcppbor_external",
+        "libcrypto",
+        "libcuttlefish_fs",
+        "libcuttlefish_security",
+        "libhardware",
+        "libkeymint",
+        "libkeymaster_messages",
+        "liblog",
+        "libutils",
+    ],
+    srcs: [
+        "remote_keymint_device.cpp",
+        "remote_keymint_operation.cpp",
+        "remote_keymaster.cpp",
+        "remote_secure_clock.cpp",
+        "service.cpp",
+    ],
+    defaults: [
+        "cuttlefish_guest_only",
+    ],
+}
diff --git a/guest/hals/keymint/remote/android.hardware.security.keymint-service.remote.rc b/guest/hals/keymint/remote/android.hardware.security.keymint-service.remote.rc
new file mode 100644
index 0000000..422fe17
--- /dev/null
+++ b/guest/hals/keymint/remote/android.hardware.security.keymint-service.remote.rc
@@ -0,0 +1,3 @@
+service vendor.keymint-remote /vendor/bin/hw/android.hardware.security.keymint-service.remote
+    class early_hal
+    user nobody
diff --git a/guest/hals/keymint/remote/android.hardware.security.keymint-service.remote.xml b/guest/hals/keymint/remote/android.hardware.security.keymint-service.remote.xml
new file mode 100644
index 0000000..4aa05ef
--- /dev/null
+++ b/guest/hals/keymint/remote/android.hardware.security.keymint-service.remote.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.security.keymint</name>
+        <fqname>IKeyMintDevice/default</fqname>
+    </hal>
+    <hal format="aidl">
+        <name>android.hardware.security.keymint</name>
+        <fqname>IRemotelyProvisionedComponent/default</fqname>
+    </hal>
+</manifest>
diff --git a/guest/hals/keymint/remote/android.hardware.security.secureclock-service.remote.xml b/guest/hals/keymint/remote/android.hardware.security.secureclock-service.remote.xml
new file mode 100644
index 0000000..c0ff775
--- /dev/null
+++ b/guest/hals/keymint/remote/android.hardware.security.secureclock-service.remote.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.security.secureclock</name>
+        <fqname>ISecureClock/default</fqname>
+    </hal>
+</manifest>
diff --git a/guest/hals/keymint/remote/android.hardware.security.sharedsecret-service.remote.xml b/guest/hals/keymint/remote/android.hardware.security.sharedsecret-service.remote.xml
new file mode 100644
index 0000000..d37981f
--- /dev/null
+++ b/guest/hals/keymint/remote/android.hardware.security.sharedsecret-service.remote.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.security.sharedsecret</name>
+        <fqname>ISharedSecret/default</fqname>
+    </hal>
+</manifest>
diff --git a/guest/hals/keymint/remote/remote_keymaster.cpp b/guest/hals/keymint/remote/remote_keymaster.cpp
new file mode 100644
index 0000000..4a37cf0
--- /dev/null
+++ b/guest/hals/keymint/remote/remote_keymaster.cpp
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#include "remote_keymaster.h"
+
+#include <android-base/logging.h>
+#include <keymaster/android_keymaster_messages.h>
+#include <keymaster/keymaster_configuration.h>
+
+namespace keymaster {
+
+RemoteKeymaster::RemoteKeymaster(cuttlefish::KeymasterChannel* channel)
+    : channel_(channel) {}
+
+RemoteKeymaster::~RemoteKeymaster() {}
+
+void RemoteKeymaster::ForwardCommand(AndroidKeymasterCommand command,
+                                     const Serializable& req,
+                                     KeymasterResponse* rsp) {
+  if (!channel_->SendRequest(command, req)) {
+    LOG(ERROR) << "Failed to send keymaster message: " << command;
+    rsp->error = KM_ERROR_UNKNOWN_ERROR;
+    return;
+  }
+  auto response = channel_->ReceiveMessage();
+  if (!response) {
+    LOG(ERROR) << "Failed to receive keymaster response: " << command;
+    rsp->error = KM_ERROR_UNKNOWN_ERROR;
+    return;
+  }
+  const uint8_t* buffer = response->payload;
+  const uint8_t* buffer_end = response->payload + response->payload_size;
+  if (!rsp->Deserialize(&buffer, buffer_end)) {
+    LOG(ERROR) << "Failed to deserialize keymaster response: " << command;
+    rsp->error = KM_ERROR_UNKNOWN_ERROR;
+    return;
+  }
+}
+
+bool RemoteKeymaster::Initialize() {
+  // We don't need to bother with GetVersion, because CF HAL and remote sides
+  // are always compiled together, so will never disagree about message
+  // versions.
+  ConfigureRequest req(message_version());
+  req.os_version = GetOsVersion();
+  req.os_patchlevel = GetOsPatchlevel();
+
+  ConfigureResponse rsp(message_version());
+  Configure(req, &rsp);
+
+  if (rsp.error != KM_ERROR_OK) {
+    LOG(ERROR) << "Failed to configure keymaster: " << rsp.error;
+    return false;
+  }
+
+  return true;
+}
+
+void RemoteKeymaster::GetVersion(const GetVersionRequest& request,
+                                 GetVersionResponse* response) {
+  ForwardCommand(GET_VERSION, request, response);
+}
+
+void RemoteKeymaster::SupportedAlgorithms(
+    const SupportedAlgorithmsRequest& request,
+    SupportedAlgorithmsResponse* response) {
+  ForwardCommand(GET_SUPPORTED_ALGORITHMS, request, response);
+}
+
+void RemoteKeymaster::SupportedBlockModes(
+    const SupportedBlockModesRequest& request,
+    SupportedBlockModesResponse* response) {
+  ForwardCommand(GET_SUPPORTED_BLOCK_MODES, request, response);
+}
+
+void RemoteKeymaster::SupportedPaddingModes(
+    const SupportedPaddingModesRequest& request,
+    SupportedPaddingModesResponse* response) {
+  ForwardCommand(GET_SUPPORTED_PADDING_MODES, request, response);
+}
+
+void RemoteKeymaster::SupportedDigests(const SupportedDigestsRequest& request,
+                                       SupportedDigestsResponse* response) {
+  ForwardCommand(GET_SUPPORTED_DIGESTS, request, response);
+}
+
+void RemoteKeymaster::SupportedImportFormats(
+    const SupportedImportFormatsRequest& request,
+    SupportedImportFormatsResponse* response) {
+  ForwardCommand(GET_SUPPORTED_IMPORT_FORMATS, request, response);
+}
+
+void RemoteKeymaster::SupportedExportFormats(
+    const SupportedExportFormatsRequest& request,
+    SupportedExportFormatsResponse* response) {
+  ForwardCommand(GET_SUPPORTED_EXPORT_FORMATS, request, response);
+}
+
+void RemoteKeymaster::AddRngEntropy(const AddEntropyRequest& request,
+                                    AddEntropyResponse* response) {
+  ForwardCommand(ADD_RNG_ENTROPY, request, response);
+}
+
+void RemoteKeymaster::Configure(const ConfigureRequest& request,
+                                ConfigureResponse* response) {
+  ForwardCommand(CONFIGURE, request, response);
+}
+
+void RemoteKeymaster::GenerateKey(const GenerateKeyRequest& request,
+                                  GenerateKeyResponse* response) {
+  GenerateKeyRequest datedRequest(request.message_version);
+  datedRequest.key_description = request.key_description;
+
+  if (!request.key_description.Contains(TAG_CREATION_DATETIME)) {
+    datedRequest.key_description.push_back(TAG_CREATION_DATETIME,
+                                           java_time(time(NULL)));
+  }
+
+  ForwardCommand(GENERATE_KEY, datedRequest, response);
+}
+
+void RemoteKeymaster::GetKeyCharacteristics(
+    const GetKeyCharacteristicsRequest& request,
+    GetKeyCharacteristicsResponse* response) {
+  ForwardCommand(GET_KEY_CHARACTERISTICS, request, response);
+}
+
+void RemoteKeymaster::ImportKey(const ImportKeyRequest& request,
+                                ImportKeyResponse* response) {
+  ForwardCommand(IMPORT_KEY, request, response);
+}
+
+void RemoteKeymaster::ImportWrappedKey(const ImportWrappedKeyRequest& request,
+                                       ImportWrappedKeyResponse* response) {
+  ForwardCommand(IMPORT_WRAPPED_KEY, request, response);
+}
+
+void RemoteKeymaster::ExportKey(const ExportKeyRequest& request,
+                                ExportKeyResponse* response) {
+  ForwardCommand(EXPORT_KEY, request, response);
+}
+
+void RemoteKeymaster::AttestKey(const AttestKeyRequest& request,
+                                AttestKeyResponse* response) {
+  ForwardCommand(ATTEST_KEY, request, response);
+}
+
+void RemoteKeymaster::UpgradeKey(const UpgradeKeyRequest& request,
+                                 UpgradeKeyResponse* response) {
+  ForwardCommand(UPGRADE_KEY, request, response);
+}
+
+void RemoteKeymaster::DeleteKey(const DeleteKeyRequest& request,
+                                DeleteKeyResponse* response) {
+  ForwardCommand(DELETE_KEY, request, response);
+}
+
+void RemoteKeymaster::DeleteAllKeys(const DeleteAllKeysRequest& request,
+                                    DeleteAllKeysResponse* response) {
+  ForwardCommand(DELETE_ALL_KEYS, request, response);
+}
+
+void RemoteKeymaster::BeginOperation(const BeginOperationRequest& request,
+                                     BeginOperationResponse* response) {
+  ForwardCommand(BEGIN_OPERATION, request, response);
+}
+
+void RemoteKeymaster::UpdateOperation(const UpdateOperationRequest& request,
+                                      UpdateOperationResponse* response) {
+  ForwardCommand(UPDATE_OPERATION, request, response);
+}
+
+void RemoteKeymaster::FinishOperation(const FinishOperationRequest& request,
+                                      FinishOperationResponse* response) {
+  ForwardCommand(FINISH_OPERATION, request, response);
+}
+
+void RemoteKeymaster::AbortOperation(const AbortOperationRequest& request,
+                                     AbortOperationResponse* response) {
+  ForwardCommand(ABORT_OPERATION, request, response);
+}
+
+GetHmacSharingParametersResponse RemoteKeymaster::GetHmacSharingParameters() {
+  // Unused empty buffer to allow ForwardCommand to have something to serialize
+  Buffer request;
+  GetHmacSharingParametersResponse response(message_version());
+  ForwardCommand(GET_HMAC_SHARING_PARAMETERS, request, &response);
+  return response;
+}
+
+ComputeSharedHmacResponse RemoteKeymaster::ComputeSharedHmac(
+    const ComputeSharedHmacRequest& request) {
+  ComputeSharedHmacResponse response(message_version());
+  ForwardCommand(COMPUTE_SHARED_HMAC, request, &response);
+  return response;
+}
+
+VerifyAuthorizationResponse RemoteKeymaster::VerifyAuthorization(
+    const VerifyAuthorizationRequest& request) {
+  VerifyAuthorizationResponse response(message_version());
+  ForwardCommand(VERIFY_AUTHORIZATION, request, &response);
+  return response;
+}
+
+DeviceLockedResponse RemoteKeymaster::DeviceLocked(
+    const DeviceLockedRequest& request) {
+  DeviceLockedResponse response(message_version());
+  ForwardCommand(DEVICE_LOCKED, request, &response);
+  return response;
+}
+
+EarlyBootEndedResponse RemoteKeymaster::EarlyBootEnded() {
+  // Unused empty buffer to allow ForwardCommand to have something to serialize
+  Buffer request;
+  EarlyBootEndedResponse response(message_version());
+  ForwardCommand(EARLY_BOOT_ENDED, request, &response);
+  return response;
+}
+
+void RemoteKeymaster::GenerateTimestampToken(GenerateTimestampTokenRequest&,
+                                             GenerateTimestampTokenResponse*) {
+  // TODO(aosp/1641315): Send a message to the host.
+  // ForwardCommand(GENERATE_TIMESTAMP_TOKEN, request, response);
+}
+
+}  // namespace keymaster
diff --git a/guest/hals/keymint/remote/remote_keymaster.h b/guest/hals/keymint/remote/remote_keymaster.h
new file mode 100644
index 0000000..6cc6c7b
--- /dev/null
+++ b/guest/hals/keymint/remote/remote_keymaster.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#ifndef REMOTE_KEYMASTER_H_
+#define REMOTE_KEYMASTER_H_
+
+#include <keymaster/android_keymaster_messages.h>
+
+#include "common/libs/security/keymaster_channel.h"
+
+namespace keymaster {
+
+class RemoteKeymaster {
+ private:
+  cuttlefish::KeymasterChannel* channel_;
+
+  void ForwardCommand(AndroidKeymasterCommand command, const Serializable& req,
+                      KeymasterResponse* rsp);
+
+ public:
+  RemoteKeymaster(cuttlefish::KeymasterChannel*);
+  ~RemoteKeymaster();
+  bool Initialize();
+  void GetVersion(const GetVersionRequest& request,
+                  GetVersionResponse* response);
+  void SupportedAlgorithms(const SupportedAlgorithmsRequest& request,
+                           SupportedAlgorithmsResponse* response);
+  void SupportedBlockModes(const SupportedBlockModesRequest& request,
+                           SupportedBlockModesResponse* response);
+  void SupportedPaddingModes(const SupportedPaddingModesRequest& request,
+                             SupportedPaddingModesResponse* response);
+  void SupportedDigests(const SupportedDigestsRequest& request,
+                        SupportedDigestsResponse* response);
+  void SupportedImportFormats(const SupportedImportFormatsRequest& request,
+                              SupportedImportFormatsResponse* response);
+  void SupportedExportFormats(const SupportedExportFormatsRequest& request,
+                              SupportedExportFormatsResponse* response);
+  void AddRngEntropy(const AddEntropyRequest& request,
+                     AddEntropyResponse* response);
+  void Configure(const ConfigureRequest& request, ConfigureResponse* response);
+  void GenerateKey(const GenerateKeyRequest& request,
+                   GenerateKeyResponse* response);
+  void GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
+                             GetKeyCharacteristicsResponse* response);
+  void ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response);
+  void ImportWrappedKey(const ImportWrappedKeyRequest& request,
+                        ImportWrappedKeyResponse* response);
+  void ExportKey(const ExportKeyRequest& request, ExportKeyResponse* response);
+  void AttestKey(const AttestKeyRequest& request, AttestKeyResponse* response);
+  void UpgradeKey(const UpgradeKeyRequest& request,
+                  UpgradeKeyResponse* response);
+  void DeleteKey(const DeleteKeyRequest& request, DeleteKeyResponse* response);
+  void DeleteAllKeys(const DeleteAllKeysRequest& request,
+                     DeleteAllKeysResponse* response);
+  void BeginOperation(const BeginOperationRequest& request,
+                      BeginOperationResponse* response);
+  void UpdateOperation(const UpdateOperationRequest& request,
+                       UpdateOperationResponse* response);
+  void FinishOperation(const FinishOperationRequest& request,
+                       FinishOperationResponse* response);
+  void AbortOperation(const AbortOperationRequest& request,
+                      AbortOperationResponse* response);
+  GetHmacSharingParametersResponse GetHmacSharingParameters();
+  ComputeSharedHmacResponse ComputeSharedHmac(
+      const ComputeSharedHmacRequest& request);
+  VerifyAuthorizationResponse VerifyAuthorization(
+      const VerifyAuthorizationRequest& request);
+  DeviceLockedResponse DeviceLocked(const DeviceLockedRequest& request);
+  EarlyBootEndedResponse EarlyBootEnded();
+  void GenerateTimestampToken(GenerateTimestampTokenRequest& request,
+                              GenerateTimestampTokenResponse* response);
+
+  // CF HAL and remote sides are always compiled together, so will never
+  // disagree about message versions.
+  uint32_t message_version() { return kDefaultMessageVersion; }
+};
+
+}  // namespace keymaster
+
+#endif  // REMOTE_KEYMASTER_H_
diff --git a/guest/hals/keymint/remote/remote_keymint_device.cpp b/guest/hals/keymint/remote/remote_keymint_device.cpp
new file mode 100644
index 0000000..fbf2568
--- /dev/null
+++ b/guest/hals/keymint/remote/remote_keymint_device.cpp
@@ -0,0 +1,415 @@
+/*
+ * Copyright 2020, 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.
+ */
+
+#define LOG_TAG "android.hardware.security.keymint-impl"
+#include <android-base/logging.h>
+
+#include "guest/hals/keymint/remote/remote_keymint_device.h"
+
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+
+#include <keymaster/android_keymaster.h>
+#include <keymaster/contexts/pure_soft_keymaster_context.h>
+#include <keymaster/keymaster_configuration.h>
+
+#include "KeyMintUtils.h"
+#include "guest/hals/keymint/remote/remote_keymint_operation.h"
+
+namespace aidl::android::hardware::security::keymint {
+
+using namespace ::keymaster;
+using namespace km_utils;
+using secureclock::TimeStampToken;
+
+namespace {
+
+vector<KeyCharacteristics> convertKeyCharacteristics(
+    SecurityLevel keyMintSecurityLevel, const AuthorizationSet& sw_enforced,
+    const AuthorizationSet& hw_enforced) {
+  KeyCharacteristics keyMintEnforced{keyMintSecurityLevel, {}};
+
+  if (keyMintSecurityLevel != SecurityLevel::SOFTWARE) {
+    // We're pretending to be TRUSTED_ENVIRONMENT or STRONGBOX.
+    keyMintEnforced.authorizations = kmParamSet2Aidl(hw_enforced);
+    // Put all the software authorizations in the keystore list.
+    KeyCharacteristics keystoreEnforced{SecurityLevel::KEYSTORE,
+                                        kmParamSet2Aidl(sw_enforced)};
+    return {std::move(keyMintEnforced), std::move(keystoreEnforced)};
+  }
+
+  KeyCharacteristics keystoreEnforced{SecurityLevel::KEYSTORE, {}};
+  CHECK(hw_enforced.empty())
+      << "Hardware-enforced list is non-empty for pure SW KeyMint";
+
+  // This is a pure software implementation, so all tags are in sw_enforced.
+  // We need to walk through the SW-enforced list and figure out which tags to
+  // return in the software list and which in the keystore list.
+
+  for (auto& entry : sw_enforced) {
+    switch (entry.tag) {
+      /* Invalid and unused */
+      case KM_TAG_ECIES_SINGLE_HASH_MODE:
+      case KM_TAG_INVALID:
+      case KM_TAG_KDF:
+      case KM_TAG_ROLLBACK_RESISTANCE:
+        CHECK(false) << "We shouldn't see tag " << entry.tag;
+        break;
+
+      /* Unimplemented */
+      case KM_TAG_ALLOW_WHILE_ON_BODY:
+      case KM_TAG_BOOTLOADER_ONLY:
+      case KM_TAG_EARLY_BOOT_ONLY:
+      case KM_TAG_ROLLBACK_RESISTANT:
+      case KM_TAG_STORAGE_KEY:
+      case KM_TAG_TRUSTED_CONFIRMATION_REQUIRED:
+      case KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED:
+        break;
+
+      /* Unenforceable */
+      case KM_TAG_CREATION_DATETIME:
+        break;
+
+      /* Disallowed in KeyCharacteristics */
+      case KM_TAG_APPLICATION_DATA:
+      case KM_TAG_ATTESTATION_APPLICATION_ID:
+        break;
+
+      /* Not key characteristics */
+      case KM_TAG_ASSOCIATED_DATA:
+      case KM_TAG_ATTESTATION_CHALLENGE:
+      case KM_TAG_ATTESTATION_ID_BRAND:
+      case KM_TAG_ATTESTATION_ID_DEVICE:
+      case KM_TAG_ATTESTATION_ID_IMEI:
+      case KM_TAG_ATTESTATION_ID_MANUFACTURER:
+      case KM_TAG_ATTESTATION_ID_MEID:
+      case KM_TAG_ATTESTATION_ID_MODEL:
+      case KM_TAG_ATTESTATION_ID_PRODUCT:
+      case KM_TAG_ATTESTATION_ID_SERIAL:
+      case KM_TAG_AUTH_TOKEN:
+      case KM_TAG_CERTIFICATE_SERIAL:
+      case KM_TAG_CERTIFICATE_SUBJECT:
+      case KM_TAG_CERTIFICATE_NOT_AFTER:
+      case KM_TAG_CERTIFICATE_NOT_BEFORE:
+      case KM_TAG_CONFIRMATION_TOKEN:
+      case KM_TAG_DEVICE_UNIQUE_ATTESTATION:
+      case KM_TAG_IDENTITY_CREDENTIAL_KEY:
+      case KM_TAG_MAC_LENGTH:
+      case KM_TAG_NONCE:
+      case KM_TAG_RESET_SINCE_ID_ROTATION:
+      case KM_TAG_ROOT_OF_TRUST:
+      case KM_TAG_UNIQUE_ID:
+        break;
+
+      /* KeyMint-enforced */
+      case KM_TAG_ALGORITHM:
+      case KM_TAG_APPLICATION_ID:
+      case KM_TAG_AUTH_TIMEOUT:
+      case KM_TAG_BLOB_USAGE_REQUIREMENTS:
+      case KM_TAG_BLOCK_MODE:
+      case KM_TAG_BOOT_PATCHLEVEL:
+      case KM_TAG_CALLER_NONCE:
+      case KM_TAG_DIGEST:
+      case KM_TAG_EC_CURVE:
+      case KM_TAG_EXPORTABLE:
+      case KM_TAG_INCLUDE_UNIQUE_ID:
+      case KM_TAG_KEY_SIZE:
+      case KM_TAG_MAX_USES_PER_BOOT:
+      case KM_TAG_MIN_MAC_LENGTH:
+      case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
+      case KM_TAG_NO_AUTH_REQUIRED:
+      case KM_TAG_ORIGIN:
+      case KM_TAG_OS_PATCHLEVEL:
+      case KM_TAG_OS_VERSION:
+      case KM_TAG_PADDING:
+      case KM_TAG_PURPOSE:
+      case KM_TAG_RSA_OAEP_MGF_DIGEST:
+      case KM_TAG_RSA_PUBLIC_EXPONENT:
+      case KM_TAG_UNLOCKED_DEVICE_REQUIRED:
+      case KM_TAG_USER_AUTH_TYPE:
+      case KM_TAG_USER_SECURE_ID:
+      case KM_TAG_VENDOR_PATCHLEVEL:
+        keyMintEnforced.authorizations.push_back(kmParam2Aidl(entry));
+        break;
+
+      /* Keystore-enforced */
+      case KM_TAG_ACTIVE_DATETIME:
+      case KM_TAG_ALL_APPLICATIONS:
+      case KM_TAG_ALL_USERS:
+      case KM_TAG_MAX_BOOT_LEVEL:
+      case KM_TAG_ORIGINATION_EXPIRE_DATETIME:
+      case KM_TAG_USAGE_EXPIRE_DATETIME:
+      case KM_TAG_USER_ID:
+      case KM_TAG_USAGE_COUNT_LIMIT:
+        keystoreEnforced.authorizations.push_back(kmParam2Aidl(entry));
+        break;
+    }
+  }
+
+  vector<KeyCharacteristics> retval;
+  retval.reserve(2);
+  if (!keyMintEnforced.authorizations.empty())
+    retval.push_back(std::move(keyMintEnforced));
+  if (!keystoreEnforced.authorizations.empty())
+    retval.push_back(std::move(keystoreEnforced));
+
+  return retval;
+}
+
+Certificate convertCertificate(const keymaster_blob_t& cert) {
+  return {std::vector<uint8_t>(cert.data, cert.data + cert.data_length)};
+}
+
+vector<Certificate> convertCertificateChain(const CertificateChain& chain) {
+  vector<Certificate> retval;
+  retval.reserve(chain.entry_count);
+  std::transform(chain.begin(), chain.end(), std::back_inserter(retval),
+                 convertCertificate);
+  return retval;
+}
+
+}  // namespace
+
+RemoteKeyMintDevice::RemoteKeyMintDevice(::keymaster::RemoteKeymaster& impl,
+                                         SecurityLevel securityLevel)
+    : impl_(impl), securityLevel_(securityLevel) {}
+
+RemoteKeyMintDevice::~RemoteKeyMintDevice() {}
+
+ScopedAStatus RemoteKeyMintDevice::getHardwareInfo(KeyMintHardwareInfo* info) {
+  info->versionNumber = 1;
+  info->securityLevel = securityLevel_;
+  info->keyMintName = "RemoteKeyMintDevice";
+  info->keyMintAuthorName = "Google";
+  info->timestampTokenRequired = false;
+  return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteKeyMintDevice::addRngEntropy(const vector<uint8_t>& data) {
+  if (data.size() == 0) {
+    return ScopedAStatus::ok();
+  }
+
+  AddEntropyRequest request(impl_.message_version());
+  request.random_data.Reinitialize(data.data(), data.size());
+
+  AddEntropyResponse response(impl_.message_version());
+  impl_.AddRngEntropy(request, &response);
+
+  return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus RemoteKeyMintDevice::generateKey(
+    const vector<KeyParameter>& keyParams,
+    const optional<AttestationKey>& attestationKey,
+    KeyCreationResult* creationResult) {
+  GenerateKeyRequest request(impl_.message_version());
+  request.key_description.Reinitialize(KmParamSet(keyParams));
+  if (attestationKey) {
+    request.attestation_signing_key_blob = KeymasterKeyBlob(
+        attestationKey->keyBlob.data(), attestationKey->keyBlob.size());
+    request.attest_key_params.Reinitialize(
+        KmParamSet(attestationKey->attestKeyParams));
+    request.issuer_subject =
+        KeymasterBlob(attestationKey->issuerSubjectName.data(),
+                      attestationKey->issuerSubjectName.size());
+  }
+
+  GenerateKeyResponse response(impl_.message_version());
+  impl_.GenerateKey(request, &response);
+
+  if (response.error != KM_ERROR_OK) {
+    // Note a key difference between this current aidl and previous hal, is
+    // that hal returns void where as aidl returns the error status.  If
+    // aidl returns error, then aidl will not return any change you may make
+    // to the out parameters.  This is quite different from hal where all
+    // output variable can be modified due to hal returning void.
+    //
+    // So the caller need to be aware not to expect aidl functions to clear
+    // the output variables for you in case of error.  If you left some
+    // wrong data set in the out parameters, they will stay there.
+    return kmError2ScopedAStatus(response.error);
+  }
+
+  creationResult->keyBlob = kmBlob2vector(response.key_blob);
+  creationResult->keyCharacteristics = convertKeyCharacteristics(
+      securityLevel_, response.unenforced, response.enforced);
+  creationResult->certificateChain =
+      convertCertificateChain(response.certificate_chain);
+  return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteKeyMintDevice::importKey(
+    const vector<KeyParameter>& keyParams, KeyFormat keyFormat,
+    const vector<uint8_t>& keyData,
+    const optional<AttestationKey>& attestationKey,
+    KeyCreationResult* creationResult) {
+  ImportKeyRequest request(impl_.message_version());
+  request.key_description.Reinitialize(KmParamSet(keyParams));
+  request.key_format = legacy_enum_conversion(keyFormat);
+  request.key_data = KeymasterKeyBlob(keyData.data(), keyData.size());
+  if (attestationKey) {
+    request.attestation_signing_key_blob = KeymasterKeyBlob(
+        attestationKey->keyBlob.data(), attestationKey->keyBlob.size());
+    request.attest_key_params.Reinitialize(
+        KmParamSet(attestationKey->attestKeyParams));
+    request.issuer_subject =
+        KeymasterBlob(attestationKey->issuerSubjectName.data(),
+                      attestationKey->issuerSubjectName.size());
+  }
+
+  ImportKeyResponse response(impl_.message_version());
+  impl_.ImportKey(request, &response);
+
+  if (response.error != KM_ERROR_OK) {
+    return kmError2ScopedAStatus(response.error);
+  }
+
+  creationResult->keyBlob = kmBlob2vector(response.key_blob);
+  creationResult->keyCharacteristics = convertKeyCharacteristics(
+      securityLevel_, response.unenforced, response.enforced);
+  creationResult->certificateChain =
+      convertCertificateChain(response.certificate_chain);
+
+  return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteKeyMintDevice::importWrappedKey(
+    const vector<uint8_t>& wrappedKeyData,         //
+    const vector<uint8_t>& wrappingKeyBlob,        //
+    const vector<uint8_t>& maskingKey,             //
+    const vector<KeyParameter>& unwrappingParams,  //
+    int64_t passwordSid, int64_t biometricSid,     //
+    KeyCreationResult* creationResult) {
+  ImportWrappedKeyRequest request(impl_.message_version());
+  request.SetWrappedMaterial(wrappedKeyData.data(), wrappedKeyData.size());
+  request.SetWrappingMaterial(wrappingKeyBlob.data(), wrappingKeyBlob.size());
+  request.SetMaskingKeyMaterial(maskingKey.data(), maskingKey.size());
+  request.additional_params.Reinitialize(KmParamSet(unwrappingParams));
+  request.password_sid = static_cast<uint64_t>(passwordSid);
+  request.biometric_sid = static_cast<uint64_t>(biometricSid);
+
+  ImportWrappedKeyResponse response(impl_.message_version());
+  impl_.ImportWrappedKey(request, &response);
+
+  if (response.error != KM_ERROR_OK) {
+    return kmError2ScopedAStatus(response.error);
+  }
+
+  creationResult->keyBlob = kmBlob2vector(response.key_blob);
+  creationResult->keyCharacteristics = convertKeyCharacteristics(
+      securityLevel_, response.unenforced, response.enforced);
+  creationResult->certificateChain =
+      convertCertificateChain(response.certificate_chain);
+
+  return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteKeyMintDevice::upgradeKey(
+    const vector<uint8_t>& keyBlobToUpgrade,
+    const vector<KeyParameter>& upgradeParams, vector<uint8_t>* keyBlob) {
+  UpgradeKeyRequest request(impl_.message_version());
+  request.SetKeyMaterial(keyBlobToUpgrade.data(), keyBlobToUpgrade.size());
+  request.upgrade_params.Reinitialize(KmParamSet(upgradeParams));
+
+  UpgradeKeyResponse response(impl_.message_version());
+  impl_.UpgradeKey(request, &response);
+
+  if (response.error != KM_ERROR_OK) {
+    return kmError2ScopedAStatus(response.error);
+  }
+
+  *keyBlob = kmBlob2vector(response.upgraded_key);
+  return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteKeyMintDevice::deleteKey(const vector<uint8_t>& keyBlob) {
+  DeleteKeyRequest request(impl_.message_version());
+  request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
+
+  DeleteKeyResponse response(impl_.message_version());
+  impl_.DeleteKey(request, &response);
+
+  return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus RemoteKeyMintDevice::deleteAllKeys() {
+  // There's nothing to be done to delete software key blobs.
+  DeleteAllKeysRequest request(impl_.message_version());
+  DeleteAllKeysResponse response(impl_.message_version());
+  impl_.DeleteAllKeys(request, &response);
+
+  return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus RemoteKeyMintDevice::destroyAttestationIds() {
+  return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
+}
+
+ScopedAStatus RemoteKeyMintDevice::begin(KeyPurpose purpose,
+                                         const vector<uint8_t>& keyBlob,
+                                         const vector<KeyParameter>& params,
+                                         const HardwareAuthToken& authToken,
+                                         BeginResult* result) {
+  BeginOperationRequest request(impl_.message_version());
+  request.purpose = legacy_enum_conversion(purpose);
+  request.SetKeyMaterial(keyBlob.data(), keyBlob.size());
+  request.additional_params.Reinitialize(KmParamSet(params));
+
+  vector<uint8_t> vector_token = authToken2AidlVec(authToken);
+  request.additional_params.push_back(
+      TAG_AUTH_TOKEN, reinterpret_cast<uint8_t*>(vector_token.data()),
+      vector_token.size());
+
+  BeginOperationResponse response(impl_.message_version());
+  impl_.BeginOperation(request, &response);
+
+  if (response.error != KM_ERROR_OK) {
+    return kmError2ScopedAStatus(response.error);
+  }
+
+  result->params = kmParamSet2Aidl(response.output_params);
+  result->challenge = response.op_handle;
+  result->operation = ndk::SharedRefBase::make<RemoteKeyMintOperation>(
+      impl_, response.op_handle);
+  return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteKeyMintDevice::deviceLocked(
+    bool passwordOnly,
+    const std::optional<secureclock::TimeStampToken>& timestampToken) {
+  DeviceLockedRequest request(impl_.message_version());
+  request.passwordOnly = passwordOnly;
+  if (timestampToken.has_value()) {
+    request.token.challenge = timestampToken->challenge;
+    request.token.mac = {timestampToken->mac.data(),
+                         timestampToken->mac.size()};
+    request.token.timestamp = timestampToken->timestamp.milliSeconds;
+  }
+  DeviceLockedResponse response = impl_.DeviceLocked(request);
+  return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus RemoteKeyMintDevice::earlyBootEnded() {
+  EarlyBootEndedResponse response = impl_.EarlyBootEnded();
+  return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus RemoteKeyMintDevice::performOperation(
+    const vector<uint8_t>& /* request */, vector<uint8_t>* /* response */) {
+  return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
+}
+
+}  // namespace aidl::android::hardware::security::keymint
diff --git a/guest/hals/keymint/remote/remote_keymint_device.h b/guest/hals/keymint/remote/remote_keymint_device.h
new file mode 100644
index 0000000..c4e840e
--- /dev/null
+++ b/guest/hals/keymint/remote/remote_keymint_device.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2020, 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/security/keymint/BnKeyMintDevice.h>
+#include <aidl/android/hardware/security/keymint/BnKeyMintOperation.h>
+#include <aidl/android/hardware/security/keymint/HardwareAuthToken.h>
+
+#include "guest/hals/keymint/remote/remote_keymaster.h"
+
+namespace aidl::android::hardware::security::keymint {
+using ::ndk::ScopedAStatus;
+using std::optional;
+using std::shared_ptr;
+using std::vector;
+
+using secureclock::TimeStampToken;
+
+class RemoteKeyMintDevice : public BnKeyMintDevice {
+ public:
+  explicit RemoteKeyMintDevice(::keymaster::RemoteKeymaster&, SecurityLevel);
+  virtual ~RemoteKeyMintDevice();
+
+  ScopedAStatus getHardwareInfo(KeyMintHardwareInfo* info) override;
+
+  ScopedAStatus addRngEntropy(const vector<uint8_t>& data) override;
+
+  ScopedAStatus generateKey(const vector<KeyParameter>& keyParams,
+                            const optional<AttestationKey>& attestationKey,
+                            KeyCreationResult* creationResult) override;
+
+  ScopedAStatus importKey(const vector<KeyParameter>& keyParams,
+                          KeyFormat keyFormat, const vector<uint8_t>& keyData,
+                          const optional<AttestationKey>& attestationKey,
+                          KeyCreationResult* creationResult) override;
+
+  ScopedAStatus importWrappedKey(const vector<uint8_t>& wrappedKeyData,
+                                 const vector<uint8_t>& wrappingKeyBlob,
+                                 const vector<uint8_t>& maskingKey,
+                                 const vector<KeyParameter>& unwrappingParams,
+                                 int64_t passwordSid, int64_t biometricSid,
+                                 KeyCreationResult* creationResult) override;
+
+  ScopedAStatus upgradeKey(const vector<uint8_t>& keyBlobToUpgrade,
+                           const vector<KeyParameter>& upgradeParams,
+                           vector<uint8_t>* keyBlob) override;
+
+  ScopedAStatus deleteKey(const vector<uint8_t>& keyBlob) override;
+  ScopedAStatus deleteAllKeys() override;
+  ScopedAStatus destroyAttestationIds() override;
+
+  ScopedAStatus begin(KeyPurpose purpose, const vector<uint8_t>& keyBlob,
+                      const vector<KeyParameter>& params,
+                      const HardwareAuthToken& authToken,
+                      BeginResult* result) override;
+
+  ScopedAStatus deviceLocked(
+      bool passwordOnly,
+      const optional<TimeStampToken>& timestampToken) override;
+  ScopedAStatus earlyBootEnded() override;
+
+  ScopedAStatus performOperation(const vector<uint8_t>& request,
+                                 vector<uint8_t>* response) override;
+
+ protected:
+  ::keymaster::RemoteKeymaster& impl_;
+  SecurityLevel securityLevel_;
+};
+
+}  // namespace aidl::android::hardware::security::keymint
diff --git a/guest/hals/keymint/remote/remote_keymint_operation.cpp b/guest/hals/keymint/remote/remote_keymint_operation.cpp
new file mode 100644
index 0000000..a5fb6aa
--- /dev/null
+++ b/guest/hals/keymint/remote/remote_keymint_operation.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2020, 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.
+ */
+
+#define LOG_TAG "android.hardware.security.keymint-impl"
+#include <log/log.h>
+
+#include "guest/hals/keymint/remote/remote_keymint_operation.h"
+
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+#include <aidl/android/hardware/security/secureclock/ISecureClock.h>
+
+#include <keymaster/android_keymaster.h>
+
+#include "KeyMintUtils.h"
+
+namespace aidl::android::hardware::security::keymint {
+
+using ::keymaster::AbortOperationRequest;
+using ::keymaster::AbortOperationResponse;
+using ::keymaster::Buffer;
+using ::keymaster::FinishOperationRequest;
+using ::keymaster::FinishOperationResponse;
+using ::keymaster::TAG_ASSOCIATED_DATA;
+using ::keymaster::UpdateOperationRequest;
+using ::keymaster::UpdateOperationResponse;
+using secureclock::TimeStampToken;
+using namespace km_utils;
+
+RemoteKeyMintOperation::RemoteKeyMintOperation(
+    ::keymaster::RemoteKeymaster& impl, keymaster_operation_handle_t opHandle)
+    : impl_(impl), opHandle_(opHandle) {}
+
+RemoteKeyMintOperation::~RemoteKeyMintOperation() {
+  if (opHandle_ != 0) {
+    abort();
+  }
+}
+
+ScopedAStatus RemoteKeyMintOperation::updateAad(
+    const vector<uint8_t>& input,
+    const optional<HardwareAuthToken>& /* authToken */,
+    const optional<TimeStampToken>& /* timestampToken */) {
+  UpdateOperationRequest request(impl_.message_version());
+  request.op_handle = opHandle_;
+  request.additional_params.push_back(TAG_ASSOCIATED_DATA, input.data(),
+                                      input.size());
+
+  UpdateOperationResponse response(impl_.message_version());
+  impl_.UpdateOperation(request, &response);
+
+  return kmError2ScopedAStatus(response.error);
+}
+
+ScopedAStatus RemoteKeyMintOperation::update(
+    const vector<uint8_t>& input,
+    const optional<HardwareAuthToken>& /* authToken */,
+    const optional<TimeStampToken>&
+    /* timestampToken */,
+    vector<uint8_t>* output) {
+  if (!output) return kmError2ScopedAStatus(KM_ERROR_OUTPUT_PARAMETER_NULL);
+
+  UpdateOperationRequest request(impl_.message_version());
+  request.op_handle = opHandle_;
+  request.input.Reinitialize(input.data(), input.size());
+
+  UpdateOperationResponse response(impl_.message_version());
+  impl_.UpdateOperation(request, &response);
+
+  if (response.error != KM_ERROR_OK)
+    return kmError2ScopedAStatus(response.error);
+  if (response.input_consumed != request.input.buffer_size()) {
+    return kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR);
+  }
+
+  *output = kmBuffer2vector(response.output);
+  return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteKeyMintOperation::finish(
+    const optional<vector<uint8_t>>& input,      //
+    const optional<vector<uint8_t>>& signature,  //
+    const optional<HardwareAuthToken>& /* authToken */,
+    const optional<TimeStampToken>& /* timestampToken */,
+    const optional<vector<uint8_t>>& /* confirmationToken */,
+    vector<uint8_t>* output) {
+  if (!output) {
+    return ScopedAStatus(AStatus_fromServiceSpecificError(
+        static_cast<int32_t>(ErrorCode::OUTPUT_PARAMETER_NULL)));
+  }
+
+  FinishOperationRequest request(impl_.message_version());
+  request.op_handle = opHandle_;
+  if (input) request.input.Reinitialize(input->data(), input->size());
+  if (signature)
+    request.signature.Reinitialize(signature->data(), signature->size());
+
+  FinishOperationResponse response(impl_.message_version());
+  impl_.FinishOperation(request, &response);
+  opHandle_ = 0;
+
+  if (response.error != KM_ERROR_OK)
+    return kmError2ScopedAStatus(response.error);
+
+  *output = kmBuffer2vector(response.output);
+  return ScopedAStatus::ok();
+}
+
+ScopedAStatus RemoteKeyMintOperation::abort() {
+  AbortOperationRequest request(impl_.message_version());
+  request.op_handle = opHandle_;
+
+  AbortOperationResponse response(impl_.message_version());
+  impl_.AbortOperation(request, &response);
+  opHandle_ = 0;
+
+  return kmError2ScopedAStatus(response.error);
+}
+
+}  // namespace aidl::android::hardware::security::keymint
diff --git a/guest/hals/keymint/remote/remote_keymint_operation.h b/guest/hals/keymint/remote/remote_keymint_operation.h
new file mode 100644
index 0000000..eb3c78b
--- /dev/null
+++ b/guest/hals/keymint/remote/remote_keymint_operation.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2020, 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/security/keymint/BnKeyMintOperation.h>
+#include <aidl/android/hardware/security/secureclock/ISecureClock.h>
+
+#include <hardware/keymaster_defs.h>
+
+#include "guest/hals/keymint/remote/remote_keymaster.h"
+
+namespace keymaster {
+class AndroidKeymaster;
+}
+
+namespace aidl::android::hardware::security::keymint {
+
+using ::ndk::ScopedAStatus;
+using secureclock::TimeStampToken;
+using std::optional;
+using std::shared_ptr;
+using std::string;
+using std::vector;
+
+class RemoteKeyMintOperation : public BnKeyMintOperation {
+ public:
+  explicit RemoteKeyMintOperation(::keymaster::RemoteKeymaster& implementation,
+                                  keymaster_operation_handle_t opHandle);
+  virtual ~RemoteKeyMintOperation();
+
+  ScopedAStatus updateAad(
+      const vector<uint8_t>& input,
+      const optional<HardwareAuthToken>& authToken,
+      const optional<TimeStampToken>& timestampToken) override;
+
+  ScopedAStatus update(const vector<uint8_t>& input,
+                       const optional<HardwareAuthToken>& authToken,
+                       const optional<TimeStampToken>& timestampToken,
+                       vector<uint8_t>* output) override;
+
+  ScopedAStatus finish(const optional<vector<uint8_t>>& input,        //
+                       const optional<vector<uint8_t>>& signature,    //
+                       const optional<HardwareAuthToken>& authToken,  //
+                       const optional<TimeStampToken>& timestampToken,
+                       const optional<vector<uint8_t>>& confirmationToken,
+                       vector<uint8_t>* output) override;
+
+  ScopedAStatus abort() override;
+
+ protected:
+  ::keymaster::RemoteKeymaster& impl_;
+  keymaster_operation_handle_t opHandle_;
+};
+
+}  // namespace aidl::android::hardware::security::keymint
diff --git a/guest/hals/keymint/remote/remote_secure_clock.cpp b/guest/hals/keymint/remote/remote_secure_clock.cpp
new file mode 100644
index 0000000..53bab78
--- /dev/null
+++ b/guest/hals/keymint/remote/remote_secure_clock.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2020, 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.
+ */
+
+#define LOG_TAG "android.hardware.security.secureclock-impl"
+#include <log/log.h>
+
+#include "guest/hals/keymint/remote/remote_secure_clock.h"
+
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+
+#include <keymaster/android_keymaster.h>
+#include <keymaster/keymaster_configuration.h>
+#include "KeyMintUtils.h"
+
+namespace aidl::android::hardware::security::secureclock {
+
+using namespace ::keymaster;
+using namespace ::aidl::android::hardware::security::keymint::km_utils;
+
+RemoteSecureClock::RemoteSecureClock(keymaster::RemoteKeymaster& impl)
+    : impl_(impl) {}
+
+RemoteSecureClock::~RemoteSecureClock() {}
+
+ScopedAStatus RemoteSecureClock::generateTimeStamp(int64_t challenge,
+                                                   TimeStampToken* token) {
+  GenerateTimestampTokenRequest request(impl_.message_version());
+  request.challenge = challenge;
+  GenerateTimestampTokenResponse response(request.message_version);
+  impl_.GenerateTimestampToken(request, &response);
+  if (response.error != KM_ERROR_OK) {
+    return kmError2ScopedAStatus(response.error);
+  }
+  token->challenge = response.token.challenge;
+  token->timestamp.milliSeconds =
+      static_cast<int64_t>(response.token.timestamp);
+  token->mac = kmBlob2vector(response.token.mac);
+  return ScopedAStatus::ok();
+}
+
+}  // namespace aidl::android::hardware::security::secureclock
diff --git a/guest/hals/keymint/remote/remote_secure_clock.h b/guest/hals/keymint/remote/remote_secure_clock.h
new file mode 100644
index 0000000..a0330e2
--- /dev/null
+++ b/guest/hals/keymint/remote/remote_secure_clock.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2020, 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/security/secureclock/BnSecureClock.h>
+#include <aidl/android/hardware/security/secureclock/TimeStampToken.h>
+#include <aidl/android/hardware/security/secureclock/Timestamp.h>
+#include "guest/hals/keymint/remote/remote_keymaster.h"
+
+namespace keymaster {
+class AndroidKeymaster;
+}
+
+namespace aidl::android::hardware::security::secureclock {
+using ::ndk::ScopedAStatus;
+using std::shared_ptr;
+using std::vector;
+
+class RemoteSecureClock : public BnSecureClock {
+ public:
+  explicit RemoteSecureClock(::keymaster::RemoteKeymaster& keymint);
+  virtual ~RemoteSecureClock();
+  ScopedAStatus generateTimeStamp(int64_t challenge,
+                                  TimeStampToken* token) override;
+
+ private:
+  ::keymaster::RemoteKeymaster& impl_;
+};
+}  // namespace aidl::android::hardware::security::secureclock
diff --git a/guest/hals/keymint/remote/service.cpp b/guest/hals/keymint/remote/service.cpp
new file mode 100644
index 0000000..0591edf
--- /dev/null
+++ b/guest/hals/keymint/remote/service.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2020, 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.
+ */
+
+#define LOG_TAG "android.hardware.security.keymint-service"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include <keymaster/soft_keymaster_logger.h>
+#include "guest/hals/keymint/remote/remote_keymint_device.h"
+
+#include <guest/hals/keymint/remote/remote_keymaster.h>
+#include <guest/hals/keymint/remote/remote_keymint_device.h>
+#include <guest/hals/keymint/remote/remote_secure_clock.h>
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/security/keymaster_channel.h"
+
+static const char device[] = "/dev/hvc3";
+
+using aidl::android::hardware::security::keymint::RemoteKeyMintDevice;
+using aidl::android::hardware::security::keymint::SecurityLevel;
+using aidl::android::hardware::security::secureclock::RemoteSecureClock;
+
+template <typename T, class... Args>
+static std::shared_ptr<T> addService(Args&&... args) {
+  std::shared_ptr<T> ser =
+      ndk::SharedRefBase::make<T>(std::forward<Args>(args)...);
+  auto instanceName = std::string(T::descriptor) + "/remote";
+  LOG(INFO) << "adding keymint service instance: " << instanceName;
+  binder_status_t status =
+      AServiceManager_addService(ser->asBinder().get(), instanceName.c_str());
+  CHECK(status == STATUS_OK);
+  return ser;
+}
+
+int main() {
+  // Zero threads seems like a useless pool, but below we'll join this thread to
+  // it, increasing the pool size to 1.
+  ABinderProcess_setThreadPoolMaxThreadCount(0);
+  // Add Keymint Service
+  auto fd = cuttlefish::SharedFD::Open(device, O_RDWR);
+  if (!fd->IsOpen()) {
+    LOG(FATAL) << "Could not connect to keymaster: " << fd->StrError();
+  }
+
+  if (fd->SetTerminalRaw() < 0) {
+    LOG(FATAL) << "Could not make " << device
+               << " a raw terminal: " << fd->StrError();
+  }
+
+  cuttlefish::KeymasterChannel keymasterChannel(fd, fd);
+
+  keymaster::RemoteKeymaster remote_keymaster(&keymasterChannel);
+
+  addService<RemoteKeyMintDevice>(remote_keymaster,
+                                  SecurityLevel::TRUSTED_ENVIRONMENT);
+  addService<RemoteSecureClock>(remote_keymaster);
+
+  ABinderProcess_joinThreadPool();
+  return EXIT_FAILURE;  // should not reach
+}