Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / chromeos / platform_keys / platform_keys_service.cc
blob4b81281ec957f333536c95ed225b7ea3ff0c5a9f
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h"
7 #include "base/bind.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;
18 namespace chromeos {
20 namespace {
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.";
26 } // namespace
28 class PlatformKeysService::Task {
29 public:
30 Task() {}
31 virtual ~Task() {}
32 virtual void Start() = 0;
33 virtual bool IsDone() = 0;
35 private:
36 DISALLOW_ASSIGN(Task);
39 class PlatformKeysService::GenerateRSAKeyTask : public Task {
40 public:
41 enum class Step {
42 GENERATE_KEY,
43 GET_EXTENSION_PERMISSIONS,
44 UPDATE_PERMISSIONS_AND_CALLBACK,
45 DONE,
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),
61 callback_(callback),
62 key_permissions_(key_permissions),
63 service_(service),
64 browser_context_(browser_context),
65 weak_factory_(this) {}
67 ~GenerateRSAKeyTask() override {}
69 void Start() override {
70 CHECK(next_step_ == Step::GENERATE_KEY);
71 DoStep();
74 bool IsDone() override { return next_step_ == Step::DONE; }
76 private:
77 void DoStep() {
78 switch (next_step_) {
79 case Step::GENERATE_KEY:
80 next_step_ = Step::GET_EXTENSION_PERMISSIONS;
81 GenerateKey();
82 return;
83 case Step::GET_EXTENSION_PERMISSIONS:
84 next_step_ = Step::UPDATE_PERMISSIONS_AND_CALLBACK;
85 GetExtensionPermissions();
86 return;
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 */);
92 DoStep();
93 return;
94 case Step::DONE:
95 service_->TaskFinished(this);
96 // |this| might be invalid now.
97 return;
101 // Generates the RSA key.
102 void GenerateKey() {
103 platform_keys::subtle::GenerateRSAKey(
104 token_id_, modulus_length_,
105 base::Bind(&GenerateRSAKeyTask::GeneratedKey,
106 weak_factory_.GetWeakPtr()),
107 browser_context_);
110 // Stores the generated key or in case of an error calls |callback_| with the
111 // error message.
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);
117 DoStep();
118 return;
120 public_key_spki_der_ = public_key_spki_der;
121 DoStep();
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();
134 DoStep();
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 {
154 public:
155 enum class Step {
156 GET_EXTENSION_PERMISSIONS,
157 SIGN_OR_ABORT,
158 DONE,
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),
178 data_(data),
179 public_key_(public_key),
180 sign_direct_pkcs_padded_(sign_direct_pkcs_padded),
181 hash_algorithm_(hash_algorithm),
182 extension_id_(extension_id),
183 callback_(callback),
184 key_permissions_(key_permissions),
185 service_(service),
186 weak_factory_(this) {}
188 ~SignTask() override {}
190 void Start() override {
191 CHECK(next_step_ == Step::GET_EXTENSION_PERMISSIONS);
192 DoStep();
195 bool IsDone() override { return next_step_ == Step::DONE; }
197 private:
198 void DoStep() {
199 switch (next_step_) {
200 case Step::GET_EXTENSION_PERMISSIONS:
201 next_step_ = Step::SIGN_OR_ABORT;
202 GetExtensionPermissions();
203 return;
204 case Step::SIGN_OR_ABORT: {
205 next_step_ = Step::DONE;
206 bool sign_granted =
207 extension_permissions_->CanUseKeyForSigning(public_key_);
208 if (sign_granted) {
209 Sign();
210 } else {
211 callback_.Run(std::string() /* no signature */,
212 kErrorKeyNotAllowedForSigning);
213 DoStep();
215 return;
217 case Step::DONE:
218 service_->TaskFinished(this);
219 // |this| might be invalid now.
220 return;
224 void GetExtensionPermissions() {
225 key_permissions_->GetPermissionsForExtension(
226 extension_id_,
227 base::Bind(&SignTask::GotPermissions, base::Unretained(this)));
230 void GotPermissions(scoped_ptr<KeyPermissions::PermissionsForExtension>
231 extension_permissions) {
232 extension_permissions_ = extension_permissions.Pass();
233 DoStep();
236 // Updates the permissions for |public_key_|, starts the actual signing
237 // operation and afterwards passes the signature (or error) to |callback_|.
238 void Sign() {
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_);
246 } else {
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);
256 DoStep();
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 {
281 public:
282 enum class Step {
283 GET_EXTENSION_PERMISSIONS,
284 GET_MATCHING_CERTS,
285 SELECT_CERTS,
286 UPDATE_PERMISSION,
287 FILTER_BY_PERMISSIONS,
288 DONE,
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,
298 bool interactive,
299 const std::string& extension_id,
300 const SelectCertificatesCallback& callback,
301 content::WebContents* web_contents,
302 KeyPermissions* key_permissions,
303 PlatformKeysService* service)
304 : request_(request),
305 interactive_(interactive),
306 extension_id_(extension_id),
307 callback_(callback),
308 web_contents_(web_contents),
309 key_permissions_(key_permissions),
310 service_(service),
311 weak_factory_(this) {}
312 ~SelectTask() override {}
314 void Start() override {
315 CHECK(next_step_ == Step::GET_EXTENSION_PERMISSIONS);
316 DoStep();
319 bool IsDone() override { return next_step_ == Step::DONE; }
321 private:
322 void DoStep() {
323 switch (next_step_) {
324 case Step::GET_EXTENSION_PERMISSIONS:
325 next_step_ = Step::GET_MATCHING_CERTS;
326 GetExtensionPermissions();
327 return;
328 case Step::GET_MATCHING_CERTS:
329 if (interactive_)
330 next_step_ = Step::SELECT_CERTS;
331 else // Skip SelectCerts and UpdatePermission if not interactive.
332 next_step_ = Step::FILTER_BY_PERMISSIONS;
333 GetMatchingCerts();
334 return;
335 case Step::SELECT_CERTS:
336 next_step_ = Step::UPDATE_PERMISSION;
337 SelectCerts();
338 return;
339 case Step::UPDATE_PERMISSION:
340 next_step_ = Step::FILTER_BY_PERMISSIONS;
341 UpdatePermission();
342 return;
343 case Step::FILTER_BY_PERMISSIONS:
344 next_step_ = Step::DONE;
345 FilterSelectionByPermission();
346 return;
347 case Step::DONE:
348 service_->TaskFinished(this);
349 // |this| might be invalid now.
350 return;
354 void GetExtensionPermissions() {
355 key_permissions_->GetPermissionsForExtension(
356 extension_id_,
357 base::Bind(&SelectTask::GotPermissions, base::Unretained(this)));
360 void GotPermissions(scoped_ptr<KeyPermissions::PermissionsForExtension>
361 extension_permissions) {
362 extension_permissions_ = extension_permissions.Pass();
363 DoStep();
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);
384 DoStep();
385 return;
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)) {
395 continue;
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
400 // request.
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()) {
413 continue;
417 matches_.push_back(certificate.Pass());
419 DoStep();
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()|.
425 void SelectCerts() {
426 CHECK(interactive_);
427 if (matches_.empty()) {
428 // Don't show a select dialog if no certificate is matching.
429 DoStep();
430 return;
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
439 // was selected.
440 void GotSelection(const scoped_refptr<net::X509Certificate>& selected_cert) {
441 selected_cert_ = selected_cert;
442 DoStep();
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() {
448 CHECK(interactive_);
449 if (!selected_cert_) {
450 DoStep();
451 return;
453 const std::string public_key_spki_der(
454 platform_keys::GetSubjectPublicKeyInfo(selected_cert_));
455 extension_permissions_->SetUserGrantedPermission(public_key_spki_der);
456 DoStep();
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);
464 if (interactive_) {
465 if (selected_cert_)
466 selection->push_back(selected_cert_);
467 } else {
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))
477 continue;
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 */);
487 DoStep();
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,
521 profile_prefs,
522 profile_policies,
523 state_store),
524 weak_factory_(this) {
525 DCHECK(browser_context);
526 DCHECK(state_store);
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,
574 bool interactive,
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())
595 tasks_.pop();
597 // Now either the queue is empty or the next task is not finished yet and it
598 // can be started.
599 if (!tasks_.empty())
600 tasks_.front()->Start();
603 } // namespace chromeos