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/platform_keys/platform_keys_service.h" | 5 #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h" |
6 | 6 |
7 #include "base/base64.h" | 7 #include "base/base64.h" |
8 #include "base/callback.h" | 8 #include "base/callback.h" |
9 #include "base/callback_helpers.h" | 9 #include "base/callback_helpers.h" |
10 #include "base/values.h" | 10 #include "base/values.h" |
11 #include "chrome/browser/chromeos/platform_keys/platform_keys.h" | 11 #include "chrome/browser/chromeos/platform_keys/platform_keys.h" |
12 #include "content/public/browser/browser_thread.h" | 12 #include "content/public/browser/browser_thread.h" |
13 #include "extensions/browser/state_store.h" | 13 #include "extensions/browser/state_store.h" |
14 #include "net/cert/x509_certificate.h" | 14 #include "net/cert/x509_certificate.h" |
15 | 15 |
16 using content::BrowserThread; | 16 using content::BrowserThread; |
17 | 17 |
18 namespace chromeos { | 18 namespace chromeos { |
19 | 19 |
| 20 struct PlatformKeysService::KeyEntry { |
| 21 // The base64-encoded DER of a X.509 Subject Public Key Info. |
| 22 std::string spki_b64; |
| 23 |
| 24 // True if the key can be used once for singing. |
| 25 // This permission is granted if an extension generated a key using the |
| 26 // enterprise.platformKeys API, so that it can build a certification request.. |
| 27 // After the first signing operation this permission will be revoked. |
| 28 bool sign_once = false; |
| 29 |
| 30 // True if the key can be used for signing an unlimited number of times. |
| 31 // This permission is granted by the user or by policy to allow the extension |
| 32 // to use the key for signing through the enterprise.platformKeys or |
| 33 // platformKeys API. |
| 34 // This permission is granted until revoked by the user or the policy. |
| 35 bool sign_unlimited = false; |
| 36 }; |
| 37 |
20 namespace { | 38 namespace { |
21 | 39 |
22 const char kErrorKeyNotAllowedForSigning[] = | 40 const char kErrorKeyNotAllowedForSigning[] = |
23 "This key is not allowed for signing. Either it was used for signing " | 41 "This key is not allowed for signing. Either it was used for signing " |
24 "before or it was not correctly generated."; | 42 "before or it was not correctly generated."; |
| 43 |
| 44 // The key at which platform key specific data is stored in each extension's |
| 45 // state store. |
| 46 // From older versions of ChromeOS, this key can hold a list of base64 and |
| 47 // DER-encoded SPKIs. A key can be used for signing at most once if it is part |
| 48 // of that list |
| 49 // and removed from that list afterwards. |
| 50 // |
| 51 // The current format of data that is written to the PlatformKeys field is a |
| 52 // list of serialized KeyEntry objects: |
| 53 // { 'SPKI': string, |
| 54 // 'signOnce': bool, // if not present, defaults to false |
| 55 // 'signUnlimited': bool // if not present, defaults to false |
| 56 // } |
| 57 // |
| 58 // Do not change this constant as clients will lose their existing state. |
25 const char kStateStorePlatformKeys[] = "PlatformKeys"; | 59 const char kStateStorePlatformKeys[] = "PlatformKeys"; |
| 60 const char kStateStoreSPKI[] = "SPKI"; |
| 61 const char kStateStoreSignOnce[] = "signOnce"; |
| 62 const char kStateStoreSignUnlimited[] = "signUnlimited"; |
26 | 63 |
27 scoped_ptr<base::StringValue> GetPublicKeyValue( | 64 scoped_ptr<PlatformKeysService::KeyEntries> KeyEntriesFromState( |
28 const std::string& public_key_spki_der) { | 65 const base::Value& state) { |
29 std::string public_key_spki_der_b64; | 66 scoped_ptr<PlatformKeysService::KeyEntries> new_entries( |
30 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64); | 67 new PlatformKeysService::KeyEntries); |
31 return make_scoped_ptr(new base::StringValue(public_key_spki_der_b64)); | 68 |
| 69 const base::ListValue* entries = nullptr; |
| 70 if (!state.GetAsList(&entries)) { |
| 71 LOG(ERROR) << "Found a state store of wrong type."; |
| 72 return new_entries.Pass(); |
| 73 } |
| 74 for (const base::Value* entry : *entries) { |
| 75 if (!entry) { |
| 76 LOG(ERROR) << "Found invalid NULL entry in PlatformKeys state store."; |
| 77 continue; |
| 78 } |
| 79 |
| 80 PlatformKeysService::KeyEntry new_entry; |
| 81 const base::DictionaryValue* dict_entry = nullptr; |
| 82 if (entry->GetAsString(&new_entry.spki_b64)) { |
| 83 // This handles the case that the store contained a plain list of base64 |
| 84 // and DER-encoded SPKIs from an older version of ChromeOS. |
| 85 new_entry.sign_once = true; |
| 86 } else if (entry->GetAsDictionary(&dict_entry)) { |
| 87 dict_entry->GetStringWithoutPathExpansion(kStateStoreSPKI, |
| 88 &new_entry.spki_b64); |
| 89 dict_entry->GetBooleanWithoutPathExpansion(kStateStoreSignOnce, |
| 90 &new_entry.sign_once); |
| 91 dict_entry->GetBooleanWithoutPathExpansion(kStateStoreSignUnlimited, |
| 92 &new_entry.sign_unlimited); |
| 93 } else { |
| 94 LOG(ERROR) << "Found invalid entry of type " << entry->GetType() |
| 95 << " in PlatformKeys state store."; |
| 96 continue; |
| 97 } |
| 98 new_entries->push_back(new_entry); |
| 99 } |
| 100 return new_entries.Pass(); |
| 101 } |
| 102 |
| 103 scoped_ptr<base::ListValue> KeyEntriesToState( |
| 104 const PlatformKeysService::KeyEntries& entries) { |
| 105 scoped_ptr<base::ListValue> new_state(new base::ListValue); |
| 106 for (const PlatformKeysService::KeyEntry& entry : entries) { |
| 107 // Drop entries that the extension doesn't have any permissions for anymore. |
| 108 if (!entry.sign_once && !entry.sign_unlimited) |
| 109 continue; |
| 110 |
| 111 scoped_ptr<base::DictionaryValue> new_entry(new base::DictionaryValue); |
| 112 new_entry->SetStringWithoutPathExpansion(kStateStoreSPKI, entry.spki_b64); |
| 113 // Omit writing default values, namely |false|. |
| 114 if (entry.sign_once) { |
| 115 new_entry->SetBooleanWithoutPathExpansion(kStateStoreSignOnce, |
| 116 entry.sign_once); |
| 117 } |
| 118 if (entry.sign_unlimited) { |
| 119 new_entry->SetBooleanWithoutPathExpansion(kStateStoreSignUnlimited, |
| 120 entry.sign_unlimited); |
| 121 } |
| 122 new_state->Append(new_entry.release()); |
| 123 } |
| 124 return new_state.Pass(); |
| 125 } |
| 126 |
| 127 // Searches |platform_keys| for an entry for |public_key_spki_der_b64|. If found |
| 128 // returns a pointer to it, otherwise returns null. |
| 129 PlatformKeysService::KeyEntry* GetMatchingEntry( |
| 130 const std::string& public_key_spki_der_b64, |
| 131 PlatformKeysService::KeyEntries* platform_keys) { |
| 132 for (PlatformKeysService::KeyEntry& entry : *platform_keys) { |
| 133 // For every ASN.1 value there is exactly one DER encoding, so it is fine to |
| 134 // compare the DER (or its base64 encoding). |
| 135 if (entry.spki_b64 == public_key_spki_der_b64) |
| 136 return &entry; |
| 137 } |
| 138 return nullptr; |
32 } | 139 } |
33 | 140 |
34 } // namespace | 141 } // namespace |
35 | 142 |
36 class PlatformKeysService::Task { | 143 class PlatformKeysService::Task { |
37 public: | 144 public: |
38 Task() {} | 145 Task() {} |
39 virtual ~Task() {} | 146 virtual ~Task() {} |
40 virtual void Start() = 0; | 147 virtual void Start() = 0; |
41 virtual bool IsDone() = 0; | 148 virtual bool IsDone() = 0; |
42 | 149 |
43 private: | 150 private: |
44 DISALLOW_ASSIGN(Task); | 151 DISALLOW_ASSIGN(Task); |
45 }; | 152 }; |
46 | 153 |
47 class PlatformKeysService::PermissionUpdateTask : public Task { | 154 class PlatformKeysService::PermissionUpdateTask : public Task { |
48 public: | 155 public: |
49 enum class Step { | 156 enum class Step { |
50 READ_PLATFORM_KEYS, | 157 READ_PLATFORM_KEYS, |
51 WRITE_UPDATE_AND_CALLBACK, | 158 WRITE_UPDATE_AND_CALLBACK, |
52 DONE, | 159 DONE, |
53 }; | 160 }; |
54 | 161 |
55 // Creates a task that reads the current permission for an extension to access | 162 // Creates a task that reads the current permission for an extension to access |
56 // a certain key. Afterwards it updates and persists the permission to the new | 163 // a certain key. Afterwards it updates and persists the permission to the new |
57 // value |new_permission_value|. |callback| will be run after the permission | 164 // value |new_permission_value|. |callback| will be run after the permission |
58 // was persisted. The old permission value is then accessible through | 165 // was persisted. The old permission values are then available through |
59 // old_permission_value(). | 166 // old_key_entry(). |
60 PermissionUpdateTask(const bool new_permission_value, | 167 PermissionUpdateTask(const SignPermission permission, |
| 168 const bool new_permission_value, |
61 const std::string& public_key_spki_der, | 169 const std::string& public_key_spki_der, |
62 const std::string& extension_id, | 170 const std::string& extension_id, |
63 base::Callback<void(Task*)> callback, | 171 base::Callback<void(Task*)> callback, |
64 PlatformKeysService* service) | 172 PlatformKeysService* service) |
65 : new_permission_value_(new_permission_value), | 173 : permission_(permission), |
| 174 new_permission_value_(new_permission_value), |
66 public_key_spki_der_(public_key_spki_der), | 175 public_key_spki_der_(public_key_spki_der), |
67 extension_id_(extension_id), | 176 extension_id_(extension_id), |
68 callback_(callback), | 177 callback_(callback), |
69 service_(service), | 178 service_(service), |
70 weak_factory_(this) {} | 179 weak_factory_(this) {} |
71 | 180 |
72 ~PermissionUpdateTask() override {} | 181 ~PermissionUpdateTask() override {} |
73 | 182 |
74 void Start() override { | 183 void Start() override { |
75 CHECK(next_step_ == Step::READ_PLATFORM_KEYS); | 184 CHECK(next_step_ == Step::READ_PLATFORM_KEYS); |
76 DoStep(); | 185 DoStep(); |
77 } | 186 } |
78 | 187 |
79 bool IsDone() override { return next_step_ == Step::DONE; } | 188 bool IsDone() override { return next_step_ == Step::DONE; } |
80 | 189 |
81 // The original permission value before setting the new value | 190 // The old key entry with the old permissions before setting |permission| to |
82 // |new_permission_value|. | 191 // the new value |new_permission_value|. |
83 bool old_permission_value() { return old_permission_value_; } | 192 const KeyEntry& old_key_entry() { return old_key_entry_; } |
84 | 193 |
85 private: | 194 private: |
86 void DoStep() { | 195 void DoStep() { |
87 switch (next_step_) { | 196 switch (next_step_) { |
88 case Step::READ_PLATFORM_KEYS: | 197 case Step::READ_PLATFORM_KEYS: |
89 next_step_ = Step::WRITE_UPDATE_AND_CALLBACK; | 198 next_step_ = Step::WRITE_UPDATE_AND_CALLBACK; |
90 ReadPlatformKeys(); | 199 ReadPlatformKeys(); |
91 return; | 200 return; |
92 case Step::WRITE_UPDATE_AND_CALLBACK: | 201 case Step::WRITE_UPDATE_AND_CALLBACK: |
93 next_step_ = Step::DONE; | 202 next_step_ = Step::DONE; |
(...skipping 12 matching lines...) Expand all Loading... |
106 } | 215 } |
107 | 216 |
108 // Reads the PlatformKeys value from the extension's state store and calls | 217 // Reads the PlatformKeys value from the extension's state store and calls |
109 // back to GotPlatformKeys(). | 218 // back to GotPlatformKeys(). |
110 void ReadPlatformKeys() { | 219 void ReadPlatformKeys() { |
111 service_->GetPlatformKeysOfExtension( | 220 service_->GetPlatformKeysOfExtension( |
112 extension_id_, base::Bind(&PermissionUpdateTask::GotPlatformKeys, | 221 extension_id_, base::Bind(&PermissionUpdateTask::GotPlatformKeys, |
113 weak_factory_.GetWeakPtr())); | 222 weak_factory_.GetWeakPtr())); |
114 } | 223 } |
115 | 224 |
116 void GotPlatformKeys(scoped_ptr<base::ListValue> platform_keys) { | 225 void GotPlatformKeys(scoped_ptr<KeyEntries> platform_keys) { |
117 platform_keys_ = platform_keys.Pass(); | 226 platform_keys_ = platform_keys.Pass(); |
118 DoStep(); | 227 DoStep(); |
119 } | 228 } |
120 | 229 |
121 // Returns whether the extension has permission to use the key for signing | 230 // Persists the existing KeyEntry in |old_key_entry_|, updates the entry with |
122 // according to the PlatformKeys value read from the extensions state store. | 231 // the new permission and persists it to the extension's state store if it was |
123 // Invalidates the key if it was found to be valid. | 232 // changed. |
124 void WriteUpdate() { | 233 void WriteUpdate() { |
125 scoped_ptr<base::StringValue> key_value( | 234 DCHECK(platform_keys_); |
126 GetPublicKeyValue(public_key_spki_der_)); | |
127 | 235 |
128 base::ListValue::const_iterator it = platform_keys_->Find(*key_value); | 236 std::string public_key_spki_der_b64; |
129 old_permission_value_ = it != platform_keys_->end(); | 237 base::Base64Encode(public_key_spki_der_, &public_key_spki_der_b64); |
130 if (old_permission_value_ == new_permission_value_) | |
131 return; | |
132 | 238 |
133 if (new_permission_value_) | 239 KeyEntry* matching_entry = |
134 platform_keys_->Append(key_value.release()); | 240 GetMatchingEntry(public_key_spki_der_b64, platform_keys_.get()); |
135 else | |
136 platform_keys_->Remove(*key_value, nullptr); | |
137 | 241 |
138 service_->SetPlatformKeysOfExtension(extension_id_, platform_keys_.Pass()); | 242 if (!matching_entry) { |
| 243 platform_keys_->push_back(KeyEntry()); |
| 244 matching_entry = &platform_keys_->back(); |
| 245 matching_entry->spki_b64 = public_key_spki_der_b64; |
| 246 } else if (permission_ == SignPermission::ONCE && new_permission_value_) { |
| 247 // The one-time sign permission is supposed to be granted once per key |
| 248 // during generation. Generated keys should be unique and thus this case |
| 249 // should never occur. |
| 250 NOTREACHED() << "Requested one-time sign permission on existing key."; |
| 251 } |
| 252 old_key_entry_ = *matching_entry; |
| 253 |
| 254 bool* permission_value = nullptr; |
| 255 switch (permission_) { |
| 256 case SignPermission::ONCE: |
| 257 permission_value = &matching_entry->sign_once; |
| 258 break; |
| 259 case SignPermission::UNLIMITED: |
| 260 permission_value = &matching_entry->sign_unlimited; |
| 261 break; |
| 262 } |
| 263 |
| 264 if (*permission_value != new_permission_value_) { |
| 265 *permission_value = new_permission_value_; |
| 266 service_->SetPlatformKeysOfExtension(extension_id_, *platform_keys_); |
| 267 } |
139 } | 268 } |
140 | 269 |
141 Step next_step_ = Step::READ_PLATFORM_KEYS; | 270 Step next_step_ = Step::READ_PLATFORM_KEYS; |
142 scoped_ptr<base::ListValue> platform_keys_; | 271 KeyEntry old_key_entry_; |
143 bool old_permission_value_ = false; | |
144 | 272 |
| 273 const SignPermission permission_; |
145 const bool new_permission_value_; | 274 const bool new_permission_value_; |
146 const std::string public_key_spki_der_; | 275 const std::string public_key_spki_der_; |
147 const std::string extension_id_; | 276 const std::string extension_id_; |
| 277 scoped_ptr<KeyEntries> platform_keys_; |
148 base::Callback<void(Task*)> callback_; | 278 base::Callback<void(Task*)> callback_; |
149 PlatformKeysService* const service_; | 279 PlatformKeysService* const service_; |
150 base::WeakPtrFactory<PermissionUpdateTask> weak_factory_; | 280 base::WeakPtrFactory<PermissionUpdateTask> weak_factory_; |
151 | 281 |
152 DISALLOW_COPY_AND_ASSIGN(PermissionUpdateTask); | 282 DISALLOW_COPY_AND_ASSIGN(PermissionUpdateTask); |
153 }; | 283 }; |
154 | 284 |
155 class PlatformKeysService::SignTask : public Task { | 285 class PlatformKeysService::SignTask : public Task { |
156 public: | 286 public: |
157 enum class Step { | 287 enum class Step { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
191 } | 321 } |
192 bool IsDone() override { return next_step_ == Step::DONE; } | 322 bool IsDone() override { return next_step_ == Step::DONE; } |
193 | 323 |
194 private: | 324 private: |
195 void DoStep() { | 325 void DoStep() { |
196 switch (next_step_) { | 326 switch (next_step_) { |
197 case Step::UPDATE_PERMISSION: | 327 case Step::UPDATE_PERMISSION: |
198 next_step_ = Step::SIGN_OR_ABORT; | 328 next_step_ = Step::SIGN_OR_ABORT; |
199 UpdatePermission(); | 329 UpdatePermission(); |
200 return; | 330 return; |
201 case Step::SIGN_OR_ABORT: | 331 case Step::SIGN_OR_ABORT: { |
202 next_step_ = Step::DONE; | 332 next_step_ = Step::DONE; |
203 if (!service_->permission_check_enabled_ || | 333 bool sign_granted = permission_update_->old_key_entry().sign_once || |
204 permission_update_->old_permission_value()) { | 334 permission_update_->old_key_entry().sign_unlimited; |
| 335 if (sign_granted) { |
205 Sign(); | 336 Sign(); |
206 } else { | 337 } else { |
207 callback_.Run(std::string() /* no signature */, | 338 if (!callback_.is_null()) { |
208 kErrorKeyNotAllowedForSigning); | 339 callback_.Run(std::string() /* no signature */, |
| 340 kErrorKeyNotAllowedForSigning); |
| 341 } |
209 DoStep(); | 342 DoStep(); |
210 } | 343 } |
211 return; | 344 return; |
| 345 } |
212 case Step::DONE: | 346 case Step::DONE: |
213 service_->TaskFinished(this); | 347 service_->TaskFinished(this); |
214 // |this| might be invalid now. | 348 // |this| might be invalid now. |
215 return; | 349 return; |
216 } | 350 } |
217 } | 351 } |
218 | 352 |
219 // Reads the current permission of the extension with |extension_id_| for key | 353 // Reads the current permission of the extension with |extension_id_| for key |
220 // |params_->public_key| and updates the permission to disable further | 354 // |params_->public_key| and updates the permission to disable further |
221 // signing operations with that key. | 355 // signing operations with that key. |
222 void UpdatePermission() { | 356 void UpdatePermission() { |
223 permission_update_.reset(new PermissionUpdateTask( | 357 permission_update_.reset(new PermissionUpdateTask( |
224 false /* new permission value */, public_key_, extension_id_, | 358 SignPermission::ONCE, false /* new permission value */, public_key_, |
| 359 extension_id_, |
225 base::Bind(&SignTask::DidUpdatePermission, weak_factory_.GetWeakPtr()), | 360 base::Bind(&SignTask::DidUpdatePermission, weak_factory_.GetWeakPtr()), |
226 service_)); | 361 service_)); |
227 permission_update_->Start(); | 362 permission_update_->Start(); |
228 } | 363 } |
229 | 364 |
230 void DidUpdatePermission(Task* /* task */) { DoStep(); } | 365 void DidUpdatePermission(Task* /* task */) { DoStep(); } |
231 | 366 |
232 // Starts the actual signing operation and afterwards passes the signature (or | 367 // Starts the actual signing operation and afterwards passes the signature (or |
233 // error) to |callback_|. | 368 // error) to |callback_|. |
234 void Sign() { | 369 void Sign() { |
235 if (sign_direct_pkcs_padded_) { | 370 if (sign_direct_pkcs_padded_) { |
236 platform_keys::subtle::SignRSAPKCS1Raw( | 371 platform_keys::subtle::SignRSAPKCS1Raw( |
237 token_id_, data_, public_key_, | 372 token_id_, data_, public_key_, |
238 base::Bind(&SignTask::DidSign, weak_factory_.GetWeakPtr()), | 373 base::Bind(&SignTask::DidSign, weak_factory_.GetWeakPtr()), |
239 service_->browser_context_); | 374 service_->browser_context_); |
240 } else { | 375 } else { |
241 platform_keys::subtle::SignRSAPKCS1Digest( | 376 platform_keys::subtle::SignRSAPKCS1Digest( |
242 token_id_, data_, public_key_, hash_algorithm_, | 377 token_id_, data_, public_key_, hash_algorithm_, |
243 base::Bind(&SignTask::DidSign, weak_factory_.GetWeakPtr()), | 378 base::Bind(&SignTask::DidSign, weak_factory_.GetWeakPtr()), |
244 service_->browser_context_); | 379 service_->browser_context_); |
245 } | 380 } |
246 } | 381 } |
247 | 382 |
248 void DidSign(const std::string& signature, const std::string& error_message) { | 383 void DidSign(const std::string& signature, const std::string& error_message) { |
249 callback_.Run(signature, error_message); | 384 callback_.Run(signature, error_message); |
250 DoStep(); | 385 DoStep(); |
251 } | 386 } |
252 | 387 |
253 Step next_step_ = Step::UPDATE_PERMISSION; | 388 Step next_step_ = Step::UPDATE_PERMISSION; |
254 scoped_ptr<base::ListValue> platform_keys_; | 389 scoped_ptr<KeyEntries> platform_keys_; |
255 scoped_ptr<PermissionUpdateTask> permission_update_; | 390 scoped_ptr<PermissionUpdateTask> permission_update_; |
256 | 391 |
257 const std::string token_id_; | 392 const std::string token_id_; |
258 const std::string data_; | 393 const std::string data_; |
259 const std::string public_key_; | 394 const std::string public_key_; |
260 | 395 |
261 // If true, |data_| will not be hashed before signing. Only PKCS#1 v1.5 | 396 // If true, |data_| will not be hashed before signing. Only PKCS#1 v1.5 |
262 // padding will be applied before signing. | 397 // padding will be applied before signing. |
263 // If false, |hash_algorithm_| is set to a value != NONE. | 398 // If false, |hash_algorithm_| is set to a value != NONE. |
264 const bool sign_direct_pkcs_padded_; | 399 const bool sign_direct_pkcs_padded_; |
265 const platform_keys::HashAlgorithm hash_algorithm_; | 400 const platform_keys::HashAlgorithm hash_algorithm_; |
266 const std::string extension_id_; | 401 const std::string extension_id_; |
267 const SignCallback callback_; | 402 const SignCallback callback_; |
268 PlatformKeysService* const service_; | 403 PlatformKeysService* const service_; |
269 base::WeakPtrFactory<SignTask> weak_factory_; | 404 base::WeakPtrFactory<SignTask> weak_factory_; |
270 | 405 |
271 DISALLOW_COPY_AND_ASSIGN(SignTask); | 406 DISALLOW_COPY_AND_ASSIGN(SignTask); |
272 }; | 407 }; |
273 | 408 |
| 409 class PlatformKeysService::SelectTask : public Task { |
| 410 public: |
| 411 enum class Step { |
| 412 GET_MATCHING_CERTS, |
| 413 SELECT_CERTS, |
| 414 READ_PLATFORM_KEYS, |
| 415 UPDATE_PERMISSION, |
| 416 FILTER_BY_PERMISSIONS, |
| 417 DONE, |
| 418 }; |
| 419 |
| 420 // This task determines all known client certs matching |request|. If |
| 421 // |interactive| is true, calls |service->select_delegate_->Select()| to |
| 422 // select a cert from all matches. The extension with |extension_id| will be |
| 423 // granted unlimited sign permission for the selected cert. |
| 424 // Finally, either the selection or, if |interactive| is false, matching certs |
| 425 // that the extension has permission for are passed to |callback|. |
| 426 SelectTask(const platform_keys::ClientCertificateRequest& request, |
| 427 bool interactive, |
| 428 const std::string& extension_id, |
| 429 const SelectCertificatesCallback& callback, |
| 430 PlatformKeysService* service) |
| 431 : request_(request), |
| 432 interactive_(interactive), |
| 433 extension_id_(extension_id), |
| 434 callback_(callback), |
| 435 service_(service), |
| 436 weak_factory_(this) {} |
| 437 ~SelectTask() override {} |
| 438 |
| 439 void Start() override { |
| 440 CHECK(next_step_ == Step::GET_MATCHING_CERTS); |
| 441 DoStep(); |
| 442 } |
| 443 bool IsDone() override { return next_step_ == Step::DONE; } |
| 444 |
| 445 private: |
| 446 void DoStep() { |
| 447 switch (next_step_) { |
| 448 case Step::GET_MATCHING_CERTS: |
| 449 if (interactive_) |
| 450 next_step_ = Step::SELECT_CERTS; |
| 451 else // Skip SelectCerts and UpdatePermission if not interactive. |
| 452 next_step_ = Step::READ_PLATFORM_KEYS; |
| 453 GetMatchingCerts(); |
| 454 return; |
| 455 case Step::SELECT_CERTS: |
| 456 next_step_ = Step::UPDATE_PERMISSION; |
| 457 SelectCerts(); |
| 458 return; |
| 459 case Step::UPDATE_PERMISSION: |
| 460 next_step_ = Step::READ_PLATFORM_KEYS; |
| 461 UpdatePermission(); |
| 462 return; |
| 463 case Step::READ_PLATFORM_KEYS: |
| 464 next_step_ = Step::FILTER_BY_PERMISSIONS; |
| 465 ReadPlatformKeys(); |
| 466 return; |
| 467 case Step::FILTER_BY_PERMISSIONS: |
| 468 next_step_ = Step::DONE; |
| 469 FilterSelectionByPermission(); |
| 470 return; |
| 471 case Step::DONE: |
| 472 service_->TaskFinished(this); |
| 473 // |this| might be invalid now. |
| 474 return; |
| 475 } |
| 476 } |
| 477 |
| 478 // Retrieves all certificates matching |request_|. Will call back to |
| 479 // |GotMatchingCerts()|. |
| 480 void GetMatchingCerts() { |
| 481 platform_keys::subtle::SelectClientCertificates( |
| 482 request_, |
| 483 base::Bind(&SelectTask::GotMatchingCerts, weak_factory_.GetWeakPtr()), |
| 484 service_->browser_context_); |
| 485 } |
| 486 |
| 487 // If the certificate request could be processed successfully, |matches| will |
| 488 // contain the list of matching certificates (maybe empty) and |error_message| |
| 489 // will be empty. If an error occurred, |matches| will be null and |
| 490 // |error_message| contain an error message. |
| 491 void GotMatchingCerts(scoped_ptr<net::CertificateList> matches, |
| 492 const std::string& error_message) { |
| 493 if (!error_message.empty()) { |
| 494 next_step_ = Step::DONE; |
| 495 callback_.Run(nullptr /* no certificates */, error_message); |
| 496 DoStep(); |
| 497 return; |
| 498 } |
| 499 matches_.swap(*matches); |
| 500 DoStep(); |
| 501 } |
| 502 |
| 503 // Calls |service_->select_delegate_->Select()| to select a cert from |
| 504 // |matches_|, which will be stored in |selected_cert_|. |
| 505 // Will call back to |GotSelection()|. |
| 506 void SelectCerts() { |
| 507 CHECK(interactive_); |
| 508 if (matches_.empty()) { |
| 509 // Don't show a select dialog if no certificate is matching. |
| 510 DoStep(); |
| 511 return; |
| 512 } |
| 513 service_->select_delegate_->Select( |
| 514 extension_id_, matches_, |
| 515 base::Bind(&SelectTask::GotSelection, base::Unretained(this))); |
| 516 } |
| 517 |
| 518 // Will be called by |SelectCerts()| with the selected cert or null if no cert |
| 519 // was selected. |
| 520 void GotSelection(scoped_refptr<net::X509Certificate> selected_cert) { |
| 521 selected_cert_ = selected_cert; |
| 522 DoStep(); |
| 523 } |
| 524 |
| 525 // Updates the extension's state store about unlimited sign permission for the |
| 526 // selected cert. Does nothing if no cert was selected. |
| 527 // Will call back to |DidUpdatePermission()|. |
| 528 void UpdatePermission() { |
| 529 CHECK(interactive_); |
| 530 if (!selected_cert_) { |
| 531 DoStep(); |
| 532 return; |
| 533 } |
| 534 const std::string public_key_spki_der( |
| 535 platform_keys::GetSubjectPublicKeyInfo(selected_cert_)); |
| 536 permission_update_.reset(new PermissionUpdateTask( |
| 537 SignPermission::UNLIMITED, true /* new permission value */, |
| 538 public_key_spki_der, extension_id_, |
| 539 base::Bind(&SelectTask::DidUpdatePermission, base::Unretained(this)), |
| 540 service_)); |
| 541 permission_update_->Start(); |
| 542 } |
| 543 |
| 544 void DidUpdatePermission(Task* /* task */) { DoStep(); } |
| 545 |
| 546 // Reads the PlatformKeys value from the extension's state store and calls |
| 547 // back to GotPlatformKeys(). |
| 548 void ReadPlatformKeys() { |
| 549 service_->GetPlatformKeysOfExtension( |
| 550 extension_id_, |
| 551 base::Bind(&SelectTask::GotPlatformKeys, weak_factory_.GetWeakPtr())); |
| 552 } |
| 553 |
| 554 void GotPlatformKeys(scoped_ptr<KeyEntries> platform_keys) { |
| 555 platform_keys_ = platform_keys.Pass(); |
| 556 DoStep(); |
| 557 } |
| 558 |
| 559 // Filters from all matches (if not interactive) or from the selection (if |
| 560 // interactive), the certificates that the extension has unlimited sign |
| 561 // permission for. Passes the filtered certs to |callback_|. |
| 562 void FilterSelectionByPermission() { |
| 563 scoped_ptr<net::CertificateList> selection(new net::CertificateList); |
| 564 if (interactive_) { |
| 565 if (selected_cert_) |
| 566 selection->push_back(selected_cert_); |
| 567 } else { |
| 568 selection->assign(matches_.begin(), matches_.end()); |
| 569 } |
| 570 |
| 571 scoped_ptr<net::CertificateList> filtered_certs(new net::CertificateList); |
| 572 for (scoped_refptr<net::X509Certificate> selected_cert : *selection) { |
| 573 const std::string public_key_spki_der( |
| 574 platform_keys::GetSubjectPublicKeyInfo(selected_cert)); |
| 575 std::string public_key_spki_der_b64; |
| 576 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64); |
| 577 |
| 578 KeyEntry* matching_entry = |
| 579 GetMatchingEntry(public_key_spki_der_b64, platform_keys_.get()); |
| 580 if (!matching_entry || !matching_entry->sign_unlimited) |
| 581 continue; |
| 582 |
| 583 filtered_certs->push_back(selected_cert); |
| 584 } |
| 585 // Note: In the interactive case this should have filtered exactly the |
| 586 // one selected cert. Checking the permissions again is not striclty |
| 587 // necessary but this ensures that the permissions were updated correctly. |
| 588 CHECK(!selected_cert_ || (filtered_certs->size() == 1 && |
| 589 filtered_certs->front() == selected_cert_)); |
| 590 callback_.Run(filtered_certs.Pass(), std::string() /* no error */); |
| 591 DoStep(); |
| 592 } |
| 593 |
| 594 Step next_step_ = Step::GET_MATCHING_CERTS; |
| 595 scoped_ptr<KeyEntries> platform_keys_; |
| 596 scoped_ptr<PermissionUpdateTask> permission_update_; |
| 597 |
| 598 net::CertificateList matches_; |
| 599 scoped_refptr<net::X509Certificate> selected_cert_; |
| 600 platform_keys::ClientCertificateRequest request_; |
| 601 const bool interactive_; |
| 602 const std::string extension_id_; |
| 603 const SelectCertificatesCallback callback_; |
| 604 PlatformKeysService* const service_; |
| 605 base::WeakPtrFactory<SelectTask> weak_factory_; |
| 606 |
| 607 DISALLOW_COPY_AND_ASSIGN(SelectTask); |
| 608 }; |
| 609 |
| 610 PlatformKeysService::SelectDelegate::SelectDelegate() { |
| 611 } |
| 612 |
| 613 PlatformKeysService::SelectDelegate::~SelectDelegate() { |
| 614 } |
| 615 |
274 PlatformKeysService::PlatformKeysService( | 616 PlatformKeysService::PlatformKeysService( |
275 content::BrowserContext* browser_context, | 617 content::BrowserContext* browser_context, |
276 extensions::StateStore* state_store) | 618 extensions::StateStore* state_store) |
277 : browser_context_(browser_context), | 619 : browser_context_(browser_context), |
278 state_store_(state_store), | 620 state_store_(state_store), |
279 weak_factory_(this) { | 621 weak_factory_(this) { |
280 DCHECK(state_store); | 622 DCHECK(state_store); |
281 } | 623 } |
282 | 624 |
283 PlatformKeysService::~PlatformKeysService() { | 625 PlatformKeysService::~PlatformKeysService() { |
284 } | 626 } |
285 | 627 |
286 void PlatformKeysService::DisablePermissionCheckForTesting() { | 628 void PlatformKeysService::SetSelectDelegate( |
287 permission_check_enabled_ = false; | 629 scoped_ptr<SelectDelegate> delegate) { |
| 630 select_delegate_ = delegate.Pass(); |
| 631 } |
| 632 |
| 633 void PlatformKeysService::GrantUnlimitedSignPermission( |
| 634 const std::string& extension_id, |
| 635 scoped_refptr<net::X509Certificate> cert) { |
| 636 const std::string public_key_spki_der( |
| 637 platform_keys::GetSubjectPublicKeyInfo(cert)); |
| 638 |
| 639 StartOrQueueTask(make_scoped_ptr(new PermissionUpdateTask( |
| 640 SignPermission::UNLIMITED, true /* new permission value */, |
| 641 public_key_spki_der, extension_id, |
| 642 base::Bind(&PlatformKeysService::TaskFinished, base::Unretained(this)), |
| 643 this))); |
288 } | 644 } |
289 | 645 |
290 void PlatformKeysService::GenerateRSAKey(const std::string& token_id, | 646 void PlatformKeysService::GenerateRSAKey(const std::string& token_id, |
291 unsigned int modulus_length, | 647 unsigned int modulus_length, |
292 const std::string& extension_id, | 648 const std::string& extension_id, |
293 const GenerateKeyCallback& callback) { | 649 const GenerateKeyCallback& callback) { |
294 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 650 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
295 | 651 |
296 platform_keys::subtle::GenerateRSAKey( | 652 platform_keys::subtle::GenerateRSAKey( |
297 token_id, modulus_length, | 653 token_id, modulus_length, |
(...skipping 21 matching lines...) Expand all Loading... |
319 const std::string& extension_id, | 675 const std::string& extension_id, |
320 const SignCallback& callback) { | 676 const SignCallback& callback) { |
321 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 677 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
322 StartOrQueueTask(make_scoped_ptr(new SignTask( | 678 StartOrQueueTask(make_scoped_ptr(new SignTask( |
323 token_id, data, public_key, true /* sign directly without hashing */, | 679 token_id, data, public_key, true /* sign directly without hashing */, |
324 platform_keys::HASH_ALGORITHM_NONE, extension_id, callback, this))); | 680 platform_keys::HASH_ALGORITHM_NONE, extension_id, callback, this))); |
325 } | 681 } |
326 | 682 |
327 void PlatformKeysService::SelectClientCertificates( | 683 void PlatformKeysService::SelectClientCertificates( |
328 const platform_keys::ClientCertificateRequest& request, | 684 const platform_keys::ClientCertificateRequest& request, |
| 685 bool interactive, |
329 const std::string& extension_id, | 686 const std::string& extension_id, |
330 const SelectCertificatesCallback& callback) { | 687 const SelectCertificatesCallback& callback) { |
331 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 688 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
332 | 689 StartOrQueueTask(make_scoped_ptr( |
333 platform_keys::subtle::SelectClientCertificates( | 690 new SelectTask(request, interactive, extension_id, callback, this))); |
334 request, | |
335 base::Bind(&PlatformKeysService::SelectClientCertificatesCallback, | |
336 weak_factory_.GetWeakPtr(), extension_id, callback), | |
337 browser_context_); | |
338 } | 691 } |
339 | 692 |
340 void PlatformKeysService::StartOrQueueTask(scoped_ptr<Task> task) { | 693 void PlatformKeysService::StartOrQueueTask(scoped_ptr<Task> task) { |
341 tasks_.push(make_linked_ptr(task.release())); | 694 tasks_.push(make_linked_ptr(task.release())); |
342 if (tasks_.size() == 1) | 695 if (tasks_.size() == 1) |
343 tasks_.front()->Start(); | 696 tasks_.front()->Start(); |
344 } | 697 } |
345 | 698 |
346 void PlatformKeysService::TaskFinished(Task* task) { | 699 void PlatformKeysService::TaskFinished(Task* task) { |
347 DCHECK(!tasks_.empty()); | 700 DCHECK(!tasks_.empty()); |
(...skipping 12 matching lines...) Expand all Loading... |
360 const std::string& extension_id, | 713 const std::string& extension_id, |
361 const GetPlatformKeysCallback& callback) { | 714 const GetPlatformKeysCallback& callback) { |
362 state_store_->GetExtensionValue( | 715 state_store_->GetExtensionValue( |
363 extension_id, kStateStorePlatformKeys, | 716 extension_id, kStateStorePlatformKeys, |
364 base::Bind(&PlatformKeysService::GotPlatformKeysOfExtension, | 717 base::Bind(&PlatformKeysService::GotPlatformKeysOfExtension, |
365 weak_factory_.GetWeakPtr(), extension_id, callback)); | 718 weak_factory_.GetWeakPtr(), extension_id, callback)); |
366 } | 719 } |
367 | 720 |
368 void PlatformKeysService::SetPlatformKeysOfExtension( | 721 void PlatformKeysService::SetPlatformKeysOfExtension( |
369 const std::string& extension_id, | 722 const std::string& extension_id, |
370 scoped_ptr<base::ListValue> platform_keys) { | 723 const KeyEntries& platform_keys) { |
371 state_store_->SetExtensionValue(extension_id, kStateStorePlatformKeys, | 724 state_store_->SetExtensionValue(extension_id, kStateStorePlatformKeys, |
372 platform_keys.Pass()); | 725 KeyEntriesToState(platform_keys)); |
373 } | 726 } |
374 | 727 |
375 void PlatformKeysService::GeneratedKey(const std::string& extension_id, | 728 void PlatformKeysService::GeneratedKey(const std::string& extension_id, |
376 const GenerateKeyCallback& callback, | 729 const GenerateKeyCallback& callback, |
377 const std::string& public_key_spki_der, | 730 const std::string& public_key_spki_der, |
378 const std::string& error_message) { | 731 const std::string& error_message) { |
379 if (!error_message.empty()) { | 732 if (!error_message.empty()) { |
380 callback.Run(std::string() /* no public key */, error_message); | 733 callback.Run(std::string() /* no public key */, error_message); |
381 return; | 734 return; |
382 } | 735 } |
383 | 736 |
384 StartOrQueueTask(make_scoped_ptr(new PermissionUpdateTask( | 737 StartOrQueueTask(make_scoped_ptr(new PermissionUpdateTask( |
385 true /* new permission value */, public_key_spki_der, extension_id, | 738 SignPermission::ONCE, true /* new permission value */, |
| 739 public_key_spki_der, extension_id, |
386 base::Bind(&PlatformKeysService::RegisteredGeneratedKey, | 740 base::Bind(&PlatformKeysService::RegisteredGeneratedKey, |
387 base::Unretained(this), callback, public_key_spki_der), | 741 base::Unretained(this), callback, public_key_spki_der), |
388 this))); | 742 this))); |
389 } | 743 } |
390 | 744 |
391 void PlatformKeysService::RegisteredGeneratedKey( | 745 void PlatformKeysService::RegisteredGeneratedKey( |
392 const GenerateKeyCallback& callback, | 746 const GenerateKeyCallback& callback, |
393 const std::string& public_key_spki_der, | 747 const std::string& public_key_spki_der, |
394 Task* task) { | 748 Task* task) { |
395 callback.Run(public_key_spki_der, std::string() /* no error */); | 749 callback.Run(public_key_spki_der, std::string() /* no error */); |
396 TaskFinished(task); | 750 TaskFinished(task); |
397 } | 751 } |
398 | 752 |
399 void PlatformKeysService::SelectClientCertificatesCallback( | |
400 const std::string& extension_id, | |
401 const SelectCertificatesCallback& callback, | |
402 scoped_ptr<net::CertificateList> matches, | |
403 const std::string& error_message) { | |
404 if (permission_check_enabled_) | |
405 matches->clear(); | |
406 | |
407 // TODO(pneubeck): Remove all certs that the extension doesn't have access to. | |
408 callback.Run(matches.Pass(), error_message); | |
409 } | |
410 | 753 |
411 void PlatformKeysService::GotPlatformKeysOfExtension( | 754 void PlatformKeysService::GotPlatformKeysOfExtension( |
412 const std::string& extension_id, | 755 const std::string& extension_id, |
413 const GetPlatformKeysCallback& callback, | 756 const GetPlatformKeysCallback& callback, |
414 scoped_ptr<base::Value> value) { | 757 scoped_ptr<base::Value> value) { |
415 if (!value) | 758 scoped_ptr<KeyEntries> key_entries(new KeyEntries); |
416 value.reset(new base::ListValue); | 759 if (value) |
| 760 key_entries = KeyEntriesFromState(*value); |
417 | 761 |
418 base::ListValue* keys = NULL; | 762 callback.Run(key_entries.Pass()); |
419 if (!value->GetAsList(&keys)) { | |
420 LOG(ERROR) << "Found a value of wrong type."; | |
421 | |
422 keys = new base::ListValue; | |
423 value.reset(keys); | |
424 } | |
425 | |
426 ignore_result(value.release()); | |
427 callback.Run(make_scoped_ptr(keys)); | |
428 } | 763 } |
429 | 764 |
430 } // namespace chromeos | 765 } // namespace chromeos |
OLD | NEW |