Commit 9d78415f authored by Anatoliy Potapchuk's avatar Anatoliy Potapchuk Committed by Commit Bot

Adding means for RSU lookup key upload

This CL adds chrome-side implementation of the lookup keys(board_id,
device_id) required for Remote Server Unlock process.

Bug: 947743
Change-Id: Iac9eee4ac08453bb42d15078b05f65fd86db094b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1596748Reviewed-by: default avatarMaksim Ivanov <emaxx@chromium.org>
Reviewed-by: default avatarRyo Hashimoto <hashimoto@chromium.org>
Commit-Queue: Anatoliy Potapchuk <apotapchuk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#672068}
parent 05478bc7
......@@ -1701,6 +1701,8 @@ source_set("chromeos") {
"policy/remote_commands/user_command_arc_job.h",
"policy/remote_commands/user_commands_factory_chromeos.cc",
"policy/remote_commands/user_commands_factory_chromeos.h",
"policy/rsu/lookup_key_uploader.cc",
"policy/rsu/lookup_key_uploader.h",
"policy/secondary_google_account_signin_policy_handler.cc",
"policy/secondary_google_account_signin_policy_handler.h",
"policy/server_backed_device_state.cc",
......@@ -2585,6 +2587,7 @@ source_set("unit_tests") {
"policy/remote_commands/device_command_start_crd_session_unittest.cc",
"policy/remote_commands/device_command_wipe_users_job_unittest.cc",
"policy/remote_commands/user_command_arc_job_unittest.cc",
"policy/rsu/lookup_key_uploader_unittest.cc",
"policy/secondary_google_account_signin_policy_handler_unittest.cc",
"policy/server_backed_state_keys_broker_unittest.cc",
"policy/single_app_install_event_log_unittest.cc",
......
......@@ -30,6 +30,7 @@
#include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
#include "chrome/browser/chromeos/policy/heartbeat_scheduler.h"
#include "chrome/browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.h"
#include "chrome/browser/chromeos/policy/rsu/lookup_key_uploader.h"
#include "chrome/browser/chromeos/policy/server_backed_state_keys_broker.h"
#include "chrome/browser/chromeos/policy/status_collector/device_status_collector.h"
#include "chrome/browser/chromeos/policy/status_uploader.h"
......@@ -241,6 +242,7 @@ void DeviceCloudPolicyManagerChromeOS::RegisterPrefs(
registry->RegisterBooleanPref(prefs::kDeviceEnrollmentCanExit, true);
registry->RegisterDictionaryPref(prefs::kServerBackedDeviceState);
registry->RegisterBooleanPref(prefs::kRemoveUsersRemoteCommand, false);
registry->RegisterStringPref(prefs::kLastRsuDeviceIdUploaded, std::string());
}
// static
......@@ -305,6 +307,9 @@ void DeviceCloudPolicyManagerChromeOS::StartConnection(
new chromeos::attestation::EnrollmentCertificateUploaderImpl(client()));
enrollment_policy_observer_.reset(
new chromeos::attestation::EnrollmentPolicyObserver(client()));
lookup_key_uploader_.reset(
new LookupKeyUploader(device_store(), g_browser_process->local_state(),
enrollment_certificate_uploader_.get()));
// Don't create a MachineCertificateUploader or start the
// AttestationPolicyObserver if machine cert requests are disabled.
......
......@@ -47,6 +47,7 @@ class HeartbeatScheduler;
class SchemaRegistry;
class StatusUploader;
class SystemLogUploader;
class LookupKeyUploader;
enum class ZeroTouchEnrollmentMode { DISABLED, ENABLED, FORCED, HANDS_OFF };
......@@ -211,6 +212,9 @@ class DeviceCloudPolicyManagerChromeOS : public CloudPolicyManager {
std::unique_ptr<chromeos::attestation::AttestationPolicyObserver>
attestation_policy_observer_;
// Uploader for remote server unlock related lookup keys.
std::unique_ptr<LookupKeyUploader> lookup_key_uploader_;
// Wrapper schema registry that will track the signin profile schema registry
// once it is passed to this class.
std::unique_ptr<ForwardingSchemaRegistry>
......
// Copyright 2019 The Chromium 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 "chrome/browser/chromeos/policy/rsu/lookup_key_uploader.h"
#include "base/strings/strcat.h"
#include "base/task/post_task.h"
#include "base/time/default_clock.h"
#include "chrome/browser/chromeos/attestation/enrollment_certificate_uploader.h"
#include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
#include "chrome/common/pref_names.h"
#include "chromeos/dbus/cryptohome/cryptohome_client.h"
#include "chromeos/dbus/cryptohome/rpc.pb.h"
#include "components/policy/core/common/cloud/cloud_policy_client.h"
#include "components/prefs/pref_service.h"
namespace policy {
const base::TimeDelta LookupKeyUploader::kRetryFrequency =
base::TimeDelta::FromHours(10);
LookupKeyUploader::LookupKeyUploader(
DeviceCloudPolicyStoreChromeOS* policy_store,
PrefService* pref_service,
chromeos::attestation::EnrollmentCertificateUploader* certificate_uploader)
: policy_store_(policy_store),
prefs_(pref_service),
certificate_uploader_(certificate_uploader),
cryptohome_client_(chromeos::CryptohomeClient::Get()),
clock_(base::DefaultClock::GetInstance()),
weak_factory_(this) {
// Can be null in tests.
if (policy_store_)
policy_store_->AddObserver(this);
}
LookupKeyUploader::~LookupKeyUploader() {
// Can be null in tests.
if (policy_store_)
policy_store_->RemoveObserver(this);
}
void LookupKeyUploader::OnStoreLoaded(CloudPolicyStore* store) {
if (!needs_upload_ || clock_->Now() - last_upload_time_ < kRetryFrequency)
return;
needs_upload_ = false;
cryptohome_client_->WaitForServiceToBeAvailable(base::BindOnce(
&LookupKeyUploader::OnCryptohomeReady, weak_factory_.GetWeakPtr()));
}
void LookupKeyUploader::OnCryptohomeReady(bool available) {
if (!available) {
needs_upload_ = true;
return;
}
cryptohome_client_->GetRsuDeviceId(base::BindOnce(
&LookupKeyUploader::OnRsuDeviceIdReceived, weak_factory_.GetWeakPtr()));
}
void LookupKeyUploader::OnStoreError(CloudPolicyStore* store) {
// Do nothing.
}
void LookupKeyUploader::OnRsuDeviceIdReceived(
base::Optional<cryptohome::BaseReply> result) {
if (!result.has_value()) {
Result(std::string(), false /* success */);
return;
}
if (!result->HasExtension(cryptohome::GetRsuDeviceIdReply::reply) ||
!result->GetExtension(cryptohome::GetRsuDeviceIdReply::reply)
.has_rsu_device_id() ||
result->GetExtension(cryptohome::GetRsuDeviceIdReply::reply)
.rsu_device_id()
.empty()) {
LOG(ERROR) << "Failed to extract RSU lookup key.";
Result(std::string(), false /* success */);
return;
}
const std::string rsu_device_id =
result->GetExtension(cryptohome::GetRsuDeviceIdReply::reply)
.rsu_device_id();
// If this ID was uploaded previously -- we are not uploading it.
if (rsu_device_id == prefs_->GetString(prefs::kLastRsuDeviceIdUploaded))
return;
certificate_uploader_->ObtainAndUploadCertificate(base::BindOnce(
&LookupKeyUploader::Result, weak_factory_.GetWeakPtr(), rsu_device_id));
}
void LookupKeyUploader::Result(const std::string& uploaded_key, bool success) {
last_upload_time_ = clock_->Now();
if (success) {
prefs_->SetString(prefs::kLastRsuDeviceIdUploaded, uploaded_key);
return;
}
// Reschedule upload on fail.
needs_upload_ = true;
}
} // namespace policy
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROMEOS_POLICY_RSU_LOOKUP_KEY_UPLOADER_H_
#define CHROME_BROWSER_CHROMEOS_POLICY_RSU_LOOKUP_KEY_UPLOADER_H_
#include <memory>
#include <string>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/time/clock.h"
#include "base/time/time.h"
#include "components/policy/core/common/cloud/cloud_policy_store.h"
class PrefService;
namespace chromeos {
namespace attestation {
class EnrollmentCertificateUploader;
}
class CryptohomeClient;
} // namespace chromeos
namespace cryptohome {
class BaseReply;
}
namespace policy {
class DeviceCloudPolicyStoreChromeOS;
// This class is used for uploading Remote Server Unlock lookup keys once per
// enrollment, attempting it whenever we receive device policy from the cloud.
class LookupKeyUploader : public CloudPolicyStore::Observer {
public:
// The observer immediately connects with DeviceCloudPolicyStoreChromeOS
// to listen for policy load events.
LookupKeyUploader(DeviceCloudPolicyStoreChromeOS* policy_store,
PrefService* pref_service,
chromeos::attestation::EnrollmentCertificateUploader*
certificate_uploader);
~LookupKeyUploader() override;
private:
// Minimum period of time between consecutive uploads.
static const base::TimeDelta kRetryFrequency;
friend class LookupKeyUploaderTest;
// Observers from ChromePolicy store.
void OnStoreLoaded(CloudPolicyStore* store) override;
void OnStoreError(CloudPolicyStore* store) override;
void Start();
void OnCryptohomeReady(bool available);
void OnRsuDeviceIdReceived(base::Optional<cryptohome::BaseReply> result);
void HandleRsuDeviceId(const std::string& rsu_device_id);
void Result(const std::string& uploaded_key, bool success);
// Used in tests.
void SetClock(base::Clock* clock) { clock_ = clock; }
DeviceCloudPolicyStoreChromeOS* policy_store_;
PrefService* prefs_;
chromeos::attestation::EnrollmentCertificateUploader* certificate_uploader_;
chromeos::CryptohomeClient* cryptohome_client_;
// Whether we need to upload the lookup key right now. By default, it is set
// to true. Later, it is set to false after first successful upload or finding
// prefs::kLastRSULookupKeyUploaded to be equal to the current lookup key.
bool needs_upload_ = true;
base::Clock* clock_;
// Timestamp of the last lookup key upload, used for resrticting too frequent
// usage.
base::Time last_upload_time_;
// Note: This should remain the last member so it'll be destroyed and
// invalidate the weak pointers before any other members are destroyed.
base::WeakPtrFactory<LookupKeyUploader> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(LookupKeyUploader);
};
} // namespace policy
#endif // CHROME_BROWSER_CHROMEOS_POLICY_RSU_LOOKUP_KEY_UPLOADER_H_
// Copyright 2019 The Chromium 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 "chrome/browser/chromeos/policy/rsu/lookup_key_uploader.h"
#include <memory>
#include <string>
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/simple_test_clock.h"
#include "base/time/time.h"
#include "chrome/browser/chromeos/attestation/mock_enrollment_certificate_uploader.h"
#include "chrome/browser/chromeos/settings/device_settings_test_helper.h"
#include "chrome/common/pref_names.h"
#include "chromeos/dbus/cryptohome/cryptohome_client.h"
#include "chromeos/dbus/cryptohome/fake_cryptohome_client.h"
#include "components/prefs/pref_registry_simple.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using chromeos::attestation::MockEnrollmentCertificateUploader;
using testing::_;
using testing::Invoke;
namespace policy {
namespace {
const char kValidRsuDeviceId[] = "123";
}
class LookupKeyUploaderTest : public chromeos::DeviceSettingsTestBase {
protected:
LookupKeyUploaderTest() = default;
void SetUp() override {
chromeos::DeviceSettingsTestBase::SetUp();
pref_service_.registry()->RegisterStringPref(
prefs::kLastRsuDeviceIdUploaded, std::string());
lookup_key_uploader_ = std::make_unique<LookupKeyUploader>(
nullptr, &pref_service_, &certificate_uploader_);
lookup_key_uploader_->SetClock(&clock_);
// We initialize clock to imitate real time.
clock_.Advance(base::TimeDelta::FromDays(50));
}
void ExpectSavedIdToBe(const std::string& key) {
EXPECT_EQ(pref_service_.GetString(prefs::kLastRsuDeviceIdUploaded), key);
}
bool NeedsUpload() { return lookup_key_uploader_->needs_upload_; }
void SetCryptohomeReplyTo(const std::string& rsu_device_id) {
chromeos::FakeCryptohomeClient::Get()->set_rsu_device_id(rsu_device_id);
}
void AdvanceTime() { clock_.Advance(lookup_key_uploader_->kRetryFrequency); }
void Start() {
lookup_key_uploader_->OnStoreLoaded(nullptr);
base::RunLoop().RunUntilIdle();
}
TestingPrefServiceSimple pref_service_;
base::SimpleTestClock clock_;
MockEnrollmentCertificateUploader certificate_uploader_;
std::unique_ptr<LookupKeyUploader> lookup_key_uploader_;
private:
DISALLOW_COPY_AND_ASSIGN(LookupKeyUploaderTest);
};
TEST_F(LookupKeyUploaderTest, Uploads) {
EXPECT_CALL(certificate_uploader_, ObtainAndUploadCertificate(_))
.WillOnce(Invoke([](base::OnceCallback<void(bool status)> callback) {
std::move(callback).Run(true);
}));
SetCryptohomeReplyTo(kValidRsuDeviceId);
Start();
ExpectSavedIdToBe(kValidRsuDeviceId);
}
TEST_F(LookupKeyUploaderTest, ReuploadsOnFail) {
SetCryptohomeReplyTo("");
Start();
EXPECT_CALL(certificate_uploader_, ObtainAndUploadCertificate(_)).Times(0);
EXPECT_TRUE(NeedsUpload());
}
TEST_F(LookupKeyUploaderTest, DoesntUploadTwice) {
pref_service_.SetString(prefs::kLastRsuDeviceIdUploaded, kValidRsuDeviceId);
SetCryptohomeReplyTo(kValidRsuDeviceId);
Start();
EXPECT_CALL(certificate_uploader_, ObtainAndUploadCertificate(_)).Times(0);
ExpectSavedIdToBe(kValidRsuDeviceId);
EXPECT_FALSE(NeedsUpload());
}
TEST_F(LookupKeyUploaderTest, DoesNotUploadVeryFrequently) {
SetCryptohomeReplyTo("");
Start();
EXPECT_TRUE(NeedsUpload()); // Will ask for restart.
// Next upload should not be executed -- because of the frequency limit.
SetCryptohomeReplyTo(kValidRsuDeviceId);
Start();
ExpectSavedIdToBe("");
EXPECT_TRUE(NeedsUpload()); // Will ask for restart.
AdvanceTime();
EXPECT_CALL(certificate_uploader_, ObtainAndUploadCertificate(_))
.WillOnce(Invoke([](base::OnceCallback<void(bool status)> callback) {
std::move(callback).Run(true);
}));
Start();
ExpectSavedIdToBe(kValidRsuDeviceId);
EXPECT_FALSE(NeedsUpload());
}
} // namespace policy
......@@ -969,6 +969,9 @@ const char kDeviceWebUsbAllowDevicesForUrls[] =
// chrome.login API.
const char kLoginExtensionApiDataForNextLoginAttempt[] =
"extensions_api.login.data_for_next_login_attempt";
// String containing last RSU lookup key uploaded. Empty until first upload.
const char kLastRsuDeviceIdUploaded[] = "rsu.last_rsu_device_id_uploaded";
#endif // defined(OS_CHROMEOS)
// A boolean pref set to true if a Home button to open the Home pages should be
......
......@@ -678,6 +678,7 @@ extern const char
extern const char kKnownUserParentAccessCodeConfig[];
extern const char kSamlInSessionPasswordChangeEnabled[];
extern const char kSamlPasswordExpirationAdvanceWarningDays[];
extern const char kLastRsuDeviceIdUploaded[];
#endif // defined(OS_CHROMEOS)
extern const char kClearPluginLSODataEnabled[];
......
......@@ -1011,6 +1011,13 @@ class CryptohomeClientImpl : public CryptohomeClient {
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void GetRsuDeviceId(
DBusMethodCallback<cryptohome::BaseReply> callback) override {
cryptohome::GetRsuDeviceIdRequest request;
CallCryptohomeMethod(cryptohome::kCryptohomeGetRsuDeviceId, request,
std::move(callback));
}
void LockToSingleUserMountUntilReboot(
const cryptohome::LockToSingleUserMountUntilRebootRequest& request,
DBusMethodCallback<cryptohome::BaseReply> callback) override {
......
......@@ -215,6 +215,11 @@ class COMPONENT_EXPORT(CRYPTOHOME_CLIENT) CryptohomeClient {
const cryptohome::MountGuestRequest& request,
DBusMethodCallback<cryptohome::BaseReply> callback) = 0;
// Calls GetRsuDeviceId method. |callback| is called after the method call
// succeeds.
virtual void GetRsuDeviceId(
DBusMethodCallback<cryptohome::BaseReply> callback) = 0;
// Calls TpmIsReady method.
virtual void TpmIsReady(DBusMethodCallback<bool> callback) = 0;
......
......@@ -171,6 +171,15 @@ void FakeCryptohomeClient::MountGuestEx(
ReturnProtobufMethodCallback(cryptohome::BaseReply(), std::move(callback));
}
void FakeCryptohomeClient::GetRsuDeviceId(
DBusMethodCallback<cryptohome::BaseReply> callback) {
cryptohome::BaseReply reply;
cryptohome::GetRsuDeviceIdReply* get_rsu_lookup_key_reply =
reply.MutableExtension(cryptohome::GetRsuDeviceIdReply::reply);
get_rsu_lookup_key_reply->set_rsu_device_id(rsu_device_id_);
ReturnProtobufMethodCallback(reply, std::move(callback));
}
void FakeCryptohomeClient::TpmIsReady(DBusMethodCallback<bool> callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), true));
......
......@@ -70,6 +70,8 @@ class COMPONENT_EXPORT(CRYPTOHOME_CLIENT) FakeCryptohomeClient
void MountGuestEx(
const cryptohome::MountGuestRequest& request,
DBusMethodCallback<cryptohome::BaseReply> callback) override;
void GetRsuDeviceId(
DBusMethodCallback<cryptohome::BaseReply> callback) override;
void TpmIsReady(DBusMethodCallback<bool> callback) override;
void TpmIsEnabled(DBusMethodCallback<bool> callback) override;
bool CallTpmIsEnabledAndBlock(bool* enabled) override;
......@@ -304,6 +306,10 @@ class COMPONENT_EXPORT(CRYPTOHOME_CLIENT) FakeCryptohomeClient
enable_auth_check_ = enable_auth_check;
}
void set_rsu_device_id(const std::string& rsu_device_id) {
rsu_device_id_ = rsu_device_id;
}
void SetTpmAttestationUserCertificate(
const cryptohome::AccountIdentifier& cryptohome_id,
const std::string& key_name,
......@@ -443,6 +449,9 @@ class COMPONENT_EXPORT(CRYPTOHOME_CLIENT) FakeCryptohomeClient
// Controls if CheckKeyEx actually checks the key.
bool enable_auth_check_ = false;
// Reply to GetRsuDeviceId().
std::string rsu_device_id_;
// MountEx fields.
cryptohome::CryptohomeErrorCode cryptohome_error_ =
cryptohome::CRYPTOHOME_ERROR_NOT_SET;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment