blob: da320760396bd65ad8b5a9da07f43d55221520cd [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 <keymaster/soft_keymaster_context.h>
#include <memory>
#include <time.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include <keymaster/android_keymaster_utils.h>
#include <keymaster/logger.h>
#include "aes_key.h"
#include "auth_encrypted_key_blob.h"
#include "ec_keymaster0_key.h"
#include "hmac_key.h"
#include "integrity_assured_key_blob.h"
#include "keymaster0_engine.h"
#include "ocb_utils.h"
#include "openssl_err.h"
#include "rsa_keymaster0_key.h"
using std::unique_ptr;
namespace keymaster {
namespace {
static uint8_t master_key_bytes[AES_BLOCK_SIZE] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
const int NONCE_LENGTH = 12;
const int TAG_LENGTH = 16;
const KeymasterKeyBlob MASTER_KEY(master_key_bytes, array_length(master_key_bytes));
} // anonymous namespace
SoftKeymasterContext::SoftKeymasterContext(keymaster0_device_t* keymaster0_device) {
if (keymaster0_device && (keymaster0_device->flags & KEYMASTER_SOFTWARE_ONLY) == 0)
engine_.reset(new Keymaster0Engine(keymaster0_device));
rsa_factory_.reset(new RsaKeymaster0KeyFactory(this, engine_.get()));
ec_factory_.reset(new EcdsaKeymaster0KeyFactory(this, engine_.get()));
aes_factory_.reset(new AesKeyFactory(this));
hmac_factory_.reset(new HmacKeyFactory(this));
}
KeyFactory* SoftKeymasterContext::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();
default:
return nullptr;
}
}
static keymaster_algorithm_t supported_algorithms[] = {KM_ALGORITHM_RSA, KM_ALGORITHM_EC,
KM_ALGORITHM_AES, KM_ALGORITHM_HMAC};
keymaster_algorithm_t*
SoftKeymasterContext::GetSupportedAlgorithms(size_t* algorithms_count) const {
*algorithms_count = array_length(supported_algorithms);
return supported_algorithms;
}
OperationFactory* SoftKeymasterContext::GetOperationFactory(keymaster_algorithm_t algorithm,
keymaster_purpose_t purpose) 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;
}
static keymaster_error_t BuildHiddenAuthorizations(const AuthorizationSet& input_set,
AuthorizationSet* hidden) {
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);
keymaster_key_param_t root_of_trust;
root_of_trust.tag = KM_TAG_ROOT_OF_TRUST;
root_of_trust.blob.data = reinterpret_cast<const uint8_t*>("SW");
root_of_trust.blob.data_length = 2;
hidden->push_back(root_of_trust);
return TranslateAuthorizationSetError(hidden->is_valid());
}
static keymaster_error_t SetAuthorizations(const AuthorizationSet& key_description,
keymaster_key_origin_t origin,
AuthorizationSet* hw_enforced,
AuthorizationSet* sw_enforced) {
sw_enforced->Clear();
for (auto& entry : key_description) {
switch (entry.tag) {
// These cannot be specified by the client.
case KM_TAG_ROOT_OF_TRUST:
case KM_TAG_ORIGIN:
LOG_E("Root of trust and origin tags may not be specified", 0);
return KM_ERROR_INVALID_TAG;
// These don't work.
case KM_TAG_ROLLBACK_RESISTANT:
LOG_E("KM_TAG_ROLLBACK_RESISTANT not supported", 0);
return KM_ERROR_UNSUPPORTED_TAG;
// These are hidden.
case KM_TAG_APPLICATION_ID:
case KM_TAG_APPLICATION_DATA:
break;
// Everything else we just copy into sw_enforced, unless the KeyFactory has placed it in
// hw_enforced, in which case we defer to its decision.
default:
if (hw_enforced->GetTagCount(entry.tag) == 0)
sw_enforced->push_back(entry);
break;
}
}
sw_enforced->push_back(TAG_CREATION_DATETIME, java_time(time(NULL)));
sw_enforced->push_back(TAG_ORIGIN, origin);
return TranslateAuthorizationSetError(sw_enforced->is_valid());
}
keymaster_error_t SoftKeymasterContext::CreateKeyBlob(const AuthorizationSet& key_description,
const 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;
AuthorizationSet hidden;
error = BuildHiddenAuthorizations(key_description, &hidden);
if (error != KM_ERROR_OK)
return error;
return SerializeIntegrityAssuredBlob(key_material, hidden, *hw_enforced, *sw_enforced, blob);
}
static keymaster_error_t ParseOcbAuthEncryptedBlob(const KeymasterKeyBlob& blob,
const AuthorizationSet& hidden,
KeymasterKeyBlob* key_material,
AuthorizationSet* hw_enforced,
AuthorizationSet* sw_enforced) {
Buffer nonce, tag;
KeymasterKeyBlob encrypted_key_material;
keymaster_error_t 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;
return OcbDecryptKey(*hw_enforced, *sw_enforced, hidden, MASTER_KEY, encrypted_key_material,
nonce, tag, key_material);
}
// Note: This parsing code in below is from system/security/softkeymaster/keymaster_openssl.cpp's
// unwrap_key function, modified for the preferred function signature and formatting. It does some
// odd things, but they have been left unchanged to avoid breaking compatibility.
static const uint8_t SOFT_KEY_MAGIC[] = {'P', 'K', '#', '8'};
const uint64_t HUNDRED_YEARS = 1000LL * 60 * 60 * 24 * 365 * 100;
static keymaster_error_t ParseOldSoftkeymasterBlob(const KeymasterKeyBlob& blob,
KeymasterKeyBlob* key_material,
AuthorizationSet* hw_enforced,
AuthorizationSet* sw_enforced) {
long publicLen = 0;
long privateLen = 0;
const uint8_t* p = blob.key_material;
const uint8_t* end = blob.key_material + blob.key_material_size;
int type = 0;
ptrdiff_t min_size =
sizeof(SOFT_KEY_MAGIC) + sizeof(type) + sizeof(publicLen) + 1 + sizeof(privateLen) + 1;
if (end - p < min_size) {
LOG_W("key blob appears to be truncated (if an old SW key)", 0);
return KM_ERROR_INVALID_KEY_BLOB;
}
if (memcmp(p, SOFT_KEY_MAGIC, sizeof(SOFT_KEY_MAGIC)) != 0)
return KM_ERROR_INVALID_KEY_BLOB;
p += sizeof(SOFT_KEY_MAGIC);
for (size_t i = 0; i < sizeof(type); i++)
type = (type << 8) | *p++;
for (size_t i = 0; i < sizeof(type); i++)
publicLen = (publicLen << 8) | *p++;
if (p + publicLen > end) {
LOG_W("public key length encoding error: size=%ld, end=%td", publicLen, end - p);
return KM_ERROR_INVALID_KEY_BLOB;
}
p += publicLen;
if (end - p < 2) {
LOG_W("key blob appears to be truncated (if an old SW key)", 0);
return KM_ERROR_INVALID_KEY_BLOB;
}
for (size_t i = 0; i < sizeof(type); i++)
privateLen = (privateLen << 8) | *p++;
if (p + privateLen > end) {
LOG_W("private key length encoding error: size=%ld, end=%td", privateLen, end - p);
return KM_ERROR_INVALID_KEY_BLOB;
}
// Just to be sure, make sure that the ASN.1 structure parses correctly. We don't actually use
// the EVP_PKEY here.
unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
if (pkey.get() == nullptr)
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
EVP_PKEY* tmp = pkey.get();
const uint8_t* key_start = p;
if (d2i_PrivateKey(type, &tmp, &p, privateLen) == NULL) {
LOG_W("Failed to parse PKCS#8 key material (if old SW key)", 0);
return KM_ERROR_INVALID_KEY_BLOB;
}
if (!key_material->Reset(privateLen))
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
memcpy(key_material->writable_data(), key_start, privateLen);
hw_enforced->Clear();
sw_enforced->Clear();
switch (type) {
case EVP_PKEY_RSA:
sw_enforced->push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
sw_enforced->push_back(TAG_DIGEST, KM_DIGEST_NONE);
sw_enforced->push_back(TAG_PADDING, KM_PAD_NONE);
break;
case EVP_PKEY_EC:
sw_enforced->push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
sw_enforced->push_back(TAG_DIGEST, KM_DIGEST_NONE);
break;
case EVP_PKEY_DSA:
return KM_ERROR_UNSUPPORTED_ALGORITHM;
default:
return KM_ERROR_INVALID_KEY_BLOB;
}
sw_enforced->push_back(TAG_PURPOSE, KM_PURPOSE_SIGN);
sw_enforced->push_back(TAG_PURPOSE, KM_PURPOSE_VERIFY);
sw_enforced->push_back(TAG_ALL_USERS);
sw_enforced->push_back(TAG_NO_AUTH_REQUIRED);
uint64_t now = java_time(time(NULL));
sw_enforced->push_back(TAG_CREATION_DATETIME, now);
sw_enforced->push_back(TAG_ORIGINATION_EXPIRE_DATETIME, now + HUNDRED_YEARS);
sw_enforced->push_back(TAG_DIGEST, KM_DIGEST_NONE);
sw_enforced->push_back(TAG_PADDING, KM_PAD_NONE);
return KM_ERROR_OK;
}
keymaster_error_t SoftKeymasterContext::ParseKeyBlob(const KeymasterKeyBlob& blob,
const AuthorizationSet& additional_params,
KeymasterKeyBlob* key_material,
AuthorizationSet* hw_enforced,
AuthorizationSet* sw_enforced) const {
// This is a little bit complicated.
//
// The SoftKeymasterContext has to handle a lot of different kinds of key blobs.
//
// 1. New keymaster1 software key blobs. These are integrity-assured but not encrypted. The
// raw key material and auth sets should be extracted and returned. This is the kind
// produced by this context when the KeyFactory doesn't use keymaster0 to back the keys.
//
// 2. Old keymaster1 software key blobs. These are OCB-encrypted with an all-zero master key.
// They should be decrypted and the key material and auth sets extracted and returned.
//
// 3. Old keymaster0 software key blobs. These are raw key material with a small header tacked
// on the front. They don't have auth sets, so reasonable defaults are generated and
// returned along with the raw key material.
//
// 4. New keymaster0 hardware key blobs. These are integrity-assured but not encrypted (though
// they're protected by the keymaster0 hardware implementation). The keymaster0 key blob
// and auth sets should be extracted and returned.
//
// 5. Old keymaster0 hardware key blobs. These are raw hardware key blobs. They don't have
// auth sets so reasonable defaults are generated and returned along with the key blob.
//
// Determining what kind of blob has arrived is somewhat tricky. What helps is that
// integrity-assured and OCB-encrypted blobs are self-consistent and effectively impossible to
// parse as anything else. Old keymaster0 software key blobs have a header. It's reasonably
// unlikely that hardware keys would have the same header. So anything that is neither
// integrity-assured nor OCB-encrypted and lacks the old software key header is assumed to be
// keymaster0 hardware.
AuthorizationSet hidden;
keymaster_error_t error = BuildHiddenAuthorizations(additional_params, &hidden);
if (error != KM_ERROR_OK)
return error;
// Assume it's an integrity-assured blob (new software-only blob, or new keymaster0-backed
// blob).
error = DeserializeIntegrityAssuredBlob(blob, hidden, key_material, hw_enforced, sw_enforced);
if (error != KM_ERROR_INVALID_KEY_BLOB)
return error;
// Wasn't an integrity-assured blob. Maybe it's an OCB-encrypted blob.
error = ParseOcbAuthEncryptedBlob(blob, hidden, key_material, hw_enforced, sw_enforced);
if (error == KM_ERROR_OK)
LOG_D("Parsed an old keymaster1 software key", 0);
if (error != KM_ERROR_INVALID_KEY_BLOB)
return error;
// Wasn't an OCB-encrypted blob. Maybe it's an old softkeymaster blob.
error = ParseOldSoftkeymasterBlob(blob, key_material, hw_enforced, sw_enforced);
if (error == KM_ERROR_OK)
LOG_D("Parsed an old sofkeymaster key", 0);
if (error != KM_ERROR_INVALID_KEY_BLOB)
return error;
// Not an old softkeymaster blob, either. The only remaining option is old HW keymaster0.
if (!engine_)
return KM_ERROR_INVALID_KEY_BLOB;
// See if the HW thinks it's valid.
unique_ptr<EVP_PKEY, EVP_PKEY_Delete> tmp_key(engine_->GetKeymaster0PublicKey(blob));
if (!tmp_key)
return KM_ERROR_INVALID_KEY_BLOB;
*key_material = blob;
return KM_ERROR_OK;
}
keymaster_error_t SoftKeymasterContext::AddRngEntropy(const uint8_t* buf, size_t length) const {
RAND_add(buf, length, 0 /* Don't assume any entropy is added to the pool. */);
return KM_ERROR_OK;
}
keymaster_error_t SoftKeymasterContext::GenerateRandom(uint8_t* buf, size_t length) const {
if (RAND_bytes(buf, length) != 1)
return KM_ERROR_UNKNOWN_ERROR;
return KM_ERROR_OK;
}
} // namespace keymaster