summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Bires <jbires@google.com>2022-03-22 23:43:41 -0700
committerMax Bires <jbires@google.com>2022-03-24 21:08:09 -0700
commit5569b04a43855707b9ff2586f3d6bedd375a9f03 (patch)
treede3b8d8657128cd8ac8623b08c0bb8c4768ab60f
parent00c493e49cce34dcb757f2eed28d736b2b45cb86 (diff)
downloadkeymaster-5569b04a43855707b9ff2586f3d6bedd375a9f03.tar.gz
Add version and impl info field to EncryptedKey
This change alters the EncryptedKey struct to provide the ability to version the KDF used to derive the key to wrap the EncryptedKey with. Additionally, it adds an addl_info field to allow the implementor to specify any other information they would like to attach to the key structure. Test: tbd Change-Id: I1a32556cdff371138118028772b773f5e9b22c61
-rw-r--r--include/keymaster/key_blob_utils/auth_encrypted_key_blob.h8
-rw-r--r--key_blob_utils/auth_encrypted_key_blob.cpp51
-rw-r--r--tests/Android.bp2
-rw-r--r--tests/key_blob_test.cpp44
4 files changed, 86 insertions, 19 deletions
diff --git a/include/keymaster/key_blob_utils/auth_encrypted_key_blob.h b/include/keymaster/key_blob_utils/auth_encrypted_key_blob.h
index b611d9c..ea9ff0f 100644
--- a/include/keymaster/key_blob_utils/auth_encrypted_key_blob.h
+++ b/include/keymaster/key_blob_utils/auth_encrypted_key_blob.h
@@ -34,6 +34,8 @@ enum AuthEncryptedBlobFormat : uint8_t {
AES_OCB = 0,
AES_GCM_WITH_SW_ENFORCED = 1,
AES_GCM_WITH_SECURE_DELETION = 2,
+ AES_GCM_WITH_SW_ENFORCED_VERSIONED = 3,
+ AES_GCM_WITH_SECURE_DELETION_VERSIONED = 4,
};
/**
@@ -69,6 +71,8 @@ struct EncryptedKey {
KeymasterKeyBlob ciphertext;
Buffer nonce;
Buffer tag;
+ uint32_t kdf_version;
+ int32_t addl_info;
};
struct DeserializedKey {
@@ -118,4 +122,8 @@ KmErrorOr<KeymasterKeyBlob> DecryptKey(const DeserializedKey& key, const Authori
const SecureDeletionData& secure_deletion_data,
const KeymasterKeyBlob& master_key);
+bool requiresSecureDeletion(const AuthEncryptedBlobFormat& fmt);
+
+bool isVersionedFormat(const AuthEncryptedBlobFormat& fmt);
+
} // namespace keymaster
diff --git a/key_blob_utils/auth_encrypted_key_blob.cpp b/key_blob_utils/auth_encrypted_key_blob.cpp
index e6ee3bf..3cdcf5c 100644
--- a/key_blob_utils/auth_encrypted_key_blob.cpp
+++ b/key_blob_utils/auth_encrypted_key_blob.cpp
@@ -51,7 +51,7 @@ KmErrorOr<Buffer> BuildDerivationInfo(const AuthEncryptedBlobFormat format, //
const AuthorizationSet& sw_enforced, //
const AuthorizationSet& hidden,
const SecureDeletionData& secure_deletion_data) {
- bool use_sdd = (format == AES_GCM_WITH_SECURE_DELETION);
+ bool use_sdd = requiresSecureDeletion(format);
size_t info_len =
hidden.SerializedSize() + hw_enforced.SerializedSize() + sw_enforced.SerializedSize();
@@ -204,13 +204,16 @@ KmErrorOr<KeymasterKeyBlob> SerializeAuthEncryptedBlob(const EncryptedKey& encry
const AuthorizationSet& hw_enforced,
const AuthorizationSet& sw_enforced,
uint32_t key_slot) {
- bool use_key_slot = (encrypted_key.format == AES_GCM_WITH_SECURE_DELETION);
+ bool use_key_slot = requiresSecureDeletion(encrypted_key.format);
size_t size = 1 /* version byte */ + encrypted_key.nonce.SerializedSize() +
encrypted_key.ciphertext.SerializedSize() + encrypted_key.tag.SerializedSize() +
hw_enforced.SerializedSize() + sw_enforced.SerializedSize();
if (use_key_slot) size += sizeof(key_slot);
-
+ if (isVersionedFormat(encrypted_key.format)) {
+ size += sizeof(encrypted_key.kdf_version);
+ size += sizeof(encrypted_key.addl_info);
+ }
KeymasterKeyBlob retval;
if (!retval.Reset(size)) return KM_ERROR_MEMORY_ALLOCATION_FAILED;
@@ -221,6 +224,10 @@ KmErrorOr<KeymasterKeyBlob> SerializeAuthEncryptedBlob(const EncryptedKey& encry
buf = encrypted_key.nonce.Serialize(buf, end);
buf = encrypted_key.ciphertext.Serialize(buf, end);
buf = encrypted_key.tag.Serialize(buf, end);
+ if (isVersionedFormat(encrypted_key.format)) {
+ buf = append_uint32_to_buf(buf, end, encrypted_key.kdf_version);
+ buf = append_uint32_to_buf(buf, end, encrypted_key.addl_info);
+ }
buf = hw_enforced.Serialize(buf, end);
buf = sw_enforced.Serialize(buf, end);
if (use_key_slot) buf = append_uint32_to_buf(buf, end, key_slot);
@@ -243,17 +250,28 @@ KmErrorOr<DeserializedKey> DeserializeAuthEncryptedBlob(const KeymasterKeyBlob&
retval.encrypted_key.format = static_cast<AuthEncryptedBlobFormat>(*(*buf_ptr)++);
if (!retval.encrypted_key.nonce.Deserialize(buf_ptr, end) || //
!retval.encrypted_key.ciphertext.Deserialize(buf_ptr, end) || //
- !retval.encrypted_key.tag.Deserialize(buf_ptr, end) || //
- !retval.hw_enforced.Deserialize(buf_ptr, end) || //
- !retval.sw_enforced.Deserialize(buf_ptr, end)) {
+ !retval.encrypted_key.tag.Deserialize(buf_ptr, end)) {
return KM_ERROR_INVALID_KEY_BLOB;
}
- if (retval.encrypted_key.format == AES_GCM_WITH_SECURE_DELETION &&
- !copy_uint32_from_buf(buf_ptr, end, &retval.key_slot)) {
+ if (isVersionedFormat(retval.encrypted_key.format)) {
+ if (!copy_uint32_from_buf(buf_ptr, end, &retval.encrypted_key.kdf_version) ||
+ !copy_uint32_from_buf(buf_ptr, end, &retval.encrypted_key.addl_info)) {
+ return KM_ERROR_INVALID_KEY_BLOB;
+ }
+ }
+
+ if (!retval.hw_enforced.Deserialize(buf_ptr, end) || //
+ !retval.sw_enforced.Deserialize(buf_ptr, end)) {
return KM_ERROR_INVALID_KEY_BLOB;
}
+ if (requiresSecureDeletion(retval.encrypted_key.format)) {
+ if (!copy_uint32_from_buf(buf_ptr, end, &retval.key_slot)) {
+ return KM_ERROR_INVALID_KEY_BLOB;
+ }
+ }
+
if (*buf_ptr != end) return KM_ERROR_INVALID_KEY_BLOB;
switch (retval.encrypted_key.format) {
@@ -266,6 +284,8 @@ KmErrorOr<DeserializedKey> DeserializeAuthEncryptedBlob(const KeymasterKeyBlob&
case AES_GCM_WITH_SW_ENFORCED:
case AES_GCM_WITH_SECURE_DELETION:
+ case AES_GCM_WITH_SW_ENFORCED_VERSIONED:
+ case AES_GCM_WITH_SECURE_DELETION_VERSIONED:
if (retval.encrypted_key.nonce.available_read() != kAesGcmNonceLength ||
retval.encrypted_key.tag.available_read() != kAesGcmTagLength) {
return KM_ERROR_INVALID_KEY_BLOB;
@@ -298,7 +318,9 @@ EncryptKey(const KeymasterKeyBlob& plaintext, AuthEncryptedBlobFormat format,
}
case AES_GCM_WITH_SW_ENFORCED:
- case AES_GCM_WITH_SECURE_DELETION: {
+ case AES_GCM_WITH_SECURE_DELETION:
+ case AES_GCM_WITH_SW_ENFORCED_VERSIONED:
+ case AES_GCM_WITH_SECURE_DELETION_VERSIONED: {
auto nonce = generate_nonce(random, kAesGcmNonceLength);
if (!nonce) return nonce.error();
return AesGcmEncryptKey(hw_enforced, sw_enforced, hidden, secure_deletion_data, master_key,
@@ -325,6 +347,8 @@ KmErrorOr<KeymasterKeyBlob> DecryptKey(const DeserializedKey& key, const Authori
case AES_GCM_WITH_SW_ENFORCED:
case AES_GCM_WITH_SECURE_DELETION:
+ case AES_GCM_WITH_SW_ENFORCED_VERSIONED:
+ case AES_GCM_WITH_SECURE_DELETION_VERSIONED:
return AesGcmDecryptKey(key, hidden, secure_deletion_data, master_key);
}
@@ -332,4 +356,13 @@ KmErrorOr<KeymasterKeyBlob> DecryptKey(const DeserializedKey& key, const Authori
return KM_ERROR_INVALID_KEY_BLOB;
}
+bool requiresSecureDeletion(const AuthEncryptedBlobFormat& fmt) {
+ return fmt == AES_GCM_WITH_SECURE_DELETION || fmt == AES_GCM_WITH_SECURE_DELETION_VERSIONED;
+}
+
+bool isVersionedFormat(const AuthEncryptedBlobFormat& fmt) {
+ return fmt == AES_GCM_WITH_SW_ENFORCED_VERSIONED ||
+ fmt == AES_GCM_WITH_SECURE_DELETION_VERSIONED;
+}
+
} // namespace keymaster
diff --git a/tests/Android.bp b/tests/Android.bp
index ea1c8e4..d5ea46b 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -9,7 +9,6 @@ package {
shared_test_libs = [
"libbase",
- "libcppbor_external",
"libcrypto",
"libcutils",
"libhidlbase",
@@ -21,6 +20,7 @@ shared_test_libs = [
]
static_test_libs = [
+ "libcppbor_external",
"libsoftkeymasterdevice",
"libcppcose_rkp",
]
diff --git a/tests/key_blob_test.cpp b/tests/key_blob_test.cpp
index b8ec193..f50d4fe 100644
--- a/tests/key_blob_test.cpp
+++ b/tests/key_blob_test.cpp
@@ -138,7 +138,8 @@ TEST_P(KeyBlobTest, EncryptDecrypt) {
ASSERT_TRUE(deserialized.isOk());
EXPECT_EQ(hw_enforced_, deserialized->hw_enforced);
EXPECT_EQ(sw_enforced_, deserialized->sw_enforced);
- if (GetParam() == AES_GCM_WITH_SECURE_DELETION) {
+ if (GetParam() == AES_GCM_WITH_SECURE_DELETION ||
+ GetParam() == AES_GCM_WITH_SECURE_DELETION_VERSIONED) {
EXPECT_EQ(key_slot, deserialized->key_slot);
} else {
EXPECT_EQ(0U, deserialized->key_slot);
@@ -379,7 +380,9 @@ TEST_P(KeyBlobTest, DupBufferToolarge) {
INSTANTIATE_TEST_SUITE_P(AllFormats, KeyBlobTest,
::testing::Values(AES_OCB, AES_GCM_WITH_SW_ENFORCED,
- AES_GCM_WITH_SECURE_DELETION),
+ AES_GCM_WITH_SECURE_DELETION,
+ AES_GCM_WITH_SW_ENFORCED_VERSIONED,
+ AES_GCM_WITH_SECURE_DELETION_VERSIONED),
[](const ::testing::TestParamInfo<KeyBlobTest::ParamType>& info) {
switch (info.param) {
case AES_OCB:
@@ -388,16 +391,39 @@ INSTANTIATE_TEST_SUITE_P(AllFormats, KeyBlobTest,
return "AES_GCM_WITH_SW_ENFORCED";
case AES_GCM_WITH_SECURE_DELETION:
return "AES_GCM_WITH_SECURE_DELETION";
+ case AES_GCM_WITH_SW_ENFORCED_VERSIONED:
+ return "AES_GCM_WITH_SW_ENFORCED_VERSIONED";
+ case AES_GCM_WITH_SECURE_DELETION_VERSIONED:
+ return "AES_GCM_WITH_SECURE_DELETION_VERSIONED";
}
CHECK(false) << "Shouldn't be able to get here";
return "Unexpected";
});
-// Tests that only apply to AES_GCM_WITH_SECURE_DELETION; we don't parameterize these.
using SecureDeletionTest = KeyBlobTest;
-TEST_F(SecureDeletionTest, WrongFactoryResetSecret) {
- ASSERT_EQ(KM_ERROR_OK, Encrypt(AES_GCM_WITH_SECURE_DELETION));
+INSTANTIATE_TEST_SUITE_P(SecureDeletionFormats, SecureDeletionTest,
+ ::testing::Values(AES_GCM_WITH_SECURE_DELETION,
+ AES_GCM_WITH_SECURE_DELETION_VERSIONED),
+ [](const ::testing::TestParamInfo<KeyBlobTest::ParamType>& info) {
+ switch (info.param) {
+ case AES_OCB:
+ return "AES_OCB";
+ case AES_GCM_WITH_SW_ENFORCED:
+ return "AES_GCM_WITH_SW_ENFORCED";
+ case AES_GCM_WITH_SECURE_DELETION:
+ return "AES_GCM_WITH_SECURE_DELETION";
+ case AES_GCM_WITH_SW_ENFORCED_VERSIONED:
+ return "AES_GCM_WITH_SW_ENFORCED_VERSIONED";
+ case AES_GCM_WITH_SECURE_DELETION_VERSIONED:
+ return "AES_GCM_WITH_SECURE_DELETION_VERSIONED";
+ }
+ CHECK(false) << "Shouldn't be able to get here";
+ return "Unexpected";
+ });
+
+TEST_P(SecureDeletionTest, WrongFactoryResetSecret) {
+ ASSERT_EQ(KM_ERROR_OK, Encrypt(GetParam()));
ASSERT_EQ(KM_ERROR_OK, Serialize());
SecureDeletionData wrong_secure_deletion(std::move(secure_deletion_data_));
@@ -410,8 +436,8 @@ TEST_F(SecureDeletionTest, WrongFactoryResetSecret) {
EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, result.error());
}
-TEST_F(SecureDeletionTest, WrongSecureDeletionSecret) {
- ASSERT_EQ(KM_ERROR_OK, Encrypt(AES_GCM_WITH_SECURE_DELETION));
+TEST_P(SecureDeletionTest, WrongSecureDeletionSecret) {
+ ASSERT_EQ(KM_ERROR_OK, Encrypt(GetParam()));
ASSERT_EQ(KM_ERROR_OK, Serialize());
SecureDeletionData wrong_secure_deletion(std::move(secure_deletion_data_));
@@ -424,8 +450,8 @@ TEST_F(SecureDeletionTest, WrongSecureDeletionSecret) {
EXPECT_EQ(KM_ERROR_INVALID_KEY_BLOB, result.error());
}
-TEST_F(SecureDeletionTest, WrongSecureDeletionKeySlot) {
- ASSERT_EQ(KM_ERROR_OK, Encrypt(AES_GCM_WITH_SECURE_DELETION));
+TEST_P(SecureDeletionTest, WrongSecureDeletionKeySlot) {
+ ASSERT_EQ(KM_ERROR_OK, Encrypt(GetParam()));
ASSERT_EQ(KM_ERROR_OK, Serialize());
SecureDeletionData wrong_secure_deletion(std::move(secure_deletion_data_));