OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/bind_helpers.h" | |
11 #include "base/callback.h" | |
12 #include "base/command_line.h" | |
13 #include "base/prefs/pref_service.h" | |
14 #include "base/threading/thread_checker.h" | |
15 #include "chrome/browser/chrome_notification_types.h" | |
16 #include "chrome/browser/chromeos/profiles/profile_helper.h" | |
17 #include "chrome/browser/chromeos/settings/cros_settings.h" | |
18 #include "chrome/browser/chromeos/settings/session_manager_operation.h" | |
19 #include "chrome/browser/profiles/profile.h" | |
20 #include "chromeos/dbus/dbus_thread_manager.h" | |
21 #include "chromeos/tpm_token_loader.h" | |
22 #include "components/ownership/owner_key_util.h" | |
23 #include "components/policy/core/common/cloud/cloud_policy_constants.h" | |
24 #include "content/public/browser/browser_thread.h" | |
25 #include "content/public/browser/notification_details.h" | |
26 #include "content/public/browser/notification_service.h" | |
27 #include "content/public/browser/notification_source.h" | |
28 #include "content/public/common/content_switches.h" | |
29 #include "crypto/nss_util.h" | |
30 #include "crypto/nss_util_internal.h" | |
31 #include "crypto/rsa_private_key.h" | |
32 #include "crypto/scoped_nss_types.h" | |
33 #include "crypto/signature_creator.h" | |
34 | |
35 namespace em = enterprise_management; | |
36 | |
37 using content::BrowserThread; | |
38 using ownership::OwnerKeyUtil; | |
39 using ownership::PrivateKey; | |
40 using ownership::PublicKey; | |
41 | |
42 namespace chromeos { | |
43 | |
44 namespace { | |
45 | |
46 DeviceSettingsService* g_device_settings_service_for_testing = NULL; | |
47 | |
48 bool IsOwnerInTests(const std::string& user_id) { | |
49 if (user_id.empty() || | |
50 !CommandLine::ForCurrentProcess()->HasSwitch(::switches::kTestType) || | |
51 !CrosSettings::IsInitialized()) { | |
52 return false; | |
53 } | |
54 const base::Value* value = CrosSettings::Get()->GetPref(kDeviceOwner); | |
55 if (!value || value->GetType() != base::Value::TYPE_STRING) | |
56 return false; | |
57 return static_cast<const base::StringValue*>(value)->GetString() == user_id; | |
58 } | |
59 | |
60 void LoadPrivateKeyByPublicKey( | |
61 const scoped_refptr<OwnerKeyUtil>& owner_key_util, | |
62 scoped_refptr<PublicKey> public_key, | |
63 const std::string& username_hash, | |
64 const base::Callback<void(const scoped_refptr<PublicKey>& public_key, | |
65 const scoped_refptr<PrivateKey>& private_key)>& | |
66 callback) { | |
67 crypto::EnsureNSSInit(); | |
68 crypto::ScopedPK11Slot slot = | |
69 crypto::GetPublicSlotForChromeOSUser(username_hash); | |
70 scoped_refptr<PrivateKey> private_key(new PrivateKey( | |
71 owner_key_util->FindPrivateKeyInSlot(public_key->data(), slot.get()))); | |
72 BrowserThread::PostTask(BrowserThread::UI, | |
73 FROM_HERE, | |
74 base::Bind(callback, public_key, private_key)); | |
75 } | |
76 | |
77 void LoadPrivateKey( | |
78 const scoped_refptr<OwnerKeyUtil>& owner_key_util, | |
79 const std::string username_hash, | |
80 const base::Callback<void(const scoped_refptr<PublicKey>& public_key, | |
81 const scoped_refptr<PrivateKey>& private_key)>& | |
82 callback) { | |
83 std::vector<uint8> public_key_data; | |
84 scoped_refptr<PublicKey> public_key; | |
85 if (!owner_key_util->ImportPublicKey(&public_key_data)) { | |
86 scoped_refptr<PrivateKey> private_key; | |
87 BrowserThread::PostTask(BrowserThread::UI, | |
88 FROM_HERE, | |
89 base::Bind(callback, public_key, private_key)); | |
90 return; | |
91 } | |
92 public_key = new PublicKey(); | |
93 public_key->data().swap(public_key_data); | |
94 bool rv = BrowserThread::PostTask(BrowserThread::IO, | |
95 FROM_HERE, | |
96 base::Bind(&LoadPrivateKeyByPublicKey, | |
97 owner_key_util, | |
98 public_key, | |
99 username_hash, | |
100 callback)); | |
101 if (!rv) { | |
102 // IO thread doesn't exists in unit tests, but it's safe to use NSS from | |
103 // BlockingPool in unit tests. | |
104 LoadPrivateKeyByPublicKey( | |
105 owner_key_util, public_key, username_hash, callback); | |
106 } | |
107 } | |
108 | |
109 bool DoesPrivateKeyExistAsyncHelper( | |
110 const scoped_refptr<OwnerKeyUtil>& owner_key_util) { | |
111 std::vector<uint8> public_key; | |
112 if (!owner_key_util->ImportPublicKey(&public_key)) | |
113 return false; | |
114 scoped_ptr<crypto::RSAPrivateKey> key( | |
115 crypto::RSAPrivateKey::FindFromPublicKeyInfo(public_key)); | |
116 bool is_owner = key.get() != NULL; | |
117 return is_owner; | |
118 } | |
119 | |
120 // Checks whether NSS slots with private key are mounted or | |
121 // not. Responds via |callback|. | |
122 void DoesPrivateKeyExistAsync( | |
123 const scoped_refptr<OwnerKeyUtil>& owner_key_util, | |
124 const OwnerSettingsServiceChromeOS::IsOwnerCallback& callback) { | |
125 if (!owner_key_util) { | |
126 callback.Run(false); | |
127 return; | |
128 } | |
129 scoped_refptr<base::TaskRunner> task_runner = | |
130 BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior( | |
131 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); | |
132 base::PostTaskAndReplyWithResult( | |
133 task_runner.get(), | |
134 FROM_HERE, | |
135 base::Bind(&DoesPrivateKeyExistAsyncHelper, owner_key_util), | |
136 callback); | |
137 } | |
138 | |
139 DeviceSettingsService* GetDeviceSettingsService() { | |
140 if (g_device_settings_service_for_testing) | |
141 return g_device_settings_service_for_testing; | |
142 return DeviceSettingsService::IsInitialized() ? DeviceSettingsService::Get() | |
143 : NULL; | |
144 } | |
145 | |
146 } // namespace | |
147 | |
148 OwnerSettingsServiceChromeOS::OwnerSettingsServiceChromeOS( | |
149 Profile* profile, | |
150 const scoped_refptr<OwnerKeyUtil>& owner_key_util) | |
151 : ownership::OwnerSettingsService(owner_key_util), | |
152 profile_(profile), | |
153 waiting_for_profile_creation_(true), | |
154 waiting_for_tpm_token_(true), | |
155 weak_factory_(this) { | |
156 if (TPMTokenLoader::IsInitialized()) { | |
157 TPMTokenLoader::TPMTokenStatus tpm_token_status = | |
158 TPMTokenLoader::Get()->IsTPMTokenEnabled( | |
159 base::Bind(&OwnerSettingsServiceChromeOS::OnTPMTokenReady, | |
160 weak_factory_.GetWeakPtr())); | |
161 waiting_for_tpm_token_ = | |
162 tpm_token_status == TPMTokenLoader::TPM_TOKEN_STATUS_UNDETERMINED; | |
163 } | |
164 | |
165 if (DBusThreadManager::IsInitialized() && | |
166 DBusThreadManager::Get()->GetSessionManagerClient()) { | |
167 DBusThreadManager::Get()->GetSessionManagerClient()->AddObserver(this); | |
168 } | |
169 | |
170 registrar_.Add(this, | |
171 chrome::NOTIFICATION_PROFILE_CREATED, | |
172 content::Source<Profile>(profile_)); | |
173 } | |
174 | |
175 OwnerSettingsServiceChromeOS::~OwnerSettingsServiceChromeOS() { | |
176 DCHECK(thread_checker_.CalledOnValidThread()); | |
177 if (DBusThreadManager::IsInitialized() && | |
178 DBusThreadManager::Get()->GetSessionManagerClient()) { | |
179 DBusThreadManager::Get()->GetSessionManagerClient()->RemoveObserver(this); | |
180 } | |
181 } | |
182 | |
183 void OwnerSettingsServiceChromeOS::OnTPMTokenReady( | |
184 bool /* tpm_token_enabled */) { | |
185 DCHECK(thread_checker_.CalledOnValidThread()); | |
186 waiting_for_tpm_token_ = false; | |
187 | |
188 // TPMTokenLoader initializes the TPM and NSS database which is necessary to | |
189 // determine ownership. Force a reload once we know these are initialized. | |
190 ReloadKeypair(); | |
191 } | |
192 | |
193 void OwnerSettingsServiceChromeOS::SignAndStorePolicyAsync( | |
194 scoped_ptr<em::PolicyData> policy, | |
195 const base::Closure& callback) { | |
196 DCHECK(thread_checker_.CalledOnValidThread()); | |
197 SignAndStoreSettingsOperation* operation = new SignAndStoreSettingsOperation( | |
198 base::Bind(&OwnerSettingsServiceChromeOS::HandleCompletedOperation, | |
199 weak_factory_.GetWeakPtr(), | |
200 callback), | |
201 policy.Pass()); | |
202 operation->set_owner_settings_service(weak_factory_.GetWeakPtr()); | |
203 pending_operations_.push_back(operation); | |
204 if (pending_operations_.front() == operation) | |
205 StartNextOperation(); | |
206 } | |
207 | |
208 void OwnerSettingsServiceChromeOS::Observe( | |
209 int type, | |
210 const content::NotificationSource& source, | |
211 const content::NotificationDetails& details) { | |
212 DCHECK(thread_checker_.CalledOnValidThread()); | |
213 if (type != chrome::NOTIFICATION_PROFILE_CREATED) { | |
214 NOTREACHED(); | |
215 return; | |
216 } | |
217 | |
218 Profile* profile = content::Source<Profile>(source).ptr(); | |
219 if (profile != profile_) { | |
220 NOTREACHED(); | |
221 return; | |
222 } | |
223 | |
224 waiting_for_profile_creation_ = false; | |
225 ReloadKeypair(); | |
226 } | |
227 | |
228 void OwnerSettingsServiceChromeOS::OwnerKeySet(bool success) { | |
229 DCHECK(thread_checker_.CalledOnValidThread()); | |
230 if (success) | |
231 ReloadKeypair(); | |
232 } | |
233 | |
234 // static | |
235 void OwnerSettingsServiceChromeOS::IsOwnerForSafeModeAsync( | |
236 const std::string& user_hash, | |
237 const scoped_refptr<OwnerKeyUtil>& owner_key_util, | |
238 const IsOwnerCallback& callback) { | |
239 CHECK(chromeos::LoginState::Get()->IsInSafeMode()); | |
240 | |
241 // Make sure NSS is initialized and NSS DB is loaded for the user before | |
242 // searching for the owner key. | |
243 BrowserThread::PostTaskAndReply( | |
244 BrowserThread::IO, | |
245 FROM_HERE, | |
246 base::Bind(base::IgnoreResult(&crypto::InitializeNSSForChromeOSUser), | |
247 user_hash, | |
248 ProfileHelper::GetProfilePathByUserIdHash(user_hash)), | |
249 base::Bind(&DoesPrivateKeyExistAsync, owner_key_util, callback)); | |
250 } | |
251 | |
252 // static | |
253 void OwnerSettingsServiceChromeOS::SetDeviceSettingsServiceForTesting( | |
254 DeviceSettingsService* device_settings_service) { | |
255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
256 g_device_settings_service_for_testing = device_settings_service; | |
257 } | |
258 | |
259 void OwnerSettingsServiceChromeOS::OnPostKeypairLoadedActions() { | |
260 DCHECK(thread_checker_.CalledOnValidThread()); | |
261 | |
262 user_id_ = profile_->GetProfileName(); | |
263 const bool is_owner = IsOwner() || IsOwnerInTests(user_id_); | |
264 if (is_owner && GetDeviceSettingsService()) | |
265 GetDeviceSettingsService()->InitOwner(user_id_, weak_factory_.GetWeakPtr()); | |
266 } | |
267 | |
268 void OwnerSettingsServiceChromeOS::ReloadKeypairImpl(const base::Callback< | |
269 void(const scoped_refptr<PublicKey>& public_key, | |
270 const scoped_refptr<PrivateKey>& private_key)>& callback) { | |
271 DCHECK(thread_checker_.CalledOnValidThread()); | |
272 | |
273 if (waiting_for_profile_creation_ || waiting_for_tpm_token_) | |
274 return; | |
275 scoped_refptr<base::TaskRunner> task_runner = | |
276 BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior( | |
277 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); | |
278 task_runner->PostTask( | |
279 FROM_HERE, | |
280 base::Bind(&LoadPrivateKey, | |
281 owner_key_util_, | |
282 ProfileHelper::GetUserIdHashFromProfile(profile_), | |
283 callback)); | |
284 } | |
285 | |
286 void OwnerSettingsServiceChromeOS::StartNextOperation() { | |
287 DeviceSettingsService* service = GetDeviceSettingsService(); | |
288 if (!pending_operations_.empty() && service && | |
289 service->session_manager_client()) { | |
290 pending_operations_.front()->Start( | |
291 service->session_manager_client(), owner_key_util_, public_key_); | |
292 } | |
293 } | |
294 | |
295 void OwnerSettingsServiceChromeOS::HandleCompletedOperation( | |
296 const base::Closure& callback, | |
297 SessionManagerOperation* operation, | |
298 DeviceSettingsService::Status status) { | |
299 DCHECK_EQ(operation, pending_operations_.front()); | |
300 | |
301 DeviceSettingsService* service = GetDeviceSettingsService(); | |
302 if (status == DeviceSettingsService::STORE_SUCCESS) { | |
303 service->set_policy_data(operation->policy_data().Pass()); | |
304 service->set_device_settings(operation->device_settings().Pass()); | |
305 } | |
306 | |
307 if ((operation->public_key() && !public_key_) || | |
308 (operation->public_key() && public_key_ && | |
309 operation->public_key()->data() != public_key_->data())) { | |
310 // Public part changed so we need to reload private part too. | |
311 ReloadKeypair(); | |
312 content::NotificationService::current()->Notify( | |
313 chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED, | |
314 content::Source<OwnerSettingsServiceChromeOS>(this), | |
315 content::NotificationService::NoDetails()); | |
316 } | |
317 service->OnSignAndStoreOperationCompleted(status); | |
318 if (!callback.is_null()) | |
319 callback.Run(); | |
320 | |
321 pending_operations_.pop_front(); | |
322 delete operation; | |
323 StartNextOperation(); | |
324 } | |
325 | |
326 } // namespace chromeos | |
OLD | NEW |