Commit 82e65101 authored by Ryan Hansberry's avatar Ryan Hansberry Committed by Commit Bot

[CrOS Multidevice] Integrate SecureChannel API into EasyUnlockServiceSignin.

EasyUnlockServiceSignin cannot directly access DeviceSync API to retrieve
RemoteDevices, because it is outside of a signed in session. Currently,
this is solved by persisting remote devices to the TPM from
EasyUnlockServiceRegular, for use later on by the Signin service. This CL
reuses that persistance mechanism by also persisting the local device
for each profile into the TPM.

I have manually verified this change, both with a single and multiple
profile(s).

I have also manually verified that this correctly migrates; that is, if
sign-in unlock is enabled before the chromeos::features::kMultiDeviceApi
flag is enabled, and then the flag becomes enabled, the local device will
correctly added as soon as the user signs in.

R=khorimoto@chromium.org

TBR=jhawkins@chromium.org

Bug: 824568, 752273
Change-Id: I613a59004076533642ee3d591637cbbf79e52795
Reviewed-on: https://chromium-review.googlesource.com/1112902
Commit-Queue: Ryan Hansberry <hansberry@chromium.org>
Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#570913}
parent 83f4c245
...@@ -337,6 +337,12 @@ void EasyUnlockCreateKeysOperation::OnGetSystemSalt( ...@@ -337,6 +337,12 @@ void EasyUnlockCreateKeysOperation::OnGetSystemSalt(
key_def.provider_data.push_back(cryptohome::KeyDefinition::ProviderData( key_def.provider_data.push_back(cryptohome::KeyDefinition::ProviderData(
kEasyUnlockKeyMetaNameSerializedBeaconSeeds, kEasyUnlockKeyMetaNameSerializedBeaconSeeds,
device->serialized_beacon_seeds)); device->serialized_beacon_seeds));
// ProviderData only has std::string and int64_t fields for persistence -- use
// the int64_t field to store this boolean. The boolean is stored as either a
// 1 or 0 in as an int64_t.
key_def.provider_data.push_back(cryptohome::KeyDefinition::ProviderData(
kEasyUnlockKeyMetaNameUnlockKey,
static_cast<int64_t>(device->unlock_key)));
std::unique_ptr<Key> auth_key(new Key(*user_context_.GetKey())); std::unique_ptr<Key> auth_key(new Key(*user_context_.GetKey()));
if (auth_key->GetKeyType() == Key::KEY_TYPE_PASSWORD_PLAIN) if (auth_key->GetKeyType() == Key::KEY_TYPE_PASSWORD_PLAIN)
......
...@@ -133,6 +133,15 @@ void EasyUnlockGetKeysOperation::OnGetKeyData( ...@@ -133,6 +133,15 @@ void EasyUnlockGetKeysOperation::OnGetKeyData(
device.serialized_beacon_seeds = *entry.bytes; device.serialized_beacon_seeds = *entry.bytes;
else else
NOTREACHED(); NOTREACHED();
} else if (entry.name == kEasyUnlockKeyMetaNameUnlockKey) {
// ProviderData only has the std::string |bytes| and int64_t |number|
// fields for persistence -- the number field is used to store this
// boolean. The boolean was stored as either a 1 or 0 in as an int64_t.
// Cast it back to bool here.
if (entry.number)
device.unlock_key = static_cast<bool>(*entry.number);
else
NOTREACHED();
} else { } else {
PA_LOG(WARNING) << "Unknown EasyUnlock key data entry, name=" PA_LOG(WARNING) << "Unknown EasyUnlock key data entry, name="
<< entry.name; << entry.name;
......
...@@ -20,6 +20,8 @@ namespace chromeos { ...@@ -20,6 +20,8 @@ namespace chromeos {
namespace { namespace {
// These same constants are used in
// EasyUnlockServiceRegular::UseLoadedRemoteDevices().
const char kKeyBluetoothAddress[] = "bluetoothAddress"; const char kKeyBluetoothAddress[] = "bluetoothAddress";
const char kKeyBluetoothType[] = "bluetoothType"; const char kKeyBluetoothType[] = "bluetoothType";
const char kKeyPermitRecord[] = "permitRecord"; const char kKeyPermitRecord[] = "permitRecord";
...@@ -29,6 +31,7 @@ const char kKeyPermitData[] = "permitRecord.data"; ...@@ -29,6 +31,7 @@ const char kKeyPermitData[] = "permitRecord.data";
const char kKeyPermitType[] = "permitRecord.type"; const char kKeyPermitType[] = "permitRecord.type";
const char kKeyPsk[] = "psk"; const char kKeyPsk[] = "psk";
const char kKeySerializedBeaconSeeds[] = "serializedBeaconSeeds"; const char kKeySerializedBeaconSeeds[] = "serializedBeaconSeeds";
const char kKeyUnlockKey[] = "unlockKey";
const char kKeyLabelPrefix[] = "easy-unlock-"; const char kKeyLabelPrefix[] = "easy-unlock-";
...@@ -123,6 +126,7 @@ void EasyUnlockKeyManager::DeviceDataToRemoteDeviceDictionary( ...@@ -123,6 +126,7 @@ void EasyUnlockKeyManager::DeviceDataToRemoteDeviceDictionary(
base::StringPrintf(kPermitPermitIdFormat, base::StringPrintf(kPermitPermitIdFormat,
account_id.GetUserEmail().c_str())); account_id.GetUserEmail().c_str()));
dict->SetString(kKeySerializedBeaconSeeds, data.serialized_beacon_seeds); dict->SetString(kKeySerializedBeaconSeeds, data.serialized_beacon_seeds);
dict->SetBoolean(kKeyUnlockKey, data.unlock_key);
} }
// static // static
...@@ -160,6 +164,17 @@ bool EasyUnlockKeyManager::RemoteDeviceDictionaryToDeviceData( ...@@ -160,6 +164,17 @@ bool EasyUnlockKeyManager::RemoteDeviceDictionaryToDeviceData(
<< "expected serialized_beacon_seeds."; << "expected serialized_beacon_seeds.";
} }
bool unlock_key;
if (!dict.GetBoolean(kKeyUnlockKey, &unlock_key)) {
// If GetBoolean() fails, that means we're reading a Dictionary from
// user prefs which did not include the bool when it was stored. That means
// it's an older Dictionary that didn't include this |unlock_key| field --
// only one device was persisted, and it was implicitly assumed to be the
// unlock key -- thus |unlock_key| should default to being true.
unlock_key = true;
}
data->unlock_key = unlock_key;
data->bluetooth_address.swap(bluetooth_address); data->bluetooth_address.swap(bluetooth_address);
data->public_key.swap(public_key); data->public_key.swap(public_key);
data->psk.swap(psk); data->psk.swap(psk);
......
...@@ -157,6 +157,15 @@ EasyUnlockServiceRegular::~EasyUnlockServiceRegular() { ...@@ -157,6 +157,15 @@ EasyUnlockServiceRegular::~EasyUnlockServiceRegular() {
// that SmartLock setup has completed successfully. Make this signal more // that SmartLock setup has completed successfully. Make this signal more
// explicit. // explicit.
void EasyUnlockServiceRegular::LoadRemoteDevices() { void EasyUnlockServiceRegular::LoadRemoteDevices() {
if (base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi) &&
!device_sync_client_->GetLocalDeviceMetadata()) {
// OnEnrollmentFinished() will call back on this method once the local
// device is ready.
PA_LOG(INFO)
<< "Local device is not ready yet, delaying UseLoadedRemoteDevices().";
return;
}
bool has_unlock_keys; bool has_unlock_keys;
if (base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)) { if (base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)) {
has_unlock_keys = !GetUnlockKeys().empty(); has_unlock_keys = !GetUnlockKeys().empty();
...@@ -228,17 +237,44 @@ void EasyUnlockServiceRegular::OnRemoteDevicesLoaded( ...@@ -228,17 +237,44 @@ void EasyUnlockServiceRegular::OnRemoteDevicesLoaded(
void EasyUnlockServiceRegular::UseLoadedRemoteDevices( void EasyUnlockServiceRegular::UseLoadedRemoteDevices(
const cryptauth::RemoteDeviceRefList& remote_devices) { const cryptauth::RemoteDeviceRefList& remote_devices) {
// When EasyUnlock is enabled, only one EasyUnlock host should exist.
// If |remote_devices| is empty, that means the caller of this method didn't
// verify that EasyUnlock is enabled, as it should have. |remote_devices|
// should never be longer than 1.
DCHECK(!remote_devices.empty());
if (remote_devices.size() != 1u) {
PA_LOG(ERROR) << "Expected only one unlock key, found "
<< remote_devices.size();
return;
}
SetProximityAuthDevices( SetProximityAuthDevices(
GetAccountId(), remote_devices, GetAccountId(), remote_devices,
base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi) base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)
? device_sync_client_->GetLocalDeviceMetadata() ? device_sync_client_->GetLocalDeviceMetadata()
: base::nullopt); : base::nullopt);
// We need to store a copy of |remote devices_| in the TPM, so it can be // EasyUnlockServiceSignin accesses this list.
// retrieved on the sign-in screen when a user session has not been started // If |chromeos::features::kMultiDeviceApi| is enabled, it will expect a final
// size of 2 (the one remote device, and the local device).
// If |chromeos::features::kMultiDeviceApi| is disabled, it will expect a
// final size of 1 (just the remote device).
// TODO(crbug.com/856380): For historical reasons, the local and remote device
// are persisted together in a list. This is awkward and hacky; they should
// be persisted in a dictionary.
cryptauth::RemoteDeviceRefList local_and_remote_devices;
local_and_remote_devices.push_back(remote_devices[0]);
if (base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)) {
local_and_remote_devices.push_back(
*device_sync_client_->GetLocalDeviceMetadata());
}
// We need to store a copy of |local_and_remote_devices| in the TPM, so it can
// be retrieved on the sign-in screen when a user session has not been started
// yet. // yet.
// These same constants are used in EasyUnlockKeyManager.
std::unique_ptr<base::ListValue> device_list(new base::ListValue()); std::unique_ptr<base::ListValue> device_list(new base::ListValue());
for (const auto& device : remote_devices) { for (const auto& device : local_and_remote_devices) {
std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
std::string b64_public_key, b64_psk; std::string b64_public_key, b64_psk;
base::Base64UrlEncode(device.public_key(), base::Base64UrlEncode(device.public_key(),
...@@ -281,6 +317,9 @@ void EasyUnlockServiceRegular::UseLoadedRemoteDevices( ...@@ -281,6 +317,9 @@ void EasyUnlockServiceRegular::UseLoadedRemoteDevices(
serializer.Serialize(*beacon_seed_list); serializer.Serialize(*beacon_seed_list);
dict->SetString("serializedBeaconSeeds", serialized_beacon_seeds); dict->SetString("serializedBeaconSeeds", serialized_beacon_seeds);
// This differentiates the local device from the remote device.
dict->SetBoolean("unlockKey", device.unlock_key());
device_list->Append(std::move(dict)); device_list->Append(std::move(dict));
} }
...@@ -581,6 +620,12 @@ void EasyUnlockServiceRegular::OnSyncFinished( ...@@ -581,6 +620,12 @@ void EasyUnlockServiceRegular::OnSyncFinished(
LoadRemoteDevices(); LoadRemoteDevices();
} }
void EasyUnlockServiceRegular::OnEnrollmentFinished() {
// If the local device is ready for the first time, or has been updated,
// reload devices.
LoadRemoteDevices();
}
void EasyUnlockServiceRegular::OnNewDevicesSynced() { void EasyUnlockServiceRegular::OnNewDevicesSynced() {
// This method copies EasyUnlockServiceRegular::OnSyncFinished(). // This method copies EasyUnlockServiceRegular::OnSyncFinished().
// TODO(crbug.com/848956): Remove EasyUnlockServiceRegular::OnSyncFinished(). // TODO(crbug.com/848956): Remove EasyUnlockServiceRegular::OnSyncFinished().
......
...@@ -115,6 +115,7 @@ class EasyUnlockServiceRegular ...@@ -115,6 +115,7 @@ class EasyUnlockServiceRegular
device_change_result) override; device_change_result) override;
// device_sync::DeviceSyncClient::Observer: // device_sync::DeviceSyncClient::Observer:
void OnEnrollmentFinished() override;
void OnNewDevicesSynced() override; void OnNewDevicesSynced() override;
void ShowNotificationIfNewDevicePresent( void ShowNotificationIfNewDevicePresent(
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_factory.h" #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_factory.h"
#include "chrome/browser/chromeos/login/session/user_session_manager.h" #include "chrome/browser/chromeos/login/session/user_session_manager.h"
#include "chrome/common/pref_names.h" #include "chrome/common/pref_names.h"
#include "chromeos/chromeos_features.h"
#include "chromeos/components/proximity_auth/logging/logging.h" #include "chromeos/components/proximity_auth/logging/logging.h"
#include "chromeos/components/proximity_auth/proximity_auth_local_state_pref_manager.h" #include "chromeos/components/proximity_auth/proximity_auth_local_state_pref_manager.h"
#include "chromeos/components/proximity_auth/switches.h" #include "chromeos/components/proximity_auth/switches.h"
...@@ -259,20 +260,28 @@ EasyUnlockServiceSignin::GetTurnOffFlowStatus() const { ...@@ -259,20 +260,28 @@ EasyUnlockServiceSignin::GetTurnOffFlowStatus() const {
std::string EasyUnlockServiceSignin::GetChallenge() const { std::string EasyUnlockServiceSignin::GetChallenge() const {
const UserData* data = FindLoadedDataForCurrentUser(); const UserData* data = FindLoadedDataForCurrentUser();
// TODO(xiyuan): Use correct remote device instead of hard coded first one. if (!data)
uint32_t device_index = 0;
if (!data || data->devices.size() <= device_index)
return std::string(); return std::string();
return data->devices[device_index].challenge;
for (const auto& device : data->devices) {
if (device.unlock_key)
return device.challenge;
}
return std::string();
} }
std::string EasyUnlockServiceSignin::GetWrappedSecret() const { std::string EasyUnlockServiceSignin::GetWrappedSecret() const {
const UserData* data = FindLoadedDataForCurrentUser(); const UserData* data = FindLoadedDataForCurrentUser();
// TODO(xiyuan): Use correct remote device instead of hard coded first one. if (!data)
uint32_t device_index = 0;
if (!data || data->devices.size() <= device_index)
return std::string(); return std::string();
return data->devices[device_index].wrapped_secret;
for (const auto& device : data->devices) {
if (device.unlock_key)
return device.wrapped_secret;
}
return std::string();
} }
void EasyUnlockServiceSignin::RecordEasySignInOutcome( void EasyUnlockServiceSignin::RecordEasySignInOutcome(
...@@ -468,6 +477,7 @@ void EasyUnlockServiceSignin::LoadCurrentUserDataIfNeeded() { ...@@ -468,6 +477,7 @@ void EasyUnlockServiceSignin::LoadCurrentUserDataIfNeeded() {
weak_ptr_factory_.GetWeakPtr(), account_id_)); weak_ptr_factory_.GetWeakPtr(), account_id_));
} }
// TODO(crbug.com/856387): Write tests for device retrieval from the TPM.
void EasyUnlockServiceSignin::OnUserDataLoaded( void EasyUnlockServiceSignin::OnUserDataLoaded(
const AccountId& account_id, const AccountId& account_id,
bool success, bool success,
...@@ -510,11 +520,6 @@ void EasyUnlockServiceSignin::OnUserDataLoaded( ...@@ -510,11 +520,6 @@ void EasyUnlockServiceSignin::OnUserDataLoaded(
<< " psk: " << device.psk; << " psk: " << device.psk;
continue; continue;
} }
// TODO(tengs): We assume that the device is an unlock key since we only
// request unlock keys for EasyUnlock. Instead, we should include unlockable
// (as well as the "supports_mobile_hotspot" bool and
// last_update_time_millis) as part of EasyUnlockDeviceKeyData instead of
// making that assumption here.
std::vector<cryptauth::BeaconSeed> beacon_seeds; std::vector<cryptauth::BeaconSeed> beacon_seeds;
if (!device.serialized_beacon_seeds.empty()) { if (!device.serialized_beacon_seeds.empty()) {
...@@ -527,7 +532,7 @@ void EasyUnlockServiceSignin::OnUserDataLoaded( ...@@ -527,7 +532,7 @@ void EasyUnlockServiceSignin::OnUserDataLoaded(
cryptauth::RemoteDevice remote_device( cryptauth::RemoteDevice remote_device(
account_id.GetUserEmail(), std::string() /* name */, decoded_public_key, account_id.GetUserEmail(), std::string() /* name */, decoded_public_key,
decoded_psk /* persistent_symmetric_key */, true /* unlock_key */, decoded_psk /* persistent_symmetric_key */, device.unlock_key,
false /* supports_mobile_hotspot */, 0L /* last_update_time_millis */, false /* supports_mobile_hotspot */, 0L /* last_update_time_millis */,
std::map<cryptauth::SoftwareFeature, cryptauth::SoftwareFeatureState>(), std::map<cryptauth::SoftwareFeature, cryptauth::SoftwareFeatureState>(),
beacon_seeds); beacon_seeds);
...@@ -535,15 +540,69 @@ void EasyUnlockServiceSignin::OnUserDataLoaded( ...@@ -535,15 +540,69 @@ void EasyUnlockServiceSignin::OnUserDataLoaded(
remote_devices.push_back(remote_device); remote_devices.push_back(remote_device);
PA_LOG(INFO) << "Loaded Remote Device:\n" PA_LOG(INFO) << "Loaded Remote Device:\n"
<< " user id: " << remote_device.user_id << "\n" << " user id: " << remote_device.user_id << "\n"
<< " name: " << remote_device.name << "\n" << " device id: "
<< " public key" << remote_device.public_key; << cryptauth::RemoteDeviceRef::TruncateDeviceIdForLogs(
remote_device.GetDeviceId());
}
// If |chromeos::features::kMultiDeviceApi| is enabled, both a remote device
// and local device are expected, and this service cannot continue unless
// both are present.
//
// If the flag is disabled, just one device, the remote device, is expected to
// be passed along -- if a second device is present, it can simply be ignored.
//
// TODO(crbug.com/856380): The remote and local devices need to be passed in a
// less hacky way.
if (remote_devices.size() > 2u) {
PA_LOG(ERROR)
<< "Expected a device list of size 1 or 2, received list of size "
<< remote_devices.size();
SetHardlockStateForUser(account_id,
EasyUnlockScreenlockStateHandler::NO_PAIRING);
return;
}
if (base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi) &&
remote_devices.size() != 2u) {
PA_LOG(ERROR) << "Expected a device list of size 2, received list of size "
<< remote_devices.size();
SetHardlockStateForUser(account_id,
EasyUnlockScreenlockStateHandler::PAIRING_CHANGED);
return;
}
std::string unlock_key_id;
// This may be left unset if the local device was not passed along.
std::string local_device_id;
for (const auto& remote_device : remote_devices) {
if (remote_device.unlock_key) {
if (!unlock_key_id.empty()) {
PA_LOG(ERROR) << "Only one of the devices should be an unlock key.";
SetHardlockStateForUser(account_id,
EasyUnlockScreenlockStateHandler::NO_PAIRING);
return;
}
unlock_key_id = remote_device.GetDeviceId();
} else {
if (!local_device_id.empty()) {
PA_LOG(ERROR) << "Only one of the devices should be the local device.";
SetHardlockStateForUser(account_id,
EasyUnlockScreenlockStateHandler::NO_PAIRING);
return;
}
local_device_id = remote_device.GetDeviceId();
}
} }
remote_device_cache_->SetRemoteDevices(remote_devices); remote_device_cache_->SetRemoteDevices(remote_devices);
// TODO(crbug.com/752273): Inject a real local device. SetProximityAuthDevices(
SetProximityAuthDevices(account_id, remote_device_cache_->GetRemoteDevices(), account_id, {*remote_device_cache_->GetRemoteDevice(unlock_key_id)},
base::nullopt /* local_device */); remote_device_cache_->GetRemoteDevice(local_device_id));
} }
const EasyUnlockServiceSignin::UserData* const EasyUnlockServiceSignin::UserData*
......
...@@ -13,6 +13,7 @@ const char kEasyUnlockKeyMetaNamePubKey[] = "eu.pubkey"; ...@@ -13,6 +13,7 @@ const char kEasyUnlockKeyMetaNamePubKey[] = "eu.pubkey";
const char kEasyUnlockKeyMetaNameChallenge[] = "eu.C"; const char kEasyUnlockKeyMetaNameChallenge[] = "eu.C";
const char kEasyUnlockKeyMetaNameWrappedSecret[] = "eu.WUK"; const char kEasyUnlockKeyMetaNameWrappedSecret[] = "eu.WUK";
const char kEasyUnlockKeyMetaNameSerializedBeaconSeeds[] = "eu.BS"; const char kEasyUnlockKeyMetaNameSerializedBeaconSeeds[] = "eu.BS";
const char kEasyUnlockKeyMetaNameUnlockKey[] = "eu.unlock_key";
EasyUnlockDeviceKeyData::EasyUnlockDeviceKeyData() EasyUnlockDeviceKeyData::EasyUnlockDeviceKeyData()
: bluetooth_type(BLUETOOTH_CLASSIC) {} : bluetooth_type(BLUETOOTH_CLASSIC) {}
......
...@@ -18,6 +18,7 @@ extern const char kEasyUnlockKeyMetaNamePubKey[]; ...@@ -18,6 +18,7 @@ extern const char kEasyUnlockKeyMetaNamePubKey[];
extern const char kEasyUnlockKeyMetaNameChallenge[]; extern const char kEasyUnlockKeyMetaNameChallenge[];
extern const char kEasyUnlockKeyMetaNameWrappedSecret[]; extern const char kEasyUnlockKeyMetaNameWrappedSecret[];
extern const char kEasyUnlockKeyMetaNameSerializedBeaconSeeds[]; extern const char kEasyUnlockKeyMetaNameSerializedBeaconSeeds[];
extern const char kEasyUnlockKeyMetaNameUnlockKey[];
// Device data that is stored with cryptohome keys. // Device data that is stored with cryptohome keys.
struct EasyUnlockDeviceKeyData { struct EasyUnlockDeviceKeyData {
...@@ -42,6 +43,9 @@ struct EasyUnlockDeviceKeyData { ...@@ -42,6 +43,9 @@ struct EasyUnlockDeviceKeyData {
std::string wrapped_secret; std::string wrapped_secret;
// Serialized BeaconSeeds used to identify this device. // Serialized BeaconSeeds used to identify this device.
std::string serialized_beacon_seeds; std::string serialized_beacon_seeds;
// True if the device is an Easy Unlock host, false if not (which implies
// that it is the local device).
bool unlock_key;
}; };
typedef std::vector<EasyUnlockDeviceKeyData> EasyUnlockDeviceKeyDataList; typedef std::vector<EasyUnlockDeviceKeyData> EasyUnlockDeviceKeyDataList;
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "chromeos/components/proximity_auth/proximity_auth_pref_manager.h" #include "chromeos/components/proximity_auth/proximity_auth_pref_manager.h"
#include "chromeos/components/proximity_auth/proximity_monitor_impl.h" #include "chromeos/components/proximity_auth/proximity_monitor_impl.h"
#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/services/secure_channel/public/cpp/client/client_channel.h"
#include "components/cryptauth/remote_device_ref.h" #include "components/cryptauth/remote_device_ref.h"
#include "components/cryptauth/secure_context.h" #include "components/cryptauth/secure_context.h"
#include "device/bluetooth/bluetooth_adapter_factory.h" #include "device/bluetooth/bluetooth_adapter_factory.h"
...@@ -154,7 +155,7 @@ void UnlockManagerImpl::OnLifeCycleStateChanged() { ...@@ -154,7 +155,7 @@ void UnlockManagerImpl::OnLifeCycleStateChanged() {
remote_screenlock_state_.reset(); remote_screenlock_state_.reset();
if (state == RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED) { if (state == RemoteDeviceLifeCycle::State::SECURE_CHANNEL_ESTABLISHED) {
DCHECK(life_cycle_->GetConnection()); DCHECK(life_cycle_->GetConnection() || life_cycle_->GetChannel());
DCHECK(GetMessenger()); DCHECK(GetMessenger());
proximity_monitor_ = CreateProximityMonitor(life_cycle_, pref_manager_); proximity_monitor_ = CreateProximityMonitor(life_cycle_, pref_manager_);
GetMessenger()->AddObserver(this); GetMessenger()->AddObserver(this);
...@@ -335,15 +336,44 @@ std::unique_ptr<ProximityMonitor> UnlockManagerImpl::CreateProximityMonitor( ...@@ -335,15 +336,44 @@ std::unique_ptr<ProximityMonitor> UnlockManagerImpl::CreateProximityMonitor(
} }
void UnlockManagerImpl::SendSignInChallenge() { void UnlockManagerImpl::SendSignInChallenge() {
if (!life_cycle_ || !GetMessenger() || !GetMessenger()->GetSecureContext()) { if (!life_cycle_ || !GetMessenger()) {
PA_LOG(ERROR) << "Not ready to send sign-in challenge"; PA_LOG(ERROR) << "Not ready to send sign-in challenge";
return; return;
} }
if (base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)) {
if (!GetMessenger()->GetChannel()) {
PA_LOG(ERROR) << "Channel is not ready to send sign-in challenge.";
return;
}
GetMessenger()->GetChannel()->GetConnectionMetadata(
base::BindOnce(&UnlockManagerImpl::OnGetConnectionMetadata,
weak_ptr_factory_.GetWeakPtr()));
} else {
if (!GetMessenger()->GetSecureContext()) {
PA_LOG(ERROR) << "SecureContext is not ready to send sign-in challenge.";
return;
}
cryptauth::RemoteDeviceRef remote_device = life_cycle_->GetRemoteDevice();
proximity_auth_client_->GetChallengeForUserAndDevice(
remote_device.user_id(), remote_device.public_key(),
GetMessenger()->GetSecureContext()->GetChannelBindingData(),
base::Bind(&UnlockManagerImpl::OnGotSignInChallenge,
weak_ptr_factory_.GetWeakPtr()));
}
}
void UnlockManagerImpl::OnGetConnectionMetadata(
chromeos::secure_channel::mojom::ConnectionMetadataPtr
connection_metadata_ptr) {
DCHECK(base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi));
cryptauth::RemoteDeviceRef remote_device = life_cycle_->GetRemoteDevice(); cryptauth::RemoteDeviceRef remote_device = life_cycle_->GetRemoteDevice();
proximity_auth_client_->GetChallengeForUserAndDevice( proximity_auth_client_->GetChallengeForUserAndDevice(
remote_device.user_id(), remote_device.public_key(), remote_device.user_id(), remote_device.public_key(),
GetMessenger()->GetSecureContext()->GetChannelBindingData(), connection_metadata_ptr->channel_binding_data,
base::Bind(&UnlockManagerImpl::OnGotSignInChallenge, base::Bind(&UnlockManagerImpl::OnGotSignInChallenge,
weak_ptr_factory_.GetWeakPtr())); weak_ptr_factory_.GetWeakPtr()));
} }
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "chromeos/components/proximity_auth/screenlock_state.h" #include "chromeos/components/proximity_auth/screenlock_state.h"
#include "chromeos/components/proximity_auth/unlock_manager.h" #include "chromeos/components/proximity_auth/unlock_manager.h"
#include "chromeos/dbus/power_manager_client.h" #include "chromeos/dbus/power_manager_client.h"
#include "chromeos/services/secure_channel/public/mojom/secure_channel.mojom.h"
#include "device/bluetooth/bluetooth_adapter.h" #include "device/bluetooth/bluetooth_adapter.h"
namespace proximity_auth { namespace proximity_auth {
...@@ -102,6 +103,10 @@ class UnlockManagerImpl : public UnlockManager, ...@@ -102,6 +103,10 @@ class UnlockManagerImpl : public UnlockManager,
// device for decryption. // device for decryption.
void SendSignInChallenge(); void SendSignInChallenge();
void OnGetConnectionMetadata(
chromeos::secure_channel::mojom::ConnectionMetadataPtr
connection_metadata_ptr);
// Called with the sign-in |challenge| so we can send it to the remote device // Called with the sign-in |challenge| so we can send it to the remote device
// for decryption. // for decryption.
void OnGotSignInChallenge(const std::string& challenge); void OnGotSignInChallenge(const std::string& challenge);
......
...@@ -9,9 +9,11 @@ ...@@ -9,9 +9,11 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_simple_task_runner.h" #include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "chromeos/chromeos_features.h"
#include "chromeos/components/proximity_auth/fake_lock_handler.h" #include "chromeos/components/proximity_auth/fake_lock_handler.h"
#include "chromeos/components/proximity_auth/fake_remote_device_life_cycle.h" #include "chromeos/components/proximity_auth/fake_remote_device_life_cycle.h"
#include "chromeos/components/proximity_auth/logging/logging.h" #include "chromeos/components/proximity_auth/logging/logging.h"
...@@ -22,6 +24,7 @@ ...@@ -22,6 +24,7 @@
#include "chromeos/components/proximity_auth/remote_status_update.h" #include "chromeos/components/proximity_auth/remote_status_update.h"
#include "chromeos/components/proximity_auth/screenlock_bridge.h" #include "chromeos/components/proximity_auth/screenlock_bridge.h"
#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/services/secure_channel/public/cpp/client/fake_client_channel.h"
#include "components/cryptauth/fake_connection.h" #include "components/cryptauth/fake_connection.h"
#include "components/cryptauth/fake_secure_context.h" #include "components/cryptauth/fake_secure_context.h"
#include "components/cryptauth/remote_device_test_util.h" #include "components/cryptauth/remote_device_test_util.h"
...@@ -156,6 +159,8 @@ class ProximityAuthUnlockManagerImplTest : public testing::Test { ...@@ -156,6 +159,8 @@ class ProximityAuthUnlockManagerImplTest : public testing::Test {
local_device_(cryptauth::CreateRemoteDeviceRefForTest()), local_device_(cryptauth::CreateRemoteDeviceRefForTest()),
life_cycle_(remote_device_, local_device_), life_cycle_(remote_device_, local_device_),
connection_(remote_device_), connection_(remote_device_),
fake_client_channel_(
std::make_unique<chromeos::secure_channel::FakeClientChannel>()),
bluetooth_adapter_(CreateAndRegisterMockBluetoothAdapter()), bluetooth_adapter_(CreateAndRegisterMockBluetoothAdapter()),
task_runner_(new base::TestSimpleTaskRunner()), task_runner_(new base::TestSimpleTaskRunner()),
thread_task_runner_handle_(task_runner_) { thread_task_runner_handle_(task_runner_) {
...@@ -163,9 +168,12 @@ class ProximityAuthUnlockManagerImplTest : public testing::Test { ...@@ -163,9 +168,12 @@ class ProximityAuthUnlockManagerImplTest : public testing::Test {
ON_CALL(messenger_, SupportsSignIn()).WillByDefault(Return(true)); ON_CALL(messenger_, SupportsSignIn()).WillByDefault(Return(true));
ON_CALL(messenger_, GetSecureContext()) ON_CALL(messenger_, GetSecureContext())
.WillByDefault(Return(&secure_context_)); .WillByDefault(Return(&secure_context_));
ON_CALL(messenger_, GetChannel())
.WillByDefault(Return(fake_client_channel_.get()));
life_cycle_.set_connection(&connection_); life_cycle_.set_connection(&connection_);
life_cycle_.set_messenger(&messenger_); life_cycle_.set_messenger(&messenger_);
life_cycle_.set_channel(fake_client_channel_.get());
ScreenlockBridge::Get()->SetLockHandler(&lock_handler_); ScreenlockBridge::Get()->SetLockHandler(&lock_handler_);
chromeos::DBusThreadManager::Initialize(); chromeos::DBusThreadManager::Initialize();
...@@ -189,6 +197,11 @@ class ProximityAuthUnlockManagerImplTest : public testing::Test { ...@@ -189,6 +197,11 @@ class ProximityAuthUnlockManagerImplTest : public testing::Test {
ScreenlockBridge::Get()->SetLockHandler(nullptr); ScreenlockBridge::Get()->SetLockHandler(nullptr);
} }
void SetMultiDeviceApiEnabled() {
scoped_feature_list_.InitAndEnableFeature(
chromeos::features::kMultiDeviceApi);
}
void CreateUnlockManager( void CreateUnlockManager(
ProximityAuthSystem::ScreenlockType screenlock_type) { ProximityAuthSystem::ScreenlockType screenlock_type) {
unlock_manager_.reset( unlock_manager_.reset(
...@@ -214,6 +227,8 @@ class ProximityAuthUnlockManagerImplTest : public testing::Test { ...@@ -214,6 +227,8 @@ class ProximityAuthUnlockManagerImplTest : public testing::Test {
cryptauth::RemoteDeviceRef local_device_; cryptauth::RemoteDeviceRef local_device_;
FakeRemoteDeviceLifeCycle life_cycle_; FakeRemoteDeviceLifeCycle life_cycle_;
cryptauth::FakeConnection connection_; cryptauth::FakeConnection connection_;
std::unique_ptr<chromeos::secure_channel::FakeClientChannel>
fake_client_channel_;
// Mock used for verifying interactions with the Bluetooth subsystem. // Mock used for verifying interactions with the Bluetooth subsystem.
scoped_refptr<device::MockBluetoothAdapter> bluetooth_adapter_; scoped_refptr<device::MockBluetoothAdapter> bluetooth_adapter_;
...@@ -224,6 +239,7 @@ class ProximityAuthUnlockManagerImplTest : public testing::Test { ...@@ -224,6 +239,7 @@ class ProximityAuthUnlockManagerImplTest : public testing::Test {
cryptauth::FakeSecureContext secure_context_; cryptauth::FakeSecureContext secure_context_;
private: private:
base::test::ScopedFeatureList scoped_feature_list_;
scoped_refptr<base::TestSimpleTaskRunner> task_runner_; scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
base::ThreadTaskRunnerHandle thread_task_runner_handle_; base::ThreadTaskRunnerHandle thread_task_runner_handle_;
FakeLockHandler lock_handler_; FakeLockHandler lock_handler_;
...@@ -799,6 +815,49 @@ TEST_F(ProximityAuthUnlockManagerImplTest, OnAuthAttempted_SignIn_Success) { ...@@ -799,6 +815,49 @@ TEST_F(ProximityAuthUnlockManagerImplTest, OnAuthAttempted_SignIn_Success) {
unlock_manager_->OnUnlockEventSent(true); unlock_manager_->OnUnlockEventSent(true);
} }
TEST_F(ProximityAuthUnlockManagerImplTest,
OnAuthAttempted_SignIn_Success_MultiDeviceApiEnabled) {
SetMultiDeviceApiEnabled();
ON_CALL(messenger_, SupportsSignIn()).WillByDefault(Return(true));
CreateUnlockManager(ProximityAuthSystem::SIGN_IN);
SimulateUserPresentState();
std::string channel_binding_data = "channel binding data";
EXPECT_CALL(proximity_auth_client_,
GetChallengeForUserAndDevice(remote_device_.user_id(),
remote_device_.public_key(),
channel_binding_data, _))
.WillOnce(Invoke(
[](const std::string& user_id, const std::string& public_key,
const std::string& channel_binding_data,
base::Callback<void(const std::string& challenge)> callback) {
callback.Run(kChallenge);
}));
EXPECT_CALL(messenger_, RequestDecryption(kChallenge));
unlock_manager_->OnAuthAttempted(mojom::AuthType::USER_CLICK);
std::vector<chromeos::secure_channel::mojom::ConnectionCreationDetail>
creation_details{
chromeos::secure_channel::mojom::ConnectionCreationDetail::
REMOTE_DEVICE_USED_BACKGROUND_BLE_ADVERTISING};
chromeos::secure_channel::mojom::ConnectionMetadataPtr
connection_metadata_ptr =
chromeos::secure_channel::mojom::ConnectionMetadata::New(
creation_details, nullptr /* bluetooth_connection_metadata */,
channel_binding_data);
fake_client_channel_->InvokePendingGetConnectionMetadataCallback(
std::move(connection_metadata_ptr));
EXPECT_CALL(messenger_, DispatchUnlockEvent());
unlock_manager_->OnDecryptResponse(kSignInSecret);
EXPECT_CALL(proximity_auth_client_, FinalizeSignin(kSignInSecret));
unlock_manager_->OnUnlockEventSent(true);
}
TEST_F(ProximityAuthUnlockManagerImplTest, TEST_F(ProximityAuthUnlockManagerImplTest,
OnAuthAttempted_SignIn_UnlockEventSendFails) { OnAuthAttempted_SignIn_UnlockEventSendFails) {
ON_CALL(messenger_, SupportsSignIn()).WillByDefault(Return(true)); ON_CALL(messenger_, SupportsSignIn()).WillByDefault(Return(true));
......
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