/* * Copyright 2020, 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. */ /****************************************************************************** * * The original Work has been changed by NXP. * * 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. * * Copyright 2022,2024 NXP * ******************************************************************************/ #define LOG_TAG "javacard.keymint.device.strongbox-impl" #include "JavacardKeyMintDevice.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "JavacardKeyMintOperation.h" #include "JavacardSharedSecret.h" namespace aidl::android::hardware::security::keymint { using cppbor::Bstr; using cppbor::EncodedItem; using cppbor::Uint; using ::keymaster::AuthorizationSet; using ::keymaster::dup_buffer; using ::keymaster::KeymasterBlob; using ::keymaster::KeymasterKeyBlob; using ::keymint::javacard::Instruction; using std::string; ScopedAStatus JavacardKeyMintDevice::defaultHwInfo(KeyMintHardwareInfo* info) { info->versionNumber = 2; info->keyMintAuthorName = "Google"; info->keyMintName = "JavacardKeymintDevice"; info->securityLevel = securitylevel_; info->timestampTokenRequired = true; return ScopedAStatus::ok(); } ScopedAStatus JavacardKeyMintDevice::getHardwareInfo(KeyMintHardwareInfo* info) { auto [item, err] = card_->sendRequest(Instruction::INS_GET_HW_INFO_CMD); std::optional optKeyMintName; std::optional optKeyMintAuthorName; std::optional optSecLevel; std::optional optVersion; std::optional optTsRequired; if (err != KM_ERROR_OK || !(optVersion = cbor_.getUint64(item, 1)) || !(optSecLevel = cbor_.getUint64(item, 2)) || !(optKeyMintName = cbor_.getByteArrayStr(item, 3)) || !(optKeyMintAuthorName = cbor_.getByteArrayStr(item, 4)) || !(optTsRequired = cbor_.getUint64(item, 5))) { LOG(ERROR) << "Error in response of getHardwareInfo."; LOG(INFO) << "Returning defaultHwInfo in getHardwareInfo."; return defaultHwInfo(info); } info->keyMintName = std::move(optKeyMintName.value()); info->keyMintAuthorName = std::move(optKeyMintAuthorName.value()); info->timestampTokenRequired = (optTsRequired.value() == 1); info->securityLevel = static_cast(std::move(optSecLevel.value())); info->versionNumber = static_cast(std::move(optVersion.value())); return ScopedAStatus::ok(); } ScopedAStatus JavacardKeyMintDevice::generateKey(const vector& keyParams, const optional& attestationKey, KeyCreationResult* creationResult) { card_->sendPendingEvents(); cppbor::Array array; // add key params cbor_.addKeyparameters(array, keyParams); // add attestation key if any cbor_.addAttestationKey(array, attestationKey); auto [item, err] = card_->sendRequest(Instruction::INS_GENERATE_KEY_CMD, array); if (err != KM_ERROR_OK) { LOG(ERROR) << "Error in sending generateKey."; return km_utils::kmError2ScopedAStatus(err); } auto optKeyBlob = cbor_.getByteArrayVec(item, 1); auto optKeyChars = cbor_.getKeyCharacteristics(item, 2); auto optCertChain = cbor_.getCertificateChain(item, 3); if (!optKeyBlob || !optKeyChars || !optCertChain) { LOG(ERROR) << "Error in decoding og response in generateKey."; return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR); } creationResult->keyCharacteristics = std::move(optKeyChars.value()); creationResult->certificateChain = std::move(optCertChain.value()); creationResult->keyBlob = std::move(optKeyBlob.value()); return ScopedAStatus::ok(); } ScopedAStatus JavacardKeyMintDevice::addRngEntropy(const vector& data) { cppbor::Array request; // add key data request.add(Bstr(data)); auto [item, err] = card_->sendRequest(Instruction::INS_ADD_RNG_ENTROPY_CMD, request); if (err != KM_ERROR_OK) { LOG(ERROR) << "Error in sending addRngEntropy."; return km_utils::kmError2ScopedAStatus(err); } return ScopedAStatus::ok(); } ScopedAStatus JavacardKeyMintDevice::importKey(const vector& keyParams, KeyFormat keyFormat, const vector& keyData, const optional& attestationKey, KeyCreationResult* creationResult) { card_->sendPendingEvents(); cppbor::Array request; // add key params cbor_.addKeyparameters(request, keyParams); // add key format request.add(Uint(static_cast(keyFormat))); // add key data request.add(Bstr(keyData)); // add attestation key if any cbor_.addAttestationKey(request, attestationKey); auto [item, err] = card_->sendRequest(Instruction::INS_IMPORT_KEY_CMD, request); if (err != KM_ERROR_OK) { LOG(ERROR) << "Error in sending data in importKey."; return km_utils::kmError2ScopedAStatus(err); } auto optKeyBlob = cbor_.getByteArrayVec(item, 1); auto optKeyChars = cbor_.getKeyCharacteristics(item, 2); auto optCertChain = cbor_.getCertificateChain(item, 3); if (!optKeyBlob || !optKeyChars || !optCertChain) { LOG(ERROR) << "Error in decoding response in importKey."; return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR); } creationResult->keyCharacteristics = std::move(optKeyChars.value()); creationResult->certificateChain = std::move(optCertChain.value()); creationResult->keyBlob = std::move(optKeyBlob.value()); return ScopedAStatus::ok(); } // import wrapped key is divided into 2 stage operation. ScopedAStatus JavacardKeyMintDevice::importWrappedKey(const vector& wrappedKeyData, const vector& wrappingKeyBlob, const vector& maskingKey, const vector& unwrappingParams, int64_t passwordSid, int64_t biometricSid, KeyCreationResult* creationResult) { card_->sendPendingEvents(); cppbor::Array request; std::unique_ptr item; vector keyBlob; std::vector response; vector keyCharacteristics; std::vector iv; std::vector transitKey; std::vector secureKey; std::vector tag; vector authList; KeyFormat keyFormat; std::vector wrappedKeyDescription; keymaster_error_t errorCode = parseWrappedKey(wrappedKeyData, iv, transitKey, secureKey, tag, authList, keyFormat, wrappedKeyDescription); if (errorCode != KM_ERROR_OK) { LOG(ERROR) << "Error in parse wrapped key in importWrappedKey."; return km_utils::kmError2ScopedAStatus(errorCode); } // begin import std::tie(item, errorCode) = sendBeginImportWrappedKeyCmd(transitKey, wrappingKeyBlob, maskingKey, unwrappingParams); if (errorCode != KM_ERROR_OK) { LOG(ERROR) << "Error in send begin import wrapped key in importWrappedKey."; return km_utils::kmError2ScopedAStatus(errorCode); } // Finish the import std::tie(item, errorCode) = sendFinishImportWrappedKeyCmd( authList, keyFormat, secureKey, tag, iv, wrappedKeyDescription, passwordSid, biometricSid); if (errorCode != KM_ERROR_OK) { LOG(ERROR) << "Error in send finish import wrapped key in importWrappedKey."; return km_utils::kmError2ScopedAStatus(errorCode); } auto optKeyBlob = cbor_.getByteArrayVec(item, 1); auto optKeyChars = cbor_.getKeyCharacteristics(item, 2); auto optCertChain = cbor_.getCertificateChain(item, 3); if (!optKeyBlob || !optKeyChars || !optCertChain) { LOG(ERROR) << "Error in decoding the response in importWrappedKey."; return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR); } creationResult->keyCharacteristics = std::move(optKeyChars.value()); creationResult->certificateChain = std::move(optCertChain.value()); creationResult->keyBlob = std::move(optKeyBlob.value()); return ScopedAStatus::ok(); } std::tuple, keymaster_error_t> JavacardKeyMintDevice::sendBeginImportWrappedKeyCmd(const std::vector& transitKey, const std::vector& wrappingKeyBlob, const std::vector& maskingKey, const vector& unwrappingParams) { Array request; request.add(std::vector(transitKey)); request.add(std::vector(wrappingKeyBlob)); request.add(std::vector(maskingKey)); cbor_.addKeyparameters(request, unwrappingParams); return card_->sendRequest(Instruction::INS_BEGIN_IMPORT_WRAPPED_KEY_CMD, request); } std::tuple, keymaster_error_t> JavacardKeyMintDevice::sendFinishImportWrappedKeyCmd( const vector& keyParams, KeyFormat keyFormat, const std::vector& secureKey, const std::vector& tag, const std::vector& iv, const std::vector& wrappedKeyDescription, int64_t passwordSid, int64_t biometricSid) { Array request; cbor_.addKeyparameters(request, keyParams); request.add(static_cast(keyFormat)); request.add(std::vector(secureKey)); request.add(std::vector(tag)); request.add(std::vector(iv)); request.add(std::vector(wrappedKeyDescription)); request.add(Uint(passwordSid)); request.add(Uint(biometricSid)); return card_->sendRequest(Instruction::INS_FINISH_IMPORT_WRAPPED_KEY_CMD, request); } ScopedAStatus JavacardKeyMintDevice::upgradeKey(const vector& keyBlobToUpgrade, const vector& upgradeParams, vector* keyBlob) { card_->sendPendingEvents(); cppbor::Array request; // add key blob request.add(Bstr(keyBlobToUpgrade)); // add key params cbor_.addKeyparameters(request, upgradeParams); auto [item, err] = card_->sendRequest(Instruction::INS_UPGRADE_KEY_CMD, request); if (err != KM_ERROR_OK) { LOG(ERROR) << "Error in sending in upgradeKey."; return km_utils::kmError2ScopedAStatus(err); } auto optKeyBlob = cbor_.getByteArrayVec(item, 1); if (!optKeyBlob) { LOG(ERROR) << "Error in decoding the response in upgradeKey."; return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR); } *keyBlob = std::move(optKeyBlob.value()); return ScopedAStatus::ok(); } ScopedAStatus JavacardKeyMintDevice::deleteKey(const vector& keyBlob) { Array request; request.add(Bstr(keyBlob)); auto [item, err] = card_->sendRequest(Instruction::INS_DELETE_KEY_CMD, request); if (err != KM_ERROR_OK) { LOG(ERROR) << "Error in sending in deleteKey."; return km_utils::kmError2ScopedAStatus(err); } return ScopedAStatus::ok(); } ScopedAStatus JavacardKeyMintDevice::deleteAllKeys() { auto [_, err] = card_->sendRequest(Instruction::INS_DELETE_ALL_KEYS_CMD); if (err != KM_ERROR_OK) { LOG(ERROR) << "Error in sending deleteAllKeys."; card_->setDeleteAllKeysPending(); return km_utils::kmError2ScopedAStatus(err); } return ScopedAStatus::ok(); } ScopedAStatus JavacardKeyMintDevice::destroyAttestationIds() { auto [item, err] = card_->sendRequest(Instruction::INS_DESTROY_ATT_IDS_CMD); if (err != KM_ERROR_OK) { LOG(ERROR) << "Error in sending in destroyAttestationIds."; return km_utils::kmError2ScopedAStatus(err); } return ScopedAStatus::ok(); } ScopedAStatus JavacardKeyMintDevice::begin(KeyPurpose purpose, const std::vector& keyBlob, const std::vector& params, const std::optional& authToken, BeginResult* result) { card_->sendPendingEvents(); cppbor::Array array; std::vector response; // make request array.add(Uint(static_cast(purpose))); array.add(Bstr(keyBlob)); cbor_.addKeyparameters(array, params); HardwareAuthToken token = authToken.value_or(HardwareAuthToken()); cbor_.addHardwareAuthToken(array, token); auto [item, err] = card_->sendRequest(Instruction::INS_BEGIN_OPERATION_CMD, array); if (err != KM_ERROR_OK) { LOG(ERROR) << "Error in sending in begin."; return km_utils::kmError2ScopedAStatus(err); } // return the result auto keyParams = cbor_.getKeyParameters(item, 1); auto optOpHandle = cbor_.getUint64(item, 2); auto optBufMode = cbor_.getUint64(item, 3); auto optMacLength = cbor_.getUint64(item, 4); if (!keyParams || !optOpHandle || !optBufMode || !optMacLength) { LOG(ERROR) << "Error in decoding the response in begin."; return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR); } result->params = std::move(keyParams.value()); result->challenge = optOpHandle.value(); result->operation = ndk::SharedRefBase::make( static_cast(optOpHandle.value()), static_cast(optBufMode.value()), optMacLength.value(), card_); return ScopedAStatus::ok(); } ScopedAStatus JavacardKeyMintDevice::deviceLocked(bool passwordOnly, const std::optional& timestampToken) { Array request; int8_t password = 1; if (!passwordOnly) { password = 0; } request.add(Uint(password)); cbor_.addTimeStampToken(request, timestampToken.value_or(TimeStampToken())); auto [item, err] = card_->sendRequest(Instruction::INS_DEVICE_LOCKED_CMD, request); if (err != KM_ERROR_OK) { return km_utils::kmError2ScopedAStatus(err); } return ScopedAStatus::ok(); } ScopedAStatus JavacardKeyMintDevice::earlyBootEnded() { auto [_, err] = card_->sendRequest(Instruction::INS_EARLY_BOOT_ENDED_CMD); if (err != KM_ERROR_OK) { LOG(ERROR) << "Error in sending earlyBootEnded."; card_->setEarlyBootEndedPending(); return km_utils::kmError2ScopedAStatus(err); } return ScopedAStatus::ok(); } ScopedAStatus JavacardKeyMintDevice::getKeyCharacteristics( const std::vector& keyBlob, const std::vector& appId, const std::vector& appData, std::vector* result) { card_->sendPendingEvents(); cppbor::Array request; request.add(vector(keyBlob)); request.add(vector(appId)); request.add(vector(appData)); auto [item, err] = card_->sendRequest(Instruction::INS_GET_KEY_CHARACTERISTICS_CMD, request); if (err != KM_ERROR_OK) { LOG(ERROR) << "Error in sending in getKeyCharacteristics."; return km_utils::kmError2ScopedAStatus(err); } auto optKeyChars = cbor_.getKeyCharacteristics(item, 1); if (!optKeyChars) { LOG(ERROR) << "Error in sending in upgradeKey."; return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR); } *result = std::move(optKeyChars.value()); return ScopedAStatus::ok(); } ScopedAStatus JavacardKeyMintDevice::getRootOfTrustChallenge(std::array* challenge) { #ifdef INIT_USING_SEHAL_TRANSPORT auto [item, err] = card_->sendRequestSeHal(Instruction::INS_GET_ROT_CHALLENGE_CMD); #else auto [item, err] = card_->sendRequest(Instruction::INS_GET_ROT_CHALLENGE_CMD); #endif if (err != KM_ERROR_OK) { LOG(ERROR) << "Error in sending in getRootOfTrustChallenge."; #ifdef INIT_USING_SEHAL_TRANSPORT card_->closeSEHal(); #endif return km_utils::kmError2ScopedAStatus(err); } auto optChallenge = cbor_.getByteArrayVec(item, 1); if (!optChallenge) { LOG(ERROR) << "Error in sending in upgradeKey."; return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR); } std::move(optChallenge->begin(), optChallenge->begin() + 16, challenge->begin()); return ScopedAStatus::ok(); } ScopedAStatus JavacardKeyMintDevice::getRootOfTrust(const std::array& /*challenge*/, std::vector* /*rootOfTrust*/) { return km_utils::kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED); } ScopedAStatus JavacardKeyMintDevice::sendRootOfTrust(const std::vector& rootOfTrust) { cppbor::Array request; std::unique_ptr item; keymaster_error_t err; request.add(EncodedItem(rootOfTrust)); // taggedItem. #ifdef INIT_USING_SEHAL_TRANSPORT std::tie(item, err) = card_->sendRequestSeHal(Instruction::INS_SEND_ROT_DATA_CMD, request.encode()); card_->closeSEHal(); #else std::tie(item, err) = card_->sendRequest(Instruction::INS_SEND_ROT_DATA_CMD, request.encode()); #endif if (err != KM_ERROR_OK) { LOG(ERROR) << "Error in sending in sendRootOfTrust."; return km_utils::kmError2ScopedAStatus(err); } LOG(INFO) << "JavacardKeyMintDevice::sendRootOfTrust success"; return ScopedAStatus::ok(); } keymaster_error_t JavacardKeyMintDevice::parseWrappedKey(const vector& wrappedKeyData, std::vector& iv, std::vector& transitKey, std::vector& secureKey, std::vector& tag, vector& authList, KeyFormat& keyFormat, std::vector& wrappedKeyDescription) { KeymasterBlob kmIv; KeymasterKeyBlob kmTransitKey; KeymasterKeyBlob kmSecureKey; KeymasterBlob kmTag; AuthorizationSet authSet; keymaster_key_format_t kmKeyFormat; KeymasterBlob kmWrappedKeyDescription; size_t keyDataLen = wrappedKeyData.size(); uint8_t* keyData = dup_buffer(wrappedKeyData.data(), keyDataLen); keymaster_key_blob_t keyMaterial = {keyData, keyDataLen}; keymaster_error_t error = parse_wrapped_key(KeymasterKeyBlob(keyMaterial), &kmIv, &kmTransitKey, &kmSecureKey, &kmTag, &authSet, &kmKeyFormat, &kmWrappedKeyDescription); if (error != KM_ERROR_OK) { LOG(ERROR) << "Error parsing wrapped key."; return error; } iv = km_utils::kmBlob2vector(kmIv); transitKey = km_utils::kmBlob2vector(kmTransitKey); secureKey = km_utils::kmBlob2vector(kmSecureKey); tag = km_utils::kmBlob2vector(kmTag); authList = km_utils::kmParamSet2Aidl(authSet); keyFormat = static_cast(kmKeyFormat); wrappedKeyDescription = km_utils::kmBlob2vector(kmWrappedKeyDescription); return KM_ERROR_OK; } ScopedAStatus JavacardKeyMintDevice::convertStorageKeyToEphemeral( const std::vector& /* storageKeyBlob */, std::vector* /* ephemeralKeyBlob */) { return km_utils::kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED); } binder_status_t JavacardKeyMintDevice::dump(int /* fd */, const char** /* p */, uint32_t /* q */) { LOG(INFO) << "\n KeyMint-JavacardKeyMintDevice HAL MemoryLeak Info = \n" << ::android::GetUnreachableMemoryString(true, 10000).c_str(); return STATUS_OK; } } // namespace aidl::android::hardware::security::keymint