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
;
20 struct PlatformKeysService::KeyEntry
{
21 // The base64-encoded DER of a X.509 Subject Public Key Info.
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
34 // This permission is granted until revoked by the user or the policy.
35 bool sign_unlimited
= false;
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
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
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:
54 // 'signOnce': bool, // if not present, defaults to false
55 // 'signUnlimited': bool // if not present, defaults to false
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
) {
76 LOG(ERROR
) << "Found invalid NULL entry in PlatformKeys state store.";
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
,
89 dict_entry
->GetBooleanWithoutPathExpansion(kStateStoreSignOnce
,
90 &new_entry
.sign_once
);
91 dict_entry
->GetBooleanWithoutPathExpansion(kStateStoreSignUnlimited
,
92 &new_entry
.sign_unlimited
);
94 LOG(ERROR
) << "Found invalid entry of type " << entry
->GetType()
95 << " in PlatformKeys state store.";
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
)
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
,
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
)
143 class PlatformKeysService::Task
{
147 virtual void Start() = 0;
148 virtual bool IsDone() = 0;
151 DISALLOW_ASSIGN(Task
);
154 class PlatformKeysService::PermissionUpdateTask
: public Task
{
158 WRITE_UPDATE_AND_CALLBACK
,
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
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
),
179 weak_factory_(this) {}
181 ~PermissionUpdateTask() override
{}
183 void Start() override
{
184 CHECK(next_step_
== Step::READ_PLATFORM_KEYS
);
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_
; }
196 switch (next_step_
) {
197 case Step::READ_PLATFORM_KEYS
:
198 next_step_
= Step::WRITE_UPDATE_AND_CALLBACK
;
201 case Step::WRITE_UPDATE_AND_CALLBACK
:
202 next_step_
= Step::DONE
;
204 if (!callback_
.is_null()) {
205 // Make a local copy of the callback to run as it might be deleted
207 base::ResetAndReturn(&callback_
).Run(this);
208 // |this| might be invalid now.
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();
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
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
;
259 case SignPermission::UNLIMITED
:
260 permission_value
= &matching_entry
->sign_unlimited
;
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
{
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
),
309 public_key_(public_key
),
310 sign_direct_pkcs_padded_(sign_direct_pkcs_padded
),
311 hash_algorithm_(hash_algorithm
),
312 extension_id_(extension_id
),
315 weak_factory_(this) {}
316 ~SignTask() override
{}
318 void Start() override
{
319 CHECK(next_step_
== Step::UPDATE_PERMISSION
);
322 bool IsDone() override
{ return next_step_
== Step::DONE
; }
326 switch (next_step_
) {
327 case Step::UPDATE_PERMISSION
:
328 next_step_
= Step::SIGN_OR_ABORT
;
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
;
338 if (!callback_
.is_null()) {
339 callback_
.Run(std::string() /* no signature */,
340 kErrorKeyNotAllowedForSigning
);
347 service_
->TaskFinished(this);
348 // |this| might be invalid now.
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_
,
360 base::Bind(&SignTask::DidUpdatePermission
, weak_factory_
.GetWeakPtr()),
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_|.
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_
);
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
);
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
{
416 FILTER_BY_PERMISSIONS
,
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
,
428 const std::string
& extension_id
,
429 const SelectCertificatesCallback
& callback
,
430 content::WebContents
* web_contents
,
431 PlatformKeysService
* service
)
433 interactive_(interactive
),
434 extension_id_(extension_id
),
436 web_contents_(web_contents
),
438 weak_factory_(this) {}
439 ~SelectTask() override
{}
441 void Start() override
{
442 CHECK(next_step_
== Step::GET_MATCHING_CERTS
);
445 bool IsDone() override
{ return next_step_
== Step::DONE
; }
449 switch (next_step_
) {
450 case Step::GET_MATCHING_CERTS
:
452 next_step_
= Step::SELECT_CERTS
;
453 else // Skip SelectCerts and UpdatePermission if not interactive.
454 next_step_
= Step::READ_PLATFORM_KEYS
;
457 case Step::SELECT_CERTS
:
458 next_step_
= Step::UPDATE_PERMISSION
;
461 case Step::UPDATE_PERMISSION
:
462 next_step_
= Step::READ_PLATFORM_KEYS
;
465 case Step::READ_PLATFORM_KEYS
:
466 next_step_
= Step::FILTER_BY_PERMISSIONS
;
469 case Step::FILTER_BY_PERMISSIONS
:
470 next_step_
= Step::DONE
;
471 FilterSelectionByPermission();
474 service_
->TaskFinished(this);
475 // |this| might be invalid now.
480 // Retrieves all certificates matching |request_|. Will call back to
481 // |GotMatchingCerts()|.
482 void GetMatchingCerts() {
483 platform_keys::subtle::SelectClientCertificates(
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
);
501 matches_
.swap(*matches
);
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()|.
510 if (matches_
.empty()) {
511 // Don't show a select dialog if no certificate is matching.
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
523 void GotSelection(const scoped_refptr
<net::X509Certificate
>& selected_cert
) {
524 selected_cert_
= selected_cert
;
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() {
533 if (!selected_cert_
) {
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)),
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(
554 base::Bind(&SelectTask::GotPlatformKeys
, weak_factory_
.GetWeakPtr()));
557 void GotPlatformKeys(scoped_ptr
<KeyEntries
> platform_keys
) {
558 platform_keys_
= platform_keys
.Pass();
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
);
569 selection
->push_back(selected_cert_
);
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
)
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 */);
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) {
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)),
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
),
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
,
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())
711 // Now either the queue is empty or the next task is not finished yet and it
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
);
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
),
750 void PlatformKeysService::RegisteredGeneratedKey(
751 const GenerateKeyCallback
& callback
,
752 const std::string
& public_key_spki_der
,
754 callback
.Run(public_key_spki_der
, std::string() /* no error */);
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
);
765 key_entries
= KeyEntriesFromState(*value
);
767 callback
.Run(key_entries
.Pass());
770 } // namespace chromeos