| /* |
| * 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 <array> |
| #include <utility> |
| |
| #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_record.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 <lib/hwkey/hwkey.h> |
| #include <lib/rng/trusty_rng.h> |
| #include <openssl/hmac.h> |
| |
| #include "secure_storage_manager.h" |
| #include "trusty_aes_key.h" |
| |
| constexpr bool kUseSecureDeletion = true; |
| uint8_t allZerosOrHashOfVerifiedBootKey[32] = {}; |
| |
| #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) { |
| *set_changed = true; |
| set->push_back(keymaster_key_param_t{.tag = tag, .integer = value}); |
| return true; |
| } |
| |
| if (set->params[index].integer > value) { |
| return false; |
| } |
| |
| if (set->params[index].integer != value) { |
| *set_changed = true; |
| set->params[index].integer = value; |
| } |
| return true; |
| } |
| |
| } // anonymous namespace |
| |
| TrustyKeymasterContext::TrustyKeymasterContext() |
| : AttestationContext(KmVersion::KEYMASTER_4), |
| enforcement_policy_(this), |
| secure_deletion_secret_storage_(*this /* random_source */), |
| rng_initialized_(false), |
| calls_since_reseed_(0) { |
| LOG_D("Creating TrustyKeymaster", 0); |
| rsa_factory_.reset(new (std::nothrow) RsaKeyFactory(*this /* blob_maker */, |
| *this /* context */)); |
| tdes_factory_.reset(new (std::nothrow) TripleDesKeyFactory( |
| *this /* blob_maker */, *this /* random_source */)); |
| ec_factory_.reset(new (std::nothrow) EcKeyFactory(*this /* blob_maker */, |
| *this /* context */)); |
| aes_factory_.reset(new (std::nothrow) TrustyAesKeyFactory( |
| *this /* blob_maker */, *this /* random_source */)); |
| hmac_factory_.reset(new (std::nothrow) HmacKeyFactory( |
| *this /* blob_maker */, *this /* random_source */)); |
| boot_params_.verified_boot_key.Reinitialize("Unbound", 7); |
| trusty_remote_provisioning_context_.reset( |
| new (std::nothrow) TrustyRemoteProvisioningContext()); |
| } |
| |
| 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, |
| bool has_secure_deletion) const { |
| sw_enforced->Clear(); |
| hw_enforced->Clear(); |
| |
| for (auto& entry : key_description) { |
| switch (entry.tag) { |
| // Tags that should never appear in key descriptions. |
| case KM_TAG_ASSOCIATED_DATA: |
| case KM_TAG_AUTH_TOKEN: |
| case KM_TAG_BOOTLOADER_ONLY: |
| case KM_TAG_INVALID: |
| case KM_TAG_MAC_LENGTH: |
| case KM_TAG_NONCE: |
| case KM_TAG_ROOT_OF_TRUST: |
| case KM_TAG_UNIQUE_ID: |
| case KM_TAG_IDENTITY_CREDENTIAL_KEY: |
| return KM_ERROR_INVALID_KEY_BLOB; |
| |
| // Tags used only to provide information for certificate creation, but |
| // which should not be included in blobs. |
| case KM_TAG_ATTESTATION_APPLICATION_ID: |
| case KM_TAG_ATTESTATION_CHALLENGE: |
| case KM_TAG_ATTESTATION_ID_BRAND: |
| case KM_TAG_ATTESTATION_ID_DEVICE: |
| case KM_TAG_ATTESTATION_ID_IMEI: |
| case KM_TAG_ATTESTATION_ID_MANUFACTURER: |
| case KM_TAG_ATTESTATION_ID_MEID: |
| case KM_TAG_ATTESTATION_ID_MODEL: |
| case KM_TAG_ATTESTATION_ID_PRODUCT: |
| case KM_TAG_ATTESTATION_ID_SERIAL: |
| case KM_TAG_CERTIFICATE_NOT_AFTER: |
| case KM_TAG_CERTIFICATE_NOT_BEFORE: |
| case KM_TAG_CERTIFICATE_SERIAL: |
| case KM_TAG_CERTIFICATE_SUBJECT: |
| case KM_TAG_RESET_SINCE_ID_ROTATION: |
| break; |
| |
| // Unimplemented tags for which we return an error. |
| case KM_TAG_DEVICE_UNIQUE_ATTESTATION: |
| return KM_ERROR_INVALID_ARGUMENT; |
| |
| // Unimplemented tags we silently ignore. |
| case KM_TAG_ALLOW_WHILE_ON_BODY: |
| break; |
| |
| // Obsolete tags we silently ignore. |
| case KM_TAG_ALL_APPLICATIONS: |
| case KM_TAG_ROLLBACK_RESISTANT: |
| case KM_TAG_CONFIRMATION_TOKEN: |
| |
| // Tags that should not be added to blobs. |
| case KM_TAG_APPLICATION_ID: |
| case KM_TAG_APPLICATION_DATA: |
| break; |
| |
| // Tags we ignore because they'll be set below. |
| case KM_TAG_BOOT_PATCHLEVEL: |
| case KM_TAG_ORIGIN: |
| case KM_TAG_OS_PATCHLEVEL: |
| case KM_TAG_OS_VERSION: |
| case KM_TAG_VENDOR_PATCHLEVEL: |
| break; |
| |
| // Tags that are hardware-enforced |
| case KM_TAG_ALGORITHM: |
| case KM_TAG_AUTH_TIMEOUT: |
| case KM_TAG_BLOB_USAGE_REQUIREMENTS: |
| case KM_TAG_BLOCK_MODE: |
| case KM_TAG_CALLER_NONCE: |
| case KM_TAG_DIGEST: |
| case KM_TAG_EARLY_BOOT_ONLY: |
| case KM_TAG_ECIES_SINGLE_HASH_MODE: |
| case KM_TAG_EC_CURVE: |
| case KM_TAG_KDF: |
| case KM_TAG_KEY_SIZE: |
| case KM_TAG_MAX_USES_PER_BOOT: |
| case KM_TAG_MIN_MAC_LENGTH: |
| case KM_TAG_MIN_SECONDS_BETWEEN_OPS: |
| case KM_TAG_NO_AUTH_REQUIRED: |
| case KM_TAG_PADDING: |
| case KM_TAG_PURPOSE: |
| case KM_TAG_ROLLBACK_RESISTANCE: |
| case KM_TAG_RSA_OAEP_MGF_DIGEST: |
| case KM_TAG_RSA_PUBLIC_EXPONENT: |
| case KM_TAG_TRUSTED_CONFIRMATION_REQUIRED: |
| case KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED: |
| case KM_TAG_UNLOCKED_DEVICE_REQUIRED: |
| case KM_TAG_USER_SECURE_ID: |
| hw_enforced->push_back(entry); |
| break; |
| |
| // KM_TAG_STORAGE_KEY handling depends if the feature is enabled. |
| case KM_TAG_STORAGE_KEY: |
| #if WITH_HWWSK_SUPPORT |
| hw_enforced->push_back(entry); |
| break; |
| #else |
| return KM_ERROR_UNIMPLEMENTED; |
| #endif |
| |
| 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.enumerated |= entry.enumerated & HW_AUTH_FINGERPRINT; |
| #endif |
| hw_enforced->push_back(elem); |
| } break; |
| |
| case KM_TAG_USAGE_COUNT_LIMIT: |
| LOG_D("Found usage count limit tag: %u", entry.integer); |
| if (entry.integer == 1 && has_secure_deletion) { |
| // We can enforce a usage count of 1 in HW. |
| hw_enforced->push_back(entry); |
| } else { |
| // Otherwise we delegate to keystore. |
| sw_enforced->push_back(entry); |
| } |
| break; |
| |
| // Keystore-enforced tags |
| case KM_TAG_ACTIVE_DATETIME: |
| case KM_TAG_ALL_USERS: |
| case KM_TAG_CREATION_DATETIME: |
| case KM_TAG_EXPORTABLE: |
| case KM_TAG_INCLUDE_UNIQUE_ID: |
| case KM_TAG_MAX_BOOT_LEVEL: |
| case KM_TAG_ORIGINATION_EXPIRE_DATETIME: |
| case KM_TAG_USAGE_EXPIRE_DATETIME: |
| case KM_TAG_USER_ID: |
| sw_enforced->push_back(entry); |
| 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_params_.boot_os_version); |
| hw_enforced->push_back(TAG_OS_PATCHLEVEL, boot_params_.boot_os_patchlevel); |
| |
| if (vendor_patchlevel_.has_value()) { |
| hw_enforced->push_back(TAG_VENDOR_PATCHLEVEL, |
| vendor_patchlevel_.value()); |
| } |
| if (boot_patchlevel_.has_value()) { |
| hw_enforced->push_back(TAG_BOOT_PATCHLEVEL, boot_patchlevel_.value()); |
| } |
| |
| 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 = boot_params_.verified_boot_key.begin(); |
| root_of_trust.blob.data_length = |
| boot_params_.verified_boot_key.buffer_size(); |
| hidden->push_back(root_of_trust); |
| |
| root_of_trust.blob.data = |
| reinterpret_cast<const uint8_t*>(&boot_params_.verified_boot_state); |
| root_of_trust.blob.data_length = sizeof(boot_params_.verified_boot_state); |
| hidden->push_back(root_of_trust); |
| |
| root_of_trust.blob.data = |
| reinterpret_cast<const uint8_t*>(&boot_params_.device_locked); |
| root_of_trust.blob.data_length = sizeof(boot_params_.device_locked); |
| hidden->push_back(root_of_trust); |
| |
| return TranslateAuthorizationSetError(hidden->is_valid()); |
| } |
| |
| keymaster_error_t TrustyKeymasterContext::GetKdfState( |
| EncryptedKey* info) const { |
| long rc = hwkey_open(); |
| if (rc < 0) { |
| LOG_S("Error failing to open a connection to hwkey: %d", rc); |
| return KM_ERROR_UNKNOWN_ERROR; |
| } |
| |
| hwkey_session_t session = (hwkey_session_t)rc; |
| struct hwkey_versioned_key_options opt = { |
| .kdf_version = HWKEY_KDF_VERSION_BEST, |
| .shared_key = false, |
| .rollback_version_source = HWKEY_ROLLBACK_COMMITTED_VERSION, |
| .os_rollback_version = HWKEY_ROLLBACK_VERSION_CURRENT, |
| .context = NULL, |
| .context_len = 0, |
| .key = NULL, |
| .key_len = 0, |
| }; |
| rc = hwkey_derive_versioned(session, &opt); |
| if (rc < 0) { |
| LOG_S("Error deriving versioned master key: %d", rc); |
| hwkey_close(session); |
| return KM_ERROR_UNKNOWN_ERROR; |
| } |
| hwkey_close(session); |
| // Any versioned format will put the KDF selection into the correct mode. |
| info->format = AES_GCM_WITH_SW_ENFORCED_VERSIONED; |
| info->kdf_version = opt.kdf_version; |
| info->addl_info = opt.os_rollback_version; |
| return KM_ERROR_OK; |
| } |
| |
| keymaster_error_t TrustyKeymasterContext::CreateAuthEncryptedKeyBlob( |
| const AuthorizationSet& key_description, |
| const KeymasterKeyBlob& key_material, |
| const AuthorizationSet& hw_enforced, |
| const AuthorizationSet& sw_enforced, |
| const std::optional<SecureDeletionData>& secure_deletion_data, |
| KeymasterKeyBlob* blob) const { |
| AuthorizationSet hidden; |
| keymaster_error_t error = |
| BuildHiddenAuthorizations(key_description, &hidden); |
| if (error != KM_ERROR_OK) |
| return error; |
| |
| KeymasterKeyBlob master_key; |
| EncryptedKey info; |
| error = GetKdfState(&info); |
| if (error != KM_ERROR_OK) { |
| return error; |
| } |
| error = DeriveMasterKey(&master_key, info); |
| if (error != KM_ERROR_OK) { |
| return error; |
| } |
| |
| KmErrorOr<EncryptedKey> encrypted_key; |
| if (secure_deletion_data) { |
| encrypted_key = EncryptKey( |
| key_material, AES_GCM_WITH_SECURE_DELETION_VERSIONED, |
| hw_enforced, sw_enforced, hidden, *secure_deletion_data, |
| master_key, *this /* random */); |
| } else { |
| encrypted_key = EncryptKey( |
| key_material, AES_GCM_WITH_SW_ENFORCED_VERSIONED, hw_enforced, |
| sw_enforced, hidden, SecureDeletionData{}, master_key, |
| *this /* random */); |
| } |
| if (!encrypted_key) { |
| return encrypted_key.error(); |
| } |
| |
| encrypted_key->kdf_version = info.kdf_version; |
| encrypted_key->addl_info = info.addl_info; |
| KmErrorOr<KeymasterKeyBlob> serialized_key = SerializeAuthEncryptedBlob( |
| *encrypted_key, hw_enforced, sw_enforced, |
| secure_deletion_data ? secure_deletion_data->key_slot : 0); |
| |
| if (!serialized_key) { |
| return serialized_key.error(); |
| } |
| |
| *blob = std::move(*serialized_key); |
| return KM_ERROR_OK; |
| } |
| |
| class KeySlotCleanup { |
| public: |
| KeySlotCleanup(const SecureDeletionSecretStorage& storage, |
| uint32_t key_slot) |
| : storage_(storage), key_slot_(key_slot) {} |
| ~KeySlotCleanup() { |
| if (key_slot_ != 0) { |
| storage_.DeleteKey(key_slot_); |
| } |
| } |
| |
| void release() { key_slot_ = 0; } |
| |
| private: |
| const SecureDeletionSecretStorage& storage_; |
| uint32_t key_slot_; |
| }; |
| |
| 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 { |
| bool request_rollback_resistance = |
| key_description.Contains(TAG_ROLLBACK_RESISTANCE); |
| bool request_usage_limit = |
| key_description.Contains(TAG_USAGE_COUNT_LIMIT, 1); |
| bool request_secure_deletion = |
| request_rollback_resistance || request_usage_limit; |
| |
| LOG_D("Getting secure deletion data", 0); |
| std::optional<SecureDeletionData> sdd; |
| if (kUseSecureDeletion) { |
| sdd = secure_deletion_secret_storage_.CreateDataForNewKey( |
| request_secure_deletion, |
| /* is_upgrade */ false); |
| } |
| |
| if (sdd) { |
| LOG_D("Got secure deletion data, FR size = %zu, SD size = %zu, slot = %u", |
| sdd->factory_reset_secret.buffer_size(), |
| sdd->secure_deletion_secret.buffer_size(), sdd->key_slot); |
| } else if (!kUseSecureDeletion) { |
| LOG_I("Not using secure deletion", 0); |
| } else { |
| LOG_W("Failed to get secure deletion data. storageproxy not up?", 0); |
| } |
| |
| uint32_t key_slot = sdd ? sdd->key_slot : 0; |
| bool has_secure_deletion = key_slot != 0; |
| if (request_secure_deletion && !has_secure_deletion) { |
| LOG_E("Secure deletion requested (rollback_resistance:%d, usage_limit:%d) but no slot available!", |
| request_rollback_resistance, request_usage_limit); |
| return KM_ERROR_ROLLBACK_RESISTANCE_UNAVAILABLE; |
| } |
| |
| // At this point we may have stored a secure deletion secret for this key. |
| // If something goes wrong before we return the blob, that slot will leak. |
| // Create an object to clean up on the error paths. |
| KeySlotCleanup key_slot_cleanup(secure_deletion_secret_storage_, key_slot); |
| |
| keymaster_error_t error = |
| SetAuthorizations(key_description, origin, hw_enforced, sw_enforced, |
| has_secure_deletion); |
| |
| if (error != KM_ERROR_OK) { |
| return error; |
| } |
| |
| error = CreateAuthEncryptedKeyBlob(key_description, key_material, |
| *hw_enforced, *sw_enforced, |
| std::move(sdd), blob); |
| if (error != KM_ERROR_OK) { |
| return error; |
| } |
| |
| key_slot_cleanup.release(); |
| return KM_ERROR_OK; |
| } |
| |
| 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); |
| LOG_I("Upgrading key blob", 1); |
| if (error != KM_ERROR_OK) { |
| return error; |
| } |
| |
| bool set_changed = false; |
| if (boot_params_.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. |
| |
| if (int pos = key->sw_enforced().find(TAG_OS_VERSION); |
| pos != -1 && |
| key->sw_enforced()[pos].integer != boot_params_.boot_os_version) { |
| set_changed = true; |
| key->sw_enforced()[pos].integer = boot_params_.boot_os_version; |
| } |
| } |
| |
| if (!UpgradeIntegerTag(TAG_OS_VERSION, boot_params_.boot_os_version, |
| &key->hw_enforced(), &set_changed) || |
| !UpgradeIntegerTag(TAG_OS_PATCHLEVEL, boot_params_.boot_os_patchlevel, |
| &key->hw_enforced(), &set_changed) || |
| (vendor_patchlevel_.has_value() && |
| !UpgradeIntegerTag(TAG_VENDOR_PATCHLEVEL, vendor_patchlevel_.value(), |
| &key->hw_enforced(), &set_changed)) || |
| (boot_patchlevel_.has_value() && |
| !UpgradeIntegerTag(TAG_BOOT_PATCHLEVEL, boot_patchlevel_.value(), |
| &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) { |
| return KM_ERROR_OK; |
| } |
| |
| bool has_secure_deletion = false; |
| if (key->secure_deletion_slot() != 0) { |
| LOG_D("Upgrading rollback-protected key blob in slot %u", |
| key->secure_deletion_slot()); |
| has_secure_deletion = true; |
| } |
| if (!has_secure_deletion && |
| upgrade_params.Contains(TAG_ROLLBACK_RESISTANCE)) { |
| LOG_D("Upgrading non rollback-protected key, adding rollback protection", |
| 0); |
| has_secure_deletion = true; |
| } |
| |
| std::optional<SecureDeletionData> sdd; |
| if (kUseSecureDeletion) { |
| sdd = secure_deletion_secret_storage_.CreateDataForNewKey( |
| has_secure_deletion, true /* is_upgrade */); |
| } |
| |
| // At this point we may have stored a secure deletion secret for this key. |
| // If something goes wrong before we return the blob, that slot will leak. |
| // Create an object to clean up on the error paths. |
| KeySlotCleanup key_slot_cleanup(secure_deletion_secret_storage_, |
| sdd ? sdd->key_slot : 0); |
| |
| error = CreateAuthEncryptedKeyBlob(upgrade_params, key->key_material(), |
| key->hw_enforced(), key->sw_enforced(), |
| std::move(sdd), upgraded_key); |
| if (error != KM_ERROR_OK) { |
| return error; |
| } |
| |
| key_slot_cleanup.release(); |
| return KM_ERROR_OK; |
| } |
| |
| constexpr std::array<uint8_t, 7> kKeystoreKeyBlobMagic = {'p', 'K', 'M', 'b', |
| 'l', 'o', 'b'}; |
| constexpr size_t kKeystoreKeyTypeOffset = kKeystoreKeyBlobMagic.size(); |
| constexpr size_t kKeystoreKeyBlobPrefixSize = kKeystoreKeyTypeOffset + 1; |
| |
| KmErrorOr<DeserializedKey> TrustyKeymasterContext::DeserializeKmCompatKeyBlob( |
| const KeymasterKeyBlob& blob) const { |
| // This blob has a keystore km_compat prefix. This means that it was |
| // created by keystore calling TrustyKeymaster through the km_compat layer. |
| // The km_compat layer adds this prefix to determine whether it's actually a |
| // hardware blob that should be passed through to Keymaster, or whether it's |
| // a software only key and should be used by the emulation layer. |
| // |
| // In the case of hardware blobs, km_compat strips the prefix before handing |
| // the blob to Keymaster. In the case of software blobs, km_compat never |
| // hands the blob to Keymaster. |
| // |
| // The fact that we've received this prefixed blob means that it was created |
| // through km_compat... but the device has now been upgraded from |
| // TrustyKeymaster to TrustyKeyMint, and so keystore is no longer using the |
| // km_compat layer, and the blob is just passed through with its prefix |
| // intact. |
| auto keyType = *(blob.begin() + kKeystoreKeyTypeOffset); |
| switch (keyType) { |
| case 0: |
| // This is a hardware blob. Strip the prefix and use the blob. |
| return DeserializeAuthEncryptedBlob( |
| KeymasterKeyBlob(blob.begin() + kKeystoreKeyBlobPrefixSize, |
| blob.size() - kKeystoreKeyBlobPrefixSize)); |
| |
| case 1: |
| LOG_E("Software key blobs are not supported.", 0); |
| return KM_ERROR_INVALID_KEY_BLOB; |
| |
| default: |
| LOG_E("Invalid keystore blob prefix value %d", keyType); |
| return KM_ERROR_INVALID_KEY_BLOB; |
| } |
| } |
| |
| bool is_km_compat_blob(const KeymasterKeyBlob& blob) { |
| return blob.size() >= kKeystoreKeyBlobPrefixSize && |
| std::equal(kKeystoreKeyBlobMagic.begin(), |
| kKeystoreKeyBlobMagic.end(), blob.begin()); |
| } |
| |
| KmErrorOr<DeserializedKey> TrustyKeymasterContext::DeserializeKeyBlob( |
| const KeymasterKeyBlob& blob) const { |
| if (is_km_compat_blob(blob)) { |
| return DeserializeKmCompatKeyBlob(blob); |
| } else { |
| return DeserializeAuthEncryptedBlob(blob); |
| } |
| } |
| |
| keymaster_error_t TrustyKeymasterContext::ParseKeyBlob( |
| const KeymasterKeyBlob& blob, |
| const AuthorizationSet& additional_params, |
| UniquePtr<Key>* key) const { |
| keymaster_error_t error; |
| |
| if (!key) { |
| return KM_ERROR_UNEXPECTED_NULL_POINTER; |
| } |
| |
| KmErrorOr<DeserializedKey> deserialized_key = DeserializeKeyBlob(blob); |
| if (!deserialized_key) { |
| return deserialized_key.error(); |
| } |
| LOG_D("Deserialized blob with format: %d", |
| deserialized_key->encrypted_key.format); |
| |
| KeymasterKeyBlob master_key; |
| error = DeriveMasterKey(&master_key, deserialized_key->encrypted_key); |
| if (error != KM_ERROR_OK) { |
| return error; |
| } |
| |
| AuthorizationSet hidden; |
| error = BuildHiddenAuthorizations(additional_params, &hidden); |
| if (error != KM_ERROR_OK) { |
| return error; |
| } |
| |
| SecureDeletionData sdd; |
| if (deserialized_key->encrypted_key.format == |
| AES_GCM_WITH_SECURE_DELETION || |
| deserialized_key->encrypted_key.format == |
| AES_GCM_WITH_SECURE_DELETION_VERSIONED) { |
| // This key requires secure deletion data. |
| sdd = secure_deletion_secret_storage_.GetDataForKey( |
| deserialized_key->key_slot); |
| } |
| |
| LOG_D("Decrypting blob with format: %d", |
| deserialized_key->encrypted_key.format); |
| KmErrorOr<KeymasterKeyBlob> key_material = |
| DecryptKey(*deserialized_key, hidden, sdd, master_key); |
| if (!key_material) { |
| return key_material.error(); |
| } |
| |
| keymaster_algorithm_t algorithm; |
| if (!deserialized_key->hw_enforced.GetTagValue(TAG_ALGORITHM, &algorithm)) { |
| return KM_ERROR_INVALID_KEY_BLOB; |
| } |
| |
| auto factory = GetKeyFactory(algorithm); |
| error = factory->LoadKey(std::move(*key_material), additional_params, |
| std::move(deserialized_key->hw_enforced), |
| std::move(deserialized_key->sw_enforced), key); |
| if (key && key->get()) { |
| (*key)->set_secure_deletion_slot(deserialized_key->key_slot); |
| } |
| |
| return error; |
| } |
| |
| keymaster_error_t TrustyKeymasterContext::DeleteKey( |
| const KeymasterKeyBlob& blob) const { |
| KmErrorOr<DeserializedKey> deserialized_key = DeserializeKeyBlob(blob); |
| if (deserialized_key) { |
| LOG_D("Deserialized blob with format: %d", |
| deserialized_key->encrypted_key.format); |
| secure_deletion_secret_storage_.DeleteKey(deserialized_key->key_slot); |
| } |
| |
| return KM_ERROR_OK; |
| } |
| |
| keymaster_error_t TrustyKeymasterContext::DeleteAllKeys() const { |
| secure_deletion_secret_storage_.DeleteAllKeys(); |
| return KM_ERROR_OK; |
| } |
| |
| 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() { |
| uint8_t rand_seed[kRngReseedSize]; |
| memset(rand_seed, 0, kRngReseedSize); |
| if (trusty_rng_hw_rand(rand_seed, 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, 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 EncryptedKey& enc_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); |
| hwkey_close(session); |
| return KM_ERROR_MEMORY_ALLOCATION_FAILED; |
| } |
| |
| if (enc_key.format < AES_GCM_WITH_SW_ENFORCED_VERSIONED) { |
| 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 legacy master key: %d", rc); |
| hwkey_close(session); |
| return KM_ERROR_UNKNOWN_ERROR; |
| } |
| } else { |
| struct hwkey_versioned_key_options opt = { |
| .kdf_version = enc_key.kdf_version, |
| .shared_key = false, |
| .rollback_version_source = HWKEY_ROLLBACK_COMMITTED_VERSION, |
| .os_rollback_version = enc_key.addl_info, |
| .context = kMasterKeyDerivationData, |
| .context_len = sizeof(kMasterKeyDerivationData), |
| .key = master_key->writable_data(), |
| .key_len = kAesKeySize, |
| }; |
| rc = hwkey_derive_versioned(session, &opt); |
| if (rc < 0) { |
| LOG_S("Error deriving versioned master key: %d", rc); |
| hwkey_close(session); |
| return KM_ERROR_UNKNOWN_ERROR; |
| } |
| } |
| |
| hwkey_close(session); |
| LOG_D("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_params_.boot_os_version = os_version; |
| boot_params_.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_params_.boot_os_version; |
| *os_patchlevel = boot_params_.boot_os_patchlevel; |
| } |
| |
| const AttestationContext::VerifiedBootParams* |
| TrustyKeymasterContext::GetVerifiedBootParams(keymaster_error_t* error) const { |
| VerifiedBootParams& vb_parms = |
| const_cast<VerifiedBootParams&>(verified_boot_params_); |
| |
| if (boot_params_.verified_boot_key.buffer_size() == 0) { |
| // If an empty verified boot key was passed by the boot loader, set the |
| // verfified boot key in attestation parameters to 32 bytes of all |
| // zeros. |
| vb_parms.verified_boot_key = {allZerosOrHashOfVerifiedBootKey, |
| sizeof(allZerosOrHashOfVerifiedBootKey)}; |
| } else if (boot_params_.verified_boot_key.buffer_size() > 0 && |
| boot_params_.verified_boot_key.buffer_size() <= 32) { |
| vb_parms.verified_boot_key = { |
| boot_params_.verified_boot_key.begin(), |
| boot_params_.verified_boot_key.buffer_size()}; |
| } else if (boot_params_.verified_boot_key.buffer_size() > 32) { |
| // If the verified boot key itself was passed by the boot loader, set |
| // SHA-256 hash of it to the verified boot key parameter of the |
| // attetation information. |
| vb_parms.verified_boot_key = { |
| SHA256(boot_params_.verified_boot_key.begin(), |
| boot_params_.verified_boot_key.buffer_size(), |
| allZerosOrHashOfVerifiedBootKey), |
| SHA256_DIGEST_LENGTH}; |
| } |
| |
| vb_parms.verified_boot_hash = { |
| boot_params_.verified_boot_hash.begin(), |
| boot_params_.verified_boot_hash.buffer_size()}; |
| vb_parms.verified_boot_state = boot_params_.verified_boot_state; |
| vb_parms.device_locked = boot_params_.device_locked; |
| |
| *error = KM_ERROR_OK; |
| return &verified_boot_params_; |
| } |
| |
| #define PROTO_BYTES_DOES_NOT_MATCH_BLOB(blob, proto) \ |
| ((blob).data_length != (proto).size) || \ |
| (memcmp((blob).data, (proto).bytes, (proto).size) != 0) |
| |
| keymaster_error_t TrustyKeymasterContext::VerifyAndCopyDeviceIds( |
| const AuthorizationSet& attestation_params, |
| AuthorizationSet* values_to_attest) const { |
| SecureStorageManager* ss_manager = SecureStorageManager::get_instance(); |
| if (ss_manager == nullptr) { |
| LOG_E("Failed to open secure storage session.", 0); |
| return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED; |
| } |
| |
| AttestationIds ids; |
| auto err = ss_manager->ReadAttestationIds(&ids); |
| if (err != KM_ERROR_OK) { |
| return err; |
| } |
| |
| bool found_mismatch = false; |
| for (auto& entry : attestation_params) { |
| switch (entry.tag) { |
| case KM_TAG_ATTESTATION_ID_BRAND: |
| found_mismatch |= |
| PROTO_BYTES_DOES_NOT_MATCH_BLOB(entry.blob, ids.brand); |
| values_to_attest->push_back(entry); |
| break; |
| |
| case KM_TAG_ATTESTATION_ID_DEVICE: |
| found_mismatch |= |
| PROTO_BYTES_DOES_NOT_MATCH_BLOB(entry.blob, ids.device); |
| values_to_attest->push_back(entry); |
| break; |
| |
| case KM_TAG_ATTESTATION_ID_PRODUCT: |
| found_mismatch |= |
| PROTO_BYTES_DOES_NOT_MATCH_BLOB(entry.blob, ids.product); |
| values_to_attest->push_back(entry); |
| break; |
| |
| case KM_TAG_ATTESTATION_ID_SERIAL: |
| found_mismatch |= |
| PROTO_BYTES_DOES_NOT_MATCH_BLOB(entry.blob, ids.serial); |
| values_to_attest->push_back(entry); |
| break; |
| |
| case KM_TAG_ATTESTATION_ID_IMEI: |
| found_mismatch |= |
| PROTO_BYTES_DOES_NOT_MATCH_BLOB(entry.blob, ids.imei); |
| values_to_attest->push_back(entry); |
| break; |
| |
| case KM_TAG_ATTESTATION_ID_MEID: |
| found_mismatch |= |
| PROTO_BYTES_DOES_NOT_MATCH_BLOB(entry.blob, ids.meid); |
| values_to_attest->push_back(entry); |
| break; |
| |
| case KM_TAG_ATTESTATION_ID_MANUFACTURER: |
| found_mismatch |= PROTO_BYTES_DOES_NOT_MATCH_BLOB(entry.blob, |
| ids.manufacturer); |
| values_to_attest->push_back(entry); |
| break; |
| |
| case KM_TAG_ATTESTATION_ID_MODEL: |
| found_mismatch |= |
| PROTO_BYTES_DOES_NOT_MATCH_BLOB(entry.blob, ids.model); |
| values_to_attest->push_back(entry); |
| break; |
| |
| default: |
| // Ignore non-ID tags. |
| break; |
| } |
| } |
| |
| if (found_mismatch) { |
| values_to_attest->Clear(); |
| return KM_ERROR_CANNOT_ATTEST_IDS; |
| } |
| |
| return KM_ERROR_OK; |
| } |
| |
| Buffer TrustyKeymasterContext::GenerateUniqueId( |
| uint64_t creation_date_time, |
| const keymaster_blob_t& application_id, |
| bool reset_since_rotation, |
| keymaster_error_t* error) const { |
| if (unique_id_hbk_.empty()) { |
| KeymasterKeyBlob hbk; |
| keymaster_error_t derive_error = |
| enforcement_policy_.GetUniqueIdKey(&hbk); |
| if (derive_error != KM_ERROR_OK) { |
| LOG_E("Failed to derive unique ID HBK: %d", derive_error); |
| *error = derive_error; |
| return {}; |
| } |
| unique_id_hbk_ = std::vector(hbk.begin(), hbk.end()); |
| } |
| |
| *error = KM_ERROR_OK; |
| return keymaster::generate_unique_id(unique_id_hbk_, creation_date_time, |
| application_id, reset_since_rotation); |
| } |
| |
| 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, |
| std::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; |
| boot_params_.verified_boot_hash.Reinitialize(verified_boot_hash); |
| root_of_trust_set_ = true; |
| boot_params_.verified_boot_state = verified_boot_state; |
| boot_params_.device_locked = device_locked; |
| boot_params_.verified_boot_key.Reinitialize("", 0); |
| |
| if (verified_boot_key.buffer_size()) { |
| boot_params_.verified_boot_key.Reinitialize(verified_boot_key); |
| } else { |
| // If no boot key was passed, default to unverified/unlocked |
| boot_params_.verified_boot_state = KM_VERIFIED_BOOT_UNVERIFIED; |
| } |
| |
| if ((verified_boot_state != KM_VERIFIED_BOOT_VERIFIED) && |
| (verified_boot_state != KM_VERIFIED_BOOT_SELF_SIGNED)) { |
| // If the device image was not verified or self signed, it cannot be |
| // locked |
| boot_params_.device_locked = false; |
| } |
| |
| trusty_remote_provisioning_context_->SetBootParams(&boot_params_); |
| |
| 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( |
| std::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(std::move(transport_key), gcm_params, |
| std::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( |
| std::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; |
| } |
| |
| keymaster_error_t TrustyKeymasterContext::CheckConfirmationToken( |
| const uint8_t* input_data, |
| size_t input_data_size, |
| const uint8_t confirmation_token[kConfirmationTokenSize]) const { |
| // Note: ConfirmationUI is using the same secret key as auth tokens, the |
| // difference is that messages are prefixed using the message tag |
| // "confirmation token". |
| keymaster_key_blob_t auth_token_key; |
| keymaster_error_t error = GetAuthTokenKey(&auth_token_key); |
| if (error != KM_ERROR_OK) { |
| return error; |
| } |
| |
| uint8_t computed_hash[EVP_MAX_MD_SIZE]; |
| unsigned int computed_hash_length; |
| if (!HMAC(EVP_sha256(), auth_token_key.key_material, |
| auth_token_key.key_material_size, input_data, input_data_size, |
| computed_hash, &computed_hash_length)) { |
| return KM_ERROR_UNKNOWN_ERROR; |
| } |
| |
| if (computed_hash_length != kConfirmationTokenSize || |
| memcmp_s(computed_hash, confirmation_token, kConfirmationTokenSize) != |
| 0) { |
| return KM_ERROR_NO_USER_CONFIRMATION; |
| } |
| |
| return KM_ERROR_OK; |
| } |
| |
| } // namespace keymaster |