Check USB device path access when prompting users to select a device.
[chromium-blink-merge.git] / chrome / browser / chromeos / platform_keys / platform_keys_service.cc
blobd4c38a66f3bdbe549cac32bb84082b2ed1fc8208
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/platform_keys/platform_keys_service.h"
7 #include "base/base64.h"
8 #include "base/callback.h"
9 #include "base/callback_helpers.h"
10 #include "base/values.h"
11 #include "chrome/browser/chromeos/platform_keys/platform_keys.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "extensions/browser/state_store.h"
14 #include "net/cert/x509_certificate.h"
16 using content::BrowserThread;
18 namespace chromeos {
20 struct PlatformKeysService::KeyEntry {
21 // The base64-encoded DER of a X.509 Subject Public Key Info.
22 std::string spki_b64;
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;
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;
38 namespace {
40 const char kErrorKeyNotAllowedForSigning[] =
41 "This key is not allowed for signing. Either it was used for signing "
42 "before or it was not correctly generated.";
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.
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 // }
58 // Do not change this constant as clients will lose their existing state.
59 const char kStateStorePlatformKeys[] = "PlatformKeys";
60 const char kStateStoreSPKI[] = "SPKI";
61 const char kStateStoreSignOnce[] = "signOnce";
62 const char kStateStoreSignUnlimited[] = "signUnlimited";
64 scoped_ptr<PlatformKeysService::KeyEntries> KeyEntriesFromState(
65 const base::Value& state) {
66 scoped_ptr<PlatformKeysService::KeyEntries> new_entries(
67 new PlatformKeysService::KeyEntries);
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();
74 for (const base::Value* entry : *entries) {
75 if (!entry) {
76 LOG(ERROR) << "Found invalid NULL entry in PlatformKeys state store.";
77 continue;
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;
98 new_entries->push_back(new_entry);
100 return new_entries.Pass();
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;
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);
118 if (entry.sign_unlimited) {
119 new_entry->SetBooleanWithoutPathExpansion(kStateStoreSignUnlimited,
120 entry.sign_unlimited);
122 new_state->Append(new_entry.release());
124 return new_state.Pass();
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;
138 return nullptr;
141 } // namespace
143 class PlatformKeysService::Task {
144 public:
145 Task() {}
146 virtual ~Task() {}
147 virtual void Start() = 0;
148 virtual bool IsDone() = 0;
150 private:
151 DISALLOW_ASSIGN(Task);
154 class PlatformKeysService::PermissionUpdateTask : public Task {
155 public:
156 enum class Step {
157 READ_PLATFORM_KEYS,
158 WRITE_UPDATE_AND_CALLBACK,
159 DONE,
162 // Creates a task that reads the current permission for an extension to access
163 // a certain key. Afterwards it updates and persists the permission to the new
164 // value |new_permission_value|. |callback| will be run after the permission
165 // was persisted. The old permission values are then available through
166 // old_key_entry().
167 PermissionUpdateTask(const SignPermission permission,
168 const bool new_permission_value,
169 const std::string& public_key_spki_der,
170 const std::string& extension_id,
171 base::Callback<void(Task*)> callback,
172 PlatformKeysService* service)
173 : permission_(permission),
174 new_permission_value_(new_permission_value),
175 public_key_spki_der_(public_key_spki_der),
176 extension_id_(extension_id),
177 callback_(callback),
178 service_(service),
179 weak_factory_(this) {}
181 ~PermissionUpdateTask() override {}
183 void Start() override {
184 CHECK(next_step_ == Step::READ_PLATFORM_KEYS);
185 DoStep();
188 bool IsDone() override { return next_step_ == Step::DONE; }
190 // The old key entry with the old permissions before setting |permission| to
191 // the new value |new_permission_value|.
192 const KeyEntry& old_key_entry() { return old_key_entry_; }
194 private:
195 void DoStep() {
196 switch (next_step_) {
197 case Step::READ_PLATFORM_KEYS:
198 next_step_ = Step::WRITE_UPDATE_AND_CALLBACK;
199 ReadPlatformKeys();
200 return;
201 case Step::WRITE_UPDATE_AND_CALLBACK:
202 next_step_ = Step::DONE;
203 WriteUpdate();
204 if (!callback_.is_null()) {
205 // Make a local copy of the callback to run as it might be deleted
206 // during the Run().
207 base::ResetAndReturn(&callback_).Run(this);
208 // |this| might be invalid now.
210 return;
211 case Step::DONE:
212 NOTREACHED();
213 return;
217 // Reads the PlatformKeys value from the extension's state store and calls
218 // back to GotPlatformKeys().
219 void ReadPlatformKeys() {
220 service_->GetPlatformKeysOfExtension(
221 extension_id_, base::Bind(&PermissionUpdateTask::GotPlatformKeys,
222 weak_factory_.GetWeakPtr()));
225 void GotPlatformKeys(scoped_ptr<KeyEntries> platform_keys) {
226 platform_keys_ = platform_keys.Pass();
227 DoStep();
230 // Persists the existing KeyEntry in |old_key_entry_|, updates the entry with
231 // the new permission and persists it to the extension's state store if it was
232 // changed.
233 void WriteUpdate() {
234 DCHECK(platform_keys_);
236 std::string public_key_spki_der_b64;
237 base::Base64Encode(public_key_spki_der_, &public_key_spki_der_b64);
239 KeyEntry* matching_entry =
240 GetMatchingEntry(public_key_spki_der_b64, platform_keys_.get());
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.";
252 old_key_entry_ = *matching_entry;
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;
264 if (*permission_value != new_permission_value_) {
265 *permission_value = new_permission_value_;
266 service_->SetPlatformKeysOfExtension(extension_id_, *platform_keys_);
270 Step next_step_ = Step::READ_PLATFORM_KEYS;
271 KeyEntry old_key_entry_;
273 const SignPermission permission_;
274 const bool new_permission_value_;
275 const std::string public_key_spki_der_;
276 const std::string extension_id_;
277 scoped_ptr<KeyEntries> platform_keys_;
278 base::Callback<void(Task*)> callback_;
279 PlatformKeysService* const service_;
280 base::WeakPtrFactory<PermissionUpdateTask> weak_factory_;
282 DISALLOW_COPY_AND_ASSIGN(PermissionUpdateTask);
285 class PlatformKeysService::SignTask : public Task {
286 public:
287 enum class Step {
288 UPDATE_PERMISSION,
289 SIGN_OR_ABORT,
290 DONE,
293 // This Task will check the permissions of the extension with |extension_id|
294 // for the key identified by |public_key_spki_der|, then updates the
295 // permission to prevent any future signing operation of that extension using
296 // that same key. If the permission check was positive, it will actually sign
297 // |data| with the key and pass the signature to |callback|.
298 // If an error occurs, an error message is passed to |callback| instead.
299 SignTask(const std::string& token_id,
300 const std::string& data,
301 const std::string& public_key,
302 bool sign_direct_pkcs_padded,
303 platform_keys::HashAlgorithm hash_algorithm,
304 const std::string& extension_id,
305 const SignCallback& callback,
306 PlatformKeysService* service)
307 : token_id_(token_id),
308 data_(data),
309 public_key_(public_key),
310 sign_direct_pkcs_padded_(sign_direct_pkcs_padded),
311 hash_algorithm_(hash_algorithm),
312 extension_id_(extension_id),
313 callback_(callback),
314 service_(service),
315 weak_factory_(this) {}
316 ~SignTask() override {}
318 void Start() override {
319 CHECK(next_step_ == Step::UPDATE_PERMISSION);
320 DoStep();
322 bool IsDone() override { return next_step_ == Step::DONE; }
324 private:
325 void DoStep() {
326 switch (next_step_) {
327 case Step::UPDATE_PERMISSION:
328 next_step_ = Step::SIGN_OR_ABORT;
329 UpdatePermission();
330 return;
331 case Step::SIGN_OR_ABORT: {
332 next_step_ = Step::DONE;
333 bool sign_granted = permission_update_->old_key_entry().sign_once ||
334 permission_update_->old_key_entry().sign_unlimited;
335 if (sign_granted) {
336 Sign();
337 } else {
338 if (!callback_.is_null()) {
339 callback_.Run(std::string() /* no signature */,
340 kErrorKeyNotAllowedForSigning);
342 DoStep();
344 return;
346 case Step::DONE:
347 service_->TaskFinished(this);
348 // |this| might be invalid now.
349 return;
353 // Reads the current permission of the extension with |extension_id_| for key
354 // |params_->public_key| and updates the permission to disable further
355 // signing operations with that key.
356 void UpdatePermission() {
357 permission_update_.reset(new PermissionUpdateTask(
358 SignPermission::ONCE, false /* new permission value */, public_key_,
359 extension_id_,
360 base::Bind(&SignTask::DidUpdatePermission, weak_factory_.GetWeakPtr()),
361 service_));
362 permission_update_->Start();
365 void DidUpdatePermission(Task* /* task */) { DoStep(); }
367 // Starts the actual signing operation and afterwards passes the signature (or
368 // error) to |callback_|.
369 void Sign() {
370 if (sign_direct_pkcs_padded_) {
371 platform_keys::subtle::SignRSAPKCS1Raw(
372 token_id_, data_, public_key_,
373 base::Bind(&SignTask::DidSign, weak_factory_.GetWeakPtr()),
374 service_->browser_context_);
375 } else {
376 platform_keys::subtle::SignRSAPKCS1Digest(
377 token_id_, data_, public_key_, hash_algorithm_,
378 base::Bind(&SignTask::DidSign, weak_factory_.GetWeakPtr()),
379 service_->browser_context_);
383 void DidSign(const std::string& signature, const std::string& error_message) {
384 callback_.Run(signature, error_message);
385 DoStep();
388 Step next_step_ = Step::UPDATE_PERMISSION;
389 scoped_ptr<KeyEntries> platform_keys_;
390 scoped_ptr<PermissionUpdateTask> permission_update_;
392 const std::string token_id_;
393 const std::string data_;
394 const std::string public_key_;
396 // If true, |data_| will not be hashed before signing. Only PKCS#1 v1.5
397 // padding will be applied before signing.
398 // If false, |hash_algorithm_| is set to a value != NONE.
399 const bool sign_direct_pkcs_padded_;
400 const platform_keys::HashAlgorithm hash_algorithm_;
401 const std::string extension_id_;
402 const SignCallback callback_;
403 PlatformKeysService* const service_;
404 base::WeakPtrFactory<SignTask> weak_factory_;
406 DISALLOW_COPY_AND_ASSIGN(SignTask);
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,
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 content::WebContents* web_contents,
431 PlatformKeysService* service)
432 : request_(request),
433 interactive_(interactive),
434 extension_id_(extension_id),
435 callback_(callback),
436 web_contents_(web_contents),
437 service_(service),
438 weak_factory_(this) {}
439 ~SelectTask() override {}
441 void Start() override {
442 CHECK(next_step_ == Step::GET_MATCHING_CERTS);
443 DoStep();
445 bool IsDone() override { return next_step_ == Step::DONE; }
447 private:
448 void DoStep() {
449 switch (next_step_) {
450 case Step::GET_MATCHING_CERTS:
451 if (interactive_)
452 next_step_ = Step::SELECT_CERTS;
453 else // Skip SelectCerts and UpdatePermission if not interactive.
454 next_step_ = Step::READ_PLATFORM_KEYS;
455 GetMatchingCerts();
456 return;
457 case Step::SELECT_CERTS:
458 next_step_ = Step::UPDATE_PERMISSION;
459 SelectCerts();
460 return;
461 case Step::UPDATE_PERMISSION:
462 next_step_ = Step::READ_PLATFORM_KEYS;
463 UpdatePermission();
464 return;
465 case Step::READ_PLATFORM_KEYS:
466 next_step_ = Step::FILTER_BY_PERMISSIONS;
467 ReadPlatformKeys();
468 return;
469 case Step::FILTER_BY_PERMISSIONS:
470 next_step_ = Step::DONE;
471 FilterSelectionByPermission();
472 return;
473 case Step::DONE:
474 service_->TaskFinished(this);
475 // |this| might be invalid now.
476 return;
480 // Retrieves all certificates matching |request_|. Will call back to
481 // |GotMatchingCerts()|.
482 void GetMatchingCerts() {
483 platform_keys::subtle::SelectClientCertificates(
484 request_,
485 base::Bind(&SelectTask::GotMatchingCerts, weak_factory_.GetWeakPtr()),
486 service_->browser_context_);
489 // If the certificate request could be processed successfully, |matches| will
490 // contain the list of matching certificates (maybe empty) and |error_message|
491 // will be empty. If an error occurred, |matches| will be null and
492 // |error_message| contain an error message.
493 void GotMatchingCerts(scoped_ptr<net::CertificateList> matches,
494 const std::string& error_message) {
495 if (!error_message.empty()) {
496 next_step_ = Step::DONE;
497 callback_.Run(nullptr /* no certificates */, error_message);
498 DoStep();
499 return;
501 matches_.swap(*matches);
502 DoStep();
505 // Calls |service_->select_delegate_->Select()| to select a cert from
506 // |matches_|, which will be stored in |selected_cert_|.
507 // Will call back to |GotSelection()|.
508 void SelectCerts() {
509 CHECK(interactive_);
510 if (matches_.empty()) {
511 // Don't show a select dialog if no certificate is matching.
512 DoStep();
513 return;
515 service_->select_delegate_->Select(
516 extension_id_, matches_,
517 base::Bind(&SelectTask::GotSelection, base::Unretained(this)),
518 web_contents_, service_->browser_context_);
521 // Will be called by |SelectCerts()| with the selected cert or null if no cert
522 // was selected.
523 void GotSelection(const scoped_refptr<net::X509Certificate>& selected_cert) {
524 selected_cert_ = selected_cert;
525 DoStep();
528 // Updates the extension's state store about unlimited sign permission for the
529 // selected cert. Does nothing if no cert was selected.
530 // Will call back to |DidUpdatePermission()|.
531 void UpdatePermission() {
532 CHECK(interactive_);
533 if (!selected_cert_) {
534 DoStep();
535 return;
537 const std::string public_key_spki_der(
538 platform_keys::GetSubjectPublicKeyInfo(selected_cert_));
539 permission_update_.reset(new PermissionUpdateTask(
540 SignPermission::UNLIMITED, true /* new permission value */,
541 public_key_spki_der, extension_id_,
542 base::Bind(&SelectTask::DidUpdatePermission, base::Unretained(this)),
543 service_));
544 permission_update_->Start();
547 void DidUpdatePermission(Task* /* task */) { DoStep(); }
549 // Reads the PlatformKeys value from the extension's state store and calls
550 // back to GotPlatformKeys().
551 void ReadPlatformKeys() {
552 service_->GetPlatformKeysOfExtension(
553 extension_id_,
554 base::Bind(&SelectTask::GotPlatformKeys, weak_factory_.GetWeakPtr()));
557 void GotPlatformKeys(scoped_ptr<KeyEntries> platform_keys) {
558 platform_keys_ = platform_keys.Pass();
559 DoStep();
562 // Filters from all matches (if not interactive) or from the selection (if
563 // interactive), the certificates that the extension has unlimited sign
564 // permission for. Passes the filtered certs to |callback_|.
565 void FilterSelectionByPermission() {
566 scoped_ptr<net::CertificateList> selection(new net::CertificateList);
567 if (interactive_) {
568 if (selected_cert_)
569 selection->push_back(selected_cert_);
570 } else {
571 selection->assign(matches_.begin(), matches_.end());
574 scoped_ptr<net::CertificateList> filtered_certs(new net::CertificateList);
575 for (scoped_refptr<net::X509Certificate> selected_cert : *selection) {
576 const std::string public_key_spki_der(
577 platform_keys::GetSubjectPublicKeyInfo(selected_cert));
578 std::string public_key_spki_der_b64;
579 base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64);
581 KeyEntry* matching_entry =
582 GetMatchingEntry(public_key_spki_der_b64, platform_keys_.get());
583 if (!matching_entry || !matching_entry->sign_unlimited)
584 continue;
586 filtered_certs->push_back(selected_cert);
588 // Note: In the interactive case this should have filtered exactly the
589 // one selected cert. Checking the permissions again is not striclty
590 // necessary but this ensures that the permissions were updated correctly.
591 CHECK(!selected_cert_ || (filtered_certs->size() == 1 &&
592 filtered_certs->front() == selected_cert_));
593 callback_.Run(filtered_certs.Pass(), std::string() /* no error */);
594 DoStep();
597 Step next_step_ = Step::GET_MATCHING_CERTS;
598 scoped_ptr<KeyEntries> platform_keys_;
599 scoped_ptr<PermissionUpdateTask> permission_update_;
601 net::CertificateList matches_;
602 scoped_refptr<net::X509Certificate> selected_cert_;
603 platform_keys::ClientCertificateRequest request_;
604 const bool interactive_;
605 const std::string extension_id_;
606 const SelectCertificatesCallback callback_;
607 content::WebContents* const web_contents_;
608 PlatformKeysService* const service_;
609 base::WeakPtrFactory<SelectTask> weak_factory_;
611 DISALLOW_COPY_AND_ASSIGN(SelectTask);
614 PlatformKeysService::SelectDelegate::SelectDelegate() {
617 PlatformKeysService::SelectDelegate::~SelectDelegate() {
620 PlatformKeysService::PlatformKeysService(
621 content::BrowserContext* browser_context,
622 extensions::StateStore* state_store)
623 : browser_context_(browser_context),
624 state_store_(state_store),
625 weak_factory_(this) {
626 DCHECK(state_store);
629 PlatformKeysService::~PlatformKeysService() {
632 void PlatformKeysService::SetSelectDelegate(
633 scoped_ptr<SelectDelegate> delegate) {
634 select_delegate_ = delegate.Pass();
637 void PlatformKeysService::GrantUnlimitedSignPermission(
638 const std::string& extension_id,
639 scoped_refptr<net::X509Certificate> cert) {
640 const std::string public_key_spki_der(
641 platform_keys::GetSubjectPublicKeyInfo(cert));
643 StartOrQueueTask(make_scoped_ptr(new PermissionUpdateTask(
644 SignPermission::UNLIMITED, true /* new permission value */,
645 public_key_spki_der, extension_id,
646 base::Bind(&PlatformKeysService::TaskFinished, base::Unretained(this)),
647 this)));
650 void PlatformKeysService::GenerateRSAKey(const std::string& token_id,
651 unsigned int modulus_length,
652 const std::string& extension_id,
653 const GenerateKeyCallback& callback) {
654 DCHECK_CURRENTLY_ON(BrowserThread::UI);
656 platform_keys::subtle::GenerateRSAKey(
657 token_id, modulus_length,
658 base::Bind(&PlatformKeysService::GeneratedKey, weak_factory_.GetWeakPtr(),
659 extension_id, callback),
660 browser_context_);
663 void PlatformKeysService::SignRSAPKCS1Digest(
664 const std::string& token_id,
665 const std::string& data,
666 const std::string& public_key,
667 platform_keys::HashAlgorithm hash_algorithm,
668 const std::string& extension_id,
669 const SignCallback& callback) {
670 DCHECK_CURRENTLY_ON(BrowserThread::UI);
671 StartOrQueueTask(make_scoped_ptr(new SignTask(
672 token_id, data, public_key, false /* digest before signing */,
673 hash_algorithm, extension_id, callback, this)));
676 void PlatformKeysService::SignRSAPKCS1Raw(const std::string& token_id,
677 const std::string& data,
678 const std::string& public_key,
679 const std::string& extension_id,
680 const SignCallback& callback) {
681 DCHECK_CURRENTLY_ON(BrowserThread::UI);
682 StartOrQueueTask(make_scoped_ptr(new SignTask(
683 token_id, data, public_key, true /* sign directly without hashing */,
684 platform_keys::HASH_ALGORITHM_NONE, extension_id, callback, this)));
687 void PlatformKeysService::SelectClientCertificates(
688 const platform_keys::ClientCertificateRequest& request,
689 bool interactive,
690 const std::string& extension_id,
691 const SelectCertificatesCallback& callback,
692 content::WebContents* web_contents) {
693 DCHECK_CURRENTLY_ON(BrowserThread::UI);
694 StartOrQueueTask(make_scoped_ptr(new SelectTask(
695 request, interactive, extension_id, callback, web_contents, this)));
698 void PlatformKeysService::StartOrQueueTask(scoped_ptr<Task> task) {
699 tasks_.push(make_linked_ptr(task.release()));
700 if (tasks_.size() == 1)
701 tasks_.front()->Start();
704 void PlatformKeysService::TaskFinished(Task* task) {
705 DCHECK(!tasks_.empty());
706 DCHECK(task == tasks_.front().get());
707 // Remove all finished tasks from the queue (should be at most one).
708 while (!tasks_.empty() && tasks_.front()->IsDone())
709 tasks_.pop();
711 // Now either the queue is empty or the next task is not finished yet and it
712 // can be started.
713 if (!tasks_.empty())
714 tasks_.front()->Start();
717 void PlatformKeysService::GetPlatformKeysOfExtension(
718 const std::string& extension_id,
719 const GetPlatformKeysCallback& callback) {
720 state_store_->GetExtensionValue(
721 extension_id, kStateStorePlatformKeys,
722 base::Bind(&PlatformKeysService::GotPlatformKeysOfExtension,
723 weak_factory_.GetWeakPtr(), extension_id, callback));
726 void PlatformKeysService::SetPlatformKeysOfExtension(
727 const std::string& extension_id,
728 const KeyEntries& platform_keys) {
729 state_store_->SetExtensionValue(extension_id, kStateStorePlatformKeys,
730 KeyEntriesToState(platform_keys));
733 void PlatformKeysService::GeneratedKey(const std::string& extension_id,
734 const GenerateKeyCallback& callback,
735 const std::string& public_key_spki_der,
736 const std::string& error_message) {
737 if (!error_message.empty()) {
738 callback.Run(std::string() /* no public key */, error_message);
739 return;
742 StartOrQueueTask(make_scoped_ptr(new PermissionUpdateTask(
743 SignPermission::ONCE, true /* new permission value */,
744 public_key_spki_der, extension_id,
745 base::Bind(&PlatformKeysService::RegisteredGeneratedKey,
746 base::Unretained(this), callback, public_key_spki_der),
747 this)));
750 void PlatformKeysService::RegisteredGeneratedKey(
751 const GenerateKeyCallback& callback,
752 const std::string& public_key_spki_der,
753 Task* task) {
754 callback.Run(public_key_spki_der, std::string() /* no error */);
755 TaskFinished(task);
759 void PlatformKeysService::GotPlatformKeysOfExtension(
760 const std::string& extension_id,
761 const GetPlatformKeysCallback& callback,
762 scoped_ptr<base::Value> value) {
763 scoped_ptr<KeyEntries> key_entries(new KeyEntries);
764 if (value)
765 key_entries = KeyEntriesFromState(*value);
767 callback.Run(key_entries.Pass());
770 } // namespace chromeos