summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Willden <swillden@google.com>2016-03-09 20:03:38 -0700
committerShawn Willden <swillden@google.com>2016-03-29 18:08:38 -0600
commitc15af1910d8f451341d0068b5533816ace5defec (patch)
treea99c6cb8bca8659b34871c02693001c8efdc8f3e
parent3609584c328ea66f95478dded394ad4697779450 (diff)
downloadandroid_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.mk5
-rw-r--r--Makefile18
-rw-r--r--android_keymaster.cpp41
-rw-r--r--android_keymaster_messages.cpp38
-rw-r--r--android_keymaster_messages_test.cpp30
-rw-r--r--android_keymaster_test.cpp197
-rw-r--r--android_keymaster_test_utils.cpp11
-rw-r--r--android_keymaster_test_utils.h6
-rw-r--r--attestation_record.cpp2
-rw-r--r--attestation_record_test.cpp14
-rw-r--r--authorization_set.cpp14
-rw-r--r--include/keymaster/android_keymaster.h1
-rw-r--r--include/keymaster/android_keymaster_messages.h33
-rw-r--r--include/keymaster/authorization_set.h2
-rw-r--r--include/keymaster/keymaster_configuration.h51
-rw-r--r--include/keymaster/keymaster_context.h25
-rw-r--r--include/keymaster/soft_keymaster_context.h12
-rw-r--r--include/keymaster/soft_keymaster_device.h9
-rw-r--r--keymaster_configuration.cpp127
-rw-r--r--keymaster_configuration_test.cpp68
-rw-r--r--soft_keymaster_context.cpp98
-rw-r--r--soft_keymaster_device.cpp144
22 files changed, 906 insertions, 40 deletions
diff --git a/Android.mk b/Android.mk
index 233ed95..3e3a25b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -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
diff --git a/Makefile b/Makefile
index b9db15b..656c4e5 100644
--- a/Makefile
+++ b/Makefile
@@ -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(&regex, kPlatformVersionRegex, REG_EXTENDED)) {
+ ALOGE("Failed to compile version regex! (%s)", kPlatformVersionRegex);
+ return 0;
+ }
+
+ regmatch_t matches[kPlatformVersionMatchCount];
+ if (regexec(&regex, 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(&regex, kPlatformPatchlevelRegex, REG_EXTENDED) != 0) {
+ ALOGE("Failed to compile platform patchlevel regex! (%s)", kPlatformPatchlevelRegex);
+ return 0;
+ }
+
+ regmatch_t matches[kPlatformPatchlevelMatchCount];
+ if (regexec(&regex, 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);
}