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"
8 #include "base/bind_helpers.h"
9 #include "base/callback.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
;
22 const char kErrorKeyNotAllowedForSigning
[] =
23 "This key is not allowed for signing. Either it was used for signing "
24 "before or it was not correctly generated.";
28 class PlatformKeysService::Task
{
32 virtual void Start() = 0;
33 virtual bool IsDone() = 0;
36 DISALLOW_ASSIGN(Task
);
39 class PlatformKeysService::GenerateRSAKeyTask
: public Task
{
43 GET_EXTENSION_PERMISSIONS
,
44 UPDATE_PERMISSIONS_AND_CALLBACK
,
48 // This Task generates an RSA key with the parameters |token_id| and
49 // |modulus_length| and registers it for the extension with id |extension_id|.
50 // The generated key will be passed to |callback|.
51 GenerateRSAKeyTask(const std::string
& token_id
,
52 unsigned int modulus_length
,
53 const std::string
& extension_id
,
54 const GenerateKeyCallback
& callback
,
55 KeyPermissions
* key_permissions
,
56 PlatformKeysService
* service
,
57 content::BrowserContext
* browser_context
)
58 : token_id_(token_id
),
59 modulus_length_(modulus_length
),
60 extension_id_(extension_id
),
62 key_permissions_(key_permissions
),
64 browser_context_(browser_context
),
65 weak_factory_(this) {}
67 ~GenerateRSAKeyTask() override
{}
69 void Start() override
{
70 CHECK(next_step_
== Step::GENERATE_KEY
);
74 bool IsDone() override
{ return next_step_
== Step::DONE
; }
79 case Step::GENERATE_KEY
:
80 next_step_
= Step::GET_EXTENSION_PERMISSIONS
;
83 case Step::GET_EXTENSION_PERMISSIONS
:
84 next_step_
= Step::UPDATE_PERMISSIONS_AND_CALLBACK
;
85 GetExtensionPermissions();
87 case Step::UPDATE_PERMISSIONS_AND_CALLBACK
:
88 next_step_
= Step::DONE
;
89 extension_permissions_
->RegisterKeyForCorporateUsage(
90 public_key_spki_der_
);
91 callback_
.Run(public_key_spki_der_
, std::string() /* no error */);
95 service_
->TaskFinished(this);
96 // |this| might be invalid now.
101 // Generates the RSA key.
103 platform_keys::subtle::GenerateRSAKey(
104 token_id_
, modulus_length_
,
105 base::Bind(&GenerateRSAKeyTask::GeneratedKey
,
106 weak_factory_
.GetWeakPtr()),
110 // Stores the generated key or in case of an error calls |callback_| with the
112 void GeneratedKey(const std::string
& public_key_spki_der
,
113 const std::string
& error_message
) {
114 if (!error_message
.empty()) {
115 next_step_
= Step::DONE
;
116 callback_
.Run(std::string() /* no public key */, error_message
);
120 public_key_spki_der_
= public_key_spki_der
;
124 // Gets the permissions for the extension with id |extension_id|.
125 void GetExtensionPermissions() {
126 key_permissions_
->GetPermissionsForExtension(
127 extension_id_
, base::Bind(&GenerateRSAKeyTask::GotPermissions
,
128 base::Unretained(this)));
131 void GotPermissions(scoped_ptr
<KeyPermissions::PermissionsForExtension
>
132 extension_permissions
) {
133 extension_permissions_
= extension_permissions
.Pass();
137 Step next_step_
= Step::GENERATE_KEY
;
139 const std::string token_id_
;
140 const unsigned int modulus_length_
;
141 std::string public_key_spki_der_
;
142 const std::string extension_id_
;
143 GenerateKeyCallback callback_
;
144 scoped_ptr
<KeyPermissions::PermissionsForExtension
> extension_permissions_
;
145 KeyPermissions
* const key_permissions_
;
146 PlatformKeysService
* const service_
;
147 content::BrowserContext
* const browser_context_
;
148 base::WeakPtrFactory
<GenerateRSAKeyTask
> weak_factory_
;
150 DISALLOW_COPY_AND_ASSIGN(GenerateRSAKeyTask
);
153 class PlatformKeysService::SignTask
: public Task
{
156 GET_EXTENSION_PERMISSIONS
,
161 // This Task will check the permissions of the extension with |extension_id|
162 // for the key identified by |public_key_spki_der|. If the permission check
163 // was positive, signs |data| with the key and passes the signature to
164 // |callback|. If the extension is not allowed to use the key multiple times,
165 // also updates the permission to prevent any future signing operation of that
166 // extension using that same key.
167 // If an error occurs, an error message is passed to |callback| instead.
168 SignTask(const std::string
& token_id
,
169 const std::string
& data
,
170 const std::string
& public_key
,
171 bool sign_direct_pkcs_padded
,
172 platform_keys::HashAlgorithm hash_algorithm
,
173 const std::string
& extension_id
,
174 const SignCallback
& callback
,
175 KeyPermissions
* key_permissions
,
176 PlatformKeysService
* service
)
177 : token_id_(token_id
),
179 public_key_(public_key
),
180 sign_direct_pkcs_padded_(sign_direct_pkcs_padded
),
181 hash_algorithm_(hash_algorithm
),
182 extension_id_(extension_id
),
184 key_permissions_(key_permissions
),
186 weak_factory_(this) {}
188 ~SignTask() override
{}
190 void Start() override
{
191 CHECK(next_step_
== Step::GET_EXTENSION_PERMISSIONS
);
195 bool IsDone() override
{ return next_step_
== Step::DONE
; }
199 switch (next_step_
) {
200 case Step::GET_EXTENSION_PERMISSIONS
:
201 next_step_
= Step::SIGN_OR_ABORT
;
202 GetExtensionPermissions();
204 case Step::SIGN_OR_ABORT
: {
205 next_step_
= Step::DONE
;
207 extension_permissions_
->CanUseKeyForSigning(public_key_
);
211 callback_
.Run(std::string() /* no signature */,
212 kErrorKeyNotAllowedForSigning
);
218 service_
->TaskFinished(this);
219 // |this| might be invalid now.
224 void GetExtensionPermissions() {
225 key_permissions_
->GetPermissionsForExtension(
227 base::Bind(&SignTask::GotPermissions
, base::Unretained(this)));
230 void GotPermissions(scoped_ptr
<KeyPermissions::PermissionsForExtension
>
231 extension_permissions
) {
232 extension_permissions_
= extension_permissions
.Pass();
236 // Updates the permissions for |public_key_|, starts the actual signing
237 // operation and afterwards passes the signature (or error) to |callback_|.
239 extension_permissions_
->SetKeyUsedForSigning(public_key_
);
241 if (sign_direct_pkcs_padded_
) {
242 platform_keys::subtle::SignRSAPKCS1Raw(
243 token_id_
, data_
, public_key_
,
244 base::Bind(&SignTask::DidSign
, weak_factory_
.GetWeakPtr()),
245 service_
->browser_context_
);
247 platform_keys::subtle::SignRSAPKCS1Digest(
248 token_id_
, data_
, public_key_
, hash_algorithm_
,
249 base::Bind(&SignTask::DidSign
, weak_factory_
.GetWeakPtr()),
250 service_
->browser_context_
);
254 void DidSign(const std::string
& signature
, const std::string
& error_message
) {
255 callback_
.Run(signature
, error_message
);
259 Step next_step_
= Step::GET_EXTENSION_PERMISSIONS
;
261 const std::string token_id_
;
262 const std::string data_
;
263 const std::string public_key_
;
265 // If true, |data_| will not be hashed before signing. Only PKCS#1 v1.5
266 // padding will be applied before signing.
267 // If false, |hash_algorithm_| is set to a value != NONE.
268 const bool sign_direct_pkcs_padded_
;
269 const platform_keys::HashAlgorithm hash_algorithm_
;
270 const std::string extension_id_
;
271 const SignCallback callback_
;
272 scoped_ptr
<KeyPermissions::PermissionsForExtension
> extension_permissions_
;
273 KeyPermissions
* const key_permissions_
;
274 PlatformKeysService
* const service_
;
275 base::WeakPtrFactory
<SignTask
> weak_factory_
;
277 DISALLOW_COPY_AND_ASSIGN(SignTask
);
280 class PlatformKeysService::SelectTask
: public Task
{
283 GET_EXTENSION_PERMISSIONS
,
285 INTERSECT_WITH_INPUT_CERTS
,
288 FILTER_BY_PERMISSIONS
,
292 // This task determines all known client certs matching |request| and that are
293 // elements of |input_client_certificates|, if given. If |interactive| is
294 // true, calls |service->select_delegate_->Select()| to select a cert from all
295 // matches. The extension with |extension_id| will be granted unlimited sign
296 // permission for the selected cert. Finally, either the selection or, if
297 // |interactive| is false, matching certs that the extension has permission
298 // for are passed to |callback|.
299 SelectTask(const platform_keys::ClientCertificateRequest
& request
,
300 scoped_ptr
<net::CertificateList
> input_client_certificates
,
302 const std::string
& extension_id
,
303 const SelectCertificatesCallback
& callback
,
304 content::WebContents
* web_contents
,
305 KeyPermissions
* key_permissions
,
306 PlatformKeysService
* service
)
308 input_client_certificates_(input_client_certificates
.Pass()),
309 interactive_(interactive
),
310 extension_id_(extension_id
),
312 web_contents_(web_contents
),
313 key_permissions_(key_permissions
),
315 weak_factory_(this) {}
316 ~SelectTask() override
{}
318 void Start() override
{
319 CHECK(next_step_
== Step::GET_EXTENSION_PERMISSIONS
);
323 bool IsDone() override
{ return next_step_
== Step::DONE
; }
327 switch (next_step_
) {
328 case Step::GET_EXTENSION_PERMISSIONS
:
329 next_step_
= Step::GET_MATCHING_CERTS
;
330 GetExtensionPermissions();
332 case Step::GET_MATCHING_CERTS
:
333 next_step_
= Step::INTERSECT_WITH_INPUT_CERTS
;
336 case Step::INTERSECT_WITH_INPUT_CERTS
:
338 next_step_
= Step::SELECT_CERTS
;
339 else // Skip SelectCerts and UpdatePermission if not interactive.
340 next_step_
= Step::FILTER_BY_PERMISSIONS
;
341 IntersectWithInputCerts();
343 case Step::SELECT_CERTS
:
344 next_step_
= Step::UPDATE_PERMISSION
;
347 case Step::UPDATE_PERMISSION
:
348 next_step_
= Step::FILTER_BY_PERMISSIONS
;
351 case Step::FILTER_BY_PERMISSIONS
:
352 next_step_
= Step::DONE
;
353 FilterSelectionByPermission();
356 service_
->TaskFinished(this);
357 // |this| might be invalid now.
362 void GetExtensionPermissions() {
363 key_permissions_
->GetPermissionsForExtension(
365 base::Bind(&SelectTask::GotPermissions
, base::Unretained(this)));
368 void GotPermissions(scoped_ptr
<KeyPermissions::PermissionsForExtension
>
369 extension_permissions
) {
370 extension_permissions_
= extension_permissions
.Pass();
374 // Retrieves all certificates matching |request_|. Will call back to
375 // |GotMatchingCerts()|.
376 void GetMatchingCerts() {
377 platform_keys::subtle::SelectClientCertificates(
378 request_
.certificate_authorities
,
379 base::Bind(&SelectTask::GotMatchingCerts
, weak_factory_
.GetWeakPtr()),
380 service_
->browser_context_
);
383 // If the certificate request could be processed successfully, |matches| will
384 // contain the list of matching certificates (maybe empty) and |error_message|
385 // will be empty. If an error occurred, |matches| will be null and
386 // |error_message| contain an error message.
387 // Note that the order of |matches|, based on the expiration/issuance date, is
388 // relevant and must be preserved in any processing of the list.
389 void GotMatchingCerts(scoped_ptr
<net::CertificateList
> matches
,
390 const std::string
& error_message
) {
391 if (!error_message
.empty()) {
392 next_step_
= Step::DONE
;
393 callback_
.Run(nullptr /* no certificates */, error_message
);
398 for (scoped_refptr
<net::X509Certificate
>& certificate
: *matches
) {
399 const std::string
public_key_spki_der(
400 platform_keys::GetSubjectPublicKeyInfo(certificate
));
401 // Skip this key if the user cannot grant any permission for it, except if
402 // this extension can already use it for signing.
403 if (!key_permissions_
->CanUserGrantPermissionFor(public_key_spki_der
) &&
404 !extension_permissions_
->CanUseKeyForSigning(public_key_spki_der
)) {
408 // Filter the retrieved certificates returning only those whose type is
409 // equal to one of the entries in the type field of the certificate
411 // If the type field does not contain any entries, certificates of all
412 // types shall be returned.
413 if (!request_
.certificate_key_types
.empty()) {
414 net::X509Certificate::PublicKeyType actual_key_type
=
415 net::X509Certificate::kPublicKeyTypeUnknown
;
416 size_t unused_key_size
= 0;
417 net::X509Certificate::GetPublicKeyInfo(
418 certificate
->os_cert_handle(), &unused_key_size
, &actual_key_type
);
419 const std::vector
<net::X509Certificate::PublicKeyType
>& accepted_types
=
420 request_
.certificate_key_types
;
421 if (std::find(accepted_types
.begin(), accepted_types
.end(),
422 actual_key_type
) == accepted_types
.end()) {
427 matches_
.push_back(certificate
.Pass());
432 // If |input_client_certificates_| is given, removes from |matches_| all
433 // certificates that are not elements of |input_client_certificates_|.
434 void IntersectWithInputCerts() {
435 if (!input_client_certificates_
) {
439 platform_keys::IntersectCertificates(
440 matches_
, *input_client_certificates_
,
441 base::Bind(&SelectTask::GotIntersection
, weak_factory_
.GetWeakPtr()));
444 void GotIntersection(scoped_ptr
<net::CertificateList
> intersection
) {
445 matches_
.swap(*intersection
);
449 // Calls |service_->select_delegate_->Select()| to select a cert from
450 // |matches_|, which will be stored in |selected_cert_|.
451 // Will call back to |GotSelection()|.
454 if (matches_
.empty()) {
455 // Don't show a select dialog if no certificate is matching.
459 service_
->select_delegate_
->Select(
460 extension_id_
, matches_
,
461 base::Bind(&SelectTask::GotSelection
, base::Unretained(this)),
462 web_contents_
, service_
->browser_context_
);
465 // Will be called by |SelectCerts()| with the selected cert or null if no cert
467 void GotSelection(const scoped_refptr
<net::X509Certificate
>& selected_cert
) {
468 selected_cert_
= selected_cert
;
472 // Updates the extension's state store about unlimited sign permission for the
473 // selected cert. Does nothing if no cert was selected.
474 void UpdatePermission() {
476 if (!selected_cert_
) {
480 const std::string
public_key_spki_der(
481 platform_keys::GetSubjectPublicKeyInfo(selected_cert_
));
482 extension_permissions_
->SetUserGrantedPermission(public_key_spki_der
);
486 // Filters from all matches (if not interactive) or from the selection (if
487 // interactive), the certificates that the extension has unlimited sign
488 // permission for. Passes the filtered certs to |callback_|.
489 void FilterSelectionByPermission() {
490 scoped_ptr
<net::CertificateList
> selection(new net::CertificateList
);
493 selection
->push_back(selected_cert_
);
495 selection
->assign(matches_
.begin(), matches_
.end());
498 scoped_ptr
<net::CertificateList
> filtered_certs(new net::CertificateList
);
499 for (scoped_refptr
<net::X509Certificate
> selected_cert
: *selection
) {
500 const std::string
public_key_spki_der(
501 platform_keys::GetSubjectPublicKeyInfo(selected_cert
));
503 if (!extension_permissions_
->CanUseKeyForSigning(public_key_spki_der
))
506 filtered_certs
->push_back(selected_cert
);
508 // Note: In the interactive case this should have filtered exactly the
509 // one selected cert. Checking the permissions again is not striclty
510 // necessary but this ensures that the permissions were updated correctly.
511 CHECK(!selected_cert_
|| (filtered_certs
->size() == 1 &&
512 filtered_certs
->front() == selected_cert_
));
513 callback_
.Run(filtered_certs
.Pass(), std::string() /* no error */);
517 Step next_step_
= Step::GET_EXTENSION_PERMISSIONS
;
519 net::CertificateList matches_
;
520 scoped_refptr
<net::X509Certificate
> selected_cert_
;
521 platform_keys::ClientCertificateRequest request_
;
522 scoped_ptr
<net::CertificateList
> input_client_certificates_
;
523 const bool interactive_
;
524 const std::string extension_id_
;
525 const SelectCertificatesCallback callback_
;
526 content::WebContents
* const web_contents_
;
527 scoped_ptr
<KeyPermissions::PermissionsForExtension
> extension_permissions_
;
528 KeyPermissions
* const key_permissions_
;
529 PlatformKeysService
* const service_
;
530 base::WeakPtrFactory
<SelectTask
> weak_factory_
;
532 DISALLOW_COPY_AND_ASSIGN(SelectTask
);
535 PlatformKeysService::SelectDelegate::SelectDelegate() {
538 PlatformKeysService::SelectDelegate::~SelectDelegate() {
541 PlatformKeysService::PlatformKeysService(
542 bool profile_is_managed
,
543 PrefService
* profile_prefs
,
544 policy::PolicyService
* profile_policies
,
545 content::BrowserContext
* browser_context
,
546 extensions::StateStore
* state_store
)
547 : browser_context_(browser_context
),
548 key_permissions_(profile_is_managed
,
552 weak_factory_(this) {
553 DCHECK(browser_context
);
557 PlatformKeysService::~PlatformKeysService() {
560 void PlatformKeysService::SetSelectDelegate(
561 scoped_ptr
<SelectDelegate
> delegate
) {
562 select_delegate_
= delegate
.Pass();
565 void PlatformKeysService::GenerateRSAKey(const std::string
& token_id
,
566 unsigned int modulus_length
,
567 const std::string
& extension_id
,
568 const GenerateKeyCallback
& callback
) {
569 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
570 StartOrQueueTask(make_scoped_ptr(
571 new GenerateRSAKeyTask(token_id
, modulus_length
, extension_id
, callback
,
572 &key_permissions_
, this, browser_context_
)));
575 void PlatformKeysService::SignRSAPKCS1Digest(
576 const std::string
& token_id
,
577 const std::string
& data
,
578 const std::string
& public_key
,
579 platform_keys::HashAlgorithm hash_algorithm
,
580 const std::string
& extension_id
,
581 const SignCallback
& callback
) {
582 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
583 StartOrQueueTask(make_scoped_ptr(new SignTask(
584 token_id
, data
, public_key
, false /* digest before signing */,
585 hash_algorithm
, extension_id
, callback
, &key_permissions_
, this)));
588 void PlatformKeysService::SignRSAPKCS1Raw(const std::string
& token_id
,
589 const std::string
& data
,
590 const std::string
& public_key
,
591 const std::string
& extension_id
,
592 const SignCallback
& callback
) {
593 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
594 StartOrQueueTask(make_scoped_ptr(new SignTask(
595 token_id
, data
, public_key
, true /* sign directly without hashing */,
596 platform_keys::HASH_ALGORITHM_NONE
, extension_id
, callback
,
597 &key_permissions_
, this)));
600 void PlatformKeysService::SelectClientCertificates(
601 const platform_keys::ClientCertificateRequest
& request
,
602 scoped_ptr
<net::CertificateList
> client_certificates
,
604 const std::string
& extension_id
,
605 const SelectCertificatesCallback
& callback
,
606 content::WebContents
* web_contents
) {
607 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
608 StartOrQueueTask(make_scoped_ptr(new SelectTask(
609 request
, client_certificates
.Pass(), interactive
, extension_id
, callback
,
610 web_contents
, &key_permissions_
, this)));
613 void PlatformKeysService::StartOrQueueTask(scoped_ptr
<Task
> task
) {
614 tasks_
.push(make_linked_ptr(task
.release()));
615 if (tasks_
.size() == 1)
616 tasks_
.front()->Start();
619 void PlatformKeysService::TaskFinished(Task
* task
) {
620 DCHECK(!tasks_
.empty());
621 DCHECK(task
== tasks_
.front().get());
622 // Remove all finished tasks from the queue (should be at most one).
623 while (!tasks_
.empty() && tasks_
.front()->IsDone())
626 // Now either the queue is empty or the next task is not finished yet and it
629 tasks_
.front()->Start();
632 } // namespace chromeos