blob: f3ec4fd5c9cdc819a337e9ecdab5dac9a5b67d7c [file] [log] [blame]
/*
* Copyright 2015 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 "trusty_keymaster_context.h"
#include "secure_storage_manager.h"
#include <lib/hwkey/hwkey.h>
#include <lib/rng/trusty_rng.h>
#include <keymaster/android_keymaster_utils.h>
#include <keymaster/contexts/soft_attestation_cert.h>
#include <keymaster/key_blob_utils/auth_encrypted_key_blob.h>
#include <keymaster/key_blob_utils/ocb_utils.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/openssl_err.h>
#include <keymaster/km_openssl/rsa_key_factory.h>
#include <keymaster/km_openssl/triple_des_key.h>
#include <keymaster/logger.h>
#include <keymaster/operation.h>
#include <keymaster/wrapped_key.h>
#include "trusty_aes_key.h"
#ifdef KEYMASTER_DEBUG
#pragma message \
"Compiling with fake Keymaster Root of Trust values! DO NOT SHIP THIS!"
#endif
// TRUSTY_KM_WRAPPING_KEY_SIZE controls the size of the AES key that is used
// to wrap keys before allowing NS to hold on to them.
// Previously, it had a hardcoded value of 16 bytes, but current guidance is to
// expand this to a 256-bit (32-byte) key.
//
// The plan is to leave old devices as they are, and issue new devices with a
// 32-byte key to ensure compatibility. New devices should set
// TRUSTY_WRAPPING_KEY_SIZE to 32 in their device Makefile to control this.
#ifndef TRUSTY_KM_WRAPPING_KEY_SIZE
#define TRUSTY_KM_WRAPPING_KEY_SIZE 16
#endif
namespace keymaster {
namespace {
static const int kAesKeySize = TRUSTY_KM_WRAPPING_KEY_SIZE;
static const int kCallsBetweenRngReseeds = 32;
static const int kRngReseedSize = 64;
static const uint8_t kMasterKeyDerivationData[kAesKeySize] = "KeymasterMaster";
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;
}
} // anonymous namespace
TrustyKeymasterContext::TrustyKeymasterContext()
: AttestationContext(KmVersion::KEYMASTER_4),
enforcement_policy_(this),
rng_initialized_(false),
calls_since_reseed_(0) {
LOG_D("Creating TrustyKeymaster", 0);
rsa_factory_.reset(
new RsaKeyFactory(*this /* blob_maker */, *this /* context */));
tdes_factory_.reset(new TripleDesKeyFactory(*this /* blob_maker */,
*this /* random_source */));
ec_factory_.reset(
new EcKeyFactory(*this /* blob_maker */, *this /* context */));
aes_factory_.reset(new TrustyAesKeyFactory(*this /* blob_maker */,
*this /* random_source */));
hmac_factory_.reset(new HmacKeyFactory(*this /* blob_maker */,
*this /* random_source */));
verified_boot_key_.Reinitialize("Unbound", 7);
}
const KeyFactory* TrustyKeymasterContext::GetKeyFactory(
keymaster_algorithm_t algorithm) const {
switch (algorithm) {
case KM_ALGORITHM_RSA:
return rsa_factory_.get();
case KM_ALGORITHM_EC:
return ec_factory_.get();
case KM_ALGORITHM_AES:
return aes_factory_.get();
case KM_ALGORITHM_HMAC:
return hmac_factory_.get();
case KM_ALGORITHM_TRIPLE_DES:
return tdes_factory_.get();
default:
return nullptr;
}
}
static keymaster_algorithm_t supported_algorithms[] = {
KM_ALGORITHM_RSA, KM_ALGORITHM_EC, KM_ALGORITHM_AES, KM_ALGORITHM_HMAC,
KM_ALGORITHM_TRIPLE_DES};
const keymaster_algorithm_t* TrustyKeymasterContext::GetSupportedAlgorithms(
size_t* algorithms_count) const {
*algorithms_count = array_length(supported_algorithms);
return supported_algorithms;
}
OperationFactory* TrustyKeymasterContext::GetOperationFactory(
keymaster_algorithm_t algorithm,
keymaster_purpose_t purpose) const {
const KeyFactory* key_factory = GetKeyFactory(algorithm);
if (!key_factory)
return nullptr;
return key_factory->GetOperationFactory(purpose);
}
static keymaster_error_t TranslateAuthorizationSetError(
AuthorizationSet::Error err) {
switch (err) {
case AuthorizationSet::OK:
return KM_ERROR_OK;
case AuthorizationSet::ALLOCATION_FAILURE:
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
case AuthorizationSet::MALFORMED_DATA:
return KM_ERROR_UNKNOWN_ERROR;
}
return KM_ERROR_OK;
}
keymaster_error_t TrustyKeymasterContext::SetAuthorizations(
const AuthorizationSet& key_description,
keymaster_key_origin_t origin,
AuthorizationSet* hw_enforced,
AuthorizationSet* sw_enforced) const {
sw_enforced->Clear();
hw_enforced->Clear();
for (auto& entry : key_description) {
switch (entry.tag) {
case KM_TAG_INVALID:
case KM_TAG_BOOTLOADER_ONLY:
case KM_TAG_NONCE:
case KM_TAG_AUTH_TOKEN:
case KM_TAG_MAC_LENGTH:
case KM_TAG_ASSOCIATED_DATA:
case KM_TAG_UNIQUE_ID:
return KM_ERROR_INVALID_KEY_BLOB;
case KM_TAG_ROLLBACK_RESISTANCE:
// Currently return UNAVAILABLE.
return KM_ERROR_ROLLBACK_RESISTANCE_UNAVAILABLE;
case KM_TAG_ROLLBACK_RESISTANT:
case KM_TAG_APPLICATION_ID:
case KM_TAG_APPLICATION_DATA:
case KM_TAG_ALL_APPLICATIONS:
case KM_TAG_ROOT_OF_TRUST:
case KM_TAG_ORIGIN:
case KM_TAG_RESET_SINCE_ID_ROTATION:
case KM_TAG_ALLOW_WHILE_ON_BODY:
case KM_TAG_ATTESTATION_CHALLENGE:
case KM_TAG_OS_VERSION:
case KM_TAG_OS_PATCHLEVEL:
// Ignore these.
break;
case KM_TAG_PURPOSE:
case KM_TAG_ALGORITHM:
case KM_TAG_KEY_SIZE:
case KM_TAG_RSA_PUBLIC_EXPONENT:
case KM_TAG_BLOB_USAGE_REQUIREMENTS:
case KM_TAG_DIGEST:
case KM_TAG_PADDING:
case KM_TAG_BLOCK_MODE:
case KM_TAG_MIN_SECONDS_BETWEEN_OPS:
case KM_TAG_MAX_USES_PER_BOOT:
case KM_TAG_USER_SECURE_ID:
case KM_TAG_NO_AUTH_REQUIRED:
case KM_TAG_AUTH_TIMEOUT:
case KM_TAG_CALLER_NONCE:
case KM_TAG_MIN_MAC_LENGTH:
case KM_TAG_KDF:
case KM_TAG_EC_CURVE:
case KM_TAG_ECIES_SINGLE_HASH_MODE:
case KM_TAG_TRUSTED_CONFIRMATION_REQUIRED:
#if WITH_HWWSK_SUPPORT
// keep KM_TAG_STORAGE_KEY is HWWSK service is enabled
case KM_TAG_STORAGE_KEY:
#endif
hw_enforced->push_back(entry);
break;
case KM_TAG_USER_AUTH_TYPE: {
keymaster_key_param_t elem = entry;
// This implementation does support TEE enforced password auth
elem.enumerated = entry.enumerated & HW_AUTH_PASSWORD;
#if TEE_FINGERPRINT_AUTH_SUPPORTED
// If HW_AUTH_FINGERPRINT is supported it needs to be included too
elem.enumerates |= entry.enumerated & HW_AUTH_FINGERPRINT;
#endif
hw_enforced->push_back(elem);
} break;
case KM_TAG_ACTIVE_DATETIME:
case KM_TAG_ORIGINATION_EXPIRE_DATETIME:
case KM_TAG_USAGE_EXPIRE_DATETIME:
case KM_TAG_USER_ID:
case KM_TAG_ALL_USERS:
case KM_TAG_CREATION_DATETIME:
case KM_TAG_INCLUDE_UNIQUE_ID:
case KM_TAG_EXPORTABLE:
sw_enforced->push_back(entry);
break;
default:
break;
}
}
hw_enforced->push_back(TAG_ORIGIN, origin);
// these values will be 0 if not set by bootloader
hw_enforced->push_back(TAG_OS_VERSION, boot_os_version_);
hw_enforced->push_back(TAG_OS_PATCHLEVEL, boot_os_patchlevel_);
if (sw_enforced->is_valid() != AuthorizationSet::OK)
return TranslateAuthorizationSetError(sw_enforced->is_valid());
if (hw_enforced->is_valid() != AuthorizationSet::OK)
return TranslateAuthorizationSetError(hw_enforced->is_valid());
return KM_ERROR_OK;
}
keymaster_error_t TrustyKeymasterContext::BuildHiddenAuthorizations(
const AuthorizationSet& input_set,
AuthorizationSet* hidden) const {
keymaster_blob_t entry;
if (input_set.GetTagValue(TAG_APPLICATION_ID, &entry))
hidden->push_back(TAG_APPLICATION_ID, entry.data, entry.data_length);
if (input_set.GetTagValue(TAG_APPLICATION_DATA, &entry))
hidden->push_back(TAG_APPLICATION_DATA, entry.data, entry.data_length);
// Copy verified boot key, verified boot state, and device lock state to
// hidden authorization set for binding to key.
keymaster_key_param_t root_of_trust;
root_of_trust.tag = KM_TAG_ROOT_OF_TRUST;
root_of_trust.blob.data = verified_boot_key_.begin();
root_of_trust.blob.data_length = verified_boot_key_.buffer_size();
hidden->push_back(root_of_trust);
root_of_trust.blob.data =
reinterpret_cast<const uint8_t*>(&verified_boot_state_);
root_of_trust.blob.data_length = sizeof(verified_boot_state_);
hidden->push_back(root_of_trust);
root_of_trust.blob.data = reinterpret_cast<const uint8_t*>(&device_locked_);
root_of_trust.blob.data_length = sizeof(device_locked_);
hidden->push_back(root_of_trust);
return TranslateAuthorizationSetError(hidden->is_valid());
}
keymaster_error_t TrustyKeymasterContext::CreateAuthEncryptedKeyBlob(
const AuthorizationSet& key_description,
const KeymasterKeyBlob& key_material,
const AuthorizationSet& hw_enforced,
const AuthorizationSet& sw_enforced,
KeymasterKeyBlob* blob) const {
AuthorizationSet hidden;
keymaster_error_t error =
BuildHiddenAuthorizations(key_description, &hidden);
if (error != KM_ERROR_OK)
return error;
KeymasterKeyBlob master_key;
error = DeriveMasterKey(&master_key);
if (error != KM_ERROR_OK)
return error;
Buffer nonce(OCB_NONCE_LENGTH);
Buffer tag(OCB_TAG_LENGTH);
if (!nonce.peek_write() || !tag.peek_write())
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
error = GenerateRandom(nonce.peek_write(), OCB_NONCE_LENGTH);
if (error != KM_ERROR_OK)
return error;
nonce.advance_write(OCB_NONCE_LENGTH);
KeymasterKeyBlob encrypted_key;
error = OcbEncryptKey(hw_enforced, sw_enforced, hidden, master_key,
key_material, nonce, &encrypted_key, &tag);
if (error != KM_ERROR_OK)
return error;
return SerializeAuthEncryptedBlob(encrypted_key, hw_enforced, sw_enforced,
nonce, tag, blob);
}
keymaster_error_t TrustyKeymasterContext::CreateKeyBlob(
const AuthorizationSet& key_description,
keymaster_key_origin_t origin,
const KeymasterKeyBlob& key_material,
KeymasterKeyBlob* blob,
AuthorizationSet* hw_enforced,
AuthorizationSet* sw_enforced) const {
keymaster_error_t error = SetAuthorizations(key_description, origin,
hw_enforced, sw_enforced);
if (error != KM_ERROR_OK)
return error;
return CreateAuthEncryptedKeyBlob(key_description, key_material,
*hw_enforced, *sw_enforced, blob);
}
keymaster_error_t TrustyKeymasterContext::UpgradeKeyBlob(
const KeymasterKeyBlob& key_to_upgrade,
const AuthorizationSet& upgrade_params,
KeymasterKeyBlob* upgraded_key) const {
UniquePtr<Key> key;
keymaster_error_t error =
ParseKeyBlob(key_to_upgrade, upgrade_params, &key);
if (error != KM_ERROR_OK)
return error;
bool set_changed = false;
if (boot_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->sw_enforced().find(TAG_OS_VERSION);
if (key_os_version_pos != -1) {
uint32_t key_os_version =
key->sw_enforced()[key_os_version_pos].integer;
if (key_os_version != 0) {
key->sw_enforced()[key_os_version_pos].integer =
boot_os_version_;
set_changed = true;
}
}
}
if (!UpgradeIntegerTag(TAG_OS_VERSION, boot_os_version_,
&key->hw_enforced(), &set_changed) ||
!UpgradeIntegerTag(TAG_OS_PATCHLEVEL, boot_os_patchlevel_,
&key->hw_enforced(), &set_changed)) {
// 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 CreateAuthEncryptedKeyBlob(upgrade_params, key->key_material(),
key->hw_enforced(), key->sw_enforced(),
upgraded_key);
}
keymaster_error_t TrustyKeymasterContext::ParseKeyBlob(
const KeymasterKeyBlob& blob,
const AuthorizationSet& additional_params,
UniquePtr<Key>* key) const {
AuthorizationSet hw_enforced;
AuthorizationSet sw_enforced;
KeymasterKeyBlob key_material;
keymaster_error_t error;
auto constructKey = [&, this]() mutable -> keymaster_error_t {
// GetKeyFactory
if (error != KM_ERROR_OK)
return error;
keymaster_algorithm_t algorithm;
if (!hw_enforced.GetTagValue(TAG_ALGORITHM, &algorithm)) {
return KM_ERROR_INVALID_ARGUMENT;
}
auto factory = GetKeyFactory(algorithm);
return factory->LoadKey(move(key_material), additional_params,
move(hw_enforced), move(sw_enforced), key);
};
Buffer nonce, tag;
KeymasterKeyBlob encrypted_key_material;
if (!key)
return KM_ERROR_UNEXPECTED_NULL_POINTER;
error = DeserializeAuthEncryptedBlob(blob, &encrypted_key_material,
&hw_enforced, &sw_enforced, &nonce,
&tag);
if (error != KM_ERROR_OK)
return error;
if (nonce.available_read() != OCB_NONCE_LENGTH ||
tag.available_read() != OCB_TAG_LENGTH)
return KM_ERROR_INVALID_KEY_BLOB;
KeymasterKeyBlob master_key;
error = DeriveMasterKey(&master_key);
if (error != KM_ERROR_OK)
return error;
AuthorizationSet hidden;
error = BuildHiddenAuthorizations(additional_params, &hidden);
if (error != KM_ERROR_OK)
return error;
error = OcbDecryptKey(hw_enforced, sw_enforced, hidden, master_key,
encrypted_key_material, nonce, tag, &key_material);
return constructKey();
}
keymaster_error_t TrustyKeymasterContext::AddRngEntropy(const uint8_t* buf,
size_t length) const {
if (trusty_rng_add_entropy(buf, length) != 0)
return KM_ERROR_UNKNOWN_ERROR;
return KM_ERROR_OK;
}
bool TrustyKeymasterContext::SeedRngIfNeeded() const {
if (ShouldReseedRng())
const_cast<TrustyKeymasterContext*>(this)->ReseedRng();
return rng_initialized_;
}
bool TrustyKeymasterContext::ShouldReseedRng() const {
if (!rng_initialized_) {
LOG_I("RNG not initalized, reseed", 0);
return true;
}
if (++calls_since_reseed_ % kCallsBetweenRngReseeds == 0) {
LOG_I("Periodic reseed", 0);
return true;
}
return false;
}
bool TrustyKeymasterContext::ReseedRng() {
UniquePtr<uint8_t[]> rand_seed(new uint8_t[kRngReseedSize]);
memset(rand_seed.get(), 0, kRngReseedSize);
if (trusty_rng_hw_rand(rand_seed.get(), kRngReseedSize) != 0) {
LOG_E("Failed to get bytes from HW RNG", 0);
return false;
}
LOG_I("Reseeding with %d bytes from HW RNG", kRngReseedSize);
trusty_rng_add_entropy(rand_seed.get(), kRngReseedSize);
rng_initialized_ = true;
return true;
}
// Gee wouldn't it be nice if the crypto service headers defined this.
enum DerivationParams {
DERIVATION_DATA_PARAM = 0,
OUTPUT_BUFFER_PARAM = 1,
};
keymaster_error_t TrustyKeymasterContext::DeriveMasterKey(
KeymasterKeyBlob* master_key) const {
LOG_D("Deriving master key", 0);
long rc = hwkey_open();
if (rc < 0) {
return KM_ERROR_UNKNOWN_ERROR;
}
hwkey_session_t session = (hwkey_session_t)rc;
if (!master_key->Reset(kAesKeySize)) {
LOG_S("Could not allocate memory for master key buffer", 0);
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
}
uint32_t kdf_version = HWKEY_KDF_VERSION_1;
rc = hwkey_derive(session, &kdf_version, kMasterKeyDerivationData,
master_key->writable_data(), kAesKeySize);
if (rc < 0) {
LOG_S("Error deriving master key: %d", rc);
return KM_ERROR_UNKNOWN_ERROR;
}
hwkey_close(session);
LOG_I("Key derivation complete", 0);
return KM_ERROR_OK;
}
bool TrustyKeymasterContext::InitializeAuthTokenKey() {
if (auth_token_key_initialized_)
return true;
keymaster_key_blob_t key;
key.key_material = auth_token_key_;
key.key_material_size = kAuthTokenKeySize;
keymaster_error_t error = enforcement_policy_.GetHmacKey(&key);
if (error == KM_ERROR_OK)
auth_token_key_initialized_ = true;
else
auth_token_key_initialized_ = false;
return auth_token_key_initialized_;
}
keymaster_error_t TrustyKeymasterContext::GetAuthTokenKey(
keymaster_key_blob_t* key) const {
if (!auth_token_key_initialized_ &&
!const_cast<TrustyKeymasterContext*>(this)->InitializeAuthTokenKey())
return KM_ERROR_UNKNOWN_ERROR;
key->key_material = auth_token_key_;
key->key_material_size = kAuthTokenKeySize;
return KM_ERROR_OK;
}
keymaster_error_t TrustyKeymasterContext::SetSystemVersion(
uint32_t os_version,
uint32_t os_patchlevel) {
if (!version_info_set_) {
// Note that version info is now set by Configure, rather than by the
// bootloader. This is to ensure that system-only updates can be done,
// to avoid breaking Project Treble.
boot_os_version_ = os_version;
boot_os_patchlevel_ = os_patchlevel;
version_info_set_ = true;
}
#ifdef KEYMASTER_DEBUG
Buffer fake_root_of_trust("000111222333444555666777888999000", 32);
Buffer verified_boot_hash_none;
if (!root_of_trust_set_) {
/* Sets bootloader parameters to what is expected on a 'good' device,
* will pass attestation CTS tests. FOR DEBUGGING ONLY.
*/
SetBootParams(os_version, os_patchlevel, fake_root_of_trust,
KM_VERIFIED_BOOT_VERIFIED, true, verified_boot_hash_none);
}
#endif
return KM_ERROR_OK;
}
void TrustyKeymasterContext::GetSystemVersion(uint32_t* os_version,
uint32_t* os_patchlevel) const {
*os_version = boot_os_version_;
*os_patchlevel = boot_os_patchlevel_;
}
const AttestationContext::VerifiedBootParams*
TrustyKeymasterContext::GetVerifiedBootParams(keymaster_error_t* error) const {
VerifiedBootParams& vb_parms =
const_cast<VerifiedBootParams&>(verified_boot_params_);
vb_parms.verified_boot_key = {verified_boot_key_.begin(),
verified_boot_key_.buffer_size()};
vb_parms.verified_boot_hash = {verified_boot_hash_.begin(),
verified_boot_hash_.buffer_size()};
vb_parms.verified_boot_state = verified_boot_state_;
vb_parms.device_locked = device_locked_;
*error = KM_ERROR_OK;
return &verified_boot_params_;
}
KeymasterKeyBlob TrustyKeymasterContext::GetAttestationKey(
keymaster_algorithm_t algorithm,
keymaster_error_t* error) const {
AttestationKeySlot key_slot;
switch (algorithm) {
case KM_ALGORITHM_RSA:
key_slot = AttestationKeySlot::kRsa;
break;
case KM_ALGORITHM_EC:
key_slot = AttestationKeySlot::kEcdsa;
break;
default:
*error = KM_ERROR_UNSUPPORTED_ALGORITHM;
return {};
}
SecureStorageManager* ss_manager = SecureStorageManager::get_instance();
if (ss_manager == nullptr) {
LOG_E("Failed to open secure storage session.", 0);
*error = KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
return {};
}
auto result = ss_manager->ReadKeyFromStorage(key_slot, error);
#if KEYMASTER_SOFT_ATTESTATION_FALLBACK
if (*error != KM_ERROR_OK) {
LOG_I("Failed to read attestation key from RPMB, falling back to test key",
0);
auto key = getAttestationKey(algorithm, error);
if (*error != KM_ERROR_OK) {
LOG_D("Software attestation key missing: %d", *error);
return {};
}
result = KeymasterKeyBlob(*key);
if (!result.key_material)
*error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
}
#endif
return result;
}
CertificateChain TrustyKeymasterContext::GetAttestationChain(
keymaster_algorithm_t algorithm,
keymaster_error_t* error) const {
AttestationKeySlot key_slot;
switch (algorithm) {
case KM_ALGORITHM_RSA:
key_slot = AttestationKeySlot::kRsa;
break;
case KM_ALGORITHM_EC:
key_slot = AttestationKeySlot::kEcdsa;
break;
default:
*error = KM_ERROR_UNSUPPORTED_ALGORITHM;
return {};
}
CertificateChain chain;
SecureStorageManager* ss_manager = SecureStorageManager::get_instance();
if (ss_manager == nullptr) {
LOG_E("Failed to open secure storage session.", 0);
*error = KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
} else {
*error = ss_manager->ReadCertChainFromStorage(key_slot, &chain);
}
#if KEYMASTER_SOFT_ATTESTATION_FALLBACK
if ((*error != KM_ERROR_OK) || (chain->entry_count == 0)) {
LOG_I("Failed to read attestation chain from RPMB, falling back to test chain",
0);
chain = getAttestationChain(algorithm, error);
}
#endif
return chain;
}
CertificateChain TrustyKeymasterContext::GenerateAttestation(
const Key& key,
const AuthorizationSet& attest_params,
UniquePtr<Key> attest_key,
const KeymasterBlob& issuer_subject,
keymaster_error_t* error) const {
*error = KM_ERROR_OK;
keymaster_algorithm_t key_algorithm;
if (!key.authorizations().GetTagValue(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 TrustyKeymasterContext we can assume that the Key is
// an AsymmetricKey. So we can downcast.
const AsymmetricKey& asymmetric_key =
static_cast<const AsymmetricKey&>(key);
AttestKeyInfo attest_key_info(attest_key, &issuer_subject, error);
if (*error != KM_ERROR_OK) {
return {};
}
return generate_attestation(asymmetric_key, attest_params,
move(attest_key_info), *this, error);
}
CertificateChain TrustyKeymasterContext::GenerateSelfSignedCertificate(
const Key& key,
const AuthorizationSet& cert_params,
bool fake_signature,
keymaster_error_t* error) const {
keymaster_algorithm_t key_algorithm;
if (!key.authorizations().GetTagValue(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 {};
}
const AsymmetricKey& asymmetric_key =
static_cast<const AsymmetricKey&>(key);
return generate_self_signed_cert(asymmetric_key, cert_params,
fake_signature, error);
}
keymaster_error_t TrustyKeymasterContext::SetBootParams(
uint32_t /* os_version */,
uint32_t /* os_patchlevel */,
const Buffer& verified_boot_key,
keymaster_verified_boot_t verified_boot_state,
bool device_locked,
const Buffer& verified_boot_hash) {
if (root_of_trust_set_)
return KM_ERROR_ROOT_OF_TRUST_ALREADY_SET;
verified_boot_hash_.Reinitialize(verified_boot_hash);
root_of_trust_set_ = true;
verified_boot_state_ = verified_boot_state;
device_locked_ = device_locked;
verified_boot_key_.Reinitialize("", 0);
// If the device is verified or self signed, load the key (if present)
if ((verified_boot_state == KM_VERIFIED_BOOT_VERIFIED) ||
(verified_boot_state == KM_VERIFIED_BOOT_SELF_SIGNED)) {
if (verified_boot_key.buffer_size()) {
verified_boot_key_.Reinitialize(verified_boot_key);
} else {
// If no boot key was passed, default to unverified/unlocked
verified_boot_state_ = KM_VERIFIED_BOOT_UNVERIFIED;
device_locked_ = false;
}
} else {
// If the device image was not signed, it cannot be locked
device_locked_ = false;
}
return KM_ERROR_OK;
}
// Mostly adapted from pure_soft_keymaster_context.cpp
keymaster_error_t TrustyKeymasterContext::UnwrapKey(
const KeymasterKeyBlob& wrapped_key_blob,
const KeymasterKeyBlob& wrapping_key_blob,
const AuthorizationSet& wrapping_key_params,
const KeymasterKeyBlob& masking_key,
AuthorizationSet* wrapped_key_params,
keymaster_key_format_t* wrapped_key_format,
KeymasterKeyBlob* wrapped_key_material) const {
LOG_D("UnwrapKey:0", 0);
keymaster_error_t error = KM_ERROR_OK;
if (wrapped_key_material == NULL) {
return KM_ERROR_UNEXPECTED_NULL_POINTER;
}
LOG_D("UnwrapKey:1", 0);
// Step 1 from IKeymasterDevice.hal file spec
// Parse wrapping key
UniquePtr<Key> wrapping_key;
error = ParseKeyBlob(wrapping_key_blob, wrapping_key_params, &wrapping_key);
if (error != KM_ERROR_OK) {
LOG_E("Failed to parse wrapping key", 0);
return error;
}
AuthProxy wrapping_key_auths(wrapping_key->hw_enforced(),
wrapping_key->sw_enforced());
// Check Wrapping Key Purpose
if (!wrapping_key_auths.Contains(TAG_PURPOSE, KM_PURPOSE_WRAP)) {
LOG_E("Wrapping key did not have KM_PURPOSE_WRAP", 0);
return KM_ERROR_INCOMPATIBLE_PURPOSE;
}
// Check Padding mode is RSA_OAEP and digest is SHA_2_256 (spec mandated)
if (!wrapping_key_auths.Contains(TAG_DIGEST, KM_DIGEST_SHA_2_256)) {
LOG_E("Wrapping key lacks authorization for SHA2-256", 0);
return KM_ERROR_INCOMPATIBLE_DIGEST;
}
if (!wrapping_key_auths.Contains(TAG_PADDING, KM_PAD_RSA_OAEP)) {
LOG_E("Wrapping key lacks authorization for padding OAEP", 0);
return KM_ERROR_INCOMPATIBLE_PADDING_MODE;
}
// Check that that was also the padding mode and digest specified
if (!wrapping_key_params.Contains(TAG_DIGEST, KM_DIGEST_SHA_2_256)) {
LOG_E("Wrapping key must use SHA2-256", 0);
return KM_ERROR_INCOMPATIBLE_DIGEST;
}
if (!wrapping_key_params.Contains(TAG_PADDING, KM_PAD_RSA_OAEP)) {
LOG_E("Wrapping key must use OAEP padding", 0);
return KM_ERROR_INCOMPATIBLE_PADDING_MODE;
}
LOG_D("UnwrapKey:2", 0);
// Step 2 from IKeymasterDevice.hal spec
// Parse wrapped key
KeymasterBlob iv;
KeymasterKeyBlob transit_key;
KeymasterKeyBlob secure_key;
KeymasterBlob tag;
KeymasterBlob wrapped_key_description;
error = parse_wrapped_key(wrapped_key_blob, &iv, &transit_key, &secure_key,
&tag, wrapped_key_params, wrapped_key_format,
&wrapped_key_description);
if (error != KM_ERROR_OK) {
return error;
}
// Decrypt encryptedTransportKey (transit_key) with wrapping_key
auto operation_factory = wrapping_key->key_factory()->GetOperationFactory(
KM_PURPOSE_DECRYPT);
if (operation_factory == NULL) {
return KM_ERROR_UNKNOWN_ERROR;
}
AuthorizationSet out_params;
OperationPtr operation(operation_factory->CreateOperation(
move(*wrapping_key), wrapping_key_params, &error));
if ((operation.get() == NULL) || (error != KM_ERROR_OK)) {
return error;
}
error = operation->Begin(wrapping_key_params, &out_params);
if (error != KM_ERROR_OK) {
return error;
}
Buffer input;
Buffer output;
// Explicitly reinitialize rather than constructing in order to report
// allocation failure.
if (!input.Reinitialize(transit_key.key_material,
transit_key.key_material_size)) {
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
}
error = operation->Finish(wrapping_key_params, input,
Buffer() /* signature */, &out_params, &output);
if (error != KM_ERROR_OK) {
return error;
}
KeymasterKeyBlob transport_key = {
output.peek_read(),
output.available_read(),
};
LOG_D("UnwrapKey:3", 0);
// Step 3 of IKeymasterDevice.hal
// XOR the transit key with the masking key
if (transport_key.key_material_size != masking_key.key_material_size) {
return KM_ERROR_INVALID_ARGUMENT;
}
for (size_t i = 0; i < transport_key.key_material_size; i++) {
transport_key.writable_data()[i] ^= masking_key.key_material[i];
}
LOG_D("UnwrapKey:4", 0);
// Step 4 of IKeymasterDevice.hal
// transit_key_authorizations is defined by spec
// TODO the mac len is NOT in the spec, but probably should be
auto transport_key_authorizations =
AuthorizationSetBuilder()
.AesEncryptionKey(256)
.Padding(KM_PAD_NONE)
.Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
.Authorization(TAG_NONCE, iv)
.Authorization(TAG_MIN_MAC_LENGTH, 128)
.build();
auto validity = transport_key_authorizations.is_valid();
if (validity != AuthorizationSet::Error::OK) {
return TranslateAuthorizationSetError(validity);
}
// gcm_params is also defined by spec
// TODO same problem with mac len not being specced
auto gcm_params = AuthorizationSetBuilder()
.Padding(KM_PAD_NONE)
.Authorization(TAG_BLOCK_MODE, KM_MODE_GCM)
.Authorization(TAG_NONCE, iv)
.Authorization(TAG_MAC_LENGTH, 128)
.build();
validity = gcm_params.is_valid();
if (validity != AuthorizationSet::Error::OK) {
return TranslateAuthorizationSetError(validity);
}
auto aes_factory = GetKeyFactory(KM_ALGORITHM_AES);
if (aes_factory == NULL) {
return KM_ERROR_UNKNOWN_ERROR;
}
UniquePtr<Key> aes_transport_key;
error = aes_factory->LoadKey(move(transport_key), gcm_params,
move(transport_key_authorizations),
AuthorizationSet(), &aes_transport_key);
if (error != KM_ERROR_OK) {
return error;
}
auto aes_operation_factory =
GetOperationFactory(KM_ALGORITHM_AES, KM_PURPOSE_DECRYPT);
if (aes_operation_factory == NULL) {
return KM_ERROR_UNKNOWN_ERROR;
}
OperationPtr aes_operation(aes_operation_factory->CreateOperation(
move(*aes_transport_key), gcm_params, &error));
if ((aes_operation.get() == NULL) || (error != KM_ERROR_OK)) {
return error;
}
error = aes_operation->Begin(gcm_params, &out_params);
if (error != KM_ERROR_OK) {
return error;
}
size_t update_consumed = 0;
AuthorizationSet update_outparams;
Buffer encrypted_key;
Buffer plaintext_key;
// Separate initialization to catch memory errors
size_t total_key_size = secure_key.key_material_size + tag.data_length;
if (!plaintext_key.Reinitialize(total_key_size)) {
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
}
if (!encrypted_key.Reinitialize(total_key_size)) {
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
}
// Concatenate key data
if (!encrypted_key.write(secure_key.key_material,
secure_key.key_material_size)) {
return KM_ERROR_UNKNOWN_ERROR;
}
if (!encrypted_key.write(tag.data, tag.data_length)) {
return KM_ERROR_UNKNOWN_ERROR;
}
auto update_params =
AuthorizationSetBuilder()
.Authorization(TAG_ASSOCIATED_DATA,
wrapped_key_description.data,
wrapped_key_description.data_length)
.build();
validity = update_params.is_valid();
if (validity != AuthorizationSet::Error::OK) {
return TranslateAuthorizationSetError(validity);
}
error = aes_operation->Update(update_params, encrypted_key,
&update_outparams, &plaintext_key,
&update_consumed);
if (error != KM_ERROR_OK) {
return error;
}
AuthorizationSet finish_params;
AuthorizationSet finish_out_params;
Buffer finish_input;
error = aes_operation->Finish(finish_params, finish_input,
Buffer() /* signature */, &finish_out_params,
&plaintext_key);
if (error != KM_ERROR_OK) {
return error;
}
*wrapped_key_material = {plaintext_key.peek_read(),
plaintext_key.available_read()};
if (!wrapped_key_material->key_material && plaintext_key.peek_read()) {
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
}
LOG_D("UnwrapKey:Done", 0);
return error;
}
} // namespace keymaster