summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Willden <swillden@google.com>2015-05-18 08:35:28 -0600
committerShawn Willden <swillden@google.com>2015-05-20 12:55:18 -0600
commit8ba2a043f0d44ad3f58d4af518f9391c03eca9c3 (patch)
treeff76cdef7952c9bfe52f7b2608373622b83a4238
parentf923963fda888eac9e7997b71d5525ea2f82a091 (diff)
downloadandroid_system_keymaster-8ba2a043f0d44ad3f58d4af518f9391c03eca9c3.tar.gz
android_system_keymaster-8ba2a043f0d44ad3f58d4af518f9391c03eca9c3.tar.bz2
android_system_keymaster-8ba2a043f0d44ad3f58d4af518f9391c03eca9c3.zip
Large refactor to move context out of AndroidKeymaster.
AndroidKeymaster made a number of assumptions about its context that are really only valid for TEE-based usage. In addition, KeyFactory made some similarly TEE-focused assumptions about key blob creation and parsing. Both concerns have been moved to a new KeymasterContext class, which is responsible for building and parsing key blobs in a manner appropriate for the context in which AndroidKeymaster is running, as well as providing other context-specific services, such as random number generation. In addition, the refactor reduces the need for the KeyBlob and UnencryptedKeyBlob classes, which encode too many assumptions about blob formatting and encryption, to the point that they can be removed and replaced by a handful of utility functions which are much cleaner and more flexible. How to review this CL: I looked hard at breaking this up into smaller CLs, but it's mostly not feasible. However, it's probably easier to approach it by starting with the fundamental changes, and then looking at the cascade effects. 1. Look at keymaster_context.h. The core of the change was pulling this set of features out of AndroidKeymaster. Note that the revised approach to key blob creation does not involve the KeyBlob and UnencryptedKeyBlob classes, but instead goes directly from raw key material plus ancillary data (e.g. auth sets) to a serialized buffer ready to return to keystore. The same is true in reverse direction for parsing key blobs. 2. Look at key.h. The revised KeyFactory GenerateKey, ImportKey and LoadKey methods are essential. GenerateKey and ImportKey no longer produce a Key object, because all that's needed is a returnable blob. LoadKey produces a Key object, but it starts with raw key material, rather than an UnencryptedKeyBlob. Also note the change to the Key class; because Key objects are only created by LoadKey, when there's a need to use a key, there's only one constructor. 3. Look at asymmetric_key.h, rsa_key.h and rsa_key.cpp. rsa_key.cpp provides a good example of how the new structure works. GenerateKey and ImportKey do all of the work necessary to produce an OpenSSL RSA key and extract the internal representation (using EvpToKeyMaterial; defined in asymmetric_key.h because it's the same for EC keys). Then, with the raw key data in hand, they call KeymasterContext::CreateKeyBlob to wrap the key data in a key blob that can be returned to the caller -- whatever that wrapping means in the current context. There's a subtlety not apparent here which is crucial to the rationale for the refactoring: RsaKeyFactory uses KeymasterContext::get_instance to retrieve the context, but key factories which depend on operating in a particular context can use a different way to get their context object, which may have a larger interface. RsaKeymaster0KeyFactory will do this. 4. Look at soft_keymaster_context. In particular, SoftKeymasterContext::CreateKeyBlob and ParseKeyBlob. CreateKeyBlob allocates authorization tags from key_description to hw_enforced and sw_enforced, then encrypts the key material and serializes it to a blob. This approach is compatible with the keys softkeymaster has been producing, but I'm going to change it (post M), because there's no reason to bother encrypting SW keys with a SW key. ParseKeyBlob reverses the process to recover the unencrypted key material and the auth lists. One debatable point was the decision to implement BuildHiddenAuthorizations and SetAuthorizations here, since all contexts will need something similar, and they really should all do it the same. I may refactor later to pull that functionality up to KeymasterContext; it will depend on what I learn implementing TrustyKeymasterContext and HybridKeymasterContext (used for the keymaster0 adapter). 5. Look at ocb_utils and auth_encrypted_key_blob. These contain the key encryption and key blob serialization code which was formerly split between AndroidKeymaster::SerializeKeyBlob, UnencryptedKeyBlob and KeyBlob, now divided into separate encryption and serialization utilities. Note the refactored key_blob_test.cpp, updated to use the new utilities rather than UnencryptedKeyBlob. 6. Look at soft_keymaster_device.cpp. Since KeyBlob no longer exists to provide a nice way to peer into a blob to extract the algorithm, for use in determining how to parse the keymaster0 signing key params (which come in as a void*, yuck), we now have to use get_key_characteristics to recover the params. This was the right way all along; the device layer should not depend on being able to parse key blobs. 7. The rest. Bug: 20912868, 19799085 Change-Id: Ieb74b8da39974f674eb8baa959bde75011fdd2e8
-rw-r--r--Android.mk10
-rw-r--r--Makefile17
-rw-r--r--aes_key.cpp18
-rw-r--r--aes_key.h23
-rw-r--r--aes_operation.h4
-rw-r--r--android_keymaster.cpp269
-rw-r--r--android_keymaster_messages_test.cpp4
-rw-r--r--android_keymaster_test.cpp36
-rw-r--r--android_softkeymaster.h68
-rw-r--r--asymmetric_key.cpp68
-rw-r--r--asymmetric_key.h49
-rw-r--r--auth_encrypted_key_blob.cpp77
-rw-r--r--auth_encrypted_key_blob.h42
-rw-r--r--ec_key.cpp127
-rw-r--r--ec_key.h40
-rw-r--r--ecdsa_operation.h2
-rw-r--r--hmac_key.cpp16
-rw-r--r--hmac_key.h23
-rw-r--r--include/keymaster/android_keymaster.h34
-rw-r--r--include/keymaster/android_keymaster_utils.h94
-rw-r--r--include/keymaster/key_blob.h130
-rw-r--r--include/keymaster/keymaster_context.h110
-rw-r--r--include/keymaster/serializable.h3
-rw-r--r--include/keymaster/soft_keymaster_device.h3
-rw-r--r--key.cpp13
-rw-r--r--key.h31
-rw-r--r--key_blob.cpp167
-rw-r--r--key_blob_test.cpp393
-rw-r--r--ocb_utils.cpp183
-rw-r--r--ocb_utils.h30
-rw-r--r--rsa_key.cpp127
-rw-r--r--rsa_key.h37
-rw-r--r--rsa_operation.h2
-rw-r--r--soft_keymaster_context.cpp194
-rw-r--r--soft_keymaster_context.h52
-rw-r--r--soft_keymaster_device.cpp64
-rw-r--r--symmetric_key.cpp133
-rw-r--r--symmetric_key.h30
-rw-r--r--unencrypted_key_blob.cpp191
-rw-r--r--unencrypted_key_blob.h82
-rw-r--r--valgrind.supp14
41 files changed, 1522 insertions, 1488 deletions
diff --git a/Android.mk b/Android.mk
index f5ace96..ef059cf 100644
--- a/Android.mk
+++ b/Android.mk
@@ -24,7 +24,6 @@ LOCAL_SRC_FILES:= \
android_keymaster_messages.cpp \
android_keymaster_utils.cpp \
authorization_set.cpp \
- key_blob.cpp \
logger.cpp \
serializable.cpp
LOCAL_C_INCLUDES := \
@@ -37,19 +36,19 @@ include $(BUILD_SHARED_LIBRARY)
###
# libkeymaster1 contains almost everything needed for a keymaster1
-# implementation, lacking only a subclass of the (abstract) AndroidKeymaster
+# implementation, lacking only a subclass of the (abstract) KeymasterContext
# class to provide environment-specific services and a wrapper to translate from
# the function-based keymaster HAL API to the message-based AndroidKeymaster API.
###
include $(CLEAR_VARS)
LOCAL_MODULE:= libkeymaster1
LOCAL_SRC_FILES:= \
- aead_mode_operation.cpp \
aes_key.cpp \
aes_operation.cpp \
android_keymaster.cpp \
android_keymaster_messages.cpp \
android_keymaster_utils.cpp \
+ auth_encrypted_key_blob.cpp \
asymmetric_key.cpp \
ec_key.cpp \
ecdsa_operation.cpp \
@@ -59,14 +58,14 @@ LOCAL_SRC_FILES:= \
hmac_operation.cpp \
key.cpp \
ocb.c \
+ ocb_utils.cpp \
openssl_err.cpp \
openssl_utils.cpp \
operation.cpp \
operation_table.cpp \
rsa_key.cpp \
rsa_operation.cpp \
- symmetric_key.cpp \
- unencrypted_key_blob.cpp
+ symmetric_key.cpp
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include
LOCAL_SHARED_LIBRARIES := libcrypto libkeymaster_messages
@@ -87,6 +86,7 @@ include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libsoftkeymasterdevice
LOCAL_SRC_FILES := \
+ soft_keymaster_context.cpp \
soft_keymaster_device.cpp \
soft_keymaster_logger.cpp
LOCAL_C_INCLUDES := \
diff --git a/Makefile b/Makefile
index 2aec87d..083c65e 100644
--- a/Makefile
+++ b/Makefile
@@ -66,6 +66,7 @@ CPPSRCS=\
android_keymaster_test_utils.cpp \
android_keymaster_utils.cpp \
asymmetric_key.cpp \
+ auth_encrypted_key_blob.cpp \
authorization_set.cpp \
authorization_set_test.cpp \
ec_key.cpp \
@@ -78,11 +79,11 @@ CPPSRCS=\
hmac_operation.cpp \
hmac_test.cpp \
key.cpp \
- key_blob.cpp \
key_blob_test.cpp \
keymaster_enforcement.cpp \
keymaster_enforcement_test.cpp \
logger.cpp \
+ ocb_utils.cpp \
openssl_err.cpp \
openssl_utils.cpp \
operation.cpp \
@@ -90,9 +91,9 @@ CPPSRCS=\
rsa_key.cpp \
rsa_operation.cpp \
serializable.cpp \
+ soft_keymaster_context.cpp \
soft_keymaster_device.cpp \
symmetric_key.cpp \
- unencrypted_key_blob.cpp
CCSRCS=$(GTEST)/src/gtest-all.cc
CSRCS=ocb.c
@@ -181,13 +182,14 @@ authorization_set_test: authorization_set_test.o \
key_blob_test: key_blob_test.o \
android_keymaster_test_utils.o \
+ android_keymaster_utils.o \
+ auth_encrypted_key_blob.o \
authorization_set.o \
- key_blob.o \
logger.o \
ocb.o \
+ ocb_utils.o \
openssl_err.o \
serializable.o \
- unencrypted_key_blob.o \
$(GTEST_OBJS)
android_keymaster_messages_test: android_keymaster_messages_test.o \
@@ -200,7 +202,6 @@ android_keymaster_messages_test: android_keymaster_messages_test.o \
$(GTEST_OBJS)
android_keymaster_test: android_keymaster_test.o \
- aead_mode_operation.o \
aes_key.o \
aes_operation.o \
android_keymaster.o \
@@ -208,15 +209,16 @@ android_keymaster_test: android_keymaster_test.o \
android_keymaster_test_utils.o \
android_keymaster_utils.o \
asymmetric_key.o \
+ auth_encrypted_key_blob.o \
authorization_set.o \
ec_key.o \
ecdsa_operation.o \
hmac_key.o \
hmac_operation.o \
key.o \
- key_blob.o \
logger.o \
ocb.o \
+ ocb_utils.o \
openssl_err.o \
openssl_utils.o \
operation.o \
@@ -224,12 +226,13 @@ android_keymaster_test: android_keymaster_test.o \
rsa_key.o \
rsa_operation.o \
serializable.o \
+ soft_keymaster_context.o \
soft_keymaster_device.o \
symmetric_key.o \
- unencrypted_key_blob.o \
$(GTEST_OBJS)
abstract_factory_registry_test: abstract_factory_registry_test.o \
+ android_keymaster_utils.o \
logger.o \
$(GTEST_OBJS)
diff --git a/aes_key.cpp b/aes_key.cpp
index 8b2c3fd..e1a890f 100644
--- a/aes_key.cpp
+++ b/aes_key.cpp
@@ -22,16 +22,20 @@
#include <openssl/rand.h>
#include "aes_operation.h"
-#include "unencrypted_key_blob.h"
namespace keymaster {
-Key* AesKeyFactory::LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) {
- return new AesKey(blob, error);
-}
-
-SymmetricKey* AesKeyFactory::CreateKey(const AuthorizationSet& auths) {
- return new AesKey(auths);
+keymaster_error_t AesKeyFactory::LoadKey(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, UniquePtr<Key>* key) {
+ if (!key)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+ keymaster_error_t error = KM_ERROR_OK;
+ key->reset(new AesKey(key_material, hw_enforced, sw_enforced, &error));
+ if (!key->get())
+ error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return error;
}
} // namespace keymaster
diff --git a/aes_key.h b/aes_key.h
index fa615f6..28efc39 100644
--- a/aes_key.h
+++ b/aes_key.h
@@ -25,22 +25,25 @@ namespace keymaster {
class AesKeyFactory : public SymmetricKeyFactory {
public:
+ AesKeyFactory(const KeymasterContext* context) : SymmetricKeyFactory(context) {}
+
keymaster_algorithm_t registry_key() const { return KM_ALGORITHM_AES; }
- Key* LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) override;
- SymmetricKey* CreateKey(const AuthorizationSet& auths) override;
+ keymaster_error_t LoadKey(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, UniquePtr<Key>* key) override;
+
+ private:
+ bool key_size_supported(size_t key_size_bits) const override {
+ return key_size_bits == 128 || key_size_bits == 192 || key_size_bits == 256;
+ }
};
class AesKey : public SymmetricKey {
public:
- AesKey(const AuthorizationSet& auths) : SymmetricKey(auths) {}
- AesKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) : SymmetricKey(blob, error) {}
-
- private:
- bool size_supported(size_t key_size) const override {
- // AES keys only come in three sizes, 128, 192 and 256 bits.
- return key_size == 128 / 8 || key_size == 192 / 8 || key_size == 256 / 8;
- }
+ AesKey(const KeymasterKeyBlob& key_material, const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, keymaster_error_t* error)
+ : SymmetricKey(key_material, hw_enforced, sw_enforced, error) {}
};
} // namespace keymaster
diff --git a/aes_operation.h b/aes_operation.h
index d4b4687..2172e2d 100644
--- a/aes_operation.h
+++ b/aes_operation.h
@@ -25,6 +25,8 @@
namespace keymaster {
+static const size_t MAX_EVP_KEY_SIZE = 32;
+
class AesEvpOperation : public Operation {
public:
AesEvpOperation(keymaster_purpose_t purpose, keymaster_block_mode_t block_mode,
@@ -54,7 +56,7 @@ class AesEvpOperation : public Operation {
const keymaster_padding_t padding_;
const bool caller_iv_;
UniquePtr<uint8_t[]> iv_;
- uint8_t key_[SymmetricKey::MAX_KEY_SIZE];
+ uint8_t key_[MAX_EVP_KEY_SIZE];
};
class AesEvpEncryptOperation : public AesEvpOperation {
diff --git a/android_keymaster.cpp b/android_keymaster.cpp
index df1d100..ba5361d 100644
--- a/android_keymaster.cpp
+++ b/android_keymaster.cpp
@@ -27,13 +27,13 @@
#include <UniquePtr.h>
#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/keymaster_context.h>
#include "ae.h"
#include "key.h"
#include "openssl_err.h"
#include "operation.h"
#include "operation_table.h"
-#include "unencrypted_key_blob.h"
namespace keymaster {
@@ -41,8 +41,8 @@ const uint8_t MAJOR_VER = 1;
const uint8_t MINOR_VER = 0;
const uint8_t SUBMINOR_VER = 0;
-AndroidKeymaster::AndroidKeymaster(size_t operation_table_size)
- : operation_table_(new OperationTable(operation_table_size)) {
+AndroidKeymaster::AndroidKeymaster(KeymasterContext* context, size_t operation_table_size)
+ : context_(context), operation_table_(new OperationTable(operation_table_size)) {
}
AndroidKeymaster::~AndroidKeymaster() {
@@ -175,6 +175,11 @@ void AndroidKeymaster::SupportedExportFormats(
response->SetResults(formats, count);
}
+keymaster_error_t AndroidKeymaster::AddRngEntropy(const AddEntropyRequest& request) {
+ return context_->AddRngEntropy(request.random_data.peek_read(),
+ request.random_data.available_read());
+}
+
void AndroidKeymaster::GenerateKey(const GenerateKeyRequest& request,
GenerateKeyResponse* response) {
if (response == NULL)
@@ -186,14 +191,13 @@ void AndroidKeymaster::GenerateKey(const GenerateKeyRequest& request,
if (!request.key_description.GetTagValue(TAG_ALGORITHM, &algorithm) ||
!(factory = KeyFactoryRegistry::Get(algorithm)))
response->error = KM_ERROR_UNSUPPORTED_ALGORITHM;
- else
- key.reset(factory->GenerateKey(request.key_description, &response->error));
-
- if (response->error != KM_ERROR_OK)
- return;
-
- response->error = SerializeKey(key.get(), KM_ORIGIN_GENERATED, &response->key_blob,
- &response->enforced, &response->unenforced);
+ else {
+ KeymasterKeyBlob key_blob;
+ response->error = factory->GenerateKey(request.key_description, &key_blob,
+ &response->enforced, &response->unenforced);
+ if (response->error == KM_ERROR_OK)
+ response->key_blob = key_blob.release();
+ }
}
void AndroidKeymaster::GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
@@ -201,13 +205,25 @@ void AndroidKeymaster::GetKeyCharacteristics(const GetKeyCharacteristicsRequest&
if (response == NULL)
return;
- UniquePtr<KeyBlob> blob(
- LoadKeyBlob(request.key_blob, request.additional_params, &(response->error)));
- if (blob.get() == NULL)
+ KeymasterKeyBlob key_material;
+ response->error =
+ context_->ParseKeyBlob(KeymasterKeyBlob(request.key_blob), request.additional_params,
+ &key_material, &response->enforced, &response->unenforced);
+ if (response->error != KM_ERROR_OK)
return;
+}
- response->enforced.Reinitialize(blob->enforced());
- response->unenforced.Reinitialize(blob->unenforced());
+static KeyFactory* GetKeyFactory(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ keymaster_algorithm_t* algorithm, keymaster_error_t* error) {
+ *error = KM_ERROR_UNSUPPORTED_ALGORITHM;
+ if (!hw_enforced.GetTagValue(TAG_ALGORITHM, algorithm) &&
+ !sw_enforced.GetTagValue(TAG_ALGORITHM, algorithm))
+ return nullptr;
+ KeyFactory* factory = KeyFactoryRegistry::Get(*algorithm);
+ if (factory)
+ *error = KM_ERROR_OK;
+ return factory;
}
void AndroidKeymaster::BeginOperation(const BeginOperationRequest& request,
@@ -216,25 +232,24 @@ void AndroidKeymaster::BeginOperation(const BeginOperationRequest& request,
return;
response->op_handle = 0;
+ AuthorizationSet hw_enforced;
+ AuthorizationSet sw_enforced;
keymaster_algorithm_t algorithm;
- UniquePtr<Key> key(
- LoadKey(request.key_blob, request.additional_params, &algorithm, &response->error));
- if (key.get() == NULL)
- return;
+ UniquePtr<Key> key;
+ response->error = LoadKey(request.key_blob, request.additional_params, &hw_enforced,
+ &sw_enforced, &algorithm, &key);
// TODO(swillden): Move this check to a general authorization checker.
- if (!key->authorizations().Contains(TAG_PURPOSE, request.purpose)) {
- // TODO(swillden): Consider introducing error codes for unauthorized usages.
- response->error = KM_ERROR_INCOMPATIBLE_PURPOSE;
+ // TODO(swillden): Consider introducing error codes for unauthorized usages.
+ response->error = KM_ERROR_INCOMPATIBLE_PURPOSE;
+ if (!hw_enforced.Contains(TAG_PURPOSE, request.purpose) &&
+ !sw_enforced.Contains(TAG_PURPOSE, request.purpose))
return;
- }
- OperationFactory::KeyType op_type(algorithm, request.purpose);
- OperationFactory* factory = OperationFactoryRegistry::Get(op_type);
- if (!factory) {
- response->error = KM_ERROR_UNSUPPORTED_PURPOSE;
+ response->error = KM_ERROR_UNSUPPORTED_PURPOSE;
+ OperationFactory* factory = OperationFactoryRegistry::Get({algorithm, request.purpose});
+ if (!factory)
return;
- }
UniquePtr<Operation> operation(
factory->CreateOperation(*key, request.additional_params, &response->error));
@@ -298,15 +313,28 @@ void AndroidKeymaster::ExportKey(const ExportKeyRequest& request, ExportKeyRespo
if (response == NULL)
return;
+ AuthorizationSet hw_enforced;
+ AuthorizationSet sw_enforced;
+ KeymasterKeyBlob key_material;
+ response->error =
+ context_->ParseKeyBlob(KeymasterKeyBlob(request.key_blob), request.additional_params,
+ &key_material, &hw_enforced, &sw_enforced);
+ if (response->error != KM_ERROR_OK)
+ return;
+
keymaster_algorithm_t algorithm;
- UniquePtr<Key> to_export(
- LoadKey(request.key_blob, request.additional_params, &algorithm, &response->error));
- if (to_export.get() == NULL)
+ KeyFactory* key_factory = GetKeyFactory(hw_enforced, sw_enforced, &algorithm, &response->error);
+ if (!key_factory)
+ return;
+
+ UniquePtr<Key> key;
+ response->error = key_factory->LoadKey(key_material, hw_enforced, sw_enforced, &key);
+ if (response->error != KM_ERROR_OK)
return;
UniquePtr<uint8_t[]> out_key;
size_t size;
- response->error = to_export->formatted_key_material(request.key_format, &out_key, &size);
+ response->error = key->formatted_key_material(request.key_format, &out_key, &size);
if (response->error == KM_ERROR_OK) {
response->key_data = out_key.release();
response->key_data_length = size;
@@ -323,168 +351,35 @@ void AndroidKeymaster::ImportKey(const ImportKeyRequest& request, ImportKeyRespo
if (!request.key_description.GetTagValue(TAG_ALGORITHM, &algorithm) ||
!(factory = KeyFactoryRegistry::Get(algorithm)))
response->error = KM_ERROR_UNSUPPORTED_ALGORITHM;
- else
- key.reset(factory->ImportKey(request.key_description, request.key_format, request.key_data,
- request.key_data_length, &response->error));
-
- if (response->error != KM_ERROR_OK)
- return;
-
- response->error = SerializeKey(key.get(), KM_ORIGIN_IMPORTED, &response->key_blob,
- &response->enforced, &response->unenforced);
+ else {
+ keymaster_key_blob_t key_material = {request.key_data, request.key_data_length};
+ KeymasterKeyBlob key_blob;
+ response->error = factory->ImportKey(request.key_description, request.key_format,
+ KeymasterKeyBlob(key_material), &key_blob,
+ &response->enforced, &response->unenforced);
+ if (response->error == KM_ERROR_OK)
+ response->key_blob = key_blob.release();
+ }
}
-keymaster_error_t AndroidKeymaster::SerializeKey(const Key* key, keymaster_key_origin_t origin,
- keymaster_key_blob_t* keymaster_blob,
- AuthorizationSet* enforced,
- AuthorizationSet* unenforced) {
- keymaster_error_t error;
-
- error = SetAuthorizations(key->authorizations(), origin, enforced, unenforced);
+keymaster_error_t AndroidKeymaster::LoadKey(const keymaster_key_blob_t& key_blob,
+ const AuthorizationSet& additional_params,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced,
+ keymaster_algorithm_t* algorithm, UniquePtr<Key>* key) {
+ KeymasterKeyBlob key_material;
+ keymaster_error_t error = context_->ParseKeyBlob(KeymasterKeyBlob(key_blob), additional_params,
+ &key_material, hw_enforced, sw_enforced);
if (error != KM_ERROR_OK)
return error;
- AuthorizationSet hidden_auths;
- error = BuildHiddenAuthorizations(key->authorizations(), &hidden_auths);
- if (error != KM_ERROR_OK)
- return error;
-
- UniquePtr<uint8_t[]> key_material;
- size_t key_material_size;
- error = key->key_material(&key_material, &key_material_size);
- if (error != KM_ERROR_OK)
+ KeyFactory* key_factory = GetKeyFactory(*hw_enforced, *sw_enforced, algorithm, &error);
+ if (error != KM_ERROR_OK) {
+ assert(!key_factory);
return error;
-
- uint8_t nonce[KeyBlob::NONCE_LENGTH];
- GenerateNonce(nonce, array_size(nonce));
-
- keymaster_key_blob_t master_key = MasterKey();
- UniquePtr<KeyBlob> blob(new UnencryptedKeyBlob(
- *enforced, *unenforced, hidden_auths, key_material.get(), key_material_size,
- master_key.key_material, master_key.key_material_size, nonce));
- if (blob.get() == NULL)
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- if (blob->error() != KM_ERROR_OK)
- return blob->error();
-
- size_t size = blob->SerializedSize();
- UniquePtr<uint8_t[]> blob_bytes(new uint8_t[size]);
- if (blob_bytes.get() == NULL)
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- blob->Serialize(blob_bytes.get(), blob_bytes.get() + size);
- keymaster_blob->key_material_size = size;
- keymaster_blob->key_material = blob_bytes.release();
-
- return KM_ERROR_OK;
-}
-
-Key* AndroidKeymaster::LoadKey(const keymaster_key_blob_t& key,
- const AuthorizationSet& client_params,
- keymaster_algorithm_t* algorithm, keymaster_error_t* error) {
- UniquePtr<UnencryptedKeyBlob> blob(LoadKeyBlob(key, client_params, error));
- if (*error != KM_ERROR_OK)
- return NULL;
-
- *algorithm = blob->algorithm();
-
- KeyFactory* factory = 0;
- if ((factory = KeyFactoryRegistry::Get(*algorithm)))
- return factory->LoadKey(*blob, error);
- *error = KM_ERROR_UNSUPPORTED_ALGORITHM;
- return NULL;
-}
-
-UnencryptedKeyBlob* AndroidKeymaster::LoadKeyBlob(const keymaster_key_blob_t& key,
- const AuthorizationSet& client_params,
- keymaster_error_t* error) {
- AuthorizationSet hidden;
- BuildHiddenAuthorizations(client_params, &hidden);
- keymaster_key_blob_t master_key = MasterKey();
- UniquePtr<UnencryptedKeyBlob> blob(
- new UnencryptedKeyBlob(key, hidden, master_key.key_material, master_key.key_material_size));
- if (blob.get() == NULL) {
- *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
- return NULL;
- } else if (blob->error() != KM_ERROR_OK) {
- *error = blob->error();
- return NULL;
- }
- *error = KM_ERROR_OK;
- return blob.release();
-}
-
-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 AndroidKeymaster::SetAuthorizations(const AuthorizationSet& key_description,
- keymaster_key_origin_t origin,
- AuthorizationSet* enforced,
- AuthorizationSet* unenforced) {
- enforced->Clear();
- unenforced->Clear();
- for (size_t i = 0; i < key_description.size(); ++i) {
- switch (key_description[i].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 the appropriate set.
- default:
- AddAuthorization(key_description[i], enforced, unenforced);
- break;
- }
}
- AddAuthorization(Authorization(TAG_CREATION_DATETIME, java_time(time(NULL))), enforced,
- unenforced);
- AddAuthorization(Authorization(TAG_ORIGIN, origin), enforced, unenforced);
-
- if (enforced->is_valid() != AuthorizationSet::OK)
- return TranslateAuthorizationSetError(enforced->is_valid());
-
- return TranslateAuthorizationSetError(unenforced->is_valid());
-}
-
-keymaster_error_t AndroidKeymaster::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);
- hidden->push_back(RootOfTrustTag());
-
- return TranslateAuthorizationSetError(hidden->is_valid());
-}
-
-void AndroidKeymaster::AddAuthorization(const keymaster_key_param_t& auth,
- AuthorizationSet* enforced, AuthorizationSet* unenforced) {
- if (is_enforced(auth.tag))
- enforced->push_back(auth);
- else
- unenforced->push_back(auth);
+ return key_factory->LoadKey(key_material, *hw_enforced, *sw_enforced, key);
}
} // namespace keymaster
diff --git a/android_keymaster_messages_test.cpp b/android_keymaster_messages_test.cpp
index 2c888d9..143b03b 100644
--- a/android_keymaster_messages_test.cpp
+++ b/android_keymaster_messages_test.cpp
@@ -18,11 +18,11 @@
#include <gtest/gtest.h>
-#include <keymaster/keymaster_tags.h>
+#include <keymaster/android_keymaster.h>
#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/keymaster_tags.h>
#include "android_keymaster_test_utils.h"
-#include "android_softkeymaster.h"
namespace keymaster {
namespace test {
diff --git a/android_keymaster_test.cpp b/android_keymaster_test.cpp
index 7f06390..e3faefa 100644
--- a/android_keymaster_test.cpp
+++ b/android_keymaster_test.cpp
@@ -78,7 +78,7 @@ TEST_F(CheckSupported, SupportedBlockModes) {
size_t len;
keymaster_block_mode_t* modes;
- EXPECT_EQ(KM_ERROR_OK, device()->get_supported_block_modes(device(), KM_ALGORITHM_RSA,
+ ASSERT_EQ(KM_ERROR_OK, device()->get_supported_block_modes(device(), KM_ALGORITHM_RSA,
KM_PURPOSE_ENCRYPT, &modes, &len));
EXPECT_EQ(0U, len);
free(modes);
@@ -87,7 +87,7 @@ TEST_F(CheckSupported, SupportedBlockModes) {
device()->get_supported_block_modes(device(), KM_ALGORITHM_EC, KM_PURPOSE_ENCRYPT,
&modes, &len));
- EXPECT_EQ(KM_ERROR_OK, device()->get_supported_block_modes(device(), KM_ALGORITHM_AES,
+ ASSERT_EQ(KM_ERROR_OK, device()->get_supported_block_modes(device(), KM_ALGORITHM_AES,
KM_PURPOSE_ENCRYPT, &modes, &len));
EXPECT_TRUE(ResponseContains({KM_MODE_ECB, KM_MODE_CBC, KM_MODE_CTR}, modes, len));
free(modes);
@@ -100,18 +100,18 @@ TEST_F(CheckSupported, SupportedPaddingModes) {
size_t len;
keymaster_padding_t* modes;
- EXPECT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_RSA,
+ ASSERT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_RSA,
KM_PURPOSE_SIGN, &modes, &len));
EXPECT_TRUE(
ResponseContains({KM_PAD_NONE, KM_PAD_RSA_PKCS1_1_5_SIGN, KM_PAD_RSA_PSS}, modes, len));
free(modes);
- EXPECT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_RSA,
+ ASSERT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_RSA,
KM_PURPOSE_ENCRYPT, &modes, &len));
EXPECT_TRUE(ResponseContains({KM_PAD_RSA_OAEP, KM_PAD_RSA_PKCS1_1_5_ENCRYPT}, modes, len));
free(modes);
- EXPECT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_EC,
+ ASSERT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_EC,
KM_PURPOSE_SIGN, &modes, &len));
EXPECT_EQ(0U, len);
free(modes);
@@ -128,12 +128,12 @@ TEST_F(CheckSupported, SupportedDigests) {
size_t len;
keymaster_digest_t* digests;
- EXPECT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_RSA,
+ ASSERT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_RSA,
KM_PURPOSE_SIGN, &digests, &len));
EXPECT_TRUE(ResponseContains({KM_DIGEST_NONE, KM_DIGEST_SHA_2_256}, digests, len));
free(digests);
- EXPECT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_EC,
+ ASSERT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_EC,
KM_PURPOSE_SIGN, &digests, &len));
EXPECT_TRUE(ResponseContains(KM_DIGEST_NONE, digests, len));
free(digests);
@@ -142,7 +142,7 @@ TEST_F(CheckSupported, SupportedDigests) {
device()->get_supported_digests(device(), KM_ALGORITHM_AES, KM_PURPOSE_SIGN, &digests,
&len));
- EXPECT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_HMAC,
+ ASSERT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_HMAC,
KM_PURPOSE_SIGN, &digests, &len));
EXPECT_TRUE(ResponseContains({KM_DIGEST_SHA_2_224, KM_DIGEST_SHA_2_256, KM_DIGEST_SHA_2_384,
KM_DIGEST_SHA_2_512, KM_DIGEST_SHA1},
@@ -156,17 +156,17 @@ TEST_F(CheckSupported, SupportedImportFormats) {
size_t len;
keymaster_key_format_t* formats;
- EXPECT_EQ(KM_ERROR_OK,
+ ASSERT_EQ(KM_ERROR_OK,
device()->get_supported_import_formats(device(), KM_ALGORITHM_RSA, &formats, &len));
EXPECT_TRUE(ResponseContains(KM_KEY_FORMAT_PKCS8, formats, len));
free(formats);
- EXPECT_EQ(KM_ERROR_OK,
+ ASSERT_EQ(KM_ERROR_OK,
device()->get_supported_import_formats(device(), KM_ALGORITHM_AES, &formats, &len));
EXPECT_TRUE(ResponseContains(KM_KEY_FORMAT_RAW, formats, len));
free(formats);
- EXPECT_EQ(KM_ERROR_OK,
+ ASSERT_EQ(KM_ERROR_OK,
device()->get_supported_import_formats(device(), KM_ALGORITHM_HMAC, &formats, &len));
EXPECT_TRUE(ResponseContains(KM_KEY_FORMAT_RAW, formats, len));
free(formats);
@@ -178,27 +178,27 @@ TEST_F(CheckSupported, SupportedExportFormats) {
size_t len;
keymaster_key_format_t* formats;
- EXPECT_EQ(KM_ERROR_OK,
+ ASSERT_EQ(KM_ERROR_OK,
device()->get_supported_export_formats(device(), KM_ALGORITHM_RSA, &formats, &len));
EXPECT_TRUE(ResponseContains(KM_KEY_FORMAT_X509, formats, len));
free(formats);
- EXPECT_EQ(KM_ERROR_OK,
+ ASSERT_EQ(KM_ERROR_OK,
device()->get_supported_export_formats(device(), KM_ALGORITHM_EC, &formats, &len));
EXPECT_TRUE(ResponseContains(KM_KEY_FORMAT_X509, formats, len));
free(formats);
- EXPECT_EQ(KM_ERROR_OK,
+ ASSERT_EQ(KM_ERROR_OK,
device()->get_supported_export_formats(device(), KM_ALGORITHM_AES, &formats, &len));
EXPECT_EQ(0U, len);
free(formats);
- EXPECT_EQ(KM_ERROR_OK,
+ ASSERT_EQ(KM_ERROR_OK,
device()->get_supported_export_formats(device(), KM_ALGORITHM_AES, &formats, &len));
EXPECT_EQ(0U, len);
free(formats);
- EXPECT_EQ(KM_ERROR_OK,
+ ASSERT_EQ(KM_ERROR_OK,
device()->get_supported_export_formats(device(), KM_ALGORITHM_HMAC, &formats, &len));
EXPECT_EQ(0U, len);
free(formats);
@@ -950,13 +950,13 @@ TEST_F(VerificationOperationsTest, RsaAllDigestAndPadCombinations) {
// Get all supported digests and padding modes.
size_t digests_len;
keymaster_digest_t* digests;
- EXPECT_EQ(KM_ERROR_OK,
+ ASSERT_EQ(KM_ERROR_OK,
device()->get_supported_digests(device(), KM_ALGORITHM_RSA, KM_PURPOSE_SIGN, &digests,
&digests_len));
size_t padding_modes_len;
keymaster_padding_t* padding_modes;
- EXPECT_EQ(KM_ERROR_OK,
+ ASSERT_EQ(KM_ERROR_OK,
device()->get_supported_padding_modes(device(), KM_ALGORITHM_RSA, KM_PURPOSE_SIGN,
&padding_modes, &padding_modes_len));
diff --git a/android_softkeymaster.h b/android_softkeymaster.h
deleted file mode 100644
index 6b9efac..0000000
--- a/android_softkeymaster.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2014 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.
- */
-
-#ifndef SYSTEM_KEYMASTER_ANDROID_SOFT_KEYMASTER_H_
-#define SYSTEM_KEYMASTER_ANDROID_SOFT_KEYMASTER_H_
-
-#include <keymaster/android_keymaster.h>
-
-#include <openssl/rand.h>
-
-#include "openssl_err.h"
-
-namespace keymaster {
-
-class AndroidSoftKeymaster : public AndroidKeymaster {
- public:
- AndroidSoftKeymaster(size_t operation_table_size) : AndroidKeymaster(operation_table_size) {
- 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;
- }
- bool is_enforced(keymaster_tag_t /* tag */) { return false; }
- bool is_hardware() { return false; }
-
- keymaster_error_t AddRngEntropy(const AddEntropyRequest& request) {
- RAND_add(request.random_data.peek_read(), request.random_data.available_read(),
- 0 /* Don't assume any entropy is added to the pool. */);
- return KM_ERROR_OK;
- }
-
- private:
- static uint8_t master_key_[];
-
- keymaster_key_blob_t MasterKey() {
- keymaster_key_blob_t blob;
- blob.key_material = master_key_;
- blob.key_material_size = 16;
- return blob;
- }
-
- void GenerateNonce(uint8_t* nonce, size_t length) {
- for (size_t i = 0; i < length; ++i)
- nonce[i] = 0;
- }
-
- keymaster_key_param_t RootOfTrustTag() { return root_of_trust; }
-
- keymaster_key_param_t root_of_trust;
-};
-
-uint8_t AndroidSoftKeymaster::master_key_[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
-} // namespace
-
-#endif // SYSTEM_KEYMASTER_ANDROID_SOFT_KEYMASTER_H_
diff --git a/asymmetric_key.cpp b/asymmetric_key.cpp
index 1af58ca..72c24a1 100644
--- a/asymmetric_key.cpp
+++ b/asymmetric_key.cpp
@@ -20,28 +20,36 @@
#include <hardware/keymaster_defs.h>
-#include "ec_key.h"
#include "openssl_err.h"
#include "openssl_utils.h"
-#include "rsa_key.h"
-#include "unencrypted_key_blob.h"
namespace keymaster {
-EVP_PKEY* AsymmetricKeyFactory::ExtractEvpKey(keymaster_key_format_t key_format,
- keymaster_algorithm_t expected_algorithm,
- const uint8_t* key_data, size_t key_data_length,
- keymaster_error_t* error) {
- *error = KM_ERROR_UNSUPPORTED_KEY_FORMAT;
+keymaster_error_t
+AsymmetricKeyFactory::KeyMaterialToEvpKey(keymaster_key_format_t key_format,
+ const KeymasterKeyBlob& key_material,
+ UniquePtr<EVP_PKEY, EVP_PKEY_Delete>* pkey) {
if (key_format != KM_KEY_FORMAT_PKCS8)
- return NULL;
+ return KM_ERROR_UNSUPPORTED_KEY_FORMAT;
+
+ return convert_pkcs8_blob_to_evp(key_material.key_material, key_material.key_material_size,
+ registry_key(), pkey);
+}
+
+keymaster_error_t AsymmetricKeyFactory::EvpKeyToKeyMaterial(const EVP_PKEY* pkey,
+ KeymasterKeyBlob* key_blob) {
+ int key_data_size = i2d_PrivateKey(pkey, NULL /* key_data*/);
+ if (key_data_size <= 0)
+ return TranslateLastOpenSslError();
+
+ key_blob->Reset(key_data_size);
+ if (!key_blob->key_material)
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey;
- *error = convert_pkcs8_blob_to_evp(key_data, key_data_length, expected_algorithm, &pkey);
- if (*error != KM_ERROR_OK)
- return NULL;
+ uint8_t* tmp = key_blob->writable_data();
+ i2d_PrivateKey(pkey, &tmp);
- return pkey.release();
+ return KM_ERROR_OK;
}
static const keymaster_key_format_t supported_import_formats[] = {KM_KEY_FORMAT_PKCS8};
@@ -56,20 +64,28 @@ const keymaster_key_format_t* AsymmetricKeyFactory::SupportedExportFormats(size_
return supported_export_formats;
}
-keymaster_error_t AsymmetricKey::LoadKey(const UnencryptedKeyBlob& blob) {
- UniquePtr<EVP_PKEY, EVP_PKEY_Delete> evp_key(EVP_PKEY_new());
- if (evp_key.get() == NULL)
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
- EVP_PKEY* tmp_pkey = evp_key.get();
- const uint8_t* key_material = blob.unencrypted_key_material();
- if (d2i_PrivateKey(evp_key_type(), &tmp_pkey, &key_material, blob.key_material_length()) ==
- NULL)
- return TranslateLastOpenSslError();
- if (!EvpToInternal(evp_key.get()))
+keymaster_error_t AsymmetricKeyFactory::LoadKey(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<Key>* key) {
+ UniquePtr<AsymmetricKey> asymmetric_key;
+ keymaster_error_t error = CreateEmptyKey(hw_enforced, sw_enforced, &asymmetric_key);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ const uint8_t* tmp = key_material.key_material;
+ EVP_PKEY* pkey =
+ d2i_PrivateKey(evp_key_type(), NULL /* pkey */, &tmp, key_material.key_material_size);
+ if (!pkey)
return TranslateLastOpenSslError();
+ UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey_deleter(pkey);
- return KM_ERROR_OK;
+ if (!asymmetric_key->EvpToInternal(pkey))
+ error = TranslateLastOpenSslError();
+ else
+ key->reset(asymmetric_key.release());
+
+ return error;
}
keymaster_error_t AsymmetricKey::key_material(UniquePtr<uint8_t[]>* material, size_t* size) const {
diff --git a/asymmetric_key.h b/asymmetric_key.h
index c638dc6..04dac15 100644
--- a/asymmetric_key.h
+++ b/asymmetric_key.h
@@ -20,14 +20,29 @@
#include <openssl/evp.h>
#include "key.h"
+#include "openssl_utils.h"
namespace keymaster {
+class AsymmetricKey;
+
class AsymmetricKeyFactory : public KeyFactory {
- protected:
- EVP_PKEY* ExtractEvpKey(keymaster_key_format_t key_format,
- keymaster_algorithm_t expected_algorithm, const uint8_t* key_data,
- size_t key_data_length, keymaster_error_t* error);
+ public:
+ AsymmetricKeyFactory(const KeymasterContext* context) : KeyFactory(context) {}
+
+ keymaster_error_t KeyMaterialToEvpKey(keymaster_key_format_t key_format,
+ const KeymasterKeyBlob& key_material,
+ UniquePtr<EVP_PKEY, EVP_PKEY_Delete>* evp_pkey);
+ keymaster_error_t EvpKeyToKeyMaterial(const EVP_PKEY* evp_pkey, KeymasterKeyBlob* key_blob);
+
+ keymaster_error_t LoadKey(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, UniquePtr<Key>* key) override;
+
+ virtual keymaster_error_t CreateEmptyKey(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<AsymmetricKey>* key) = 0;
+ virtual int evp_key_type() = 0;
virtual const keymaster_key_format_t* SupportedImportFormats(size_t* format_count);
virtual const keymaster_key_format_t* SupportedExportFormats(size_t* format_count);
@@ -35,27 +50,15 @@ class AsymmetricKeyFactory : public KeyFactory {
class AsymmetricKey : public Key {
public:
- protected:
- AsymmetricKey(const KeyBlob& blob) : Key(blob) {}
- keymaster_error_t LoadKey(const UnencryptedKeyBlob& blob);
-
- /**
- * Return a copy of raw key material, in the key's preferred binary format.
- */
- virtual keymaster_error_t key_material(UniquePtr<uint8_t[]>* material, size_t* size) const;
+ AsymmetricKey(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+ keymaster_error_t* error)
+ : Key(hw_enforced, sw_enforced, error) {}
- /**
- * Return a copy of raw key material, in the specified format.
- */
- virtual keymaster_error_t formatted_key_material(keymaster_key_format_t format,
- UniquePtr<uint8_t[]>* material,
- size_t* size) const;
+ keymaster_error_t key_material(UniquePtr<uint8_t[]>* material, size_t* size) const override;
+ keymaster_error_t formatted_key_material(keymaster_key_format_t format,
+ UniquePtr<uint8_t[]>* material,
+ size_t* size) const override;
- protected:
- AsymmetricKey(const AuthorizationSet& auths) : Key(auths) {}
-
- private:
- virtual int evp_key_type() = 0;
virtual bool InternalToEvp(EVP_PKEY* pkey) const = 0;
virtual bool EvpToInternal(const EVP_PKEY* pkey) = 0;
};
diff --git a/auth_encrypted_key_blob.cpp b/auth_encrypted_key_blob.cpp
new file mode 100644
index 0000000..eb9e2ca
--- /dev/null
+++ b/auth_encrypted_key_blob.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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 "auth_encrypted_key_blob.h"
+
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/logger.h>
+
+#include "ocb_utils.h"
+
+namespace keymaster {
+
+const uint32_t CURRENT_BLOB_VERSION = 0;
+
+keymaster_error_t SerializeAuthEncryptedBlob(const KeymasterKeyBlob& encrypted_key_material,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+
+ const Buffer& nonce, const Buffer& tag,
+ KeymasterKeyBlob* key_blob) {
+ size_t size = 1 /* version byte */ + nonce.SerializedSize() +
+ encrypted_key_material.SerializedSize() + tag.SerializedSize() +
+ hw_enforced.SerializedSize() + sw_enforced.SerializedSize();
+
+ if (!key_blob->Reset(size))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ uint8_t* buf = key_blob->writable_data();
+ const uint8_t* end = key_blob->key_material + key_blob->key_material_size;
+
+ *buf++ = CURRENT_BLOB_VERSION;
+ buf = nonce.Serialize(buf, end);
+ buf = encrypted_key_material.Serialize(buf, end);
+ buf = tag.Serialize(buf, end);
+ buf = hw_enforced.Serialize(buf, end);
+ buf = sw_enforced.Serialize(buf, end);
+ if (buf != key_blob->key_material + key_blob->key_material_size)
+ return KM_ERROR_UNKNOWN_ERROR;
+
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t DeserializeAuthEncryptedBlob(const KeymasterKeyBlob& key_blob,
+ KeymasterKeyBlob* encrypted_key_material,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced, Buffer* nonce,
+ Buffer* tag) {
+ const uint8_t* tmp = key_blob.key_material;
+ const uint8_t** buf_ptr = &tmp;
+ const uint8_t* end = tmp + key_blob.key_material_size;
+
+ uint8_t version = *(*buf_ptr)++;
+ if (version != CURRENT_BLOB_VERSION || //
+ !nonce->Deserialize(buf_ptr, end) || nonce->available_read() != OCB_NONCE_LENGTH ||
+ !encrypted_key_material->Deserialize(buf_ptr, end) || //
+ !tag->Deserialize(buf_ptr, end) || tag->available_read() != OCB_TAG_LENGTH ||
+ !hw_enforced->Deserialize(buf_ptr, end) || //
+ !sw_enforced->Deserialize(buf_ptr, end))
+ return KM_ERROR_INVALID_KEY_BLOB;
+ return KM_ERROR_OK;
+}
+
+} // namespace keymaster
diff --git a/auth_encrypted_key_blob.h b/auth_encrypted_key_blob.h
new file mode 100644
index 0000000..b987d77
--- /dev/null
+++ b/auth_encrypted_key_blob.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#ifndef SYSTEM_KEYMASTER_AUTH_ENCRYPTED_KEY_BLOB_H_
+#define SYSTEM_KEYMASTER_AUTH_ENCRYPTED_KEY_BLOB_H_
+
+#include <hardware/keymaster_defs.h>
+
+namespace keymaster {
+
+class AuthorizationSet;
+class Buffer;
+struct KeymasterKeyBlob;
+
+keymaster_error_t SerializeAuthEncryptedBlob(const KeymasterKeyBlob& encrypted_key_material,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ const Buffer& nonce, const Buffer& tag,
+ KeymasterKeyBlob* key_blob);
+
+keymaster_error_t DeserializeAuthEncryptedBlob(const KeymasterKeyBlob& key_blob,
+ KeymasterKeyBlob* encrypted_key_material,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced, Buffer* nonce,
+ Buffer* tag);
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_AUTH_ENCRYPTED_KEY_BLOB_H_
diff --git a/ec_key.cpp b/ec_key.cpp
index 456ffb8..4deb1c0 100644
--- a/ec_key.cpp
+++ b/ec_key.cpp
@@ -15,43 +15,44 @@
*/
#include "ec_key.h"
-#include "operation.h"
+
+#include <keymaster/keymaster_context.h>
+
#include "openssl_err.h"
#include "openssl_utils.h"
-#include "unencrypted_key_blob.h"
-namespace keymaster {
+#if defined(OPENSSL_IS_BORINGSSL)
+typedef size_t openssl_size_t;
+#else
+typedef int openssl_size_t;
+#endif
-Key* EcKeyFactory::LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) {
- return new EcKey(blob, error);
-}
+namespace keymaster {
-Key* EcKeyFactory::GenerateKey(const AuthorizationSet& key_description,
- keymaster_error_t* error) {
- if (!error)
- return NULL;
+keymaster_error_t EcKeyFactory::GenerateKey(const AuthorizationSet& key_description,
+ KeymasterKeyBlob* key_blob,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) {
+ if (!key_blob || !hw_enforced || !sw_enforced)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
AuthorizationSet authorizations(key_description);
uint32_t key_size;
-
if (!authorizations.GetTagValue(TAG_KEY_SIZE, &key_size)) {
LOG_E("%s", "No key size specified for EC key generation");
- *error = KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ return KM_ERROR_UNSUPPORTED_KEY_SIZE;
}
UniquePtr<EC_KEY, EcKey::EC_Delete> ec_key(EC_KEY_new());
UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
- if (ec_key.get() == NULL || pkey.get() == NULL) {
- *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
- return NULL;
- }
+ if (ec_key.get() == NULL || pkey.get() == NULL)
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
UniquePtr<EC_GROUP, EC_GROUP_Delete> group(choose_group(key_size));
if (group.get() == NULL) {
- // Technically, could also have been a memory allocation problem.
LOG_E("Unable to get EC group for key of size %d", key_size);
- *error = KM_ERROR_UNSUPPORTED_KEY_SIZE;
- return NULL;
+ return KM_ERROR_UNSUPPORTED_KEY_SIZE;
}
#if !defined(OPENSSL_IS_BORINGSSL)
@@ -61,47 +62,52 @@ Key* EcKeyFactory::GenerateKey(const AuthorizationSet& key_description,
if (EC_KEY_set_group(ec_key.get(), group.get()) != 1 ||
EC_KEY_generate_key(ec_key.get()) != 1 || EC_KEY_check_key(ec_key.get()) < 0) {
- *error = TranslateLastOpenSslError();
- return NULL;
+ return TranslateLastOpenSslError();
}
- EcKey* new_key = new EcKey(ec_key.release(), authorizations);
- *error = new_key ? KM_ERROR_OK : KM_ERROR_MEMORY_ALLOCATION_FAILED;
- return new_key;
-}
+ if (EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get()) != 1)
+ return TranslateLastOpenSslError();
-Key* EcKeyFactory::ImportKey(const AuthorizationSet& key_description,
- keymaster_key_format_t key_format, const uint8_t* key_data,
- size_t key_data_length, keymaster_error_t* error) {
- if (!error)
- return NULL;
+ KeymasterKeyBlob key_material;
+ keymaster_error_t error = EvpKeyToKeyMaterial(pkey.get(), &key_material);
+ if (error != KM_ERROR_OK)
+ return error;
- UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(
- ExtractEvpKey(key_format, registry_key(), key_data, key_data_length, error));
- if (*error != KM_ERROR_OK)
- return NULL;
- assert(pkey.get());
+ return context_->CreateKeyBlob(authorizations, KM_ORIGIN_GENERATED, key_material, key_blob,
+ hw_enforced, sw_enforced);
+}
- UniquePtr<EC_KEY, EcKey::EC_Delete> ec_key(EVP_PKEY_get1_EC_KEY(pkey.get()));
- if (!ec_key.get()) {
- *error = TranslateLastOpenSslError();
- return NULL;
- }
+keymaster_error_t EcKeyFactory::ImportKey(const AuthorizationSet& key_description,
+ keymaster_key_format_t input_key_material_format,
+ const KeymasterKeyBlob& input_key_material,
+ KeymasterKeyBlob* output_key_blob,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) {
+ if (!output_key_blob || !hw_enforced || !sw_enforced)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+ UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey;
+ keymaster_error_t error =
+ KeyMaterialToEvpKey(input_key_material_format, input_key_material, &pkey);
+ if (error != KM_ERROR_OK)
+ return error;
- size_t extracted_key_size_bits;
- *error = get_group_size(*EC_KEY_get0_group(ec_key.get()), &extracted_key_size_bits);
- if (*error != KM_ERROR_OK)
- return NULL;
+ UniquePtr<EC_KEY, EcKey::EC_Delete> ec_key(EVP_PKEY_get1_EC_KEY(pkey.get()));
+ if (!ec_key.get())
+ return TranslateLastOpenSslError();
AuthorizationSet authorizations(key_description);
+ size_t extracted_key_size_bits;
+ error = get_group_size(*EC_KEY_get0_group(ec_key.get()), &extracted_key_size_bits);
+ if (error != KM_ERROR_OK)
+ return error;
+
uint32_t key_size_bits;
if (authorizations.GetTagValue(TAG_KEY_SIZE, &key_size_bits)) {
// key_size_bits specified, make sure it matches the key.
- if (key_size_bits != extracted_key_size_bits) {
- *error = KM_ERROR_IMPORT_PARAMETER_MISMATCH;
- return NULL;
- }
+ if (key_size_bits != extracted_key_size_bits)
+ return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
} else {
// key_size_bits not specified, add it.
authorizations.push_back(TAG_KEY_SIZE, extracted_key_size_bits);
@@ -109,18 +115,14 @@ Key* EcKeyFactory::ImportKey(const AuthorizationSet& key_description,
keymaster_algorithm_t algorithm;
if (authorizations.GetTagValue(TAG_ALGORITHM, &algorithm)) {
- if (algorithm != registry_key()) {
- *error = KM_ERROR_IMPORT_PARAMETER_MISMATCH;
- return NULL;
- }
+ if (algorithm != registry_key())
+ return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
} else {
authorizations.push_back(TAG_ALGORITHM, registry_key());
}
- // Don't bother with the other parameters. If the necessary padding, digest, purpose, etc. are
- // missing, the error will be diagnosed when the key is used (when auth checking is
- // implemented).
- *error = KM_ERROR_OK;
- return new EcKey(ec_key.release(), authorizations);
+
+ return context_->CreateKeyBlob(authorizations, KM_ORIGIN_IMPORTED, input_key_material,
+ output_key_blob, hw_enforced, sw_enforced);
}
/* static */
@@ -164,9 +166,14 @@ keymaster_error_t EcKeyFactory::get_group_size(const EC_GROUP& group, size_t* ke
return KM_ERROR_OK;
}
-EcKey::EcKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) : AsymmetricKey(blob) {
- if (error)
- *error = LoadKey(blob);
+keymaster_error_t EcKeyFactory::CreateEmptyKey(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<AsymmetricKey>* key) {
+ keymaster_error_t error;
+ key->reset(new EcKey(hw_enforced, sw_enforced, &error));
+ if (!key->get())
+ error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return error;
}
bool EcKey::EvpToInternal(const EVP_PKEY* pkey) {
diff --git a/ec_key.h b/ec_key.h
index 1748fe0..e3e15f6 100644
--- a/ec_key.h
+++ b/ec_key.h
@@ -25,11 +25,20 @@ namespace keymaster {
class EcKeyFactory : public AsymmetricKeyFactory {
public:
- Key* GenerateKey(const AuthorizationSet& key_description, keymaster_error_t* error) override;
- Key* ImportKey(const AuthorizationSet& key_description, keymaster_key_format_t key_format,
- const uint8_t* key_data, size_t key_data_length,
- keymaster_error_t* error) override;
- Key* LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) override;
+ EcKeyFactory(const KeymasterContext* context) : AsymmetricKeyFactory(context) {}
+
+ keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
+ KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) override;
+ keymaster_error_t ImportKey(const AuthorizationSet& key_description,
+ keymaster_key_format_t input_key_material_format,
+ const KeymasterKeyBlob& input_key_material,
+ KeymasterKeyBlob* output_key_blob, AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) override;
+
+ keymaster_error_t CreateEmptyKey(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<AsymmetricKey>* key) override;
private:
static EC_GROUP* choose_group(size_t key_size_bits);
@@ -42,23 +51,22 @@ class EcKeyFactory : public AsymmetricKeyFactory {
class EcdsaKeyFactory : public EcKeyFactory {
public:
- virtual keymaster_algorithm_t registry_key() const { return KM_ALGORITHM_EC; }
+ EcdsaKeyFactory(const KeymasterContext* context) : EcKeyFactory(context) {}
+
+ keymaster_algorithm_t registry_key() const override { return KM_ALGORITHM_EC; }
+ int evp_key_type() override { return EVP_PKEY_EC; }
};
class EcdsaOperationFactory;
class EcKey : public AsymmetricKey {
- private:
- friend EcKeyFactory;
- friend EcdsaKeyFactory;
- friend EcdsaOperationFactory;
-
- EcKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error);
- EcKey(EC_KEY* ec_key, const AuthorizationSet auths) : AsymmetricKey(auths), ec_key_(ec_key) {}
+ public:
+ EcKey(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+ keymaster_error_t* error)
+ : AsymmetricKey(hw_enforced, sw_enforced, error) {}
- virtual int evp_key_type() { return EVP_PKEY_EC; }
- virtual bool InternalToEvp(EVP_PKEY* pkey) const;
- virtual bool EvpToInternal(const EVP_PKEY* pkey);
+ bool InternalToEvp(EVP_PKEY* pkey) const override;
+ bool EvpToInternal(const EVP_PKEY* pkey) override;
struct EC_Delete {
void operator()(EC_KEY* p) { EC_KEY_free(p); }
diff --git a/ecdsa_operation.h b/ecdsa_operation.h
index 85a54d3..dd5a61f 100644
--- a/ecdsa_operation.h
+++ b/ecdsa_operation.h
@@ -21,8 +21,6 @@
#include <UniquePtr.h>
-#include <keymaster/key_blob.h>
-
#include "operation.h"
namespace keymaster {
diff --git a/hmac_key.cpp b/hmac_key.cpp
index 294832d..1f2e4a4 100644
--- a/hmac_key.cpp
+++ b/hmac_key.cpp
@@ -23,12 +23,18 @@
namespace keymaster {
-Key* HmacKeyFactory::LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) {
- return new HmacKey(blob, error);
-}
+keymaster_error_t HmacKeyFactory::LoadKey(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<Key>* key) {
+ if (!key)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
-SymmetricKey* HmacKeyFactory::CreateKey(const AuthorizationSet& auths) {
- return new HmacKey(auths);
+ keymaster_error_t error;
+ key->reset(new HmacKey(key_material, hw_enforced, sw_enforced, &error));
+ if (!key->get())
+ error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return error;
}
} // namespace keymaster
diff --git a/hmac_key.h b/hmac_key.h
index 065effc..c5a7b91 100644
--- a/hmac_key.h
+++ b/hmac_key.h
@@ -23,21 +23,26 @@ namespace keymaster {
class HmacKeyFactory : public SymmetricKeyFactory {
public:
+ HmacKeyFactory(const KeymasterContext* context) : SymmetricKeyFactory(context) {}
+
keymaster_algorithm_t registry_key() const override { return KM_ALGORITHM_HMAC; }
- Key* LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) override;
- SymmetricKey* CreateKey(const AuthorizationSet& auths) override;
+ keymaster_error_t LoadKey(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, UniquePtr<Key>* key) override;
+
+ private:
+ bool key_size_supported(size_t key_size_bits) const override {
+ return key_size_bits > 0 && key_size_bits % 8 == 00 &&
+ key_size_bits <= 2048 /* Some RFC test cases require >1024-bit keys */;
+ }
};
class HmacKey : public SymmetricKey {
- static const size_t MAX_HMAC_KEY_SIZE = 256; /* Arbitrary limit, for DoS prevention */
-
public:
- HmacKey(const AuthorizationSet& auths) : SymmetricKey(auths) {}
- HmacKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) : SymmetricKey(blob, error) {}
-
- private:
- bool size_supported(size_t key_size) const override { return key_size < MAX_HMAC_KEY_SIZE; }
+ HmacKey(const KeymasterKeyBlob& key_material, const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, keymaster_error_t* error)
+ : SymmetricKey(key_material, hw_enforced, sw_enforced, error) {}
};
} // namespace keymaster
diff --git a/include/keymaster/android_keymaster.h b/include/keymaster/android_keymaster.h
index 7f8e65f..c7a3f41 100644
--- a/include/keymaster/android_keymaster.h
+++ b/include/keymaster/android_keymaster.h
@@ -23,7 +23,7 @@
namespace keymaster {
class Key;
-class UnencryptedKeyBlob;
+class KeymasterContext;
class OperationTable;
/**
@@ -46,7 +46,7 @@ class OperationTable;
*/
class AndroidKeymaster {
public:
- AndroidKeymaster(size_t operation_table_size);
+ AndroidKeymaster(KeymasterContext* context, size_t operation_table_size);
virtual ~AndroidKeymaster();
void SupportedAlgorithms(SupportedResponse<keymaster_algorithm_t>* response) const;
@@ -61,7 +61,7 @@ class AndroidKeymaster {
void SupportedExportFormats(keymaster_algorithm_t algorithm,
SupportedResponse<keymaster_key_format_t>* response) const;
- virtual keymaster_error_t AddRngEntropy(const AddEntropyRequest& request) = 0;
+ keymaster_error_t AddRngEntropy(const AddEntropyRequest& request);
void GenerateKey(const GenerateKeyRequest& request, GenerateKeyResponse* response);
void GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
GetKeyCharacteristicsResponse* response);
@@ -74,30 +74,12 @@ class AndroidKeymaster {
void GetVersion(const GetVersionRequest& request, GetVersionResponse* response);
private:
- virtual bool is_enforced(keymaster_tag_t tag) = 0;
- virtual bool is_hardware() = 0;
- virtual keymaster_key_param_t RootOfTrustTag() = 0;
- virtual keymaster_key_blob_t MasterKey() = 0;
- virtual void GenerateNonce(uint8_t* nonce, size_t length) = 0;
-
- keymaster_error_t SerializeKey(const Key* key, keymaster_key_origin_t origin,
- keymaster_key_blob_t* keymaster_blob, AuthorizationSet* enforced,
- AuthorizationSet* unenforced);
- Key* LoadKey(const keymaster_key_blob_t& key, const AuthorizationSet& client_params,
- keymaster_algorithm_t* algorithm, keymaster_error_t* error);
- UnencryptedKeyBlob* LoadKeyBlob(const keymaster_key_blob_t& key,
- const AuthorizationSet& client_params,
- keymaster_error_t* error);
-
- keymaster_error_t SetAuthorizations(const AuthorizationSet& key_description,
- keymaster_key_origin_t origin, AuthorizationSet* enforced,
- AuthorizationSet* unenforced);
- keymaster_error_t BuildHiddenAuthorizations(const AuthorizationSet& input_set,
- AuthorizationSet* hidden);
-
- void AddAuthorization(const keymaster_key_param_t& auth, AuthorizationSet* enforced,
- AuthorizationSet* unenforced);
+ keymaster_error_t LoadKey(const keymaster_key_blob_t& key_blob,
+ const AuthorizationSet& additional_params,
+ AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced,
+ keymaster_algorithm_t* algorithm, UniquePtr<Key>* key);
+ UniquePtr<KeymasterContext> context_;
UniquePtr<OperationTable> operation_table_;
};
diff --git a/include/keymaster/android_keymaster_utils.h b/include/keymaster/android_keymaster_utils.h
index 20afcdd..c636f5c 100644
--- a/include/keymaster/android_keymaster_utils.h
+++ b/include/keymaster/android_keymaster_utils.h
@@ -23,6 +23,7 @@
#include <UniquePtr.h>
+#include <hardware/keymaster_defs.h>
#include <keymaster/serializable.h>
namespace keymaster {
@@ -49,14 +50,14 @@ inline int64_t java_time(time_t time) {
/**
* Return the size in bytes of the array \p a.
*/
-template <typename T, size_t N> inline size_t array_size(const T (&a)[N]) {
+template <typename T, size_t N> inline size_t array_size(const T(&a)[N]) {
return sizeof(a);
}
/**
* Return the number of elements in array \p a.
*/
-template <typename T, size_t N> inline size_t array_length(const T (&)[N]) {
+template <typename T, size_t N> inline size_t array_length(const T(&)[N]) {
return N;
}
@@ -77,7 +78,7 @@ template <typename T> inline T* dup_array(const T* a, size_t n) {
* responsibility. Note that the dup is necessarily returned as a pointer, so size is lost. Call
* array_length() on the original array to discover the size.
*/
-template <typename T, size_t N> inline T* dup_array(const T (&a)[N]) {
+template <typename T, size_t N> inline T* dup_array(const T(&a)[N]) {
return dup_array(a, N);
}
@@ -90,7 +91,7 @@ uint8_t* dup_buffer(const void* buf, size_t size);
/**
* Copy the contents of array \p arr to \p dest.
*/
-template <typename T, size_t N> inline void copy_array(const T (&arr)[N], T* dest) {
+template <typename T, size_t N> inline void copy_array(const T(&arr)[N], T* dest) {
for (size_t i = 0; i < N; ++i)
dest[i] = arr[i];
}
@@ -100,7 +101,7 @@ template <typename T, size_t N> inline void copy_array(const T (&arr)[N], T* des
* early-exit, meaning that it should not be used in contexts where timing analysis attacks could be
* a concern.
*/
-template <typename T, size_t N> inline bool array_contains(const T (&a)[N], T val) {
+template <typename T, size_t N> inline bool array_contains(const T(&a)[N], T val) {
for (size_t i = 0; i < N; ++i) {
if (a[i] == val) {
return true;
@@ -144,9 +145,9 @@ class Eraser {
template <typename T>
explicit Eraser(T& t)
- : buf_(reinterpret_cast<uint8_t*> (&t)), size_(sizeof(t)) {}
+ : buf_(reinterpret_cast<uint8_t*>(&t)), size_(sizeof(t)) {}
- template <size_t N> explicit Eraser(uint8_t (&arr)[N]) : buf_(arr), size_(N) {}
+ template <size_t N> explicit Eraser(uint8_t(&arr)[N]) : buf_(arr), size_(N) {}
Eraser(void* buf, size_t size) : buf_(static_cast<uint8_t*>(buf)), size_(size) {}
~Eraser() { memset_s(buf_, 0, size_); }
@@ -206,6 +207,85 @@ template <typename T> T hton(T t) {
return retval;
}
+/**
+ * KeymasterKeyBlob is a very simple extension of the C struct keymaster_key_blob_t. It manages its
+ * own memory, which makes avoiding memory leaks much easier.
+ */
+struct KeymasterKeyBlob : public keymaster_key_blob_t {
+ KeymasterKeyBlob() {
+ key_material = nullptr;
+ key_material_size = 0;
+ }
+
+ KeymasterKeyBlob(const uint8_t* data, size_t size) {
+ key_material = dup_buffer(data, size);
+ key_material_size = size;
+ }
+
+ explicit KeymasterKeyBlob(size_t size) {
+ key_material = new uint8_t[size];
+ key_material_size = size;
+ }
+
+ explicit KeymasterKeyBlob(const keymaster_key_blob_t& blob) {
+ key_material = dup_buffer(blob.key_material, blob.key_material_size);
+ key_material_size = blob.key_material_size;
+ }
+
+ KeymasterKeyBlob(const KeymasterKeyBlob& blob) {
+ key_material = dup_buffer(blob.key_material, blob.key_material_size);
+ key_material_size = blob.key_material_size;
+ }
+
+ ~KeymasterKeyBlob() { Clear(); }
+
+ const uint8_t* begin() const { return key_material; }
+ const uint8_t* end() const { return key_material + key_material_size; }
+
+ void Clear() {
+ memset_s(const_cast<uint8_t*>(key_material), 0, key_material_size);
+ delete[] key_material;
+ key_material = nullptr;
+ key_material_size = 0;
+ }
+
+ const uint8_t* Reset(size_t new_size) {
+ Clear();
+ key_material = new uint8_t[new_size];
+ key_material_size = new_size;
+ return key_material;
+ }
+
+ // The key_material in keymaster_key_blob_t is const, which is the right thing in most
+ // circumstances, but occasionally we do need to write into it. This method exposes a non-const
+ // version of the pointer. Use sparingly.
+ uint8_t* writable_data() { return const_cast<uint8_t*>(key_material); }
+
+ keymaster_key_blob_t release() {
+ keymaster_key_blob_t tmp = {key_material, key_material_size};
+ key_material = nullptr;
+ key_material_size = 0;
+ return tmp;
+ }
+
+ size_t SerializedSize() const { return sizeof(uint32_t) + key_material_size; }
+ uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const {
+ return append_size_and_data_to_buf(buf, end, key_material, key_material_size);
+ }
+
+ bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
+ Clear();
+ UniquePtr<uint8_t[]> tmp;
+ if (!copy_size_and_data_from_buf(buf_ptr, end, &key_material_size, &tmp)) {
+ key_material = nullptr;
+ key_material_size = 0;
+ return false;
+ }
+ key_material = tmp.release();
+ return true;
+ }
+};
+
} // namespace keymaster
#endif // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_UTILS_H_
diff --git a/include/keymaster/key_blob.h b/include/keymaster/key_blob.h
deleted file mode 100644
index b2a3778..0000000
--- a/include/keymaster/key_blob.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright 2014 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.
- */
-
-#ifndef SYSTEM_KEYMASTER_KEY_BLOB_H_
-#define SYSTEM_KEYMASTER_KEY_BLOB_H_
-
-#include <cstddef>
-
-#include <stdint.h>
-
-#include <UniquePtr.h>
-
-#include <hardware/keymaster_defs.h>
-#include <keymaster/android_keymaster_utils.h>
-#include <keymaster/authorization_set.h>
-#include <keymaster/serializable.h>
-
-namespace keymaster {
-
-/**
- * This class represents a Keymaster key blob, including authorization sets and encrypted key
- * material. It serializes and deserializes blob arrays, and provides access to the data in the
- * blob.
- */
-class KeyBlob : public Serializable {
- public:
- static const size_t NONCE_LENGTH = 12;
- static const size_t TAG_LENGTH = 128 / 8;
-
- /**
- * Create a KeyBlob, extracting the enforced and unenforced sets. The KeyBlob does *not* take
- * ownership of \p key_blob.
- *
- * IMPORTANT: After constructing a KeyBlob, call error() to verify that the blob is usable.
- */
- KeyBlob(const uint8_t* key_blob, size_t key_blob_length);
-
- /**
- * Create a KeyBlob, extracting the enforced and unenforced sets. The KeyBlob does *not* take
- * ownership of \p key_blob's contents.
- *
- * IMPORTANT: After constructing a KeyBlob, call error() to verify that the blob is usable.
- */
- KeyBlob(const keymaster_key_blob_t& key_blob);
-
- ~KeyBlob() {
- ClearKeyData();
- // AuthorizationSets clear themselves.
- }
-
- size_t SerializedSize() const;
- uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const;
- bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end);
-
- /**
- * Returns KM_ERROR_OK if all is well, or an appropriate error code if there is a problem. This
- * error code should be checked after construction or deserialization, and if it does not return
- * KM_ERROR_OK, then don't call any other methods.
- */
- inline keymaster_error_t error() { return error_; }
-
- inline const uint8_t* nonce() const { return nonce_.get(); }
- inline const uint8_t* encrypted_key_material() const { return encrypted_key_material_.get(); }
- inline size_t key_material_length() const { return key_material_length_; }
- inline const uint8_t* tag() const { return tag_.get(); }
-
- inline const AuthorizationSet& enforced() const { return enforced_; }
- inline const AuthorizationSet& unenforced() const { return unenforced_; }
- inline keymaster_algorithm_t algorithm() const { return algorithm_; }
- inline size_t key_size_bits() const { return key_size_bits_; }
- keymaster_key_origin_t origin() const;
- bool is_hardware() const;
-
- protected:
- /**
- * Create a KeyBlob containing the specified authorization data.
- *
- * IMPORTANT: After constructing a KeyBlob, call error() to verify that the blob is usable.
- */
- KeyBlob(const AuthorizationSet& enforced, const AuthorizationSet& unenforced);
-
- /**
- * Set encrypted key and supporting nonce and tag. Takes ownership of all arguments.
- */
- void SetEncryptedKey(uint8_t* encrypted_key_material, size_t encrypted_key_material_length,
- uint8_t* nonce, uint8_t* tag);
-
- keymaster_error_t error_;
-
- private:
- void ClearKeyData() {
- // None of these are sensitive, but clear them anyway.
- if (encrypted_key_material_.get())
- memset_s(encrypted_key_material_.get(), 0, key_material_length_);
- if (nonce_.get())
- memset_s(nonce_.get(), 0, NONCE_LENGTH);
- if (tag_.get())
- memset_s(tag_.get(), 0, TAG_LENGTH);
- }
-
- bool DeserializeUnversionedBlob(const uint8_t** buf_ptr, const uint8_t* end);
-
- bool ExtractKeyCharacteristics();
-
- UniquePtr<uint8_t[]> nonce_;
- UniquePtr<uint8_t[]> encrypted_key_material_;
- UniquePtr<uint8_t[]> tag_;
- size_t key_material_length_;
- AuthorizationSet enforced_;
- AuthorizationSet unenforced_;
- keymaster_algorithm_t algorithm_;
- uint32_t key_size_bits_;
-};
-
-} // namespace keymaster
-
-#endif // SYSTEM_KEYMASTER_KEY_BLOB_H_
diff --git a/include/keymaster/keymaster_context.h b/include/keymaster/keymaster_context.h
new file mode 100644
index 0000000..68410f8
--- /dev/null
+++ b/include/keymaster/keymaster_context.h
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+#ifndef SYSTEM_KEYMASTER_KEYMASTER_CONTEXT_H_
+#define SYSTEM_KEYMASTER_KEYMASTER_CONTEXT_H_
+
+#include <assert.h>
+
+#include <keymaster/authorization_set.h>
+#include <keymaster/android_keymaster_utils.h>
+
+namespace keymaster {
+
+/**
+ * KeymasterContext provides a singleton abstract interface that encapsulates various
+ * environment-dependent elements of AndroidKeymaster.
+ *
+ * AndroidKeymaster runs in multiple contexts. Primarily:
+ *
+ * - In a trusted execution environment (TEE) as a "secure hardware" implementation. In this
+ * context keys are wrapped with an master key that never leaves the TEE, TEE-specific routines
+ * are used for random number generation, all AndroidKeymaster-enforced authorizations are
+ * considered hardware-enforced, and there's a bootloader-provided root of trust.
+ *
+ * - In the non-secure world as a software-only implementation. In this context keys are not
+ * encrypted (though they are integrity-checked) because there is no place to securely store a
+ * key, OpenSSL is used for random number generation, no AndroidKeymaster-enforced authorizations
+ * are considered hardware enforced and the root of trust is a static string.
+ *
+ * - In the non-secure world as a hybrid implementation fronting a less-capable hardware
+ * implementation. For example, a keymaster0 hardware implementation. In this context keys are
+ * not encrypted by AndroidKeymaster, but some may be opaque blobs provided by the backing
+ * hardware, but blobs that lack the extended authorization lists of keymaster1. In addition,
+ * keymaster0 lacks many features of keymaster1, including modes of operation related to the
+ * backing keymaster0 keys. AndroidKeymaster must extend the blobs to add authorization lists,
+ * and must provide the missing operation mode implementations in software, which means that
+ * authorization lists are partially hardware-enforced (the bits that are enforced by the
+ * underlying keymaster0) and partially software-enforced (the rest). OpenSSL is used for number
+ * generation and the root of trust is a static string.
+ *
+ * More contexts are possible.
+ */
+class KeymasterContext {
+ public:
+ KeymasterContext() {}
+ virtual ~KeymasterContext() {};
+
+ /**
+ * CreateKeyBlob takes authorization sets and key material and produces a key blob and hardware
+ * and software authorization lists ready to be returned to the AndroidKeymaster client
+ * (Keystore, generally). The blob is integrity-checked and may be encrypted, depending on the
+ * needs of the context.
+ *
+ * This method is generally called only by KeyFactory subclassses.
+ */
+ virtual keymaster_error_t CreateKeyBlob(const AuthorizationSet& key_description,
+ keymaster_key_origin_t origin,
+ const KeymasterKeyBlob& key_material,
+ KeymasterKeyBlob* blob, AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) const = 0;
+
+ /**
+ * ParseKeyBlob takes a blob and extracts authorization sets and key material, returning an
+ * error if the blob fails integrity checking or decryption. Note that the returned key
+ * material may itself be an opaque blob usable only by secure hardware (in the hybrid case).
+ *
+ * This method is called by AndroidKeymaster.
+ */
+ virtual keymaster_error_t ParseKeyBlob(const KeymasterKeyBlob& blob,
+ const AuthorizationSet& additional_params,
+ KeymasterKeyBlob* key_material,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) const = 0;
+
+ /**
+ * Adds entropy to the Cryptographic Pseudo Random Number Generator used to generate key
+ * material, and other cryptographic protocol elements. Note that if the underlying CPRNG
+ * tracks the size of its entropy pool, it should not assume that the provided data contributes
+ * any entropy, and it should also ensure that data provided through this interface cannot
+ * "poison" the CPRNG outputs, making them predictable.
+ */
+ virtual keymaster_error_t AddRngEntropy(const uint8_t* buf, size_t length) const = 0;
+
+ /**
+ * Generates \p length random bytes, placing them in \p buf.
+ */
+ virtual keymaster_error_t GenerateRandom(uint8_t* buf, size_t length) const = 0;
+
+ private:
+ // Uncopyable.
+ KeymasterContext(const KeymasterContext&);
+ void operator=(const KeymasterContext&);
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_KEYMASTER_CONTEXT_H_
diff --git a/include/keymaster/serializable.h b/include/keymaster/serializable.h
index b183367..e996fd8 100644
--- a/include/keymaster/serializable.h
+++ b/include/keymaster/serializable.h
@@ -194,6 +194,9 @@ class Buffer : public Serializable {
return Reinitialize(buffer.peek_read(), buffer.available_read());
}
+ const uint8_t* begin() const { return peek_read(); }
+ const uint8_t* end() const { return peek_read() + available_read(); }
+
void Clear();
size_t available_write() const;
diff --git a/include/keymaster/soft_keymaster_device.h b/include/keymaster/soft_keymaster_device.h
index 58dd2d9..44e64e9 100644
--- a/include/keymaster/soft_keymaster_device.h
+++ b/include/keymaster/soft_keymaster_device.h
@@ -51,7 +51,8 @@ class SoftKeymasterDevice {
}
private:
- static keymaster_error_t ExtractSigningParams(const void* signing_params,
+ static keymaster_error_t ExtractSigningParams(const keymaster1_device_t* dev,
+ const void* signing_params,
const uint8_t* key_blob, size_t key_blob_length,
AuthorizationSet* auth_set);
static void StoreDefaultNewKeyParams(AuthorizationSet* auth_set);
diff --git a/key.cpp b/key.cpp
index ffc2b83..776ca1b 100644
--- a/key.cpp
+++ b/key.cpp
@@ -19,16 +19,19 @@
#include <openssl/x509.h>
#include "openssl_utils.h"
-#include "unencrypted_key_blob.h"
namespace keymaster {
/* static */
template <> KeyFactoryRegistry* KeyFactoryRegistry::instance_ptr = 0;
-Key::Key(const KeyBlob& blob) {
- authorizations_.push_back(blob.unenforced());
- authorizations_.push_back(blob.enforced());
+Key::Key(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+ keymaster_error_t* error) {
+ assert(error);
+ authorizations_.push_back(hw_enforced);
+ authorizations_.push_back(sw_enforced);
+ *error = KM_ERROR_OK;
+ if (authorizations_.is_valid() != AuthorizationSet::OK)
+ *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
}
-
} // namespace keymaster
diff --git a/key.h b/key.h
index f7d2a1c..0eb1539 100644
--- a/key.h
+++ b/key.h
@@ -22,18 +22,19 @@
#include <keymaster/logger.h>
#include "abstract_factory_registry.h"
-#include "unencrypted_key_blob.h"
namespace keymaster {
class Key;
+class KeymasterContext;
/**
- * KeyFactory is a pure interface whose subclasses know how to construct a specific subclass of Key.
+ * KeyFactory is a abstraction whose subclasses know how to construct a specific subclass of Key.
* There is a one to one correspondence between Key subclasses and KeyFactory subclasses.
*/
class KeyFactory {
public:
+ KeyFactory(const KeymasterContext* context) : context_(context) {}
virtual ~KeyFactory() {}
// Required for registry
@@ -41,15 +42,27 @@ class KeyFactory {
virtual keymaster_algorithm_t registry_key() const = 0;
// Factory methods.
- virtual Key* GenerateKey(const AuthorizationSet& key_description, keymaster_error_t* error) = 0;
- virtual Key* ImportKey(const AuthorizationSet& key_description,
- keymaster_key_format_t key_format, const uint8_t* key_data,
- size_t key_data_length, keymaster_error_t* error) = 0;
- virtual Key* LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) = 0;
+ virtual keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
+ KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) = 0;
+
+ virtual keymaster_error_t ImportKey(const AuthorizationSet& key_description,
+ keymaster_key_format_t input_key_material_format,
+ const KeymasterKeyBlob& input_key_material,
+ KeymasterKeyBlob* output_key_blob,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) = 0;
+
+ virtual keymaster_error_t LoadKey(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, UniquePtr<Key>* key) = 0;
// Informational methods.
virtual const keymaster_key_format_t* SupportedImportFormats(size_t* format_count) = 0;
virtual const keymaster_key_format_t* SupportedExportFormats(size_t* format_count) = 0;
+
+ protected:
+ const KeymasterContext* context_;
};
typedef AbstractFactoryRegistry<KeyFactory> KeyFactoryRegistry;
@@ -77,8 +90,8 @@ class Key {
const AuthorizationSet& authorizations() const { return authorizations_; }
protected:
- Key(const KeyBlob& blob);
- Key(const AuthorizationSet& authorizations) : authorizations_(authorizations) {}
+ Key(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+ keymaster_error_t* error);
private:
AuthorizationSet authorizations_;
diff --git a/key_blob.cpp b/key_blob.cpp
deleted file mode 100644
index 4dfdc60..0000000
--- a/key_blob.cpp
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright 2014 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 <assert.h>
-
-#include <keymaster/android_keymaster_utils.h>
-#include <keymaster/key_blob.h>
-#include <keymaster/logger.h>
-
-namespace keymaster {
-
-const size_t KeyBlob::NONCE_LENGTH;
-const size_t KeyBlob::TAG_LENGTH;
-
-KeyBlob::KeyBlob(const uint8_t* key_blob, size_t key_blob_length) : error_(KM_ERROR_OK) {
- Deserialize(&key_blob, key_blob + key_blob_length);
-}
-
-KeyBlob::KeyBlob(const keymaster_key_blob_t& key_blob) : error_(KM_ERROR_OK) {
- const uint8_t* key_material = key_blob.key_material;
- Deserialize(&key_material, key_blob.key_material + key_blob.key_material_size);
-}
-
-size_t KeyBlob::SerializedSize() const {
- return 1 /* version byte */ + sizeof(uint32_t) /* nonce length */ + NONCE_LENGTH +
- sizeof(uint32_t) + key_material_length() + sizeof(uint32_t) /* tag length */ +
- TAG_LENGTH + enforced_.SerializedSize() + unenforced_.SerializedSize();
-}
-
-const uint8_t BLOB_VERSION = 0;
-
-uint8_t* KeyBlob::Serialize(uint8_t* buf, const uint8_t* end) const {
- const uint8_t* start __attribute__((__unused__)) = buf;
- *buf++ = BLOB_VERSION;
- buf = append_size_and_data_to_buf(buf, end, nonce(), NONCE_LENGTH);
- buf = append_size_and_data_to_buf(buf, end, encrypted_key_material(), key_material_length());
- buf = append_size_and_data_to_buf(buf, end, tag(), TAG_LENGTH);
- buf = enforced_.Serialize(buf, end);
- buf = unenforced_.Serialize(buf, end);
- assert(buf - start == static_cast<ptrdiff_t>(SerializedSize()));
- return buf;
-}
-
-bool KeyBlob::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) {
- const uint8_t* start = *buf_ptr;
- uint8_t version = *(*buf_ptr)++;
- size_t nonce_length;
- size_t tag_length;
- if (version != BLOB_VERSION ||
- !copy_size_and_data_from_buf(buf_ptr, end, &nonce_length, &nonce_) ||
- nonce_length != NONCE_LENGTH ||
- !copy_size_and_data_from_buf(buf_ptr, end, &key_material_length_,
- &encrypted_key_material_) ||
- !copy_size_and_data_from_buf(buf_ptr, end, &tag_length, &tag_) ||
- tag_length != TAG_LENGTH || !enforced_.Deserialize(buf_ptr, end) ||
- !unenforced_.Deserialize(buf_ptr, end)) {
- *buf_ptr = start;
- // This blob failed to parse. Either it's corrupted or it's a blob generated by an earlier
- // version of keymaster using a previous blob format which did not include the version byte
- // or the nonce or tag length fields. So we try to parse it as that previous version.
- //
- // Note that it's not really a problem if we erronously parse a corrupted blob, because
- // decryption will fail the authentication check.
- //
- // A bigger potential problem is: What if a valid unversioned blob appears to parse
- // correctly as a versioned blob? It would then be rejected during decryption, causing a
- // valid key to become unusable. If this is a disk encryption key, upgrading to a keymaster
- // version with the new format would destroy the user's data.
- //
- // What is the probability that an unversioned key could be successfully parsed as a version
- // 0 key? The first 12 bytes of an unversioned key are the nonce, which, in the only
- // keymaster version released with unversioned keys, is chosen randomly. In order for an
- // unversioned key to parse as a version 0 key, the following must be true about the first
- // five of those random bytes:
- //
- // 1. The first byte must be zero. This will happen with probability 1/2^8.
- //
- // 2. The second through fifth bytes must contain an unsigned integer value equal to
- // NONCE_LENGTH. This will happen with probability 1/2^32.
- //
- // Based on those two checks alone, the probability of interpreting an unversioned blob as a
- // version 0 blob is 1/2^40. That's small enough to be negligible, but there are additional
- // checks which lower it further.
- LOG_I("Failed to deserialize versioned key blob. Assuming unversioned.");
- *buf_ptr = start;
- if (!DeserializeUnversionedBlob(buf_ptr, end))
- return false;
- }
- return ExtractKeyCharacteristics();
-}
-
-bool KeyBlob::DeserializeUnversionedBlob(const uint8_t** buf_ptr, const uint8_t* end) {
- nonce_.reset(new uint8_t[NONCE_LENGTH]);
- tag_.reset(new uint8_t[TAG_LENGTH]);
- if (!nonce_.get() || !tag_.get()) {
- error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
- return false;
- }
-
- if (!copy_from_buf(buf_ptr, end, nonce_.get(), NONCE_LENGTH) ||
- !copy_size_and_data_from_buf(buf_ptr, end, &key_material_length_,
- &encrypted_key_material_) ||
- !copy_from_buf(buf_ptr, end, tag_.get(), TAG_LENGTH) ||
- !enforced_.Deserialize(buf_ptr, end) || !unenforced_.Deserialize(buf_ptr, end)) {
- encrypted_key_material_.reset();
- LOG_E("Failed to deserialize unversioned blob", 0);
- error_ = KM_ERROR_INVALID_KEY_BLOB;
- return false;
- }
- return ExtractKeyCharacteristics();
-}
-
-KeyBlob::KeyBlob(const AuthorizationSet& enforced, const AuthorizationSet& unenforced)
- : error_(KM_ERROR_OK), enforced_(enforced), unenforced_(unenforced) {
-}
-
-void KeyBlob::SetEncryptedKey(uint8_t* encrypted_key_material, size_t encrypted_key_material_length,
- uint8_t* nonce, uint8_t* tag) {
- ClearKeyData();
- encrypted_key_material_.reset(encrypted_key_material);
- key_material_length_ = encrypted_key_material_length;
- nonce_.reset(nonce);
- tag_.reset(tag);
-}
-
-bool KeyBlob::ExtractKeyCharacteristics() {
- if (!enforced_.GetTagValue(TAG_ALGORITHM, &algorithm_) &&
- !unenforced_.GetTagValue(TAG_ALGORITHM, &algorithm_)) {
- error_ = KM_ERROR_UNSUPPORTED_ALGORITHM;
- return false;
- }
- if (!enforced_.GetTagValue(TAG_KEY_SIZE, &key_size_bits_) &&
- !unenforced_.GetTagValue(TAG_KEY_SIZE, &key_size_bits_)) {
- error_ = KM_ERROR_UNSUPPORTED_KEY_SIZE;
- return false;
- }
- return true;
-}
-
-keymaster_key_origin_t KeyBlob::origin() const {
- keymaster_key_origin_t origin;
- if (!enforced_.GetTagValue(TAG_ORIGIN, &origin) &&
- !unenforced_.GetTagValue(TAG_ORIGIN, &origin))
- // This should be impossible.
- assert(false);
- return origin;
-}
-
-bool KeyBlob::is_hardware() const {
- keymaster_key_origin_t origin;
- return enforced_.GetTagValue(TAG_ORIGIN, &origin);
-}
-
-} // namespace keymaster
diff --git a/key_blob_test.cpp b/key_blob_test.cpp
index fc4d8cd..0c60ad2 100644
--- a/key_blob_test.cpp
+++ b/key_blob_test.cpp
@@ -25,7 +25,9 @@
#include <keymaster/android_keymaster_utils.h>
#include <keymaster/keymaster_tags.h>
-#include "unencrypted_key_blob.h"
+#include "android_keymaster_test_utils.h"
+#include "auth_encrypted_key_blob.h"
+#include "ocb_utils.h"
namespace keymaster {
@@ -36,277 +38,254 @@ const uint8_t key_data[5] = {21, 22, 23, 24, 25};
class KeyBlobTest : public testing::Test {
protected:
- KeyBlobTest() {
- enforced_.push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
- enforced_.push_back(TAG_KEY_SIZE, 256);
- enforced_.push_back(TAG_BLOB_USAGE_REQUIREMENTS, KM_BLOB_STANDALONE);
- enforced_.push_back(TAG_MIN_SECONDS_BETWEEN_OPS, 10);
- enforced_.push_back(TAG_ALL_USERS);
- enforced_.push_back(TAG_NO_AUTH_REQUIRED);
- enforced_.push_back(TAG_ORIGIN, KM_ORIGIN_GENERATED);
-
- unenforced_.push_back(TAG_ACTIVE_DATETIME, 10);
- unenforced_.push_back(TAG_ORIGINATION_EXPIRE_DATETIME, 100);
- unenforced_.push_back(TAG_CREATION_DATETIME, 10);
- unenforced_.push_back(TAG_CHUNK_LENGTH, 10);
+ KeyBlobTest()
+ : master_key_(master_key_data, array_length(master_key_data)),
+ key_material_(key_data, array_length(key_data)) {
+ hw_enforced_.push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
+ hw_enforced_.push_back(TAG_KEY_SIZE, 256);
+ hw_enforced_.push_back(TAG_BLOB_USAGE_REQUIREMENTS, KM_BLOB_STANDALONE);
+ hw_enforced_.push_back(TAG_MIN_SECONDS_BETWEEN_OPS, 10);
+ hw_enforced_.push_back(TAG_ALL_USERS);
+ hw_enforced_.push_back(TAG_NO_AUTH_REQUIRED);
+ hw_enforced_.push_back(TAG_ORIGIN, KM_ORIGIN_GENERATED);
+
+ sw_enforced_.push_back(TAG_ACTIVE_DATETIME, 10);
+ sw_enforced_.push_back(TAG_ORIGINATION_EXPIRE_DATETIME, 100);
+ sw_enforced_.push_back(TAG_CREATION_DATETIME, 10);
+ sw_enforced_.push_back(TAG_CHUNK_LENGTH, 10);
hidden_.push_back(TAG_ROOT_OF_TRUST, "foo", 3);
hidden_.push_back(TAG_APPLICATION_ID, "my_app", 6);
- EXPECT_EQ(1, RAND_bytes(nonce_, array_size(nonce_)));
+ nonce_.reserve(OCB_NONCE_LENGTH);
+ EXPECT_EQ(1, RAND_bytes(nonce_.peek_write(), OCB_NONCE_LENGTH));
+ nonce_.advance_write(OCB_NONCE_LENGTH);
- blob_.reset(new UnencryptedKeyBlob(enforced_, unenforced_, hidden_, key_data,
- array_size(key_data), master_key_data,
- array_size(master_key_data), nonce_));
+ tag_.reserve(OCB_TAG_LENGTH);
}
- AuthorizationSet enforced_;
- AuthorizationSet unenforced_;
+ keymaster_error_t Encrypt() {
+ return OcbEncryptKey(hw_enforced_, sw_enforced_, hidden_, master_key_, key_material_,
+ nonce_, &ciphertext_, &tag_);
+ }
+
+ keymaster_error_t Decrypt() {
+ return OcbDecryptKey(hw_enforced_, sw_enforced_, hidden_, master_key_, ciphertext_, nonce_,
+ tag_, &decrypted_plaintext_);
+ }
+
+ keymaster_error_t Serialize() {
+ return SerializeAuthEncryptedBlob(ciphertext_, hw_enforced_, sw_enforced_, nonce_, tag_,
+ &serialized_blob_);
+ }
+
+ keymaster_error_t Deserialize() {
+ return DeserializeAuthEncryptedBlob(serialized_blob_, &ciphertext_, &hw_enforced_,
+ &sw_enforced_, &nonce_, &tag_);
+ }
+
+ AuthorizationSet hw_enforced_;
+ AuthorizationSet sw_enforced_;
AuthorizationSet hidden_;
+ Buffer nonce_, tag_;
- UniquePtr<UnencryptedKeyBlob> blob_;
- uint8_t nonce_[KeyBlob::NONCE_LENGTH];
+ KeymasterKeyBlob master_key_;
+ KeymasterKeyBlob key_material_;
+ KeymasterKeyBlob ciphertext_;
+ KeymasterKeyBlob decrypted_plaintext_;
+ KeymasterKeyBlob serialized_blob_;
};
TEST_F(KeyBlobTest, EncryptDecrypt) {
- size_t size = blob_->SerializedSize();
- UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
- blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
-
- // key_data shouldn't be anywhere in the blob.
- uint8_t* begin = serialized_blob.get();
- uint8_t* end = begin + size;
- EXPECT_EQ(end, std::search(begin, end, key_data, key_data + array_size(key_data)));
-
- // Recover the key material.
- keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
- UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, master_key_data,
- array_size(master_key_data));
- EXPECT_EQ(KM_ERROR_OK, deserialized.error());
- EXPECT_EQ(0, memcmp(deserialized.unencrypted_key_material(), key_data, array_size(key_data)));
+ ASSERT_EQ(KM_ERROR_OK, Encrypt());
+ ASSERT_EQ(KM_ERROR_OK, Serialize());
+
+ // key_data shouldn't be anywhere in the blob, ciphertext should.
+ EXPECT_EQ(serialized_blob_.end(), std::search(serialized_blob_.begin(), serialized_blob_.end(),
+ key_material_.begin(), key_material_.end()));
+ EXPECT_NE(serialized_blob_.end(), std::search(serialized_blob_.begin(), serialized_blob_.end(),
+ ciphertext_.begin(), ciphertext_.end()));
+
+ ciphertext_.Clear();
+ nonce_.Clear();
+ tag_.Clear();
+ AuthorizationSet hw2;
+ AuthorizationSet sw2;
+
+ ASSERT_EQ(KM_ERROR_OK, DeserializeAuthEncryptedBlob(serialized_blob_, &ciphertext_, &hw2, &sw2,
+ &nonce_, &tag_));
+ KeymasterKeyBlob plaintext;
+ OcbDecryptKey(hw2, sw2, hidden_, master_key_, ciphertext_, nonce_, tag_, &plaintext);
+
+ EXPECT_EQ(hw_enforced_, hw2);
+ EXPECT_EQ(sw_enforced_, sw2);
+
+ ASSERT_EQ(key_material_.key_material_size, plaintext.key_material_size);
+ EXPECT_EQ(0, memcmp(plaintext.begin(), key_material_.begin(), plaintext.key_material_size));
}
TEST_F(KeyBlobTest, WrongKeyLength) {
- size_t size = blob_->SerializedSize();
- UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
- blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
-
- // Modify the key length
- serialized_blob[UnencryptedKeyBlob::NONCE_LENGTH]++;
-
- // Decrypting with wrong nonce should fail.
- keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
- UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, master_key_data,
- array_size(master_key_data));
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
+ ASSERT_EQ(KM_ERROR_OK, Encrypt());
+ ASSERT_EQ(KM_ERROR_OK, Serialize());
+
+ // Modify the key length, shouldn't be able to parse.
+ serialized_blob_.writable_data()[1 /* version */ + 4 /* nonce len */ + 12 /* nonce */ + 3]++;
+
+ ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Deserialize());
}
TEST_F(KeyBlobTest, WrongNonce) {
- size_t size = blob_->SerializedSize();
- UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
- blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
+ ASSERT_EQ(KM_ERROR_OK, Encrypt());
+ ASSERT_EQ(KM_ERROR_OK, Serialize());
// Find the nonce, then modify it.
- uint8_t* begin = serialized_blob.get();
- uint8_t* end = begin + size;
- auto nonce_ptr = std::search(begin, end, nonce_, nonce_ + array_size(nonce_));
- ASSERT_NE(nonce_ptr, end);
- EXPECT_EQ(end, std::search(nonce_ptr + 1, end, nonce_, nonce_ + array_size(nonce_)));
- (*nonce_ptr)++;
-
- // Decrypting with wrong nonce should fail.
- keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
- UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, master_key_data,
- array_size(master_key_data));
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
- EXPECT_NE(0, memcmp(deserialized.unencrypted_key_material(), key_data, array_size(key_data)));
+ auto nonce_ptr =
+ std::search(serialized_blob_.begin(), serialized_blob_.end(), nonce_.begin(), nonce_.end());
+ ASSERT_NE(nonce_ptr, serialized_blob_.end());
+ EXPECT_EQ(serialized_blob_.end(),
+ std::search(nonce_ptr + 1, serialized_blob_.end(), nonce_.begin(), nonce_.end()));
+ (*const_cast<uint8_t*>(nonce_ptr))++;
+
+ // Deserialization shouldn't be affected, but decryption should fail.
+ ASSERT_EQ(KM_ERROR_OK, Deserialize());
+ ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt());
}
TEST_F(KeyBlobTest, WrongTag) {
- size_t size = blob_->SerializedSize();
- UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
- blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
+ ASSERT_EQ(KM_ERROR_OK, Encrypt());
+ ASSERT_EQ(KM_ERROR_OK, Serialize());
// Find the tag, them modify it.
- uint8_t* begin = serialized_blob.get();
- uint8_t* end = begin + size;
auto tag_ptr =
- std::search(begin, end, blob_->tag(), blob_->tag() + UnencryptedKeyBlob::TAG_LENGTH);
- ASSERT_NE(tag_ptr, end);
- EXPECT_EQ(end, std::search(tag_ptr + 1, end, blob_->tag(),
- blob_->tag() + UnencryptedKeyBlob::TAG_LENGTH));
- (*tag_ptr)++;
-
- // Decrypting with wrong tag should fail.
- keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
- UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, master_key_data,
- array_size(master_key_data));
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
- EXPECT_NE(0, memcmp(deserialized.unencrypted_key_material(), key_data, array_size(key_data)));
+ std::search(serialized_blob_.begin(), serialized_blob_.end(), tag_.begin(), tag_.end());
+ ASSERT_NE(tag_ptr, serialized_blob_.end());
+ EXPECT_EQ(serialized_blob_.end(),
+ std::search(tag_ptr + 1, serialized_blob_.end(), tag_.begin(), tag_.end()));
+ (*const_cast<uint8_t*>(tag_ptr))++;
+
+ // Deserialization shouldn't be affected, but decryption should fail.
+ ASSERT_EQ(KM_ERROR_OK, Deserialize());
+ ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt());
}
TEST_F(KeyBlobTest, WrongCiphertext) {
- size_t size = blob_->SerializedSize();
- UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
- blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
+ ASSERT_EQ(KM_ERROR_OK, Encrypt());
+ ASSERT_EQ(KM_ERROR_OK, Serialize());
// Find the ciphertext, them modify it.
- uint8_t* begin = serialized_blob.get();
- uint8_t* end = begin + size;
- auto ciphertext_ptr =
- std::search(begin, end, blob_->encrypted_key_material(),
- blob_->encrypted_key_material() + blob_->key_material_length());
- ASSERT_NE(ciphertext_ptr, end);
- EXPECT_EQ(end, std::search(ciphertext_ptr + 1, end, blob_->encrypted_key_material(),
- blob_->encrypted_key_material() + blob_->key_material_length()));
- (*ciphertext_ptr)++;
-
- // Decrypting with wrong tag should fail.
- keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
- UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, master_key_data,
- array_size(master_key_data));
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
- EXPECT_NE(0, memcmp(deserialized.unencrypted_key_material(), key_data, array_size(key_data)));
+ auto ciphertext_ptr = std::search(serialized_blob_.begin(), serialized_blob_.end(),
+ ciphertext_.begin(), ciphertext_.end());
+ ASSERT_NE(ciphertext_ptr, serialized_blob_.end());
+ EXPECT_EQ(serialized_blob_.end(), std::search(ciphertext_ptr + 1, serialized_blob_.end(),
+ ciphertext_.begin(), ciphertext_.end()));
+ (*const_cast<uint8_t*>(ciphertext_ptr))++;
+
+ // Deserialization shouldn't be affected, but decryption should fail.
+ ASSERT_EQ(KM_ERROR_OK, Deserialize());
+ ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt());
}
TEST_F(KeyBlobTest, WrongMasterKey) {
- size_t size = blob_->SerializedSize();
- UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
- blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
+ ASSERT_EQ(KM_ERROR_OK, Encrypt());
+ ASSERT_EQ(KM_ERROR_OK, Serialize());
uint8_t wrong_master_data[] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ KeymasterKeyBlob wrong_master(wrong_master_data, array_length(wrong_master_data));
// Decrypting with wrong master key should fail.
- keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
- UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, wrong_master_data,
- array_size(wrong_master_data));
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
- EXPECT_NE(0, memcmp(deserialized.unencrypted_key_material(), key_data, array_size(key_data)));
+ ASSERT_EQ(KM_ERROR_OK, Deserialize());
+ ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+ OcbDecryptKey(hw_enforced_, sw_enforced_, hidden_, wrong_master, ciphertext_, nonce_,
+ tag_, &decrypted_plaintext_));
}
-TEST_F(KeyBlobTest, WrongEnforced) {
- size_t size = blob_->SerializedSize();
- UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
- blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
- uint8_t* begin = serialized_blob.get();
- uint8_t* end = begin + size;
+TEST_F(KeyBlobTest, WrongHwEnforced) {
+ ASSERT_EQ(KM_ERROR_OK, Encrypt());
+ ASSERT_EQ(KM_ERROR_OK, Serialize());
// Find enforced serialization data and modify it.
- size_t enforced_size = enforced_.SerializedSize();
- UniquePtr<uint8_t[]> enforced_data(new uint8_t[enforced_size]);
- enforced_.Serialize(enforced_data.get(), enforced_data.get() + enforced_size);
-
- auto enforced_ptr =
- std::search(begin, end, enforced_data.get(), enforced_data.get() + enforced_size);
- ASSERT_NE(end, enforced_ptr);
- EXPECT_EQ(end, std::search(enforced_ptr + 1, end, enforced_data.get(),
- enforced_data.get() + enforced_size));
- (*(enforced_ptr + enforced_size - 1))++;
-
- // Decrypting with wrong unenforced data should fail.
- keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
- UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, master_key_data,
- array_size(master_key_data));
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
+ size_t hw_enforced_size = hw_enforced_.SerializedSize();
+ UniquePtr<uint8_t[]> hw_enforced_data(new uint8_t[hw_enforced_size]);
+ hw_enforced_.Serialize(hw_enforced_data.get(), hw_enforced_data.get() + hw_enforced_size);
+
+ auto hw_enforced_ptr =
+ std::search(serialized_blob_.begin(), serialized_blob_.end(), hw_enforced_data.get(),
+ hw_enforced_data.get() + hw_enforced_size);
+ ASSERT_NE(serialized_blob_.end(), hw_enforced_ptr);
+ EXPECT_EQ(serialized_blob_.end(),
+ std::search(hw_enforced_ptr + 1, serialized_blob_.end(), hw_enforced_data.get(),
+ hw_enforced_data.get() + hw_enforced_size));
+ (*(const_cast<uint8_t*>(hw_enforced_ptr) + hw_enforced_size - 1))++;
+
+ // Deserialization shouldn't be affected, but decryption should fail.
+ ASSERT_EQ(KM_ERROR_OK, Deserialize());
+ ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt());
}
-TEST_F(KeyBlobTest, WrongUnenforced) {
- size_t size = blob_->SerializedSize();
- UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
- blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
- uint8_t* begin = serialized_blob.get();
- uint8_t* end = begin + size;
-
- // Find unenforced serialization data and modify it.
- size_t unenforced_size = unenforced_.SerializedSize();
- UniquePtr<uint8_t[]> unenforced_data(new uint8_t[unenforced_size]);
- unenforced_.Serialize(unenforced_data.get(), unenforced_data.get() + unenforced_size);
-
- auto unenforced_ptr =
- std::search(begin, end, unenforced_data.get(), unenforced_data.get() + unenforced_size);
- ASSERT_NE(end, unenforced_ptr);
- EXPECT_EQ(end, std::search(unenforced_ptr + 1, end, unenforced_data.get(),
- unenforced_data.get() + unenforced_size));
- (*(unenforced_ptr + unenforced_size - 1))++;
-
- // Decrypting with wrong unenforced data should fail.
- keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
- UnencryptedKeyBlob deserialized(encrypted_blob, hidden_, master_key_data,
- array_size(master_key_data));
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
+TEST_F(KeyBlobTest, WrongSwEnforced) {
+ ASSERT_EQ(KM_ERROR_OK, Encrypt());
+ ASSERT_EQ(KM_ERROR_OK, Serialize());
+
+ // Find enforced serialization data and modify it.
+ size_t sw_enforced_size = sw_enforced_.SerializedSize();
+ UniquePtr<uint8_t[]> sw_enforced_data(new uint8_t[sw_enforced_size]);
+ sw_enforced_.Serialize(sw_enforced_data.get(), sw_enforced_data.get() + sw_enforced_size);
+
+ auto sw_enforced_ptr =
+ std::search(serialized_blob_.begin(), serialized_blob_.end(), sw_enforced_data.get(),
+ sw_enforced_data.get() + sw_enforced_size);
+ ASSERT_NE(serialized_blob_.end(), sw_enforced_ptr);
+ EXPECT_EQ(serialized_blob_.end(),
+ std::search(sw_enforced_ptr + 1, serialized_blob_.end(), sw_enforced_data.get(),
+ sw_enforced_data.get() + sw_enforced_size));
+ (*(const_cast<uint8_t*>(sw_enforced_ptr) + sw_enforced_size - 1))++;
+
+ // Deserialization shouldn't be affected, but decryption should fail.
+ ASSERT_EQ(KM_ERROR_OK, Deserialize());
+ ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, Decrypt());
}
TEST_F(KeyBlobTest, EmptyHidden) {
- size_t size = blob_->SerializedSize();
- UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
- blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
+ ASSERT_EQ(KM_ERROR_OK, Encrypt());
+ ASSERT_EQ(KM_ERROR_OK, Serialize());
AuthorizationSet wrong_hidden;
- // Decrypting with wrong hidden data should fail.
- keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
- UnencryptedKeyBlob deserialized(encrypted_blob, wrong_hidden, master_key_data,
- array_size(master_key_data));
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
+ // Deserialization shouldn't be affected, but decryption should fail.
+ ASSERT_EQ(KM_ERROR_OK, Deserialize());
+ EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+ OcbDecryptKey(hw_enforced_, sw_enforced_, wrong_hidden, master_key_, ciphertext_,
+ nonce_, tag_, &decrypted_plaintext_));
}
TEST_F(KeyBlobTest, WrongRootOfTrust) {
- size_t size = blob_->SerializedSize();
- UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
- blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
+ ASSERT_EQ(KM_ERROR_OK, Encrypt());
+ ASSERT_EQ(KM_ERROR_OK, Serialize());
AuthorizationSet wrong_hidden;
- wrong_hidden.push_back(TAG_ROOT_OF_TRUST, "bar", 3);
+ wrong_hidden.push_back(TAG_ROOT_OF_TRUST, "bar", 2);
wrong_hidden.push_back(TAG_APPLICATION_ID, "my_app", 6);
- // Decrypting with wrong hidden data should fail.
- keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
- UnencryptedKeyBlob deserialized(encrypted_blob, wrong_hidden, master_key_data,
- array_size(master_key_data));
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
+ // Deserialization shouldn't be affected, but decryption should fail.
+ ASSERT_EQ(KM_ERROR_OK, Deserialize());
+ EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+ OcbDecryptKey(hw_enforced_, sw_enforced_, wrong_hidden, master_key_, ciphertext_,
+ nonce_, tag_, &decrypted_plaintext_));
}
TEST_F(KeyBlobTest, WrongAppId) {
- size_t size = blob_->SerializedSize();
- UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
- blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
+ ASSERT_EQ(KM_ERROR_OK, Encrypt());
+ ASSERT_EQ(KM_ERROR_OK, Serialize());
AuthorizationSet wrong_hidden;
wrong_hidden.push_back(TAG_ROOT_OF_TRUST, "foo", 3);
wrong_hidden.push_back(TAG_APPLICATION_ID, "your_app", 7);
- // Decrypting with wrong hidden data should fail.
- keymaster_key_blob_t encrypted_blob = {serialized_blob.get(), size};
- UnencryptedKeyBlob deserialized(encrypted_blob, wrong_hidden, master_key_data,
- array_size(master_key_data));
- EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, deserialized.error());
-}
-
-TEST_F(KeyBlobTest, UnversionedBlob) {
- // Manually construct an unversioned blob serialization.
- size_t unversioned_blob_size =
- KeyBlob::NONCE_LENGTH + // nonce data
- sizeof(uint32_t) + // length of key material
- blob_->key_material_length() + // key material data
- KeyBlob::TAG_LENGTH + // tag data
- blob_->enforced().SerializedSize() + // serialization of enforced set
- blob_->unenforced().SerializedSize(); // serialization of unenforced set
- UniquePtr<uint8_t[]> unversioned_serialized_blob(new uint8_t[unversioned_blob_size]);
- uint8_t* buf = unversioned_serialized_blob.get();
- const uint8_t* end = buf + unversioned_blob_size;
- buf = append_to_buf(buf, end, blob_->nonce(), KeyBlob::NONCE_LENGTH);
- buf = append_size_and_data_to_buf(buf, end, blob_->encrypted_key_material(),
- blob_->key_material_length());
- buf = append_to_buf(buf, end, blob_->tag(), KeyBlob::TAG_LENGTH);
- buf = blob_->enforced().Serialize(buf, end);
- buf = blob_->unenforced().Serialize(buf, end);
- EXPECT_EQ(buf, end);
-
- keymaster_key_blob_t unversioned_blob = {unversioned_serialized_blob.get(),
- unversioned_blob_size};
- UnencryptedKeyBlob deserialized(unversioned_blob, hidden_, master_key_data,
- array_size(master_key_data));
- EXPECT_EQ(KM_ERROR_OK, deserialized.error());
+ // Deserialization shouldn't be affected, but decryption should fail.
+ ASSERT_EQ(KM_ERROR_OK, Deserialize());
+ EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB,
+ OcbDecryptKey(hw_enforced_, sw_enforced_, wrong_hidden, master_key_, ciphertext_,
+ nonce_, tag_, &decrypted_plaintext_));
}
} // namespace test
diff --git a/ocb_utils.cpp b/ocb_utils.cpp
new file mode 100644
index 0000000..171d07e
--- /dev/null
+++ b/ocb_utils.cpp
@@ -0,0 +1,183 @@
+/*
+ * 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 "ocb_utils.h"
+
+#include <assert.h>
+
+#include <openssl/aes.h>
+#include <openssl/sha.h>
+
+#include <hardware/keymaster_defs.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/android_keymaster_utils.h>
+
+#include "openssl_err.h"
+
+namespace keymaster {
+
+class AeCtx {
+ public:
+ AeCtx() : ctx_(ae_allocate(NULL)) {}
+ ~AeCtx() {
+ ae_clear(ctx_);
+ ae_free(ctx_);
+ }
+
+ ae_ctx* get() { return ctx_; }
+
+ private:
+ ae_ctx* ctx_;
+};
+
+static keymaster_error_t BuildDerivationData(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ const AuthorizationSet& hidden,
+ UniquePtr<uint8_t[]>* derivation_data,
+ size_t* derivation_data_length) {
+ *derivation_data_length =
+ hidden.SerializedSize() + hw_enforced.SerializedSize() + sw_enforced.SerializedSize();
+ derivation_data->reset(new uint8_t[*derivation_data_length]);
+ if (!derivation_data->get())
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ uint8_t* buf = derivation_data->get();
+ uint8_t* end = derivation_data->get() + *derivation_data_length;
+ buf = hidden.Serialize(buf, end);
+ buf = hw_enforced.Serialize(buf, end);
+ buf = sw_enforced.Serialize(buf, end);
+
+ return KM_ERROR_OK;
+}
+
+static keymaster_error_t InitializeKeyWrappingContext(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ const AuthorizationSet& hidden,
+ const KeymasterKeyBlob& master_key,
+ AeCtx* ctx) {
+ size_t derivation_data_length;
+ UniquePtr<uint8_t[]> derivation_data;
+ keymaster_error_t error = BuildDerivationData(hw_enforced, sw_enforced, hidden,
+ &derivation_data, &derivation_data_length);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ SHA256_CTX sha256_ctx;
+ UniquePtr<uint8_t[]> hash_buf(new uint8_t[SHA256_DIGEST_LENGTH]);
+ Eraser hash_eraser(hash_buf.get(), SHA256_DIGEST_LENGTH);
+ UniquePtr<uint8_t[]> derived_key(new uint8_t[AES_BLOCK_SIZE]);
+ Eraser derived_key_eraser(derived_key.get(), AES_BLOCK_SIZE);
+
+ if (!ctx->get() || !hash_buf.get() || !derived_key.get())
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ // Hash derivation data.
+ Eraser sha256_ctx_eraser(sha256_ctx);
+ SHA256_Init(&sha256_ctx);
+ SHA256_Update(&sha256_ctx, derivation_data.get(), derivation_data_length);
+ SHA256_Final(hash_buf.get(), &sha256_ctx);
+
+ // Encrypt hash with master key to build derived key.
+ AES_KEY aes_key;
+ Eraser aes_key_eraser(AES_KEY);
+ if (0 !=
+ AES_set_encrypt_key(master_key.key_material, master_key.key_material_size * 8, &aes_key))
+ return TranslateLastOpenSslError();
+
+ AES_encrypt(hash_buf.get(), derived_key.get(), &aes_key);
+
+ // Set up AES OCB context using derived key.
+ if (ae_init(ctx->get(), derived_key.get(), AES_BLOCK_SIZE /* key length */, OCB_NONCE_LENGTH,
+ OCB_TAG_LENGTH) != AE_SUCCESS) {
+ memset_s(ctx->get(), 0, ae_ctx_sizeof());
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t OcbEncryptKey(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, const AuthorizationSet& hidden,
+ const KeymasterKeyBlob& master_key,
+ const KeymasterKeyBlob& plaintext, const Buffer& nonce,
+ KeymasterKeyBlob* ciphertext, Buffer* tag) {
+ assert(ciphertext && tag);
+
+ if (nonce.available_read() != OCB_NONCE_LENGTH)
+ return KM_ERROR_INVALID_ARGUMENT;
+
+ AeCtx ctx;
+ keymaster_error_t error =
+ InitializeKeyWrappingContext(hw_enforced, sw_enforced, hidden, master_key, &ctx);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ ciphertext->Reset(plaintext.key_material_size);
+ if (!ciphertext->key_material)
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ int ae_err = ae_encrypt(ctx.get(), nonce.peek_read(), plaintext.key_material,
+ plaintext.key_material_size, NULL /* additional data */,
+ 0 /* additional data length */, ciphertext->writable_data(),
+ tag->peek_write(), 1 /* final */);
+ if (ae_err < 0) {
+ LOG_E("Error %d while encrypting key", ae_err);
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+ tag->advance_write(OCB_TAG_LENGTH);
+ assert(ae_err == static_cast<int>(plaintext.key_material_size));
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t OcbDecryptKey(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, const AuthorizationSet& hidden,
+ const KeymasterKeyBlob& master_key,
+ const KeymasterKeyBlob& ciphertext, const Buffer& nonce,
+ const Buffer& tag, KeymasterKeyBlob* plaintext) {
+ assert(plaintext);
+
+ if (nonce.available_read() != OCB_NONCE_LENGTH || tag.available_read() != OCB_TAG_LENGTH)
+ return KM_ERROR_INVALID_ARGUMENT;
+
+ AeCtx ctx;
+ keymaster_error_t error =
+ InitializeKeyWrappingContext(hw_enforced, sw_enforced, hidden, master_key, &ctx);
+ if (error != KM_ERROR_OK)
+ return error;
+
+ plaintext->Reset(ciphertext.key_material_size);
+ if (!plaintext->key_material)
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ int ae_err = ae_decrypt(ctx.get(), nonce.peek_read(), ciphertext.key_material,
+ ciphertext.key_material_size, NULL /* additional data */,
+ 0 /* additional data length */, plaintext->writable_data(),
+ tag.peek_read(), 1 /* final */);
+ if (ae_err == AE_INVALID) {
+ // Authentication failed! Decryption probably succeeded(ish), but we don't want to return
+ // any data when the authentication fails, so clear it.
+ plaintext->Clear();
+ LOG_E("Failed to validate authentication tag during key decryption", 0);
+ return KM_ERROR_INVALID_KEY_BLOB;
+ } else if (ae_err < 0) {
+ LOG_E("Failed to decrypt key, error: %d", ae_err);
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+ assert(ae_err == static_cast<int>(ciphertext.key_material_size));
+ return KM_ERROR_OK;
+}
+
+} // namespace keymaster
diff --git a/ocb_utils.h b/ocb_utils.h
index 2104742..bae1e08 100644
--- a/ocb_utils.h
+++ b/ocb_utils.h
@@ -19,21 +19,29 @@
#include "ae.h"
+#include <hardware/keymaster_defs.h>
+
+#include <keymaster/serializable.h>
+
namespace keymaster {
-class AeCtx {
- public:
- AeCtx() : ctx_(ae_allocate(NULL)) {}
- ~AeCtx() {
- ae_clear(ctx_);
- ae_free(ctx_);
- }
+class AuthorizationSet;
+struct KeymasterKeyBlob;
+
+static const int OCB_NONCE_LENGTH = 12;
+static const int OCB_TAG_LENGTH = 16;
- ae_ctx* get() { return ctx_; }
+keymaster_error_t OcbEncryptKey(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, const AuthorizationSet& hidden,
+ const KeymasterKeyBlob& master_key,
+ const KeymasterKeyBlob& plaintext, const Buffer& nonce,
+ KeymasterKeyBlob* ciphertext, Buffer* tag);
- private:
- ae_ctx* ctx_;
-};
+keymaster_error_t OcbDecryptKey(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, const AuthorizationSet& hidden,
+ const KeymasterKeyBlob& master_key,
+ const KeymasterKeyBlob& ciphertext, const Buffer& nonce,
+ const Buffer& tag, KeymasterKeyBlob* plaintext);
} // namespace keymaster
diff --git a/rsa_key.cpp b/rsa_key.cpp
index 5150588..293d51e 100644
--- a/rsa_key.cpp
+++ b/rsa_key.cpp
@@ -16,10 +16,10 @@
#include "rsa_key.h"
+#include <keymaster/keymaster_context.h>
+
#include "openssl_err.h"
#include "openssl_utils.h"
-#include "rsa_operation.h"
-#include "unencrypted_key_blob.h"
#if defined(OPENSSL_IS_BORINGSSL)
typedef size_t openssl_size_t;
@@ -29,66 +29,67 @@ typedef int openssl_size_t;
namespace keymaster {
-Key* RsaKeyFactory::LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) {
- return new RsaKey(blob, error);
-}
-
-Key* RsaKeyFactory::GenerateKey(const AuthorizationSet& key_description, keymaster_error_t* error) {
- if (!error)
- return NULL;
+keymaster_error_t RsaKeyFactory::GenerateKey(const AuthorizationSet& key_description,
+ KeymasterKeyBlob* key_blob,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) {
+ if (!key_blob || !hw_enforced || !sw_enforced)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
AuthorizationSet authorizations(key_description);
uint64_t public_exponent;
if (!authorizations.GetTagValue(TAG_RSA_PUBLIC_EXPONENT, &public_exponent)) {
LOG_E("%s", "No public exponent specified for RSA key generation");
- *error = KM_ERROR_INVALID_ARGUMENT;
- return NULL;
+ return KM_ERROR_INVALID_ARGUMENT;
}
uint32_t key_size;
if (!authorizations.GetTagValue(TAG_KEY_SIZE, &key_size)) {
LOG_E("%s", "No key size specified for RSA key generation");
- *error = KM_ERROR_UNSUPPORTED_KEY_SIZE;
- return NULL;
+ return KM_ERROR_UNSUPPORTED_KEY_SIZE;
}
UniquePtr<BIGNUM, BIGNUM_Delete> exponent(BN_new());
UniquePtr<RSA, RsaKey::RSA_Delete> rsa_key(RSA_new());
UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKEY_new());
- if (exponent.get() == NULL || rsa_key.get() == NULL || pkey.get() == NULL) {
- *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
- return NULL;
- }
+ if (exponent.get() == NULL || rsa_key.get() == NULL || pkey.get() == NULL)
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
if (!BN_set_word(exponent.get(), public_exponent) ||
- !RSA_generate_key_ex(rsa_key.get(), key_size, exponent.get(), NULL /* callback */)) {
- *error = TranslateLastOpenSslError();
- return NULL;
- }
+ !RSA_generate_key_ex(rsa_key.get(), key_size, exponent.get(), NULL /* callback */))
+ return TranslateLastOpenSslError();
- RsaKey* new_key = new RsaKey(rsa_key.release(), authorizations);
- *error = new_key ? KM_ERROR_OK : KM_ERROR_MEMORY_ALLOCATION_FAILED;
- return new_key;
-}
+ if (EVP_PKEY_set1_RSA(pkey.get(), rsa_key.get()) != 1)
+ return TranslateLastOpenSslError();
-Key* RsaKeyFactory::ImportKey(const AuthorizationSet& key_description,
- keymaster_key_format_t key_format, const uint8_t* key_data,
- size_t key_data_length, keymaster_error_t* error) {
- if (!error)
- return NULL;
+ KeymasterKeyBlob key_material;
+ keymaster_error_t error = EvpKeyToKeyMaterial(pkey.get(), &key_material);
+ if (error != KM_ERROR_OK)
+ return error;
- UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(
- ExtractEvpKey(key_format, KM_ALGORITHM_RSA, key_data, key_data_length, error));
- if (*error != KM_ERROR_OK)
- return NULL;
- assert(pkey.get());
+ return context_->CreateKeyBlob(authorizations, KM_ORIGIN_GENERATED, key_material, key_blob,
+ hw_enforced, sw_enforced);
+}
+
+keymaster_error_t RsaKeyFactory::ImportKey(const AuthorizationSet& key_description,
+ keymaster_key_format_t input_key_material_format,
+ const KeymasterKeyBlob& input_key_material,
+ KeymasterKeyBlob* output_key_blob,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) {
+ if (!output_key_blob || !hw_enforced || !sw_enforced)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+ UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey;
+ keymaster_error_t error =
+ KeyMaterialToEvpKey(input_key_material_format, input_key_material, &pkey);
+ if (error != KM_ERROR_OK)
+ return error;
UniquePtr<RSA, RsaKey::RSA_Delete> rsa_key(EVP_PKEY_get1_RSA(pkey.get()));
- if (!rsa_key.get()) {
- *error = TranslateLastOpenSslError();
- return NULL;
- }
+ if (!rsa_key.get())
+ return TranslateLastOpenSslError();
AuthorizationSet authorizations(key_description);
@@ -97,28 +98,22 @@ Key* RsaKeyFactory::ImportKey(const AuthorizationSet& key_description,
// public_exponent specified, make sure it matches the key
UniquePtr<BIGNUM, BIGNUM_Delete> public_exponent_bn(BN_new());
if (!BN_set_word(public_exponent_bn.get(), public_exponent))
- return NULL;
- if (BN_cmp(public_exponent_bn.get(), rsa_key->e) != 0) {
- *error = KM_ERROR_IMPORT_PARAMETER_MISMATCH;
- return NULL;
- }
+ return KM_ERROR_UNKNOWN_ERROR;
+ if (BN_cmp(public_exponent_bn.get(), rsa_key->e) != 0)
+ return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
} else {
// public_exponent not specified, use the one from the key.
public_exponent = BN_get_word(rsa_key->e);
- if (public_exponent == 0xffffffffL) {
- *error = KM_ERROR_IMPORT_PARAMETER_MISMATCH;
- return NULL;
- }
+ if (public_exponent == 0xffffffffL)
+ return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
authorizations.push_back(TAG_RSA_PUBLIC_EXPONENT, public_exponent);
}
uint32_t key_size;
if (authorizations.GetTagValue(TAG_KEY_SIZE, &key_size)) {
// key_size specified, make sure it matches the key.
- if (RSA_size(rsa_key.get()) * 8 != (openssl_size_t)key_size) {
- *error = KM_ERROR_IMPORT_PARAMETER_MISMATCH;
- return NULL;
- }
+ if (RSA_size(rsa_key.get()) * 8 != (openssl_size_t)key_size)
+ return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
} else {
key_size = RSA_size(rsa_key.get()) * 8;
authorizations.push_back(TAG_KEY_SIZE, key_size);
@@ -126,28 +121,24 @@ Key* RsaKeyFactory::ImportKey(const AuthorizationSet& key_description,
keymaster_algorithm_t algorithm;
if (authorizations.GetTagValue(TAG_ALGORITHM, &algorithm)) {
- if (algorithm != KM_ALGORITHM_RSA) {
- *error = KM_ERROR_IMPORT_PARAMETER_MISMATCH;
- return NULL;
- }
+ if (algorithm != KM_ALGORITHM_RSA)
+ return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
} else {
authorizations.push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
}
- // Don't bother with the other parameters. If the necessary padding, digest, purpose, etc. are
- // missing, the error will be diagnosed when the key is used (when auth checking is
- // implemented).
- *error = KM_ERROR_OK;
- return new RsaKey(rsa_key.release(), authorizations);
-}
-
-RsaKey::RsaKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) : AsymmetricKey(blob) {
- if (error)
- *error = LoadKey(blob);
+ return context_->CreateKeyBlob(authorizations, KM_ORIGIN_IMPORTED, input_key_material,
+ output_key_blob, hw_enforced, sw_enforced);
}
-RSA* RsaKey::key() const {
- return rsa_key_.get();
+keymaster_error_t RsaKeyFactory::CreateEmptyKey(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<AsymmetricKey>* key) {
+ keymaster_error_t error;
+ key->reset(new RsaKey(hw_enforced, sw_enforced, &error));
+ if (!key->get())
+ error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return error;
}
bool RsaKey::EvpToInternal(const EVP_PKEY* pkey) {
diff --git a/rsa_key.h b/rsa_key.h
index 129f774..e5b4051 100644
--- a/rsa_key.h
+++ b/rsa_key.h
@@ -25,25 +25,33 @@ namespace keymaster {
class RsaKeyFactory : public AsymmetricKeyFactory {
public:
+ RsaKeyFactory(const KeymasterContext* context) : AsymmetricKeyFactory(context) {}
+
keymaster_algorithm_t registry_key() const override { return KM_ALGORITHM_RSA; }
- Key* GenerateKey(const AuthorizationSet& key_description, keymaster_error_t* error);
- Key* ImportKey(const AuthorizationSet& key_description, keymaster_key_format_t key_format,
- const uint8_t* key_data, size_t key_data_length,
- keymaster_error_t* error) override;
- Key* LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) override;
+ int evp_key_type() override { return EVP_PKEY_RSA; }
+
+ keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
+ KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) override;
+ keymaster_error_t ImportKey(const AuthorizationSet& key_description,
+ keymaster_key_format_t input_key_material_format,
+ const KeymasterKeyBlob& input_key_material,
+ KeymasterKeyBlob* output_key_blob, AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) override;
+
+ keymaster_error_t CreateEmptyKey(const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced,
+ UniquePtr<AsymmetricKey>* key) override;
};
class RsaOperationFactory;
class RsaKey : public AsymmetricKey {
- private:
- friend class RsaKeyFactory;
- friend class RsaOperationFactory;
-
- RsaKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error);
- RsaKey(RSA* rsa_key, const AuthorizationSet& auths) : AsymmetricKey(auths), rsa_key_(rsa_key) {}
+ public:
+ RsaKey(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+ keymaster_error_t* error)
+ : AsymmetricKey(hw_enforced, sw_enforced, error) {}
- int evp_key_type() override { return EVP_PKEY_RSA; }
bool InternalToEvp(EVP_PKEY* pkey) const override;
bool EvpToInternal(const EVP_PKEY* pkey) override;
@@ -54,9 +62,10 @@ class RsaKey : public AsymmetricKey {
void operator()(RSA* p) { RSA_free(p); }
};
- RSA* key() const;
+ RSA* key() const { return rsa_key_.get(); }
- mutable UniquePtr<RSA, RSA_Delete> rsa_key_;
+ private:
+ UniquePtr<RSA, RSA_Delete> rsa_key_;
};
} // namespace keymaster
diff --git a/rsa_operation.h b/rsa_operation.h
index ea8d81d..586aaa1 100644
--- a/rsa_operation.h
+++ b/rsa_operation.h
@@ -22,8 +22,6 @@
#include <openssl/evp.h>
#include <openssl/rsa.h>
-#include <keymaster/key_blob.h>
-
#include "operation.h"
namespace keymaster {
diff --git a/soft_keymaster_context.cpp b/soft_keymaster_context.cpp
new file mode 100644
index 0000000..485d3cd
--- /dev/null
+++ b/soft_keymaster_context.cpp
@@ -0,0 +1,194 @@
+/*
+ * 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 "soft_keymaster_context.h"
+
+#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_key.h"
+#include "hmac_key.h"
+#include "ocb_utils.h"
+#include "openssl_err.h"
+#include "rsa_key.h"
+
+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
+
+class SoftKeymasterKeyRegistrations {
+ public:
+ SoftKeymasterKeyRegistrations(const KeymasterContext* context)
+ : rsa_(context), ec_(context), hmac_(context), aes_(context) {}
+
+ KeyFactoryRegistry::Registration<RsaKeyFactory> rsa_;
+ KeyFactoryRegistry::Registration<EcdsaKeyFactory> ec_;
+ KeyFactoryRegistry::Registration<HmacKeyFactory> hmac_;
+ KeyFactoryRegistry::Registration<AesKeyFactory> aes_;
+};
+
+SoftKeymasterContext::SoftKeymasterContext()
+ : registrations_(new SoftKeymasterKeyRegistrations(this)) {
+}
+
+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) {
+ hw_enforced->Clear();
+ sw_enforced->Clear();
+ for (size_t i = 0; i < key_description.size(); ++i) {
+ switch (key_description[i].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.
+ default:
+ sw_enforced->push_back(key_description[i]);
+ 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;
+
+ 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;
+
+ Buffer nonce, tag;
+ if (!nonce.reserve(OCB_NONCE_LENGTH) || !tag.reserve(OCB_TAG_LENGTH))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ GenerateRandom(nonce.peek_write(), OCB_NONCE_LENGTH);
+ 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 SoftKeymasterContext::ParseKeyBlob(const KeymasterKeyBlob& blob,
+ const AuthorizationSet& additional_params,
+ KeymasterKeyBlob* key_material,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) const {
+ 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;
+
+ AuthorizationSet hidden;
+ error = BuildHiddenAuthorizations(additional_params, &hidden);
+ 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);
+}
+
+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
diff --git a/soft_keymaster_context.h b/soft_keymaster_context.h
new file mode 100644
index 0000000..1dba59d
--- /dev/null
+++ b/soft_keymaster_context.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef SYSTEM_KEYMASTER_SOFT_KEYMASTER_CONTEXT_H_
+#define SYSTEM_KEYMASTER_SOFT_KEYMASTER_CONTEXT_H_
+
+#include <memory>
+
+#include <keymaster/keymaster_context.h>
+
+namespace keymaster {
+
+class SoftKeymasterKeyRegistrations;
+
+/**
+ * SoftKeymasterContext provides the context for a non-secure implementation of AndroidKeymaster.
+ */
+class SoftKeymasterContext : public KeymasterContext {
+ public:
+ SoftKeymasterContext();
+
+ keymaster_error_t CreateKeyBlob(const AuthorizationSet& auths, keymaster_key_origin_t origin,
+ const KeymasterKeyBlob& key_material, KeymasterKeyBlob* blob,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) const override;
+ keymaster_error_t ParseKeyBlob(const KeymasterKeyBlob& blob,
+ const AuthorizationSet& additional_params,
+ KeymasterKeyBlob* key_material, AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) const override;
+ keymaster_error_t AddRngEntropy(const uint8_t* buf, size_t length) const override;
+ keymaster_error_t GenerateRandom(uint8_t* buf, size_t length) const override;
+
+ private:
+ std::unique_ptr<SoftKeymasterKeyRegistrations> registrations_;
+};
+
+} // namespace keymaster
+
+#endif // SYSTEM_KEYMASTER_SOFT_KEYMASTER_CONTEXT_H_
diff --git a/soft_keymaster_device.cpp b/soft_keymaster_device.cpp
index 18ac3e6..9b2fdb4 100644
--- a/soft_keymaster_device.cpp
+++ b/soft_keymaster_device.cpp
@@ -33,16 +33,13 @@
#define LOG_TAG "SoftKeymasterDevice"
#include <cutils/log.h>
-#include <keymaster/authorization_set.h>
+#include <keymaster/android_keymaster.h>
#include <keymaster/android_keymaster_messages.h>
-#include <keymaster/key_blob.h>
+#include <keymaster/authorization_set.h>
#include <keymaster/soft_keymaster_logger.h>
-#include "aes_key.h"
-#include "ec_key.h"
-#include "android_softkeymaster.h"
-#include "hmac_key.h"
-#include "rsa_key.h"
+#include "soft_keymaster_context.h"
+#include "openssl_utils.h"
struct keystore_module soft_keymaster_device_module = {
.common =
@@ -61,12 +58,8 @@ struct keystore_module soft_keymaster_device_module = {
namespace keymaster {
-static KeyFactoryRegistry::Registration<AesKeyFactory> aes_registration;
-static KeyFactoryRegistry::Registration<EcdsaKeyFactory> ec_registration;
-static KeyFactoryRegistry::Registration<HmacKeyFactory> hmac_registration;
-static KeyFactoryRegistry::Registration<RsaKeyFactory> rsa_registration;
-
-SoftKeymasterDevice::SoftKeymasterDevice() : impl_(new AndroidSoftKeymaster(16)) {
+SoftKeymasterDevice::SoftKeymasterDevice()
+ : impl_(new AndroidKeymaster(new SoftKeymasterContext, 16)) {
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
static_assert(std::is_standard_layout<SoftKeymasterDevice>::value,
"SoftKeymasterDevice must be standard layout");
@@ -265,14 +258,6 @@ int SoftKeymasterDevice::import_keypair(const keymaster1_device_t* dev, const ui
return KM_ERROR_OK;
}
-struct EVP_PKEY_Delete {
- void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); }
-};
-
-struct PKCS8_PRIV_KEY_INFO_Delete {
- void operator()(PKCS8_PRIV_KEY_INFO* p) const { PKCS8_PRIV_KEY_INFO_free(p); }
-};
-
/* static */
keymaster_error_t SoftKeymasterDevice::GetPkcs8KeyAlgorithm(const uint8_t* key, size_t key_length,
keymaster_algorithm_t* algorithm) {
@@ -360,8 +345,8 @@ int SoftKeymasterDevice::sign_data(const keymaster1_device_t* dev, const void* p
BeginOperationRequest begin_request;
begin_request.purpose = KM_PURPOSE_SIGN;
begin_request.SetKeyMaterial(key_blob, key_blob_length);
- keymaster_error_t err =
- ExtractSigningParams(params, key_blob, key_blob_length, &begin_request.additional_params);
+ keymaster_error_t err = ExtractSigningParams(dev, params, key_blob, key_blob_length,
+ &begin_request.additional_params);
if (err != KM_ERROR_OK)
return err;
@@ -413,12 +398,10 @@ int SoftKeymasterDevice::verify_data(const keymaster1_device_t* dev, const void*
BeginOperationRequest begin_request;
begin_request.purpose = KM_PURPOSE_VERIFY;
begin_request.SetKeyMaterial(key_blob, key_blob_length);
- {
- keymaster_error_t err = ExtractSigningParams(params, key_blob, key_blob_length,
- &begin_request.additional_params);
- if (err != KM_ERROR_OK)
- return err;
- }
+ keymaster_error_t err = ExtractSigningParams(dev, params, key_blob, key_blob_length,
+ &begin_request.additional_params);
+ if (err != KM_ERROR_OK)
+ return err;
BeginOperationResponse begin_response;
convert_device(dev)->impl_->BeginOperation(begin_request, &begin_response);
@@ -859,15 +842,28 @@ keymaster_error_t SoftKeymasterDevice::abort(const keymaster1_device_t* dev,
}
/* static */
-keymaster_error_t SoftKeymasterDevice::ExtractSigningParams(const void* signing_params,
+keymaster_error_t SoftKeymasterDevice::ExtractSigningParams(const keymaster1_device_t* dev,
+ const void* signing_params,
const uint8_t* key_blob,
size_t key_blob_length,
AuthorizationSet* auth_set) {
- KeyBlob blob(key_blob, key_blob_length);
- if (blob.error() != KM_ERROR_OK)
- return blob.error();
+ const keymaster_blob_t client_id = {nullptr, 0};
+ const keymaster_blob_t app_data = {nullptr, 0};
+ const keymaster_key_blob_t blob = {key_blob, key_blob_length};
+ keymaster_key_characteristics_t* characteristics;
+ keymaster_error_t error =
+ get_key_characteristics(dev, &blob, &client_id, &app_data, &characteristics);
+
+ if (error != KM_ERROR_OK)
+ return error;
+
+ AuthorizationSet auths(characteristics->hw_enforced);
+ auths.push_back(AuthorizationSet(characteristics->sw_enforced));
+ keymaster_algorithm_t algorithm;
+ if (!auths.GetTagValue(TAG_ALGORITHM, &algorithm))
+ return KM_ERROR_INVALID_KEY_BLOB;
- switch (blob.algorithm()) {
+ switch (algorithm) {
case KM_ALGORITHM_RSA: {
const keymaster_rsa_sign_params_t* rsa_params =
reinterpret_cast<const keymaster_rsa_sign_params_t*>(signing_params);
diff --git a/symmetric_key.cpp b/symmetric_key.cpp
index e1ce39f..68fa6f1 100644
--- a/symmetric_key.cpp
+++ b/symmetric_key.cpp
@@ -22,53 +22,73 @@
#include <openssl/rand.h>
#include <keymaster/logger.h>
+#include <keymaster/keymaster_context.h>
#include "aes_key.h"
#include "hmac_key.h"
#include "openssl_err.h"
-#include "unencrypted_key_blob.h"
namespace keymaster {
-Key* SymmetricKeyFactory::GenerateKey(const AuthorizationSet& key_description,
- keymaster_error_t* error) {
- UniquePtr<SymmetricKey> key(CreateKeyAndValidateSize(key_description, error));
- if (!key.get())
- return NULL;
+keymaster_error_t SymmetricKeyFactory::GenerateKey(const AuthorizationSet& key_description,
+ KeymasterKeyBlob* key_blob,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) {
+ if (!key_blob || !hw_enforced || !sw_enforced)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
- if (RAND_bytes(key->key_data_.get(), key->key_data_size_) != 1) {
- LOG_E("Error %ul generating %d bit AES key", ERR_get_error(), key->key_data_size_ * 8);
- *error = TranslateLastOpenSslError();
- return NULL;
+ uint32_t key_size_bits;
+ if (!key_description.GetTagValue(TAG_KEY_SIZE, &key_size_bits) ||
+ !key_size_supported(key_size_bits))
+ return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+
+ size_t key_data_size = key_size_bits / 8;
+ KeymasterKeyBlob key_material(key_data_size);
+ if (!key_material.key_material)
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ keymaster_error_t error = context_->GenerateRandom(key_material.writable_data(), key_data_size);
+ if (error != KM_ERROR_OK) {
+ LOG_E("Error generating %d bit symmetric key", key_size_bits);
+ return error;
}
- if (*error != KM_ERROR_OK)
- return NULL;
- return key.release();
+ return context_->CreateKeyBlob(key_description, KM_ORIGIN_GENERATED, key_material, key_blob,
+ hw_enforced, sw_enforced);
}
-Key* SymmetricKeyFactory::ImportKey(const AuthorizationSet& key_description,
- keymaster_key_format_t format, const uint8_t* key_material,
- size_t key_material_length, keymaster_error_t* error) {
- UniquePtr<SymmetricKey> key(CreateKeyAndValidateSize(key_description, error));
- if (!key.get())
- return NULL;
+keymaster_error_t SymmetricKeyFactory::ImportKey(const AuthorizationSet& key_description,
+ keymaster_key_format_t input_key_material_format,
+ const KeymasterKeyBlob& input_key_material,
+ KeymasterKeyBlob* output_key_blob,
+ AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) {
+ if (!output_key_blob || !hw_enforced || !sw_enforced)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+ AuthorizationSet authorizations(key_description);
- if (format != KM_KEY_FORMAT_RAW) {
- *error = KM_ERROR_UNSUPPORTED_KEY_FORMAT;
- return NULL;
+ uint32_t key_size_bits;
+ if (!authorizations.GetTagValue(TAG_KEY_SIZE, &key_size_bits)) {
+ // Default key size if not specified.
+ key_size_bits = input_key_material.key_material_size * 8;
+ authorizations.push_back(TAG_KEY_SIZE, key_size_bits);
}
- if (key->key_data_size_ != key_material_length) {
- LOG_E("Expected %d byte key data but got %d bytes", key->key_data_size_,
- key_material_length);
- *error = KM_ERROR_INVALID_KEY_BLOB;
- return NULL;
+ if (!key_size_supported(key_size_bits))
+ return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+
+ if (input_key_material_format != KM_KEY_FORMAT_RAW)
+ return KM_ERROR_UNSUPPORTED_KEY_FORMAT;
+
+ if (key_size_bits != input_key_material.key_material_size * 8) {
+ LOG_E("Expected %d-bit key data but got %d bits", key_size_bits,
+ input_key_material.key_material_size * 8);
+ return KM_ERROR_INVALID_KEY_BLOB;
}
- key->key_data_size_ = key_material_length;
- memcpy(key->key_data_.get(), key_material, key_material_length);
- return key.release();
+ return context_->CreateKeyBlob(authorizations, KM_ORIGIN_IMPORTED, input_key_material,
+ output_key_blob, hw_enforced, sw_enforced);
}
static const keymaster_key_format_t supported_import_formats[] = {KM_KEY_FORMAT_RAW};
@@ -77,40 +97,21 @@ const keymaster_key_format_t* SymmetricKeyFactory::SupportedImportFormats(size_t
return supported_import_formats;
}
-SymmetricKey* SymmetricKeyFactory::CreateKeyAndValidateSize(const AuthorizationSet& key_description,
- keymaster_error_t* error) {
- if (!error)
- return NULL;
- *error = KM_ERROR_OK;
-
- UniquePtr<SymmetricKey> key(CreateKey(key_description));
-
- uint32_t key_size_bits;
- if (!key_description.GetTagValue(TAG_KEY_SIZE, &key_size_bits) || key_size_bits % 8 != 0) {
- *error = KM_ERROR_UNSUPPORTED_KEY_SIZE;
- return NULL;
- }
-
- *error = key->set_size(key_size_bits / 8);
+SymmetricKey::SymmetricKey(const KeymasterKeyBlob& key_material,
+ const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
+ keymaster_error_t* error)
+ : Key(hw_enforced, sw_enforced, error) {
if (*error != KM_ERROR_OK)
- return NULL;
-
- return key.release();
-}
-
-SymmetricKey::SymmetricKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error)
- : Key(blob), key_data_size_(blob.unencrypted_key_material_length()) {
- key_data_.reset(new uint8_t[key_data_size_]);
- if (!key_data_.get()) {
- if (error)
- *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
- key_data_size_ = 0;
return;
- }
- memcpy(key_data_.get(), blob.unencrypted_key_material(), key_data_size_);
- if (error)
+ uint8_t* tmp = dup_buffer(key_material.key_material, key_material.key_material_size);
+ if (tmp) {
+ key_data_.reset(tmp);
+ key_data_size_ = key_material.key_material_size;
*error = KM_ERROR_OK;
+ } else {
+ *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
}
SymmetricKey::~SymmetricKey() {
@@ -127,16 +128,4 @@ keymaster_error_t SymmetricKey::key_material(UniquePtr<uint8_t[]>* key_material,
return KM_ERROR_OK;
}
-keymaster_error_t SymmetricKey::set_size(size_t key_size) {
- if (!size_supported(key_size))
- return KM_ERROR_UNSUPPORTED_KEY_SIZE;
-
- key_data_.reset(new uint8_t[key_size]);
- if (!key_data_.get())
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- key_data_size_ = key_size;
-
- return KM_ERROR_OK;
-}
-
} // namespace keymaster
diff --git a/symmetric_key.h b/symmetric_key.h
index 7662a4a..3e39364 100644
--- a/symmetric_key.h
+++ b/symmetric_key.h
@@ -24,9 +24,17 @@ namespace keymaster {
class SymmetricKey;
class SymmetricKeyFactory : public KeyFactory {
- Key* GenerateKey(const AuthorizationSet& key_description, keymaster_error_t* error) override;
- Key* ImportKey(const AuthorizationSet&, keymaster_key_format_t, const uint8_t*, size_t,
- keymaster_error_t* error) override;
+ public:
+ SymmetricKeyFactory(const KeymasterContext* context) : KeyFactory(context) {}
+
+ keymaster_error_t GenerateKey(const AuthorizationSet& key_description,
+ KeymasterKeyBlob* key_blob, AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) override;
+ keymaster_error_t ImportKey(const AuthorizationSet& key_description,
+ keymaster_key_format_t input_key_material_format,
+ const KeymasterKeyBlob& input_key_material,
+ KeymasterKeyBlob* output_key_blob, AuthorizationSet* hw_enforced,
+ AuthorizationSet* sw_enforced) override;
virtual const keymaster_key_format_t* SupportedImportFormats(size_t* format_count);
virtual const keymaster_key_format_t* SupportedExportFormats(size_t* format_count) {
@@ -34,10 +42,8 @@ class SymmetricKeyFactory : public KeyFactory {
};
private:
- SymmetricKey* CreateKeyAndValidateSize(const AuthorizationSet& key_description,
- keymaster_error_t* error);
+ virtual bool key_size_supported(size_t key_size_bits) const = 0;
- virtual SymmetricKey* CreateKey(const AuthorizationSet& auths) = 0;
const keymaster_key_format_t* NoFormats(size_t* format_count) {
*format_count = 0;
return NULL;
@@ -46,10 +52,6 @@ class SymmetricKeyFactory : public KeyFactory {
class SymmetricKey : public Key {
public:
- static const int MAX_KEY_SIZE = 32;
- static const int MAX_MAC_LENGTH = 32;
- static const uint32_t MAX_CHUNK_LENGTH = 64 * 1024;
-
~SymmetricKey();
virtual keymaster_error_t key_material(UniquePtr<uint8_t[]>* key_material, size_t* size) const;
@@ -62,16 +64,12 @@ class SymmetricKey : public Key {
size_t key_data_size() const { return key_data_size_; }
protected:
- SymmetricKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error);
- SymmetricKey(const AuthorizationSet& auths) : Key(auths) {}
+ SymmetricKey(const KeymasterKeyBlob& key_material, const AuthorizationSet& hw_enforced,
+ const AuthorizationSet& sw_enforced, keymaster_error_t* error);
private:
friend SymmetricKeyFactory;
- keymaster_error_t LoadKey(const UnencryptedKeyBlob& blob);
- keymaster_error_t set_size(size_t key_size);
- virtual bool size_supported(size_t key_size) const = 0;
-
size_t key_data_size_;
UniquePtr<uint8_t[]> key_data_;
};
diff --git a/unencrypted_key_blob.cpp b/unencrypted_key_blob.cpp
deleted file mode 100644
index 43a7c25..0000000
--- a/unencrypted_key_blob.cpp
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright 2014 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 <assert.h>
-
-#include <openssl/aes.h>
-#include <openssl/sha.h>
-
-#include <keymaster/android_keymaster_utils.h>
-
-#include "ae.h"
-#include "unencrypted_key_blob.h"
-#include "ocb_utils.h"
-#include "openssl_err.h"
-
-namespace keymaster {
-
-UnencryptedKeyBlob::UnencryptedKeyBlob(const AuthorizationSet& enforced,
- const AuthorizationSet& unenforced,
- const AuthorizationSet& hidden,
- const uint8_t* unencrypted_key,
- size_t unencrypted_key_length, const uint8_t* master_key,
- size_t master_key_length, const uint8_t nonce[NONCE_LENGTH])
- : KeyBlob(enforced, unenforced), hidden_(hidden) {
- // Check that KeyBlob ctor succeeded.
- if (error_ != KM_ERROR_OK)
- return;
-
- if (hidden_.is_valid() == AuthorizationSet::ALLOCATION_FAILURE) {
- error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
- return;
- }
-
- if (hidden_.is_valid() != AuthorizationSet::OK) {
- error_ = KM_ERROR_UNKNOWN_ERROR;
- return;
- }
-
- unencrypted_key_material_.reset(new uint8_t[unencrypted_key_length]);
- if (!unencrypted_key_material_.get()) {
- error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
- return;
- }
-
- unencrypted_key_material_length_ = unencrypted_key_length;
- memcpy(unencrypted_key_material_.get(), unencrypted_key, unencrypted_key_length);
- EncryptKey(master_key, master_key_length, nonce);
-}
-
-UnencryptedKeyBlob::UnencryptedKeyBlob(const keymaster_key_blob_t& key,
- const AuthorizationSet& hidden, const uint8_t* master_key,
- size_t master_key_length)
- : KeyBlob(key), hidden_(hidden) {
- // Check that KeyBlob ctor succeeded.
- if (error_ != KM_ERROR_OK)
- return;
- DecryptKey(master_key, master_key_length);
-}
-
-void UnencryptedKeyBlob::EncryptKey(const uint8_t* master_key, size_t master_key_length,
- const uint8_t* nonce) {
- UniquePtr<AeCtx> ctx(InitializeKeyWrappingContext(master_key, master_key_length));
- if (error_ != KM_ERROR_OK)
- return;
-
- UniquePtr<uint8_t[]> encrypted_key_material(new uint8_t[unencrypted_key_material_length()]);
- UniquePtr<uint8_t[]> tag(new uint8_t[TAG_LENGTH]);
- UniquePtr<uint8_t[]> nonce_copy(new uint8_t[NONCE_LENGTH]);
- if (!encrypted_key_material.get() || !tag.get() || !nonce_copy.get()) {
- error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
- return;
- }
- memcpy(nonce_copy.get(), nonce, NONCE_LENGTH);
-
- int ae_err =
- ae_encrypt(ctx->get(), nonce, unencrypted_key_material(), unencrypted_key_material_length(),
- NULL /* additional data */, 0 /* additional data length */,
- encrypted_key_material.get(), tag.get(), 1 /* final */);
- if (ae_err < 0) {
- LOG_E("Error %d while encrypting key", ae_err);
- error_ = KM_ERROR_UNKNOWN_ERROR;
- return;
- }
- assert(ae_err == static_cast<int>(unencrypted_key_material_length()));
-
- SetEncryptedKey(encrypted_key_material.release(), unencrypted_key_material_length(),
- nonce_copy.release(), tag.release());
-}
-
-void UnencryptedKeyBlob::DecryptKey(const uint8_t* master_key, size_t master_key_length) {
- UniquePtr<AeCtx> ctx(InitializeKeyWrappingContext(master_key, master_key_length));
- if (error_ != KM_ERROR_OK)
- return;
-
- unencrypted_key_material_length_ = key_material_length();
- unencrypted_key_material_.reset(new uint8_t[unencrypted_key_material_length_]);
- int ae_err = ae_decrypt(ctx->get(), nonce(), encrypted_key_material(), key_material_length(),
- NULL /* additional data */, 0 /* additional data length */,
- unencrypted_key_material_.get(), tag(), 1 /* final */);
- if (ae_err == AE_INVALID) {
- // Authentication failed! Decryption probably succeeded(ish), but we don't want to return
- // any data when the authentication fails, so clear it.
- memset_s(unencrypted_key_material_.get(), 0, unencrypted_key_material_length());
- LOG_E("Failed to validate authentication tag during key decryption", 0);
- error_ = KM_ERROR_INVALID_KEY_BLOB;
- return;
- } else if (ae_err < 0) {
- LOG_E("Failed to decrypt key, error: %d", ae_err);
- error_ = KM_ERROR_UNKNOWN_ERROR;
- return;
- }
- assert(ae_err == static_cast<int>(unencrypted_key_material_length()));
- error_ = KM_ERROR_OK;
-}
-
-AeCtx* UnencryptedKeyBlob::InitializeKeyWrappingContext(const uint8_t* master_key,
- size_t master_key_length) {
- size_t derivation_data_length;
- UniquePtr<const uint8_t[]> derivation_data(BuildDerivationData(&derivation_data_length));
- if (derivation_data.get() == NULL) {
- error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
- return NULL;
- }
-
- UniquePtr<AeCtx> ctx(new AeCtx);
-
- SHA256_CTX sha256_ctx;
- UniquePtr<uint8_t[]> hash_buf(new uint8_t[SHA256_DIGEST_LENGTH]);
- Eraser hash_eraser(hash_buf.get(), SHA256_DIGEST_LENGTH);
- UniquePtr<uint8_t[]> derived_key(new uint8_t[AES_BLOCK_SIZE]);
- Eraser derived_key_eraser(derived_key.get(), AES_BLOCK_SIZE);
-
- if (ctx.get() == NULL || hash_buf.get() == NULL || derived_key.get() == NULL) {
- error_ = KM_ERROR_MEMORY_ALLOCATION_FAILED;
- return NULL;
- }
-
- Eraser sha256_ctx_eraser(sha256_ctx);
-
- // Hash derivation data.
- SHA256_Init(&sha256_ctx);
- SHA256_Update(&sha256_ctx, derivation_data.get(), derivation_data_length);
- SHA256_Final(hash_buf.get(), &sha256_ctx);
-
- // Encrypt hash with master key to build derived key.
- AES_KEY aes_key;
- Eraser aes_key_eraser(AES_KEY);
- if (AES_set_encrypt_key(master_key, master_key_length * 8, &aes_key) != 0) {
- error_ = TranslateLastOpenSslError();
- return NULL;
- }
- AES_encrypt(hash_buf.get(), derived_key.get(), &aes_key);
-
- // Set up AES OCB context using derived key.
- if (ae_init(ctx->get(), derived_key.get(), AES_BLOCK_SIZE /* key length */, NONCE_LENGTH,
- TAG_LENGTH) == AE_SUCCESS)
- return ctx.release();
- else {
- memset_s(ctx->get(), 0, ae_ctx_sizeof());
- return NULL;
- }
-}
-
-const uint8_t* UnencryptedKeyBlob::BuildDerivationData(size_t* derivation_data_length) const {
- *derivation_data_length =
- hidden_.SerializedSize() + enforced().SerializedSize() + unenforced().SerializedSize();
- uint8_t* derivation_data = new uint8_t[*derivation_data_length];
- if (derivation_data != NULL) {
- uint8_t* buf = derivation_data;
- uint8_t* end = derivation_data + *derivation_data_length;
- buf = hidden_.Serialize(buf, end);
- buf = enforced().Serialize(buf, end);
- buf = unenforced().Serialize(buf, end);
- }
- return derivation_data;
-}
-
-} // namespace keymaster
diff --git a/unencrypted_key_blob.h b/unencrypted_key_blob.h
deleted file mode 100644
index e559527..0000000
--- a/unencrypted_key_blob.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 2014 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.
- */
-
-#ifndef SYSTEM_KEYMASTER_UNENCRYPTED_KEY_BLOB_H_
-#define SYSTEM_KEYMASTER_UNENCRYPTED_KEY_BLOB_H_
-
-#include <keymaster/key_blob.h>
-
-namespace keymaster {
-
-class AeCtx;
-
-/**
- * Extends KeyBlob to provide access the the unencrypted key material as well as the encrypted form.
- */
-class UnencryptedKeyBlob : public KeyBlob {
- public:
- /**
- * Create a UnencryptedKeyBlob containing the specified authorization data and key material. \p
- * key will be encrypted with a key derived from \p master_key, using OCB authenticated
- * encryption with \p nonce. It is critically important that nonces NEVER be reused. The most
- * convenient way to accomplish that is to choose them randomly.
- *
- * IMPORTANT: After constructing a UnencryptedKeyBlob, call error() to verify that the blob is
- * usable.
- */
- UnencryptedKeyBlob(const AuthorizationSet& enforced, const AuthorizationSet& unenforced,
- const AuthorizationSet& hidden, const uint8_t* unencrypted_key,
- size_t unencrypted_key_length, const uint8_t* master_key,
- size_t master_key_length, const uint8_t nonce[NONCE_LENGTH]);
-
- /**
- * Create a UnencryptedKeyBlob, extracting the enforced and unenforced sets and decrypting the
- * key. The KeyBlob does *not* take ownership of key_blob.
- *
- * IMPORTANT: After constructing a UnencryptedKeyBlob, call error() to verify that the blob is
- * usable.
- */
- UnencryptedKeyBlob(const keymaster_key_blob_t& key_blob, const AuthorizationSet& hidden,
- const uint8_t* master_key, size_t master_key_length);
-
- inline const uint8_t* unencrypted_key_material() const {
- return unencrypted_key_material_.get();
- }
- inline size_t unencrypted_key_material_length() const {
- return unencrypted_key_material_length_;
- }
- inline const AuthorizationSet& hidden() const { return hidden_; }
-
- private:
- void DecryptKey(const uint8_t* master_key, size_t master_key_length);
- void EncryptKey(const uint8_t* master_key, size_t master_key_length, const uint8_t* nonce);
-
- /**
- * Create an AES_OCB context initialized with a key derived using \p master_key and the
- * authorizations.
- */
- AeCtx* InitializeKeyWrappingContext(const uint8_t* master_key, size_t master_key_length);
-
- const uint8_t* BuildDerivationData(size_t* derivation_data_len) const;
-
- UniquePtr<uint8_t[]> unencrypted_key_material_;
- size_t unencrypted_key_material_length_;
- AuthorizationSet hidden_;
-};
-
-} // namespace keymaster
-
-#endif // SYSTEM_KEYMASTER_UNENCRYPTED_KEY_BLOB_H_
diff --git a/valgrind.supp b/valgrind.supp
index 2ca244c..2b51c4b 100644
--- a/valgrind.supp
+++ b/valgrind.supp
@@ -22,4 +22,18 @@
fun:RSA_sign_raw
fun:RSA_private_encrypt
...
+}
+{
+ EcKeyErrorLeak1
+ Memcheck:Leak
+ fun:malloc
+ fun:err_add_error_vdata
+ fun:ERR_add_error_data
+ fun:ASN1_item_ex_d2i
+ fun:ASN1_item_d2i
+ fun:d2i_EC_PRIVATEKEY
+ fun:d2i_ECPrivateKey
+ fun:old_ec_priv_decode
+ fun:d2i_PrivateKey
+ ...
} \ No newline at end of file