| |
| // Copyright 2022 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/auth_factor_vault_keyset_converter.h" |
| |
| #include <stdint.h> |
| |
| #include <map> |
| #include <memory> |
| #include <vector> |
| |
| #include <base/check.h> |
| #include <brillo/cryptohome.h> |
| #include <cryptohome/proto_bindings/UserDataAuth.pb.h> |
| #include <cryptohome/proto_bindings/auth_factor.pb.h> |
| #include <cryptohome/proto_bindings/rpc.pb.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| #include <libhwsec-foundation/crypto/secure_blob_util.h> |
| |
| #include "cryptohome/auth_factor/auth_factor.h" |
| #include "cryptohome/auth_factor/auth_factor_label.h" |
| #include "cryptohome/auth_factor/auth_factor_type.h" |
| #include "cryptohome/credentials.h" |
| #include "cryptohome/crypto.h" |
| #include "cryptohome/filesystem_layout.h" |
| #include "cryptohome/key_objects.h" |
| #include "cryptohome/keyset_management.h" |
| #include "cryptohome/mock_crypto.h" |
| #include "cryptohome/mock_platform.h" |
| #include "cryptohome/mock_tpm.h" |
| #include "cryptohome/vault_keyset.h" |
| #include "cryptohome/vault_keyset.pb.h" |
| |
| using ::testing::NiceMock; |
| |
| namespace { |
| constexpr char kUsername[] = "user"; |
| constexpr char kPinLabel[] = "pin"; |
| constexpr char kLabel[] = "label0"; |
| constexpr char kLabel1[] = "label1"; |
| constexpr char kLabel2[] = "label2"; |
| constexpr char kUserPassword[] = "user_pass"; |
| |
| constexpr char kFirstIndice[] = "0"; |
| constexpr char kSecondIndice[] = "1"; |
| constexpr char kThirdIndice[] = "2"; |
| |
| } // namespace |
| |
| namespace cryptohome { |
| |
| class AuthFactorVaultKeysetConverterTest : public ::testing::Test { |
| public: |
| AuthFactorVaultKeysetConverterTest() : crypto_(&platform_) {} |
| |
| ~AuthFactorVaultKeysetConverterTest() override {} |
| |
| // Not copyable or movable |
| AuthFactorVaultKeysetConverterTest( |
| const AuthFactorVaultKeysetConverterTest&) = delete; |
| AuthFactorVaultKeysetConverterTest& operator=( |
| const AuthFactorVaultKeysetConverterTest&) = delete; |
| AuthFactorVaultKeysetConverterTest(AuthFactorVaultKeysetConverterTest&&) = |
| delete; |
| AuthFactorVaultKeysetConverterTest& operator=( |
| AuthFactorVaultKeysetConverterTest&&) = delete; |
| |
| void SetUp() override { |
| // Setup salt for brillo functions. |
| keyset_management_ = std::make_unique<KeysetManagement>( |
| &platform_, &crypto_, std::make_unique<VaultKeysetFactory>()); |
| converter_ = std::make_unique<AuthFactorVaultKeysetConverter>( |
| keyset_management_.get()); |
| file_system_keyset_ = FileSystemKeyset::CreateRandom(); |
| |
| AddUser(kUserPassword); |
| |
| PrepareDirectoryStructure(); |
| } |
| |
| protected: |
| NiceMock<MockPlatform> platform_; |
| Crypto crypto_; |
| FileSystemKeyset file_system_keyset_; |
| std::unique_ptr<KeysetManagement> keyset_management_; |
| std::unique_ptr<AuthFactorVaultKeysetConverter> converter_; |
| struct UserInfo { |
| std::string name; |
| std::string obfuscated; |
| brillo::SecureBlob passkey; |
| Credentials credentials; |
| base::FilePath homedir_path; |
| base::FilePath user_path; |
| }; |
| |
| UserInfo user; |
| |
| void AddUser(const char* password) { |
| std::string obfuscated = |
| brillo::cryptohome::home::SanitizeUserName(kUsername); |
| brillo::SecureBlob passkey(password); |
| Credentials credentials(kUsername, passkey); |
| |
| user = {kUsername, |
| obfuscated, |
| passkey, |
| credentials, |
| UserPath(obfuscated), |
| brillo::cryptohome::home::GetHashedUserPath(obfuscated)}; |
| } |
| |
| void PrepareDirectoryStructure() { |
| ASSERT_TRUE(platform_.CreateDirectory(ShadowRoot())); |
| ASSERT_TRUE(platform_.CreateDirectory( |
| brillo::cryptohome::home::GetUserPathPrefix())); |
| // We only need the homedir path, not the vault/mount paths. |
| ASSERT_TRUE(platform_.CreateDirectory(user.homedir_path)); |
| } |
| |
| KeyData SetKeyData(const std::string& label) { |
| KeyData key_data; |
| key_data.set_label(label); |
| return key_data; |
| } |
| |
| void KeysetSetUpWithKeyData(const KeyData& key_data, |
| const std::string& indice) { |
| VaultKeyset vk; |
| vk.Initialize(&platform_, &crypto_); |
| vk.CreateFromFileSystemKeyset(file_system_keyset_); |
| vk.SetKeyData(key_data); |
| user.credentials.set_key_data(key_data); |
| ASSERT_TRUE(vk.Encrypt(user.passkey, user.obfuscated).ok()); |
| ASSERT_TRUE( |
| vk.Save(user.homedir_path.Append(kKeyFile).AddExtension(indice))); |
| } |
| }; |
| |
| // Test that VaultKeysetsToAuthFactors return correct error when there is |
| // no VaultKeyset on the disk. |
| TEST_F(AuthFactorVaultKeysetConverterTest, |
| ConvertToAuthFactorFailWhenListEmpty) { |
| std::map<std::string, std::unique_ptr<AuthFactor>> label_to_auth_factor; |
| EXPECT_EQ( |
| user_data_auth::CRYPTOHOME_ERROR_KEY_NOT_FOUND, |
| converter_->VaultKeysetsToAuthFactors(kUsername, label_to_auth_factor)); |
| EXPECT_TRUE(label_to_auth_factor.empty()); |
| } |
| |
| // Test that VaultKeysetsToAuthFactors lists the existing VaultKeyset on |
| // the disk. |
| TEST_F(AuthFactorVaultKeysetConverterTest, ConvertToAuthFactorListSuccess) { |
| KeysetSetUpWithKeyData(SetKeyData(kLabel), kFirstIndice); |
| std::map<std::string, std::unique_ptr<AuthFactor>> label_to_auth_factor; |
| |
| EXPECT_EQ( |
| user_data_auth::CRYPTOHOME_ERROR_NOT_SET, |
| converter_->VaultKeysetsToAuthFactors(kUsername, label_to_auth_factor)); |
| EXPECT_FALSE(label_to_auth_factor.empty()); |
| EXPECT_EQ(kLabel, label_to_auth_factor[kLabel]->label()); |
| EXPECT_EQ(AuthFactorType::kPassword, label_to_auth_factor[kLabel]->type()); |
| } |
| |
| // Test that VaultKeysetsToAuthFactors lists all the VaultKeysets in the |
| // disk. |
| TEST_F(AuthFactorVaultKeysetConverterTest, |
| ConvertToAuthFactorListMultipleVaultKeysetsSuccess) { |
| KeysetSetUpWithKeyData(SetKeyData(kLabel), kFirstIndice); |
| KeysetSetUpWithKeyData(SetKeyData(kLabel1), kSecondIndice); |
| KeysetSetUpWithKeyData(SetKeyData(kLabel2), kThirdIndice); |
| |
| std::map<std::string, std::unique_ptr<AuthFactor>> label_to_auth_factor; |
| |
| EXPECT_EQ( |
| user_data_auth::CRYPTOHOME_ERROR_NOT_SET, |
| converter_->VaultKeysetsToAuthFactors(kUsername, label_to_auth_factor)); |
| EXPECT_EQ(3, label_to_auth_factor.size()); |
| |
| EXPECT_EQ(kLabel, label_to_auth_factor[kLabel]->label()); |
| EXPECT_EQ(AuthFactorType::kPassword, label_to_auth_factor[kLabel]->type()); |
| |
| EXPECT_EQ(kLabel1, label_to_auth_factor[kLabel1]->label()); |
| EXPECT_EQ(AuthFactorType::kPassword, label_to_auth_factor[kLabel1]->type()); |
| |
| EXPECT_EQ(kLabel2, label_to_auth_factor[kLabel2]->label()); |
| EXPECT_EQ(AuthFactorType::kPassword, label_to_auth_factor[kLabel2]->type()); |
| } |
| |
| // Test that PopulateKeyDataForVK returns correct KeyData for the given |
| // label. |
| TEST_F(AuthFactorVaultKeysetConverterTest, ConvertToVaultKeysetDataSuccess) { |
| KeyData test_key_data = SetKeyData(kLabel); |
| KeysetSetUpWithKeyData(test_key_data, kFirstIndice); |
| |
| KeyData key_data; |
| std::string auth_factor_label = kLabel; |
| EXPECT_EQ( |
| user_data_auth::CRYPTOHOME_ERROR_NOT_SET, |
| converter_->PopulateKeyDataForVK(kUsername, auth_factor_label, key_data)); |
| EXPECT_EQ(kLabel, key_data.label()); |
| } |
| |
| // Test that PopulateKeyDataForVK fails to return KeyData for a wrong given |
| // label. |
| TEST_F(AuthFactorVaultKeysetConverterTest, ConvertToVaultKeysetDataFail) { |
| KeyData test_key_data = SetKeyData(kLabel); |
| KeysetSetUpWithKeyData(test_key_data, kFirstIndice); |
| |
| KeyData key_data; |
| std::string auth_factor_label = kLabel1; |
| EXPECT_EQ( |
| user_data_auth::CRYPTOHOME_ERROR_KEY_NOT_FOUND, |
| converter_->PopulateKeyDataForVK(kUsername, auth_factor_label, key_data)); |
| } |
| |
| // Test that AuthFactorToKeyData generates correct KeyData for the given |
| // password label and type. |
| TEST_F(AuthFactorVaultKeysetConverterTest, GenerateKeyDataPassword) { |
| KeyData key_data = SetKeyData(kLabel); |
| key_data.set_type(KeyData::KEY_TYPE_PASSWORD); |
| |
| KeyData test_key_data; |
| std::string auth_factor_label = kLabel; |
| AuthFactorType auth_factor_type = AuthFactorType::kPassword; |
| |
| EXPECT_EQ(user_data_auth::CRYPTOHOME_ERROR_NOT_SET, |
| converter_->AuthFactorToKeyData(auth_factor_label, auth_factor_type, |
| test_key_data)); |
| EXPECT_EQ(key_data.label(), test_key_data.label()); |
| EXPECT_EQ(key_data.type(), test_key_data.type()); |
| EXPECT_FALSE(test_key_data.policy().low_entropy_credential()); |
| } |
| |
| // Test that AuthFactorToKeyData generates correct KeyData for the given |
| // password label and type. |
| TEST_F(AuthFactorVaultKeysetConverterTest, GenerateKeyDataPin) { |
| KeyData key_data = SetKeyData(kPinLabel); |
| key_data.set_type(KeyData::KEY_TYPE_PASSWORD); |
| key_data.mutable_policy()->set_low_entropy_credential(true); |
| |
| KeyData test_key_data; |
| std::string auth_factor_label = kPinLabel; |
| AuthFactorType auth_factor_type = AuthFactorType::kPin; |
| |
| EXPECT_EQ(user_data_auth::CRYPTOHOME_ERROR_NOT_SET, |
| converter_->AuthFactorToKeyData(auth_factor_label, auth_factor_type, |
| test_key_data)); |
| EXPECT_EQ(key_data.label(), test_key_data.label()); |
| EXPECT_EQ(key_data.type(), test_key_data.type()); |
| EXPECT_TRUE(test_key_data.policy().low_entropy_credential()); |
| } |
| |
| // Test that VaultKeysetToAuthFactor returns correct AuthFactor for the given |
| // label. |
| TEST_F(AuthFactorVaultKeysetConverterTest, VaultKeysetToAuthFactorSuccess) { |
| KeyData test_key_data = SetKeyData(kLabel); |
| KeysetSetUpWithKeyData(test_key_data, kFirstIndice); |
| |
| KeyData key_data; |
| std::string auth_factor_label = kLabel; |
| std::unique_ptr<AuthFactor> auth_factor = |
| converter_->VaultKeysetToAuthFactor(kUsername, auth_factor_label); |
| EXPECT_NE(nullptr, auth_factor); |
| EXPECT_EQ(kLabel, auth_factor->label()); |
| EXPECT_EQ(AuthFactorType::kPassword, auth_factor->type()); |
| } |
| |
| // Test that VaultKeysetToAuthFactor fails to return AuthFactor for a wrong |
| // given label. |
| TEST_F(AuthFactorVaultKeysetConverterTest, VaultKeysetToAuthFactorFail) { |
| KeyData test_key_data = SetKeyData(kLabel); |
| KeysetSetUpWithKeyData(test_key_data, kFirstIndice); |
| |
| KeyData key_data; |
| std::string auth_factor_label = kLabel1; |
| std::unique_ptr<AuthFactor> auth_factor = |
| converter_->VaultKeysetToAuthFactor(kUsername, auth_factor_label); |
| EXPECT_EQ(nullptr, auth_factor); |
| } |
| |
| } // namespace cryptohome |