blob: 784a6803d1ef72c423efe3faa028a9be7cdac6a1 [file] [log] [blame]
/*
* 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/IGetKeyCallback.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::IGetKeyCallback;
using ::android::security::rkp::IRegistration;
using ::android::security::rkp::IRemoteProvisioning;
using ::android::security::rkp::RemotelyProvisionedKey;
constexpr const char* kRemoteProvisioningServiceName = "remote_provisioning";
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::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>(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;
}
} // namespace identity
} // namespace security
} // namespace android