blob: 3c569a004b46dc430f3b0239fa7c7e3826e3f9f8 [file] [log] [blame]
/*
* Copyright 2017, 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 "KeymasterDevice.h"
#include "buffer.h"
#include "export_key.h"
#include "certs.h"
#include "import_key.h"
#include "import_wrapped_key.h"
#include "proto_utils.h"
#include <Keymaster.client.h>
#include <nos/debug.h>
#include <nos/NuggetClient.h>
#include <keymasterV4_0/key_param_output.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <algorithm>
#include <time.h>
namespace android {
namespace hardware {
namespace keymaster {
namespace {
constexpr char PROPERTY_OS_VERSION[] = "ro.build.version.release";
constexpr char PROPERTY_OS_PATCHLEVEL[] = "ro.build.version.security_patch";
constexpr char PROPERTY_VENDOR_PATCHLEVEL[] = "ro.vendor.build.security_patch";
std::string DigitsOnly(const std::string& code) {
// Keep digits only.
std::string filtered_code;
std::copy_if(code.begin(), code.end(), std::back_inserter(filtered_code),
isdigit);
return filtered_code;
}
/** Get one version number from a string and move loc to the point after the
* next version delimiter.
*/
uint32_t ExtractVersion(const std::string& version, size_t* loc) {
if (*loc == std::string::npos || *loc >= version.size()) {
return 0;
}
uint32_t value = 0;
size_t new_loc = version.find('.', *loc);
if (new_loc == std::string::npos) {
auto sanitized = DigitsOnly(version.substr(*loc));
if (!sanitized.empty()) {
if (sanitized.size() < version.size() - *loc) {
LOG(ERROR) << "Unexpected version format: \"" << version
<< "\"";
}
value = std::stoi(sanitized);
}
*loc = new_loc;
} else {
auto sanitized = DigitsOnly(version.substr(*loc, new_loc - *loc));
if (!sanitized.empty()) {
if (sanitized.size() < new_loc - *loc) {
LOG(ERROR) << "Unexpected version format: \"" << version
<< "\"";
}
value = std::stoi(sanitized);
}
*loc = new_loc + 1;
}
return value;
}
uint32_t VersionToUint32(const std::string& version) {
size_t loc = 0;
uint32_t major = ExtractVersion(version, &loc);
uint32_t minor = ExtractVersion(version, &loc);
uint32_t subminor = ExtractVersion(version, &loc);
return major * 10000 + minor * 100 + subminor;
}
uint32_t DateCodeToUint32(const std::string& code, bool include_day) {
// Keep digits only.
std::string filtered_code = DigitsOnly(code);
// Return 0 if the date string has an unexpected number of digits.
uint32_t return_value = 0;
if (filtered_code.size() == 8) {
return_value = std::stoi(filtered_code);
if (!include_day) {
return_value /= 100;
}
} else if (filtered_code.size() == 6) {
return_value = std::stoi(filtered_code);
if (include_day) {
return_value *= 100;
}
} else {
LOG(ERROR) << "Unexpected patchset format: \"" << code << "\"";
}
return return_value;
}
// Helper class to call a finalizer on stack unwind.
class Finalize {
private:
std::function<void()> f_;
public:
Finalize(std::function<void()> f) : f_(f) {}
~Finalize() { if (f_) f_(); }
void release() { f_ = {}; }
};
} // namespace
// std
using std::string;
// base
using ::android::base::GetProperty;
using ::android::base::WaitForPropertyCreation;
// libhidl
using ::android::hardware::Void;
// HAL
using ::android::hardware::keymaster::V4_0::Algorithm;
using ::android::hardware::keymaster::V4_0::KeyCharacteristics;
using ::android::hardware::keymaster::V4_0::KeyFormat;
using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
using ::android::hardware::keymaster::V4_0::HardwareAuthenticatorType;
using ::android::hardware::keymaster::V4_0::SecurityLevel;
using ::android::hardware::keymaster::V4_0::Tag;
// nos
using nos::NuggetClient;
// Keymaster app
// KM 3.0 types
using ::nugget::app::keymaster::AddRngEntropyRequest;
using ::nugget::app::keymaster::AddRngEntropyResponse;
using ::nugget::app::keymaster::GenerateKeyRequest;
using ::nugget::app::keymaster::GenerateKeyResponse;
using ::nugget::app::keymaster::GetKeyCharacteristicsRequest;
using ::nugget::app::keymaster::GetKeyCharacteristicsResponse;
using ::nugget::app::keymaster::ImportKeyRequest;
using ::nugget::app::keymaster::ImportKeyResponse;
using ::nugget::app::keymaster::ExportKeyRequest;
using ::nugget::app::keymaster::ExportKeyResponse;
using ::nugget::app::keymaster::StartAttestKeyRequest;
using ::nugget::app::keymaster::StartAttestKeyResponse;
using ::nugget::app::keymaster::ContinueAttestKeyRequest;
using ::nugget::app::keymaster::ContinueAttestKeyResponse;
using ::nugget::app::keymaster::FinishAttestKeyRequest;
using ::nugget::app::keymaster::FinishAttestKeyResponse;
using ::nugget::app::keymaster::UpgradeKeyRequest;
using ::nugget::app::keymaster::UpgradeKeyResponse;
using ::nugget::app::keymaster::DeleteKeyRequest;
using ::nugget::app::keymaster::DeleteKeyResponse;
using ::nugget::app::keymaster::DeleteAllKeysRequest;
using ::nugget::app::keymaster::DeleteAllKeysResponse;
using ::nugget::app::keymaster::DestroyAttestationIdsRequest;
using ::nugget::app::keymaster::DestroyAttestationIdsResponse;
using ::nugget::app::keymaster::BeginOperationRequest;
using ::nugget::app::keymaster::BeginOperationResponse;
using ::nugget::app::keymaster::UpdateOperationRequest;
using ::nugget::app::keymaster::UpdateOperationResponse;
using ::nugget::app::keymaster::FinishOperationRequest;
using ::nugget::app::keymaster::FinishOperationResponse;
using ::nugget::app::keymaster::AbortOperationRequest;
using ::nugget::app::keymaster::AbortOperationResponse;
using ::nugget::app::keymaster::ComputeSharedHmacRequest;
using ::nugget::app::keymaster::ComputeSharedHmacResponse;
using ::nugget::app::keymaster::GetHmacSharingParametersRequest;
using ::nugget::app::keymaster::GetHmacSharingParametersResponse;
using ::nugget::app::keymaster::SetSystemVersionInfoRequest;
using ::nugget::app::keymaster::SetSystemVersionInfoResponse;
using ::nugget::app::keymaster::GetBootInfoRequest;
using ::nugget::app::keymaster::GetBootInfoResponse;
// KM 4.0 types
using ::nugget::app::keymaster::ImportWrappedKeyRequest;
namespace nosapp = ::nugget::app::keymaster;
// KM internal types
using ::nugget::app::keymaster::AttestationSelector;
static ErrorCode status_to_error_code(uint32_t status)
{
switch (status) {
case APP_SUCCESS:
return ErrorCode::OK;
break;
case APP_ERROR_BOGUS_ARGS:
return ErrorCode::INVALID_ARGUMENT;
break;
case APP_ERROR_INTERNAL:
return ErrorCode::UNKNOWN_ERROR;
break;
case APP_ERROR_TOO_MUCH:
return ErrorCode::INSUFFICIENT_BUFFER_SPACE;
break;
case APP_ERROR_RPC:
return ErrorCode::SECURE_HW_COMMUNICATION_FAILED;
break;
// TODO: app specific error codes go here.
default:
return ErrorCode::UNKNOWN_ERROR;
break;
}
}
#define KM_CALL(meth, request, response) { \
const uint32_t status = _keymaster. meth (request, &response); \
const ErrorCode error_code = translate_error_code(response.error_code()); \
if (status != APP_SUCCESS) { \
LOG(ERROR) << #meth << " : request failed with status: " \
<< nos::StatusCodeString(status); \
return status_to_error_code(status); \
} \
if (error_code != ErrorCode::OK) { \
LOG(ERROR) << #meth << " : device response error code: " \
<< error_code; \
return error_code; \
} \
}
#define KM_CALLV(meth, request, response, ...) { \
const uint32_t status = _keymaster. meth (request, &response); \
const ErrorCode error_code = translate_error_code(response.error_code()); \
if (status != APP_SUCCESS) { \
LOG(ERROR) << #meth << " : request failed with status: " \
<< nos::StatusCodeString(status); \
_hidl_cb(status_to_error_code(status), __VA_ARGS__); \
return Void(); \
} \
if (error_code != ErrorCode::OK) { \
LOG(ERROR) << #meth << " : device response error code: " \
<< error_code; \
_hidl_cb(error_code, __VA_ARGS__); \
return Void(); \
} \
}
// Methods from ::android::hardware::keymaster::V3_0::IKeymasterDevice follow.
KeymasterDevice::KeymasterDevice(KeymasterClient& keymaster) :
_keymaster{keymaster} {
// Block until all of the properties have been created
while (!(WaitForPropertyCreation(PROPERTY_OS_VERSION) &&
WaitForPropertyCreation(PROPERTY_OS_PATCHLEVEL) &&
WaitForPropertyCreation(PROPERTY_VENDOR_PATCHLEVEL))) {}
_os_version = VersionToUint32(GetProperty(PROPERTY_OS_VERSION, ""));
_os_patchlevel = DateCodeToUint32(GetProperty(PROPERTY_OS_PATCHLEVEL, ""),
false /* include_day */);
_vendor_patchlevel = DateCodeToUint32(
GetProperty(PROPERTY_VENDOR_PATCHLEVEL, ""),
true /* include_day */);
SendSystemVersionInfo();
GetBootInfo();
}
Return<void> KeymasterDevice::getHardwareInfo(
getHardwareInfo_cb _hidl_cb)
{
LOG(VERBOSE) << "Running KeymasterDevice::getHardwareInfo";
(void)_keymaster;
_hidl_cb(SecurityLevel::STRONGBOX,
string("CitadelKeymaster"), string("Google"));
return Void();
}
Return<void> KeymasterDevice::getHmacSharingParameters(
getHmacSharingParameters_cb _hidl_cb)
{
LOG(VERBOSE) << "Running KeymasterDevice::getHmacSharingParameters";
GetHmacSharingParametersRequest request;
GetHmacSharingParametersResponse response;
HmacSharingParameters result;
KM_CALLV(GetHmacSharingParameters, request, response, result);
ErrorCode ec = translate_error_code(response.error_code());
if (ec != ErrorCode::OK) {
_hidl_cb(ec, HmacSharingParameters());
}
const std::string & nonce = response.hmac_sharing_params().nonce();
const std::string & seed = response.hmac_sharing_params().seed();
if (seed.size() == 32) {
result.seed.setToExternal(reinterpret_cast<uint8_t*>(
const_cast<char*>(seed.data())),
seed.size(), false);
} else if (seed.size() != 0) {
LOG(ERROR) << "Citadel returned unexpected seed size: "
<< seed.size();
_hidl_cb(ErrorCode::UNKNOWN_ERROR, HmacSharingParameters());
return Void();
}
if (nonce.size() == result.nonce.size()) {
std::copy(nonce.begin(), nonce.end(), result.nonce.data());
} else {
LOG(ERROR) << "Citadel returned unexpected nonce size: "
<< nonce.size();
_hidl_cb(ErrorCode::UNKNOWN_ERROR, HmacSharingParameters());
return Void();
}
_hidl_cb(ec, result);
return Void();
}
Return<void> KeymasterDevice::computeSharedHmac(
const hidl_vec<HmacSharingParameters>& params,
computeSharedHmac_cb _hidl_cb)
{
LOG(VERBOSE) << "Running KeymasterDevice::computeSharedHmac";
ComputeSharedHmacRequest request;
ComputeSharedHmacResponse response;
hidl_vec<uint8_t> result;
for (const HmacSharingParameters & param : params) {
// TODO respect max number of parameters defined in
// keymaster_types.proto
nosapp::HmacSharingParameters* req_param =
request.add_hmac_sharing_params();
req_param->set_nonce(
reinterpret_cast<const int8_t*>(
param.nonce.data()), param.nonce.size());
req_param->set_seed(reinterpret_cast<const int8_t*>(param.seed.data()),
param.seed.size());
}
KM_CALLV(ComputeSharedHmac, request, response, result);
ErrorCode ec = translate_error_code(response.error_code());
if (ec != ErrorCode::OK) {
_hidl_cb(ec, result);
return Void();
}
const std::string & share_check = response.sharing_check();
result.setToExternal(reinterpret_cast<uint8_t*>(
const_cast<char*>(share_check.data())), share_check.size(), false);
_hidl_cb(ec, result);
return Void();
}
Return<void> KeymasterDevice::verifyAuthorization(
uint64_t operationHandle, const hidl_vec<KeyParameter>& parametersToVerify,
const HardwareAuthToken& authToken, verifyAuthorization_cb _hidl_cb)
{
LOG(VERBOSE) << "Running KeymasterDevice::verifyAuthorization";
(void)operationHandle;
(void)parametersToVerify;
(void)authToken;
(void)_keymaster;
_hidl_cb(ErrorCode::UNIMPLEMENTED, VerificationToken());
return Void();
}
Return<ErrorCode> KeymasterDevice::addRngEntropy(const hidl_vec<uint8_t>& data)
{
LOG(VERBOSE) << "Running KeymasterDevice::addRngEntropy";
if (!data.size()) return ErrorCode::OK;
const size_t chunk_size = 1024;
for (size_t i = 0; i < data.size(); i += chunk_size) {
AddRngEntropyRequest request;
AddRngEntropyResponse response;
request.set_data(&data[i], std::min(chunk_size, data.size() - i));
// Call device.
KM_CALL(AddRngEntropy, request, response);
}
return ErrorCode::OK;
}
Return<void> KeymasterDevice::generateKey(
const hidl_vec<KeyParameter>& keyParams,
generateKey_cb _hidl_cb)
{
LOG(VERBOSE) << "Running KeymasterDevice::generateKey";
GenerateKeyRequest request;
GenerateKeyResponse response;
hidl_vec<uint8_t> blob;
KeyCharacteristics characteristics;
if (hidl_params_to_pb(
keyParams, request.mutable_params()) != ErrorCode::OK) {
_hidl_cb(ErrorCode::INVALID_ARGUMENT, blob, characteristics);
return Void();
}
// Call device.
KM_CALLV(GenerateKey, request, response,
hidl_vec<uint8_t>{}, KeyCharacteristics());
blob.setToExternal(
reinterpret_cast<uint8_t*>(
const_cast<char*>(response.blob().blob().data())),
response.blob().blob().size(), false);
pb_to_hidl_params(response.characteristics().software_enforced(),
&characteristics.softwareEnforced);
pb_to_hidl_params(response.characteristics().tee_enforced(),
&characteristics.hardwareEnforced);
_hidl_cb(translate_error_code(response.error_code()),
blob, characteristics);
return Void();
}
Return<void> KeymasterDevice::getKeyCharacteristics(
const hidl_vec<uint8_t>& keyBlob,
const hidl_vec<uint8_t>& clientId,
const hidl_vec<uint8_t>& appData,
getKeyCharacteristics_cb _hidl_cb)
{
LOG(VERBOSE) << "Running KeymasterDevice::getKeyCharacteristics";
GetKeyCharacteristicsRequest request;
GetKeyCharacteristicsResponse response;
request.mutable_blob()->set_blob(&keyBlob[0], keyBlob.size());
request.set_client_id(&clientId[0], clientId.size());
request.set_app_data(&appData[0], appData.size());
// Call device.
KM_CALLV(GetKeyCharacteristics, request, response, KeyCharacteristics());
KeyCharacteristics characteristics;
pb_to_hidl_params(response.characteristics().software_enforced(),
&characteristics.softwareEnforced);
pb_to_hidl_params(response.characteristics().tee_enforced(),
&characteristics.hardwareEnforced);
_hidl_cb(translate_error_code(response.error_code()), characteristics);
return Void();
}
Return<void> KeymasterDevice::importKey(
const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb)
{
LOG(VERBOSE) << "Running KeymasterDevice::importKey";
ErrorCode error;
ImportKeyRequest request;
ImportKeyResponse response;
error = import_key_request(params, keyFormat, keyData, &request);
if (error != ErrorCode::OK) {
LOG(ERROR) << "ImportKey request parsing failed with error "
<< error;
_hidl_cb(error, hidl_vec<uint8_t>{}, KeyCharacteristics{});
return Void();
}
KM_CALLV(ImportKey, request, response,
hidl_vec<uint8_t>{}, KeyCharacteristics{});
hidl_vec<uint8_t> blob;
blob.setToExternal(
reinterpret_cast<uint8_t*>(
const_cast<char*>(response.blob().blob().data())),
response.blob().blob().size(), false);
KeyCharacteristics characteristics;
pb_to_hidl_params(response.characteristics().software_enforced(),
&characteristics.softwareEnforced);
error = pb_to_hidl_params(response.characteristics().tee_enforced(),
&characteristics.hardwareEnforced);
if (error != ErrorCode::OK) {
LOG(ERROR) << "KeymasterDevice::importKey: response tee_enforced :"
<< error;
_hidl_cb(error, hidl_vec<uint8_t>{}, KeyCharacteristics{});
return Void();
}
_hidl_cb(ErrorCode::OK, blob, characteristics);
return Void();
}
Return<void> KeymasterDevice::exportKey(
KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
const hidl_vec<uint8_t>& clientId,
const hidl_vec<uint8_t>& appData, exportKey_cb _hidl_cb)
{
LOG(VERBOSE) << "Running KeymasterDevice::exportKey";
ExportKeyRequest request;
ExportKeyResponse response;
request.set_format((::nugget::app::keymaster::KeyFormat)exportFormat);
request.mutable_blob()->set_blob(&keyBlob[0], keyBlob.size());
request.set_client_id(&clientId[0], clientId.size());
request.set_app_data(&appData[0], appData.size());
KM_CALLV(ExportKey, request, response, hidl_vec<uint8_t>{});
hidl_vec<uint8_t> der;
ErrorCode error_code = export_key_der(response, &der);
if (error_code != ErrorCode::OK) {
LOG(ERROR) << "KeymasterDevice::exportKey: DER conversion failed: "
<< error_code;
_hidl_cb(error_code, hidl_vec<uint8_t>{});
return Void();
}
_hidl_cb(error_code, der);
return Void();
}
#define ATTESTATION_APPLICATION_ID_MAX_SIZE 1024
#define UTCTIME_STR_WITH_NUL_SIZE 14
static size_t integer_size(uint64_t value)
{
size_t octet_count = 1;
for (value >>= 8; value; value >>= 8) {
octet_count++;
}
return octet_count;
}
static size_t encoded_length_size(size_t length)
{
if (length < 0x80) {
return 1;
}
return integer_size(length) + 1;
}
static uint8_t *asn1_encode_length(size_t length, const uint8_t *head, uint8_t *tail)
{
if (!tail || tail < head + encoded_length_size(length)) {
return NULL;
}
if (length < 0x80) {
// Short length case
*(--tail) = length;
} else {
// Encode length
uint8_t length_len;
uint8_t *orig_tail = tail;
do {
*(--tail) = length & 0xFF;
length >>= 8;
} while (length);
// Encode length of length. Assumes length < pow(128, 127).
// Should be good.
length_len = (orig_tail - tail);
*(--tail) = 0x80 | length_len;
}
return tail;
}
Return<void> KeymasterDevice::attestKey(
const hidl_vec<uint8_t>& keyToAttest,
const hidl_vec<KeyParameter>& attestParams,
attestKey_cb _hidl_cb)
{
LOG(VERBOSE) << "Running KeymasterDevice::attestKey";
StartAttestKeyRequest startRequest;
StartAttestKeyResponse startResponse;
// Ensure that required parameters are present.
tag_map_t attest_tag_map;
if (hidl_params_to_map(attestParams, &attest_tag_map) != ErrorCode::OK) {
_hidl_cb(ErrorCode::INVALID_ARGUMENT, hidl_vec<hidl_vec<uint8_t> >{});
return Void();
}
if (attest_tag_map.find(Tag::ATTESTATION_APPLICATION_ID) ==
attest_tag_map.end()) {
_hidl_cb(ErrorCode::ATTESTATION_APPLICATION_ID_MISSING,
hidl_vec<hidl_vec<uint8_t> >{});
return Void();
}
hidl_vec<uint8_t> client_id;
if (attest_tag_map.find(Tag::APPLICATION_ID) != attest_tag_map.end()) {
client_id = attest_tag_map.find(Tag::APPLICATION_ID)->second[0].blob;
}
hidl_vec<uint8_t> app_data;
if (attest_tag_map.find(Tag::APPLICATION_DATA) != attest_tag_map.end()) {
app_data = attest_tag_map.find(
Tag::APPLICATION_DATA)->second[0].blob;
}
GetKeyCharacteristicsRequest charRequest;
GetKeyCharacteristicsResponse charResponse;
charRequest.mutable_blob()->set_blob(&keyToAttest[0], keyToAttest.size());
charRequest.set_client_id(&client_id[0], client_id.size());
charRequest.set_app_data(&app_data[0], app_data.size());
// Call device.
KM_CALLV(GetKeyCharacteristics, charRequest,
charResponse, hidl_vec<hidl_vec<uint8_t> >{});
KeyCharacteristics characteristics;
pb_to_hidl_params(charResponse.characteristics().software_enforced(),
&characteristics.softwareEnforced);
pb_to_hidl_params(charResponse.characteristics().tee_enforced(),
&characteristics.hardwareEnforced);
tag_map_t char_tag_map;
if (hidl_params_to_map(characteristics.softwareEnforced,
&attest_tag_map) != ErrorCode::OK) {
_hidl_cb(ErrorCode::INVALID_ARGUMENT, hidl_vec<hidl_vec<uint8_t> >{});
return Void();
}
time_t not_before = 0;
if (char_tag_map.find(Tag::ACTIVE_DATETIME) != char_tag_map.end()) {
not_before = char_tag_map.find(
Tag::ACTIVE_DATETIME)->second[0].f.dateTime;
} else if (char_tag_map.find(Tag::CREATION_DATETIME) !=
char_tag_map.end()) {
not_before = char_tag_map.find(
Tag::CREATION_DATETIME)->second[0].f.dateTime;
}
// TODO: else: both ACTIVE and CREATION datetime are absent, is
// this an error?
time_t not_after = 0;
if (char_tag_map.find(Tag::USAGE_EXPIRE_DATETIME) != char_tag_map.end()) {
not_after = char_tag_map.find(
Tag::USAGE_EXPIRE_DATETIME)->second[0].f.dateTime;
} else {
not_after = 1842739199; // Batch cert expiry date: 2028-05-23:23:59:59.
}
char not_before_str[UTCTIME_STR_WITH_NUL_SIZE] = {};
char not_after_str[UTCTIME_STR_WITH_NUL_SIZE] = {};
if (::strftime(not_before_str, sizeof(not_before_str),
"%y%m%d%H%M%SZ", gmtime(&not_before)) == 0 ||
::strftime(not_after_str, sizeof(not_after_str),
"%y%m%d%H%M%SZ", gmtime(&not_after)) == 0) {
_hidl_cb(ErrorCode::UNKNOWN_ERROR, hidl_vec<hidl_vec<uint8_t> >{});
}
startRequest.mutable_blob()->set_blob(&keyToAttest[0], keyToAttest.size());
if (hidl_params_to_pb(
attestParams, startRequest.mutable_params()) != ErrorCode::OK) {
_hidl_cb(ErrorCode::INVALID_ARGUMENT, hidl_vec<hidl_vec<uint8_t> >{});
return Void();
}
// Developer configs (i.e. nodelocked-RO), and PROTO devices will
// fall back to TEST certs here, since BATCH certs will be
// unavailable. The selected certificate may be determined via
// info included in the response to FinishAttestKeyRequest().
startRequest.set_selector(AttestationSelector::ATTEST_BATCH);
startRequest.set_not_before(not_before_str,
sizeof(not_before_str) - 1);
startRequest.set_not_after(not_after_str,
sizeof(not_after_str) - 1);
// TODO: as an optimization, avoid sending the
// ATTESTATION_APPLICATION_ID to Start, since only the length of
// this field is needed at this stage.
// NOTE: citadel adds the AAID to the hash in the prologue for now. So if this
// is ever changes the HASH_update call needs to move in the citadel firmware.
KM_CALLV(StartAttestKey, startRequest, startResponse,
hidl_vec<hidl_vec<uint8_t> >{});
uint64_t operationHandle = startResponse.handle().handle();
ContinueAttestKeyRequest continueRequest;
ContinueAttestKeyResponse continueResponse;
// Prepare to abort the pending operation in event of an error.
Finalize finalize([&] () { abort(operationHandle); });
continueRequest.mutable_handle()->set_handle(operationHandle);
if (hidl_params_to_pb(
attestParams, continueRequest.mutable_params()) != ErrorCode::OK) {
LOG(ERROR) << "Failed to parse attest params";
_hidl_cb(ErrorCode::INVALID_ARGUMENT, hidl_vec<hidl_vec<uint8_t> >{});
return Void();
}
KM_CALLV(ContinueAttestKey, continueRequest, continueResponse,
hidl_vec<hidl_vec<uint8_t> >{});
FinishAttestKeyRequest finishRequest;
FinishAttestKeyResponse finishResponse;
finishRequest.mutable_handle()->set_handle(operationHandle);
KM_CALLV(FinishAttestKey, finishRequest, finishResponse,
hidl_vec<hidl_vec<uint8_t> >{});
hidl_vec<uint8_t>& attestation_application_id =
attest_tag_map[Tag::ATTESTATION_APPLICATION_ID].begin()->blob;
size_t cert_len = startResponse.certificate_prologue().size()
+ attestation_application_id.size()
+ continueResponse.certificate_body().size()
+ finishResponse.certificate_epilogue().size();
std::stringstream ss;
{
char c = 0x30;
ss.write(&c, 1); // DER_SEQUENCE | DER_CONSTRUCTED
uint8_t buffer[10];
auto * cert_header = asn1_encode_length(cert_len, buffer, buffer + sizeof(buffer));
if (cert_header == nullptr) {
LOG(ERROR) << "Failed to generate attestation certificate sequence header";
_hidl_cb(ErrorCode::UNKNOWN_ERROR, hidl_vec<hidl_vec<uint8_t> >{});
return Void();
}
ss.write(reinterpret_cast<char*>(cert_header), buffer + sizeof(buffer) - cert_header);
}
ss << startResponse.certificate_prologue();
ss.write(reinterpret_cast<const std::stringstream::char_type*>(
attestation_application_id.data()), attestation_application_id.size());
ss << continueResponse.certificate_body();
ss << finishResponse.certificate_epilogue();
if (!ss) {
LOG(ERROR) << "Failed to generate attestation certificate";
_hidl_cb(ErrorCode::UNKNOWN_ERROR, hidl_vec<hidl_vec<uint8_t> >{});
return Void();
}
vector<hidl_vec<uint8_t> > chain;
{
hidl_vec<uint8_t> attestation_certificate;
attestation_certificate.setToExternal(
reinterpret_cast<uint8_t*>(
const_cast<char*>(ss.str().data())),
ss.str().size(), false);
chain.push_back(std::move(attestation_certificate));
hidl_vec<uint8_t> batch_cert;
hidl_vec<uint8_t> intermediate_cert;
hidl_vec<uint8_t> root;
for (const KeyParameter &param : characteristics.hardwareEnforced) {
if (param.tag != Tag::ALGORITHM) {
continue;
}
// Node-locked RO implies that factory provisioned certs
// (if any), are inaccessible, so fallback to the TEST
// certs. Similarly, PROTO chips were not provisioned
// with certs, and hence will fallback to TEST certs.
if (finishResponse.nodelocked_ro() ||
finishResponse.chip_fusing() == nosapp::FUSING_PROTO) {
if (param.f.algorithm == Algorithm::RSA) {
batch_cert.setToExternal(
const_cast<uint8_t*>(
TEST_BATCH_RSA_CERT),
sizeof(TEST_BATCH_RSA_CERT));
intermediate_cert.setToExternal(
const_cast<uint8_t*>(
TEST_BATCH_RSA_INT_CERT),
sizeof(TEST_BATCH_RSA_INT_CERT));
root.setToExternal(
const_cast<uint8_t*>(
TEST_BATCH_ROOT_CERT),
sizeof(TEST_BATCH_ROOT_CERT));
} else {
batch_cert.setToExternal(
const_cast<uint8_t*>(
TEST_BATCH_EC_CERT),
sizeof(TEST_BATCH_EC_CERT));
intermediate_cert.setToExternal(
const_cast<uint8_t*>(
TEST_BATCH_EC_INT_CERT),
sizeof(TEST_BATCH_EC_INT_CERT));
root.setToExternal(
const_cast<uint8_t*>(
TEST_BATCH_ROOT_CERT),
sizeof(TEST_BATCH_ROOT_CERT));
}
} else if (finishResponse.chip_fusing() == nosapp::FUSING_DVT) {
if (param.f.algorithm == Algorithm::RSA) {
batch_cert.setToExternal(
const_cast<uint8_t*>(DEV_BATCH_RSA_CERT),
sizeof(DEV_BATCH_RSA_CERT));
intermediate_cert.setToExternal(
const_cast<uint8_t*>(DEV_BATCH_RSA_INT_CERT),
sizeof(DEV_BATCH_RSA_INT_CERT));
} else {
batch_cert.setToExternal(
const_cast<uint8_t*>(DEV_BATCH_EC_CERT),
sizeof(DEV_BATCH_EC_CERT));
intermediate_cert.setToExternal(
const_cast<uint8_t*>(DEV_BATCH_EC_INT_CERT),
sizeof(DEV_BATCH_EC_INT_CERT));
}
root.setToExternal(
const_cast<uint8_t*>(DEV_BATCH_ROOT_CERT),
sizeof(DEV_BATCH_ROOT_CERT));
} else { // PVT!
if (param.f.algorithm == Algorithm::RSA) {
batch_cert.setToExternal(
const_cast<uint8_t*>(PROD_BATCH_RSA_CERT),
sizeof(PROD_BATCH_RSA_CERT));
intermediate_cert.setToExternal(
const_cast<uint8_t*>(PROD_BATCH_RSA_INT_CERT),
sizeof(PROD_BATCH_RSA_INT_CERT));
} else {
batch_cert.setToExternal(
const_cast<uint8_t*>(PROD_BATCH_EC_CERT),
sizeof(PROD_BATCH_EC_CERT));
intermediate_cert.setToExternal(
const_cast<uint8_t*>(PROD_BATCH_EC_INT_CERT),
sizeof(PROD_BATCH_EC_INT_CERT));
}
root.setToExternal(
const_cast<uint8_t*>(PROD_BATCH_ROOT_CERT),
sizeof(PROD_BATCH_ROOT_CERT));
}
break; // we found the ALGORITM tag so we can break the loop
}
chain.push_back(std::move(batch_cert));
chain.push_back(std::move(intermediate_cert));
chain.push_back(std::move(root));
}
_hidl_cb(ErrorCode::OK, chain);
finalize.release();
return Void();
}
Return<void> KeymasterDevice::upgradeKey(
const hidl_vec<uint8_t>& keyBlobToUpgrade,
const hidl_vec<KeyParameter>& upgradeParams,
upgradeKey_cb _hidl_cb)
{
LOG(VERBOSE) << "Running KeymasterDevice::upgradeKey";
UpgradeKeyRequest request;
UpgradeKeyResponse response;
request.mutable_blob()->set_blob(&keyBlobToUpgrade[0],
keyBlobToUpgrade.size());
hidl_vec<uint8_t> blob;
if (hidl_params_to_pb(
upgradeParams, request.mutable_params()) != ErrorCode::OK) {
_hidl_cb(ErrorCode::INVALID_ARGUMENT, blob);
return Void();
}
KM_CALLV(UpgradeKey, request, response, hidl_vec<uint8_t>{});
blob.setToExternal(
reinterpret_cast<uint8_t*>(
const_cast<char*>(response.blob().blob().data())),
response.blob().blob().size(), false);
_hidl_cb(translate_error_code(response.error_code()), blob);
return Void();
}
Return<ErrorCode> KeymasterDevice::deleteKey(const hidl_vec<uint8_t>& keyBlob)
{
LOG(VERBOSE) << "Running KeymasterDevice::deleteKey";
DeleteKeyRequest request;
DeleteKeyResponse response;
request.mutable_blob()->set_blob(&keyBlob[0], keyBlob.size());
KM_CALL(DeleteKey, request, response);
return translate_error_code(response.error_code());
}
Return<ErrorCode> KeymasterDevice::deleteAllKeys()
{
LOG(VERBOSE) << "Running KeymasterDevice::deleteAllKeys";
DeleteAllKeysRequest request;
DeleteAllKeysResponse response;
KM_CALL(DeleteAllKeys, request, response);
return translate_error_code(response.error_code());
}
Return<ErrorCode> KeymasterDevice::destroyAttestationIds()
{
LOG(VERBOSE) << "Running KeymasterDevice::destroyAttestationIds";
DestroyAttestationIdsRequest request;
DestroyAttestationIdsResponse response;
KM_CALL(DestroyAttestationIds, request, response);
return translate_error_code(response.error_code());
}
Return<void> KeymasterDevice::begin(
KeyPurpose purpose, const hidl_vec<uint8_t>& key,
const hidl_vec<KeyParameter>& inParams,
const HardwareAuthToken& authToken,
begin_cb _hidl_cb)
{
LOG(VERBOSE) << "Running KeymasterDevice::begin";
BeginOperationRequest request;
BeginOperationResponse response;
request.set_purpose((::nugget::app::keymaster::KeyPurpose)purpose);
request.mutable_blob()->set_blob(&key[0], key.size());
hidl_vec<KeyParameter> params;
if (translate_auth_token(
authToken, request.mutable_auth_token()) != ErrorCode::OK) {
_hidl_cb(ErrorCode::INVALID_ARGUMENT, params,
response.handle().handle());
return Void();
}
if (hidl_params_to_pb(
inParams, request.mutable_params()) != ErrorCode::OK) {
_hidl_cb(ErrorCode::INVALID_ARGUMENT, params,
response.handle().handle());
return Void();
}
tag_map_t tag_map;
if (hidl_params_to_map(inParams, &tag_map) != ErrorCode::OK) {
_hidl_cb(ErrorCode::INVALID_ARGUMENT, params,
response.handle().handle());
return Void();
}
KM_CALLV(BeginOperation, request, response, hidl_vec<KeyParameter>{}, 0);
// Setup HAL buffering for this operation's data.
Algorithm algorithm;
if (translate_algorithm(response.algorithm(), &algorithm) !=
ErrorCode::OK) {
if (this->abort(response.handle().handle()) != ErrorCode::OK) {
LOG(ERROR) << "abort( " << response.handle().handle()
<< ") failed";
}
_hidl_cb(ErrorCode::INVALID_ARGUMENT, params,
response.handle().handle());
return Void();
}
ErrorCode error_code = buffer_begin(response.handle().handle(), algorithm);
if (error_code != ErrorCode::OK) {
if (this->abort(response.handle().handle()) != ErrorCode::OK) {
LOG(ERROR) << "abort( " << response.handle().handle()
<< ") failed";
}
_hidl_cb(ErrorCode::UNKNOWN_ERROR, params,
response.handle().handle());
return Void();
}
pb_to_hidl_params(response.params(), &params);
_hidl_cb(translate_error_code(response.error_code()), params,
response.handle().handle());
return Void();
}
Return<void> KeymasterDevice::update(
uint64_t operationHandle,
const hidl_vec<KeyParameter>& inParams,
const hidl_vec<uint8_t>& input,
const HardwareAuthToken& authToken,
const VerificationToken& verificationToken,
update_cb _hidl_cb)
{
LOG(VERBOSE) << "Running KeymasterDevice::update";
UpdateOperationRequest request;
UpdateOperationResponse response;
// TODO: does keystore chunk stream data? To what quantum?
if (input.size() > KM_MAX_PROTO_FIELD_SIZE) {
LOG(ERROR) << "Excess input length: " << input.size()
<< " max allowed: " << KM_MAX_PROTO_FIELD_SIZE;
if (this->abort(operationHandle) != ErrorCode::OK) {
LOG(ERROR) << "abort( " << operationHandle
<< ") failed";
}
_hidl_cb(ErrorCode::INVALID_INPUT_LENGTH, 0,
hidl_vec<KeyParameter>{}, hidl_vec<uint8_t>{});
return Void();
}
uint32_t consumed;
hidl_vec<uint8_t> output;
hidl_vec<KeyParameter> params;
ErrorCode error_code;
error_code = buffer_append(operationHandle, input, &consumed);
if (error_code != ErrorCode::OK) {
_hidl_cb(error_code, 0, params, output);
return Void();
}
hidl_vec<uint8_t> blocks;
error_code = buffer_peek(operationHandle, &blocks);
if (error_code != ErrorCode::OK) {
_hidl_cb(error_code, 0, params, output);
return Void();
}
// blocks.size() may be zero, but do a round-trip none-the-less
// since this may be GCM, there may be AAD data in params.
// TODO: as an optimization, do some inspection apriori.
request.mutable_handle()->set_handle(operationHandle);
if (hidl_params_to_pb(
inParams, request.mutable_params()) != ErrorCode::OK) {
_hidl_cb(ErrorCode::INVALID_ARGUMENT, 0, params, output);
return Void();
}
request.set_input(&blocks[0], blocks.size());
if (translate_auth_token(
authToken, request.mutable_auth_token()) != ErrorCode::OK) {
_hidl_cb(ErrorCode::INVALID_ARGUMENT, 0, params, output);
return Void();
}
translate_verification_token(verificationToken,
request.mutable_verification_token());
KM_CALLV(UpdateOperation, request, response,
0, hidl_vec<KeyParameter>{}, hidl_vec<uint8_t>{});
if (buffer_advance(operationHandle, response.consumed()) != ErrorCode::OK) {
_hidl_cb(ErrorCode::UNKNOWN_ERROR, 0, params, output);
return Void();
}
pb_to_hidl_params(response.params(), &params);
output.setToExternal(
reinterpret_cast<uint8_t*>(const_cast<char*>(response.output().data())),
response.output().size(), false);
_hidl_cb(ErrorCode::OK, consumed, params, output);
return Void();
}
Return<void> KeymasterDevice::finish(
uint64_t operationHandle,
const hidl_vec<KeyParameter>& inParams,
const hidl_vec<uint8_t>& input,
const hidl_vec<uint8_t>& signature,
const HardwareAuthToken& authToken,
const VerificationToken& verificationToken,
finish_cb _hidl_cb)
{
LOG(VERBOSE) << "Running KeymasterDevice::finish";
FinishOperationRequest request;
FinishOperationResponse response;
if (input.size() > KM_MAX_PROTO_FIELD_SIZE) {
LOG(ERROR) << "Excess input length: " << input.size()
<< " max allowed: " << KM_MAX_PROTO_FIELD_SIZE;
if (this->abort(operationHandle) != ErrorCode::OK) {
LOG(ERROR) << "abort( " << operationHandle
<< ") failed";
}
_hidl_cb(ErrorCode::INVALID_INPUT_LENGTH,
hidl_vec<KeyParameter>{}, hidl_vec<uint8_t>{});
return Void();
}
uint32_t consumed;
ErrorCode error_code;
error_code = buffer_append(operationHandle, input, &consumed);
if (error_code != ErrorCode::OK) {
_hidl_cb(error_code,
hidl_vec<KeyParameter>{}, hidl_vec<uint8_t>{});
return Void();
}
hidl_vec<uint8_t> data;
error_code = buffer_final(operationHandle, &data);
if (error_code != ErrorCode::OK) {
_hidl_cb(error_code,
hidl_vec<KeyParameter>{}, hidl_vec<uint8_t>{});
return Void();
}
request.mutable_handle()->set_handle(operationHandle);
hidl_vec<KeyParameter> params;
hidl_vec<uint8_t> output;
if (hidl_params_to_pb(
inParams, request.mutable_params()) != ErrorCode::OK) {
_hidl_cb(ErrorCode::INVALID_ARGUMENT, params, output);
return Void();
}
request.set_input(&data[0], data.size());
request.set_signature(&signature[0], signature.size());
if (translate_auth_token(
authToken, request.mutable_auth_token()) != ErrorCode::OK) {
_hidl_cb(ErrorCode::INVALID_ARGUMENT, params, output);
return Void();
}
translate_verification_token(verificationToken,
request.mutable_verification_token());
KM_CALLV(FinishOperation, request, response,
hidl_vec<KeyParameter>{}, hidl_vec<uint8_t>{});
pb_to_hidl_params(response.params(), &params);
output.setToExternal(
reinterpret_cast<uint8_t*>(const_cast<char*>(response.output().data())),
response.output().size(), false);
_hidl_cb(ErrorCode::OK, params, output);
return Void();
}
Return<ErrorCode> KeymasterDevice::abort(uint64_t operationHandle)
{
LOG(VERBOSE) << "Running KeymasterDevice::abort";
AbortOperationRequest request;
AbortOperationResponse response;
request.mutable_handle()->set_handle(operationHandle);
KM_CALL(AbortOperation, request, response);
return ErrorCode::OK;
}
// Methods from ::android::hardware::keymaster::V4_0::IKeymasterDevice follow.
Return<void> KeymasterDevice::importWrappedKey(
const hidl_vec<uint8_t>& wrappedKeyData,
const hidl_vec<uint8_t>& wrappingKeyBlob,
const hidl_vec<uint8_t>& maskingKey,
const hidl_vec<KeyParameter>& /* unwrappingParams */,
uint64_t /* passwordSid */, uint64_t /* biometricSid */,
importWrappedKey_cb _hidl_cb)
{
LOG(VERBOSE) << "Running KeymasterDevice::importWrappedKey";
ErrorCode error;
ImportWrappedKeyRequest request;
ImportKeyResponse response;
if (maskingKey.size() != KM_WRAPPER_MASKING_KEY_SIZE) {
_hidl_cb(ErrorCode::INVALID_ARGUMENT, hidl_vec<uint8_t>{},
KeyCharacteristics{});
return Void();
}
error = import_wrapped_key_request(wrappedKeyData, wrappingKeyBlob,
maskingKey, &request);
if (error != ErrorCode::OK) {
LOG(ERROR) << "ImportWrappedKey request parsing failed with error "
<< error;
_hidl_cb(error, hidl_vec<uint8_t>{}, KeyCharacteristics{});
return Void();
}
KM_CALLV(ImportWrappedKey, request, response,
hidl_vec<uint8_t>{}, KeyCharacteristics{});
hidl_vec<uint8_t> blob;
blob.setToExternal(
reinterpret_cast<uint8_t*>(
const_cast<char*>(response.blob().blob().data())),
response.blob().blob().size(), false);
KeyCharacteristics characteristics;
// TODO: anything to do here with softwareEnforced?
pb_to_hidl_params(response.characteristics().software_enforced(),
&characteristics.softwareEnforced);
error = pb_to_hidl_params(response.characteristics().tee_enforced(),
&characteristics.hardwareEnforced);
if (error != ErrorCode::OK) {
LOG(ERROR) <<
"KeymasterDevice::importWrappedKey: response tee_enforced :"
<< error;
_hidl_cb(error, hidl_vec<uint8_t>{}, KeyCharacteristics{});
return Void();
}
_hidl_cb(ErrorCode::OK, blob, characteristics);
return Void();
}
// Private methods.
Return<ErrorCode> KeymasterDevice::SendSystemVersionInfo() const {
SetSystemVersionInfoRequest request;
SetSystemVersionInfoResponse response;
request.set_system_version(_os_version);
request.set_system_security_level(_os_patchlevel);
request.set_vendor_security_level(_vendor_patchlevel);
KM_CALL(SetSystemVersionInfo, request, response);
return ErrorCode::OK;
}
Return<ErrorCode> KeymasterDevice::GetBootInfo() {
GetBootInfoRequest request;
GetBootInfoResponse response;
KM_CALL(GetBootInfo, request, response);
_is_unlocked = response.is_unlocked();
_boot_color = response.boot_color();
_boot_key.assign(response.boot_key().begin(), response.boot_key().end());
_boot_hash.assign(response.boot_hash().begin(), response.boot_hash().end());
return ErrorCode::OK;
}
} // namespace keymaster
} // namespace hardware
} // namespace android