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