diff options
author | Max Bires <jbires@google.com> | 2022-03-22 23:43:41 -0700 |
---|---|---|
committer | Max Bires <jbires@google.com> | 2022-03-24 21:08:09 -0700 |
commit | 5569b04a43855707b9ff2586f3d6bedd375a9f03 (patch) | |
tree | de3b8d8657128cd8ac8623b08c0bb8c4768ab60f | |
parent | 00c493e49cce34dcb757f2eed28d736b2b45cb86 (diff) | |
download | keymaster-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.h | 8 | ||||
-rw-r--r-- | key_blob_utils/auth_encrypted_key_blob.cpp | 51 | ||||
-rw-r--r-- | tests/Android.bp | 2 | ||||
-rw-r--r-- | 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<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_)); |