summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Willden <swillden@google.com>2015-05-23 03:36:30 +0000
committerShawn Willden <swillden@google.com>2015-05-23 03:36:30 +0000
commit13fbe3e93247943c26e7ca2ed27b6d650282b8bf (patch)
treecd71086d18f6eb1ffc47d7f8cc3d92346ba639c6
parent8ba2a043f0d44ad3f58d4af518f9391c03eca9c3 (diff)
downloadandroid_system_keymaster-13fbe3e93247943c26e7ca2ed27b6d650282b8bf.tar.gz
android_system_keymaster-13fbe3e93247943c26e7ca2ed27b6d650282b8bf.tar.bz2
android_system_keymaster-13fbe3e93247943c26e7ca2ed27b6d650282b8bf.zip
Revert "Large refactor to move context out of AndroidKeymaster."
This reverts commit 8ba2a043f0d44ad3f58d4af518f9391c03eca9c3. I need to update the Volantis non-secure code in sync. Reverting while I get that done. Change-Id: I0fb9f928e7e624ad678050a04bb873b43b1c9a48
-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, 1488 insertions, 1522 deletions
diff --git a/Android.mk b/Android.mk
index ef059cf..f5ace96 100644
--- a/Android.mk
+++ b/Android.mk
@@ -24,6 +24,7 @@ LOCAL_SRC_FILES:= \
android_keymaster_messages.cpp \
android_keymaster_utils.cpp \
authorization_set.cpp \
+ key_blob.cpp \
logger.cpp \
serializable.cpp
LOCAL_C_INCLUDES := \
@@ -36,19 +37,19 @@ include $(BUILD_SHARED_LIBRARY)
###
# libkeymaster1 contains almost everything needed for a keymaster1
-# implementation, lacking only a subclass of the (abstract) KeymasterContext
+# implementation, lacking only a subclass of the (abstract) AndroidKeymaster
# 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 \
@@ -58,14 +59,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
+ symmetric_key.cpp \
+ unencrypted_key_blob.cpp
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include
LOCAL_SHARED_LIBRARIES := libcrypto libkeymaster_messages
@@ -86,7 +87,6 @@ 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 083c65e..2aec87d 100644
--- a/Makefile
+++ b/Makefile
@@ -66,7 +66,6 @@ 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 \
@@ -79,11 +78,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 \
@@ -91,9 +90,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
@@ -182,14 +181,13 @@ 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 \
@@ -202,6 +200,7 @@ 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 \
@@ -209,16 +208,15 @@ 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 \
@@ -226,13 +224,12 @@ 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 e1a890f..8b2c3fd 100644
--- a/aes_key.cpp
+++ b/aes_key.cpp
@@ -22,20 +22,16 @@
#include <openssl/rand.h>
#include "aes_operation.h"
+#include "unencrypted_key_blob.h"
namespace keymaster {
-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;
+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);
}
} // namespace keymaster
diff --git a/aes_key.h b/aes_key.h
index 28efc39..fa615f6 100644
--- a/aes_key.h
+++ b/aes_key.h
@@ -25,25 +25,22 @@ namespace keymaster {
class AesKeyFactory : public SymmetricKeyFactory {
public:
- AesKeyFactory(const KeymasterContext* context) : SymmetricKeyFactory(context) {}
-
keymaster_algorithm_t registry_key() const { return KM_ALGORITHM_AES; }
- 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;
- }
+ Key* LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) override;
+ SymmetricKey* CreateKey(const AuthorizationSet& auths) override;
};
class AesKey : public SymmetricKey {
public:
- 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) {}
+ 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;
+ }
};
} // namespace keymaster
diff --git a/aes_operation.h b/aes_operation.h
index 2172e2d..d4b4687 100644
--- a/aes_operation.h
+++ b/aes_operation.h
@@ -25,8 +25,6 @@
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,
@@ -56,7 +54,7 @@ class AesEvpOperation : public Operation {
const keymaster_padding_t padding_;
const bool caller_iv_;
UniquePtr<uint8_t[]> iv_;
- uint8_t key_[MAX_EVP_KEY_SIZE];
+ uint8_t key_[SymmetricKey::MAX_KEY_SIZE];
};
class AesEvpEncryptOperation : public AesEvpOperation {
diff --git a/android_keymaster.cpp b/android_keymaster.cpp
index ba5361d..df1d100 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(KeymasterContext* context, size_t operation_table_size)
- : context_(context), operation_table_(new OperationTable(operation_table_size)) {
+AndroidKeymaster::AndroidKeymaster(size_t operation_table_size)
+ : operation_table_(new OperationTable(operation_table_size)) {
}
AndroidKeymaster::~AndroidKeymaster() {
@@ -175,11 +175,6 @@ 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)
@@ -191,13 +186,14 @@ 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 {
- 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();
- }
+ 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);
}
void AndroidKeymaster::GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
@@ -205,25 +201,13 @@ void AndroidKeymaster::GetKeyCharacteristics(const GetKeyCharacteristicsRequest&
if (response == NULL)
return;
- 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)
+ UniquePtr<KeyBlob> blob(
+ LoadKeyBlob(request.key_blob, request.additional_params, &(response->error)));
+ if (blob.get() == NULL)
return;
-}
-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;
+ response->enforced.Reinitialize(blob->enforced());
+ response->unenforced.Reinitialize(blob->unenforced());
}
void AndroidKeymaster::BeginOperation(const BeginOperationRequest& request,
@@ -232,24 +216,25 @@ void AndroidKeymaster::BeginOperation(const BeginOperationRequest& request,
return;
response->op_handle = 0;
- AuthorizationSet hw_enforced;
- AuthorizationSet sw_enforced;
keymaster_algorithm_t algorithm;
- UniquePtr<Key> key;
- response->error = LoadKey(request.key_blob, request.additional_params, &hw_enforced,
- &sw_enforced, &algorithm, &key);
+ UniquePtr<Key> key(
+ LoadKey(request.key_blob, request.additional_params, &algorithm, &response->error));
+ if (key.get() == NULL)
+ return;
// TODO(swillden): Move this check to a general authorization checker.
- // 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))
+ if (!key->authorizations().Contains(TAG_PURPOSE, request.purpose)) {
+ // TODO(swillden): Consider introducing error codes for unauthorized usages.
+ response->error = KM_ERROR_INCOMPATIBLE_PURPOSE;
return;
+ }
- response->error = KM_ERROR_UNSUPPORTED_PURPOSE;
- OperationFactory* factory = OperationFactoryRegistry::Get({algorithm, request.purpose});
- if (!factory)
+ OperationFactory::KeyType op_type(algorithm, request.purpose);
+ OperationFactory* factory = OperationFactoryRegistry::Get(op_type);
+ if (!factory) {
+ response->error = KM_ERROR_UNSUPPORTED_PURPOSE;
return;
+ }
UniquePtr<Operation> operation(
factory->CreateOperation(*key, request.additional_params, &response->error));
@@ -313,28 +298,15 @@ 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;
- 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)
+ UniquePtr<Key> to_export(
+ LoadKey(request.key_blob, request.additional_params, &algorithm, &response->error));
+ if (to_export.get() == NULL)
return;
UniquePtr<uint8_t[]> out_key;
size_t size;
- response->error = key->formatted_key_material(request.key_format, &out_key, &size);
+ response->error = to_export->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;
@@ -351,35 +323,168 @@ 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 {
- 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();
- }
+ 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);
}
-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);
+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);
if (error != KM_ERROR_OK)
return error;
- KeyFactory* key_factory = GetKeyFactory(*hw_enforced, *sw_enforced, algorithm, &error);
- if (error != KM_ERROR_OK) {
- assert(!key_factory);
+ 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)
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;
+ }
}
- return key_factory->LoadKey(key_material, *hw_enforced, *sw_enforced, key);
+ 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);
}
} // namespace keymaster
diff --git a/android_keymaster_messages_test.cpp b/android_keymaster_messages_test.cpp
index 143b03b..2c888d9 100644
--- a/android_keymaster_messages_test.cpp
+++ b/android_keymaster_messages_test.cpp
@@ -18,11 +18,11 @@
#include <gtest/gtest.h>
-#include <keymaster/android_keymaster.h>
-#include <keymaster/android_keymaster_utils.h>
#include <keymaster/keymaster_tags.h>
+#include <keymaster/android_keymaster_utils.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 e3faefa..7f06390 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;
- ASSERT_EQ(KM_ERROR_OK, device()->get_supported_block_modes(device(), KM_ALGORITHM_RSA,
+ EXPECT_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));
- ASSERT_EQ(KM_ERROR_OK, device()->get_supported_block_modes(device(), KM_ALGORITHM_AES,
+ EXPECT_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;
- ASSERT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_RSA,
+ EXPECT_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);
- ASSERT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_RSA,
+ EXPECT_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);
- ASSERT_EQ(KM_ERROR_OK, device()->get_supported_padding_modes(device(), KM_ALGORITHM_EC,
+ EXPECT_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;
- ASSERT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_RSA,
+ EXPECT_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);
- ASSERT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_EC,
+ EXPECT_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));
- ASSERT_EQ(KM_ERROR_OK, device()->get_supported_digests(device(), KM_ALGORITHM_HMAC,
+ EXPECT_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;
- ASSERT_EQ(KM_ERROR_OK,
+ EXPECT_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);
- ASSERT_EQ(KM_ERROR_OK,
+ EXPECT_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);
- ASSERT_EQ(KM_ERROR_OK,
+ EXPECT_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;
- ASSERT_EQ(KM_ERROR_OK,
+ EXPECT_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);
- ASSERT_EQ(KM_ERROR_OK,
+ EXPECT_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);
- ASSERT_EQ(KM_ERROR_OK,
+ EXPECT_EQ(KM_ERROR_OK,
device()->get_supported_export_formats(device(), KM_ALGORITHM_AES, &formats, &len));
EXPECT_EQ(0U, len);
free(formats);
- ASSERT_EQ(KM_ERROR_OK,
+ EXPECT_EQ(KM_ERROR_OK,
device()->get_supported_export_formats(device(), KM_ALGORITHM_AES, &formats, &len));
EXPECT_EQ(0U, len);
free(formats);
- ASSERT_EQ(KM_ERROR_OK,
+ EXPECT_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;
- ASSERT_EQ(KM_ERROR_OK,
+ EXPECT_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;
- ASSERT_EQ(KM_ERROR_OK,
+ EXPECT_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
new file mode 100644
index 0000000..6b9efac
--- /dev/null
+++ b/android_softkeymaster.h
@@ -0,0 +1,68 @@
+/*
+ * 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 72c24a1..1af58ca 100644
--- a/asymmetric_key.cpp
+++ b/asymmetric_key.cpp
@@ -20,36 +20,28 @@
#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 {
-keymaster_error_t
-AsymmetricKeyFactory::KeyMaterialToEvpKey(keymaster_key_format_t key_format,
- const KeymasterKeyBlob& key_material,
- UniquePtr<EVP_PKEY, EVP_PKEY_Delete>* pkey) {
+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;
if (key_format != KM_KEY_FORMAT_PKCS8)
- 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;
+ return NULL;
- uint8_t* tmp = key_blob->writable_data();
- i2d_PrivateKey(pkey, &tmp);
+ 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;
- return KM_ERROR_OK;
+ return pkey.release();
}
static const keymaster_key_format_t supported_import_formats[] = {KM_KEY_FORMAT_PKCS8};
@@ -64,28 +56,20 @@ const keymaster_key_format_t* AsymmetricKeyFactory::SupportedExportFormats(size_
return supported_export_formats;
}
-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);
+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;
- if (!asymmetric_key->EvpToInternal(pkey))
- error = TranslateLastOpenSslError();
- else
- key->reset(asymmetric_key.release());
+ 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()))
+ return TranslateLastOpenSslError();
- return error;
+ return KM_ERROR_OK;
}
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 04dac15..c638dc6 100644
--- a/asymmetric_key.h
+++ b/asymmetric_key.h
@@ -20,29 +20,14 @@
#include <openssl/evp.h>
#include "key.h"
-#include "openssl_utils.h"
namespace keymaster {
-class AsymmetricKey;
-
class AsymmetricKeyFactory : public KeyFactory {
- 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;
+ 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);
virtual const keymaster_key_format_t* SupportedImportFormats(size_t* format_count);
virtual const keymaster_key_format_t* SupportedExportFormats(size_t* format_count);
@@ -50,15 +35,27 @@ class AsymmetricKeyFactory : public KeyFactory {
class AsymmetricKey : public Key {
public:
- AsymmetricKey(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
- keymaster_error_t* error)
- : Key(hw_enforced, sw_enforced, error) {}
+ 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;
- 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;
+ /**
+ * 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;
+ 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
deleted file mode 100644
index eb9e2ca..0000000
--- a/auth_encrypted_key_blob.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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
deleted file mode 100644
index b987d77..0000000
--- a/auth_encrypted_key_blob.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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 4deb1c0..456ffb8 100644
--- a/ec_key.cpp
+++ b/ec_key.cpp
@@ -15,44 +15,43 @@
*/
#include "ec_key.h"
-
-#include <keymaster/keymaster_context.h>
-
+#include "operation.h"
#include "openssl_err.h"
#include "openssl_utils.h"
-
-#if defined(OPENSSL_IS_BORINGSSL)
-typedef size_t openssl_size_t;
-#else
-typedef int openssl_size_t;
-#endif
+#include "unencrypted_key_blob.h"
namespace keymaster {
-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;
+Key* EcKeyFactory::LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) {
+ return new EcKey(blob, error);
+}
+
+Key* EcKeyFactory::GenerateKey(const AuthorizationSet& key_description,
+ keymaster_error_t* error) {
+ if (!error)
+ return 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");
- return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ *error = 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)
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
-
+ if (ec_key.get() == NULL || pkey.get() == NULL) {
+ *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return NULL;
+ }
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);
- return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ *error = KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ return NULL;
}
#if !defined(OPENSSL_IS_BORINGSSL)
@@ -62,52 +61,47 @@ keymaster_error_t EcKeyFactory::GenerateKey(const AuthorizationSet& key_descript
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) {
- return TranslateLastOpenSslError();
+ *error = TranslateLastOpenSslError();
+ return NULL;
}
- if (EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get()) != 1)
- return TranslateLastOpenSslError();
-
- KeymasterKeyBlob key_material;
- keymaster_error_t error = EvpKeyToKeyMaterial(pkey.get(), &key_material);
- if (error != KM_ERROR_OK)
- return error;
-
- return context_->CreateKeyBlob(authorizations, KM_ORIGIN_GENERATED, key_material, key_blob,
- hw_enforced, sw_enforced);
+ EcKey* new_key = new EcKey(ec_key.release(), authorizations);
+ *error = new_key ? KM_ERROR_OK : KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return new_key;
}
-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;
+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;
- UniquePtr<EC_KEY, EcKey::EC_Delete> ec_key(EVP_PKEY_get1_EC_KEY(pkey.get()));
- if (!ec_key.get())
- return TranslateLastOpenSslError();
+ 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());
- AuthorizationSet authorizations(key_description);
+ UniquePtr<EC_KEY, EcKey::EC_Delete> ec_key(EVP_PKEY_get1_EC_KEY(pkey.get()));
+ if (!ec_key.get()) {
+ *error = TranslateLastOpenSslError();
+ return NULL;
+ }
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;
+ *error = get_group_size(*EC_KEY_get0_group(ec_key.get()), &extracted_key_size_bits);
+ if (*error != KM_ERROR_OK)
+ return NULL;
+
+ AuthorizationSet authorizations(key_description);
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)
- return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+ if (key_size_bits != extracted_key_size_bits) {
+ *error = KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+ return NULL;
+ }
} else {
// key_size_bits not specified, add it.
authorizations.push_back(TAG_KEY_SIZE, extracted_key_size_bits);
@@ -115,14 +109,18 @@ keymaster_error_t EcKeyFactory::ImportKey(const AuthorizationSet& key_descriptio
keymaster_algorithm_t algorithm;
if (authorizations.GetTagValue(TAG_ALGORITHM, &algorithm)) {
- if (algorithm != registry_key())
- return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+ if (algorithm != registry_key()) {
+ *error = KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+ return NULL;
+ }
} else {
authorizations.push_back(TAG_ALGORITHM, registry_key());
}
-
- return context_->CreateKeyBlob(authorizations, KM_ORIGIN_IMPORTED, input_key_material,
- output_key_blob, hw_enforced, sw_enforced);
+ // 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);
}
/* static */
@@ -166,14 +164,9 @@ keymaster_error_t EcKeyFactory::get_group_size(const EC_GROUP& group, size_t* ke
return KM_ERROR_OK;
}
-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;
+EcKey::EcKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) : AsymmetricKey(blob) {
+ if (error)
+ *error = LoadKey(blob);
}
bool EcKey::EvpToInternal(const EVP_PKEY* pkey) {
diff --git a/ec_key.h b/ec_key.h
index e3e15f6..1748fe0 100644
--- a/ec_key.h
+++ b/ec_key.h
@@ -25,20 +25,11 @@ namespace keymaster {
class EcKeyFactory : public AsymmetricKeyFactory {
public:
- 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;
+ 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;
private:
static EC_GROUP* choose_group(size_t key_size_bits);
@@ -51,22 +42,23 @@ class EcKeyFactory : public AsymmetricKeyFactory {
class EcdsaKeyFactory : public EcKeyFactory {
public:
- 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; }
+ virtual keymaster_algorithm_t registry_key() const { return KM_ALGORITHM_EC; }
};
class EcdsaOperationFactory;
class EcKey : public AsymmetricKey {
- public:
- EcKey(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
- keymaster_error_t* error)
- : AsymmetricKey(hw_enforced, sw_enforced, error) {}
+ 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) {}
- bool InternalToEvp(EVP_PKEY* pkey) const override;
- bool EvpToInternal(const EVP_PKEY* pkey) override;
+ virtual int evp_key_type() { return EVP_PKEY_EC; }
+ virtual bool InternalToEvp(EVP_PKEY* pkey) const;
+ virtual bool EvpToInternal(const EVP_PKEY* pkey);
struct EC_Delete {
void operator()(EC_KEY* p) { EC_KEY_free(p); }
diff --git a/ecdsa_operation.h b/ecdsa_operation.h
index dd5a61f..85a54d3 100644
--- a/ecdsa_operation.h
+++ b/ecdsa_operation.h
@@ -21,6 +21,8 @@
#include <UniquePtr.h>
+#include <keymaster/key_blob.h>
+
#include "operation.h"
namespace keymaster {
diff --git a/hmac_key.cpp b/hmac_key.cpp
index 1f2e4a4..294832d 100644
--- a/hmac_key.cpp
+++ b/hmac_key.cpp
@@ -23,18 +23,12 @@
namespace keymaster {
-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;
+Key* HmacKeyFactory::LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) {
+ return new HmacKey(blob, error);
+}
- 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;
+SymmetricKey* HmacKeyFactory::CreateKey(const AuthorizationSet& auths) {
+ return new HmacKey(auths);
}
} // namespace keymaster
diff --git a/hmac_key.h b/hmac_key.h
index c5a7b91..065effc 100644
--- a/hmac_key.h
+++ b/hmac_key.h
@@ -23,26 +23,21 @@ namespace keymaster {
class HmacKeyFactory : public SymmetricKeyFactory {
public:
- HmacKeyFactory(const KeymasterContext* context) : SymmetricKeyFactory(context) {}
-
keymaster_algorithm_t registry_key() const override { return KM_ALGORITHM_HMAC; }
- 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 */;
- }
+ Key* LoadKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error) override;
+ SymmetricKey* CreateKey(const AuthorizationSet& auths) override;
};
class HmacKey : public SymmetricKey {
+ static const size_t MAX_HMAC_KEY_SIZE = 256; /* Arbitrary limit, for DoS prevention */
+
public:
- 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) {}
+ 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; }
};
} // namespace keymaster
diff --git a/include/keymaster/android_keymaster.h b/include/keymaster/android_keymaster.h
index c7a3f41..7f8e65f 100644
--- a/include/keymaster/android_keymaster.h
+++ b/include/keymaster/android_keymaster.h
@@ -23,7 +23,7 @@
namespace keymaster {
class Key;
-class KeymasterContext;
+class UnencryptedKeyBlob;
class OperationTable;
/**
@@ -46,7 +46,7 @@ class OperationTable;
*/
class AndroidKeymaster {
public:
- AndroidKeymaster(KeymasterContext* context, size_t operation_table_size);
+ AndroidKeymaster(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;
- keymaster_error_t AddRngEntropy(const AddEntropyRequest& request);
+ virtual keymaster_error_t AddRngEntropy(const AddEntropyRequest& request) = 0;
void GenerateKey(const GenerateKeyRequest& request, GenerateKeyResponse* response);
void GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
GetKeyCharacteristicsResponse* response);
@@ -74,12 +74,30 @@ class AndroidKeymaster {
void GetVersion(const GetVersionRequest& request, GetVersionResponse* response);
private:
- 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);
+ 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);
- UniquePtr<KeymasterContext> context_;
UniquePtr<OperationTable> operation_table_;
};
diff --git a/include/keymaster/android_keymaster_utils.h b/include/keymaster/android_keymaster_utils.h
index c636f5c..20afcdd 100644
--- a/include/keymaster/android_keymaster_utils.h
+++ b/include/keymaster/android_keymaster_utils.h
@@ -23,7 +23,6 @@
#include <UniquePtr.h>
-#include <hardware/keymaster_defs.h>
#include <keymaster/serializable.h>
namespace keymaster {
@@ -50,14 +49,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;
}
@@ -78,7 +77,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);
}
@@ -91,7 +90,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];
}
@@ -101,7 +100,7 @@ template <typename T, size_t N> inline void copy_array(const T(&arr)[N], T* dest
* 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;
@@ -145,9 +144,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_); }
@@ -207,85 +206,6 @@ 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
new file mode 100644
index 0000000..b2a3778
--- /dev/null
+++ b/include/keymaster/key_blob.h
@@ -0,0 +1,130 @@
+/*
+ * 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
deleted file mode 100644
index 68410f8..0000000
--- a/include/keymaster/keymaster_context.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * 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 e996fd8..b183367 100644
--- a/include/keymaster/serializable.h
+++ b/include/keymaster/serializable.h
@@ -194,9 +194,6 @@ 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 44e64e9..58dd2d9 100644
--- a/include/keymaster/soft_keymaster_device.h
+++ b/include/keymaster/soft_keymaster_device.h
@@ -51,8 +51,7 @@ class SoftKeymasterDevice {
}
private:
- static keymaster_error_t ExtractSigningParams(const keymaster1_device_t* dev,
- const void* signing_params,
+ static keymaster_error_t ExtractSigningParams(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 776ca1b..ffc2b83 100644
--- a/key.cpp
+++ b/key.cpp
@@ -19,19 +19,16 @@
#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 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;
+Key::Key(const KeyBlob& blob) {
+ authorizations_.push_back(blob.unenforced());
+ authorizations_.push_back(blob.enforced());
}
+
} // namespace keymaster
diff --git a/key.h b/key.h
index 0eb1539..f7d2a1c 100644
--- a/key.h
+++ b/key.h
@@ -22,19 +22,18 @@
#include <keymaster/logger.h>
#include "abstract_factory_registry.h"
+#include "unencrypted_key_blob.h"
namespace keymaster {
class Key;
-class KeymasterContext;
/**
- * KeyFactory is a abstraction whose subclasses know how to construct a specific subclass of Key.
+ * KeyFactory is a pure interface 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
@@ -42,27 +41,15 @@ class KeyFactory {
virtual keymaster_algorithm_t registry_key() const = 0;
// Factory methods.
- 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;
+ 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;
// 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;
@@ -90,8 +77,8 @@ class Key {
const AuthorizationSet& authorizations() const { return authorizations_; }
protected:
- Key(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
- keymaster_error_t* error);
+ Key(const KeyBlob& blob);
+ Key(const AuthorizationSet& authorizations) : authorizations_(authorizations) {}
private:
AuthorizationSet authorizations_;
diff --git a/key_blob.cpp b/key_blob.cpp
new file mode 100644
index 0000000..4dfdc60
--- /dev/null
+++ b/key_blob.cpp
@@ -0,0 +1,167 @@
+/*
+ * 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 0c60ad2..fc4d8cd 100644
--- a/key_blob_test.cpp
+++ b/key_blob_test.cpp
@@ -25,9 +25,7 @@
#include <keymaster/android_keymaster_utils.h>
#include <keymaster/keymaster_tags.h>
-#include "android_keymaster_test_utils.h"
-#include "auth_encrypted_key_blob.h"
-#include "ocb_utils.h"
+#include "unencrypted_key_blob.h"
namespace keymaster {
@@ -38,254 +36,277 @@ const uint8_t key_data[5] = {21, 22, 23, 24, 25};
class KeyBlobTest : public testing::Test {
protected:
- 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);
+ 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);
hidden_.push_back(TAG_ROOT_OF_TRUST, "foo", 3);
hidden_.push_back(TAG_APPLICATION_ID, "my_app", 6);
- nonce_.reserve(OCB_NONCE_LENGTH);
- EXPECT_EQ(1, RAND_bytes(nonce_.peek_write(), OCB_NONCE_LENGTH));
- nonce_.advance_write(OCB_NONCE_LENGTH);
+ EXPECT_EQ(1, RAND_bytes(nonce_, array_size(nonce_)));
- tag_.reserve(OCB_TAG_LENGTH);
+ blob_.reset(new UnencryptedKeyBlob(enforced_, unenforced_, hidden_, key_data,
+ array_size(key_data), master_key_data,
+ array_size(master_key_data), nonce_));
}
- 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 enforced_;
+ AuthorizationSet unenforced_;
AuthorizationSet hidden_;
- Buffer nonce_, tag_;
- KeymasterKeyBlob master_key_;
- KeymasterKeyBlob key_material_;
- KeymasterKeyBlob ciphertext_;
- KeymasterKeyBlob decrypted_plaintext_;
- KeymasterKeyBlob serialized_blob_;
+ UniquePtr<UnencryptedKeyBlob> blob_;
+ uint8_t nonce_[KeyBlob::NONCE_LENGTH];
};
TEST_F(KeyBlobTest, EncryptDecrypt) {
- 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));
+ 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)));
}
TEST_F(KeyBlobTest, WrongKeyLength) {
- 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());
+ 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());
}
TEST_F(KeyBlobTest, WrongNonce) {
- ASSERT_EQ(KM_ERROR_OK, Encrypt());
- ASSERT_EQ(KM_ERROR_OK, Serialize());
+ size_t size = blob_->SerializedSize();
+ UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
+ blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
// Find the nonce, then modify it.
- 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());
+ 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)));
}
TEST_F(KeyBlobTest, WrongTag) {
- ASSERT_EQ(KM_ERROR_OK, Encrypt());
- ASSERT_EQ(KM_ERROR_OK, Serialize());
+ size_t size = blob_->SerializedSize();
+ UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
+ blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
// Find the tag, them modify it.
+ uint8_t* begin = serialized_blob.get();
+ uint8_t* end = begin + size;
auto tag_ptr =
- 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());
+ 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)));
}
TEST_F(KeyBlobTest, WrongCiphertext) {
- ASSERT_EQ(KM_ERROR_OK, Encrypt());
- ASSERT_EQ(KM_ERROR_OK, Serialize());
+ size_t size = blob_->SerializedSize();
+ UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
+ blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
// Find the ciphertext, them modify it.
- 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());
+ 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)));
}
TEST_F(KeyBlobTest, WrongMasterKey) {
- ASSERT_EQ(KM_ERROR_OK, Encrypt());
- ASSERT_EQ(KM_ERROR_OK, Serialize());
+ 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 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.
- 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_));
+ 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)));
}
-TEST_F(KeyBlobTest, WrongHwEnforced) {
- ASSERT_EQ(KM_ERROR_OK, Encrypt());
- ASSERT_EQ(KM_ERROR_OK, Serialize());
+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;
// Find enforced serialization data and modify it.
- 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());
+ 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());
}
-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, 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, EmptyHidden) {
- ASSERT_EQ(KM_ERROR_OK, Encrypt());
- ASSERT_EQ(KM_ERROR_OK, Serialize());
+ size_t size = blob_->SerializedSize();
+ UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
+ blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
AuthorizationSet wrong_hidden;
- // 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_));
+ // 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, WrongRootOfTrust) {
- ASSERT_EQ(KM_ERROR_OK, Encrypt());
- ASSERT_EQ(KM_ERROR_OK, Serialize());
+ size_t size = blob_->SerializedSize();
+ UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
+ blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
AuthorizationSet wrong_hidden;
- wrong_hidden.push_back(TAG_ROOT_OF_TRUST, "bar", 2);
+ wrong_hidden.push_back(TAG_ROOT_OF_TRUST, "bar", 3);
wrong_hidden.push_back(TAG_APPLICATION_ID, "my_app", 6);
- // 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_));
+ // 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, WrongAppId) {
- ASSERT_EQ(KM_ERROR_OK, Encrypt());
- ASSERT_EQ(KM_ERROR_OK, Serialize());
+ size_t size = blob_->SerializedSize();
+ UniquePtr<uint8_t[]> serialized_blob(new uint8_t[size]);
+ blob_->Serialize(serialized_blob.get(), serialized_blob.get() + size);
AuthorizationSet wrong_hidden;
wrong_hidden.push_back(TAG_ROOT_OF_TRUST, "foo", 3);
wrong_hidden.push_back(TAG_APPLICATION_ID, "your_app", 7);
- // 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_));
+ // 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());
}
} // namespace test
diff --git a/ocb_utils.cpp b/ocb_utils.cpp
deleted file mode 100644
index 171d07e..0000000
--- a/ocb_utils.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * 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 bae1e08..2104742 100644
--- a/ocb_utils.h
+++ b/ocb_utils.h
@@ -19,29 +19,21 @@
#include "ae.h"
-#include <hardware/keymaster_defs.h>
-
-#include <keymaster/serializable.h>
-
namespace keymaster {
-class AuthorizationSet;
-struct KeymasterKeyBlob;
-
-static const int OCB_NONCE_LENGTH = 12;
-static const int OCB_TAG_LENGTH = 16;
+class AeCtx {
+ public:
+ AeCtx() : ctx_(ae_allocate(NULL)) {}
+ ~AeCtx() {
+ ae_clear(ctx_);
+ ae_free(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);
+ ae_ctx* get() { return 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);
+ private:
+ ae_ctx* ctx_;
+};
} // namespace keymaster
diff --git a/rsa_key.cpp b/rsa_key.cpp
index 293d51e..5150588 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,67 +29,66 @@ typedef int openssl_size_t;
namespace keymaster {
-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;
+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;
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");
- return KM_ERROR_INVALID_ARGUMENT;
+ *error = KM_ERROR_INVALID_ARGUMENT;
+ return NULL;
}
uint32_t key_size;
if (!authorizations.GetTagValue(TAG_KEY_SIZE, &key_size)) {
LOG_E("%s", "No key size specified for RSA key generation");
- return KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ *error = KM_ERROR_UNSUPPORTED_KEY_SIZE;
+ return NULL;
}
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)
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ if (exponent.get() == NULL || rsa_key.get() == NULL || pkey.get() == NULL) {
+ *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return NULL;
+ }
if (!BN_set_word(exponent.get(), public_exponent) ||
- !RSA_generate_key_ex(rsa_key.get(), key_size, exponent.get(), NULL /* callback */))
- return TranslateLastOpenSslError();
-
- if (EVP_PKEY_set1_RSA(pkey.get(), rsa_key.get()) != 1)
- return TranslateLastOpenSslError();
-
- KeymasterKeyBlob key_material;
- keymaster_error_t error = EvpKeyToKeyMaterial(pkey.get(), &key_material);
- if (error != KM_ERROR_OK)
- return error;
+ !RSA_generate_key_ex(rsa_key.get(), key_size, exponent.get(), NULL /* callback */)) {
+ *error = TranslateLastOpenSslError();
+ return NULL;
+ }
- return context_->CreateKeyBlob(authorizations, KM_ORIGIN_GENERATED, key_material, key_blob,
- hw_enforced, sw_enforced);
+ RsaKey* new_key = new RsaKey(rsa_key.release(), authorizations);
+ *error = new_key ? KM_ERROR_OK : KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ return new_key;
}
-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;
+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;
+
+ 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());
UniquePtr<RSA, RsaKey::RSA_Delete> rsa_key(EVP_PKEY_get1_RSA(pkey.get()));
- if (!rsa_key.get())
- return TranslateLastOpenSslError();
+ if (!rsa_key.get()) {
+ *error = TranslateLastOpenSslError();
+ return NULL;
+ }
AuthorizationSet authorizations(key_description);
@@ -98,22 +97,28 @@ keymaster_error_t RsaKeyFactory::ImportKey(const AuthorizationSet& key_descripti
// 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 KM_ERROR_UNKNOWN_ERROR;
- if (BN_cmp(public_exponent_bn.get(), rsa_key->e) != 0)
- return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+ return NULL;
+ if (BN_cmp(public_exponent_bn.get(), rsa_key->e) != 0) {
+ *error = KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+ return NULL;
+ }
} else {
// public_exponent not specified, use the one from the key.
public_exponent = BN_get_word(rsa_key->e);
- if (public_exponent == 0xffffffffL)
- return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+ if (public_exponent == 0xffffffffL) {
+ *error = KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+ return NULL;
+ }
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)
- return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+ if (RSA_size(rsa_key.get()) * 8 != (openssl_size_t)key_size) {
+ *error = KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+ return NULL;
+ }
} else {
key_size = RSA_size(rsa_key.get()) * 8;
authorizations.push_back(TAG_KEY_SIZE, key_size);
@@ -121,24 +126,28 @@ keymaster_error_t RsaKeyFactory::ImportKey(const AuthorizationSet& key_descripti
keymaster_algorithm_t algorithm;
if (authorizations.GetTagValue(TAG_ALGORITHM, &algorithm)) {
- if (algorithm != KM_ALGORITHM_RSA)
- return KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+ if (algorithm != KM_ALGORITHM_RSA) {
+ *error = KM_ERROR_IMPORT_PARAMETER_MISMATCH;
+ return NULL;
+ }
} else {
authorizations.push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
}
- return context_->CreateKeyBlob(authorizations, KM_ORIGIN_IMPORTED, input_key_material,
- output_key_blob, hw_enforced, sw_enforced);
+ // 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);
}
-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;
+RSA* RsaKey::key() const {
+ return rsa_key_.get();
}
bool RsaKey::EvpToInternal(const EVP_PKEY* pkey) {
diff --git a/rsa_key.h b/rsa_key.h
index e5b4051..129f774 100644
--- a/rsa_key.h
+++ b/rsa_key.h
@@ -25,33 +25,25 @@ namespace keymaster {
class RsaKeyFactory : public AsymmetricKeyFactory {
public:
- RsaKeyFactory(const KeymasterContext* context) : AsymmetricKeyFactory(context) {}
-
keymaster_algorithm_t registry_key() const override { return KM_ALGORITHM_RSA; }
- 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;
+ 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;
};
class RsaOperationFactory;
class RsaKey : public AsymmetricKey {
- public:
- RsaKey(const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
- keymaster_error_t* error)
- : AsymmetricKey(hw_enforced, sw_enforced, error) {}
+ 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) {}
+ int evp_key_type() override { return EVP_PKEY_RSA; }
bool InternalToEvp(EVP_PKEY* pkey) const override;
bool EvpToInternal(const EVP_PKEY* pkey) override;
@@ -62,10 +54,9 @@ class RsaKey : public AsymmetricKey {
void operator()(RSA* p) { RSA_free(p); }
};
- RSA* key() const { return rsa_key_.get(); }
+ RSA* key() const;
- private:
- UniquePtr<RSA, RSA_Delete> rsa_key_;
+ mutable UniquePtr<RSA, RSA_Delete> rsa_key_;
};
} // namespace keymaster
diff --git a/rsa_operation.h b/rsa_operation.h
index 586aaa1..ea8d81d 100644
--- a/rsa_operation.h
+++ b/rsa_operation.h
@@ -22,6 +22,8 @@
#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
deleted file mode 100644
index 485d3cd..0000000
--- a/soft_keymaster_context.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 1dba59d..0000000
--- a/soft_keymaster_context.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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 9b2fdb4..18ac3e6 100644
--- a/soft_keymaster_device.cpp
+++ b/soft_keymaster_device.cpp
@@ -33,13 +33,16 @@
#define LOG_TAG "SoftKeymasterDevice"
#include <cutils/log.h>
-#include <keymaster/android_keymaster.h>
-#include <keymaster/android_keymaster_messages.h>
#include <keymaster/authorization_set.h>
+#include <keymaster/android_keymaster_messages.h>
+#include <keymaster/key_blob.h>
#include <keymaster/soft_keymaster_logger.h>
-#include "soft_keymaster_context.h"
-#include "openssl_utils.h"
+#include "aes_key.h"
+#include "ec_key.h"
+#include "android_softkeymaster.h"
+#include "hmac_key.h"
+#include "rsa_key.h"
struct keystore_module soft_keymaster_device_module = {
.common =
@@ -58,8 +61,12 @@ struct keystore_module soft_keymaster_device_module = {
namespace keymaster {
-SoftKeymasterDevice::SoftKeymasterDevice()
- : impl_(new AndroidKeymaster(new SoftKeymasterContext, 16)) {
+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)) {
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
static_assert(std::is_standard_layout<SoftKeymasterDevice>::value,
"SoftKeymasterDevice must be standard layout");
@@ -258,6 +265,14 @@ 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) {
@@ -345,8 +360,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(dev, params, key_blob, key_blob_length,
- &begin_request.additional_params);
+ keymaster_error_t err =
+ ExtractSigningParams(params, key_blob, key_blob_length, &begin_request.additional_params);
if (err != KM_ERROR_OK)
return err;
@@ -398,10 +413,12 @@ 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(dev, params, key_blob, key_blob_length,
- &begin_request.additional_params);
- if (err != KM_ERROR_OK)
- return err;
+ {
+ keymaster_error_t err = ExtractSigningParams(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);
@@ -842,28 +859,15 @@ keymaster_error_t SoftKeymasterDevice::abort(const keymaster1_device_t* dev,
}
/* static */
-keymaster_error_t SoftKeymasterDevice::ExtractSigningParams(const keymaster1_device_t* dev,
- const void* signing_params,
+keymaster_error_t SoftKeymasterDevice::ExtractSigningParams(const void* signing_params,
const uint8_t* key_blob,
size_t key_blob_length,
AuthorizationSet* auth_set) {
- 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;
+ KeyBlob blob(key_blob, key_blob_length);
+ if (blob.error() != KM_ERROR_OK)
+ return blob.error();
- switch (algorithm) {
+ switch (blob.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 68fa6f1..e1ce39f 100644
--- a/symmetric_key.cpp
+++ b/symmetric_key.cpp
@@ -22,73 +22,53 @@
#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 {
-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;
+Key* SymmetricKeyFactory::GenerateKey(const AuthorizationSet& key_description,
+ keymaster_error_t* error) {
+ UniquePtr<SymmetricKey> key(CreateKeyAndValidateSize(key_description, error));
+ if (!key.get())
+ 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 (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;
}
- return context_->CreateKeyBlob(key_description, KM_ORIGIN_GENERATED, key_material, key_blob,
- hw_enforced, sw_enforced);
+ if (*error != KM_ERROR_OK)
+ return NULL;
+ return key.release();
}
-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);
+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;
- 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 (format != KM_KEY_FORMAT_RAW) {
+ *error = KM_ERROR_UNSUPPORTED_KEY_FORMAT;
+ 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;
+ 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;
}
- return context_->CreateKeyBlob(authorizations, KM_ORIGIN_IMPORTED, input_key_material,
- output_key_blob, hw_enforced, sw_enforced);
+ key->key_data_size_ = key_material_length;
+ memcpy(key->key_data_.get(), key_material, key_material_length);
+ return key.release();
}
static const keymaster_key_format_t supported_import_formats[] = {KM_KEY_FORMAT_RAW};
@@ -97,21 +77,40 @@ const keymaster_key_format_t* SymmetricKeyFactory::SupportedImportFormats(size_t
return supported_import_formats;
}
-SymmetricKey::SymmetricKey(const KeymasterKeyBlob& key_material,
- const AuthorizationSet& hw_enforced, const AuthorizationSet& sw_enforced,
- keymaster_error_t* error)
- : Key(hw_enforced, sw_enforced, error) {
+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);
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;
+ }
- 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;
+ memcpy(key_data_.get(), blob.unencrypted_key_material(), key_data_size_);
+ if (error)
*error = KM_ERROR_OK;
- } else {
- *error = KM_ERROR_MEMORY_ALLOCATION_FAILED;
- }
}
SymmetricKey::~SymmetricKey() {
@@ -128,4 +127,16 @@ 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 3e39364..7662a4a 100644
--- a/symmetric_key.h
+++ b/symmetric_key.h
@@ -24,17 +24,9 @@ namespace keymaster {
class SymmetricKey;
class SymmetricKeyFactory : public KeyFactory {
- 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;
+ 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;
virtual const keymaster_key_format_t* SupportedImportFormats(size_t* format_count);
virtual const keymaster_key_format_t* SupportedExportFormats(size_t* format_count) {
@@ -42,8 +34,10 @@ class SymmetricKeyFactory : public KeyFactory {
};
private:
- virtual bool key_size_supported(size_t key_size_bits) const = 0;
+ SymmetricKey* CreateKeyAndValidateSize(const AuthorizationSet& key_description,
+ keymaster_error_t* error);
+ virtual SymmetricKey* CreateKey(const AuthorizationSet& auths) = 0;
const keymaster_key_format_t* NoFormats(size_t* format_count) {
*format_count = 0;
return NULL;
@@ -52,6 +46,10 @@ 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;
@@ -64,12 +62,16 @@ class SymmetricKey : public Key {
size_t key_data_size() const { return key_data_size_; }
protected:
- SymmetricKey(const KeymasterKeyBlob& key_material, const AuthorizationSet& hw_enforced,
- const AuthorizationSet& sw_enforced, keymaster_error_t* error);
+ SymmetricKey(const UnencryptedKeyBlob& blob, keymaster_error_t* error);
+ SymmetricKey(const AuthorizationSet& auths) : Key(auths) {}
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
new file mode 100644
index 0000000..43a7c25
--- /dev/null
+++ b/unencrypted_key_blob.cpp
@@ -0,0 +1,191 @@
+/*
+ * 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
new file mode 100644
index 0000000..e559527
--- /dev/null
+++ b/unencrypted_key_blob.h
@@ -0,0 +1,82 @@
+/*
+ * 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 2b51c4b..2ca244c 100644
--- a/valgrind.supp
+++ b/valgrind.supp
@@ -22,18 +22,4 @@
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