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