blob: 850d48ba2aefdb7eab7511c7cc1ff6e6f49ba319 [file] [log] [blame]
//
// Copyright (C) 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 "tpm_keymaster_context.h"
#include <android-base/logging.h>
#include <keymaster/contexts/soft_attestation_cert.h>
#include <keymaster/km_openssl/aes_key.h>
#include <keymaster/km_openssl/asymmetric_key.h>
#include <keymaster/km_openssl/attestation_utils.h>
#include <keymaster/km_openssl/certificate_utils.h>
#include <keymaster/km_openssl/ec_key_factory.h>
#include <keymaster/km_openssl/hmac_key.h>
#include <keymaster/km_openssl/rsa_key_factory.h>
#include <keymaster/km_openssl/soft_keymaster_enforcement.h>
#include <keymaster/km_openssl/triple_des_key.h>
#include "host/commands/secure_env/tpm_attestation_record.h"
#include "host/commands/secure_env/tpm_random_source.h"
#include "host/commands/secure_env/tpm_key_blob_maker.h"
using keymaster::AuthorizationSet;
using keymaster::KeymasterKeyBlob;
using keymaster::KeyFactory;
using keymaster::OperationFactory;
TpmKeymasterContext::TpmKeymasterContext(
TpmResourceManager& resource_manager,
keymaster::KeymasterEnforcement& enforcement)
: resource_manager_(resource_manager)
, enforcement_(enforcement)
, key_blob_maker_(new TpmKeyBlobMaker(resource_manager_))
, random_source_(new TpmRandomSource(resource_manager_.Esys()))
, attestation_context_(new TpmAttestationRecordContext()) {
key_factories_.emplace(
KM_ALGORITHM_RSA, new keymaster::RsaKeyFactory(*key_blob_maker_, *this));
key_factories_.emplace(
KM_ALGORITHM_EC, new keymaster::EcKeyFactory(*key_blob_maker_, *this));
key_factories_.emplace(
KM_ALGORITHM_AES,
new keymaster::AesKeyFactory(*key_blob_maker_, *random_source_));
key_factories_.emplace(
KM_ALGORITHM_TRIPLE_DES,
new keymaster::TripleDesKeyFactory(*key_blob_maker_, *random_source_));
key_factories_.emplace(
KM_ALGORITHM_HMAC,
new keymaster::HmacKeyFactory(*key_blob_maker_, *random_source_));
for (const auto& it : key_factories_) {
supported_algorithms_.push_back(it.first);
}
}
keymaster_error_t TpmKeymasterContext::SetSystemVersion(
uint32_t os_version, uint32_t os_patchlevel) {
// TODO(b/155697375): Only accept new values of these from the bootloader
os_version_ = os_version;
os_patchlevel_ = os_patchlevel;
key_blob_maker_->SetSystemVersion(os_version, os_patchlevel);
return KM_ERROR_OK;
}
void TpmKeymasterContext::GetSystemVersion(
uint32_t* os_version, uint32_t* os_patchlevel) const {
*os_version = os_version_;
*os_patchlevel = os_patchlevel_;
}
const KeyFactory* TpmKeymasterContext::GetKeyFactory(
keymaster_algorithm_t algorithm) const {
auto it = key_factories_.find(algorithm);
if (it == key_factories_.end()) {
LOG(ERROR) << "Could not find key factory for " << algorithm;
return nullptr;
}
return it->second.get();
}
const OperationFactory* TpmKeymasterContext::GetOperationFactory(
keymaster_algorithm_t algorithm, keymaster_purpose_t purpose) const {
auto key_factory = GetKeyFactory(algorithm);
if (key_factory == nullptr) {
LOG(ERROR) << "Tried to get operation factory for " << purpose
<< " for invalid algorithm " << algorithm;
return nullptr;
}
auto operation_factory = key_factory->GetOperationFactory(purpose);
if (operation_factory == nullptr) {
LOG(ERROR) << "Could not get operation factory for " << purpose
<< " from key factory for " << algorithm;
}
return operation_factory;
}
const keymaster_algorithm_t* TpmKeymasterContext::GetSupportedAlgorithms(
size_t* algorithms_count) const {
*algorithms_count = supported_algorithms_.size();
return supported_algorithms_.data();
}
// Based on https://cs.android.com/android/platform/superproject/+/master:system/keymaster/key_blob_utils/software_keyblobs.cpp;l=44;drc=master
static bool UpgradeIntegerTag(
keymaster_tag_t tag,
uint32_t value,
AuthorizationSet* set,
bool* set_changed) {
int index = set->find(tag);
if (index == -1) {
keymaster_key_param_t param;
param.tag = tag;
param.integer = value;
set->push_back(param);
*set_changed = true;
return true;
}
if (set->params[index].integer > value) {
return false;
}
if (set->params[index].integer != value) {
set->params[index].integer = value;
*set_changed = true;
}
return true;
}
// Based on https://cs.android.com/android/platform/superproject/+/master:system/keymaster/key_blob_utils/software_keyblobs.cpp;l=310;drc=master
keymaster_error_t TpmKeymasterContext::UpgradeKeyBlob(
const KeymasterKeyBlob& blob_to_upgrade,
const AuthorizationSet& upgrade_params,
KeymasterKeyBlob* upgraded_key) const {
keymaster::UniquePtr<keymaster::Key> key;
auto error = ParseKeyBlob(blob_to_upgrade, upgrade_params, &key);
if (error != KM_ERROR_OK) {
LOG(ERROR) << "Failed to parse key blob";
return error;
}
bool set_changed = false;
if (os_version_ == 0) {
// We need to allow "upgrading" OS version to zero, to support upgrading
// from proper numbered releases to unnumbered development and preview
// releases.
int key_os_version_pos = key->hw_enforced().find(keymaster::TAG_OS_VERSION);
if (key_os_version_pos != -1) {
uint32_t key_os_version = key->hw_enforced()[key_os_version_pos].integer;
if (key_os_version != 0) {
key->hw_enforced()[key_os_version_pos].integer = os_version_;
set_changed = true;
}
}
}
auto update_os = UpgradeIntegerTag(keymaster::TAG_OS_VERSION, os_version_,
&key->hw_enforced(), &set_changed);
auto update_patchlevel =
UpgradeIntegerTag(keymaster::TAG_OS_PATCHLEVEL, os_patchlevel_,
&key->hw_enforced(), &set_changed);
if (!update_os || !update_patchlevel) {
LOG(ERROR) << "One of the version fields would have been a downgrade. "
<< "Not allowed.";
return KM_ERROR_INVALID_ARGUMENT;
}
if (!set_changed) {
// Don't need an upgrade.
return KM_ERROR_OK;
}
return key_blob_maker_->UnvalidatedCreateKeyBlob(
key->key_material(), key->hw_enforced(), key->sw_enforced(),
upgraded_key);
}
keymaster_error_t TpmKeymasterContext::ParseKeyBlob(
const KeymasterKeyBlob& blob,
const AuthorizationSet& additional_params,
keymaster::UniquePtr<keymaster::Key>* key) const {
keymaster::AuthorizationSet hw_enforced;
keymaster::AuthorizationSet sw_enforced;
keymaster::KeymasterKeyBlob key_material;
auto rc =
key_blob_maker_->UnwrapKeyBlob(
blob,
&hw_enforced,
&sw_enforced,
&key_material);
if (rc != KM_ERROR_OK) {
LOG(ERROR) << "Failed to unwrap key: " << rc;
return rc;
}
keymaster_algorithm_t algorithm;
if (!hw_enforced.GetTagValue(keymaster::TAG_ALGORITHM, &algorithm) &&
!sw_enforced.GetTagValue(keymaster::TAG_ALGORITHM, &algorithm)) {
LOG(ERROR) << "No TAG_ALGORITHM value in hw_enforced or sw_enforced.";
return KM_ERROR_UNKNOWN_ERROR;
}
auto factory = GetKeyFactory(algorithm);
if (factory == nullptr) {
LOG(ERROR) << "Unable to find key factory for " << algorithm;
return KM_ERROR_UNSUPPORTED_ALGORITHM;
}
rc =
factory->LoadKey(
std::move(key_material),
additional_params,
std::move(hw_enforced),
std::move(sw_enforced),
key);
if (rc != KM_ERROR_OK) {
LOG(ERROR) << "Unable to load unwrapped key: " << rc;
}
return rc;
}
keymaster_error_t TpmKeymasterContext::AddRngEntropy(
const uint8_t* buffer, size_t size) const {
return random_source_->AddRngEntropy(buffer, size);
}
keymaster::KeymasterEnforcement* TpmKeymasterContext::enforcement_policy() {
return &enforcement_;
}
// Based on https://cs.android.com/android/platform/superproject/+/master:system/keymaster/contexts/pure_soft_keymaster_context.cpp;l=261;drc=8367d5351c4d417a11f49b12394b63a413faa02d
keymaster::CertificateChain TpmKeymasterContext::GenerateAttestation(
const keymaster::Key& key, const keymaster::AuthorizationSet& attest_params,
keymaster::UniquePtr<keymaster::Key> /* attest_key */,
const keymaster::KeymasterBlob& /* issuer_subject */,
keymaster_error_t* error) const {
LOG(INFO) << "TODO(b/155697200): Link attestation back to the TPM";
keymaster_algorithm_t key_algorithm;
if (!key.authorizations().GetTagValue(keymaster::TAG_ALGORITHM,
&key_algorithm)) {
*error = KM_ERROR_UNKNOWN_ERROR;
return {};
}
if ((key_algorithm != KM_ALGORITHM_RSA && key_algorithm != KM_ALGORITHM_EC)) {
*error = KM_ERROR_INCOMPATIBLE_ALGORITHM;
return {};
}
// We have established that the given key has the correct algorithm, and
// because this is the TpmKeymasterContext we can assume that the Key is an
// AsymmetricKey. So we can downcast.
const keymaster::AsymmetricKey& asymmetric_key =
static_cast<const keymaster::AsymmetricKey&>(key);
// DEVICE_UNIQUE_ATTESTATION is only allowed for strongbox devices. See
// hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl:845
// at commit beefae4790ccd4f1ee75ea69603d4c9c2a45c0aa .
// While the specification says to return ErrorCode::INVALID_ARGUMENT , the
// relevant VTS test actually tests for ErrorCode::UNIMPLEMENTED . See
// hardware/interfaces/keymaster/4.1/vts/functional/DeviceUniqueAttestationTest.cpp:203
// at commit 36dcf1a404a9cf07ca5a2a6ad92371507194fe1b .
if (attest_params.find(keymaster::TAG_DEVICE_UNIQUE_ATTESTATION) != -1) {
*error = KM_ERROR_UNIMPLEMENTED;
return {};
}
return keymaster::generate_attestation(asymmetric_key, attest_params,
{} /* attest_key */,
*attestation_context_, error);
}
keymaster::CertificateChain TpmKeymasterContext::GenerateSelfSignedCertificate(
const keymaster::Key& key, const keymaster::AuthorizationSet& cert_params,
bool fake_signature, keymaster_error_t* error) const {
keymaster_algorithm_t key_algorithm;
if (!key.authorizations().GetTagValue(keymaster::TAG_ALGORITHM, &key_algorithm)) {
*error = KM_ERROR_UNKNOWN_ERROR;
return {};
}
if ((key_algorithm != KM_ALGORITHM_RSA && key_algorithm != KM_ALGORITHM_EC)) {
*error = KM_ERROR_INCOMPATIBLE_ALGORITHM;
return {};
}
// We have established that the given key has the correct algorithm, and because this is the
// SoftKeymasterContext we can assume that the Key is an AsymmetricKey. So we can downcast.
const keymaster::AsymmetricKey& asymmetric_key =
static_cast<const keymaster::AsymmetricKey&>(key);
return generate_self_signed_cert(asymmetric_key, cert_params, fake_signature, error);
}
keymaster_error_t TpmKeymasterContext::UnwrapKey(
const KeymasterKeyBlob&,
const KeymasterKeyBlob&,
const AuthorizationSet&,
const KeymasterKeyBlob&,
AuthorizationSet*,
keymaster_key_format_t*,
KeymasterKeyBlob*) const {
LOG(ERROR) << "TODO(b/155697375): Implement UnwrapKey";
return KM_ERROR_UNIMPLEMENTED;
}