Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / chrome / browser / chromeos / platform_keys / platform_keys_service.cc
blobce4e92478b28af9cc68837bdbdc00ad6e337184d
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 INTERSECT_WITH_INPUT_CERTS,
286 SELECT_CERTS,
287 UPDATE_PERMISSION,
288 FILTER_BY_PERMISSIONS,
289 DONE,
292 // This task determines all known client certs matching |request| and that are
293 // elements of |input_client_certificates|, if given. If |interactive| is
294 // true, calls |service->select_delegate_->Select()| to select a cert from all
295 // matches. The extension with |extension_id| will be granted unlimited sign
296 // permission for the selected cert. Finally, either the selection or, if
297 // |interactive| is false, matching certs that the extension has permission
298 // for are passed to |callback|.
299 SelectTask(const platform_keys::ClientCertificateRequest& request,
300 scoped_ptr<net::CertificateList> input_client_certificates,
301 bool interactive,
302 const std::string& extension_id,
303 const SelectCertificatesCallback& callback,
304 content::WebContents* web_contents,
305 KeyPermissions* key_permissions,
306 PlatformKeysService* service)
307 : request_(request),
308 input_client_certificates_(input_client_certificates.Pass()),
309 interactive_(interactive),
310 extension_id_(extension_id),
311 callback_(callback),
312 web_contents_(web_contents),
313 key_permissions_(key_permissions),
314 service_(service),
315 weak_factory_(this) {}
316 ~SelectTask() override {}
318 void Start() override {
319 CHECK(next_step_ == Step::GET_EXTENSION_PERMISSIONS);
320 DoStep();
323 bool IsDone() override { return next_step_ == Step::DONE; }
325 private:
326 void DoStep() {
327 switch (next_step_) {
328 case Step::GET_EXTENSION_PERMISSIONS:
329 next_step_ = Step::GET_MATCHING_CERTS;
330 GetExtensionPermissions();
331 return;
332 case Step::GET_MATCHING_CERTS:
333 next_step_ = Step::INTERSECT_WITH_INPUT_CERTS;
334 GetMatchingCerts();
335 return;
336 case Step::INTERSECT_WITH_INPUT_CERTS:
337 if (interactive_)
338 next_step_ = Step::SELECT_CERTS;
339 else // Skip SelectCerts and UpdatePermission if not interactive.
340 next_step_ = Step::FILTER_BY_PERMISSIONS;
341 IntersectWithInputCerts();
342 return;
343 case Step::SELECT_CERTS:
344 next_step_ = Step::UPDATE_PERMISSION;
345 SelectCerts();
346 return;
347 case Step::UPDATE_PERMISSION:
348 next_step_ = Step::FILTER_BY_PERMISSIONS;
349 UpdatePermission();
350 return;
351 case Step::FILTER_BY_PERMISSIONS:
352 next_step_ = Step::DONE;
353 FilterSelectionByPermission();
354 return;
355 case Step::DONE:
356 service_->TaskFinished(this);
357 // |this| might be invalid now.
358 return;
362 void GetExtensionPermissions() {
363 key_permissions_->GetPermissionsForExtension(
364 extension_id_,
365 base::Bind(&SelectTask::GotPermissions, base::Unretained(this)));
368 void GotPermissions(scoped_ptr<KeyPermissions::PermissionsForExtension>
369 extension_permissions) {
370 extension_permissions_ = extension_permissions.Pass();
371 DoStep();
374 // Retrieves all certificates matching |request_|. Will call back to
375 // |GotMatchingCerts()|.
376 void GetMatchingCerts() {
377 platform_keys::subtle::SelectClientCertificates(
378 request_.certificate_authorities,
379 base::Bind(&SelectTask::GotMatchingCerts, weak_factory_.GetWeakPtr()),
380 service_->browser_context_);
383 // If the certificate request could be processed successfully, |matches| will
384 // contain the list of matching certificates (maybe empty) and |error_message|
385 // will be empty. If an error occurred, |matches| will be null and
386 // |error_message| contain an error message.
387 // Note that the order of |matches|, based on the expiration/issuance date, is
388 // relevant and must be preserved in any processing of the list.
389 void GotMatchingCerts(scoped_ptr<net::CertificateList> matches,
390 const std::string& error_message) {
391 if (!error_message.empty()) {
392 next_step_ = Step::DONE;
393 callback_.Run(nullptr /* no certificates */, error_message);
394 DoStep();
395 return;
398 for (scoped_refptr<net::X509Certificate>& certificate : *matches) {
399 const std::string public_key_spki_der(
400 platform_keys::GetSubjectPublicKeyInfo(certificate));
401 // Skip this key if the user cannot grant any permission for it, except if
402 // this extension can already use it for signing.
403 if (!key_permissions_->CanUserGrantPermissionFor(public_key_spki_der) &&
404 !extension_permissions_->CanUseKeyForSigning(public_key_spki_der)) {
405 continue;
408 // Filter the retrieved certificates returning only those whose type is
409 // equal to one of the entries in the type field of the certificate
410 // request.
411 // If the type field does not contain any entries, certificates of all
412 // types shall be returned.
413 if (!request_.certificate_key_types.empty()) {
414 net::X509Certificate::PublicKeyType actual_key_type =
415 net::X509Certificate::kPublicKeyTypeUnknown;
416 size_t unused_key_size = 0;
417 net::X509Certificate::GetPublicKeyInfo(
418 certificate->os_cert_handle(), &unused_key_size, &actual_key_type);
419 const std::vector<net::X509Certificate::PublicKeyType>& accepted_types =
420 request_.certificate_key_types;
421 if (std::find(accepted_types.begin(), accepted_types.end(),
422 actual_key_type) == accepted_types.end()) {
423 continue;
427 matches_.push_back(certificate.Pass());
429 DoStep();
432 // If |input_client_certificates_| is given, removes from |matches_| all
433 // certificates that are not elements of |input_client_certificates_|.
434 void IntersectWithInputCerts() {
435 if (!input_client_certificates_) {
436 DoStep();
437 return;
439 platform_keys::IntersectCertificates(
440 matches_, *input_client_certificates_,
441 base::Bind(&SelectTask::GotIntersection, weak_factory_.GetWeakPtr()));
444 void GotIntersection(scoped_ptr<net::CertificateList> intersection) {
445 matches_.swap(*intersection);
446 DoStep();
449 // Calls |service_->select_delegate_->Select()| to select a cert from
450 // |matches_|, which will be stored in |selected_cert_|.
451 // Will call back to |GotSelection()|.
452 void SelectCerts() {
453 CHECK(interactive_);
454 if (matches_.empty()) {
455 // Don't show a select dialog if no certificate is matching.
456 DoStep();
457 return;
459 service_->select_delegate_->Select(
460 extension_id_, matches_,
461 base::Bind(&SelectTask::GotSelection, base::Unretained(this)),
462 web_contents_, service_->browser_context_);
465 // Will be called by |SelectCerts()| with the selected cert or null if no cert
466 // was selected.
467 void GotSelection(const scoped_refptr<net::X509Certificate>& selected_cert) {
468 selected_cert_ = selected_cert;
469 DoStep();
472 // Updates the extension's state store about unlimited sign permission for the
473 // selected cert. Does nothing if no cert was selected.
474 void UpdatePermission() {
475 CHECK(interactive_);
476 if (!selected_cert_) {
477 DoStep();
478 return;
480 const std::string public_key_spki_der(
481 platform_keys::GetSubjectPublicKeyInfo(selected_cert_));
482 extension_permissions_->SetUserGrantedPermission(public_key_spki_der);
483 DoStep();
486 // Filters from all matches (if not interactive) or from the selection (if
487 // interactive), the certificates that the extension has unlimited sign
488 // permission for. Passes the filtered certs to |callback_|.
489 void FilterSelectionByPermission() {
490 scoped_ptr<net::CertificateList> selection(new net::CertificateList);
491 if (interactive_) {
492 if (selected_cert_)
493 selection->push_back(selected_cert_);
494 } else {
495 selection->assign(matches_.begin(), matches_.end());
498 scoped_ptr<net::CertificateList> filtered_certs(new net::CertificateList);
499 for (scoped_refptr<net::X509Certificate> selected_cert : *selection) {
500 const std::string public_key_spki_der(
501 platform_keys::GetSubjectPublicKeyInfo(selected_cert));
503 if (!extension_permissions_->CanUseKeyForSigning(public_key_spki_der))
504 continue;
506 filtered_certs->push_back(selected_cert);
508 // Note: In the interactive case this should have filtered exactly the
509 // one selected cert. Checking the permissions again is not striclty
510 // necessary but this ensures that the permissions were updated correctly.
511 CHECK(!selected_cert_ || (filtered_certs->size() == 1 &&
512 filtered_certs->front() == selected_cert_));
513 callback_.Run(filtered_certs.Pass(), std::string() /* no error */);
514 DoStep();
517 Step next_step_ = Step::GET_EXTENSION_PERMISSIONS;
519 net::CertificateList matches_;
520 scoped_refptr<net::X509Certificate> selected_cert_;
521 platform_keys::ClientCertificateRequest request_;
522 scoped_ptr<net::CertificateList> input_client_certificates_;
523 const bool interactive_;
524 const std::string extension_id_;
525 const SelectCertificatesCallback callback_;
526 content::WebContents* const web_contents_;
527 scoped_ptr<KeyPermissions::PermissionsForExtension> extension_permissions_;
528 KeyPermissions* const key_permissions_;
529 PlatformKeysService* const service_;
530 base::WeakPtrFactory<SelectTask> weak_factory_;
532 DISALLOW_COPY_AND_ASSIGN(SelectTask);
535 PlatformKeysService::SelectDelegate::SelectDelegate() {
538 PlatformKeysService::SelectDelegate::~SelectDelegate() {
541 PlatformKeysService::PlatformKeysService(
542 bool profile_is_managed,
543 PrefService* profile_prefs,
544 policy::PolicyService* profile_policies,
545 content::BrowserContext* browser_context,
546 extensions::StateStore* state_store)
547 : browser_context_(browser_context),
548 key_permissions_(profile_is_managed,
549 profile_prefs,
550 profile_policies,
551 state_store),
552 weak_factory_(this) {
553 DCHECK(browser_context);
554 DCHECK(state_store);
557 PlatformKeysService::~PlatformKeysService() {
560 void PlatformKeysService::SetSelectDelegate(
561 scoped_ptr<SelectDelegate> delegate) {
562 select_delegate_ = delegate.Pass();
565 void PlatformKeysService::GenerateRSAKey(const std::string& token_id,
566 unsigned int modulus_length,
567 const std::string& extension_id,
568 const GenerateKeyCallback& callback) {
569 DCHECK_CURRENTLY_ON(BrowserThread::UI);
570 StartOrQueueTask(make_scoped_ptr(
571 new GenerateRSAKeyTask(token_id, modulus_length, extension_id, callback,
572 &key_permissions_, this, browser_context_)));
575 void PlatformKeysService::SignRSAPKCS1Digest(
576 const std::string& token_id,
577 const std::string& data,
578 const std::string& public_key,
579 platform_keys::HashAlgorithm hash_algorithm,
580 const std::string& extension_id,
581 const SignCallback& callback) {
582 DCHECK_CURRENTLY_ON(BrowserThread::UI);
583 StartOrQueueTask(make_scoped_ptr(new SignTask(
584 token_id, data, public_key, false /* digest before signing */,
585 hash_algorithm, extension_id, callback, &key_permissions_, this)));
588 void PlatformKeysService::SignRSAPKCS1Raw(const std::string& token_id,
589 const std::string& data,
590 const std::string& public_key,
591 const std::string& extension_id,
592 const SignCallback& callback) {
593 DCHECK_CURRENTLY_ON(BrowserThread::UI);
594 StartOrQueueTask(make_scoped_ptr(new SignTask(
595 token_id, data, public_key, true /* sign directly without hashing */,
596 platform_keys::HASH_ALGORITHM_NONE, extension_id, callback,
597 &key_permissions_, this)));
600 void PlatformKeysService::SelectClientCertificates(
601 const platform_keys::ClientCertificateRequest& request,
602 scoped_ptr<net::CertificateList> client_certificates,
603 bool interactive,
604 const std::string& extension_id,
605 const SelectCertificatesCallback& callback,
606 content::WebContents* web_contents) {
607 DCHECK_CURRENTLY_ON(BrowserThread::UI);
608 StartOrQueueTask(make_scoped_ptr(new SelectTask(
609 request, client_certificates.Pass(), interactive, extension_id, callback,
610 web_contents, &key_permissions_, this)));
613 void PlatformKeysService::StartOrQueueTask(scoped_ptr<Task> task) {
614 tasks_.push(make_linked_ptr(task.release()));
615 if (tasks_.size() == 1)
616 tasks_.front()->Start();
619 void PlatformKeysService::TaskFinished(Task* task) {
620 DCHECK(!tasks_.empty());
621 DCHECK(task == tasks_.front().get());
622 // Remove all finished tasks from the queue (should be at most one).
623 while (!tasks_.empty() && tasks_.front()->IsDone())
624 tasks_.pop();
626 // Now either the queue is empty or the next task is not finished yet and it
627 // can be started.
628 if (!tasks_.empty())
629 tasks_.front()->Start();
632 } // namespace chromeos