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.
4
5 #include "chrome/browser/chromeos/platform_keys/extension_platform_keys_service.h"
6
7 #include <stddef.h>
8
9 #include <utility>
10
11 #include "base/bind.h"
12 #include "base/callback.h"
13 #include "base/callback_helpers.h"
14 #include "base/macros.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/optional.h"
17 #include "base/stl_util.h"
18 #include "base/values.h"
19 #include "chrome/browser/chromeos/platform_keys/key_permissions/extension_key_permissions_service.h"
20 #include "chrome/browser/chromeos/platform_keys/key_permissions/extension_key_permissions_service_factory.h"
21 #include "chrome/browser/chromeos/platform_keys/key_permissions/key_permissions_service.h"
22 #include "chrome/browser/chromeos/platform_keys/key_permissions/key_permissions_service_factory.h"
23 #include "chrome/browser/chromeos/platform_keys/platform_keys.h"
24 #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h"
25 #include "chrome/browser/chromeos/platform_keys/platform_keys_service_factory.h"
26 #include "chrome/browser/chromeos/profiles/profile_helper.h"
27 #include "chrome/browser/profiles/profile.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "extensions/browser/extension_registry.h"
30 #include "extensions/browser/state_store.h"
31 #include "extensions/common/extension.h"
32 #include "extensions/common/features/behavior_feature.h"
33 #include "extensions/common/features/feature.h"
34 #include "extensions/common/features/feature_provider.h"
35 #include "net/cert/x509_certificate.h"
36
37 using content::BrowserThread;
38
39 namespace chromeos {
40
41 namespace {
42
43 #if defined(OS_CHROMEOS)
44
45 // Verify the allowlisted kKeyPermissionsInLoginScreen feature behaviors.
IsExtensionAllowlisted(const extensions::Extension * extension)46 bool IsExtensionAllowlisted(const extensions::Extension* extension) {
47 // Can be nullptr if the extension is uninstalled before the SignTask is
48 // completed.
49 if (!extension)
50 return false;
51
52 const extensions::Feature* key_permissions_in_login_screen =
53 extensions::FeatureProvider::GetBehaviorFeature(
54 extensions::behavior_feature::kKeyPermissionsInLoginScreen);
55
56 return key_permissions_in_login_screen->IsAvailableToExtension(extension)
57 .is_available();
58 }
59 #endif // defined(OS_CHROMEOS)
60
61 } // namespace
62
63 class ExtensionPlatformKeysService::Task {
64 public:
Task()65 Task() {}
~Task()66 virtual ~Task() {}
67 virtual void Start() = 0;
68 virtual bool IsDone() = 0;
69
70 private:
71 DISALLOW_ASSIGN(Task);
72 };
73
74 class ExtensionPlatformKeysService::GenerateKeyTask : public Task {
75 public:
76 enum class Step {
77 GENERATE_KEY,
78 GET_EXTENSION_PERMISSIONS,
79 UPDATE_PERMISSIONS_AND_CALLBACK,
80 DONE,
81 };
82
GenerateKeyTask(platform_keys::TokenId token_id,const std::string & extension_id,const GenerateKeyCallback & callback,ExtensionPlatformKeysService * service)83 GenerateKeyTask(platform_keys::TokenId token_id,
84 const std::string& extension_id,
85 const GenerateKeyCallback& callback,
86 ExtensionPlatformKeysService* service)
87 : token_id_(token_id),
88 extension_id_(extension_id),
89 callback_(callback),
90 service_(service) {}
91
92 ~GenerateKeyTask() override = default;
93
Start()94 void Start() override {
95 CHECK(next_step_ == Step::GENERATE_KEY);
96 DoStep();
97 }
98
IsDone()99 bool IsDone() override { return next_step_ == Step::DONE; }
100
101 protected:
102 virtual void GenerateKey(GenerateKeyCallback callback) = 0;
103
104 platform_keys::TokenId token_id_;
105 std::string public_key_spki_der_;
106 const std::string extension_id_;
107 GenerateKeyCallback callback_;
108 std::unique_ptr<platform_keys::ExtensionKeyPermissionsService>
109 extension_key_permissions_service_;
110 ExtensionPlatformKeysService* const service_;
111
112 private:
DoStep()113 void DoStep() {
114 switch (next_step_) {
115 case Step::GENERATE_KEY:
116 next_step_ = Step::GET_EXTENSION_PERMISSIONS;
117 GenerateKey(base::Bind(&GenerateKeyTask::GeneratedKey,
118 weak_factory_.GetWeakPtr()));
119 return;
120 case Step::GET_EXTENSION_PERMISSIONS:
121 next_step_ = Step::UPDATE_PERMISSIONS_AND_CALLBACK;
122 GetExtensionPermissions();
123 return;
124 case Step::UPDATE_PERMISSIONS_AND_CALLBACK:
125 next_step_ = Step::DONE;
126 UpdatePermissionsAndCallBack();
127 return;
128 case Step::DONE:
129 service_->TaskFinished(this);
130 // |this| might be invalid now.
131 return;
132 }
133 }
134
135 // Stores the generated key or in case of an error calls |callback_| with the
136 // error status.
GeneratedKey(const std::string & public_key_spki_der,platform_keys::Status status)137 void GeneratedKey(const std::string& public_key_spki_der,
138 platform_keys::Status status) {
139 if (status != platform_keys::Status::kSuccess) {
140 next_step_ = Step::DONE;
141 callback_.Run(std::string() /* no public key */, status);
142 DoStep();
143 return;
144 }
145 public_key_spki_der_ = public_key_spki_der;
146 DoStep();
147 }
148
149 // Gets the permissions for the extension with id |extension_id|.
GetExtensionPermissions()150 void GetExtensionPermissions() {
151 platform_keys::ExtensionKeyPermissionsServiceFactory::
152 GetForBrowserContextAndExtension(
153 base::BindOnce(&GenerateKeyTask::GotPermissions,
154 base::Unretained(this)),
155 service_->browser_context_, extension_id_,
156 service_->key_permissions_service_);
157 }
158
OnKeyRegisteredForCorporateUsage(platform_keys::Status status)159 void OnKeyRegisteredForCorporateUsage(platform_keys::Status status) {
160 if (status == platform_keys::Status::kSuccess) {
161 callback_.Run(public_key_spki_der_, status);
162 DoStep();
163 return;
164 }
165
166 // TODO(crbug.com/1131436): Delete public key if corporate registration
167 // failed.
168 LOG(ERROR) << "Corporate key registration failed: "
169 << platform_keys::StatusToString(status);
170 next_step_ = Step::DONE;
171 callback_.Run(std::string() /* no public key */, status);
172 DoStep();
173 }
174
UpdatePermissionsAndCallBack()175 void UpdatePermissionsAndCallBack() {
176 extension_key_permissions_service_->RegisterKeyForCorporateUsage(
177 public_key_spki_der_,
178 base::BindOnce(&GenerateKeyTask::OnKeyRegisteredForCorporateUsage,
179 base::Unretained(this)));
180 }
181
GotPermissions(std::unique_ptr<platform_keys::ExtensionKeyPermissionsService> extension_key_permissions_service)182 void GotPermissions(
183 std::unique_ptr<platform_keys::ExtensionKeyPermissionsService>
184 extension_key_permissions_service) {
185 extension_key_permissions_service_ =
186 std::move(extension_key_permissions_service);
187 DoStep();
188 }
189
190 Step next_step_ = Step::GENERATE_KEY;
191
192 base::WeakPtrFactory<GenerateKeyTask> weak_factory_{this};
193
194 DISALLOW_COPY_AND_ASSIGN(GenerateKeyTask);
195 };
196
197 class ExtensionPlatformKeysService::GenerateRSAKeyTask
198 : public GenerateKeyTask {
199 public:
200 // This key task generates an RSA key with the parameters |token_id| and
201 // |modulus_length| and registers it for the extension with id |extension_id|.
202 // The generated key will be passed to |callback|.
GenerateRSAKeyTask(platform_keys::TokenId token_id,unsigned int modulus_length,const std::string & extension_id,const GenerateKeyCallback & callback,ExtensionPlatformKeysService * service)203 GenerateRSAKeyTask(platform_keys::TokenId token_id,
204 unsigned int modulus_length,
205 const std::string& extension_id,
206 const GenerateKeyCallback& callback,
207 ExtensionPlatformKeysService* service)
208 : GenerateKeyTask(token_id, extension_id, callback, service),
209 modulus_length_(modulus_length) {}
210
~GenerateRSAKeyTask()211 ~GenerateRSAKeyTask() override {}
212
213 private:
214 // Generates the RSA key.
GenerateKey(GenerateKeyCallback callback)215 void GenerateKey(GenerateKeyCallback callback) override {
216 service_->platform_keys_service_->GenerateRSAKey(token_id_, modulus_length_,
217 callback);
218 }
219
220 const unsigned int modulus_length_;
221 };
222
223 class ExtensionPlatformKeysService::GenerateECKeyTask : public GenerateKeyTask {
224 public:
225 // This Task generates an EC key with the parameters |token_id| and
226 // |named_curve| and registers it for the extension with id |extension_id|.
227 // The generated key will be passed to |callback|.
GenerateECKeyTask(platform_keys::TokenId token_id,const std::string & named_curve,const std::string & extension_id,const GenerateKeyCallback & callback,ExtensionPlatformKeysService * service)228 GenerateECKeyTask(platform_keys::TokenId token_id,
229 const std::string& named_curve,
230 const std::string& extension_id,
231 const GenerateKeyCallback& callback,
232 ExtensionPlatformKeysService* service)
233 : GenerateKeyTask(token_id, extension_id, callback, service),
234 named_curve_(named_curve) {}
235
~GenerateECKeyTask()236 ~GenerateECKeyTask() override {}
237
238 private:
239 // Generates the EC key.
GenerateKey(GenerateKeyCallback callback)240 void GenerateKey(GenerateKeyCallback callback) override {
241 service_->platform_keys_service_->GenerateECKey(token_id_, named_curve_,
242 callback);
243 }
244
245 const std::string named_curve_;
246 };
247
248 class ExtensionPlatformKeysService::SignTask : public Task {
249 public:
250 enum class Step {
251 GET_EXTENSION_PERMISSIONS,
252 CHECK_SIGN_PERMISSIONS,
253 UPDATE_SIGN_PERMISSIONS,
254 SIGN,
255 DONE,
256 };
257
258 // This Task will check the permissions of the extension with |extension_id|
259 // for the key of type |key_type| identified by |public_key_spki_der|. If the
260 // permission check was positive, signs |data| with the key and passes the
261 // signature to |callback|. If the extension is not allowed to use the key
262 // multiple times, also updates the permission to prevent any future signing
263 // operation of that extension using that same key. If an error occurs, an
264 // error status is passed to |callback|.
SignTask(base::Optional<platform_keys::TokenId> token_id,const std::string & data,const std::string & public_key_spki_der,bool raw_pkcs1,platform_keys::KeyType key_type,platform_keys::HashAlgorithm hash_algorithm,const std::string & extension_id,const SignCallback & callback,ExtensionPlatformKeysService * service)265 SignTask(base::Optional<platform_keys::TokenId> token_id,
266 const std::string& data,
267 const std::string& public_key_spki_der,
268 bool raw_pkcs1,
269 platform_keys::KeyType key_type,
270 platform_keys::HashAlgorithm hash_algorithm,
271 const std::string& extension_id,
272 const SignCallback& callback,
273 ExtensionPlatformKeysService* service)
274 : token_id_(token_id),
275 data_(data),
276 public_key_spki_der_(public_key_spki_der),
277 raw_pkcs1_(raw_pkcs1),
278 key_type_(key_type),
279 hash_algorithm_(hash_algorithm),
280 extension_id_(extension_id),
281 callback_(callback),
282 service_(service) {}
283
~SignTask()284 ~SignTask() override {}
285
Start()286 void Start() override {
287 CHECK(next_step_ == Step::GET_EXTENSION_PERMISSIONS);
288 DoStep();
289 }
290
IsDone()291 bool IsDone() override { return next_step_ == Step::DONE; }
292
293 private:
DoStep()294 void DoStep() {
295 switch (next_step_) {
296 case Step::GET_EXTENSION_PERMISSIONS:
297 next_step_ = Step::CHECK_SIGN_PERMISSIONS;
298 GetExtensionPermissions();
299 return;
300 case Step::CHECK_SIGN_PERMISSIONS:
301 next_step_ = Step::UPDATE_SIGN_PERMISSIONS;
302 CheckSignPermissions();
303 return;
304 case Step::UPDATE_SIGN_PERMISSIONS:
305 next_step_ = Step::SIGN;
306 UpdateSignPermissions();
307 return;
308 case Step::SIGN:
309 next_step_ = Step::DONE;
310 Sign();
311 return;
312 case Step::DONE:
313 service_->TaskFinished(this);
314 // |this| might be invalid now.
315 return;
316 }
317 }
318
GetExtensionPermissions()319 void GetExtensionPermissions() {
320 platform_keys::ExtensionKeyPermissionsServiceFactory::
321 GetForBrowserContextAndExtension(
322 base::BindOnce(&SignTask::GotPermissions, base::Unretained(this)),
323 service_->browser_context_, extension_id_,
324 service_->key_permissions_service_);
325 }
326
GotPermissions(std::unique_ptr<platform_keys::ExtensionKeyPermissionsService> extension_key_permissions_service)327 void GotPermissions(
328 std::unique_ptr<platform_keys::ExtensionKeyPermissionsService>
329 extension_key_permissions_service) {
330 extension_key_permissions_service_ =
331 std::move(extension_key_permissions_service);
332 DoStep();
333 }
334
CheckSignPermissions()335 void CheckSignPermissions() {
336 const extensions::Extension* extension =
337 extensions::ExtensionRegistry::Get(service_->browser_context_)
338 ->GetExtensionById(extension_id_,
339 extensions::ExtensionRegistry::ENABLED);
340 if (service_->IsUsingSigninProfile() && IsExtensionAllowlisted(extension)) {
341 DoStep();
342 return;
343 }
344
345 extension_key_permissions_service_->CanUseKeyForSigning(
346 public_key_spki_der_,
347 base::BindOnce(&SignTask::OnCanUseKeyForSigningKnown,
348 base::Unretained(this)));
349 }
350
OnCanUseKeyForSigningKnown(bool allowed)351 void OnCanUseKeyForSigningKnown(bool allowed) {
352 if (!allowed) {
353 callback_.Run(std::string() /* no signature */,
354 platform_keys::Status::kErrorKeyNotAllowedForSigning);
355 next_step_ = Step::DONE;
356 DoStep();
357 return;
358 }
359
360 DoStep();
361 }
362
363 // Updates the signing permissions for |public_key_spki_der_|.
UpdateSignPermissions()364 void UpdateSignPermissions() {
365 extension_key_permissions_service_->SetKeyUsedForSigning(
366 public_key_spki_der_,
367 base::BindOnce(&SignTask::OnSetKeyUsedForSigningDone,
368 base::Unretained(this)));
369 }
370
OnSetKeyUsedForSigningDone(platform_keys::Status status)371 void OnSetKeyUsedForSigningDone(platform_keys::Status status) {
372 if (status != platform_keys::Status::kSuccess) {
373 LOG(ERROR) << "Marking a key used for signing failed: "
374 << platform_keys::StatusToString(status);
375 next_step_ = Step::DONE;
376 callback_.Run(std::string() /* no signature */, status);
377 DoStep();
378 return;
379 }
380
381 DoStep();
382 }
383
384 // Starts the actual signing operation and afterwards passes the signature (or
385 // error) to |callback_|.
Sign()386 void Sign() {
387 switch (key_type_) {
388 case platform_keys::KeyType::kRsassaPkcs1V15: {
389 if (raw_pkcs1_) {
390 service_->platform_keys_service_->SignRSAPKCS1Raw(
391 token_id_, data_, public_key_spki_der_,
392 base::Bind(&SignTask::DidSign, weak_factory_.GetWeakPtr()));
393 } else {
394 service_->platform_keys_service_->SignRSAPKCS1Digest(
395 token_id_, data_, public_key_spki_der_, hash_algorithm_,
396
397 base::Bind(&SignTask::DidSign, weak_factory_.GetWeakPtr()));
398 }
399 break;
400 }
401 case platform_keys::KeyType::kEcdsa: {
402 service_->platform_keys_service_->SignECDSADigest(
403 token_id_, data_, public_key_spki_der_, hash_algorithm_,
404 base::Bind(&SignTask::DidSign, weak_factory_.GetWeakPtr()));
405 break;
406 }
407 }
408 }
409
DidSign(const std::string & signature,platform_keys::Status status)410 void DidSign(const std::string& signature, platform_keys::Status status) {
411 callback_.Run(signature, status);
412 DoStep();
413 }
414
415 Step next_step_ = Step::GET_EXTENSION_PERMISSIONS;
416
417 base::Optional<platform_keys::TokenId> token_id_;
418 const std::string data_;
419 const std::string public_key_spki_der_;
420
421 // If true, |data_| will not be hashed before signing. Only PKCS#1 v1.5
422 // padding will be applied before signing.
423 // If false, |hash_algorithm_| is set to a value != NONE.
424 bool raw_pkcs1_;
425 const platform_keys::KeyType key_type_;
426 const platform_keys::HashAlgorithm hash_algorithm_;
427 const std::string extension_id_;
428 const SignCallback callback_;
429 std::unique_ptr<platform_keys::ExtensionKeyPermissionsService>
430 extension_key_permissions_service_;
431 ExtensionPlatformKeysService* const service_;
432 base::WeakPtrFactory<SignTask> weak_factory_{this};
433
434 DISALLOW_COPY_AND_ASSIGN(SignTask);
435 };
436
437 class ExtensionPlatformKeysService::SelectTask : public Task {
438 public:
439 enum class Step {
440 GET_EXTENSION_PERMISSIONS,
441 GET_MATCHING_CERTS,
442 CHECK_KEY_PERMISSIONS,
443 INTERSECT_WITH_INPUT_CERTS,
444 SELECT_CERTS,
445 UPDATE_PERMISSION,
446 PASS_RESULTING_CERTS,
447 DONE,
448 };
449
450 // This task determines all known client certs matching |request| and that are
451 // elements of |input_client_certificates|, if given. If |interactive| is
452 // true, calls |service->select_delegate_->Select()| to select a cert from all
453 // matches. The extension with |extension_id| will be granted unlimited sign
454 // permission for the selected cert. Finally, either the selection or, if
455 // |interactive| is false, matching certs that the extension has permission
456 // for are passed to |callback|.
SelectTask(const platform_keys::ClientCertificateRequest & request,std::unique_ptr<net::CertificateList> input_client_certificates,bool interactive,const std::string & extension_id,const SelectCertificatesCallback & callback,content::WebContents * web_contents,ExtensionPlatformKeysService * service)457 SelectTask(const platform_keys::ClientCertificateRequest& request,
458 std::unique_ptr<net::CertificateList> input_client_certificates,
459 bool interactive,
460 const std::string& extension_id,
461 const SelectCertificatesCallback& callback,
462 content::WebContents* web_contents,
463 ExtensionPlatformKeysService* service)
464 : request_(request),
465 input_client_certificates_(std::move(input_client_certificates)),
466 interactive_(interactive),
467 extension_id_(extension_id),
468 callback_(callback),
469 web_contents_(web_contents),
470 service_(service) {}
~SelectTask()471 ~SelectTask() override {}
472
Start()473 void Start() override {
474 CHECK(next_step_ == Step::GET_EXTENSION_PERMISSIONS);
475 DoStep();
476 }
477
IsDone()478 bool IsDone() override { return next_step_ == Step::DONE; }
479
480 private:
DoStep()481 void DoStep() {
482 switch (next_step_) {
483 case Step::GET_EXTENSION_PERMISSIONS:
484 next_step_ = Step::GET_MATCHING_CERTS;
485 GetExtensionPermissions();
486 return;
487 case Step::GET_MATCHING_CERTS:
488 next_step_ = Step::CHECK_KEY_PERMISSIONS;
489 GetMatchingCerts();
490 return;
491 case Step::CHECK_KEY_PERMISSIONS:
492 // Don't advance to the next step yet - CheckKeyPermissions is repeated
493 // for all matching certs. The next step will be selected in
494 // CheckKeyPermissions.
495 CheckKeyPermissions(Step::INTERSECT_WITH_INPUT_CERTS /* next_step */);
496 return;
497 case Step::INTERSECT_WITH_INPUT_CERTS:
498 if (interactive_)
499 next_step_ = Step::SELECT_CERTS;
500 else // Skip SelectCerts and UpdatePermission if not interactive.
501 next_step_ = Step::PASS_RESULTING_CERTS;
502 IntersectWithInputCerts();
503 return;
504 case Step::SELECT_CERTS:
505 next_step_ = Step::UPDATE_PERMISSION;
506 SelectCerts();
507 return;
508 case Step::UPDATE_PERMISSION:
509 next_step_ = Step::PASS_RESULTING_CERTS;
510 UpdatePermission();
511 return;
512 case Step::PASS_RESULTING_CERTS:
513 next_step_ = Step::DONE;
514 PassResultingCerts();
515 return;
516 case Step::DONE:
517 service_->TaskFinished(this);
518 // |this| might be invalid now.
519 return;
520 }
521 }
522
GetExtensionPermissions()523 void GetExtensionPermissions() {
524 platform_keys::ExtensionKeyPermissionsServiceFactory::
525 GetForBrowserContextAndExtension(
526 base::BindOnce(&SelectTask::GotPermissions, base::Unretained(this)),
527 service_->browser_context_, extension_id_,
528 service_->key_permissions_service_);
529 }
530
GotPermissions(std::unique_ptr<platform_keys::ExtensionKeyPermissionsService> extension_key_permissions_service)531 void GotPermissions(
532 std::unique_ptr<platform_keys::ExtensionKeyPermissionsService>
533 extension_key_permissions_service) {
534 extension_key_permissions_service_ =
535 std::move(extension_key_permissions_service);
536 DoStep();
537 }
538
539 // Retrieves all certificates matching |request_|. Will call back to
540 // |GotMatchingCerts()|.
GetMatchingCerts()541 void GetMatchingCerts() {
542 service_->platform_keys_service_->SelectClientCertificates(
543 request_.certificate_authorities,
544 base::Bind(&SelectTask::GotMatchingCerts, weak_factory_.GetWeakPtr()));
545 }
546
547 // If the certificate request could be processed successfully, |matches| will
548 // contain the list of matching certificates (maybe empty). If an error
549 // occurred, |matches| will be null. Note that the order of |matches|, based
550 // on the expiration/issuance date, is relevant and must be preserved in any
551 // processing of the list.
GotMatchingCerts(std::unique_ptr<net::CertificateList> matches,platform_keys::Status status)552 void GotMatchingCerts(std::unique_ptr<net::CertificateList> matches,
553 platform_keys::Status status) {
554 if (status != platform_keys::Status::kSuccess) {
555 next_step_ = Step::DONE;
556 callback_.Run(nullptr /* no certificates */, status);
557 DoStep();
558 return;
559 }
560
561 for (scoped_refptr<net::X509Certificate>& certificate : *matches) {
562 // Filter the retrieved certificates returning only those whose type is
563 // equal to one of the entries in the type field of the certificate
564 // request.
565 // If the type field does not contain any entries, certificates of all
566 // types shall be returned.
567 if (!request_.certificate_key_types.empty()) {
568 net::X509Certificate::PublicKeyType actual_key_type =
569 net::X509Certificate::kPublicKeyTypeUnknown;
570 size_t unused_key_size = 0;
571 net::X509Certificate::GetPublicKeyInfo(
572 certificate->cert_buffer(), &unused_key_size, &actual_key_type);
573 const std::vector<net::X509Certificate::PublicKeyType>& accepted_types =
574 request_.certificate_key_types;
575 if (!base::Contains(accepted_types, actual_key_type))
576 continue;
577 }
578
579 matches_pending_permissions_check_.push_back(std::move(certificate));
580 }
581 DoStep();
582 }
583
584 // This is called once for each certificate in
585 // |matches_pending_permissions_check_|. Each invocation processes the first
586 // element and removes it from the deque. Each processed certificate is added
587 // to |matches_| if it is selectable according to KeyPermissionsService. When
588 // all certificates have been processed, advances the SignTask state machine
589 // to |next_step|.
CheckKeyPermissions(Step next_step)590 void CheckKeyPermissions(Step next_step) {
591 if (matches_pending_permissions_check_.empty()) {
592 next_step_ = next_step;
593 DoStep();
594 return;
595 }
596
597 scoped_refptr<net::X509Certificate> certificate =
598 std::move(matches_pending_permissions_check_.front());
599 matches_pending_permissions_check_.pop_front();
600 const std::string public_key_spki_der(
601 platform_keys::GetSubjectPublicKeyInfo(certificate));
602
603 extension_key_permissions_service_->CanUseKeyForSigning(
604 public_key_spki_der,
605 base::BindOnce(&SelectTask::OnKeySigningPermissionKnown,
606 base::Unretained(this), public_key_spki_der,
607 certificate));
608 }
609
OnKeySigningPermissionKnown(const std::string & public_key_spki_der,const scoped_refptr<net::X509Certificate> & certificate,bool allowed)610 void OnKeySigningPermissionKnown(
611 const std::string& public_key_spki_der,
612 const scoped_refptr<net::X509Certificate>& certificate,
613 bool allowed) {
614 if (allowed) {
615 matches_.push_back(certificate);
616 DoStep();
617 } else if (interactive_) {
618 platform_keys::KeyPermissionsService* const key_permissions_service =
619 platform_keys::KeyPermissionsServiceFactory::GetForBrowserContext(
620 service_->browser_context_);
621 key_permissions_service->CanUserGrantPermissionForKey(
622 public_key_spki_der,
623 base::BindOnce(&SelectTask::OnAbilityToGrantPermissionKnown,
624 base::Unretained(this), std::move(certificate)));
625 } else {
626 DoStep();
627 }
628 }
629
OnAbilityToGrantPermissionKnown(const scoped_refptr<net::X509Certificate> & certificate,bool allowed)630 void OnAbilityToGrantPermissionKnown(
631 const scoped_refptr<net::X509Certificate>& certificate,
632 bool allowed) {
633 if (allowed) {
634 matches_.push_back(certificate);
635 }
636 DoStep();
637 }
638
639 // If |input_client_certificates_| is given, removes from |matches_| all
640 // certificates that are not elements of |input_client_certificates_|.
IntersectWithInputCerts()641 void IntersectWithInputCerts() {
642 if (!input_client_certificates_) {
643 DoStep();
644 return;
645 }
646 platform_keys::IntersectCertificates(
647 matches_, *input_client_certificates_,
648 base::Bind(&SelectTask::GotIntersection, weak_factory_.GetWeakPtr()));
649 }
650
GotIntersection(std::unique_ptr<net::CertificateList> intersection)651 void GotIntersection(std::unique_ptr<net::CertificateList> intersection) {
652 matches_.swap(*intersection);
653 DoStep();
654 }
655
656 // Calls |service_->select_delegate_->Select()| to select a cert from
657 // |matches_|, which will be stored in |selected_cert_|.
658 // Will call back to |GotSelection()|.
SelectCerts()659 void SelectCerts() {
660 CHECK(interactive_);
661 if (matches_.empty()) {
662 // Don't show a select dialog if no certificate is matching.
663 DoStep();
664 return;
665 }
666 service_->select_delegate_->Select(
667 extension_id_, matches_,
668 base::Bind(&SelectTask::GotSelection, base::Unretained(this)),
669 web_contents_, service_->browser_context_);
670 }
671
672 // Will be called by |SelectCerts()| with the selected cert or null if no cert
673 // was selected.
GotSelection(const scoped_refptr<net::X509Certificate> & selected_cert)674 void GotSelection(const scoped_refptr<net::X509Certificate>& selected_cert) {
675 selected_cert_ = selected_cert;
676 DoStep();
677 }
678
679 // Updates the extension's state store about unlimited sign permission for the
680 // selected cert. Does nothing if no cert was selected.
UpdatePermission()681 void UpdatePermission() {
682 CHECK(interactive_);
683 if (!selected_cert_) {
684 DoStep();
685 return;
686 }
687 const std::string public_key_spki_der(
688 platform_keys::GetSubjectPublicKeyInfo(selected_cert_));
689 extension_key_permissions_service_->SetUserGrantedPermission(
690 public_key_spki_der, base::BindOnce(&SelectTask::OnPermissionsUpdated,
691 base::Unretained(this)));
692 }
693
OnPermissionsUpdated(platform_keys::Status status)694 void OnPermissionsUpdated(platform_keys::Status status) {
695 if (status != platform_keys::Status::kSuccess) {
696 LOG(WARNING) << "Error while updating permissions: "
697 << platform_keys::StatusToString(status);
698 }
699
700 DoStep();
701 }
702
703 // Passes the filtered certs to |callback_|.
PassResultingCerts()704 void PassResultingCerts() {
705 std::unique_ptr<net::CertificateList> selection(new net::CertificateList);
706 if (interactive_) {
707 if (selected_cert_)
708 selection->push_back(selected_cert_);
709 } else {
710 selection->assign(matches_.begin(), matches_.end());
711 }
712
713 callback_.Run(std::move(selection), platform_keys::Status::kSuccess);
714 DoStep();
715 }
716
717 Step next_step_ = Step::GET_EXTENSION_PERMISSIONS;
718
719 std::deque<scoped_refptr<net::X509Certificate>>
720 matches_pending_permissions_check_;
721 net::CertificateList matches_;
722 scoped_refptr<net::X509Certificate> selected_cert_;
723 platform_keys::ClientCertificateRequest request_;
724 std::unique_ptr<net::CertificateList> input_client_certificates_;
725 const bool interactive_;
726 const std::string extension_id_;
727 const SelectCertificatesCallback callback_;
728 content::WebContents* const web_contents_;
729 std::unique_ptr<platform_keys::ExtensionKeyPermissionsService>
730 extension_key_permissions_service_;
731 ExtensionPlatformKeysService* const service_;
732 base::WeakPtrFactory<SelectTask> weak_factory_{this};
733
734 DISALLOW_COPY_AND_ASSIGN(SelectTask);
735 };
736
SelectDelegate()737 ExtensionPlatformKeysService::SelectDelegate::SelectDelegate() {}
738
~SelectDelegate()739 ExtensionPlatformKeysService::SelectDelegate::~SelectDelegate() {}
740
ExtensionPlatformKeysService(bool profile_is_managed,PrefService * profile_prefs,policy::PolicyService * profile_policies,content::BrowserContext * browser_context,extensions::StateStore * state_store)741 ExtensionPlatformKeysService::ExtensionPlatformKeysService(
742 bool profile_is_managed,
743 PrefService* profile_prefs,
744 policy::PolicyService* profile_policies,
745 content::BrowserContext* browser_context,
746 extensions::StateStore* state_store)
747 : browser_context_(browser_context),
748 platform_keys_service_(
749 platform_keys::PlatformKeysServiceFactory::GetForBrowserContext(
750 browser_context)),
751 key_permissions_service_(
752 chromeos::platform_keys::KeyPermissionsServiceFactory::
753 GetForBrowserContext(browser_context)) {
754 DCHECK(platform_keys_service_);
755 DCHECK(browser_context);
756 DCHECK(state_store);
757 }
758
~ExtensionPlatformKeysService()759 ExtensionPlatformKeysService::~ExtensionPlatformKeysService() {}
760
SetSelectDelegate(std::unique_ptr<SelectDelegate> delegate)761 void ExtensionPlatformKeysService::SetSelectDelegate(
762 std::unique_ptr<SelectDelegate> delegate) {
763 select_delegate_ = std::move(delegate);
764 }
765
GenerateRSAKey(platform_keys::TokenId token_id,unsigned int modulus_length,const std::string & extension_id,const GenerateKeyCallback & callback)766 void ExtensionPlatformKeysService::GenerateRSAKey(
767 platform_keys::TokenId token_id,
768 unsigned int modulus_length,
769 const std::string& extension_id,
770 const GenerateKeyCallback& callback) {
771 DCHECK_CURRENTLY_ON(BrowserThread::UI);
772 StartOrQueueTask(std::make_unique<GenerateRSAKeyTask>(
773 token_id, modulus_length, extension_id, callback, this));
774 }
775
GenerateECKey(platform_keys::TokenId token_id,const std::string & named_curve,const std::string & extension_id,const GenerateKeyCallback & callback)776 void ExtensionPlatformKeysService::GenerateECKey(
777 platform_keys::TokenId token_id,
778 const std::string& named_curve,
779 const std::string& extension_id,
780 const GenerateKeyCallback& callback) {
781 DCHECK_CURRENTLY_ON(BrowserThread::UI);
782 StartOrQueueTask(std::make_unique<GenerateECKeyTask>(
783 token_id, named_curve, extension_id, callback, this));
784 }
785
IsUsingSigninProfile()786 bool ExtensionPlatformKeysService::IsUsingSigninProfile() {
787 return ProfileHelper::IsSigninProfile(
788 Profile::FromBrowserContext(browser_context_));
789 }
790
SignDigest(base::Optional<platform_keys::TokenId> token_id,const std::string & data,const std::string & public_key_spki_der,platform_keys::KeyType key_type,platform_keys::HashAlgorithm hash_algorithm,const std::string & extension_id,const SignCallback & callback)791 void ExtensionPlatformKeysService::SignDigest(
792 base::Optional<platform_keys::TokenId> token_id,
793 const std::string& data,
794 const std::string& public_key_spki_der,
795 platform_keys::KeyType key_type,
796 platform_keys::HashAlgorithm hash_algorithm,
797 const std::string& extension_id,
798 const SignCallback& callback) {
799 DCHECK_CURRENTLY_ON(BrowserThread::UI);
800 StartOrQueueTask(
801 std::make_unique<SignTask>(token_id, data, public_key_spki_der,
802 /*raw_pkcs1=*/false, key_type, hash_algorithm,
803 extension_id, callback, this));
804 }
805
SignRSAPKCS1Raw(base::Optional<platform_keys::TokenId> token_id,const std::string & data,const std::string & public_key_spki_der,const std::string & extension_id,const SignCallback & callback)806 void ExtensionPlatformKeysService::SignRSAPKCS1Raw(
807 base::Optional<platform_keys::TokenId> token_id,
808 const std::string& data,
809 const std::string& public_key_spki_der,
810 const std::string& extension_id,
811 const SignCallback& callback) {
812 DCHECK_CURRENTLY_ON(BrowserThread::UI);
813 StartOrQueueTask(std::make_unique<SignTask>(
814 token_id, data, public_key_spki_der,
815 /*raw_pkcs1=*/true, /*key_type=*/platform_keys::KeyType::kRsassaPkcs1V15,
816 platform_keys::HASH_ALGORITHM_NONE, extension_id, callback, this));
817 }
818
SelectClientCertificates(const platform_keys::ClientCertificateRequest & request,std::unique_ptr<net::CertificateList> client_certificates,bool interactive,const std::string & extension_id,const SelectCertificatesCallback & callback,content::WebContents * web_contents)819 void ExtensionPlatformKeysService::SelectClientCertificates(
820 const platform_keys::ClientCertificateRequest& request,
821 std::unique_ptr<net::CertificateList> client_certificates,
822 bool interactive,
823 const std::string& extension_id,
824 const SelectCertificatesCallback& callback,
825 content::WebContents* web_contents) {
826 DCHECK_CURRENTLY_ON(BrowserThread::UI);
827 StartOrQueueTask(std::make_unique<SelectTask>(
828 request, std::move(client_certificates), interactive, extension_id,
829 callback, web_contents, this));
830 }
831
StartOrQueueTask(std::unique_ptr<Task> task)832 void ExtensionPlatformKeysService::StartOrQueueTask(
833 std::unique_ptr<Task> task) {
834 tasks_.push(std::move(task));
835 if (tasks_.size() == 1)
836 tasks_.front()->Start();
837 }
838
TaskFinished(Task * task)839 void ExtensionPlatformKeysService::TaskFinished(Task* task) {
840 DCHECK(!tasks_.empty());
841 DCHECK(task == tasks_.front().get());
842 // Remove all finished tasks from the queue (should be at most one).
843 while (!tasks_.empty() && tasks_.front()->IsDone())
844 tasks_.pop();
845
846 // Now either the queue is empty or the next task is not finished yet and it
847 // can be started.
848 if (!tasks_.empty())
849 tasks_.front()->Start();
850 }
851
852 } // namespace chromeos
853