| // Copyright (c) 2012 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. |
| |
| // Unit tests for VaultKeyset. |
| |
| #include "cryptohome/vault_keyset.h" |
| |
| #include <string.h> // For memcmp(). |
| |
| #include <base/files/file_path.h> |
| #include <base/logging.h> |
| #include <brillo/secure_blob.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "cryptohome/crypto.h" |
| #include "cryptohome/cryptohome_common.h" |
| #include "cryptohome/mock_platform.h" |
| |
| namespace cryptohome { |
| using base::FilePath; |
| using brillo::SecureBlob; |
| |
| using ::testing::_; |
| using ::testing::Return; |
| using ::testing::SaveArg; |
| using ::testing::SetArgPointee; |
| using ::testing::WithArg; |
| |
| class VaultKeysetTest : public ::testing::Test { |
| public: |
| VaultKeysetTest() {} |
| VaultKeysetTest(const VaultKeysetTest&) = delete; |
| VaultKeysetTest& operator=(const VaultKeysetTest&) = delete; |
| |
| virtual ~VaultKeysetTest() {} |
| |
| static bool FindBlobInBlob(const brillo::SecureBlob& haystack, |
| const brillo::SecureBlob& needle) { |
| if (needle.size() > haystack.size()) { |
| return false; |
| } |
| for (unsigned int start = 0; start <= (haystack.size() - needle.size()); |
| start++) { |
| if (memcmp(&haystack[start], needle.data(), needle.size()) == 0) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| protected: |
| MockPlatform platform_; |
| }; |
| |
| TEST_F(VaultKeysetTest, AllocateRandom) { |
| // Check that allocating a random VaultKeyset works |
| Crypto crypto(&platform_); |
| VaultKeyset vault_keyset; |
| vault_keyset.Initialize(&platform_, &crypto); |
| vault_keyset.CreateRandom(); |
| |
| EXPECT_EQ(CRYPTOHOME_DEFAULT_KEY_SIZE, vault_keyset.GetFek().size()); |
| EXPECT_EQ(CRYPTOHOME_DEFAULT_KEY_SIGNATURE_SIZE, |
| vault_keyset.GetFekSig().size()); |
| EXPECT_EQ(CRYPTOHOME_DEFAULT_KEY_SALT_SIZE, vault_keyset.GetFekSalt().size()); |
| |
| EXPECT_EQ(CRYPTOHOME_DEFAULT_KEY_SIZE, vault_keyset.GetFnek().size()); |
| EXPECT_EQ(CRYPTOHOME_DEFAULT_KEY_SIGNATURE_SIZE, |
| vault_keyset.GetFnekSig().size()); |
| EXPECT_EQ(CRYPTOHOME_DEFAULT_KEY_SALT_SIZE, |
| vault_keyset.GetFnekSalt().size()); |
| EXPECT_EQ(CRYPTOHOME_CHAPS_KEY_LENGTH, vault_keyset.GetChapsKey().size()); |
| } |
| |
| TEST_F(VaultKeysetTest, SerializeTest) { |
| // Check that serialize works |
| Crypto crypto(&platform_); |
| VaultKeyset vault_keyset; |
| vault_keyset.Initialize(&platform_, &crypto); |
| vault_keyset.CreateRandom(); |
| |
| SecureBlob blob; |
| EXPECT_TRUE(vault_keyset.ToKeysBlob(&blob)); |
| |
| EXPECT_TRUE(VaultKeysetTest::FindBlobInBlob(blob, vault_keyset.GetFek())); |
| EXPECT_TRUE(VaultKeysetTest::FindBlobInBlob(blob, vault_keyset.GetFekSig())); |
| EXPECT_TRUE(VaultKeysetTest::FindBlobInBlob(blob, vault_keyset.GetFekSalt())); |
| |
| EXPECT_TRUE(VaultKeysetTest::FindBlobInBlob(blob, vault_keyset.GetFnek())); |
| EXPECT_TRUE(VaultKeysetTest::FindBlobInBlob(blob, vault_keyset.GetFnekSig())); |
| EXPECT_TRUE( |
| VaultKeysetTest::FindBlobInBlob(blob, vault_keyset.GetFnekSalt())); |
| } |
| |
| TEST_F(VaultKeysetTest, DeserializeTest) { |
| // Check that deserialize works |
| Crypto crypto(&platform_); |
| VaultKeyset vault_keyset; |
| vault_keyset.Initialize(&platform_, &crypto); |
| vault_keyset.CreateRandom(); |
| |
| SecureBlob blob; |
| EXPECT_TRUE(vault_keyset.ToKeysBlob(&blob)); |
| |
| VaultKeyset new_vault_keyset; |
| new_vault_keyset.FromKeysBlob(blob); |
| |
| EXPECT_EQ(vault_keyset.GetFek().size(), new_vault_keyset.GetFek().size()); |
| EXPECT_TRUE(VaultKeysetTest::FindBlobInBlob(vault_keyset.GetFek(), |
| new_vault_keyset.GetFek())); |
| EXPECT_EQ(vault_keyset.GetFekSig().size(), |
| new_vault_keyset.GetFekSig().size()); |
| EXPECT_TRUE(VaultKeysetTest::FindBlobInBlob(vault_keyset.GetFekSig(), |
| new_vault_keyset.GetFekSig())); |
| EXPECT_EQ(vault_keyset.GetFekSalt().size(), |
| new_vault_keyset.GetFekSalt().size()); |
| EXPECT_TRUE(VaultKeysetTest::FindBlobInBlob(vault_keyset.GetFekSalt(), |
| new_vault_keyset.GetFekSalt())); |
| |
| EXPECT_EQ(vault_keyset.GetFnek().size(), new_vault_keyset.GetFnek().size()); |
| EXPECT_TRUE(VaultKeysetTest::FindBlobInBlob(vault_keyset.GetFnek(), |
| new_vault_keyset.GetFnek())); |
| EXPECT_EQ(vault_keyset.GetFnekSig().size(), |
| new_vault_keyset.GetFnekSig().size()); |
| EXPECT_TRUE(VaultKeysetTest::FindBlobInBlob(vault_keyset.GetFnekSig(), |
| new_vault_keyset.GetFnekSig())); |
| EXPECT_EQ(vault_keyset.GetFnekSalt().size(), |
| new_vault_keyset.GetFnekSalt().size()); |
| EXPECT_TRUE(VaultKeysetTest::FindBlobInBlob(vault_keyset.GetFnekSalt(), |
| new_vault_keyset.GetFnekSalt())); |
| } |
| |
| ACTION_P(CopyToSecureBlob, b) { |
| b->assign(arg0.begin(), arg0.end()); |
| return true; |
| } |
| |
| ACTION_P(CopyFromSecureBlob, b) { |
| arg0->assign(b->begin(), b->end()); |
| return true; |
| } |
| |
| TEST_F(VaultKeysetTest, LoadSaveTest) { |
| MockPlatform platform; |
| Crypto crypto(&platform); |
| VaultKeyset keyset; |
| keyset.Initialize(&platform, &crypto); |
| |
| keyset.CreateRandom(); |
| SecureBlob bytes; |
| |
| static const int kTestTimestamp = 123; |
| static const int kFscryptPolicyVersion = 2; |
| cryptohome::Timestamp timestamp; |
| timestamp.set_timestamp(kTestTimestamp); |
| SecureBlob tbytes(timestamp.ByteSizeLong()); |
| google::protobuf::uint8* buf = |
| static_cast<google::protobuf::uint8*>(tbytes.data()); |
| timestamp.SerializeWithCachedSizesToArray(buf); |
| |
| keyset.SetFscryptPolicyVersion(kFscryptPolicyVersion); |
| |
| EXPECT_CALL(platform, WriteFileAtomicDurable(FilePath("foo"), _, _)) |
| .WillOnce(WithArg<1>(CopyToSecureBlob(&bytes))); |
| EXPECT_CALL(platform, ReadFile(FilePath("foo"), _)) |
| .WillOnce(WithArg<1>(CopyFromSecureBlob(&bytes))); |
| |
| EXPECT_CALL(platform, ReadFile(FilePath("foo").AddExtension("timestamp"), _)) |
| .WillOnce(WithArg<1>(CopyFromSecureBlob(&tbytes))); |
| |
| SecureBlob key("key"); |
| EXPECT_TRUE(keyset.Encrypt(key, "")); |
| EXPECT_TRUE(keyset.Save(FilePath("foo"))); |
| |
| VaultKeyset new_keyset; |
| new_keyset.Initialize(&platform, &crypto); |
| EXPECT_TRUE(new_keyset.Load(FilePath("foo"))); |
| ASSERT_TRUE(new_keyset.HasLastActivityTimestamp()); |
| EXPECT_EQ(kTestTimestamp, new_keyset.GetLastActivityTimestamp()); |
| EXPECT_TRUE(new_keyset.Decrypt(key, false /* locked_to_single_user */, |
| nullptr /* crypto_error */)); |
| EXPECT_EQ(new_keyset.GetFscryptPolicyVersion(), kFscryptPolicyVersion); |
| } |
| |
| TEST_F(VaultKeysetTest, WriteError) { |
| MockPlatform platform; |
| Crypto crypto(&platform); |
| VaultKeyset keyset; |
| keyset.Initialize(&platform, &crypto); |
| |
| keyset.CreateRandom(); |
| SecureBlob bytes; |
| |
| EXPECT_CALL(platform, WriteFileAtomicDurable(FilePath("foo"), _, _)) |
| .WillOnce(Return(false)); |
| |
| SecureBlob key("key"); |
| EXPECT_TRUE(keyset.Encrypt(key, "")); |
| EXPECT_FALSE(keyset.Save(FilePath("foo"))); |
| } |
| |
| TEST_F(VaultKeysetTest, AuthLockedDefault) { |
| MockPlatform platform; |
| Crypto crypto(&platform); |
| VaultKeyset keyset; |
| keyset.Initialize(&platform, &crypto); |
| |
| static const int kFscryptPolicyVersion = 2; |
| |
| keyset.CreateRandom(); |
| keyset.SetFscryptPolicyVersion(kFscryptPolicyVersion); |
| keyset.SetFlags(SerializedVaultKeyset::LE_CREDENTIAL); |
| |
| SecureBlob key("key"); |
| EXPECT_TRUE(keyset.Encrypt(key, "")); |
| EXPECT_FALSE(keyset.GetAuthLocked()); |
| } |
| |
| TEST_F(VaultKeysetTest, GetPcrBoundAuthBlockStateTest) { |
| MockPlatform platform; |
| Crypto crypto(&platform); |
| VaultKeyset keyset; |
| keyset.Initialize(&platform, &crypto); |
| |
| keyset.CreateRandom(); |
| keyset.SetFlags(SerializedVaultKeyset::TPM_WRAPPED | |
| SerializedVaultKeyset::SCRYPT_DERIVED | |
| SerializedVaultKeyset::PCR_BOUND); |
| keyset.SetTpmPublicKeyHash(brillo::SecureBlob("yadayada")); |
| keyset.SetTPMKey(brillo::SecureBlob("blabla")); |
| keyset.SetExtendedTPMKey(brillo::SecureBlob("foobaz")); |
| |
| AuthBlockState auth_state; |
| EXPECT_TRUE(keyset.GetAuthBlockState(&auth_state)); |
| |
| EXPECT_TRUE(auth_state.has_tpm_bound_to_pcr_state()); |
| EXPECT_TRUE(auth_state.tpm_bound_to_pcr_state().scrypt_derived()); |
| EXPECT_TRUE(auth_state.tpm_bound_to_pcr_state().has_extended_tpm_key()); |
| EXPECT_TRUE(auth_state.tpm_bound_to_pcr_state().has_tpm_key()); |
| } |
| |
| TEST_F(VaultKeysetTest, GetNotPcrBoundAuthBlockState) { |
| MockPlatform platform; |
| Crypto crypto(&platform); |
| VaultKeyset keyset; |
| keyset.Initialize(&platform, &crypto); |
| |
| keyset.CreateRandom(); |
| keyset.SetFlags(SerializedVaultKeyset::TPM_WRAPPED); |
| keyset.SetTpmPublicKeyHash(brillo::SecureBlob("yadayada")); |
| keyset.SetTPMKey(brillo::SecureBlob("blabla")); |
| |
| AuthBlockState auth_state; |
| EXPECT_TRUE(keyset.GetAuthBlockState(&auth_state)); |
| |
| EXPECT_TRUE(auth_state.has_tpm_not_bound_to_pcr_state()); |
| EXPECT_FALSE(auth_state.tpm_not_bound_to_pcr_state().scrypt_derived()); |
| EXPECT_TRUE(auth_state.tpm_not_bound_to_pcr_state().has_tpm_key()); |
| } |
| |
| TEST_F(VaultKeysetTest, GetPinWeaverAuthBlockState) { |
| MockPlatform platform; |
| Crypto crypto(&platform); |
| VaultKeyset keyset; |
| keyset.Initialize(&platform, &crypto); |
| |
| const uint64_t le_label = 012345; |
| keyset.CreateRandom(); |
| keyset.SetFlags(SerializedVaultKeyset::LE_CREDENTIAL); |
| keyset.SetLELabel(le_label); |
| |
| AuthBlockState auth_state; |
| EXPECT_TRUE(keyset.GetAuthBlockState(&auth_state)); |
| |
| EXPECT_TRUE(auth_state.has_pin_weaver_state()); |
| EXPECT_TRUE(auth_state.pin_weaver_state().has_le_label()); |
| EXPECT_EQ(le_label, auth_state.pin_weaver_state().le_label()); |
| } |
| |
| TEST_F(VaultKeysetTest, GetChallengeCredentialAuthBlockState) { |
| MockPlatform platform; |
| Crypto crypto(&platform); |
| VaultKeyset keyset; |
| keyset.Initialize(&platform, &crypto); |
| |
| keyset.CreateRandom(); |
| keyset.SetFlags(SerializedVaultKeyset::SCRYPT_WRAPPED | |
| SerializedVaultKeyset::SIGNATURE_CHALLENGE_PROTECTED); |
| |
| AuthBlockState auth_state; |
| EXPECT_TRUE(keyset.GetAuthBlockState(&auth_state)); |
| |
| EXPECT_TRUE(auth_state.has_challenge_credential_state()); |
| } |
| |
| TEST_F(VaultKeysetTest, GetLibscryptCompatAuthBlockState) { |
| MockPlatform platform; |
| Crypto crypto(&platform); |
| VaultKeyset keyset; |
| keyset.Initialize(&platform, &crypto); |
| |
| keyset.CreateRandom(); |
| keyset.SetFlags(SerializedVaultKeyset::SCRYPT_WRAPPED); |
| |
| AuthBlockState auth_state; |
| EXPECT_TRUE(keyset.GetAuthBlockState(&auth_state)); |
| |
| EXPECT_TRUE(auth_state.has_libscrypt_compat_state()); |
| } |
| |
| } // namespace cryptohome |