diff options
| author | Shawn Willden <swillden@google.com> | 2016-03-09 20:03:38 -0700 |
|---|---|---|
| committer | Shawn Willden <swillden@google.com> | 2016-03-29 18:08:38 -0600 |
| commit | c15af1910d8f451341d0068b5533816ace5defec (patch) | |
| tree | a99c6cb8bca8659b34871c02693001c8efdc8f3e | |
| parent | 3609584c328ea66f95478dded394ad4697779450 (diff) | |
| download | android_system_keymaster-c15af1910d8f451341d0068b5533816ace5defec.tar.gz android_system_keymaster-c15af1910d8f451341d0068b5533816ace5defec.tar.bz2 android_system_keymaster-c15af1910d8f451341d0068b5533816ace5defec.zip | |
Implement key version binding.
Change-Id: If0f3bc12380b8b65bf1e60d5d8d039eb972c8a15
| -rw-r--r-- | Android.mk | 5 | ||||
| -rw-r--r-- | Makefile | 18 | ||||
| -rw-r--r-- | android_keymaster.cpp | 41 | ||||
| -rw-r--r-- | android_keymaster_messages.cpp | 38 | ||||
| -rw-r--r-- | android_keymaster_messages_test.cpp | 30 | ||||
| -rw-r--r-- | android_keymaster_test.cpp | 197 | ||||
| -rw-r--r-- | android_keymaster_test_utils.cpp | 11 | ||||
| -rw-r--r-- | android_keymaster_test_utils.h | 6 | ||||
| -rw-r--r-- | attestation_record.cpp | 2 | ||||
| -rw-r--r-- | attestation_record_test.cpp | 14 | ||||
| -rw-r--r-- | authorization_set.cpp | 14 | ||||
| -rw-r--r-- | include/keymaster/android_keymaster.h | 1 | ||||
| -rw-r--r-- | include/keymaster/android_keymaster_messages.h | 33 | ||||
| -rw-r--r-- | include/keymaster/authorization_set.h | 2 | ||||
| -rw-r--r-- | include/keymaster/keymaster_configuration.h | 51 | ||||
| -rw-r--r-- | include/keymaster/keymaster_context.h | 25 | ||||
| -rw-r--r-- | include/keymaster/soft_keymaster_context.h | 12 | ||||
| -rw-r--r-- | include/keymaster/soft_keymaster_device.h | 9 | ||||
| -rw-r--r-- | keymaster_configuration.cpp | 127 | ||||
| -rw-r--r-- | keymaster_configuration_test.cpp | 68 | ||||
| -rw-r--r-- | soft_keymaster_context.cpp | 98 | ||||
| -rw-r--r-- | soft_keymaster_device.cpp | 144 |
22 files changed, 906 insertions, 40 deletions
@@ -90,7 +90,7 @@ LOCAL_CLANG_CFLAGS += -Wno-error=unused-const-variable -Wno-error=unused-private # TODO(krasin): reenable coverage flags, when the new Clang toolchain is released. # Currently, if enabled, these flags will cause an internal error in Clang. LOCAL_CLANG_CFLAGS += -fno-sanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp -# Ignore benigh warnings for now. +# Ignore benign warnings for now. LOCAL_CLANG_CFLAGS += -Wno-error=unused-private-field LOCAL_MODULE_TAGS := optional LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include @@ -111,6 +111,7 @@ LOCAL_SRC_FILES := \ ecdsa_keymaster1_operation.cpp \ keymaster0_engine.cpp \ keymaster1_engine.cpp \ + keymaster_configuration.cpp \ rsa_keymaster0_key.cpp \ rsa_keymaster1_key.cpp \ rsa_keymaster1_operation.cpp \ @@ -126,7 +127,7 @@ LOCAL_CLANG_CFLAGS += -Wno-error=unused-const-variable -Wno-error=unused-private # TODO(krasin): reenable coverage flags, when the new Clang toolchain is released. # Currently, if enabled, these flags will cause an internal error in Clang. LOCAL_CLANG_CFLAGS += -fno-sanitize-coverage=edge,indirect-calls,8bit-counters,trace-cmp -LOCAL_SHARED_LIBRARIES := libkeymaster_messages libkeymaster1 liblog libcrypto +LOCAL_SHARED_LIBRARIES := libkeymaster_messages libkeymaster1 liblog libcrypto libcutils LOCAL_MODULE_TAGS := optional LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include @@ -49,11 +49,11 @@ CFLAGS += -fprofile-arcs -ftest-coverage endif LDFLAGS += $(ARCH_FLAGS) -CPPFLAGS = $(INCLUDES) -g -O0 -MD -MP +CPPFLAGS = $(INCLUDES) -g -O0 -MD -MP $(ARCH_FLAGS) -DKEYMASTER_UNIT_TEST_BUILD -DHOST_BUILD CXXFLAGS += -Wall -Werror -Wno-unused -Winit-self -Wpointer-arith -Wunused-parameter \ -Werror=sign-compare -Werror=return-type -fno-permissive \ -Wno-deprecated-declarations -fno-exceptions -DKEYMASTER_NAME_TAGS $(ARCH_FLAGS) -CFLAGS += $(ARCH_FLAGS) +CFLAGS += $(ARCH_FLAGS) -DKEYMASTER_UNIT_TEST_BUILD -DHOST_BUILD # Uncomment to enable debug logging. # CXXFLAGS += -DDEBUG @@ -94,13 +94,15 @@ CPPSRCS=\ integrity_assured_key_blob.cpp \ iso18033kdf.cpp \ kdf.cpp \ - kdf_test.cpp \ kdf1_test.cpp \ kdf2_test.cpp \ + kdf_test.cpp \ key.cpp \ key_blob_test.cpp \ keymaster0_engine.cpp \ keymaster1_engine.cpp \ + keymaster_configuration.cpp \ + keymaster_configuration_test.cpp \ keymaster_enforcement.cpp \ keymaster_enforcement_test.cpp \ keymaster_tags.cpp \ @@ -137,10 +139,11 @@ BINARIES = \ ecies_kem_test \ hkdf_test \ hmac_test \ - kdf_test \ kdf1_test \ kdf2_test \ + kdf_test \ key_blob_test \ + keymaster_configuration_test \ keymaster_enforcement_test \ nist_curve_key_exchange_test @@ -191,6 +194,13 @@ massif: $(BINARIES:=.massif) GTEST_OBJS = $(GTEST)/src/gtest-all.o gtest_main.o +keymaster_configuration_test: keymaster_configuration_test.o \ + authorization_set.o \ + serializable.o \ + logger.o \ + keymaster_configuration.o \ + $(GTEST_OBJS) + hmac_test: hmac_test.o \ android_keymaster_test_utils.o \ android_keymaster_utils.o \ diff --git a/android_keymaster.cpp b/android_keymaster.cpp index 3a53394..aeb4f4d 100644 --- a/android_keymaster.cpp +++ b/android_keymaster.cpp @@ -38,10 +38,33 @@ namespace keymaster { +namespace { + const uint8_t MAJOR_VER = 1; const uint8_t MINOR_VER = 1; const uint8_t SUBMINOR_VER = 0; +keymaster_error_t CheckVersionInfo(const AuthorizationSet& tee_enforced, + const AuthorizationSet& sw_enforced, + const KeymasterContext& context) { + uint32_t os_version; + uint32_t os_patchlevel; + context.GetSystemVersion(&os_version, &os_patchlevel); + + uint32_t key_os_patchlevel; + if (tee_enforced.GetTagValue(TAG_OS_PATCHLEVEL, &key_os_patchlevel) || + sw_enforced.GetTagValue(TAG_OS_PATCHLEVEL, &key_os_patchlevel)) { + if (key_os_patchlevel < os_patchlevel) + return KM_ERROR_KEY_REQUIRES_UPGRADE; + else if (key_os_patchlevel > os_patchlevel) + return KM_ERROR_INVALID_KEY_BLOB; + } + + return KM_ERROR_OK; +} + +} // anonymous namespace + AndroidKeymaster::AndroidKeymaster(KeymasterContext* context, size_t operation_table_size) : context_(context), operation_table_(new OperationTable(operation_table_size)) {} @@ -193,6 +216,8 @@ void AndroidKeymaster::GetKeyCharacteristics(const GetKeyCharacteristicsRequest& &key_material, &response->enforced, &response->unenforced); if (response->error != KM_ERROR_OK) return; + + response->error = CheckVersionInfo(response->enforced, response->unenforced, *context_); } static KeyFactory* GetKeyFactory(const KeymasterContext& context, @@ -381,6 +406,18 @@ void AndroidKeymaster::AttestKey(const AttestKeyRequest& request, AttestKeyRespo sw_enforced, &response->certificate_chain); } +void AndroidKeymaster::UpgradeKey(const UpgradeKeyRequest& request, UpgradeKeyResponse* response) { + if (!response) + return; + + KeymasterKeyBlob upgraded_key; + response->error = context_->UpgradeKeyBlob(KeymasterKeyBlob(request.key_blob), + request.upgrade_params, &upgraded_key); + if (response->error != KM_ERROR_OK) + return; + response->upgraded_key = upgraded_key.release(); +} + void AndroidKeymaster::ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response) { if (response == NULL) return; @@ -429,6 +466,10 @@ keymaster_error_t AndroidKeymaster::LoadKey(const keymaster_key_blob_t& key_blob if (error != KM_ERROR_OK) return error; + error = CheckVersionInfo(*hw_enforced, *sw_enforced, *context_); + if (error != KM_ERROR_OK) + return error; + keymaster_algorithm_t algorithm; *factory = GetKeyFactory(*context_, *hw_enforced, *sw_enforced, &algorithm, &error); if (error != KM_ERROR_OK) diff --git a/android_keymaster_messages.cpp b/android_keymaster_messages.cpp index 1b8f36e..83a1785 100644 --- a/android_keymaster_messages.cpp +++ b/android_keymaster_messages.cpp @@ -523,4 +523,42 @@ bool AttestKeyResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8 return true; } +UpgradeKeyRequest::~UpgradeKeyRequest() { + delete[] key_blob.key_material; +} + +void UpgradeKeyRequest::SetKeyMaterial(const void* key_material, size_t length) { + set_key_blob(&key_blob, key_material, length); +} + +size_t UpgradeKeyRequest::SerializedSize() const { + return key_blob_size(key_blob) + upgrade_params.SerializedSize(); +} + +uint8_t* UpgradeKeyRequest::Serialize(uint8_t* buf, const uint8_t* end) const { + buf = serialize_key_blob(key_blob, buf, end); + return upgrade_params.Serialize(buf, end); +} + +bool UpgradeKeyRequest::Deserialize(const uint8_t** buf_ptr, const uint8_t* end) { + return deserialize_key_blob(&key_blob, buf_ptr, end) && + upgrade_params.Deserialize(buf_ptr, end); +} + +UpgradeKeyResponse::~UpgradeKeyResponse() { + delete[] upgraded_key.key_material; +} + +size_t UpgradeKeyResponse::NonErrorSerializedSize() const { + return key_blob_size(upgraded_key); +} + +uint8_t* UpgradeKeyResponse::NonErrorSerialize(uint8_t* buf, const uint8_t* end) const { + return serialize_key_blob(upgraded_key, buf, end); +} + +bool UpgradeKeyResponse::NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) { + return deserialize_key_blob(&upgraded_key, buf_ptr, end); +} + } // namespace keymaster diff --git a/android_keymaster_messages_test.cpp b/android_keymaster_messages_test.cpp index e6b70fa..28c06d2 100644 --- a/android_keymaster_messages_test.cpp +++ b/android_keymaster_messages_test.cpp @@ -578,6 +578,34 @@ TEST(RoundTrip, AttestKeyResponse) { } } +TEST(RoundTrip, UpgradeKeyRequest) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + UpgradeKeyRequest msg(ver); + msg.SetKeyMaterial("foo", 3); + msg.upgrade_params.Reinitialize(params, array_length(params)); + + UniquePtr<UpgradeKeyRequest> deserialized(round_trip(ver, msg, 85)); + EXPECT_EQ(3U, deserialized->key_blob.key_material_size); + EXPECT_EQ(0, memcmp("foo", deserialized->key_blob.key_material, 3)); + EXPECT_EQ(msg.upgrade_params, deserialized->upgrade_params); + } +} + +TEST(RoundTrip, UpgradeKeyResponse) { + for (int ver = 0; ver <= MAX_MESSAGE_VERSION; ++ver) { + UpgradeKeyResponse req(ver); + req.error = KM_ERROR_OK; + req.upgraded_key.key_material = dup_array(TEST_DATA); + req.upgraded_key.key_material_size = array_length(TEST_DATA); + + UniquePtr<UpgradeKeyResponse> deserialized(round_trip(ver, req, 19)); + EXPECT_EQ(KM_ERROR_OK, deserialized->error); + EXPECT_EQ(req.upgraded_key.key_material_size, deserialized->upgraded_key.key_material_size); + EXPECT_EQ(0, memcmp(req.upgraded_key.key_material, deserialized->upgraded_key.key_material, + req.upgraded_key.key_material_size)); + } +} + uint8_t msgbuf[] = { 220, 88, 183, 255, 71, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 0, 0, 0, 228, 174, 98, 187, 191, 135, 253, 200, 51, 230, 114, 247, 151, 109, @@ -672,6 +700,8 @@ GARBAGE_TEST(UpdateOperationRequest); GARBAGE_TEST(UpdateOperationResponse); GARBAGE_TEST(AttestKeyRequest); GARBAGE_TEST(AttestKeyResponse); +GARBAGE_TEST(UpgradeKeyRequest); +GARBAGE_TEST(UpgradeKeyResponse); // The macro doesn't work on this one. TEST(GarbageTest, SupportedResponse) { diff --git a/android_keymaster_test.cpp b/android_keymaster_test.cpp index 70c2022..1ea0c34 100644 --- a/android_keymaster_test.cpp +++ b/android_keymaster_test.cpp @@ -50,6 +50,9 @@ int __android_log_print(int prio, const char* tag, const char* fmt) { namespace keymaster { namespace test { +const uint32_t kOsVersion = 060000; +const uint32_t kOsPatchLevel = 201603; + StdoutLogger logger; template <typename T> vector<T> make_vector(const T* array, size_t len) { @@ -90,18 +93,28 @@ class TestKeymasterContext : public SoftKeymasterContext { }; /** - * Test instance creator that builds a pure software keymaster1 implementations. + * Test instance creator that builds a pure software keymaster2 implementation. */ class SoftKeymasterTestInstanceCreator : public Keymaster2TestInstanceCreator { public: keymaster2_device_t* CreateDevice() const override { std::cerr << "Creating software-only device" << std::endl; - SoftKeymasterDevice* device = new SoftKeymasterDevice(new TestKeymasterContext); + context_ = new TestKeymasterContext; + SoftKeymasterDevice* device = new SoftKeymasterDevice(context_); + AuthorizationSet version_info(AuthorizationSetBuilder() + .Authorization(TAG_OS_VERSION, kOsVersion) + .Authorization(TAG_OS_PATCHLEVEL, kOsPatchLevel)); + device->keymaster2_device()->configure(device->keymaster2_device(), &version_info); return device->keymaster2_device(); } bool algorithm_in_km0_hardware(keymaster_algorithm_t) const override { return false; } int keymaster0_calls() const override { return 0; } + bool is_keymaster1_hw() const override { return false; } + KeymasterContext* keymaster_context() const override { return context_; } + + private: + mutable TestKeymasterContext* context_; }; /** @@ -130,8 +143,13 @@ class Keymaster0AdapterTestInstanceCreator : public Keymaster2TestInstanceCreato counting_keymaster0_device_ = new Keymaster0CountingWrapper(keymaster0_device); - SoftKeymasterDevice* keymaster = new SoftKeymasterDevice(new TestKeymasterContext); + context_ = new TestKeymasterContext; + SoftKeymasterDevice* keymaster = new SoftKeymasterDevice(context_); keymaster->SetHardwareDevice(counting_keymaster0_device_); + AuthorizationSet version_info(AuthorizationSetBuilder() + .Authorization(TAG_OS_VERSION, kOsVersion) + .Authorization(TAG_OS_PATCHLEVEL, kOsPatchLevel)); + keymaster->keymaster2_device()->configure(keymaster->keymaster2_device(), &version_info); return keymaster->keymaster2_device(); } @@ -146,8 +164,11 @@ class Keymaster0AdapterTestInstanceCreator : public Keymaster2TestInstanceCreato } } int keymaster0_calls() const override { return counting_keymaster0_device_->count(); } + bool is_keymaster1_hw() const override { return false; } + KeymasterContext* keymaster_context() const override { return context_; } private: + mutable TestKeymasterContext* context_; mutable Keymaster0CountingWrapper* counting_keymaster0_device_; bool support_ec_; }; @@ -156,7 +177,7 @@ class Keymaster0AdapterTestInstanceCreator : public Keymaster2TestInstanceCreato * Test instance creator that builds a SoftKeymasterDevice which wraps a fake hardware keymaster1 * instance, with minimal digest support. */ -class Sha256OnlyKeymaster1TestInstanceCreator : public Keymaster2TestInstanceCreator { +class Sha256OnlyKeymaster2TestInstanceCreator : public Keymaster2TestInstanceCreator { keymaster2_device_t* CreateDevice() const { std::cerr << "Creating keymaster1-backed device that supports only SHA256"; @@ -165,22 +186,32 @@ class Sha256OnlyKeymaster1TestInstanceCreator : public Keymaster2TestInstanceCre (new SoftKeymasterDevice(new TestKeymasterContext("PseudoHW")))->keymaster_device()); // device doesn't leak; it's cleaned up by device->keymaster_device()->common.close(). - SoftKeymasterDevice* device = new SoftKeymasterDevice(new TestKeymasterContext); + context_ = new TestKeymasterContext; + SoftKeymasterDevice* device = new SoftKeymasterDevice(context_); device->SetHardwareDevice(fake_device); + AuthorizationSet version_info(AuthorizationSetBuilder() + .Authorization(TAG_OS_VERSION, kOsVersion) + .Authorization(TAG_OS_PATCHLEVEL, kOsPatchLevel)); + device->keymaster2_device()->configure(device->keymaster2_device(), &version_info); return device->keymaster2_device(); } bool algorithm_in_km0_hardware(keymaster_algorithm_t) const override { return false; } int keymaster0_calls() const override { return 0; } int minimal_digest_set() const override { return true; } + bool is_keymaster1_hw() const override { return true; } + KeymasterContext* keymaster_context() const override { return context_; } + + private: + mutable TestKeymasterContext* context_; }; static auto test_params = testing::Values( InstanceCreatorPtr(new SoftKeymasterTestInstanceCreator), InstanceCreatorPtr(new Keymaster0AdapterTestInstanceCreator(true /* support_ec */)), InstanceCreatorPtr(new Keymaster0AdapterTestInstanceCreator(false /* support_ec */)), - InstanceCreatorPtr(new Sha256OnlyKeymaster1TestInstanceCreator)); + InstanceCreatorPtr(new Sha256OnlyKeymaster2TestInstanceCreator)); class NewKeyGeneration : public Keymaster2Test { protected: @@ -206,6 +237,16 @@ class NewKeyGeneration : public Keymaster2Test { // Now check that unspecified, defaulted tags are correct. EXPECT_TRUE(contains(auths, KM_TAG_CREATION_DATETIME)); + if (GetParam()->is_keymaster1_hw()) { + // If the underlying (faked) HW is KM1, it will not have version info. + EXPECT_FALSE(auths.Contains(TAG_OS_VERSION)); + EXPECT_FALSE(auths.Contains(TAG_OS_PATCHLEVEL)); + } else { + // In all othe cases; SoftKeymasterDevice keys, or keymaster0 keys wrapped by + // SoftKeymasterDevice, version information will be present and up to date. + EXPECT_TRUE(contains(auths, TAG_OS_VERSION, kOsVersion)); + EXPECT_TRUE(contains(auths, TAG_OS_PATCHLEVEL, kOsPatchLevel)); + } } }; INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, NewKeyGeneration, test_params); @@ -3621,6 +3662,150 @@ TEST_P(AttestationTest, EcAttestation) { keymaster_free_cert_chain(&cert_chain); } +typedef Keymaster2Test KeyUpgradeTest; +INSTANTIATE_TEST_CASE_P(AndroidKeymasterTest, KeyUpgradeTest, test_params); + +TEST_P(KeyUpgradeTest, AesVersionUpgrade) { + GetParam()->keymaster_context()->SetSystemVersion(1, 1); + + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder() + .AesEncryptionKey(128) + .Authorization(TAG_BLOCK_MODE, KM_MODE_ECB) + .Padding(KM_PAD_NONE))); + + // Key should operate fine. + string message = "1234567890123456"; + string ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE); + EXPECT_EQ(message, DecryptMessage(ciphertext, KM_MODE_ECB, KM_PAD_NONE)); + + // Increase patch level. Key usage should fail with KM_ERROR_KEY_REQUIRES_UPGRADE. + GetParam()->keymaster_context()->SetSystemVersion(1, 2); + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_BLOCK_MODE, KM_MODE_ECB); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + if (GetParam()->is_keymaster1_hw()) { + // Keymaster1 hardware can't support version binding. The key will work regardless + // of system version. Just abort the remainder of the test. + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + EXPECT_EQ(KM_ERROR_OK, AbortOperation()); + return; + } + EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + + // Getting characteristics should also fail + EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, GetCharacteristics()); + + // Upgrade key. + EXPECT_EQ(KM_ERROR_OK, UpgradeKey(client_params())); + + // Key should work again + ciphertext = EncryptMessage(message, KM_MODE_ECB, KM_PAD_NONE); + EXPECT_EQ(message, DecryptMessage(ciphertext, KM_MODE_ECB, KM_PAD_NONE)); + + // Decrease patch level. Key usage should fail with KM_ERROR_INVALID_KEY_BLOB. + GetParam()->keymaster_context()->SetSystemVersion(1, 1); + EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, GetCharacteristics()); + + // Upgrade should fail + EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, UpgradeKey(client_params())); + + EXPECT_EQ(0, GetParam()->keymaster0_calls()); +} + +TEST_P(KeyUpgradeTest, RsaVersionUpgrade) { + GetParam()->keymaster_context()->SetSystemVersion(1, 1); + + ASSERT_EQ(KM_ERROR_OK, + GenerateKey(AuthorizationSetBuilder().RsaEncryptionKey(128, 3).Padding(KM_PAD_NONE))); + + // Key should operate fine. + string message = "1234567890123456"; + string ciphertext = EncryptMessage(message, KM_PAD_NONE); + EXPECT_EQ(message, DecryptMessage(ciphertext, KM_PAD_NONE)); + + // Increase patch level. Key usage should fail with KM_ERROR_KEY_REQUIRES_UPGRADE. + GetParam()->keymaster_context()->SetSystemVersion(1, 2); + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_PADDING, KM_PAD_NONE); + if (GetParam()->is_keymaster1_hw()) { + // Keymaster1 hardware can't support version binding. The key will work regardless + // of system version. Just abort the remainder of the test. + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + EXPECT_EQ(KM_ERROR_OK, AbortOperation()); + return; + } + EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + + // Getting characteristics should also fail + EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, GetCharacteristics()); + + // Upgrade key. + EXPECT_EQ(KM_ERROR_OK, UpgradeKey(client_params())); + + // Key should work again + ciphertext = EncryptMessage(message, KM_PAD_NONE); + EXPECT_EQ(message, DecryptMessage(ciphertext, KM_PAD_NONE)); + + // Decrease patch level. Key usage should fail with KM_ERROR_INVALID_KEY_BLOB. + GetParam()->keymaster_context()->SetSystemVersion(1, 1); + EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, GetCharacteristics()); + + // Upgrade should fail + EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, UpgradeKey(client_params())); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_RSA)) + EXPECT_EQ(7, GetParam()->keymaster0_calls()); +} + +TEST_P(KeyUpgradeTest, EcVersionUpgrade) { + GetParam()->keymaster_context()->SetSystemVersion(1, 1); + + ASSERT_EQ(KM_ERROR_OK, GenerateKey(AuthorizationSetBuilder().EcdsaSigningKey(256).Digest( + KM_DIGEST_SHA_2_256))); + + // Key should operate fine. + string message = "1234567890123456"; + string signature; + SignMessage(message, &signature, KM_DIGEST_SHA_2_256); + VerifyMessage(message, signature, KM_DIGEST_SHA_2_256); + + // Increase patch level. Key usage should fail with KM_ERROR_KEY_REQUIRES_UPGRADE. + GetParam()->keymaster_context()->SetSystemVersion(1, 2); + AuthorizationSet begin_params(client_params()); + begin_params.push_back(TAG_DIGEST, KM_DIGEST_SHA_2_256); + if (GetParam()->is_keymaster1_hw()) { + // Keymaster1 hardware can't support version binding. The key will work regardless + // of system version. Just abort the remainder of the test. + EXPECT_EQ(KM_ERROR_OK, BeginOperation(KM_PURPOSE_SIGN, begin_params)); + EXPECT_EQ(KM_ERROR_OK, AbortOperation()); + return; + } + EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, BeginOperation(KM_PURPOSE_SIGN, begin_params)); + + // Getting characteristics should also fail + EXPECT_EQ(KM_ERROR_KEY_REQUIRES_UPGRADE, GetCharacteristics()); + + // Upgrade key. + EXPECT_EQ(KM_ERROR_OK, UpgradeKey(client_params())); + + // Key should work again + SignMessage(message, &signature, KM_DIGEST_SHA_2_256); + VerifyMessage(message, signature, KM_DIGEST_SHA_2_256); + + // Decrease patch level. Key usage should fail with KM_ERROR_INVALID_KEY_BLOB. + GetParam()->keymaster_context()->SetSystemVersion(1, 1); + EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, BeginOperation(KM_PURPOSE_ENCRYPT, begin_params)); + EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, GetCharacteristics()); + + // Upgrade should fail + EXPECT_EQ(KM_ERROR_INVALID_ARGUMENT, UpgradeKey(client_params())); + + if (GetParam()->algorithm_in_km0_hardware(KM_ALGORITHM_EC)) + EXPECT_EQ(7, GetParam()->keymaster0_calls()); +} + TEST(SoftKeymasterWrapperTest, CheckKeymaster2Device) { // Make a good fake device, and wrap it. SoftKeymasterDevice* good_fake(new SoftKeymasterDevice(new TestKeymasterContext)); diff --git a/android_keymaster_test_utils.cpp b/android_keymaster_test_utils.cpp index c2f84d7..3c4b545 100644 --- a/android_keymaster_test_utils.cpp +++ b/android_keymaster_test_utils.cpp @@ -338,6 +338,17 @@ keymaster_error_t Keymaster2Test::AttestKey(const string& attest_challenge, return device()->attest_key(device(), &blob_, &attest_params, cert_chain); } +keymaster_error_t Keymaster2Test::UpgradeKey(const AuthorizationSet& upgrade_params) { + keymaster_key_blob_t upgraded_blob; + keymaster_error_t error = + device()->upgrade_key(device(), &blob_, &upgrade_params, &upgraded_blob); + if (error == KM_ERROR_OK) { + FreeKeyBlob(); + blob_ = upgraded_blob; + } + return error; +} + string Keymaster2Test::ProcessMessage(keymaster_purpose_t purpose, const string& message) { EXPECT_EQ(KM_ERROR_OK, BeginOperation(purpose, client_params(), NULL /* output_params */)); diff --git a/android_keymaster_test_utils.h b/android_keymaster_test_utils.h index ca8ce23..38d7d01 100644 --- a/android_keymaster_test_utils.h +++ b/android_keymaster_test_utils.h @@ -35,8 +35,10 @@ #include <hardware/keymaster1.h> #include <hardware/keymaster2.h> #include <hardware/keymaster_defs.h> + #include <keymaster/android_keymaster_utils.h> #include <keymaster/authorization_set.h> +#include <keymaster/keymaster_context.h> #include <keymaster/logger.h> std::ostream& operator<<(std::ostream& os, const keymaster_key_param_t& param); @@ -162,6 +164,8 @@ class Keymaster2TestInstanceCreator { virtual bool algorithm_in_km0_hardware(keymaster_algorithm_t algorithm) const = 0; virtual int keymaster0_calls() const = 0; virtual int minimal_digest_set() const { return false; } + virtual bool is_keymaster1_hw() const = 0; + virtual KeymasterContext* keymaster_context() const = 0; }; // Use a shared_ptr because it's copyable. @@ -210,6 +214,8 @@ class Keymaster2Test : public testing::TestWithParam<InstanceCreatorPtr> { keymaster_error_t AttestKey(const std::string& attest_challenge, keymaster_cert_chain_t* chain); + keymaster_error_t UpgradeKey(const AuthorizationSet& upgrade_params); + keymaster_error_t GetVersion(uint8_t* major, uint8_t* minor, uint8_t* subminor); std::string ProcessMessage(keymaster_purpose_t purpose, const std::string& message); diff --git a/attestation_record.cpp b/attestation_record.cpp index 868613a..ead45e7 100644 --- a/attestation_record.cpp +++ b/attestation_record.cpp @@ -429,7 +429,7 @@ keymaster_error_t build_attestation_record(const AuthorizationSet& attestation_p !ASN1_ENUMERATED_set(key_desc->keymaster_security_level, keymaster_security_level)) return TranslateLastOpenSslError(); - keymaster_blob_t attestation_challenge = {}; + keymaster_blob_t attestation_challenge = {nullptr, 0}; if (!attestation_params.GetTagValue(TAG_ATTESTATION_CHALLENGE, &attestation_challenge)) return KM_ERROR_ATTESTATION_CHALLENGE_MISSING; if (!ASN1_OCTET_STRING_set(key_desc->attestation_challenge, attestation_challenge.data, diff --git a/attestation_record_test.cpp b/attestation_record_test.cpp index 2d7af3b..e417105 100644 --- a/attestation_record_test.cpp +++ b/attestation_record_test.cpp @@ -31,7 +31,14 @@ class TestContext : public KeymasterContext { keymaster_security_level_t GetSecurityLevel() const override { return KM_SECURITY_LEVEL_SOFTWARE; } - + keymaster_error_t SetSystemVersion(uint32_t /* os_version */, + uint32_t /* os_patchlevel */) override { + return KM_ERROR_UNIMPLEMENTED; + } + void GetSystemVersion(uint32_t* os_version, uint32_t* os_patchlevel) const override { + *os_version = 0; + *os_patchlevel = 0; + } KeyFactory* GetKeyFactory(keymaster_algorithm_t /* algorithm */) const override { return nullptr; } @@ -50,6 +57,11 @@ class TestContext : public KeymasterContext { AuthorizationSet* /* sw_enforced */) const override { return KM_ERROR_UNIMPLEMENTED; } + keymaster_error_t UpgradeKeyBlob(const KeymasterKeyBlob& /* key_to_upgrade */, + const AuthorizationSet& /* upgrade_params */, + KeymasterKeyBlob* /* upgraded_key */) const override { + return KM_ERROR_UNIMPLEMENTED; + } keymaster_error_t ParseKeyBlob(const KeymasterKeyBlob& /* blob */, const AuthorizationSet& /* additional_params */, KeymasterKeyBlob* /* key_material */, diff --git a/authorization_set.cpp b/authorization_set.cpp index 00cd425..b241b78 100644 --- a/authorization_set.cpp +++ b/authorization_set.cpp @@ -213,8 +213,8 @@ int AuthorizationSet::find(keymaster_tag_t tag, int begin) const { return i; } -bool AuthorizationSet::erase(size_t index) { - if (index >= size()) +bool AuthorizationSet::erase(int index) { + if (index < 0 || index >= static_cast<int>(size())) return false; --elems_size_; @@ -223,21 +223,21 @@ bool AuthorizationSet::erase(size_t index) { return true; } -keymaster_key_param_t empty_set = {}; +keymaster_key_param_t empty_param = {KM_TAG_INVALID, {}}; keymaster_key_param_t& AuthorizationSet::operator[](int at) { if (is_valid() == OK && at < (int)elems_size_) { return elems_[at]; } - empty_set = {}; - return empty_set; + empty_param = {KM_TAG_INVALID, {}}; + return empty_param; } keymaster_key_param_t AuthorizationSet::operator[](int at) const { if (is_valid() == OK && at < (int)elems_size_) { return elems_[at]; } - empty_set = {}; - return empty_set; + empty_param = {KM_TAG_INVALID, {}}; + return empty_param; } bool AuthorizationSet::push_back(const keymaster_key_param_set_t& set) { diff --git a/include/keymaster/android_keymaster.h b/include/keymaster/android_keymaster.h index c7ecfad..301703b 100644 --- a/include/keymaster/android_keymaster.h +++ b/include/keymaster/android_keymaster.h @@ -71,6 +71,7 @@ class AndroidKeymaster { void ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response); void ExportKey(const ExportKeyRequest& request, ExportKeyResponse* response); void AttestKey(const AttestKeyRequest& request, AttestKeyResponse* response); + void UpgradeKey(const UpgradeKeyRequest& request, UpgradeKeyResponse* response); void DeleteKey(const DeleteKeyRequest& request, DeleteKeyResponse* response); void DeleteAllKeys(const DeleteAllKeysRequest& request, DeleteAllKeysResponse* response); void BeginOperation(const BeginOperationRequest& request, BeginOperationResponse* response); diff --git a/include/keymaster/android_keymaster_messages.h b/include/keymaster/android_keymaster_messages.h index 3da7f47..5b1da56 100644 --- a/include/keymaster/android_keymaster_messages.h +++ b/include/keymaster/android_keymaster_messages.h @@ -45,6 +45,7 @@ enum AndroidKeymasterCommand { GET_SUPPORTED_EXPORT_FORMATS = 14, GET_KEY_CHARACTERISTICS = 15, ATTEST_KEY = 16, + UPGRADE_KEY = 17, }; /** @@ -621,6 +622,38 @@ struct AttestKeyResponse : public KeymasterResponse { keymaster_cert_chain_t certificate_chain; }; +struct UpgradeKeyRequest : public KeymasterMessage { + explicit UpgradeKeyRequest(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterMessage(ver) { + key_blob = {nullptr, 0}; + } + ~UpgradeKeyRequest(); + + void SetKeyMaterial(const void* key_material, size_t length); + void SetKeyMaterial(const keymaster_key_blob_t& blob) { + SetKeyMaterial(blob.key_material, blob.key_material_size); + } + + size_t SerializedSize() const override; + uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override; + bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override; + + keymaster_key_blob_t key_blob; + AuthorizationSet upgrade_params; +}; + +struct UpgradeKeyResponse : public KeymasterResponse { + explicit UpgradeKeyResponse(int32_t ver = MAX_MESSAGE_VERSION) : KeymasterResponse(ver) { + upgraded_key = {nullptr, 0}; + } + ~UpgradeKeyResponse(); + + size_t NonErrorSerializedSize() const override; + uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t* end) const override; + bool NonErrorDeserialize(const uint8_t** buf_ptr, const uint8_t* end) override; + + keymaster_key_blob_t upgraded_key; +}; + } // namespace keymaster #endif // SYSTEM_KEYMASTER_ANDROID_KEYMASTER_MESSAGES_H_ diff --git a/include/keymaster/authorization_set.h b/include/keymaster/authorization_set.h index f7fa28a..5be5d83 100644 --- a/include/keymaster/authorization_set.h +++ b/include/keymaster/authorization_set.h @@ -180,7 +180,7 @@ class AuthorizationSet : public Serializable, public keymaster_key_param_set_t { * Removes the entry at the specified index. Returns true if successful, false if the index was * out of bounds. */ - bool erase(size_t index); + bool erase(int index); /** * Returns iterator (pointer) to beginning of elems array, to enable STL-style iteration diff --git a/include/keymaster/keymaster_configuration.h b/include/keymaster/keymaster_configuration.h new file mode 100644 index 0000000..97b7fa5 --- /dev/null +++ b/include/keymaster/keymaster_configuration.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2016 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_CONFIGURATION_H_ +#define SYSTEM_KEYMASTER_KEYMASTER_CONFIGURATION_H_ + +#include <string> + +#include <stdint.h> + +#include <hardware/keymaster2.h> +#include <hardware/keymaster_defs.h> + +namespace keymaster { + +/** + * Retrieves OS version information from system build properties and configures the provided + * keymaster device. + */ +keymaster_error_t ConfigureDevice(keymaster2_device_t* dev); + +/** + * Parses OS version string, returning in integer form. For example, "6.1.2" will be returned as + * 60102. Ignores any non-numeric suffix, and allows short build numbers, e.g. "6" -> 60000 and + * "6.1" -> 60100. Returns 0 if the string doesn't contain a numeric version number. + */ +uint32_t GetOsVersion(const char* version_string); + +/** + * Parses OS patch level string, returning year and month in integer form. For example, "2016-03-25" + * will be returned as 201603. Returns 0 if the string doesn't contain a date in the form + * YYYY-MM-DD. + */ +uint32_t GetOsPatchlevel(const char* patchlevel_string); + +} // namespace keymaster + +#endif // SYSTEM_KEYMASTER_KEYMASTER_CONFIGURATION_H_ diff --git a/include/keymaster/keymaster_context.h b/include/keymaster/keymaster_context.h index d598acd..efd06e8 100644 --- a/include/keymaster/keymaster_context.h +++ b/include/keymaster/keymaster_context.h @@ -70,6 +70,23 @@ class KeymasterContext { */ virtual keymaster_security_level_t GetSecurityLevel() const = 0; + /** + * Sets the system version as reported by the system *itself*. This is used to verify that the + * system believes itself to be running the same version that is reported by the bootloader, in + * hardware implementations. For SoftKeymasterDevice, this sets the version information used. + * + * If the specified values don't match the bootloader-provided values, this method must return + * KM_ERROR_INVALID_ARGUMENT; + */ + virtual keymaster_error_t SetSystemVersion(uint32_t os_version, uint32_t os_patchlevel) = 0; + + /** + * Returns the system version. For hardware-based implementations this will be the value + * reported by the bootloader. For SoftKeymasterDevice it will be the verion information set by + * SetSystemVersion above. + */ + virtual void GetSystemVersion(uint32_t* os_version, uint32_t* os_patchlevel) const = 0; + virtual KeyFactory* GetKeyFactory(keymaster_algorithm_t algorithm) const = 0; virtual OperationFactory* GetOperationFactory(keymaster_algorithm_t algorithm, keymaster_purpose_t purpose) const = 0; @@ -90,6 +107,14 @@ class KeymasterContext { AuthorizationSet* sw_enforced) const = 0; /** + * UpgradeKeyBlob takes an existing blob, parses out key material and constructs a new blob with + * the current format and OS version info. + */ + virtual keymaster_error_t UpgradeKeyBlob(const KeymasterKeyBlob& key_to_upgrade, + const AuthorizationSet& upgrade_params, + KeymasterKeyBlob* upgraded_key) 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). diff --git a/include/keymaster/soft_keymaster_context.h b/include/keymaster/soft_keymaster_context.h index 65f9c14..b3cb8b2 100644 --- a/include/keymaster/soft_keymaster_context.h +++ b/include/keymaster/soft_keymaster_context.h @@ -57,6 +57,9 @@ class SoftKeymasterContext : public KeymasterContext { return KM_SECURITY_LEVEL_SOFTWARE; } + keymaster_error_t SetSystemVersion(uint32_t os_version, uint32_t os_patchlevel) override; + void GetSystemVersion(uint32_t* os_version, uint32_t* os_patchlevel) const override; + KeyFactory* GetKeyFactory(keymaster_algorithm_t algorithm) const override; OperationFactory* GetOperationFactory(keymaster_algorithm_t algorithm, keymaster_purpose_t purpose) const override; @@ -65,7 +68,9 @@ class SoftKeymasterContext : public KeymasterContext { const KeymasterKeyBlob& key_material, KeymasterKeyBlob* blob, AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced) const override; - + keymaster_error_t UpgradeKeyBlob(const KeymasterKeyBlob& key_to_upgrade, + const AuthorizationSet& upgrade_params, + KeymasterKeyBlob* upgraded_key) const override; keymaster_error_t ParseKeyBlob(const KeymasterKeyBlob& blob, const AuthorizationSet& additional_params, KeymasterKeyBlob* key_material, AuthorizationSet* hw_enforced, @@ -85,7 +90,10 @@ class SoftKeymasterContext : public KeymasterContext { return nullptr; } + void AddSystemVersionToSet(AuthorizationSet* auth_set) const; + private: + keymaster_error_t ParseOldSoftkeymasterBlob(const KeymasterKeyBlob& blob, KeymasterKeyBlob* key_material, AuthorizationSet* hw_enforced, @@ -112,6 +120,8 @@ class SoftKeymasterContext : public KeymasterContext { std::unique_ptr<KeyFactory> hmac_factory_; keymaster1_device* km1_dev_; const std::string root_of_trust_; + uint32_t os_version_; + uint32_t os_patchlevel_; }; } // namespace keymaster diff --git a/include/keymaster/soft_keymaster_device.h b/include/keymaster/soft_keymaster_device.h index e9e325d..ffe98da 100644 --- a/include/keymaster/soft_keymaster_device.h +++ b/include/keymaster/soft_keymaster_device.h @@ -79,6 +79,8 @@ class SoftKeymasterDevice { impl_->GetVersion(req, rsp); } + bool configured() const { return configured_; } + typedef std::pair<keymaster_algorithm_t, keymaster_purpose_t> AlgPurposePair; typedef std::map<AlgPurposePair, std::vector<keymaster_digest_t>> DigestMap; @@ -177,6 +179,8 @@ class SoftKeymasterDevice { keymaster_operation_handle_t operation_handle); // Keymaster2 methods + static keymaster_error_t configure(const keymaster2_device_t* dev, + const keymaster_key_param_set_t* params); static keymaster_error_t add_rng_entropy(const keymaster2_device_t* dev, const uint8_t* data, size_t data_length); static keymaster_error_t generate_key(const keymaster2_device_t* dev, @@ -204,6 +208,10 @@ class SoftKeymasterDevice { const keymaster_key_blob_t* key_to_attest, const keymaster_key_param_set_t* attest_params, keymaster_cert_chain_t* cert_chain); + static keymaster_error_t upgrade_key(const keymaster2_device_t* dev, + const keymaster_key_blob_t* key_to_upgrade, + const keymaster_key_param_set_t* upgrade_params, + keymaster_key_blob_t* upgraded_key); static keymaster_error_t delete_key(const keymaster2_device_t* dev, const keymaster_key_blob_t* key); static keymaster_error_t delete_all_keys(const keymaster2_device_t* dev); @@ -238,6 +246,7 @@ class SoftKeymasterDevice { UniquePtr<AndroidKeymaster> impl_; std::string module_name_; hw_module_t updated_module_; + bool configured_; }; } // namespace keymaster diff --git a/keymaster_configuration.cpp b/keymaster_configuration.cpp new file mode 100644 index 0000000..428197c --- /dev/null +++ b/keymaster_configuration.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <keymaster/keymaster_configuration.h> + +#include <regex> +#include <string> + +#include <regex.h> + +#define LOG_TAG "keymaster" +#include <cutils/log.h> + +#ifndef KEYMASTER_UNIT_TEST_BUILD +#include <cutils/properties.h> +#else +#define PROPERTY_VALUE_MAX 80 /* Value doesn't matter */ +void property_get(const char* /* prop_name */, char* /* prop */, const char* /* default */) {} +#endif + +#include <keymaster/authorization_set.h> + +namespace keymaster { + +namespace { + +constexpr char kPlatformVersionProp[] = "ro.build.version.release"; +constexpr char kPlatformVersionRegex[] = "^([0-9]{1,2})(\\.([0-9]{1,2}))?(\\.([0-9]{1,2}))?"; +constexpr size_t kMajorVersionMatch = 1; +constexpr size_t kMinorVersionMatch = 3; +constexpr size_t kSubminorVersionMatch = 5; +constexpr size_t kPlatformVersionMatchCount = kSubminorVersionMatch + 1; + +constexpr char kPlatformPatchlevelProp[] = "ro.build.version.security_patch"; +constexpr char kPlatformPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-[0-9]{2}$"; +constexpr size_t kYearMatch = 1; +constexpr size_t kMonthMatch = 2; +constexpr size_t kPlatformPatchlevelMatchCount = kMonthMatch + 1; + +uint32_t match_to_uint32(const char* expression, const regmatch_t& match) { + if (match.rm_so == -1) + return 0; + + size_t len = match.rm_eo - match.rm_so; + std::string s(expression + match.rm_so, len); + return std::stoul(s); +} + +} // anonymous namespace + +keymaster_error_t ConfigureDevice(keymaster2_device_t* dev, uint32_t os_version, + uint32_t os_patchlevel) { + AuthorizationSet config_params(AuthorizationSetBuilder() + .Authorization(keymaster::TAG_OS_VERSION, os_version) + .Authorization(keymaster::TAG_OS_PATCHLEVEL, os_patchlevel)); + return dev->configure(dev, &config_params); +} + +keymaster_error_t ConfigureDevice(keymaster2_device_t* dev) { + char version_str[PROPERTY_VALUE_MAX]; + property_get(kPlatformVersionProp, version_str, "" /* default */); + uint32_t version = GetOsVersion(version_str); + + char patchlevel_str[PROPERTY_VALUE_MAX]; + property_get(kPlatformPatchlevelProp, patchlevel_str, "" /* default */); + uint32_t patchlevel = GetOsPatchlevel(patchlevel_str); + + return ConfigureDevice(dev, version, patchlevel); +} + +uint32_t GetOsVersion(const char* version_str) { + regex_t regex; + if (regcomp(®ex, kPlatformVersionRegex, REG_EXTENDED)) { + ALOGE("Failed to compile version regex! (%s)", kPlatformVersionRegex); + return 0; + } + + regmatch_t matches[kPlatformVersionMatchCount]; + if (regexec(®ex, version_str, kPlatformVersionMatchCount, matches, 0 /* flags */)) { + ALOGI("Platform version string does not match expected format. Using version 0."); + return 0; + } + + uint32_t major = match_to_uint32(version_str, matches[kMajorVersionMatch]); + uint32_t minor = match_to_uint32(version_str, matches[kMinorVersionMatch]); + uint32_t subminor = match_to_uint32(version_str, matches[kSubminorVersionMatch]); + + return (major * 100 + minor) * 100 + subminor; +} + +uint32_t GetOsPatchlevel(const char* patchlevel_str) { + regex_t regex; + if (regcomp(®ex, kPlatformPatchlevelRegex, REG_EXTENDED) != 0) { + ALOGE("Failed to compile platform patchlevel regex! (%s)", kPlatformPatchlevelRegex); + return 0; + } + + regmatch_t matches[kPlatformPatchlevelMatchCount]; + if (regexec(®ex, patchlevel_str, kPlatformPatchlevelMatchCount, matches, 0 /* flags */)) { + ALOGI("Platform patchlevel string does not match expected format. Using patchlevel 0"); + return 0; + } + + uint32_t year = match_to_uint32(patchlevel_str, matches[kYearMatch]); + uint32_t month = match_to_uint32(patchlevel_str, matches[kMonthMatch]); + + if (month < 1 || month > 12) { + ALOGE("Invalid patch month %d", month); + return 0; + } + return year * 100 + month; +} + +} // namespace keymaster diff --git a/keymaster_configuration_test.cpp b/keymaster_configuration_test.cpp new file mode 100644 index 0000000..81e9598 --- /dev/null +++ b/keymaster_configuration_test.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2016 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 <gtest/gtest.h> + +#include <keymaster/keymaster_configuration.h> + +#ifdef HOST_BUILD +extern "C" { +int __android_log_print(int prio, const char* tag, const char* fmt); +int __android_log_print(int prio, const char* tag, const char* fmt) { + (void)prio, (void)tag, (void)fmt; + std::cout << fmt << std::endl; + return 0; +} +} // extern "C" +#endif // HOST_BUILD + +namespace keymaster { +namespace test { + +TEST(VersionParsingTest, Full) { + EXPECT_EQ(612334U, GetOsVersion("61.23.34")); + EXPECT_EQ(680000U, GetOsVersion("681.23.24")); + EXPECT_EQ(682300U, GetOsVersion("68.231.24")); + EXPECT_EQ(682324U, GetOsVersion("68.23.241")); + EXPECT_EQ(60102U, GetOsVersion("6.1.2-extrajunk")); + EXPECT_EQ(0U, GetOsVersion("extra6.1.2")); +} + +TEST(VersionParsingTest, FullWithExtraChars) {} + +TEST(VersionParsingTest, MajorOnly) { + EXPECT_EQ(60000U, GetOsVersion("6")); + EXPECT_EQ(680000U, GetOsVersion("68")); + EXPECT_EQ(680000U, GetOsVersion("681")); + EXPECT_EQ(60000U, GetOsVersion("6.junk")); +} + +TEST(VersionParsingTest, MajorMinorOnly) { + EXPECT_EQ(60100U, GetOsVersion("6.1")); + EXPECT_EQ(60100U, GetOsVersion("6.1junk")); +} + +TEST(PatchLevelParsingTest, Full) { + EXPECT_EQ(201603U, GetOsPatchlevel("2016-03-23")); + EXPECT_EQ(0U, GetOsPatchlevel("2016-13-23")); + EXPECT_EQ(0U, GetOsPatchlevel("2016-03")); + EXPECT_EQ(0U, GetOsPatchlevel("2016-3-23")); + EXPECT_EQ(0U, GetOsPatchlevel("2016-03-23r")); + EXPECT_EQ(0U, GetOsPatchlevel("r2016-03-23")); +} + +} // namespace test +} // namespace keymaster diff --git a/soft_keymaster_context.cpp b/soft_keymaster_context.cpp index ab68760..9df7d2a 100644 --- a/soft_keymaster_context.cpp +++ b/soft_keymaster_context.cpp @@ -281,12 +281,34 @@ static uint8_t kEcAttestRootCert[] = { size_t kCertificateChainLength = 2; +bool UpgradeIntegerTag(keymaster_tag_t tag, uint32_t value, AuthorizationSet* set, + bool* set_changed) { + int index = set->find(tag); + if (index == -1) { + keymaster_key_param_t param; + param.tag = tag; + param.integer = value; + set->push_back(param); + *set_changed = true; + return true; + } + + if (set->params[index].integer > value) + return false; + + if (set->params[index].integer != value) { + set->params[index].integer = value; + *set_changed = true; + } + return true; +} + } // anonymous namespace SoftKeymasterContext::SoftKeymasterContext(const std::string& root_of_trust) : rsa_factory_(new RsaKeyFactory(this)), ec_factory_(new EcKeyFactory(this)), aes_factory_(new AesKeyFactory(this)), hmac_factory_(new HmacKeyFactory(this)), - km1_dev_(nullptr), root_of_trust_(root_of_trust) {} + km1_dev_(nullptr), root_of_trust_(root_of_trust), os_version_(0), os_patchlevel_(0) {} SoftKeymasterContext::~SoftKeymasterContext() {} @@ -326,6 +348,18 @@ keymaster_error_t SoftKeymasterContext::SetHardwareDevice(keymaster1_device_t* k return KM_ERROR_OK; } +keymaster_error_t SoftKeymasterContext::SetSystemVersion(uint32_t os_version, + uint32_t os_patchlevel) { + os_version_ = os_version; + os_patchlevel_ = os_patchlevel; + return KM_ERROR_OK; +} + +void SoftKeymasterContext::GetSystemVersion(uint32_t* os_version, uint32_t* os_patchlevel) const { + *os_version = os_version_; + *os_patchlevel = os_patchlevel_; +} + KeyFactory* SoftKeymasterContext::GetKeyFactory(keymaster_algorithm_t algorithm) const { switch (algorithm) { case KM_ALGORITHM_RSA: @@ -371,8 +405,8 @@ static keymaster_error_t TranslateAuthorizationSetError(AuthorizationSet::Error } static keymaster_error_t SetAuthorizations(const AuthorizationSet& key_description, - keymaster_key_origin_t origin, - AuthorizationSet* hw_enforced, + keymaster_key_origin_t origin, uint32_t os_version, + uint32_t os_patchlevel, AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced) { sw_enforced->Clear(); @@ -405,6 +439,9 @@ static keymaster_error_t SetAuthorizations(const AuthorizationSet& key_descripti sw_enforced->push_back(TAG_CREATION_DATETIME, java_time(time(NULL))); sw_enforced->push_back(TAG_ORIGIN, origin); + sw_enforced->push_back(TAG_OS_VERSION, os_version); + sw_enforced->push_back(TAG_OS_PATCHLEVEL, os_patchlevel); + return TranslateAuthorizationSetError(sw_enforced->is_valid()); } @@ -414,7 +451,8 @@ keymaster_error_t SoftKeymasterContext::CreateKeyBlob(const AuthorizationSet& ke KeymasterKeyBlob* blob, AuthorizationSet* hw_enforced, AuthorizationSet* sw_enforced) const { - keymaster_error_t error = SetAuthorizations(key_description, origin, hw_enforced, sw_enforced); + keymaster_error_t error = SetAuthorizations(key_description, origin, os_version_, + os_patchlevel_, hw_enforced, sw_enforced); if (error != KM_ERROR_OK) return error; @@ -426,6 +464,51 @@ keymaster_error_t SoftKeymasterContext::CreateKeyBlob(const AuthorizationSet& ke return SerializeIntegrityAssuredBlob(key_material, hidden, *hw_enforced, *sw_enforced, blob); } +keymaster_error_t SoftKeymasterContext::UpgradeKeyBlob(const KeymasterKeyBlob& key_to_upgrade, + const AuthorizationSet& upgrade_params, + KeymasterKeyBlob* upgraded_key) const { + KeymasterKeyBlob key_material; + AuthorizationSet tee_enforced; + AuthorizationSet sw_enforced; + keymaster_error_t error = + ParseKeyBlob(key_to_upgrade, upgrade_params, &key_material, &tee_enforced, &sw_enforced); + if (error != KM_ERROR_OK) + return error; + + // Three cases here: + // + // 1. Software key blob. Version info, if present, is in sw_enforced. If not present, we + // should add it. + // + // 2. Keymaster0 hardware key blob. Version info, if present, is in sw_enforced. If not + // present we should add it. + // + // 3. Keymaster1 hardware key blob. Version info is not present and we shouldn't have been + // asked to upgrade. + + // Handle case 3. + if (km1_dev_ && tee_enforced.Contains(TAG_PURPOSE) && !tee_enforced.Contains(TAG_OS_PATCHLEVEL)) + return KM_ERROR_INVALID_ARGUMENT; + + // Handle cases 1 & 2. + bool set_changed = false; + if (!UpgradeIntegerTag(TAG_OS_VERSION, os_version_, &sw_enforced, &set_changed) || + !UpgradeIntegerTag(TAG_OS_PATCHLEVEL, os_patchlevel_, &sw_enforced, &set_changed)) + // One of the version fields would have been a downgrade. Not allowed. + return KM_ERROR_INVALID_ARGUMENT; + + if (!set_changed) + // Dont' need an upgrade. + return KM_ERROR_OK; + + AuthorizationSet hidden; + error = BuildHiddenAuthorizations(upgrade_params, &hidden); + if (error != KM_ERROR_OK) + return error; + return SerializeIntegrityAssuredBlob(key_material, hidden, tee_enforced, sw_enforced, + upgraded_key); +} + static keymaster_error_t ParseOcbAuthEncryptedBlob(const KeymasterKeyBlob& blob, const AuthorizationSet& hidden, KeymasterKeyBlob* key_material, @@ -657,6 +740,13 @@ keymaster_error_t SoftKeymasterContext::GenerateRandom(uint8_t* buf, size_t leng return KM_ERROR_OK; } +void SoftKeymasterContext::AddSystemVersionToSet(AuthorizationSet* auth_set) const { + if (!auth_set->Contains(TAG_OS_VERSION)) + auth_set->push_back(TAG_OS_VERSION, os_version_); + if (!auth_set->Contains(TAG_OS_PATCHLEVEL)) + auth_set->push_back(TAG_OS_PATCHLEVEL, os_patchlevel_); +} + EVP_PKEY* SoftKeymasterContext::AttestationKey(keymaster_algorithm_t algorithm, keymaster_error_t* error) const { diff --git a/soft_keymaster_device.cpp b/soft_keymaster_device.cpp index 5d646e2..d6c9e6b 100644 --- a/soft_keymaster_device.cpp +++ b/soft_keymaster_device.cpp @@ -126,7 +126,7 @@ static keymaster_error_t map_digests(keymaster1_device_t* dev, SoftKeymasterDevice::SoftKeymasterDevice() : wrapped_km0_device_(nullptr), wrapped_km1_device_(nullptr), context_(new SoftKeymasterContext), - impl_(new AndroidKeymaster(context_, kOperationTableSize)) { + impl_(new AndroidKeymaster(context_, kOperationTableSize)), configured_(false) { LOG_I("Creating device", 0); LOG_D("Device address: %p", this); @@ -136,7 +136,7 @@ SoftKeymasterDevice::SoftKeymasterDevice() SoftKeymasterDevice::SoftKeymasterDevice(SoftKeymasterContext* context) : wrapped_km0_device_(nullptr), wrapped_km1_device_(nullptr), context_(context), - impl_(new AndroidKeymaster(context_, kOperationTableSize)) { + impl_(new AndroidKeymaster(context_, kOperationTableSize)), configured_(false) { LOG_I("Creating test device", 0); LOG_D("Device address: %p", this); @@ -275,14 +275,14 @@ void SoftKeymasterDevice::initialize_device_struct(uint32_t flags) { km2_device_.common.module = reinterpret_cast<hw_module_t*>(&soft_keymaster2_device_module); km2_device_.common.close = &close_device; - km2_device_.configure = nullptr; + km2_device_.configure = configure; km2_device_.add_rng_entropy = add_rng_entropy; km2_device_.generate_key = generate_key; km2_device_.get_key_characteristics = get_key_characteristics; km2_device_.import_key = import_key; km2_device_.export_key = export_key; km2_device_.attest_key = attest_key; - km2_device_.upgrade_key = nullptr; // TODO(swillden) Implement upgrade + km2_device_.upgrade_key = upgrade_key; km2_device_.delete_key = delete_key; km2_device_.delete_all_keys = delete_all_keys; km2_device_.begin = begin; @@ -601,6 +601,25 @@ keymaster_error_t SoftKeymasterDevice::get_supported_export_formats( } /* static */ +keymaster_error_t SoftKeymasterDevice::configure(const keymaster2_device_t* dev, + const keymaster_key_param_set_t* params) { + AuthorizationSet params_copy(*params); + uint32_t os_version; + uint32_t os_patchlevel; + if (!params_copy.GetTagValue(TAG_OS_VERSION, &os_version) || + !params_copy.GetTagValue(TAG_OS_PATCHLEVEL, &os_patchlevel)) { + LOG_E("Configuration parameters must contain OS version and patch level", 0); + return KM_ERROR_INVALID_ARGUMENT; + } + + keymaster_error_t error = + convert_device(dev)->context_->SetSystemVersion(os_version, os_patchlevel); + if (error == KM_ERROR_OK) + convert_device(dev)->configured_ = true; + return error; +} + +/* static */ keymaster_error_t SoftKeymasterDevice::add_rng_entropy(const keymaster1_device_t* dev, const uint8_t* data, size_t data_length) { if (!dev) @@ -625,6 +644,9 @@ keymaster_error_t SoftKeymasterDevice::add_rng_entropy(const keymaster2_device_t if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER; + if (!convert_device(dev)->configured()) + return KM_ERROR_KEYMASTER_NOT_CONFIGURED; + SoftKeymasterDevice* sk_dev = convert_device(dev); return add_rng_entropy(&sk_dev->km1_device_, data, data_length); } @@ -735,6 +757,12 @@ keymaster_error_t SoftKeymasterDevice::generate_key( key_blob->key_material = tmp; if (characteristics) { + // This is a keymaster1 method, and keymaster1 doesn't include version info, so remove it. + response.enforced.erase(response.enforced.find(TAG_OS_VERSION)); + response.enforced.erase(response.enforced.find(TAG_OS_PATCHLEVEL)); + response.unenforced.erase(response.unenforced.find(TAG_OS_VERSION)); + response.unenforced.erase(response.unenforced.find(TAG_OS_PATCHLEVEL)); + *characteristics = BuildCharacteristics(response.enforced, response.unenforced); if (!*characteristics) return KM_ERROR_MEMORY_ALLOCATION_FAILED; @@ -751,6 +779,9 @@ SoftKeymasterDevice::generate_key(const keymaster2_device_t* dev, // if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER; + if (!convert_device(dev)->configured()) + return KM_ERROR_KEYMASTER_NOT_CONFIGURED; + if (!key_blob) return KM_ERROR_OUTPUT_PARAMETER_NULL; @@ -771,6 +802,7 @@ SoftKeymasterDevice::generate_key(const keymaster2_device_t* dev, // *characteristics = *chars_ptr; free(chars_ptr); } + return KM_ERROR_OK; } @@ -806,9 +838,10 @@ keymaster_error_t SoftKeymasterDevice::get_key_characteristics( return KM_ERROR_OUTPUT_PARAMETER_NULL; const keymaster1_device_t* km1_dev = convert_device(dev)->wrapped_km1_device_; - if (km1_dev) + if (km1_dev) { return km1_dev->get_key_characteristics(km1_dev, key_blob, client_id, app_data, characteristics); + } GetKeyCharacteristicsRequest request; request.SetKeyMaterial(*key_blob); @@ -819,9 +852,16 @@ keymaster_error_t SoftKeymasterDevice::get_key_characteristics( if (response.error != KM_ERROR_OK) return response.error; + // This is a keymaster1 method, and keymaster1 doesn't include version info, so remove it. + response.enforced.erase(response.enforced.find(TAG_OS_VERSION)); + response.enforced.erase(response.enforced.find(TAG_OS_PATCHLEVEL)); + response.unenforced.erase(response.unenforced.find(TAG_OS_VERSION)); + response.unenforced.erase(response.unenforced.find(TAG_OS_PATCHLEVEL)); + *characteristics = BuildCharacteristics(response.enforced, response.unenforced); if (!*characteristics) return KM_ERROR_MEMORY_ALLOCATION_FAILED; + return KM_ERROR_OK; } @@ -833,21 +873,39 @@ keymaster_error_t SoftKeymasterDevice::get_key_characteristics( if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER; + if (!convert_device(dev)->configured()) + return KM_ERROR_KEYMASTER_NOT_CONFIGURED; + if (!characteristics) return KM_ERROR_OUTPUT_PARAMETER_NULL; SoftKeymasterDevice* sk_dev = convert_device(dev); - keymaster_error_t error; - keymaster_key_characteristics_t* key_characteristics; - error = get_key_characteristics(&sk_dev->km1_device_, key_blob, client_id, app_data, - &key_characteristics); - if (error != KM_ERROR_OK) + const keymaster1_device_t* km1_dev = sk_dev->wrapped_km1_device_; + if (km1_dev) { + keymaster_key_characteristics_t* tmp_characteristics; + keymaster_error_t error = km1_dev->get_key_characteristics(km1_dev, key_blob, client_id, + app_data, &tmp_characteristics); + if (error == KM_ERROR_OK) { + *characteristics = *tmp_characteristics; + free(tmp_characteristics); + } return error; - *characteristics = *key_characteristics; - free(key_characteristics); + } - return error; + GetKeyCharacteristicsRequest request; + request.SetKeyMaterial(*key_blob); + AddClientAndAppData(client_id, app_data, &request); + + GetKeyCharacteristicsResponse response; + sk_dev->impl_->GetKeyCharacteristics(request, &response); + if (response.error != KM_ERROR_OK) + return response.error; + + response.enforced.CopyToParamSet(&characteristics->hw_enforced); + response.unenforced.CopyToParamSet(&characteristics->sw_enforced); + + return KM_ERROR_OK; } /* static */ @@ -905,6 +963,9 @@ keymaster_error_t SoftKeymasterDevice::import_key( if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER; + if (!convert_device(dev)->configured()) + return KM_ERROR_KEYMASTER_NOT_CONFIGURED; + SoftKeymasterDevice* sk_dev = convert_device(dev); keymaster_error_t error; @@ -973,6 +1034,9 @@ keymaster_error_t SoftKeymasterDevice::export_key(const keymaster2_device_t* dev if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER; + if (!convert_device(dev)->configured()) + return KM_ERROR_KEYMASTER_NOT_CONFIGURED; + SoftKeymasterDevice* sk_dev = convert_device(dev); return export_key(&sk_dev->km1_device_, export_format, key_to_export, client_id, app_data, export_data); @@ -986,6 +1050,9 @@ keymaster_error_t SoftKeymasterDevice::attest_key(const keymaster2_device_t* dev if (!dev || !key_to_attest || !attest_params || !cert_chain) return KM_ERROR_UNEXPECTED_NULL_POINTER; + if (!convert_device(dev)->configured()) + return KM_ERROR_KEYMASTER_NOT_CONFIGURED; + cert_chain->entry_count = 0; cert_chain->entries = nullptr; @@ -1025,6 +1092,39 @@ keymaster_error_t SoftKeymasterDevice::attest_key(const keymaster2_device_t* dev } /* static */ +keymaster_error_t SoftKeymasterDevice::upgrade_key(const keymaster2_device_t* dev, + const keymaster_key_blob_t* key_to_upgrade, + const keymaster_key_param_set_t* upgrade_params, + keymaster_key_blob_t* upgraded_key) { + if (!dev || !key_to_upgrade || !upgrade_params) + return KM_ERROR_UNEXPECTED_NULL_POINTER; + + if (!upgraded_key) + return KM_ERROR_OUTPUT_PARAMETER_NULL; + + if (!convert_device(dev)->configured()) + return KM_ERROR_KEYMASTER_NOT_CONFIGURED; + + UpgradeKeyRequest request; + request.SetKeyMaterial(*key_to_upgrade); + request.upgrade_params.Reinitialize(*upgrade_params); + + UpgradeKeyResponse response; + convert_device(dev)->impl_->UpgradeKey(request, &response); + if (response.error != KM_ERROR_OK) + return response.error; + + upgraded_key->key_material_size = response.upgraded_key.key_material_size; + uint8_t* tmp = reinterpret_cast<uint8_t*>(malloc(upgraded_key->key_material_size)); + if (!tmp) + return KM_ERROR_MEMORY_ALLOCATION_FAILED; + memcpy(tmp, response.upgraded_key.key_material, response.upgraded_key.key_material_size); + upgraded_key->key_material = tmp; + + return KM_ERROR_OK; +} + +/* static */ keymaster_error_t SoftKeymasterDevice::delete_key(const keymaster1_device_t* dev, const keymaster_key_blob_t* key) { if (!dev || !key || !key->key_material) @@ -1040,6 +1140,9 @@ keymaster_error_t SoftKeymasterDevice::delete_key(const keymaster2_device_t* dev if (!dev || !key || !key->key_material) return KM_ERROR_UNEXPECTED_NULL_POINTER; + if (!convert_device(dev)->configured()) + return KM_ERROR_KEYMASTER_NOT_CONFIGURED; + KeymasterKeyBlob blob(*key); return convert_device(dev)->context_->DeleteKey(blob); } @@ -1057,6 +1160,9 @@ keymaster_error_t SoftKeymasterDevice::delete_all_keys(const keymaster2_device_t if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER; + if (!convert_device(dev)->configured()) + return KM_ERROR_KEYMASTER_NOT_CONFIGURED; + return convert_device(dev)->context_->DeleteAllKeys(); } @@ -1126,6 +1232,9 @@ keymaster_error_t SoftKeymasterDevice::begin(const keymaster2_device_t* dev, if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER; + if (!convert_device(dev)->configured()) + return KM_ERROR_KEYMASTER_NOT_CONFIGURED; + SoftKeymasterDevice* sk_dev = convert_device(dev); return begin(&sk_dev->km1_device_, purpose, key, in_params, out_params, operation_handle); } @@ -1204,6 +1313,9 @@ keymaster_error_t SoftKeymasterDevice::update(const keymaster2_device_t* dev, if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER; + if (!convert_device(dev)->configured()) + return KM_ERROR_KEYMASTER_NOT_CONFIGURED; + SoftKeymasterDevice* sk_dev = convert_device(dev); return update(&sk_dev->km1_device_, operation_handle, in_params, input, input_consumed, out_params, output); @@ -1276,6 +1388,9 @@ keymaster_error_t SoftKeymasterDevice::finish(const keymaster2_device_t* dev, if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER; + if (!convert_device(dev)->configured()) + return KM_ERROR_KEYMASTER_NOT_CONFIGURED; + if (input && input->data) return KM_ERROR_UNIMPLEMENTED; // TODO(swillden): Implement this @@ -1307,6 +1422,9 @@ keymaster_error_t SoftKeymasterDevice::abort(const keymaster2_device_t* dev, if (!dev) return KM_ERROR_UNEXPECTED_NULL_POINTER; + if (!convert_device(dev)->configured()) + return KM_ERROR_KEYMASTER_NOT_CONFIGURED; + SoftKeymasterDevice* sk_dev = convert_device(dev); return abort(&sk_dev->km1_device_, operation_handle); } |
