blob: 541cdbe6d1ca518920af34124f104709bb4f6bd2 [file] [log] [blame]
/*
* 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 NXP
*
******************************************************************************/
#define LOG_TAG "javacard.keymint.device.strongbox-impl"
#include "JavacardKeyMintDevice.h"
#include "JavacardKeyMintOperation.h"
#include "JavacardSharedSecret.h"
#include <JavacardKeyMintUtils.h>
#include <algorithm>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <hardware/hw_auth_token.h>
#include <iostream>
#include <iterator>
#include <keymaster/android_keymaster_messages.h>
#include <keymaster/wrapped_key.h>
#include <memory>
#include <regex.h>
#include <string>
#include <vector>
namespace aidl::android::hardware::security::keymint {
using km_utils::KmParamSet;
using namespace ::keymaster;
using namespace ::keymint::javacard;
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<uint32_t>(item, 1, version) ||
!cbor_.getUint64<uint32_t>(item, 2, secLevel) ||
!cbor_.getBinaryArray(item, 3, info->keyMintName) ||
!cbor_.getBinaryArray(item, 4, info->keyMintAuthorName) ||
!cbor_.getUint64<uint64_t>(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<SecurityLevel>(secLevel);
info->versionNumber = static_cast<int32_t>(version);
return ScopedAStatus::ok();
}
ScopedAStatus JavacardKeyMintDevice::generateKey(const vector<KeyParameter>& keyParams,
const optional<AttestationKey>& attestationKey,
KeyCreationResult* creationResult) {
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);
}
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<uint8_t>& 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<KeyParameter>& keyParams,
KeyFormat keyFormat, const vector<uint8_t>& keyData,
const optional<AttestationKey>& attestationKey,
KeyCreationResult* creationResult) {
cppbor::Array request;
// add key params
cbor_.addKeyparameters(request, keyParams);
// add key format
request.add(Uint(static_cast<uint8_t>(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<uint8_t>& wrappedKeyData,
const vector<uint8_t>& wrappingKeyBlob,
const vector<uint8_t>& maskingKey,
const vector<KeyParameter>& unwrappingParams,
int64_t passwordSid, int64_t biometricSid,
KeyCreationResult* creationResult) {
cppbor::Array request;
std::unique_ptr<Item> item;
vector<uint8_t> keyBlob;
std::vector<uint8_t> response;
vector<KeyCharacteristics> keyCharacteristics;
std::vector<uint8_t> iv;
std::vector<uint8_t> transitKey;
std::vector<uint8_t> secureKey;
std::vector<uint8_t> tag;
vector<KeyParameter> authList;
KeyFormat keyFormat;
std::vector<uint8_t> 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<std::unique_ptr<Item>, keymaster_error_t>
JavacardKeyMintDevice::sendBeginImportWrappedKeyCmd(const std::vector<uint8_t>& transitKey,
const std::vector<uint8_t>& wrappingKeyBlob,
const std::vector<uint8_t>& maskingKey,
const vector<KeyParameter>& unwrappingParams) {
Array request;
request.add(std::vector<uint8_t>(transitKey));
request.add(std::vector<uint8_t>(wrappingKeyBlob));
request.add(std::vector<uint8_t>(maskingKey));
cbor_.addKeyparameters(request, unwrappingParams);
return card_->sendRequest(Instruction::INS_BEGIN_IMPORT_WRAPPED_KEY_CMD, request);
}
std::tuple<std::unique_ptr<Item>, keymaster_error_t>
JavacardKeyMintDevice::sendFinishImportWrappedKeyCmd(
const vector<KeyParameter>& keyParams, KeyFormat keyFormat,
const std::vector<uint8_t>& secureKey, const std::vector<uint8_t>& tag,
const std::vector<uint8_t>& iv, const std::vector<uint8_t>& wrappedKeyDescription,
int64_t passwordSid, int64_t biometricSid) {
Array request;
cbor_.addKeyparameters(request, keyParams);
request.add(static_cast<uint64_t>(keyFormat));
request.add(std::vector<uint8_t>(secureKey));
request.add(std::vector<uint8_t>(tag));
request.add(std::vector<uint8_t>(iv));
request.add(std::vector<uint8_t>(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<uint8_t>& keyBlobToUpgrade,
const vector<KeyParameter>& upgradeParams,
vector<uint8_t>* keyBlob) {
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);
}
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<uint8_t>& 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<uint8_t>& keyBlob,
const std::vector<KeyParameter>& params,
const std::optional<HardwareAuthToken>& authToken,
BeginResult* result) {
cppbor::Array array;
std::vector<uint8_t> response;
// make request
array.add(Uint(static_cast<uint64_t>(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<uint64_t>(item, 2, opHandle) ||
!cbor_.getUint64<uint8_t>(item, 3, bufMode) ||
!cbor_.getUint64<uint16_t>(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<JavacardKeyMintOperation>(
static_cast<keymaster_operation_handle_t>(opHandle), static_cast<BufferingMode>(bufMode),
macLength, card_);
return ScopedAStatus::ok();
}
// TODO
ScopedAStatus
JavacardKeyMintDevice::deviceLocked(bool passwordOnly,
const std::optional<TimeStampToken>& 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<uint8_t>& keyBlob, const std::vector<uint8_t>& appId,
const std::vector<uint8_t>& appData, std::vector<KeyCharacteristics>* result) {
cppbor::Array request;
request.add(vector<uint8_t>(keyBlob));
request.add(vector<uint8_t>(appId));
request.add(vector<uint8_t>(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<uint8_t, 16>* 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<uint8_t> 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<uint8_t, 16>& in_challenge,
__attribute__((unused)) std::vector<uint8_t>* rootOfTrust) {
return km_utils::kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
}
ScopedAStatus JavacardKeyMintDevice::sendRootOfTrust(const std::vector<uint8_t>& in_rootOfTrust) {
std::vector<uint8_t> 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<uint8_t>& wrappedKeyData,
std::vector<uint8_t>& iv, std::vector<uint8_t>& transitKey,
std::vector<uint8_t>& secureKey, std::vector<uint8_t>& tag,
vector<KeyParameter>& authList, KeyFormat& keyFormat,
std::vector<uint8_t>& 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<KeyFormat>(kmKeyFormat);
wrappedKeyDescription = km_utils::kmBlob2vector(kmWrappedKeyDescription);
return KM_ERROR_OK;
}
ScopedAStatus JavacardKeyMintDevice::convertStorageKeyToEphemeral(
const std::vector<uint8_t>& /* storageKeyBlob */,
std::vector<uint8_t>* /* ephemeralKeyBlob */) {
return km_utils::kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
}
} // namespace aidl::android::hardware::security::keymint