From 5569b04a43855707b9ff2586f3d6bedd375a9f03 Mon Sep 17 00:00:00 2001 From: Max Bires Date: Tue, 22 Mar 2022 23:43:41 -0700 Subject: 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 --- .../key_blob_utils/auth_encrypted_key_blob.h | 8 ++++ key_blob_utils/auth_encrypted_key_blob.cpp | 51 ++++++++++++++++++---- tests/Android.bp | 2 +- tests/key_blob_test.cpp | 44 +++++++++++++++---- 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 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 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 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 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 DeserializeAuthEncryptedBlob(const KeymasterKeyBlob& retval.encrypted_key.format = static_cast(*(*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 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 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 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& 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& 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_)); -- cgit v1.2.3