1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h"
8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/values.h"
12 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.h"
13 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_factory.h"
19 const char kKeyBluetoothAddress
[] = "bluetoothAddress";
20 const char kKeyPermitRecord
[] = "permitRecord";
21 const char kKeyPermitId
[] = "permitRecord.id";
22 const char kKeyPermitPermitId
[] = "permitRecord.permitId";
23 const char kKeyPermitData
[] = "permitRecord.data";
24 const char kKeyPermitType
[] = "permitRecord.type";
25 const char kKeyPsk
[] = "psk";
27 const char kKeyLabelPrefix
[] = "easy-unlock-";
29 const char kPermitPermitIdFormat
[] = "permit://google.com/easyunlock/v1/%s";
30 const char kPermitTypeLicence
[] = "licence";
34 EasyUnlockKeyManager::EasyUnlockKeyManager()
35 : write_queue_deleter_(&write_operation_queue_
),
36 read_queue_deleter_(&read_operation_queue_
),
37 weak_ptr_factory_(this) {
40 EasyUnlockKeyManager::~EasyUnlockKeyManager() {
43 void EasyUnlockKeyManager::RefreshKeys(const UserContext
& user_context
,
44 const base::ListValue
& remote_devices
,
45 const RefreshKeysCallback
& callback
) {
46 base::Closure do_refresh_keys
= base::Bind(
47 &EasyUnlockKeyManager::RefreshKeysWithTpmKeyPresent
,
48 weak_ptr_factory_
.GetWeakPtr(),
50 base::Owned(remote_devices
.DeepCopy()),
53 EasyUnlockTpmKeyManager
* tpm_key_manager
=
54 EasyUnlockTpmKeyManagerFactory::GetInstance()->GetForUser(
55 user_context
.GetUserID());
56 if (!tpm_key_manager
) {
57 LOG(ERROR
) << "No TPM key manager.";
62 // Private TPM key is needed only when adding new keys.
63 if (remote_devices
.empty() ||
64 tpm_key_manager
->PrepareTpmKey(false /* check_private_key */,
66 do_refresh_keys
.Run();
68 // In case Chrome is supposed to restart to apply user session flags, the
69 // Chrome restart will be postponed until Easy Sign-in keys are refreshed.
70 // This is to ensure that creating TPM key does not hang if TPM system
71 // loading takes too much time. Note that in normal circumstances the
72 // chances that TPM slot cannot be loaded should be extremely low.
73 // TODO(tbarzic): Add some metrics to measure if the timeout even gets hit.
74 tpm_key_manager
->StartGetSystemSlotTimeoutMs(2000);
78 void EasyUnlockKeyManager::RefreshKeysWithTpmKeyPresent(
79 const UserContext
& user_context
,
80 base::ListValue
* remote_devices
,
81 const RefreshKeysCallback
& callback
) {
82 EasyUnlockTpmKeyManager
* tpm_key_manager
=
83 EasyUnlockTpmKeyManagerFactory::GetInstance()->GetForUser(
84 user_context
.GetUserID());
85 std::string tpm_public_key
=
86 tpm_key_manager
->GetPublicTpmKey(user_context
.GetUserID());
88 EasyUnlockDeviceKeyDataList devices
;
89 if (!RemoteDeviceListToDeviceDataList(*remote_devices
, &devices
))
92 write_operation_queue_
.push_back(new EasyUnlockRefreshKeysOperation(
93 user_context
, tpm_public_key
, devices
,
94 base::Bind(&EasyUnlockKeyManager::OnKeysRefreshed
,
95 weak_ptr_factory_
.GetWeakPtr(), callback
)));
99 void EasyUnlockKeyManager::GetDeviceDataList(
100 const UserContext
& user_context
,
101 const GetDeviceDataListCallback
& callback
) {
102 read_operation_queue_
.push_back(new EasyUnlockGetKeysOperation(
103 user_context
, base::Bind(&EasyUnlockKeyManager::OnKeysFetched
,
104 weak_ptr_factory_
.GetWeakPtr(), callback
)));
109 void EasyUnlockKeyManager::DeviceDataToRemoteDeviceDictionary(
110 const std::string
& user_id
,
111 const EasyUnlockDeviceKeyData
& data
,
112 base::DictionaryValue
* dict
) {
113 dict
->SetString(kKeyBluetoothAddress
, data
.bluetooth_address
);
114 dict
->SetString(kKeyPsk
, data
.psk
);
115 scoped_ptr
<base::DictionaryValue
> permit_record(new base::DictionaryValue
);
116 dict
->Set(kKeyPermitRecord
, permit_record
.release());
117 dict
->SetString(kKeyPermitId
, data
.public_key
);
118 dict
->SetString(kKeyPermitData
, data
.public_key
);
119 dict
->SetString(kKeyPermitType
, kPermitTypeLicence
);
120 dict
->SetString(kKeyPermitPermitId
,
121 base::StringPrintf(kPermitPermitIdFormat
,
126 bool EasyUnlockKeyManager::RemoteDeviceDictionaryToDeviceData(
127 const base::DictionaryValue
& dict
,
128 EasyUnlockDeviceKeyData
* data
) {
129 std::string bluetooth_address
;
130 std::string public_key
;
133 if (!dict
.GetString(kKeyBluetoothAddress
, &bluetooth_address
) ||
134 !dict
.GetString(kKeyPermitId
, &public_key
) ||
135 !dict
.GetString(kKeyPsk
, &psk
)) {
139 data
->bluetooth_address
.swap(bluetooth_address
);
140 data
->public_key
.swap(public_key
);
146 void EasyUnlockKeyManager::DeviceDataListToRemoteDeviceList(
147 const std::string
& user_id
,
148 const EasyUnlockDeviceKeyDataList
& data_list
,
149 base::ListValue
* device_list
) {
150 device_list
->Clear();
151 for (size_t i
= 0; i
< data_list
.size(); ++i
) {
152 scoped_ptr
<base::DictionaryValue
> device_dict(new base::DictionaryValue
);
153 DeviceDataToRemoteDeviceDictionary(
154 user_id
, data_list
[i
], device_dict
.get());
155 device_list
->Append(device_dict
.release());
160 bool EasyUnlockKeyManager::RemoteDeviceListToDeviceDataList(
161 const base::ListValue
& device_list
,
162 EasyUnlockDeviceKeyDataList
* data_list
) {
163 EasyUnlockDeviceKeyDataList parsed_devices
;
164 for (base::ListValue::const_iterator it
= device_list
.begin();
165 it
!= device_list
.end();
167 const base::DictionaryValue
* dict
;
168 if (!(*it
)->GetAsDictionary(&dict
) || !dict
)
171 EasyUnlockDeviceKeyData data
;
172 if (!RemoteDeviceDictionaryToDeviceData(*dict
, &data
))
175 parsed_devices
.push_back(data
);
178 data_list
->swap(parsed_devices
);
183 std::string
EasyUnlockKeyManager::GetKeyLabel(size_t key_index
) {
184 return base::StringPrintf("%s%zu", kKeyLabelPrefix
, key_index
);
187 void EasyUnlockKeyManager::RunNextOperation() {
188 if (pending_write_operation_
|| pending_read_operation_
)
191 if (!write_operation_queue_
.empty()) {
192 pending_write_operation_
= make_scoped_ptr(write_operation_queue_
.front());
193 write_operation_queue_
.pop_front();
194 pending_write_operation_
->Start();
195 } else if (!read_operation_queue_
.empty()) {
196 pending_read_operation_
= make_scoped_ptr(read_operation_queue_
.front());
197 read_operation_queue_
.pop_front();
198 pending_read_operation_
->Start();
202 void EasyUnlockKeyManager::OnKeysRefreshed(const RefreshKeysCallback
& callback
,
203 bool refresh_success
) {
204 if (!callback
.is_null())
205 callback
.Run(refresh_success
);
207 DCHECK(pending_write_operation_
);
208 pending_write_operation_
.reset();
212 void EasyUnlockKeyManager::OnKeysFetched(
213 const GetDeviceDataListCallback
& callback
,
215 const EasyUnlockDeviceKeyDataList
& fetched_data
) {
216 if (!callback
.is_null())
217 callback
.Run(fetch_success
, fetched_data
);
219 DCHECK(pending_read_operation_
);
220 pending_read_operation_
.reset();
224 } // namespace chromeos