Add helper library to get remotely provisioned key
The code is mostly from credstore. The intention here is that we replace
that code with a common library.
Test: librkp_support_test
Change-Id: I28ebc5a253c037277dad6d39b761b4e8aa4347e8
diff --git a/provisioner/support/rkpd_client.cpp b/provisioner/support/rkpd_client.cpp
new file mode 100644
index 0000000..0643457
--- /dev/null
+++ b/provisioner/support/rkpd_client.cpp
@@ -0,0 +1,219 @@
+/*
+ * 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 "rkpd_client"
+
+#include <atomic>
+
+#include <android-base/logging.h>
+#include <android/security/rkp/BnGetKeyCallback.h>
+#include <android/security/rkp/BnGetRegistrationCallback.h>
+#include <android/security/rkp/IGetKeyCallback.h>
+#include <android/security/rkp/IRemoteProvisioning.h>
+#include <binder/IServiceManager.h>
+#include <binder/Status.h>
+#include <rkp/support/rkpd_client.h>
+#include <vintf/VintfObject.h>
+
+namespace android::security::rkp::support {
+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::IGetKeyCallback;
+using ::android::security::rkp::IRegistration;
+using ::android::security::rkp::IRemoteProvisioning;
+using ::android::security::rkp::RemotelyProvisionedKey;
+
+constexpr const char* kRemoteProvisioningServiceName = "remote_provisioning";
+
+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. "
+ << "This is a bug in the vendor implementation.";
+ return std::nullopt;
+ }
+
+ return *rpcHwInfo.uniqueId;
+}
+
+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(IGetKeyCallback::ErrorCode error, const String16& description) override {
+ if (called_.test_and_set()) {
+ return Status::ok();
+ }
+ LOG(ERROR) << "GetKeyCallback failed: " << static_cast<int>(error) << ", " << description;
+ 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(IGetKeyCallback::ErrorCode::ERROR_UNKNOWN,
+ 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::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>(String16(kRemoteProvisioningServiceName));
+ 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;
+}
+
+std::optional<RemotelyProvisionedKey> getRpcKey(const sp<IRemotelyProvisionedComponent>& rpc,
+ int32_t keyId, int32_t timeout_sec) {
+ auto rpcKeyFuture = getRpcKeyFuture(rpc, keyId);
+ if (!rpcKeyFuture) {
+ LOG(ERROR) << "Failed getRpcKeyFuture()";
+ return std::nullopt;
+ }
+
+ auto timeout = std::chrono::seconds(timeout_sec);
+ if (rpcKeyFuture->wait_for(timeout) != std::future_status::ready) {
+ LOG(ERROR) << "Waiting for remotely provisioned attestation key timed out";
+ return std::nullopt;
+ }
+
+ return rpcKeyFuture->get();
+}
+
+} // namespace android::security::rkp::support