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