blob: 09e4de8488ec45db1290c9b5849d21eda979c501 [file] [log] [blame]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include <string>
#include <utility>
#include <base/test/mock_callback.h>
#include <base/test/task_environment.h>
#include <brillo/cryptohome.h>
#include <brillo/secure_blob.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <libhwsec/frontend/cryptohome/mock_frontend.h>
#include <libhwsec/frontend/pinweaver/mock_frontend.h>
#include <libhwsec-foundation/error/testing_helper.h>
#include "cryptohome/auth_blocks/auth_block.h"
#include "cryptohome/auth_blocks/auth_block_utility_impl.h"
#include "cryptohome/auth_blocks/libscrypt_compat_auth_block.h"
#include "cryptohome/auth_factor/auth_factor_manager.h"
#include "cryptohome/auth_session_manager.h"
#include "cryptohome/cleanup/mock_user_oldest_activity_timestamp_manager.h"
#include "cryptohome/credentials.h"
#include "cryptohome/credentials_test_util.h"
#include "cryptohome/crypto.h"
#include "cryptohome/filesystem_layout.h"
#include "cryptohome/mock_cryptohome_keys_manager.h"
#include "cryptohome/mock_install_attributes.h"
#include "cryptohome/mock_keyset_management.h"
#include "cryptohome/mock_le_credential_manager.h"
#include "cryptohome/mock_pkcs11_init.h"
#include "cryptohome/mock_platform.h"
#include "cryptohome/mock_vault_keyset_factory.h"
#include "cryptohome/pkcs11/mock_pkcs11_token_factory.h"
#include "cryptohome/storage/mock_homedirs.h"
#include "cryptohome/user_secret_stash_storage.h"
#include "cryptohome/user_session/mock_user_session.h"
#include "cryptohome/user_session/mock_user_session_factory.h"
#include "cryptohome/user_session/user_session_map.h"
#include "cryptohome/userdataauth.h"
#include "cryptohome/vault_keyset.h"
namespace cryptohome {
using ::testing::_;
using ::testing::NiceMock;
using ::testing::NotNull;
using ::testing::Return;
using base::test::TaskEnvironment;
using brillo::cryptohome::home::SanitizeUserName;
using hwsec_foundation::error::testing::ReturnValue;
using hwsec_foundation::status::OkStatus;
namespace {
constexpr char kUsername[] = "foo@example.com";
constexpr char kPassword[] = "password";
} // namespace
namespace {
// TODO(b/233700483): Replace this with the mock auth block.
class FallbackVaultKeyset : public VaultKeyset {
protected:
std::unique_ptr<cryptohome::SyncAuthBlock> GetAuthBlockForCreation()
const override {
auto auth_block_for_creation = VaultKeyset::GetAuthBlockForCreation();
if (!auth_block_for_creation) {
return std::make_unique<LibScryptCompatAuthBlock>();
}
return auth_block_for_creation;
}
};
} // namespace
class AuthSessionTestWithKeysetManagement : public ::testing::Test {
public:
AuthSessionTestWithKeysetManagement()
: crypto_(&hwsec_,
&pinweaver_,
&cryptohome_keys_manager_,
/*recovery_hwsec=*/nullptr) {
// Setting HWSec Expectations.
EXPECT_CALL(hwsec_, IsEnabled()).WillRepeatedly(ReturnValue(true));
EXPECT_CALL(hwsec_, IsReady()).WillRepeatedly(ReturnValue(true));
EXPECT_CALL(hwsec_, IsSealingSupported()).WillRepeatedly(ReturnValue(true));
EXPECT_CALL(hwsec_, GetManufacturer())
.WillRepeatedly(ReturnValue(0x43524f53));
EXPECT_CALL(hwsec_, GetAuthValue(_, _))
.WillRepeatedly(ReturnValue(brillo::SecureBlob()));
EXPECT_CALL(hwsec_, SealWithCurrentUser(_, _, _))
.WillRepeatedly(ReturnValue(brillo::Blob()));
EXPECT_CALL(hwsec_, GetPubkeyHash(_))
.WillRepeatedly(ReturnValue(brillo::Blob()));
crypto_.set_le_manager_for_testing(
std::make_unique<MockLECredentialManager>());
DCHECK(crypto_.Init());
mock_vault_keyset_factory_ = new NiceMock<MockVaultKeysetFactory>();
ON_CALL(*mock_vault_keyset_factory_, New(&platform_, &crypto_))
.WillByDefault([this](auto, auto) {
auto* vk = new FallbackVaultKeyset();
vk->Initialize(&platform_, &crypto_);
return vk;
});
keyset_management_ = std::make_unique<KeysetManagement>(
&platform_, &crypto_, base::WrapUnique(mock_vault_keyset_factory_));
auth_block_utility_ = std::make_unique<AuthBlockUtilityImpl>(
keyset_management_.get(), &crypto_, &platform_);
auth_session_manager_ = std::make_unique<AuthSessionManager>(
&crypto_, &platform_, &user_session_map_, keyset_management_.get(),
auth_block_utility_.get(), &auth_factor_manager_,
&user_secret_stash_storage_);
// Initializing UserData class.
userdataauth_.set_platform(&platform_);
userdataauth_.set_homedirs(&homedirs_);
userdataauth_.set_user_session_factory(&user_session_factory_);
userdataauth_.set_keyset_management(keyset_management_.get());
userdataauth_.set_auth_factor_manager_for_testing(&auth_factor_manager_);
userdataauth_.set_user_secret_stash_storage_for_testing(
&user_secret_stash_storage_);
userdataauth_.set_auth_session_manager(auth_session_manager_.get());
userdataauth_.set_pkcs11_token_factory(&pkcs11_token_factory_);
userdataauth_.set_user_activity_timestamp_manager(
&user_activity_timestamp_manager_);
userdataauth_.set_install_attrs(&install_attrs_);
userdataauth_.set_mount_task_runner(
task_environment_.GetMainThreadTaskRunner());
userdataauth_.set_current_thread_id_for_test(
UserDataAuth::TestThreadId::kMountThread);
file_system_keyset_ = FileSystemKeyset::CreateRandom();
PrepareDirectoryStructure();
}
protected:
struct UserInfo {
std::string name;
std::string obfuscated;
brillo::SecureBlob passkey;
Credentials credentials;
base::FilePath homedir_path;
base::FilePath user_path;
};
void AddUser(const std::string& name, const std::string& password) {
std::string obfuscated = SanitizeUserName(name);
brillo::SecureBlob passkey(password);
Credentials credentials(name, passkey);
UserInfo info = {name,
obfuscated,
passkey,
credentials,
UserPath(obfuscated),
brillo::cryptohome::home::GetHashedUserPath(obfuscated)};
users_.push_back(info);
}
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.
for (const auto& user : users_) {
ASSERT_TRUE(platform_.CreateDirectory(user.homedir_path));
}
}
void KeysetSetUpWithoutKeyData() {
for (UserInfo& user : users_) {
FallbackVaultKeyset vk;
vk.Initialize(&platform_, &crypto_);
vk.CreateFromFileSystemKeyset(file_system_keyset_);
ASSERT_TRUE(vk.Encrypt(user.passkey, user.obfuscated).ok());
ASSERT_TRUE(
vk.Save(user.homedir_path.Append(kKeyFile).AddExtension("0")));
ASSERT_FALSE(vk.HasKeyData());
}
}
base::test::TaskEnvironment task_environment_;
NiceMock<MockPlatform> platform_;
NiceMock<hwsec::MockCryptohomeFrontend> hwsec_;
NiceMock<hwsec::MockPinWeaverFrontend> pinweaver_;
NiceMock<MockCryptohomeKeysManager> cryptohome_keys_manager_;
Crypto crypto_;
UserSessionMap user_session_map_;
FileSystemKeyset file_system_keyset_;
MockVaultKeysetFactory* mock_vault_keyset_factory_;
std::unique_ptr<KeysetManagement> keyset_management_;
NiceMock<MockHomeDirs> homedirs_;
NiceMock<MockUserSessionFactory> user_session_factory_;
std::unique_ptr<AuthBlockUtilityImpl> auth_block_utility_;
AuthFactorManager auth_factor_manager_{&platform_};
UserSecretStashStorage user_secret_stash_storage_{&platform_};
std::unique_ptr<AuthSessionManager> auth_session_manager_;
NiceMock<MockPkcs11TokenFactory> pkcs11_token_factory_;
NiceMock<MockUserOldestActivityTimestampManager>
user_activity_timestamp_manager_;
NiceMock<MockInstallAttributes> install_attrs_;
UserDataAuth userdataauth_;
// Store user info for users that will be setup.
std::vector<UserInfo> users_;
};
// This test checks if StartAuthSession can return keydataless keysets
// correctly.
TEST_F(AuthSessionTestWithKeysetManagement, StartAuthSessionWithoutKeyData) {
AddUser(kUsername, kPassword);
KeysetSetUpWithoutKeyData();
user_data_auth::StartAuthSessionRequest start_auth_session_req;
start_auth_session_req.mutable_account_id()->set_account_id(users_[0].name);
user_data_auth::StartAuthSessionReply auth_session_reply;
userdataauth_.StartAuthSession(
start_auth_session_req,
base::BindOnce(
[](user_data_auth::StartAuthSessionReply* auth_reply_ptr,
const user_data_auth::StartAuthSessionReply& reply) {
*auth_reply_ptr = reply;
},
base::Unretained(&auth_session_reply)));
EXPECT_EQ(auth_session_reply.error(),
user_data_auth::CRYPTOHOME_ERROR_NOT_SET);
std::optional<base::UnguessableToken> auth_session_id =
AuthSession::GetTokenFromSerializedString(
auth_session_reply.auth_session_id());
EXPECT_TRUE(auth_session_id.has_value());
EXPECT_THAT(userdataauth_.auth_session_manager_->FindAuthSession(
auth_session_id.value()),
NotNull());
EXPECT_FALSE(auth_session_reply.key_label_data().empty());
const auto& key_label_data = auth_session_reply.key_label_data();
ASSERT_THAT(key_label_data, testing::SizeIs(1));
EXPECT_THAT(key_label_data.begin()->first, "legacy-0");
}
} // namespace cryptohome