blob: b5440f35ceee92fec7c058d407e3d0edb22a33e5 [file] [log] [blame]
/*
* Copyright 2021, 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 "MicrodroidKeymasterContext.h"
#include <android-base/logging.h>
#include <keymaster/key.h>
#include <keymaster/key_blob_utils/auth_encrypted_key_blob.h>
#include <keymaster/key_blob_utils/software_keyblobs.h>
using namespace ::keymaster;
// This value is used for the ROOT_OF_TRUST tag which is only used in
// attestation records which aren't supported in this implementation so a
// constant doesn't cause any hard. MicroDroid SoftWare root-of-trust.
static uint8_t SWROT[] = {'M', 'D', 'S', 'W'};
static const KeymasterBlob microdroidSoftwareRootOfTrust(SWROT);
keymaster_error_t MicrodroidKeymasterContext::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;
if (key_description.GetTagValue(TAG_ROLLBACK_RESISTANCE)) {
return KM_ERROR_ROLLBACK_RESISTANCE_UNAVAILABLE;
}
error = SetKeyBlobAuthorizations(key_description, origin, os_version_, os_patchlevel_,
hw_enforced, sw_enforced);
if (error != KM_ERROR_OK) return error;
AuthorizationSet hidden;
error = BuildHiddenAuthorizations(key_description, &hidden, microdroidSoftwareRootOfTrust);
if (error != KM_ERROR_OK) return error;
CHECK(hw_enforced->empty());
// Note that the authorizations included in the blob are not encrypted. This
// doesn't pose a problem for the current applications but may be a
// candidate for hardening.
auto encrypted_key = EncryptKey(key_material, AES_GCM_WITH_SW_ENFORCED, *hw_enforced,
*sw_enforced, hidden, root_key_, random_, &error);
if (error != KM_ERROR_OK) return error;
*blob = SerializeAuthEncryptedBlob(encrypted_key, *hw_enforced, *sw_enforced, &error);
return error;
}
keymaster_error_t MicrodroidKeymasterContext::ParseKeyBlob(
const KeymasterKeyBlob& blob, const AuthorizationSet& additional_params,
UniquePtr<Key>* key) const {
keymaster_error_t error;
AuthorizationSet hidden;
error = BuildHiddenAuthorizations(additional_params, &hidden, microdroidSoftwareRootOfTrust);
if (error != KM_ERROR_OK) return error;
auto deserialized_key = DeserializeAuthEncryptedBlob(blob, &error);
if (error != KM_ERROR_OK) return error;
keymaster_algorithm_t algorithm;
if (!deserialized_key.sw_enforced.GetTagValue(TAG_ALGORITHM, &algorithm)) {
return KM_ERROR_INVALID_ARGUMENT;
}
auto key_material = DecryptKey(deserialized_key, hidden, root_key_, &error);
if (error != KM_ERROR_OK) return error;
auto factory = GetKeyFactory(algorithm);
return factory->LoadKey(move(key_material), additional_params,
move(deserialized_key.hw_enforced), move(deserialized_key.sw_enforced),
key);
}
static bool UpgradeIntegerTag(keymaster_tag_t tag, uint32_t value, AuthorizationSet* set) {
int index = set->find(tag);
if (index == -1) {
keymaster_key_param_t param;
param.tag = tag;
param.integer = value;
set->push_back(param);
return true;
}
if (set->params[index].integer > value) return false;
if (set->params[index].integer != value) {
set->params[index].integer = value;
}
return true;
}
keymaster_error_t MicrodroidKeymasterContext::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;
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->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 = os_version_;
}
}
}
if (!UpgradeIntegerTag(TAG_OS_VERSION, os_version_, &key->sw_enforced()) ||
!UpgradeIntegerTag(TAG_OS_PATCHLEVEL, os_patchlevel_, &key->sw_enforced()))
// One of the version fields would have been a downgrade. Not allowed.
return KM_ERROR_INVALID_ARGUMENT;
AuthorizationSet hidden;
error = BuildHiddenAuthorizations(upgrade_params, &hidden, microdroidSoftwareRootOfTrust);
if (error != KM_ERROR_OK) return error;
auto encrypted_key =
EncryptKey(key->key_material(), AES_GCM_WITH_SW_ENFORCED, key->hw_enforced(),
key->sw_enforced(), hidden, root_key_, random_, &error);
if (error != KM_ERROR_OK) return error;
*upgraded_key = SerializeAuthEncryptedBlob(encrypted_key, key->hw_enforced(),
key->sw_enforced(), &error);
return error;
}