identity: Migrate to RKPD for attestation keys

Bug: 261214100
Test: TBD
Change-Id: I760ba8c23be0889e7d01ac6c1513eba348ff96b2
diff --git a/identity/Android.bp b/identity/Android.bp
index 9117b7f..7b81685 100644
--- a/identity/Android.bp
+++ b/identity/Android.bp
@@ -32,35 +32,39 @@
     ],
 
     srcs: [
-        "main.cpp",
-        "CredentialStore.cpp",
-        "CredentialStoreFactory.cpp",
-        "WritableCredential.cpp",
         "Credential.cpp",
         "CredentialData.cpp",
+        "CredentialStore.cpp",
+        "CredentialStoreFactory.cpp",
+        "RemotelyProvisionedKey.cpp",
         "Session.cpp",
         "Util.cpp",
+        "WritableCredential.cpp",
+        "main.cpp",
     ],
     init_rc: ["credstore.rc"],
     shared_libs: [
+        "android.hardware.identity-support-lib",
+        "android.hardware.keymaster@4.0",
+        "android.security.authorization-ndk",
+	"android.security.remoteprovisioning-cpp",
         "libbase",
         "libbinder",
         "libbinder_ndk",
-        "android.hardware.keymaster@4.0",
         "libcredstore_aidl",
         "libcrypto",
-        "libutils",
         "libhidlbase",
-        "android.hardware.identity-support-lib",
         "libkeymaster4support",
         "libkeystore-attestation-application-id",
-        "android.security.authorization-ndk",
-        "android.security.remoteprovisioning-cpp",
+        "libutils",
         "libutilscallstack",
+        "libvintf",
+	"server_configurable_flags",
     ],
     static_libs: [
         "android.hardware.security.rkp-V3-cpp",
         "android.hardware.keymaster-V3-cpp",
+        "android.security.rkp_aidl-cpp",
         "libcppbor_external",
     ],
 }
diff --git a/identity/CredentialStore.cpp b/identity/CredentialStore.cpp
index c5c429b..eb9bdb6 100644
--- a/identity/CredentialStore.cpp
+++ b/identity/CredentialStore.cpp
@@ -26,6 +26,8 @@
 #include <android/security/remoteprovisioning/RemotelyProvisionedKey.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
+#include <server_configurable_flags/get_flags.h>
+#include <vintf/VintfObject.h>
 
 #include "Credential.h"
 #include "CredentialData.h"
