220 lines
7.6 KiB
C++
220 lines
7.6 KiB
C++
|
|
/*
|
||
|
|
* 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
|