| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h" | 5 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/stl_util.h" | 9 #include "base/memory/scoped_ptr.h" |
| 10 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
| 11 #include "base/values.h" | 11 #include "base/values.h" |
| 12 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager.
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" | 13 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_tpm_key_manager_
factory.h" |
| 14 | 14 |
| 15 namespace chromeos { | 15 namespace chromeos { |
| 16 | 16 |
| 17 namespace { | 17 namespace { |
| 18 | 18 |
| 19 const char kKeyBluetoothAddress[] = "bluetoothAddress"; | 19 const char kKeyBluetoothAddress[] = "bluetoothAddress"; |
| 20 const char kKeyPermitRecord[] = "permitRecord"; | 20 const char kKeyPermitRecord[] = "permitRecord"; |
| 21 const char kKeyPermitId[] = "permitRecord.id"; | 21 const char kKeyPermitId[] = "permitRecord.id"; |
| 22 const char kKeyPermitPermitId[] = "permitRecord.permitId"; | 22 const char kKeyPermitPermitId[] = "permitRecord.permitId"; |
| 23 const char kKeyPermitData[] = "permitRecord.data"; | 23 const char kKeyPermitData[] = "permitRecord.data"; |
| 24 const char kKeyPermitType[] = "permitRecord.type"; | 24 const char kKeyPermitType[] = "permitRecord.type"; |
| 25 const char kKeyPsk[] = "psk"; | 25 const char kKeyPsk[] = "psk"; |
| 26 | 26 |
| 27 const char kKeyLabelPrefix[] = "easy-unlock-"; | 27 const char kKeyLabelPrefix[] = "easy-unlock-"; |
| 28 | 28 |
| 29 const char kPermitPermitIdFormat[] = "permit://google.com/easyunlock/v1/%s"; | 29 const char kPermitPermitIdFormat[] = "permit://google.com/easyunlock/v1/%s"; |
| 30 const char kPermitTypeLicence[] = "licence"; | 30 const char kPermitTypeLicence[] = "licence"; |
| 31 | 31 |
| 32 } // namespace | 32 } // namespace |
| 33 | 33 |
| 34 EasyUnlockKeyManager::EasyUnlockKeyManager() | 34 EasyUnlockKeyManager::EasyUnlockKeyManager() |
| 35 : operation_id_(0), | 35 : write_queue_deleter_(&write_operation_queue_), |
| 36 read_queue_deleter_(&read_operation_queue_), |
| 36 weak_ptr_factory_(this) { | 37 weak_ptr_factory_(this) { |
| 37 } | 38 } |
| 38 | 39 |
| 39 EasyUnlockKeyManager::~EasyUnlockKeyManager() { | 40 EasyUnlockKeyManager::~EasyUnlockKeyManager() { |
| 40 STLDeleteContainerPairSecondPointers(get_keys_ops_.begin(), | |
| 41 get_keys_ops_.end()); | |
| 42 } | 41 } |
| 43 | 42 |
| 44 void EasyUnlockKeyManager::RefreshKeys(const UserContext& user_context, | 43 void EasyUnlockKeyManager::RefreshKeys(const UserContext& user_context, |
| 45 const base::ListValue& remote_devices, | 44 const base::ListValue& remote_devices, |
| 46 const RefreshKeysCallback& callback) { | 45 const RefreshKeysCallback& callback) { |
| 47 // Must have the secret. | |
| 48 DCHECK(!user_context.GetKey()->GetSecret().empty()); | |
| 49 | |
| 50 base::Closure do_refresh_keys = base::Bind( | 46 base::Closure do_refresh_keys = base::Bind( |
| 51 &EasyUnlockKeyManager::RefreshKeysWithTpmKeyPresent, | 47 &EasyUnlockKeyManager::RefreshKeysWithTpmKeyPresent, |
| 52 weak_ptr_factory_.GetWeakPtr(), | 48 weak_ptr_factory_.GetWeakPtr(), |
| 53 user_context, | 49 user_context, |
| 54 base::Owned(remote_devices.DeepCopy()), | 50 base::Owned(remote_devices.DeepCopy()), |
| 55 callback); | 51 callback); |
| 56 | 52 |
| 57 EasyUnlockTpmKeyManager* tpm_key_manager = | 53 EasyUnlockTpmKeyManager* tpm_key_manager = |
| 58 EasyUnlockTpmKeyManagerFactory::GetInstance()->GetForUser( | 54 EasyUnlockTpmKeyManagerFactory::GetInstance()->GetForUser( |
| 59 user_context.GetUserID()); | 55 user_context.GetUserID()); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 84 EasyUnlockTpmKeyManager* tpm_key_manager = | 80 EasyUnlockTpmKeyManager* tpm_key_manager = |
| 85 EasyUnlockTpmKeyManagerFactory::GetInstance()->GetForUser( | 81 EasyUnlockTpmKeyManagerFactory::GetInstance()->GetForUser( |
| 86 user_context.GetUserID()); | 82 user_context.GetUserID()); |
| 87 std::string tpm_public_key = | 83 std::string tpm_public_key = |
| 88 tpm_key_manager->GetPublicTpmKey(user_context.GetUserID()); | 84 tpm_key_manager->GetPublicTpmKey(user_context.GetUserID()); |
| 89 | 85 |
| 90 EasyUnlockDeviceKeyDataList devices; | 86 EasyUnlockDeviceKeyDataList devices; |
| 91 if (!RemoteDeviceListToDeviceDataList(*remote_devices, &devices)) | 87 if (!RemoteDeviceListToDeviceDataList(*remote_devices, &devices)) |
| 92 devices.clear(); | 88 devices.clear(); |
| 93 | 89 |
| 94 // Only one pending request. | 90 write_operation_queue_.push_back(new EasyUnlockRefreshKeysOperation( |
| 95 DCHECK(!HasPendingOperations()); | 91 user_context, tpm_public_key, devices, |
| 96 create_keys_op_.reset(new EasyUnlockCreateKeysOperation( | 92 base::Bind(&EasyUnlockKeyManager::OnKeysRefreshed, |
| 97 user_context, | 93 weak_ptr_factory_.GetWeakPtr(), callback))); |
| 98 tpm_public_key, | 94 RunNextOperation(); |
| 99 devices, | |
| 100 base::Bind(&EasyUnlockKeyManager::OnKeysCreated, | |
| 101 weak_ptr_factory_.GetWeakPtr(), | |
| 102 devices.size(), | |
| 103 callback))); | |
| 104 create_keys_op_->Start(); | |
| 105 } | |
| 106 | |
| 107 void EasyUnlockKeyManager::RemoveKeys(const UserContext& user_context, | |
| 108 size_t start_index, | |
| 109 const RemoveKeysCallback& callback) { | |
| 110 // Must have the secret. | |
| 111 DCHECK(!user_context.GetKey()->GetSecret().empty()); | |
| 112 // Only one pending request. | |
| 113 DCHECK(!HasPendingOperations()); | |
| 114 | |
| 115 remove_keys_op_.reset( | |
| 116 new EasyUnlockRemoveKeysOperation( | |
| 117 user_context, | |
| 118 start_index, | |
| 119 base::Bind(&EasyUnlockKeyManager::OnKeysRemoved, | |
| 120 weak_ptr_factory_.GetWeakPtr(), | |
| 121 callback))); | |
| 122 remove_keys_op_->Start(); | |
| 123 } | 95 } |
| 124 | 96 |
| 125 void EasyUnlockKeyManager::GetDeviceDataList( | 97 void EasyUnlockKeyManager::GetDeviceDataList( |
| 126 const UserContext& user_context, | 98 const UserContext& user_context, |
| 127 const GetDeviceDataListCallback& callback) { | 99 const GetDeviceDataListCallback& callback) { |
| 128 // Defer the get operation if there is pending write operations. | 100 read_operation_queue_.push_back(new EasyUnlockGetKeysOperation( |
| 129 if (create_keys_op_ || remove_keys_op_) { | 101 user_context, base::Bind(&EasyUnlockKeyManager::OnKeysFetched, |
| 130 pending_ops_.push_back(base::Bind(&EasyUnlockKeyManager::GetDeviceDataList, | 102 weak_ptr_factory_.GetWeakPtr(), callback))); |
| 131 weak_ptr_factory_.GetWeakPtr(), | 103 RunNextOperation(); |
| 132 user_context, | |
| 133 callback)); | |
| 134 return; | |
| 135 } | |
| 136 | |
| 137 const int op_id = GetNextOperationId(); | |
| 138 scoped_ptr<EasyUnlockGetKeysOperation> op(new EasyUnlockGetKeysOperation( | |
| 139 user_context, | |
| 140 base::Bind(&EasyUnlockKeyManager::OnKeysFetched, | |
| 141 weak_ptr_factory_.GetWeakPtr(), | |
| 142 op_id, | |
| 143 callback))); | |
| 144 op->Start(); | |
| 145 get_keys_ops_[op_id] = op.release(); | |
| 146 } | 104 } |
| 147 | 105 |
| 148 // static | 106 // static |
| 149 void EasyUnlockKeyManager::DeviceDataToRemoteDeviceDictionary( | 107 void EasyUnlockKeyManager::DeviceDataToRemoteDeviceDictionary( |
| 150 const std::string& user_id, | 108 const std::string& user_id, |
| 151 const EasyUnlockDeviceKeyData& data, | 109 const EasyUnlockDeviceKeyData& data, |
| 152 base::DictionaryValue* dict) { | 110 base::DictionaryValue* dict) { |
| 153 dict->SetString(kKeyBluetoothAddress, data.bluetooth_address); | 111 dict->SetString(kKeyBluetoothAddress, data.bluetooth_address); |
| 154 dict->SetString(kKeyPsk, data.psk); | 112 dict->SetString(kKeyPsk, data.psk); |
| 155 scoped_ptr<base::DictionaryValue> permit_record(new base::DictionaryValue); | 113 scoped_ptr<base::DictionaryValue> permit_record(new base::DictionaryValue); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 217 | 175 |
| 218 data_list->swap(parsed_devices); | 176 data_list->swap(parsed_devices); |
| 219 return true; | 177 return true; |
| 220 } | 178 } |
| 221 | 179 |
| 222 // static | 180 // static |
| 223 std::string EasyUnlockKeyManager::GetKeyLabel(size_t key_index) { | 181 std::string EasyUnlockKeyManager::GetKeyLabel(size_t key_index) { |
| 224 return base::StringPrintf("%s%zu", kKeyLabelPrefix, key_index); | 182 return base::StringPrintf("%s%zu", kKeyLabelPrefix, key_index); |
| 225 } | 183 } |
| 226 | 184 |
| 227 bool EasyUnlockKeyManager::HasPendingOperations() const { | 185 void EasyUnlockKeyManager::RunNextOperation() { |
| 228 return create_keys_op_ || remove_keys_op_ || !get_keys_ops_.empty(); | 186 if (pending_write_operation_ || pending_read_operation_) |
| 187 return; |
| 188 |
| 189 if (!write_operation_queue_.empty()) { |
| 190 pending_write_operation_ = make_scoped_ptr(write_operation_queue_.front()); |
| 191 write_operation_queue_.pop_front(); |
| 192 pending_write_operation_->Start(); |
| 193 } else if (!read_operation_queue_.empty()) { |
| 194 pending_read_operation_ = make_scoped_ptr(read_operation_queue_.front()); |
| 195 read_operation_queue_.pop_front(); |
| 196 pending_read_operation_->Start(); |
| 197 } |
| 229 } | 198 } |
| 230 | 199 |
| 231 int EasyUnlockKeyManager::GetNextOperationId() { | 200 void EasyUnlockKeyManager::OnKeysRefreshed(const RefreshKeysCallback& callback, |
| 232 return ++operation_id_; | 201 bool refresh_success) { |
| 233 } | 202 if (!callback.is_null()) |
| 203 callback.Run(refresh_success); |
| 234 | 204 |
| 235 void EasyUnlockKeyManager::RunNextPendingOp() { | 205 DCHECK(pending_write_operation_); |
| 236 if (pending_ops_.empty()) | 206 pending_write_operation_.reset(); |
| 237 return; | 207 RunNextOperation(); |
| 238 | |
| 239 pending_ops_.front().Run(); | |
| 240 pending_ops_.pop_front(); | |
| 241 } | |
| 242 | |
| 243 void EasyUnlockKeyManager::OnKeysCreated( | |
| 244 size_t remove_start_index, | |
| 245 const RefreshKeysCallback& callback, | |
| 246 bool create_success) { | |
| 247 scoped_ptr<EasyUnlockCreateKeysOperation> op = create_keys_op_.Pass(); | |
| 248 if (!callback.is_null()) | |
| 249 callback.Run(create_success); | |
| 250 | |
| 251 // Remove extra existing keys. | |
| 252 RemoveKeys(op->user_context(), remove_start_index, RemoveKeysCallback()); | |
| 253 } | |
| 254 | |
| 255 void EasyUnlockKeyManager::OnKeysRemoved(const RemoveKeysCallback& callback, | |
| 256 bool remove_success) { | |
| 257 scoped_ptr<EasyUnlockRemoveKeysOperation> op = remove_keys_op_.Pass(); | |
| 258 if (!callback.is_null()) | |
| 259 callback.Run(remove_success); | |
| 260 | |
| 261 if (!HasPendingOperations()) | |
| 262 RunNextPendingOp(); | |
| 263 } | 208 } |
| 264 | 209 |
| 265 void EasyUnlockKeyManager::OnKeysFetched( | 210 void EasyUnlockKeyManager::OnKeysFetched( |
| 266 int op_id, | |
| 267 const GetDeviceDataListCallback& callback, | 211 const GetDeviceDataListCallback& callback, |
| 268 bool fetch_success, | 212 bool fetch_success, |
| 269 const EasyUnlockDeviceKeyDataList& fetched_data) { | 213 const EasyUnlockDeviceKeyDataList& fetched_data) { |
| 270 std::map<int, EasyUnlockGetKeysOperation*>::iterator it = | |
| 271 get_keys_ops_.find(op_id); | |
| 272 scoped_ptr<EasyUnlockGetKeysOperation> op; | |
| 273 if (it != get_keys_ops_.end()) { | |
| 274 op.reset(it->second); | |
| 275 get_keys_ops_.erase(it); | |
| 276 } else { | |
| 277 NOTREACHED(); | |
| 278 } | |
| 279 | |
| 280 if (!callback.is_null()) | 214 if (!callback.is_null()) |
| 281 callback.Run(fetch_success, fetched_data); | 215 callback.Run(fetch_success, fetched_data); |
| 282 | 216 |
| 283 if (!HasPendingOperations()) | 217 DCHECK(pending_read_operation_); |
| 284 RunNextPendingOp(); | 218 pending_read_operation_.reset(); |
| 219 RunNextOperation(); |
| 285 } | 220 } |
| 286 | 221 |
| 287 } // namespace chromeos | 222 } // namespace chromeos |
| OLD | NEW |