/* * 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-2023 NXP * ******************************************************************************/ #define LOG_TAG "javacard.keymint.device.strongbox-impl" #include "JavacardKeyMintDevice.h" #include "JavacardKeyMintOperation.h" #include "JavacardSharedSecret.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace aidl::android::hardware::security::keymint { using cppbor::Array; using cppbor::Bstr; using cppbor::Uint; using ::keymaster::AuthorizationSet; using ::keymaster::dup_buffer; using ::keymaster::KeymasterBlob; using ::keymaster::KeymasterKeyBlob; using ::keymint::javacard::Instruction; ScopedAStatus JavacardKeyMintDevice::defaultHwInfo(KeyMintHardwareInfo* info) { info->versionNumber = 1; info->keyMintAuthorName = "Google"; info->keyMintName = "JavacardKeymintDevice"; info->securityLevel = securitylevel_; info->timestampTokenRequired = true; return ScopedAStatus::ok(); } ScopedAStatus JavacardKeyMintDevice::getHardwareInfo(KeyMintHardwareInfo* info) { uint64_t tsRequired = 1; auto [item, err] = card_->sendRequest(Instruction::INS_GET_HW_INFO_CMD); uint32_t secLevel; uint32_t version; if (err != KM_ERROR_OK || !cbor_.getUint64(item, 1, version) || !cbor_.getUint64(item, 2, secLevel) || !cbor_.getBinaryArray(item, 3, info->keyMintName) || !cbor_.getBinaryArray(item, 4, info->keyMintAuthorName) || !cbor_.getUint64(item, 5, tsRequired)) { // TODO should we return HARDWARE_NOT_YET_AVAILABLE instead of default Hardware Info. LOG(ERROR) << "Error in response of getHardwareInfo."; LOG(INFO) << "Returning defaultHwInfo in getHardwareInfo."; return defaultHwInfo(info); } card_->initializeJavacard(); info->timestampTokenRequired = (tsRequired == 1); info->securityLevel = static_cast(secLevel); info->versionNumber = static_cast(version); return ScopedAStatus::ok(); } ScopedAStatus JavacardKeyMintDevice::generateKey(const vector& keyParams, const optional& attestationKey, KeyCreationResult* creationResult) { 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); } if (!cbor_.getBinaryArray(item, 1, creationResult->keyBlob) || !cbor_.getKeyCharacteristics(item, 2, creationResult->keyCharacteristics) || !cbor_.getCertificateChain(item, 3, creationResult->certificateChain)) { LOG(ERROR) << "Error in decoding og response in generateKey."; return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR); } return ScopedAStatus::ok(); } ScopedAStatus JavacardKeyMintDevice::addRngEntropy(const vector& data) { 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) { 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); } if (!cbor_.getBinaryArray(item, 1, creationResult->keyBlob) || !cbor_.getKeyCharacteristics(item, 2, creationResult->keyCharacteristics) || !cbor_.getCertificateChain(item, 3, creationResult->certificateChain)) { LOG(ERROR) << "Error in decoding response in importKey."; return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR); } 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) { 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); } if (!cbor_.getBinaryArray(item, 1, creationResult->keyBlob) || !cbor_.getKeyCharacteristics(item, 2, creationResult->keyCharacteristics) || !cbor_.getCertificateChain(item, 3, creationResult->certificateChain)) { LOG(ERROR) << "Error in decoding the response in importWrappedKey."; return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR); } 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) { 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); } if (!cbor_.getBinaryArray(item, 1, *keyBlob)) { LOG(ERROR) << "Error in decoding the response in upgradeKey."; return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR); } 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 [item, err] = card_->sendRequest(Instruction::INS_DELETE_ALL_KEYS_CMD); if (err != KM_ERROR_OK) { LOG(ERROR) << "Error in sending in deleteAllKeys."; 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) { 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); // Send earlyBootEnded if there is any pending earlybootEnded event. handleSendEarlyBootEndedEvent(); 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 uint64_t opHandle; uint8_t bufMode; uint16_t macLength; if (!cbor_.getKeyParameters(item, 1, result->params) || !cbor_.getUint64(item, 2, opHandle) || !cbor_.getUint64(item, 3, bufMode) || !cbor_.getUint64(item, 4, macLength)) { LOG(ERROR) << "Error in decoding the response in begin."; return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR); } result->challenge = opHandle; result->operation = ndk::SharedRefBase::make( static_cast(opHandle), static_cast(bufMode), macLength, card_); return ScopedAStatus::ok(); } // TODO 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(); } void JavacardKeyMintDevice::handleSendEarlyBootEndedEvent() { if (isEarlyBootEventPending) { LOG(INFO) << "JavacardKeyMintDevice::handleSendEarlyBootEndedEvent send earlyBootEnded Event."; if (earlyBootEnded().isOk()) { isEarlyBootEventPending = false; } } } ScopedAStatus JavacardKeyMintDevice::earlyBootEnded() { auto [item, err] = card_->sendRequest(Instruction::INS_EARLY_BOOT_ENDED_CMD); if (err != KM_ERROR_OK) { // In case of failure cache the event and send in the next immediate request to Applet. isEarlyBootEventPending = true; return km_utils::kmError2ScopedAStatus(err); } isEarlyBootEventPending = false; return ScopedAStatus::ok(); } ScopedAStatus JavacardKeyMintDevice::getKeyCharacteristics( const std::vector& keyBlob, const std::vector& appId, const std::vector& appData, std::vector* result) { 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); } if (!cbor_.getKeyCharacteristics(item, 1, *result)) { LOG(ERROR) << "Error in sending in upgradeKey."; return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR); } return ScopedAStatus::ok(); } ScopedAStatus JavacardKeyMintDevice::getRootOfTrustChallenge(std::array* challenge) { auto [item, err] = card_->sendRequest(Instruction::INS_GET_ROT_CHALLENGE_CMD); if (err != KM_ERROR_OK) { LOG(ERROR) << "Error in getRootOfTrustChallenge."; return km_utils::kmError2ScopedAStatus(err); } std::vector rotChallenge; if (!cbor_.getBinaryArray(item, 1, rotChallenge) || (rotChallenge.size() != 16)) { LOG(ERROR) << "Error in RotChallenge Data"; return km_utils::kmError2ScopedAStatus(KM_ERROR_UNKNOWN_ERROR); } std::copy_n(rotChallenge.begin(), 16, challenge->begin()); return ScopedAStatus::ok(); } ScopedAStatus JavacardKeyMintDevice::getRootOfTrust(__attribute__((unused)) const std::array& in_challenge, __attribute__((unused)) std::vector* rootOfTrust) { return km_utils::kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED); } ScopedAStatus JavacardKeyMintDevice::sendRootOfTrust(const std::vector& in_rootOfTrust) { std::vector rootOfTrust(in_rootOfTrust); auto [item, err] = card_->sendRequest(Instruction::INS_SEND_ROT_DATA_CMD, rootOfTrust); if (err != KM_ERROR_OK) { LOG(ERROR) << "Error in sendRootOfTrust."; return km_utils::kmError2ScopedAStatus(err); } 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