| /* |
| * 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 |