| /* |
| * Copyright (C) 2025 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. |
| */ |
| |
| #include <aidl/android/hardware/security/see/hwcrypto/BnCryptoOperationContext.h> |
| #include <aidl/android/hardware/security/see/hwcrypto/BnHwCryptoOperations.h> |
| #include <aidl/android/hardware/security/see/hwcrypto/BnOpaqueKey.h> |
| #include <aidl/android/hardware/security/see/hwcrypto/IOpaqueKey.h> |
| #include <android-base/logging.h> |
| #include <android/hardware/security/see/hwcrypto/BnHwCryptoKey.h> |
| #include <binder/RpcTrusty.h> |
| #include <trusty/tipc.h> |
| #include <optional> |
| #include <string> |
| #include "hwcryptokeyimpl.h" |
| |
| using android::IBinder; |
| using android::IInterface; |
| using android::RpcSession; |
| using android::RpcTrustyConnectWithSessionInitializer; |
| using android::sp; |
| using android::wp; |
| using android::base::ErrnoError; |
| using android::base::Error; |
| using android::base::Result; |
| using android::binder::Status; |
| |
| namespace android { |
| namespace trusty { |
| namespace hwcryptohalservice { |
| |
| #define HWCRYPTO_KEY_PORT "com.android.trusty.rust.hwcryptohal.V1" |
| |
| // Even though we get the cpp_hwcrypto::IOpaqueKey and cpp_hwcrypto::ICryptoOperationContext and |
| // create the ndk_hwcrypto wrappers on this library we cannot cast them back when we need them |
| // because they are received on the function calls as binder objects and there is no reliable |
| // we to do this cast yet. Because of that we are creating maps to hold the wrapped objects |
| // and translate them on function calls. |
| // TODO: Add cleanup of both keyMapping and contextMapping once we have more test infrastructure in |
| // place. |
| std::map<std::weak_ptr<ndk_hwcrypto::IOpaqueKey>, wp<cpp_hwcrypto::IOpaqueKey>, std::owner_less<>> |
| keyMapping; |
| std::map<std::weak_ptr<ndk_hwcrypto::ICryptoOperationContext>, |
| wp<cpp_hwcrypto::ICryptoOperationContext>, std::owner_less<>> |
| contextMapping; |
| |
| static ndk::ScopedAStatus convertStatus(Status status) { |
| if (status.isOk()) { |
| return ndk::ScopedAStatus::ok(); |
| } else { |
| auto exCode = status.exceptionCode(); |
| if (exCode == Status::Exception::EX_SERVICE_SPECIFIC) { |
| return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage( |
| status.serviceSpecificErrorCode(), status.exceptionMessage()); |
| } else { |
| return ndk::ScopedAStatus::fromExceptionCodeWithMessage(exCode, |
| status.exceptionMessage()); |
| } |
| } |
| } |
| |
| static std::optional<cpp_hwcrypto::types::ExplicitKeyMaterial> convertExplicitKeyMaterial( |
| const ndk_hwcrypto::types::ExplicitKeyMaterial& keyMaterial) { |
| auto explicitKeyCpp = cpp_hwcrypto::types::ExplicitKeyMaterial(); |
| |
| if (keyMaterial.getTag() == ndk_hwcrypto::types::ExplicitKeyMaterial::aes) { |
| auto aesKey = keyMaterial.get<ndk_hwcrypto::types::ExplicitKeyMaterial::aes>(); |
| auto aesKeyCpp = cpp_hwcrypto::types::AesKey(); |
| if (aesKey.getTag() == ndk_hwcrypto::types::AesKey::aes128) { |
| aesKeyCpp.set<cpp_hwcrypto::types::AesKey::aes128>( |
| aesKey.get<ndk_hwcrypto::types::AesKey::aes128>()); |
| explicitKeyCpp.set<cpp_hwcrypto::types::ExplicitKeyMaterial::aes>(aesKeyCpp); |
| } else if (aesKey.getTag() == ndk_hwcrypto::types::AesKey::aes256) { |
| aesKeyCpp.set<cpp_hwcrypto::types::AesKey::aes256>( |
| aesKey.get<ndk_hwcrypto::types::AesKey::aes256>()); |
| explicitKeyCpp.set<cpp_hwcrypto::types::ExplicitKeyMaterial::aes>(aesKeyCpp); |
| } else { |
| LOG(ERROR) << "unknown AesKey type"; |
| return std::nullopt; |
| } |
| } else if (keyMaterial.getTag() == ndk_hwcrypto::types::ExplicitKeyMaterial::hmac) { |
| auto hmacKey = keyMaterial.get<ndk_hwcrypto::types::ExplicitKeyMaterial::hmac>(); |
| auto hmacKeyCpp = cpp_hwcrypto::types::HmacKey(); |
| if (hmacKey.getTag() == ndk_hwcrypto::types::HmacKey::sha256) { |
| hmacKeyCpp.set<cpp_hwcrypto::types::HmacKey::sha256>( |
| hmacKey.get<ndk_hwcrypto::types::HmacKey::sha256>()); |
| explicitKeyCpp.set<cpp_hwcrypto::types::ExplicitKeyMaterial::hmac>(hmacKeyCpp); |
| } else if (hmacKey.getTag() == ndk_hwcrypto::types::HmacKey::sha512) { |
| hmacKeyCpp.set<cpp_hwcrypto::types::HmacKey::sha512>( |
| hmacKey.get<ndk_hwcrypto::types::HmacKey::sha512>()); |
| explicitKeyCpp.set<cpp_hwcrypto::types::ExplicitKeyMaterial::hmac>(hmacKeyCpp); |
| } else { |
| LOG(ERROR) << "unknown HmacKey type"; |
| return std::nullopt; |
| } |
| } else { |
| LOG(ERROR) << "unknown Key type"; |
| return std::nullopt; |
| } |
| return explicitKeyCpp; |
| } |
| |
| class HwCryptoOperationContextNdk : public ndk_hwcrypto::BnCryptoOperationContext { |
| private: |
| sp<cpp_hwcrypto::ICryptoOperationContext> mContext; |
| std::weak_ptr<ndk_hwcrypto::ICryptoOperationContext> self; |
| |
| public: |
| HwCryptoOperationContextNdk(sp<cpp_hwcrypto::ICryptoOperationContext> operations) |
| : mContext(std::move(operations)) {} |
| |
| ~HwCryptoOperationContextNdk() { contextMapping.erase(self); } |
| |
| static std::shared_ptr<HwCryptoOperationContextNdk> Create( |
| sp<cpp_hwcrypto::ICryptoOperationContext> operations) { |
| if (operations == nullptr) { |
| return nullptr; |
| } |
| std::shared_ptr<HwCryptoOperationContextNdk> contextNdk = |
| ndk::SharedRefBase::make<HwCryptoOperationContextNdk>(std::move(operations)); |
| |
| if (!contextNdk) { |
| LOG(ERROR) << "failed to allocate HwCryptoOperationContext"; |
| return nullptr; |
| } |
| contextNdk->self = contextNdk; |
| return contextNdk; |
| } |
| }; |
| |
| std::optional<cpp_hwcrypto::types::OperationData> convertOperationData( |
| const ndk_hwcrypto::types::OperationData& ndkOperationData) { |
| cpp_hwcrypto::types::OperationData cppOperationData = cpp_hwcrypto::types::OperationData(); |
| cpp_hwcrypto::types::MemoryBufferReference cppMemBuffRef; |
| switch (ndkOperationData.getTag()) { |
| case ndk_hwcrypto::types::OperationData::dataBuffer: |
| cppOperationData.set<cpp_hwcrypto::types::OperationData::dataBuffer>( |
| ndkOperationData.get<ndk_hwcrypto::types::OperationData::dataBuffer>()); |
| break; |
| case ndk_hwcrypto::types::OperationData::memoryBufferReference: |
| cppMemBuffRef.startOffset = |
| ndkOperationData |
| .get<ndk_hwcrypto::types::OperationData::memoryBufferReference>() |
| .startOffset; |
| cppMemBuffRef.sizeBytes = |
| ndkOperationData |
| .get<ndk_hwcrypto::types::OperationData::memoryBufferReference>() |
| .sizeBytes; |
| cppOperationData.set<cpp_hwcrypto::types::OperationData::memoryBufferReference>( |
| std::move(cppMemBuffRef)); |
| break; |
| default: |
| LOG(ERROR) << "received unknown operation data type"; |
| return std::nullopt; |
| } |
| return cppOperationData; |
| } |
| |
| std::optional<cpp_hwcrypto::PatternParameters> convertPatternParameters( |
| const ndk_hwcrypto::PatternParameters& ndkpatternParameters) { |
| int64_t numberBlocksProcess = ndkpatternParameters.numberBlocksProcess; |
| int64_t numberBlocksCopy = ndkpatternParameters.numberBlocksCopy; |
| if ((numberBlocksProcess < 0) || (numberBlocksCopy < 0)) { |
| LOG(ERROR) << "received invalid pattern parameters"; |
| return std::nullopt; |
| } |
| cpp_hwcrypto::PatternParameters patternParameters = cpp_hwcrypto::PatternParameters(); |
| patternParameters.numberBlocksProcess = numberBlocksProcess; |
| patternParameters.numberBlocksCopy = numberBlocksCopy; |
| return patternParameters; |
| } |
| |
| std::optional<cpp_hwcrypto::types::SymmetricOperation> convertSymmetricOperation( |
| const ndk_hwcrypto::types::SymmetricOperation& ndkSymmetricOperation) { |
| cpp_hwcrypto::types::SymmetricOperation symmetricOperation = |
| cpp_hwcrypto::types::SymmetricOperation(); |
| switch (ndkSymmetricOperation) { |
| case ndk_hwcrypto::types::SymmetricOperation::ENCRYPT: |
| symmetricOperation = cpp_hwcrypto::types::SymmetricOperation::ENCRYPT; |
| break; |
| case ndk_hwcrypto::types::SymmetricOperation::DECRYPT: |
| symmetricOperation = cpp_hwcrypto::types::SymmetricOperation::DECRYPT; |
| break; |
| default: |
| LOG(ERROR) << "invalid symmetric operation type"; |
| return std::nullopt; |
| } |
| return symmetricOperation; |
| } |
| |
| cpp_hwcrypto::types::CipherModeParameters convertSymmetricModeParameters( |
| const ndk_hwcrypto::types::CipherModeParameters& ndkcipherModeParameters) { |
| cpp_hwcrypto::types::CipherModeParameters cipherModeParameters = |
| cpp_hwcrypto::types::CipherModeParameters(); |
| cipherModeParameters.nonce = ndkcipherModeParameters.nonce; |
| return cipherModeParameters; |
| } |
| |
| cpp_hwcrypto::types::AesGcmMode::AesGcmModeParameters convertSymmetricModeParameters( |
| const ndk_hwcrypto::types::AesGcmMode::AesGcmModeParameters& ndkgcmModeParameters) { |
| cpp_hwcrypto::types::AesGcmMode::AesGcmModeParameters gcmModeParameters = |
| cpp_hwcrypto::types::AesGcmMode::AesGcmModeParameters(); |
| gcmModeParameters.nonce = ndkgcmModeParameters.nonce; |
| return gcmModeParameters; |
| } |
| |
| std::optional<cpp_hwcrypto::MemoryBufferParameter> convertMemoryBufferParameters( |
| const ndk_hwcrypto::MemoryBufferParameter& ndkMemBuffParams) { |
| cpp_hwcrypto::MemoryBufferParameter memBuffParams = cpp_hwcrypto::MemoryBufferParameter(); |
| memBuffParams.sizeBytes = ndkMemBuffParams.sizeBytes; |
| android::os::ParcelFileDescriptor pfd; |
| ndk::ScopedFileDescriptor ndkFd; |
| switch (ndkMemBuffParams.bufferHandle.getTag()) { |
| case ndk_hwcrypto::MemoryBufferParameter::MemoryBuffer::input: |
| ndkFd = ndkMemBuffParams.bufferHandle |
| .get<ndk_hwcrypto::MemoryBufferParameter::MemoryBuffer::input>() |
| .dup(); |
| pfd.reset(binder::unique_fd(ndkFd.release())); |
| memBuffParams.bufferHandle |
| .set<cpp_hwcrypto::MemoryBufferParameter::MemoryBuffer::input>(std::move(pfd)); |
| break; |
| case ndk_hwcrypto::MemoryBufferParameter::MemoryBuffer::output: |
| ndkFd = ndkMemBuffParams.bufferHandle |
| .get<ndk_hwcrypto::MemoryBufferParameter::MemoryBuffer::output>() |
| .dup(); |
| pfd.reset(binder::unique_fd(ndkFd.release())); |
| memBuffParams.bufferHandle |
| .set<cpp_hwcrypto::MemoryBufferParameter::MemoryBuffer::output>(std::move(pfd)); |
| break; |
| default: |
| LOG(ERROR) << "unknown bufferHandle type"; |
| return std::nullopt; |
| } |
| return memBuffParams; |
| } |
| |
| std::optional<cpp_hwcrypto::OperationParameters> convertOperationParameters( |
| const ndk_hwcrypto::OperationParameters& ndkOperationParameters) { |
| cpp_hwcrypto::OperationParameters operationParameters = cpp_hwcrypto::OperationParameters(); |
| sp<cpp_hwcrypto::IOpaqueKey> opaqueKey; |
| cpp_hwcrypto::types::HmacOperationParameters hmacParameters = |
| cpp_hwcrypto::types::HmacOperationParameters(); |
| std::optional<cpp_hwcrypto::types::SymmetricOperation> cppSymmetricOperation; |
| cpp_hwcrypto::types::CipherModeParameters cipherModeParameters; |
| cpp_hwcrypto::types::AesCipherMode cppAesCipherMode = cpp_hwcrypto::types::AesCipherMode(); |
| cpp_hwcrypto::types::SymmetricOperationParameters cppSymmetricOperationParameters = |
| cpp_hwcrypto::types::SymmetricOperationParameters(); |
| cpp_hwcrypto::types::SymmetricAuthOperationParameters cppSymmetricAuthOperationParameters = |
| cpp_hwcrypto::types::SymmetricAuthOperationParameters(); |
| cpp_hwcrypto::types::AesGcmMode::AesGcmModeParameters cppAesGcmModeParameters = |
| cpp_hwcrypto::types::AesGcmMode::AesGcmModeParameters(); |
| cpp_hwcrypto::types::AesGcmMode cppAesGcmMode = cpp_hwcrypto::types::AesGcmMode(); |
| switch (ndkOperationParameters.getTag()) { |
| case ndk_hwcrypto::OperationParameters::symmetricAuthCrypto: |
| opaqueKey = retrieveCppBinder<cpp_hwcrypto::IOpaqueKey, ndk_hwcrypto::IOpaqueKey, |
| keyMapping>( |
| ndkOperationParameters |
| .get<ndk_hwcrypto::OperationParameters::symmetricAuthCrypto>() |
| .key); |
| if (!opaqueKey) { |
| LOG(ERROR) << "couldn't get aes key"; |
| return std::nullopt; |
| } |
| cppSymmetricAuthOperationParameters.key = std::move(opaqueKey); |
| cppSymmetricOperation = convertSymmetricOperation( |
| ndkOperationParameters |
| .get<ndk_hwcrypto::OperationParameters::symmetricAuthCrypto>() |
| .direction); |
| if (!cppSymmetricOperation.has_value()) { |
| LOG(ERROR) << "couldn't get aes direction"; |
| return std::nullopt; |
| } |
| cppSymmetricAuthOperationParameters.direction = |
| std::move(cppSymmetricOperation.value()); |
| switch (ndkOperationParameters |
| .get<ndk_hwcrypto::OperationParameters::symmetricAuthCrypto>() |
| .parameters.getTag()) { |
| case ndk_hwcrypto::types::SymmetricAuthCryptoParameters::aes: |
| switch (ndkOperationParameters |
| .get<ndk_hwcrypto::OperationParameters::symmetricAuthCrypto>() |
| .parameters |
| .get<ndk_hwcrypto::types::SymmetricAuthCryptoParameters::aes>() |
| .getTag()) { |
| case ndk_hwcrypto::types::AesGcmMode::gcmTag16: |
| cppAesGcmModeParameters = convertSymmetricModeParameters( |
| ndkOperationParameters |
| .get<ndk_hwcrypto::OperationParameters:: |
| symmetricAuthCrypto>() |
| .parameters |
| .get<ndk_hwcrypto::types:: |
| SymmetricAuthCryptoParameters::aes>() |
| .get<ndk_hwcrypto::types::AesGcmMode::gcmTag16>()); |
| cppAesGcmMode.set<cpp_hwcrypto::types::AesGcmMode::gcmTag16>( |
| std::move(cppAesGcmModeParameters)); |
| cppSymmetricAuthOperationParameters.parameters |
| .set<cpp_hwcrypto::types::SymmetricAuthCryptoParameters::aes>( |
| std::move(cppAesGcmMode)); |
| break; |
| default: |
| LOG(ERROR) << "received invalid aes gcm parameters"; |
| return std::nullopt; |
| } |
| break; |
| default: |
| LOG(ERROR) << "received invalid symmetric auth crypto parameters"; |
| return std::nullopt; |
| } |
| operationParameters.set<cpp_hwcrypto::OperationParameters::symmetricAuthCrypto>( |
| std::move(cppSymmetricAuthOperationParameters)); |
| break; |
| case ndk_hwcrypto::OperationParameters::symmetricCrypto: |
| opaqueKey = retrieveCppBinder<cpp_hwcrypto::IOpaqueKey, ndk_hwcrypto::IOpaqueKey, |
| keyMapping>( |
| ndkOperationParameters.get<ndk_hwcrypto::OperationParameters::symmetricCrypto>() |
| .key); |
| if (!opaqueKey) { |
| LOG(ERROR) << "couldn't get aes key"; |
| return std::nullopt; |
| } |
| cppSymmetricOperationParameters.key = std::move(opaqueKey); |
| cppSymmetricOperation = convertSymmetricOperation( |
| ndkOperationParameters.get<ndk_hwcrypto::OperationParameters::symmetricCrypto>() |
| .direction); |
| if (!cppSymmetricOperation.has_value()) { |
| LOG(ERROR) << "couldn't get aes direction"; |
| return std::nullopt; |
| } |
| cppSymmetricOperationParameters.direction = std::move(cppSymmetricOperation.value()); |
| switch (ndkOperationParameters.get<ndk_hwcrypto::OperationParameters::symmetricCrypto>() |
| .parameters.getTag()) { |
| case ndk_hwcrypto::types::SymmetricCryptoParameters::aes: |
| switch (ndkOperationParameters |
| .get<ndk_hwcrypto::OperationParameters::symmetricCrypto>() |
| .parameters |
| .get<ndk_hwcrypto::types::SymmetricCryptoParameters::aes>() |
| .getTag()) { |
| case ndk_hwcrypto::types::AesCipherMode::cbc: |
| cipherModeParameters = convertSymmetricModeParameters( |
| ndkOperationParameters |
| .get<ndk_hwcrypto::OperationParameters:: |
| symmetricCrypto>() |
| .parameters |
| .get<ndk_hwcrypto::types::SymmetricCryptoParameters:: |
| aes>() |
| .get<ndk_hwcrypto::types::AesCipherMode::cbc>()); |
| cppAesCipherMode.set<cpp_hwcrypto::types::AesCipherMode::cbc>( |
| std::move(cipherModeParameters)); |
| cppSymmetricOperationParameters.parameters |
| .set<cpp_hwcrypto::types::SymmetricCryptoParameters::aes>( |
| std::move(cppAesCipherMode)); |
| break; |
| case ndk_hwcrypto::types::AesCipherMode::ctr: |
| cipherModeParameters = convertSymmetricModeParameters( |
| ndkOperationParameters |
| .get<ndk_hwcrypto::OperationParameters:: |
| symmetricCrypto>() |
| .parameters |
| .get<ndk_hwcrypto::types::SymmetricCryptoParameters:: |
| aes>() |
| .get<ndk_hwcrypto::types::AesCipherMode::ctr>()); |
| cppAesCipherMode.set<cpp_hwcrypto::types::AesCipherMode::ctr>( |
| std::move(cipherModeParameters)); |
| cppSymmetricOperationParameters.parameters |
| .set<cpp_hwcrypto::types::SymmetricCryptoParameters::aes>( |
| std::move(cppAesCipherMode)); |
| break; |
| default: |
| LOG(ERROR) << "received invalid aes parameters"; |
| return std::nullopt; |
| } |
| break; |
| default: |
| LOG(ERROR) << "received invalid symmetric crypto parameters"; |
| return std::nullopt; |
| } |
| operationParameters.set<cpp_hwcrypto::OperationParameters::symmetricCrypto>( |
| std::move(cppSymmetricOperationParameters)); |
| break; |
| case ndk_hwcrypto::OperationParameters::hmac: |
| opaqueKey = retrieveCppBinder<cpp_hwcrypto::IOpaqueKey, ndk_hwcrypto::IOpaqueKey, |
| keyMapping>( |
| ndkOperationParameters.get<ndk_hwcrypto::OperationParameters::hmac>().key); |
| if (!opaqueKey) { |
| LOG(ERROR) << "couldn't get hmac key"; |
| return std::nullopt; |
| } |
| hmacParameters.key = opaqueKey; |
| operationParameters.set<cpp_hwcrypto::OperationParameters::hmac>( |
| std::move(hmacParameters)); |
| break; |
| default: |
| LOG(ERROR) << "received invalid operation parameters"; |
| return std::nullopt; |
| } |
| return operationParameters; |
| } |
| |
| class HwCryptoOperationsNdk : public ndk_hwcrypto::BnHwCryptoOperations { |
| private: |
| sp<cpp_hwcrypto::IHwCryptoOperations> mHwCryptoOperations; |
| |
| public: |
| HwCryptoOperationsNdk(sp<cpp_hwcrypto::IHwCryptoOperations> operations) |
| : mHwCryptoOperations(std::move(operations)) {} |
| |
| static std::shared_ptr<HwCryptoOperationsNdk> Create( |
| sp<cpp_hwcrypto::IHwCryptoOperations> operations) { |
| if (operations == nullptr) { |
| return nullptr; |
| } |
| std::shared_ptr<HwCryptoOperationsNdk> operationsNdk = |
| ndk::SharedRefBase::make<HwCryptoOperationsNdk>(std::move(operations)); |
| |
| if (!operationsNdk) { |
| LOG(ERROR) << "failed to allocate HwCryptoOperations"; |
| return nullptr; |
| } |
| return operationsNdk; |
| } |
| |
| ndk::ScopedAStatus processCommandList( |
| std::vector<ndk_hwcrypto::CryptoOperationSet>* operationSets, |
| std::vector<ndk_hwcrypto::CryptoOperationResult>* aidl_return) { |
| Status status = Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); |
| if (operationSets == nullptr) { |
| LOG(ERROR) << "received a null operation set"; |
| return convertStatus(status); |
| } |
| if (aidl_return == nullptr) { |
| LOG(ERROR) << "received a null CryptoOperationResult set"; |
| return convertStatus(status); |
| } |
| std::vector<cpp_hwcrypto::CryptoOperationResult> binderResult; |
| std::vector<cpp_hwcrypto::CryptoOperationSet> cppOperationSets; |
| for (ndk_hwcrypto::CryptoOperationSet& operationSet : *operationSets) { |
| cpp_hwcrypto::CryptoOperationSet cppSingleOperation = |
| cpp_hwcrypto::CryptoOperationSet(); |
| cppSingleOperation.context = |
| retrieveCppBinder<cpp_hwcrypto::ICryptoOperationContext, |
| ndk_hwcrypto::ICryptoOperationContext, contextMapping>( |
| operationSet.context); |
| for (ndk_hwcrypto::CryptoOperation& operation : operationSet.operations) { |
| cpp_hwcrypto::CryptoOperation cppOperation; |
| cpp_hwcrypto::types::Void voidObj; |
| std::optional<cpp_hwcrypto::types::OperationData> cppOperationData; |
| std::optional<cpp_hwcrypto::PatternParameters> cppPatternParameters; |
| std::optional<cpp_hwcrypto::OperationParameters> cppOperationParameters; |
| std::optional<cpp_hwcrypto::MemoryBufferParameter> cppMemBuffParams; |
| switch (operation.getTag()) { |
| case ndk_hwcrypto::CryptoOperation::setMemoryBuffer: |
| cppMemBuffParams = convertMemoryBufferParameters( |
| operation.get<ndk_hwcrypto::CryptoOperation::setMemoryBuffer>()); |
| if (cppMemBuffParams.has_value()) { |
| cppOperation.set<cpp_hwcrypto::CryptoOperation::setMemoryBuffer>( |
| std::move(cppMemBuffParams.value())); |
| } else { |
| return convertStatus(status); |
| } |
| break; |
| case ndk_hwcrypto::CryptoOperation::setOperationParameters: |
| cppOperationParameters = convertOperationParameters( |
| operation.get< |
| ndk_hwcrypto::CryptoOperation::setOperationParameters>()); |
| if (cppOperationParameters.has_value()) { |
| cppOperation.set<cpp_hwcrypto::CryptoOperation::setOperationParameters>( |
| std::move(cppOperationParameters.value())); |
| } else { |
| LOG(ERROR) << "couldn't convert operation parameters"; |
| return convertStatus(status); |
| } |
| break; |
| case ndk_hwcrypto::CryptoOperation::setPattern: |
| cppPatternParameters = convertPatternParameters( |
| operation.get<ndk_hwcrypto::CryptoOperation::setPattern>()); |
| if (cppPatternParameters.has_value()) { |
| cppOperation.set<cpp_hwcrypto::CryptoOperation::setPattern>( |
| std::move(cppPatternParameters.value())); |
| } else { |
| LOG(ERROR) << "couldn't convert pattern parameters"; |
| return convertStatus(status); |
| } |
| break; |
| case ndk_hwcrypto::CryptoOperation::copyData: |
| cppOperationData = convertOperationData( |
| operation.get<ndk_hwcrypto::CryptoOperation::copyData>()); |
| if (cppOperationData.has_value()) { |
| cppOperation.set<cpp_hwcrypto::CryptoOperation::copyData>( |
| std::move(cppOperationData.value())); |
| } else { |
| LOG(ERROR) << "couldn't convert CryptoOperation::copyData"; |
| return convertStatus(status); |
| } |
| break; |
| case ndk_hwcrypto::CryptoOperation::aadInput: |
| cppOperationData = convertOperationData( |
| operation.get<ndk_hwcrypto::CryptoOperation::aadInput>()); |
| if (cppOperationData.has_value()) { |
| cppOperation.set<cpp_hwcrypto::CryptoOperation::aadInput>( |
| std::move(cppOperationData.value())); |
| } else { |
| LOG(ERROR) << "couldn't convert CryptoOperation::aadInput"; |
| return convertStatus(status); |
| } |
| break; |
| case ndk_hwcrypto::CryptoOperation::dataInput: |
| cppOperationData = convertOperationData( |
| operation.get<ndk_hwcrypto::CryptoOperation::dataInput>()); |
| if (cppOperationData.has_value()) { |
| cppOperation.set<cpp_hwcrypto::CryptoOperation::dataInput>( |
| std::move(cppOperationData.value())); |
| } else { |
| LOG(ERROR) << "couldn't convert CryptoOperation::dataInput"; |
| return convertStatus(status); |
| } |
| break; |
| case ndk_hwcrypto::CryptoOperation::dataOutput: |
| cppOperationData = convertOperationData( |
| operation.get<ndk_hwcrypto::CryptoOperation::dataOutput>()); |
| if (cppOperationData.has_value()) { |
| cppOperation.set<cpp_hwcrypto::CryptoOperation::dataOutput>( |
| std::move(cppOperationData.value())); |
| } else { |
| LOG(ERROR) << "couldn't convert CryptoOperation::dataOutput"; |
| return convertStatus(status); |
| } |
| break; |
| case ndk_hwcrypto::CryptoOperation::destroyContext: |
| cppOperation.set<cpp_hwcrypto::CryptoOperation::destroyContext>( |
| std::move(voidObj)); |
| break; |
| case ndk_hwcrypto::CryptoOperation::finish: |
| cppOperation.set<cpp_hwcrypto::CryptoOperation::finish>(std::move(voidObj)); |
| break; |
| default: |
| // This shouldn't happen |
| LOG(ERROR) << "received unknown crypto operation"; |
| return convertStatus(status); |
| } |
| cppSingleOperation.operations.push_back(std::move(cppOperation)); |
| } |
| cppOperationSets.push_back(std::move(cppSingleOperation)); |
| } |
| status = mHwCryptoOperations->processCommandList(&cppOperationSets, &binderResult); |
| if (status.isOk()) { |
| *aidl_return = std::vector<ndk_hwcrypto::CryptoOperationResult>(); |
| for (cpp_hwcrypto::CryptoOperationResult& result : binderResult) { |
| ndk_hwcrypto::CryptoOperationResult ndkResult = |
| ndk_hwcrypto::CryptoOperationResult(); |
| if (result.context != nullptr) { |
| insertBinderMapping<cpp_hwcrypto::ICryptoOperationContext, |
| ndk_hwcrypto::ICryptoOperationContext, |
| HwCryptoOperationContextNdk, contextMapping>( |
| result.context, &ndkResult.context); |
| } else { |
| ndkResult.context = nullptr; |
| } |
| aidl_return->push_back(std::move(ndkResult)); |
| } |
| } else { |
| // No reason to copy back the data output vectors if this failed |
| LOG(ERROR) << "couldn't process command list"; |
| return convertStatus(status); |
| } |
| // We need to copy the vectors from the cpp operations back to the ndk one |
| if (cppOperationSets.size() != operationSets->size()) { |
| LOG(ERROR) << "ndk and cpp operation sets had a different number of elements"; |
| return convertStatus(Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT)); |
| } |
| for (unsigned setIdx = 0; setIdx < cppOperationSets.size(); ++setIdx) { |
| if (cppOperationSets[setIdx].operations.size() != |
| (*operationSets)[setIdx].operations.size()) { |
| LOG(ERROR) << "ndk and cpp operations on set " << setIdx |
| << " had a different number of elements"; |
| return convertStatus(Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT)); |
| } |
| for (unsigned operationIdx = 0; |
| operationIdx < cppOperationSets[setIdx].operations.size(); ++operationIdx) { |
| if (cppOperationSets[setIdx].operations[operationIdx].getTag() == |
| cpp_hwcrypto::CryptoOperation::dataOutput) { |
| if ((*operationSets)[setIdx].operations[operationIdx].getTag() != |
| ndk_hwcrypto::CryptoOperation::dataOutput) { |
| LOG(ERROR) |
| << "ndk and cpp operations on set " << setIdx << " and operation " |
| << operationIdx << " had a different operation type"; |
| return convertStatus( |
| Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT)); |
| } |
| if (cppOperationSets[setIdx] |
| .operations[operationIdx] |
| .get<cpp_hwcrypto::CryptoOperation::dataOutput>() |
| .getTag() == cpp_hwcrypto::types::OperationData::dataBuffer) { |
| // This is the only case on which we need to move the data backto the |
| // original array |
| if ((*operationSets)[setIdx] |
| .operations[operationIdx] |
| .get<ndk_hwcrypto::CryptoOperation::dataOutput>() |
| .getTag() != ndk_hwcrypto::types::OperationData::dataBuffer) { |
| LOG(ERROR) << "ndk and cpp operations on set " << setIdx |
| << " and operation " << operationIdx |
| << " had a different operation data output type"; |
| return convertStatus( |
| Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT)); |
| } |
| (*operationSets)[setIdx] |
| .operations[operationIdx] |
| .get<ndk_hwcrypto::CryptoOperation::dataOutput>() |
| .set<ndk_hwcrypto::types::OperationData::dataBuffer>( |
| cppOperationSets[setIdx] |
| .operations[operationIdx] |
| .get<cpp_hwcrypto::CryptoOperation::dataOutput>() |
| .get<cpp_hwcrypto::types::OperationData:: |
| dataBuffer>()); |
| } |
| } |
| } |
| } |
| return convertStatus(status); |
| } |
| }; |
| |
| class OpaqueKeyNdk : public ndk_hwcrypto::BnOpaqueKey { |
| private: |
| sp<cpp_hwcrypto::IOpaqueKey> mOpaqueKey; |
| std::weak_ptr<ndk_hwcrypto::IOpaqueKey> self; |
| |
| public: |
| OpaqueKeyNdk(sp<cpp_hwcrypto::IOpaqueKey> opaqueKey) : mOpaqueKey(std::move(opaqueKey)) {} |
| |
| ~OpaqueKeyNdk() { keyMapping.erase(self); } |
| |
| static std::shared_ptr<OpaqueKeyNdk> Create(sp<cpp_hwcrypto::IOpaqueKey> opaqueKey) { |
| if (opaqueKey == nullptr) { |
| return nullptr; |
| } |
| std::shared_ptr<OpaqueKeyNdk> opaqueKeyNdk = |
| ndk::SharedRefBase::make<OpaqueKeyNdk>(std::move(opaqueKey)); |
| |
| if (!opaqueKeyNdk) { |
| LOG(ERROR) << "failed to allocate HwCryptoKey"; |
| return nullptr; |
| } |
| opaqueKeyNdk->self = opaqueKeyNdk; |
| return opaqueKeyNdk; |
| } |
| |
| ndk::ScopedAStatus exportWrappedKey( |
| const std::shared_ptr<ndk_hwcrypto::IOpaqueKey>& wrappingKey, |
| ::std::vector<uint8_t>* aidl_return) { |
| Status status = Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); |
| auto wrappingKeyNdk = |
| retrieveCppBinder<cpp_hwcrypto::IOpaqueKey, ndk_hwcrypto::IOpaqueKey, keyMapping>( |
| wrappingKey); |
| if (wrappingKeyNdk == nullptr) { |
| LOG(ERROR) << "couldn't get wrapped key"; |
| return convertStatus(status); |
| } |
| status = mOpaqueKey->exportWrappedKey(wrappingKeyNdk, aidl_return); |
| return convertStatus(status); |
| } |
| |
| ndk::ScopedAStatus getKeyPolicy(ndk_hwcrypto::KeyPolicy* aidl_return) { |
| Status status = Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); |
| if (aidl_return == nullptr) { |
| LOG(ERROR) << "return value passed to getKeyPolicy is nullptr"; |
| return convertStatus(status); |
| } |
| cpp_hwcrypto::KeyPolicy cppPolicy = cpp_hwcrypto::KeyPolicy(); |
| |
| status = mOpaqueKey->getKeyPolicy(&cppPolicy); |
| if (status.isOk()) { |
| auto ndkPolicy = |
| convertKeyPolicy<ndk_hwcrypto::KeyPolicy, cpp_hwcrypto::KeyPolicy>(cppPolicy); |
| *aidl_return = std::move(ndkPolicy); |
| } |
| return convertStatus(status); |
| } |
| |
| ndk::ScopedAStatus getPublicKey(::std::vector<uint8_t>* aidl_return) { |
| auto status = mOpaqueKey->getPublicKey(aidl_return); |
| return convertStatus(status); |
| } |
| |
| ndk::ScopedAStatus getShareableToken(const ::std::vector<uint8_t>& sealingDicePolicy, |
| ndk_hwcrypto::types::OpaqueKeyToken* aidl_return) { |
| Status status = Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); |
| if (aidl_return == nullptr) { |
| LOG(ERROR) << "return value passed to getShareableToken is nullptr"; |
| return convertStatus(status); |
| } |
| cpp_hwcrypto::types::OpaqueKeyToken binder_return; |
| status = mOpaqueKey->getShareableToken(sealingDicePolicy, &binder_return); |
| if (status.isOk()) { |
| aidl_return->keyToken = std::move(binder_return.keyToken); |
| } |
| return convertStatus(status); |
| } |
| |
| ndk::ScopedAStatus setProtectionId( |
| const ndk_hwcrypto::types::ProtectionId /*protectionId*/, |
| const ::std::vector<ndk_hwcrypto::types::OperationType>& /*allowedOperations*/) { |
| return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage( |
| ndk_hwcrypto::types::HalErrorCode::UNAUTHORIZED, |
| "android is not authorized to call setProtectionId"); |
| } |
| }; |
| |
| Result<void> HwCryptoKey::connectToTrusty(const char* tipcDev) { |
| assert(!mSession); |
| auto session_initializer = [](sp<RpcSession>& session) { |
| session->setFileDescriptorTransportMode(RpcSession::FileDescriptorTransportMode::TRUSTY); |
| }; |
| mSession = |
| RpcTrustyConnectWithSessionInitializer(tipcDev, HWCRYPTO_KEY_PORT, session_initializer); |
| if (!mSession) { |
| return ErrnoError() << "failed to connect to hwcrypto"; |
| } |
| mRoot = mSession->getRootObject(); |
| mHwCryptoServer = cpp_hwcrypto::IHwCryptoKey::asInterface(mRoot); |
| return {}; |
| } |
| |
| HwCryptoKey::HwCryptoKey() {} |
| |
| std::shared_ptr<HwCryptoKey> HwCryptoKey::Create(const char* tipcDev) { |
| std::shared_ptr<HwCryptoKey> hwCrypto = ndk::SharedRefBase::make<HwCryptoKey>(); |
| |
| if (!hwCrypto) { |
| LOG(ERROR) << "failed to allocate HwCryptoKey"; |
| return nullptr; |
| } |
| |
| auto ret = hwCrypto->connectToTrusty(tipcDev); |
| if (!ret.ok()) { |
| LOG(ERROR) << "failed to connect HwCryptoKey to Trusty: " << ret.error(); |
| return nullptr; |
| } |
| |
| return hwCrypto; |
| } |
| |
| ndk::ScopedAStatus HwCryptoKey::deriveCurrentDicePolicyBoundKey( |
| const ndk_hwcrypto::IHwCryptoKey::DiceBoundDerivationKey& /*derivationKey*/, |
| ndk_hwcrypto::IHwCryptoKey::DiceCurrentBoundKeyResult* /*aidl_return*/) { |
| return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage( |
| ndk_hwcrypto::types::HalErrorCode::UNAUTHORIZED, |
| "android is not authorized to call deriveCurrentDicePolicyBoundKey"); |
| } |
| |
| ndk::ScopedAStatus HwCryptoKey::deriveDicePolicyBoundKey( |
| const ndk_hwcrypto::IHwCryptoKey::DiceBoundDerivationKey& /*derivationKey*/, |
| const ::std::vector<uint8_t>& /*dicePolicyForKeyVersion*/, |
| ndk_hwcrypto::IHwCryptoKey::DiceBoundKeyResult* /*aidl_return*/) { |
| return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage( |
| ndk_hwcrypto::types::HalErrorCode::UNAUTHORIZED, |
| "android is not authorized to call deriveDicePolicyBoundKey"); |
| } |
| |
| ndk::ScopedAStatus HwCryptoKey::deriveKey( |
| const ndk_hwcrypto::IHwCryptoKey::DerivedKeyParameters& /*parameters*/, |
| ndk_hwcrypto::IHwCryptoKey::DerivedKey* /*aidl_return*/) { |
| return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage( |
| ndk_hwcrypto::types::HalErrorCode::UNAUTHORIZED, |
| "android is not authorized to call deriveKey"); |
| } |
| |
| ndk::ScopedAStatus HwCryptoKey::getHwCryptoOperations( |
| std::shared_ptr<ndk_hwcrypto::IHwCryptoOperations>* aidl_return) { |
| Status status = Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); |
| if (aidl_return == nullptr) { |
| LOG(ERROR) << "return value passed to getHwCryptoOperations is nullptr"; |
| return convertStatus(status); |
| } |
| sp<cpp_hwcrypto::IHwCryptoOperations> binder_return; |
| status = mHwCryptoServer->getHwCryptoOperations(&binder_return); |
| if (status.isOk()) { |
| std::shared_ptr<ndk_hwcrypto::IHwCryptoOperations> operations = |
| HwCryptoOperationsNdk::Create(binder_return); |
| *aidl_return = operations; |
| } |
| return convertStatus(status); |
| } |
| |
| ndk::ScopedAStatus HwCryptoKey::importClearKey( |
| const ndk_hwcrypto::types::ExplicitKeyMaterial& keyMaterial, |
| const ndk_hwcrypto::KeyPolicy& newKeyPolicy, |
| std::shared_ptr<ndk_hwcrypto::IOpaqueKey>* aidl_return) { |
| sp<cpp_hwcrypto::IOpaqueKey> binder_return = nullptr; |
| Status status = Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); |
| if (aidl_return == nullptr) { |
| LOG(ERROR) << "return value passed to importClearKey is nullptr"; |
| return convertStatus(status); |
| } |
| auto cppKeyPolicy = |
| convertKeyPolicy<cpp_hwcrypto::KeyPolicy, ndk_hwcrypto::KeyPolicy>(newKeyPolicy); |
| auto explicitKeyCpp = convertExplicitKeyMaterial(keyMaterial); |
| if (!explicitKeyCpp.has_value()) { |
| LOG(ERROR) << "couldn't convert key material"; |
| return convertStatus(status); |
| } |
| status = mHwCryptoServer->importClearKey(explicitKeyCpp.value(), cppKeyPolicy, &binder_return); |
| if (status.isOk()) { |
| if ((binder_return != nullptr)) { |
| insertBinderMapping<cpp_hwcrypto::IOpaqueKey, ndk_hwcrypto::IOpaqueKey, OpaqueKeyNdk, |
| keyMapping>(binder_return, aidl_return); |
| } else { |
| *aidl_return = nullptr; |
| } |
| } |
| return convertStatus(status); |
| } |
| |
| ndk::ScopedAStatus HwCryptoKey::getCurrentDicePolicy(std::vector<uint8_t>* aidl_return) { |
| auto status = mHwCryptoServer->getCurrentDicePolicy(aidl_return); |
| return convertStatus(status); |
| } |
| |
| ndk::ScopedAStatus HwCryptoKey::keyTokenImport( |
| const ndk_hwcrypto::types::OpaqueKeyToken& requestedKey, |
| const ::std::vector<uint8_t>& sealingDicePolicy, |
| std::shared_ptr<ndk_hwcrypto::IOpaqueKey>* aidl_return) { |
| Status status = Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); |
| if (aidl_return == nullptr) { |
| LOG(ERROR) << "return value passed to keyTokenImport is nullptr"; |
| return convertStatus(status); |
| } |
| sp<cpp_hwcrypto::IOpaqueKey> binder_return; |
| cpp_hwcrypto::types::OpaqueKeyToken requestedKeyCpp; |
| // trying first a shallow copy of the vector |
| requestedKeyCpp.keyToken = requestedKey.keyToken; |
| status = mHwCryptoServer->keyTokenImport(requestedKeyCpp, sealingDicePolicy, &binder_return); |
| if (status.isOk()) { |
| std::shared_ptr<ndk_hwcrypto::IOpaqueKey> opaqueKey = OpaqueKeyNdk::Create(binder_return); |
| *aidl_return = opaqueKey; |
| } |
| return convertStatus(status); |
| } |
| |
| ndk::ScopedAStatus HwCryptoKey::getKeyslotData( |
| ndk_hwcrypto::IHwCryptoKey::KeySlot /*slotId*/, |
| std::shared_ptr<ndk_hwcrypto::IOpaqueKey>* /*aidl_return*/) { |
| return ndk::ScopedAStatus::fromServiceSpecificError( |
| ndk_hwcrypto::types::HalErrorCode::UNAUTHORIZED); |
| } |
| |
| } // namespace hwcryptohalservice |
| } // namespace trusty |
| } // namespace android |