blob: 1148b837002970ee85f72f57fcb9a306c606babe [file] [log] [blame]
// 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));
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