blob: 61bcf8cb6eebe21585d6f6898265371fc35373ce [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.
*/
#include "CborConverter.h"
#include <map>
#include <string>
#include <android-base/logging.h>
#include <KeyMintUtils.h>
namespace keymint::javacard {
using ::aidl::android::hardware::security::keymint::KeyParameterValue;
using ::aidl::android::hardware::security::keymint::SecurityLevel;
using ::aidl::android::hardware::security::keymint::km_utils::kmParam2Aidl;
using ::aidl::android::hardware::security::keymint::km_utils::legacy_enum_conversion;
using ::aidl::android::hardware::security::keymint::km_utils::typeFromTag;
constexpr int SB_ENFORCED = 0;
constexpr int TEE_ENFORCED = 1;
constexpr int SW_ENFORCED = 2;
namespace {
template <KeyParameterValue::Tag aidl_tag>
std::optional<uint32_t> aidlEnumVal2Uint32(const KeyParameterValue& value) {
return (value.getTag() == aidl_tag)
? std::optional(static_cast<uint32_t>(value.get<aidl_tag>()))
: std::nullopt;
}
std::optional<uint32_t> aidlEnumParam2Uint32(const KeyParameter& param) {
auto tag = legacy_enum_conversion(param.tag);
switch (tag) {
case KM_TAG_PURPOSE:
return aidlEnumVal2Uint32<KeyParameterValue::keyPurpose>(param.value);
case KM_TAG_ALGORITHM:
return aidlEnumVal2Uint32<KeyParameterValue::algorithm>(param.value);
case KM_TAG_BLOCK_MODE:
return aidlEnumVal2Uint32<KeyParameterValue::blockMode>(param.value);
case KM_TAG_DIGEST:
case KM_TAG_RSA_OAEP_MGF_DIGEST:
return aidlEnumVal2Uint32<KeyParameterValue::digest>(param.value);
case KM_TAG_PADDING:
return aidlEnumVal2Uint32<KeyParameterValue::paddingMode>(param.value);
case KM_TAG_EC_CURVE:
return aidlEnumVal2Uint32<KeyParameterValue::ecCurve>(param.value);
case KM_TAG_USER_AUTH_TYPE:
return aidlEnumVal2Uint32<KeyParameterValue::hardwareAuthenticatorType>(param.value);
case KM_TAG_ORIGIN:
return aidlEnumVal2Uint32<KeyParameterValue::origin>(param.value);
case KM_TAG_BLOB_USAGE_REQUIREMENTS:
case KM_TAG_KDF:
default:
LOG(FATAL) << "Unknown or unused enum tag: Something is broken";
return std::nullopt;
}
}
} // namespace
bool CborConverter::addAttestationKey(Array& array,
const std::optional<AttestationKey>& attestationKey) {
if (attestationKey.has_value()) {
array.add(Bstr(attestationKey->keyBlob));
addKeyparameters(array, attestationKey->attestKeyParams);
array.add(Bstr(attestationKey->issuerSubjectName));
} else {
array.add(std::move(Bstr(vector<uint8_t>(0))));
array.add(std::move(Map()));
array.add(std::move(Bstr(vector<uint8_t>(0))));
}
return true;
}
bool CborConverter::addKeyparameters(Array& array, const vector<KeyParameter>& keyParams) {
Map map;
std::map<uint32_t, vector<uint8_t>> enum_repetition;
std::map<uint32_t, Array> uint_repetition;
for (auto& param : keyParams) {
auto tag = legacy_enum_conversion(param.tag);
switch (typeFromTag(tag)) {
case KM_ENUM: {
auto paramEnum = aidlEnumParam2Uint32(param);
if (paramEnum.has_value()) {
map.add(static_cast<uint32_t>(tag), *paramEnum);
}
break;
}
case KM_UINT:
if (param.value.getTag() == KeyParameterValue::integer) {
uint32_t intVal = param.value.get<KeyParameterValue::integer>();
map.add(static_cast<uint32_t>(tag), intVal);
}
break;
case KM_UINT_REP:
if (param.value.getTag() == KeyParameterValue::integer) {
uint32_t intVal = param.value.get<KeyParameterValue::integer>();
uint_repetition[static_cast<uint32_t>(tag)].add(intVal);
}
break;
case KM_ENUM_REP: {
auto paramEnumRep = aidlEnumParam2Uint32(param);
if (paramEnumRep.has_value()) {
enum_repetition[static_cast<uint32_t>(tag)].push_back(*paramEnumRep);
}
break;
}
case KM_ULONG:
if (param.value.getTag() == KeyParameterValue::longInteger) {
uint64_t longVal = param.value.get<KeyParameterValue::longInteger>();
map.add(static_cast<uint32_t>(tag), longVal);
}
break;
case KM_ULONG_REP:
if (param.value.getTag() == KeyParameterValue::longInteger) {
uint64_t longVal = param.value.get<KeyParameterValue::longInteger>();
uint_repetition[static_cast<uint32_t>(tag)].add(longVal);
}
break;
case KM_DATE:
if (param.value.getTag() == KeyParameterValue::dateTime) {
uint64_t dateVal = param.value.get<KeyParameterValue::dateTime>();
map.add(static_cast<uint32_t>(tag), dateVal);
}
break;
case KM_BOOL:
map.add(static_cast<uint32_t>(tag), 1 /* true */);
break;
case KM_BIGNUM:
case KM_BYTES:
if (param.value.getTag() == KeyParameterValue::blob) {
const auto& value = param.value.get<KeyParameterValue::blob>();
map.add(static_cast<uint32_t>(tag), value);
}
break;
case KM_INVALID:
break;
}
}
for (auto const& [key, val] : enum_repetition) {
Bstr bstr(val);
map.add(key, std::move(bstr));
}
for (auto& [key, val] : uint_repetition) {
map.add(key, std::move(val));
}
array.add(std::move(map));
return true;
}
// Array of three maps
std::optional<vector<KeyCharacteristics>>
CborConverter::getKeyCharacteristics(const unique_ptr<Item>& item, const uint32_t pos) {
vector<KeyCharacteristics> keyCharacteristics;
auto arrayItem = getItemAtPos(item, pos);
if (!arrayItem || (MajorType::ARRAY != getType(arrayItem.value()))) {
return std::nullopt;
}
KeyCharacteristics swEnf{SecurityLevel::KEYSTORE, {}};
KeyCharacteristics teeEnf{SecurityLevel::TRUSTED_ENVIRONMENT, {}};
KeyCharacteristics sbEnf{SecurityLevel::STRONGBOX, {}};
auto optSbEnf = getKeyParameters(arrayItem.value(), SB_ENFORCED);
if (!optSbEnf) {
return std::nullopt;
}
sbEnf.authorizations = std::move(optSbEnf.value());
auto optTeeEnf = getKeyParameters(arrayItem.value(), TEE_ENFORCED);
if (!optTeeEnf) {
return std::nullopt;
}
teeEnf.authorizations = std::move(optTeeEnf.value());
auto optSwEnf = getKeyParameters(arrayItem.value(), SW_ENFORCED);
if (!optSwEnf) {
return std::nullopt;
}
swEnf.authorizations = std::move(optSwEnf.value());
// VTS will fail if the authorizations list is empty.
if (!sbEnf.authorizations.empty()) keyCharacteristics.push_back(std::move(sbEnf));
if (!teeEnf.authorizations.empty()) keyCharacteristics.push_back(std::move(teeEnf));
if (!swEnf.authorizations.empty()) keyCharacteristics.push_back(std::move(swEnf));
return keyCharacteristics;
}
std::optional<std::vector<KeyParameter>> CborConverter::getKeyParameter(
const std::pair<const std::unique_ptr<Item>&, const std::unique_ptr<Item>&> pair) {
std::vector<KeyParameter> keyParams;
keymaster_tag_t key;
auto optValue = getUint64(pair.first);
if (!optValue) {
return std::nullopt;
}
key = static_cast<keymaster_tag_t>(optValue.value());
switch (keymaster_tag_get_type(key)) {
case KM_ENUM_REP: {
/* ENUM_REP contains values encoded in a Byte string */
const Bstr* bstr = pair.second.get()->asBstr();
if (bstr == nullptr) {
return std::nullopt;
}
for (auto bchar : bstr->value()) {
keymaster_key_param_t keyParam;
keyParam.tag = key;
keyParam.enumerated = bchar;
keyParams.push_back(kmParam2Aidl(keyParam));
}
return keyParams;
}
case KM_ENUM: {
keymaster_key_param_t keyParam;
keyParam.tag = key;
if (!(optValue = getUint64(pair.second))) {
return std::nullopt;
}
keyParam.enumerated = static_cast<uint32_t>(optValue.value());
keyParams.push_back(kmParam2Aidl(keyParam));
return keyParams;
}
case KM_UINT: {
keymaster_key_param_t keyParam;
keyParam.tag = key;
if (!(optValue = getUint64(pair.second))) {
return std::nullopt;
}
keyParam.integer = static_cast<uint32_t>(optValue.value());
keyParams.push_back(kmParam2Aidl(keyParam));
return keyParams;
}
case KM_ULONG: {
keymaster_key_param_t keyParam;
keyParam.tag = key;
if (!(optValue = getUint64(pair.second))) {
return std::nullopt;
}
keyParam.long_integer = optValue.value();
keyParams.push_back(kmParam2Aidl(keyParam));
return keyParams;
}
case KM_UINT_REP: {
/* UINT_REP contains values encoded in a Array */
Array* array = const_cast<Array*>(pair.second.get()->asArray());
if (array == nullptr) return std::nullopt;
for (int i = 0; i < array->size(); i++) {
keymaster_key_param_t keyParam;
keyParam.tag = key;
const std::unique_ptr<Item>& item = array->get(i);
if (!(optValue = getUint64(item))) {
return std::nullopt;
}
keyParam.integer = static_cast<uint32_t>(optValue.value());
keyParams.push_back(kmParam2Aidl(keyParam));
}
return keyParams;
}
case KM_ULONG_REP: {
/* ULONG_REP contains values encoded in a Array */
Array* array = const_cast<Array*>(pair.second.get()->asArray());
if (array == nullptr) return std::nullopt;
for (int i = 0; i < array->size(); i++) {
keymaster_key_param_t keyParam;
keyParam.tag = key;
const std::unique_ptr<Item>& item = array->get(i);
if (!(optValue = getUint64(item))) {
return std::nullopt;
}
keyParam.long_integer = optValue.value();
keyParams.push_back(kmParam2Aidl(keyParam));
}
return keyParams;
}
case KM_DATE: {
keymaster_key_param_t keyParam;
keyParam.tag = key;
if (!(optValue = getUint64(pair.second))) {
return std::nullopt;
}
keyParam.date_time = optValue.value();
keyParams.push_back(kmParam2Aidl(keyParam));
return keyParams;
}
case KM_BOOL: {
keymaster_key_param_t keyParam;
keyParam.tag = key;
if (!(optValue = getUint64(pair.second))) {
return std::nullopt;
}
// If a tag with this type is present, the value is true. If absent,
// false.
keyParam.boolean = true;
keyParams.push_back(kmParam2Aidl(keyParam));
return keyParams;
}
case KM_BIGNUM:
case KM_BYTES: {
keymaster_key_param_t keyParam;
keyParam.tag = key;
const Bstr* bstr = pair.second.get()->asBstr();
if (bstr == nullptr) return std::nullopt;
keyParam.blob.data = bstr->value().data();
keyParam.blob.data_length = bstr->value().size();
keyParams.push_back(kmParam2Aidl(keyParam));
return keyParams;
}
case KM_INVALID:
break;
}
return std::nullopt;
}
// array of a blobs
std::optional<vector<Certificate>>
CborConverter::getCertificateChain(const std::unique_ptr<Item>& item, const uint32_t pos) {
vector<Certificate> certChain;
auto arrayItem = getItemAtPos(item, pos);
if (!arrayItem || (MajorType::ARRAY != getType(arrayItem.value()))) return std::nullopt;
const Array* arr = arrayItem.value().get()->asArray();
for (int i = 0; i < arr->size(); i++) {
Certificate cert;
auto optTemp = getByteArrayVec(arrayItem.value(), i);
if (!optTemp) return std::nullopt;
cert.encodedCertificate = std::move(optTemp.value());
certChain.push_back(std::move(cert));
}
return certChain;
}
std::optional<string> CborConverter::getTextStr(const unique_ptr<Item>& item, const uint32_t pos) {
auto textStrItem = getItemAtPos(item, pos);
if (!textStrItem || (MajorType::TSTR != getType(textStrItem.value()))) {
return std::nullopt;
}
const Tstr* tstr = textStrItem.value().get()->asTstr();
return tstr->value();
}
std::optional<string> CborConverter::getByteArrayStr(const unique_ptr<Item>& item,
const uint32_t pos) {
auto optTemp = getByteArrayVec(item, pos);
if (!optTemp) {
return std::nullopt;
}
std::string str(optTemp->begin(), optTemp->end());
return str;
}
std::optional<std::vector<uint8_t>> CborConverter::getByteArrayVec(const unique_ptr<Item>& item,
const uint32_t pos) {
auto strItem = getItemAtPos(item, pos);
if (!strItem || (MajorType::BSTR != getType(strItem.value()))) {
return std::nullopt;
}
const Bstr* bstr = strItem.value().get()->asBstr();
return bstr->value();
}
std::optional<SharedSecretParameters>
CborConverter::getSharedSecretParameters(const unique_ptr<Item>& item, const uint32_t pos) {
SharedSecretParameters params;
// Array [seed, nonce]
auto arrayItem = getItemAtPos(item, pos);
if (!arrayItem || (MajorType::ARRAY != getType(arrayItem.value()))) {
return std::nullopt;
}
auto optSeed = getByteArrayVec(arrayItem.value(), 0);
auto optNonce = getByteArrayVec(arrayItem.value(), 1);
if (!optSeed || !optNonce) {
return std::nullopt;
}
params.seed = std::move(optSeed.value());
params.nonce = std::move(optNonce.value());
return params;
}
bool CborConverter::addSharedSecretParameters(Array& array,
const vector<SharedSecretParameters>& params) {
Array cborParamsVec;
for (auto param : params) {
Array cborParam;
cborParam.add(Bstr(param.seed));
cborParam.add(Bstr(param.nonce));
cborParamsVec.add(std::move(cborParam));
}
array.add(std::move(cborParamsVec));
return true;
}
bool CborConverter::addTimeStampToken(Array& array, const TimeStampToken& token) {
Array vToken;
vToken.add(static_cast<uint64_t>(token.challenge));
vToken.add(static_cast<uint64_t>(token.timestamp.milliSeconds));
vToken.add((std::vector<uint8_t>(token.mac)));
array.add(std::move(vToken));
return true;
}
bool CborConverter::addHardwareAuthToken(Array& array, const HardwareAuthToken& authToken) {
Array hwAuthToken;
hwAuthToken.add(static_cast<uint64_t>(authToken.challenge));
hwAuthToken.add(static_cast<uint64_t>(authToken.userId));
hwAuthToken.add(static_cast<uint64_t>(authToken.authenticatorId));
hwAuthToken.add(static_cast<uint64_t>(authToken.authenticatorType));
hwAuthToken.add(static_cast<uint64_t>(authToken.timestamp.milliSeconds));
hwAuthToken.add((std::vector<uint8_t>(authToken.mac)));
array.add(std::move(hwAuthToken));
return true;
}
std::optional<TimeStampToken> CborConverter::getTimeStampToken(const unique_ptr<Item>& item,
const uint32_t pos) {
TimeStampToken token;
// {challenge, timestamp, Mac}
auto optChallenge = getUint64(item, pos);
auto optTimestampMillis = getUint64(item, pos + 1);
auto optTemp = getByteArrayVec(item, pos + 2);
if (!optChallenge || !optTimestampMillis || !optTemp) {
return std::nullopt;
}
token.mac = std::move(optTemp.value());
token.challenge = static_cast<long>(std::move(optChallenge.value()));
token.timestamp.milliSeconds = static_cast<long>(std::move(optTimestampMillis.value()));
return token;
}
std::optional<Array> CborConverter::getArrayItem(const std::unique_ptr<Item>& item,
const uint32_t pos) {
Array array;
auto arrayItem = getItemAtPos(item, pos);
if (!arrayItem || (MajorType::ARRAY != getType(arrayItem.value()))) {
return std::nullopt;
}
array = std::move(*(arrayItem.value().get()->asArray()));
return array;
}
std::optional<Map> CborConverter::getMapItem(const std::unique_ptr<Item>& item,
const uint32_t pos) {
Map map;
auto mapItem = getItemAtPos(item, pos);
if (!mapItem || (MajorType::MAP != getType(mapItem.value()))) {
return std::nullopt;
}
map = std::move(*(mapItem.value().get()->asMap()));
return map;
}
std::optional<vector<KeyParameter>> CborConverter::getKeyParameters(const unique_ptr<Item>& item,
const uint32_t pos) {
vector<KeyParameter> params;
auto mapItem = getItemAtPos(item, pos);
if (!mapItem || (MajorType::MAP != getType(mapItem.value()))) return std::nullopt;
const Map* map = mapItem.value().get()->asMap();
size_t mapSize = map->size();
for (int i = 0; i < mapSize; i++) {
auto optKeyParams = getKeyParameter((*map)[i]);
if (optKeyParams) {
params.insert(params.end(), optKeyParams->begin(), optKeyParams->end());
} else {
return std::nullopt;
}
}
return params;
}
std::tuple<std::unique_ptr<Item>, keymaster_error_t>
CborConverter::decodeData(const std::vector<uint8_t>& response) {
auto [item, pos, message] = cppbor::parse(response);
if (!item || MajorType::ARRAY != getType(item)) {
return {nullptr, KM_ERROR_UNKNOWN_ERROR};
}
auto optErrorCode = getErrorCode(item, 0);
if (!optErrorCode) {
return {nullptr, KM_ERROR_UNKNOWN_ERROR};
}
return {std::move(item), optErrorCode.value()};
}
std::optional<keymaster_error_t>
CborConverter::getErrorCode(const std::unique_ptr<cppbor::Item>& item, const uint32_t pos) {
auto optErrorVal = getUint64(item, pos);
if (!optErrorVal) {
return std::nullopt;
}
return static_cast<keymaster_error_t>(0 - optErrorVal.value());
}
std::optional<uint64_t> CborConverter::getUint64(const unique_ptr<Item>& item) {
if ((item == nullptr) || (MajorType::UINT != getType(item))) {
return std::nullopt;
}
const Uint* uintVal = item.get()->asUint();
return uintVal->unsignedValue();
}
std::optional<uint64_t> CborConverter::getUint64(const unique_ptr<Item>& item, const uint32_t pos) {
auto intItem = getItemAtPos(item, pos);
if (!intItem) {
return std::nullopt;
}
return getUint64(intItem.value());
}
} // namespace keymint::javacard