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
,
287 FILTER_BY_PERMISSIONS
,
291 // This task determines all known client certs matching |request|. If
292 // |interactive| is true, calls |service->select_delegate_->Select()| to
293 // select a cert from all matches. The extension with |extension_id| will be
294 // granted unlimited sign permission for the selected cert.
295 // Finally, either the selection or, if |interactive| is false, matching certs
296 // that the extension has permission for are passed to |callback|.
297 SelectTask(const platform_keys::ClientCertificateRequest
& request
,
299 const std::string
& extension_id
,
300 const SelectCertificatesCallback
& callback
,
301 content::WebContents
* web_contents
,
302 KeyPermissions
* key_permissions
,
303 PlatformKeysService
* service
)
305 interactive_(interactive
),
306 extension_id_(extension_id
),
308 web_contents_(web_contents
),
309 key_permissions_(key_permissions
),
311 weak_factory_(this) {}
312 ~SelectTask() override
{}
314 void Start() override
{
315 CHECK(next_step_
== Step::GET_EXTENSION_PERMISSIONS
);
319 bool IsDone() override
{ return next_step_
== Step::DONE
; }
323 switch (next_step_
) {
324 case Step::GET_EXTENSION_PERMISSIONS
:
325 next_step_
= Step::GET_MATCHING_CERTS
;
326 GetExtensionPermissions();
328 case Step::GET_MATCHING_CERTS
:
330 next_step_
= Step::SELECT_CERTS
;
331 else // Skip SelectCerts and UpdatePermission if not interactive.
332 next_step_
= Step::FILTER_BY_PERMISSIONS
;
335 case Step::SELECT_CERTS
:
336 next_step_
= Step::UPDATE_PERMISSION
;
339 case Step::UPDATE_PERMISSION
:
340 next_step_
= Step::FILTER_BY_PERMISSIONS
;
343 case Step::FILTER_BY_PERMISSIONS
:
344 next_step_
= Step::DONE
;
345 FilterSelectionByPermission();
348 service_
->TaskFinished(this);
349 // |this| might be invalid now.
354 void GetExtensionPermissions() {
355 key_permissions_
->GetPermissionsForExtension(
357 base::Bind(&SelectTask::GotPermissions
, base::Unretained(this)));
360 void GotPermissions(scoped_ptr
<KeyPermissions::PermissionsForExtension
>
361 extension_permissions
) {
362 extension_permissions_
= extension_permissions
.Pass();
366 // Retrieves all certificates matching |request_|. Will call back to
367 // |GotMatchingCerts()|.
368 void GetMatchingCerts() {
369 platform_keys::subtle::SelectClientCertificates(
370 request_
.certificate_authorities
,
371 base::Bind(&SelectTask::GotMatchingCerts
, weak_factory_
.GetWeakPtr()),
372 service_
->browser_context_
);
375 // If the certificate request could be processed successfully, |matches| will
376 // contain the list of matching certificates (maybe empty) and |error_message|
377 // will be empty. If an error occurred, |matches| will be null and
378 // |error_message| contain an error message.
379 void GotMatchingCerts(scoped_ptr
<net::CertificateList
> matches
,
380 const std::string
& error_message
) {
381 if (!error_message
.empty()) {
382 next_step_
= Step::DONE
;
383 callback_
.Run(nullptr /* no certificates */, error_message
);
388 for (scoped_refptr
<net::X509Certificate
>& certificate
: *matches
) {
389 const std::string
public_key_spki_der(
390 platform_keys::GetSubjectPublicKeyInfo(certificate
));
391 // Skip this key if the user cannot grant any permission for it, except if
392 // this extension can already use it for signing.
393 if (!key_permissions_
->CanUserGrantPermissionFor(public_key_spki_der
) &&
394 !extension_permissions_
->CanUseKeyForSigning(public_key_spki_der
)) {
398 // Filter the retrieved certificates returning only those whose type is
399 // equal to one of the entries in the type field of the certificate
401 // If the type field does not contain any entries, certificates of all
402 // types shall be returned.
403 if (!request_
.certificate_key_types
.empty()) {
404 net::X509Certificate::PublicKeyType actual_key_type
=
405 net::X509Certificate::kPublicKeyTypeUnknown
;
406 size_t unused_key_size
= 0;
407 net::X509Certificate::GetPublicKeyInfo(
408 certificate
->os_cert_handle(), &unused_key_size
, &actual_key_type
);
409 const std::vector
<net::X509Certificate::PublicKeyType
>& accepted_types
=
410 request_
.certificate_key_types
;
411 if (std::find(accepted_types
.begin(), accepted_types
.end(),
412 actual_key_type
) == accepted_types
.end()) {
417 matches_
.push_back(certificate
.Pass());
422 // Calls |service_->select_delegate_->Select()| to select a cert from
423 // |matches_|, which will be stored in |selected_cert_|.
424 // Will call back to |GotSelection()|.
427 if (matches_
.empty()) {
428 // Don't show a select dialog if no certificate is matching.
432 service_
->select_delegate_
->Select(
433 extension_id_
, matches_
,
434 base::Bind(&SelectTask::GotSelection
, base::Unretained(this)),
435 web_contents_
, service_
->browser_context_
);
438 // Will be called by |SelectCerts()| with the selected cert or null if no cert
440 void GotSelection(const scoped_refptr
<net::X509Certificate
>& selected_cert
) {
441 selected_cert_
= selected_cert
;
445 // Updates the extension's state store about unlimited sign permission for the
446 // selected cert. Does nothing if no cert was selected.
447 void UpdatePermission() {
449 if (!selected_cert_
) {
453 const std::string
public_key_spki_der(
454 platform_keys::GetSubjectPublicKeyInfo(selected_cert_
));
455 extension_permissions_
->SetUserGrantedPermission(public_key_spki_der
);
459 // Filters from all matches (if not interactive) or from the selection (if
460 // interactive), the certificates that the extension has unlimited sign
461 // permission for. Passes the filtered certs to |callback_|.
462 void FilterSelectionByPermission() {
463 scoped_ptr
<net::CertificateList
> selection(new net::CertificateList
);
466 selection
->push_back(selected_cert_
);
468 selection
->assign(matches_
.begin(), matches_
.end());
471 scoped_ptr
<net::CertificateList
> filtered_certs(new net::CertificateList
);
472 for (scoped_refptr
<net::X509Certificate
> selected_cert
: *selection
) {
473 const std::string
public_key_spki_der(
474 platform_keys::GetSubjectPublicKeyInfo(selected_cert
));
476 if (!extension_permissions_
->CanUseKeyForSigning(public_key_spki_der
))
479 filtered_certs
->push_back(selected_cert
);
481 // Note: In the interactive case this should have filtered exactly the
482 // one selected cert. Checking the permissions again is not striclty
483 // necessary but this ensures that the permissions were updated correctly.
484 CHECK(!selected_cert_
|| (filtered_certs
->size() == 1 &&
485 filtered_certs
->front() == selected_cert_
));
486 callback_
.Run(filtered_certs
.Pass(), std::string() /* no error */);
490 Step next_step_
= Step::GET_EXTENSION_PERMISSIONS
;
492 net::CertificateList matches_
;
493 scoped_refptr
<net::X509Certificate
> selected_cert_
;
494 platform_keys::ClientCertificateRequest request_
;
495 const bool interactive_
;
496 const std::string extension_id_
;
497 const SelectCertificatesCallback callback_
;
498 content::WebContents
* const web_contents_
;
499 scoped_ptr
<KeyPermissions::PermissionsForExtension
> extension_permissions_
;
500 KeyPermissions
* const key_permissions_
;
501 PlatformKeysService
* const service_
;
502 base::WeakPtrFactory
<SelectTask
> weak_factory_
;
504 DISALLOW_COPY_AND_ASSIGN(SelectTask
);
507 PlatformKeysService::SelectDelegate::SelectDelegate() {
510 PlatformKeysService::SelectDelegate::~SelectDelegate() {
513 PlatformKeysService::PlatformKeysService(
514 bool profile_is_managed
,
515 PrefService
* profile_prefs
,
516 policy::PolicyService
* profile_policies
,
517 content::BrowserContext
* browser_context
,
518 extensions::StateStore
* state_store
)
519 : browser_context_(browser_context
),
520 key_permissions_(profile_is_managed
,
524 weak_factory_(this) {
525 DCHECK(browser_context
);
529 PlatformKeysService::~PlatformKeysService() {
532 void PlatformKeysService::SetSelectDelegate(
533 scoped_ptr
<SelectDelegate
> delegate
) {
534 select_delegate_
= delegate
.Pass();
537 void PlatformKeysService::GenerateRSAKey(const std::string
& token_id
,
538 unsigned int modulus_length
,
539 const std::string
& extension_id
,
540 const GenerateKeyCallback
& callback
) {
541 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
542 StartOrQueueTask(make_scoped_ptr(
543 new GenerateRSAKeyTask(token_id
, modulus_length
, extension_id
, callback
,
544 &key_permissions_
, this, browser_context_
)));
547 void PlatformKeysService::SignRSAPKCS1Digest(
548 const std::string
& token_id
,
549 const std::string
& data
,
550 const std::string
& public_key
,
551 platform_keys::HashAlgorithm hash_algorithm
,
552 const std::string
& extension_id
,
553 const SignCallback
& callback
) {
554 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
555 StartOrQueueTask(make_scoped_ptr(new SignTask(
556 token_id
, data
, public_key
, false /* digest before signing */,
557 hash_algorithm
, extension_id
, callback
, &key_permissions_
, this)));
560 void PlatformKeysService::SignRSAPKCS1Raw(const std::string
& token_id
,
561 const std::string
& data
,
562 const std::string
& public_key
,
563 const std::string
& extension_id
,
564 const SignCallback
& callback
) {
565 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
566 StartOrQueueTask(make_scoped_ptr(new SignTask(
567 token_id
, data
, public_key
, true /* sign directly without hashing */,
568 platform_keys::HASH_ALGORITHM_NONE
, extension_id
, callback
,
569 &key_permissions_
, this)));
572 void PlatformKeysService::SelectClientCertificates(
573 const platform_keys::ClientCertificateRequest
& request
,
575 const std::string
& extension_id
,
576 const SelectCertificatesCallback
& callback
,
577 content::WebContents
* web_contents
) {
578 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
579 StartOrQueueTask(make_scoped_ptr(
580 new SelectTask(request
, interactive
, extension_id
, callback
, web_contents
,
581 &key_permissions_
, this)));
584 void PlatformKeysService::StartOrQueueTask(scoped_ptr
<Task
> task
) {
585 tasks_
.push(make_linked_ptr(task
.release()));
586 if (tasks_
.size() == 1)
587 tasks_
.front()->Start();
590 void PlatformKeysService::TaskFinished(Task
* task
) {
591 DCHECK(!tasks_
.empty());
592 DCHECK(task
== tasks_
.front().get());
593 // Remove all finished tasks from the queue (should be at most one).
594 while (!tasks_
.empty() && tasks_
.front()->IsDone())
597 // Now either the queue is empty or the next task is not finished yet and it
600 tasks_
.front()->Start();
603 } // namespace chromeos