blob: f7aaa3d4a72e8ca750892e0afe5be430b179e406 [file] [log] [blame]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "arc/keymaster/context/arc_keymaster_context.h"
#include <algorithm>
#include <string>
#include <utility>
#include <base/logging.h>
#include <base/stl_util.h>
#include <keymaster/android_keymaster_utils.h>
#include <keymaster/key_blob_utils/integrity_assured_key_blob.h>
#include <keymaster/key_blob_utils/software_keyblobs.h>
#include "arc/keymaster/context/chaps_client.h"
#include "arc/keymaster/context/openssl_utils.h"
namespace arc {
namespace keymaster {
namespace context {
namespace {
bool DeserializeKeyMaterialToBlob(const std::string& key_material,
::keymaster::KeymasterKeyBlob* output) {
if (!output->Reset(key_material.size()))
return false;
uint8_t* end = std::copy(key_material.begin(), key_material.end(),
output->writable_data());
CHECK_EQ(end - output->key_material, output->key_material_size);
return true;
}
bool DeserializeKeyDataToBlob(const KeyData& key_data,
::keymaster::KeymasterKeyBlob* output) {
if (!output->Reset(key_data.ByteSizeLong()))
return false;
uint8_t* end =
key_data.SerializeWithCachedSizesToArray(output->writable_data());
return end - output->key_material == output->key_material_size;
}
void SerializeAuthorizationSet(const ::keymaster::AuthorizationSet& auth_set,
std::string* output) {
output->resize(auth_set.SerializedSize());
uint8_t* buffer = reinterpret_cast<uint8_t*>(base::data(*output));
auth_set.Serialize(buffer, buffer + output->size());
}
bool DeserializeAuthorizationSet(const std::string& serialized_auth_set,
::keymaster::AuthorizationSet* output) {
std::string mutable_auth_set(serialized_auth_set);
const uint8_t* buffer =
reinterpret_cast<uint8_t*>(base::data(mutable_auth_set));
return output->Deserialize(&buffer, buffer + serialized_auth_set.size());
}
brillo::Blob SerializeAuthorizationSetToBlob(
const ::keymaster::AuthorizationSet& authorization_set) {
brillo::Blob blob(authorization_set.SerializedSize());
authorization_set.Serialize(blob.data(), blob.data() + blob.size());
return blob;
}
bool UpgradeIntegerTag(keymaster_tag_t tag,
uint32_t value,
::keymaster::AuthorizationSet* authorization_set,
bool* authorization_set_did_change) {
*authorization_set_did_change = false;
int tag_index = authorization_set->find(tag);
if (tag_index == -1) {
keymaster_key_param_t key_param;
key_param.tag = tag;
key_param.integer = value;
authorization_set->push_back(key_param);
*authorization_set_did_change = true;
return true;
}
if (authorization_set->params[tag_index].integer > value)
return false;
if (authorization_set->params[tag_index].integer != value) {
authorization_set->params[tag_index].integer = value;
*authorization_set_did_change = true;
}
return true;
}
KeyData PackToArcKeyData(const ::keymaster::KeymasterKeyBlob& key_material,
const ::keymaster::AuthorizationSet& hw_enforced,
const ::keymaster::AuthorizationSet& sw_enforced) {
KeyData key_data;
// Copy key material.
key_data.mutable_arc_key()->set_key_material(key_material.key_material,
key_material.key_material_size);
// Serialize hardware enforced authorization set.
SerializeAuthorizationSet(hw_enforced, key_data.mutable_hw_enforced_tags());
// Serialize software enforced authorization set.
SerializeAuthorizationSet(sw_enforced, key_data.mutable_sw_enforced_tags());
return key_data;
}
bool UnpackFromArcKeyData(const KeyData& key_data,
::keymaster::KeymasterKeyBlob* key_material,
::keymaster::AuthorizationSet* hw_enforced,
::keymaster::AuthorizationSet* sw_enforced) {
// For ARC keys, deserialize the actual key material into |key_material|.
if (key_data.data_case() == KeyData::DataCase::kArcKey &&
!DeserializeKeyMaterialToBlob(key_data.arc_key().key_material(),
key_material)) {
return false;
}
// For any other key type, store the full |key_data| into |key_material|.
if (key_data.data_case() != KeyData::DataCase::kArcKey &&
!DeserializeKeyDataToBlob(key_data, key_material)) {
return false;
}
// Deserialize hardware enforced authorization set.
if (!DeserializeAuthorizationSet(key_data.hw_enforced_tags(), hw_enforced))
return false;
// Deserialize software enforced authorization set.
return DeserializeAuthorizationSet(key_data.sw_enforced_tags(), sw_enforced);
}
base::Optional<keymaster_algorithm_t> FindAlgorithmTag(
const ::keymaster::AuthorizationSet& hw_enforced,
const ::keymaster::AuthorizationSet& sw_enforced) {
keymaster_algorithm_t algorithm;
if (!hw_enforced.GetTagValue(::keymaster::TAG_ALGORITHM, &algorithm) &&
!sw_enforced.GetTagValue(::keymaster::TAG_ALGORITHM, &algorithm))
return base::nullopt;
return algorithm;
}
} // anonymous namespace
ArcKeymasterContext::ArcKeymasterContext()
: rsa_key_factory_(context_adaptor_.GetWeakPtr(), KM_ALGORITHM_RSA) {}
ArcKeymasterContext::~ArcKeymasterContext() = default;
keymaster_error_t ArcKeymasterContext::CreateKeyBlob(
const ::keymaster::AuthorizationSet& key_description,
const keymaster_key_origin_t origin,
const ::keymaster::KeymasterKeyBlob& key_material,
::keymaster::KeymasterKeyBlob* key_blob,
::keymaster::AuthorizationSet* hw_enforced,
::keymaster::AuthorizationSet* sw_enforced) const {
keymaster_error_t error =
SetKeyBlobAuthorizations(key_description, origin, os_version_,
os_patchlevel_, hw_enforced, sw_enforced);
if (error != KM_ERROR_OK)
return error;
::keymaster::AuthorizationSet hidden;
error = BuildHiddenAuthorizations(key_description, &hidden,
::keymaster::softwareRootOfTrust);
if (error != KM_ERROR_OK)
return error;
return SerializeKeyDataBlob(key_material, hidden, *hw_enforced, *sw_enforced,
key_blob);
}
keymaster_error_t ArcKeymasterContext::ParseKeyBlob(
const ::keymaster::KeymasterKeyBlob& key_blob,
const ::keymaster::AuthorizationSet& additional_params,
::keymaster::UniquePtr<::keymaster::Key>* key) const {
if (!key)
return KM_ERROR_OUTPUT_PARAMETER_NULL;
::keymaster::AuthorizationSet hw_enforced;
::keymaster::AuthorizationSet sw_enforced;
::keymaster::KeymasterKeyBlob key_material;
keymaster_error_t error;
::keymaster::AuthorizationSet hidden;
error = BuildHiddenAuthorizations(additional_params, &hidden,
::keymaster::softwareRootOfTrust);
if (error != KM_ERROR_OK)
return error;
error = DeserializeBlob(key_blob, hidden, &key_material, &hw_enforced,
&sw_enforced, key);
if (error != KM_ERROR_OK)
return error;
if (*key)
return KM_ERROR_OK;
base::Optional<keymaster_algorithm_t> algorithm =
FindAlgorithmTag(hw_enforced, sw_enforced);
if (!algorithm.has_value())
return KM_ERROR_INVALID_ARGUMENT;
::keymaster::KeyFactory* factory = GetKeyFactory(algorithm.value());
return factory->LoadKey(move(key_material), additional_params,
move(hw_enforced), move(sw_enforced), key);
}
keymaster_error_t ArcKeymasterContext::UpgradeKeyBlob(
const ::keymaster::KeymasterKeyBlob& key_blob,
const ::keymaster::AuthorizationSet& upgrade_params,
::keymaster::KeymasterKeyBlob* upgraded_key) const {
// Deserialize |key_blob| so it can be upgraded.
::keymaster::AuthorizationSet hidden;
keymaster_error_t error = BuildHiddenAuthorizations(
upgrade_params, &hidden, ::keymaster::softwareRootOfTrust);
if (error != KM_ERROR_OK)
return error;
::keymaster::AuthorizationSet hw_enforced;
::keymaster::AuthorizationSet sw_enforced;
::keymaster::KeymasterKeyBlob key_material;
error = DeserializeBlob(key_blob, hidden, &key_material, &hw_enforced,
&sw_enforced, /*key=*/nullptr);
if (error != KM_ERROR_OK)
return error;
// Try to upgrade system version and patchlevel, return if upgrade fails.
bool os_version_did_change = false;
bool patchlevel_did_change = false;
if (!UpgradeIntegerTag(::keymaster::TAG_OS_VERSION, os_version_, &sw_enforced,
&os_version_did_change) ||
!UpgradeIntegerTag(::keymaster::TAG_OS_PATCHLEVEL, os_patchlevel_,
&sw_enforced, &patchlevel_did_change)) {
return KM_ERROR_INVALID_ARGUMENT;
}
// Do nothing if blob is already up to date.
if (!os_version_did_change && !patchlevel_did_change)
return KM_ERROR_OK;
// Serialize the new blob into |upgraded_key|.
return SerializeKeyDataBlob(key_material, hidden, hw_enforced, sw_enforced,
upgraded_key);
}
keymaster_error_t ArcKeymasterContext::DeserializeBlob(
const ::keymaster::KeymasterKeyBlob& key_blob,
const ::keymaster::AuthorizationSet& hidden,
::keymaster::KeymasterKeyBlob* key_material,
::keymaster::AuthorizationSet* hw_enforced,
::keymaster::AuthorizationSet* sw_enforced,
::keymaster::UniquePtr<::keymaster::Key>* key) const {
keymaster_error_t error;
error = DeserializeKeyDataBlob(key_blob, hidden, key_material, hw_enforced,
sw_enforced, key);
if (error == KM_ERROR_OK)
return error;
// Still need to parse insecure blobs when upgrading to the encrypted format.
// TODO(b/151146402) drop support for insecure blobs.
return DeserializeIntegrityAssuredBlob(key_blob, hidden, key_material,
hw_enforced, sw_enforced);
}
keymaster_error_t ArcKeymasterContext::SerializeKeyDataBlob(
const ::keymaster::KeymasterKeyBlob& key_material,
const ::keymaster::AuthorizationSet& hidden,
const ::keymaster::AuthorizationSet& hw_enforced,
const ::keymaster::AuthorizationSet& sw_enforced,
::keymaster::KeymasterKeyBlob* key_blob) const {
if (!key_blob)
return KM_ERROR_OUTPUT_PARAMETER_NULL;
KeyData key_data = PackToArcKeyData(key_material, hw_enforced, sw_enforced);
// Serialize key data into the output |key_blob|.
if (!SerializeKeyData(key_data, hidden, key_blob)) {
LOG(ERROR) << "Failed to serialize KeyData.";
return KM_ERROR_UNKNOWN_ERROR;
}
return KM_ERROR_OK;
}
keymaster_error_t ArcKeymasterContext::DeserializeKeyDataBlob(
const ::keymaster::KeymasterKeyBlob& key_blob,
const ::keymaster::AuthorizationSet& hidden,
::keymaster::KeymasterKeyBlob* key_material,
::keymaster::AuthorizationSet* hw_enforced,
::keymaster::AuthorizationSet* sw_enforced,
::keymaster::UniquePtr<::keymaster::Key>* key) const {
if (!key_material || !hw_enforced || !sw_enforced)
return KM_ERROR_OUTPUT_PARAMETER_NULL;
// Deserialize a KeyData object from the given |key_blob|.
base::Optional<KeyData> key_data = DeserializeKeyData(key_blob, hidden);
if (!key_data.has_value() || key_data->data_case() == KeyData::DATA_NOT_SET) {
LOG(ERROR) << "Failed to parse a KeyData from key blob.";
return KM_ERROR_INVALID_KEY_BLOB;
}
// Unpack Keymaster structures from KeyData.
if (!UnpackFromArcKeyData(key_data.value(), key_material, hw_enforced,
sw_enforced)) {
LOG(ERROR) << "Failed to unpack key blob.";
return KM_ERROR_INVALID_KEY_BLOB;
}
// Load it here if this is not an ARC key (it is a Chrome OS key).
if (!key_data->has_arc_key() && key) {
return LoadKey(std::move(key_data.value()), std::move(*hw_enforced),
std::move(*sw_enforced), key);
}
// Otherwise, return success and let Keymaster load ARC keys itself.
return KM_ERROR_OK;
}
keymaster_error_t ArcKeymasterContext::LoadKey(
KeyData&& key_data,
::keymaster::AuthorizationSet&& hw_enforced,
::keymaster::AuthorizationSet&& sw_enforced,
::keymaster::UniquePtr<::keymaster::Key>* key) const {
base::Optional<keymaster_algorithm_t> algorithm =
FindAlgorithmTag(hw_enforced, sw_enforced);
if (!algorithm.has_value())
return KM_ERROR_INVALID_ARGUMENT;
keymaster_error_t error;
switch (algorithm.value()) {
case KM_ALGORITHM_RSA:
error =
rsa_key_factory_.LoadKey(std::move(key_data), std::move(hw_enforced),
std::move(sw_enforced), key);
return error;
default:
return KM_ERROR_UNSUPPORTED_ALGORITHM;
}
}
bool ArcKeymasterContext::SerializeKeyData(
const KeyData& key_data,
const ::keymaster::AuthorizationSet& hidden,
::keymaster::KeymasterKeyBlob* key_blob) const {
// Fetch key.
ChapsClient chaps(context_adaptor_.GetWeakPtr());
base::Optional<brillo::SecureBlob> encryption_key =
chaps.ExportOrGenerateEncryptionKey();
if (!encryption_key.has_value())
return false;
// Initialize a KeyData blob. Allocated blobs should offer the same guarantees
// as brillo::SecureBlob (b/151103358).
brillo::SecureBlob data(key_data.ByteSizeLong());
key_data.SerializeWithCachedSizesToArray(data.data());
// Encrypt the KeyData blob. As of Android R KeyStore's client ID and data
// used in |auth_data| is empty. We still bind to it to comply with VTS tests.
brillo::Blob auth_data = SerializeAuthorizationSetToBlob(hidden);
base::Optional<brillo::Blob> encrypted =
Aes256GcmEncrypt(encryption_key.value(), auth_data, data);
if (!encrypted.has_value())
return false;
// Copy |encrypted| to output |key_blob|.
if (!key_blob->Reset(encrypted->size()))
return false;
std::copy(encrypted->begin(), encrypted->end(), key_blob->writable_data());
return true;
}
base::Optional<KeyData> ArcKeymasterContext::DeserializeKeyData(
const ::keymaster::KeymasterKeyBlob& key_blob,
const ::keymaster::AuthorizationSet& hidden) const {
// Fetch key.
ChapsClient chaps(context_adaptor_.GetWeakPtr());
base::Optional<brillo::SecureBlob> encryption_key =
chaps.ExportOrGenerateEncryptionKey();
if (!encryption_key.has_value())
return base::nullopt;
// Decrypt the KeyData blob.
brillo::Blob encrypted(key_blob.begin(), key_blob.end());
brillo::Blob auth_data = SerializeAuthorizationSetToBlob(hidden);
base::Optional<brillo::SecureBlob> unencrypted =
Aes256GcmDecrypt(encryption_key.value(), auth_data, encrypted);
if (!unencrypted.has_value())
return base::nullopt;
// Parse the |unencrypted| blob into a KeyData object and return it.
KeyData key_data;
if (!key_data.ParseFromArray(unencrypted->data(), unencrypted->size()))
return base::nullopt;
return key_data;
}
namespace internal {
brillo::Blob TestSerializeAuthorizationSetToBlob(
const ::keymaster::AuthorizationSet& authorization_set) {
return SerializeAuthorizationSetToBlob(authorization_set);
}
} // namespace internal
} // namespace context
} // namespace keymaster
} // namespace arc