@@ -39,41 +41,14 @@
 namespace identity {
 namespace {
 
-using ::android::hardware::security::keymint::IRemotelyProvisionedComponent;
-using ::android::hardware::security::keymint::RpcHardwareInfo;
 using ::android::security::remoteprovisioning::IRemotelyProvisionedKeyPool;
-using ::android::security::remoteprovisioning::RemotelyProvisionedKey;
+using ::android::security::rkp::IRemoteProvisioning;
 
-std::optional<std::string>
-getRemotelyProvisionedComponentId(const sp<IIdentityCredentialStore>& hal) {
-    auto init = [](const sp<IIdentityCredentialStore>& hal) -> std::optional<std::string> {
-        sp<IRemotelyProvisionedComponent> remotelyProvisionedComponent;
-        Status status = hal->getRemotelyProvisionedComponent(&remotelyProvisionedComponent);
-        if (!status.isOk()) {
-            LOG(ERROR) << "Error getting remotely provisioned component: " << status;
-            return std::nullopt;
-        }
-
-        RpcHardwareInfo rpcHwInfo;
-        status = remotelyProvisionedComponent->getHardwareInfo(&rpcHwInfo);
-        if (!status.isOk()) {
-            LOG(ERROR) << "Error getting remotely provisioned component hardware info: " << status;
-            return std::nullopt;
-        }
-
-        if (!rpcHwInfo.uniqueId) {
-            LOG(ERROR) << "Remotely provisioned component is missing a unique id, which is "
-                       << "required for credential key remotely provisioned attestation keys. "
-                       << "This is a bug in the vendor implementation.";
-            return std::nullopt;
-        }
-
-        // This id is required to later fetch remotely provisioned attestation keys.
-        return *rpcHwInfo.uniqueId;
-    };
-
-    static std::optional<std::string> id = init(hal);
-    return id;
+bool useRkpd() {
+    std::string useRkpdFlagValue = server_configurable_flags::GetServerConfigurableFlag(
+        "remote_key_provisioning_native", "enable_rkpd",
+        /*default_value=*/"false");
+    return useRkpdFlagValue == "true";
 }
 
 }  // namespace
@@ -90,13 +65,30 @@
     halApiVersion_ = hal_->getInterfaceVersion();
 
     if (hwInfo_.isRemoteKeyProvisioningSupported) {
-        keyPool_ = android::waitForService<IRemotelyProvisionedKeyPool>(
-            IRemotelyProvisionedKeyPool::descriptor);
-        if (keyPool_.get() == nullptr) {
-            LOG(ERROR) << "Error getting IRemotelyProvisionedKeyPool HAL with service name '"
-                       << IRemotelyProvisionedKeyPool::descriptor << "'";
+        status = hal_->getRemotelyProvisionedComponent(&rpc_);
+        if (!status.isOk()) {
+            LOG(ERROR) << "Error getting remotely provisioned component: " << status;
             return false;
         }
+        useRkpd_ = useRkpd();
+
+        if (useRkpd_) {
+            uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
+            auto rpcKeyFuture = getRpcKeyFuture(rpc_, callingUid);
+            if (!rpcKeyFuture) {
+                LOG(ERROR) << "Error in getRpcKeyFuture()";
+                return false;
+            }
+            rpcKeyFuture_ = std::move(*rpcKeyFuture);
+        } else {
+            keyPool_ = android::waitForService<IRemotelyProvisionedKeyPool>(
+                IRemotelyProvisionedKeyPool::descriptor);
+            if (!keyPool_) {
+                LOG(ERROR) << "Error getting IRemotelyProvisionedKeyPool HAL with service name '"
+                           << IRemotelyProvisionedKeyPool::descriptor << "'";
+                return false;
+            }
+        }
     }
 
     LOG(INFO) << "Connected to Identity Credential HAL with API version " << halApiVersion_
@@ -209,28 +201,54 @@
 
 Status CredentialStore::setRemotelyProvisionedAttestationKey(
     IWritableIdentityCredential* halWritableCredential) {
-    std::optional<std::string> rpcId = getRemotelyProvisionedComponentId(hal_);
-    if (!rpcId) {
-        return Status::fromServiceSpecificError(ERROR_GENERIC,
-                                                "Error getting remotely provisioned component id");
+    std::vector<uint8_t> keyBlob;
+    std::vector<uint8_t> encodedCertChain;
+    Status status;
+
+    if (useRkpd_) {
+        if (rpcKeyFuture_.wait_for(std::chrono::seconds(10)) != std::future_status::ready) {
+            return Status::fromServiceSpecificError(
+                ERROR_GENERIC, "Waiting for remotely provisioned attestation key timed out");
+        }
+
+        std::optional<::android::security::rkp::RemotelyProvisionedKey> key = rpcKeyFuture_.get();
+        if (!key) {
+            return Status::fromServiceSpecificError(
+                ERROR_GENERIC, "Failed to get remotely provisioned attestation key");
+        }
+
+        if (key->keyBlob.empty()) {
+            return Status::fromServiceSpecificError(
+                ERROR_GENERIC, "Remotely provisioned attestation key blob is empty");
+        }
+
+        keyBlob = std::move(key->keyBlob);
+        encodedCertChain = std::move(key->encodedCertChain);
+    } else {
+        std::optional<std::string> rpcId = getRpcId(rpc_);
+        if (!rpcId) {
+            return Status::fromServiceSpecificError(
+                ERROR_GENERIC, "Error getting remotely provisioned component id");
+        }
+
+        uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
+        ::android::security::remoteprovisioning::RemotelyProvisionedKey key;
+        Status status = keyPool_->getAttestationKey(callingUid, *rpcId, &key);
+        if (!status.isOk()) {
+            LOG(WARNING) << "Unable to fetch remotely provisioned attestation key, falling back "
+                         << "to the factory-provisioned attestation key.";
+            return Status::ok();
+        }
+
+        keyBlob = std::move(key.keyBlob);
+        encodedCertChain = std::move(key.encodedCertChain);
     }
 
-    uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
-    RemotelyProvisionedKey key;
-    Status status = keyPool_->getAttestationKey(callingUid, *rpcId, &key);
-    if (!status.isOk()) {
-        LOG(WARNING) << "Unable to fetch remotely provisioned attestation key, falling back "
-                     << "to the factory-provisioned attestation key.";
-        return Status::ok();
-    }
-
-    status = halWritableCredential->setRemotelyProvisionedAttestationKey(key.keyBlob,
-                                                                         key.encodedCertChain);
+    status = halWritableCredential->setRemotelyProvisionedAttestationKey(keyBlob, encodedCertChain);
     if (!status.isOk()) {
         LOG(ERROR) << "Error setting remotely provisioned attestation key on credential";
         return status;
     }
-
     return Status::ok();
 }
 
diff --git a/identity/CredentialStore.h b/identity/CredentialStore.h
index df7928e..495841b 100644
--- a/identity/CredentialStore.h
+++ b/identity/CredentialStore.h
@@ -17,12 +17,16 @@
 #ifndef SYSTEM_SECURITY_CREDENTIAL_STORE_H_
 #define SYSTEM_SECURITY_CREDENTIAL_STORE_H_
 
+#include <future>
 #include <string>
 #include <vector>
 
 #include <android/hardware/identity/IIdentityCredentialStore.h>
 #include <android/security/identity/BnCredentialStore.h>
 #include <android/security/remoteprovisioning/IRemotelyProvisionedKeyPool.h>
+#include <android/security/rkp/IRemoteProvisioning.h>
+
+#include "RemotelyProvisionedKey.h"
 
 namespace android {
 namespace security {
@@ -39,6 +43,7 @@
 using ::android::hardware::identity::IIdentityCredentialStore;
 using ::android::hardware::identity::IPresentationSession;
 using ::android::hardware::identity::IWritableIdentityCredential;
+using ::android::hardware::security::keymint::IRemotelyProvisionedComponent;
 using ::android::security::remoteprovisioning::IRemotelyProvisionedKeyPool;
 
 class CredentialStore : public BnCredentialStore {
@@ -73,9 +78,12 @@
     sp<IIdentityCredentialStore> hal_;
     int halApiVersion_;
 
-    sp<IRemotelyProvisionedKeyPool> keyPool_;
-
     HardwareInformation hwInfo_;
+
+    bool useRkpd_;
+    sp<IRemotelyProvisionedComponent> rpc_;
+    sp<IRemotelyProvisionedKeyPool> keyPool_;
+    std::future<std::optional<RemotelyProvisionedKey>> rpcKeyFuture_;
 };
 
 }  // namespace identity
diff --git a/identity/RemotelyProvisionedKey.cpp b/identity/RemotelyProvisionedKey.cpp
new file mode 100644
index 0000000..46a42f4
--- /dev/null
+++ b/identity/RemotelyProvisionedKey.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2019, 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 "credstore"
+
+#include <atomic>
+
+#include <android-base/logging.h>
+#include <android/security/rkp/BnGetKeyCallback.h>
+#include <android/security/rkp/BnGetRegistrationCallback.h>
+#include <android/security/rkp/IRemoteProvisioning.h>
+#include <binder/IServiceManager.h>
+#include <binder/Status.h>
+#include <vintf/VintfObject.h>
+
+#include "RemotelyProvisionedKey.h"
+
+namespace android {
+namespace security {
+namespace identity {
+namespace {
+
+using ::android::binder::Status;
+using ::android::hardware::security::keymint::IRemotelyProvisionedComponent;
+using ::android::hardware::security::keymint::RpcHardwareInfo;
+using ::android::security::rkp::BnGetKeyCallback;
+using ::android::security::rkp::BnGetRegistrationCallback;
+using ::android::security::rkp::IRegistration;
+using ::android::security::rkp::IRemoteProvisioning;
+using ::android::security::rkp::RemotelyProvisionedKey;
+
+std::optional<String16> findRpcNameById(std::string_view targetRpcId) {
+    auto deviceManifest = vintf::VintfObject::GetDeviceHalManifest();
+    auto instances = deviceManifest->getAidlInstances("android.hardware.security.keymint",
+                                                      "IRemotelyProvisionedComponent");
+    for (const std::string& instance : instances) {
+        auto rpcName =
+            IRemotelyProvisionedComponent::descriptor + String16("/") + String16(instance.c_str());
+        sp<IRemotelyProvisionedComponent> rpc =
+            android::waitForService<IRemotelyProvisionedComponent>(rpcName);
+
+        auto rpcId = getRpcId(rpc);
+        if (!rpcId) {
+            continue;
+        }
+        if (*rpcId == targetRpcId) {
+            return rpcName;
+        }
+    }
+
+    LOG(ERROR) << "Remotely provisioned component with given unique ID: " << targetRpcId
+               << " not found";
+    return std::nullopt;
+}
+
+std::optional<String16> getRpcName(const sp<IRemotelyProvisionedComponent>& rpc) {
+    std::optional<std::string> targetRpcId = getRpcId(rpc);
+    if (!targetRpcId) {
+        return std::nullopt;
+    }
+    return findRpcNameById(*targetRpcId);
+}
+
+class GetKeyCallback : public BnGetKeyCallback {
+  public:
+    GetKeyCallback(std::promise<std::optional<RemotelyProvisionedKey>> keyPromise)
+        : keyPromise_(std::move(keyPromise)), called_() {}
+
+    Status onSuccess(const RemotelyProvisionedKey& key) override {
+        if (called_.test_and_set()) {
+            return Status::ok();
+        }
+        keyPromise_.set_value(key);
+        return Status::ok();
+    }
+    Status onCancel() override {
+        if (called_.test_and_set()) {
+            return Status::ok();
+        }
+        LOG(ERROR) << "GetKeyCallback cancelled";
+        keyPromise_.set_value(std::nullopt);
+        return Status::ok();
+    }
+    Status onError(const String16& error) override {
+        if (called_.test_and_set()) {
+            return Status::ok();
+        }
+        LOG(ERROR) << "GetKeyCallback failed: " << error;
+        keyPromise_.set_value(std::nullopt);
+        return Status::ok();
+    }
+
+  private:
+    std::promise<std::optional<RemotelyProvisionedKey>> keyPromise_;
+    // This callback can only be called into once
+    std::atomic_flag called_;
+};
+
+class GetRegistrationCallback : public BnGetRegistrationCallback {
+  public:
+    GetRegistrationCallback(std::promise<std::optional<RemotelyProvisionedKey>> keyPromise,
+                            uint32_t keyId)
+        : keyPromise_(std::move(keyPromise)), keyId_(keyId), called_() {}
+
+    Status onSuccess(const sp<IRegistration>& registration) override {
+        if (called_.test_and_set()) {
+            return Status::ok();
+        }
+        auto cb = sp<GetKeyCallback>::make(std::move(keyPromise_));
+        auto status = registration->getKey(keyId_, cb);
+        if (!status.isOk()) {
+            cb->onError(String16("Failed to register GetKeyCallback"));
+        }
+        return Status::ok();
+    }
+    Status onCancel() override {
+        if (called_.test_and_set()) {
+            return Status::ok();
+        }
+        LOG(ERROR) << "GetRegistrationCallback cancelled";
+        keyPromise_.set_value(std::nullopt);
+        return Status::ok();
+    }
+    Status onError(const String16& error) override {
+        if (called_.test_and_set()) {
+            return Status::ok();
+        }
+        LOG(ERROR) << "GetRegistrationCallback failed: " << error;
+        keyPromise_.set_value(std::nullopt);
+        return Status::ok();
+    }
+
+  private:
+    std::promise<std::optional<RemotelyProvisionedKey>> keyPromise_;
+    int32_t keyId_;
+    // This callback can only be called into once
+    std::atomic_flag called_;
+};
+
+}  // namespace
+
+std::optional<std::string> getRpcId(const sp<IRemotelyProvisionedComponent>& rpc) {
+    RpcHardwareInfo rpcHwInfo;
+    Status status = rpc->getHardwareInfo(&rpcHwInfo);
+    if (!status.isOk()) {
+        LOG(ERROR) << "Error getting remotely provisioned component hardware info: " << status;
+        return std::nullopt;
+    }
+
+    if (!rpcHwInfo.uniqueId) {
+        LOG(ERROR) << "Remotely provisioned component is missing a unique id, which is "
+                   << "required for credential key remotely provisioned attestation keys. "
+                   << "This is a bug in the vendor implementation.";
+        return std::nullopt;
+    }
+
+    return *rpcHwInfo.uniqueId;
+}
+
+std::optional<std::future<std::optional<RemotelyProvisionedKey>>>
+getRpcKeyFuture(const sp<IRemotelyProvisionedComponent>& rpc, int32_t keyId) {
+    std::promise<std::optional<RemotelyProvisionedKey>> keyPromise;
+    auto keyFuture = keyPromise.get_future();
+
+    auto rpcName = getRpcName(rpc);
+    if (!rpcName) {
+        LOG(ERROR) << "Failed to get IRemotelyProvisionedComponent name";
+        return std::nullopt;
+    }
+
+    sp<IRemoteProvisioning> remoteProvisioning =
+        android::waitForService<IRemoteProvisioning>(IRemoteProvisioning::descriptor);
+    if (!remoteProvisioning) {
+        LOG(ERROR) << "Failed to get IRemoteProvisioning HAL";
+        return std::nullopt;
+    }
+
+    auto cb = sp<GetRegistrationCallback>::make(std::move(keyPromise), keyId);
+    Status status = remoteProvisioning->getRegistration(*rpcName, cb);
+    if (!status.isOk()) {
+        LOG(ERROR) << "Failed getRegistration()";
+        return std::nullopt;
+    }
+
+    return keyFuture;
+}
+
+}  // namespace identity
+}  // namespace security
+}  // namespace android
diff --git a/identity/RemotelyProvisionedKey.h b/identity/RemotelyProvisionedKey.h
new file mode 100644
index 0000000..e7ddfca
--- /dev/null
+++ b/identity/RemotelyProvisionedKey.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2022, 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 <future>
+#include <optional>
+
+#include <android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
+
+namespace android {
+namespace security {
+namespace identity {
+
+using ::android::hardware::security::keymint::IRemotelyProvisionedComponent;
+using ::android::security::rkp::RemotelyProvisionedKey;
+
+std::optional<std::string> getRpcId(const sp<IRemotelyProvisionedComponent>& rpc);
+
+std::optional<std::future<std::optional<RemotelyProvisionedKey>>>
+getRpcKeyFuture(const sp<IRemotelyProvisionedComponent>& rpc, int32_t keyId);
+
+}  // namespace identity
+}  // namespace security
+}  // namespace android