| // Copyright 2019 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "cryptohome/pinweaver_le_credential_backend.h" |
| |
| #include <string> |
| |
| #include <trunks/tpm_pinweaver.h> |
| |
| #include <brillo/secure_blob.h> |
| #include <gtest/gtest.h> |
| |
| #include "cryptohome/pinweaver.pb.h" |
| #include "cryptohome/tpm2_impl.h" |
| |
| namespace cryptohome { |
| |
| namespace { |
| // see pinweaver.h for struct leaf_sensitive_data_t |
| constexpr uint32_t kLeafSensitiveDataSize = 3 * PW_SECRET_SIZE; |
| } // namespace |
| |
| // If these change MetadataBuilder need to be updated |
| static_assert(56 == offsetof(unimported_leaf_data_t, payload), |
| "Changed unimported_leaf_data_t layout"); |
| static_assert(220 == sizeof(leaf_public_data_t), |
| "Changed leaf_public_data_t size"); |
| |
| // Can build cred_metadata for versions 0.0 and 0.1 |
| class MetadataBuilder { |
| public: |
| MetadataBuilder(uint16_t major, uint16_t minor) { |
| this->version.major = major; |
| this->version.minor = minor; |
| memset(&data, 0, sizeof(data)); |
| } |
| |
| MetadataBuilder& SetAttemptCount(uint32_t value) { |
| data.attempt_count.v = value; |
| return *this; |
| } |
| |
| MetadataBuilder& SetValidPCRValueBitmask(uint8_t index, |
| uint8_t b0, |
| uint8_t b1) { |
| EXPECT_LT(index, PW_MAX_PCR_CRITERIA_COUNT); |
| data.valid_pcr_criteria[index].bitmask[0] = b0; |
| data.valid_pcr_criteria[index].bitmask[1] = b1; |
| return *this; |
| } |
| |
| std::vector<uint8_t> write() { |
| EXPECT_TRUE((version.major == 0 && version.minor == 1) || |
| (version.major == 0 && version.minor == 0)); |
| |
| std::vector<uint8_t> ret(sizeof(unimported_leaf_data_t) + |
| sizeof(leaf_public_data_t) + |
| kLeafSensitiveDataSize, |
| 0); |
| |
| unimported_leaf_data_t header; |
| memset(&header, 0, sizeof(header)); |
| |
| header.head.leaf_version = version; |
| header.head.pub_len = sizeof(struct leaf_public_data_t); |
| header.head.sec_len = kLeafSensitiveDataSize; |
| |
| // Remove field added in version 0.1 |
| if (version.major == 0 && version.minor == 0) |
| header.head.pub_len -= |
| sizeof(struct valid_pcr_value_t[PW_MAX_PCR_CRITERIA_COUNT]); |
| |
| uint8_t* target = ret.data(); |
| |
| memcpy(target, &header, sizeof(header)); |
| memcpy(target + offsetof(unimported_leaf_data_t, payload), &data, |
| header.head.pub_len); |
| memset(target + offsetof(unimported_leaf_data_t, payload) + |
| header.head.pub_len, |
| 0, header.head.sec_len); |
| |
| return ret; |
| } |
| |
| private: |
| struct leaf_version_t version; |
| struct leaf_public_data_t data; |
| }; |
| |
| // Using MetadataBuilder we test the behaviour of functions for all |
| // possible metadata versions |
| |
| // CHANGES |
| // 0.0 Initial version |
| // 0.1 valid_pcr_value_t field is added to leaf_public_data_t |
| |
| TEST(PinweaverLECredentialBackend, NeedsPCRBinding) { |
| // The field valid_pcr_value_t was added in 0.1 |
| // Version 0.0 should always return true |
| |
| Tpm2Impl tpm; |
| PinweaverLECredentialBackend backend(&tpm); |
| |
| { |
| // Metadata too short |
| std::vector<uint8_t> s(10); |
| |
| EXPECT_TRUE(backend.NeedsPCRBinding(s)); |
| } |
| |
| { |
| std::vector<uint8_t> v_0_0 = |
| MetadataBuilder(0, 0).SetValidPCRValueBitmask(0, 0, 0).write(); |
| |
| EXPECT_TRUE(backend.NeedsPCRBinding(v_0_0)); |
| |
| v_0_0 = MetadataBuilder(0, 0) |
| .SetValidPCRValueBitmask(0, 1, 1) // Value should be ignored |
| .write(); |
| |
| EXPECT_TRUE(backend.NeedsPCRBinding(v_0_0)); |
| } |
| |
| { |
| std::vector<uint8_t> v_0_1 = |
| MetadataBuilder(0, 1).SetValidPCRValueBitmask(0, 0, 0).write(); |
| |
| EXPECT_TRUE(backend.NeedsPCRBinding(v_0_1)); |
| |
| v_0_1 = |
| MetadataBuilder(0, 1) |
| .SetValidPCRValueBitmask(0, 0, 1) // Value should not be ignored |
| .write(); |
| |
| EXPECT_FALSE(backend.NeedsPCRBinding(v_0_1)); |
| |
| v_0_1 = |
| MetadataBuilder(0, 1) |
| .SetValidPCRValueBitmask(0, 1, 0) // Value should not be ignored |
| .write(); |
| |
| EXPECT_FALSE(backend.NeedsPCRBinding(v_0_1)); |
| } |
| } |
| |
| TEST(PinweaverLECredentialBackend, GetWrongAuthAttempts) { |
| // No changes should affect GetWrongAuthAttempts |
| |
| Tpm2Impl tpm; |
| PinweaverLECredentialBackend backend(&tpm); |
| |
| { |
| // Metadata too short |
| std::vector<uint8_t> s(10); |
| |
| EXPECT_EQ(-1, backend.GetWrongAuthAttempts(s)); |
| } |
| |
| { |
| std::vector<uint8_t> v_0_0 = |
| MetadataBuilder(0, 0).SetAttemptCount(5).write(); |
| |
| EXPECT_EQ(5, backend.GetWrongAuthAttempts(v_0_0)); |
| } |
| |
| { |
| std::vector<uint8_t> v_0_1 = |
| MetadataBuilder(0, 1).SetAttemptCount(7).write(); |
| |
| EXPECT_EQ(7, backend.GetWrongAuthAttempts(v_0_1)); |
| } |
| } |
| |
| } // namespace cryptohome |