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/platform_keys.h"
6
7#include <cryptohi.h>
8
9#include "base/bind.h"
10#include "base/bind_helpers.h"
11#include "base/callback.h"
12#include "base/compiler_specific.h"
13#include "base/location.h"
14#include "base/logging.h"
15#include "base/macros.h"
16#include "base/single_thread_task_runner.h"
17#include "base/thread_task_runner_handle.h"
18#include "base/threading/worker_pool.h"
19#include "chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.h"
20#include "chrome/browser/net/nss_context.h"
21#include "content/public/browser/browser_context.h"
22#include "content/public/browser/browser_thread.h"
23#include "crypto/rsa_private_key.h"
24#include "net/base/crypto_module.h"
25#include "net/base/net_errors.h"
26#include "net/cert/cert_database.h"
27#include "net/cert/nss_cert_database.h"
28#include "net/cert/x509_certificate.h"
29
30using content::BrowserContext;
31using content::BrowserThread;
32
33namespace {
34const char kErrorInternal[] = "Internal Error.";
35const char kErrorKeyNotFound[] = "Key not found.";
36const char kErrorCertificateNotFound[] = "Certificate could not be found.";
37const char kErrorAlgorithmNotSupported[] = "Algorithm not supported.";
38
39// The current maximal RSA modulus length that ChromeOS's TPM supports for key
40// generation.
41const unsigned int kMaxRSAModulusLengthBits = 2048;
42}
43
44namespace chromeos {
45
46namespace platform_keys {
47
48namespace {
49
50// Base class to store state that is common to all NSS database operations and
51// to provide convenience methods to call back.
52// Keeps track of the originating task runner.
53class NSSOperationState {
54 public:
55  NSSOperationState();
56  virtual ~NSSOperationState() {}
57
58  // Called if an error occurred during the execution of the NSS operation
59  // described by this object.
60  virtual void OnError(const tracked_objects::Location& from,
61                       const std::string& error_message) = 0;
62
63  crypto::ScopedPK11Slot slot_;
64
65  // The task runner on which the NSS operation was called. Any reply must be
66  // posted to this runner.
67  scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
68
69 private:
70  DISALLOW_COPY_AND_ASSIGN(NSSOperationState);
71};
72
73typedef base::Callback<void(net::NSSCertDatabase* cert_db)> GetCertDBCallback;
74
75// Used by GetCertDatabaseOnIOThread and called back with the requested
76// NSSCertDatabase.
77// If |token_id| is not empty, sets |slot_| of |state| accordingly and calls
78// |callback| if the database was successfully retrieved.
79void DidGetCertDBOnIOThread(const std::string& token_id,
80                            const GetCertDBCallback& callback,
81                            NSSOperationState* state,
82                            net::NSSCertDatabase* cert_db) {
83  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
84  if (!cert_db) {
85    LOG(ERROR) << "Couldn't get NSSCertDatabase.";
86    state->OnError(FROM_HERE, kErrorInternal);
87    return;
88  }
89
90  if (!token_id.empty()) {
91    if (token_id == kTokenIdUser)
92      state->slot_ = cert_db->GetPrivateSlot();
93    else if (token_id == kTokenIdSystem)
94      state->slot_ = cert_db->GetSystemSlot();
95
96    if (!state->slot_) {
97      LOG(ERROR) << "Slot for token id '" << token_id << "' not available.";
98      state->OnError(FROM_HERE, kErrorInternal);
99      return;
100    }
101  }
102
103  callback.Run(cert_db);
104}
105
106// Retrieves the NSSCertDatabase from |context| and, if |token_id| is not empty,
107// the slot for |token_id|.
108// Must be called on the IO thread.
109void GetCertDatabaseOnIOThread(const std::string& token_id,
110                               const GetCertDBCallback& callback,
111                               content::ResourceContext* context,
112                               NSSOperationState* state) {
113  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
114  net::NSSCertDatabase* cert_db = GetNSSCertDatabaseForResourceContext(
115      context, base::Bind(&DidGetCertDBOnIOThread, token_id, callback, state));
116
117  if (cert_db)
118    DidGetCertDBOnIOThread(token_id, callback, state, cert_db);
119}
120
121// Asynchronously fetches the NSSCertDatabase for |browser_context| and, if
122// |token_id| is not empty, the slot for |token_id|. Stores the slot in |state|
123// and passes the database to |callback|. Will run |callback| on the IO thread.
124void GetCertDatabase(const std::string& token_id,
125                     const GetCertDBCallback& callback,
126                     BrowserContext* browser_context,
127                     NSSOperationState* state) {
128  BrowserThread::PostTask(BrowserThread::IO,
129                          FROM_HERE,
130                          base::Bind(&GetCertDatabaseOnIOThread,
131                                     token_id,
132                                     callback,
133                                     browser_context->GetResourceContext(),
134                                     state));
135}
136
137class GenerateRSAKeyState : public NSSOperationState {
138 public:
139  GenerateRSAKeyState(unsigned int modulus_length_bits,
140                      const subtle::GenerateKeyCallback& callback);
141  virtual ~GenerateRSAKeyState() {}
142
143  virtual void OnError(const tracked_objects::Location& from,
144                       const std::string& error_message) OVERRIDE {
145    CallBack(from, std::string() /* no public key */, error_message);
146  }
147
148  void CallBack(const tracked_objects::Location& from,
149                const std::string& public_key_spki_der,
150                const std::string& error_message) {
151    origin_task_runner_->PostTask(
152        from, base::Bind(callback_, public_key_spki_der, error_message));
153  }
154
155  const unsigned int modulus_length_bits_;
156
157 private:
158  // Must be called on origin thread, therefore use CallBack().
159  subtle::GenerateKeyCallback callback_;
160};
161
162class SignState : public NSSOperationState {
163 public:
164  SignState(const std::string& public_key,
165            HashAlgorithm hash_algorithm,
166            const std::string& data,
167            const subtle::SignCallback& callback);
168  virtual ~SignState() {}
169
170  virtual void OnError(const tracked_objects::Location& from,
171                       const std::string& error_message) OVERRIDE {
172    CallBack(from, std::string() /* no signature */, error_message);
173  }
174
175  void CallBack(const tracked_objects::Location& from,
176                const std::string& signature,
177                const std::string& error_message) {
178    origin_task_runner_->PostTask(
179        from, base::Bind(callback_, signature, error_message));
180  }
181
182  const std::string public_key_;
183  HashAlgorithm hash_algorithm_;
184  const std::string data_;
185
186 private:
187  // Must be called on origin thread, therefore use CallBack().
188  subtle::SignCallback callback_;
189};
190
191class GetCertificatesState : public NSSOperationState {
192 public:
193  explicit GetCertificatesState(const GetCertificatesCallback& callback);
194  virtual ~GetCertificatesState() {}
195
196  virtual void OnError(const tracked_objects::Location& from,
197                       const std::string& error_message) OVERRIDE {
198    CallBack(from,
199             scoped_ptr<net::CertificateList>() /* no certificates */,
200             error_message);
201  }
202
203  void CallBack(const tracked_objects::Location& from,
204                scoped_ptr<net::CertificateList> certs,
205                const std::string& error_message) {
206    origin_task_runner_->PostTask(
207        from, base::Bind(callback_, base::Passed(&certs), error_message));
208  }
209
210  scoped_ptr<net::CertificateList> certs_;
211
212 private:
213  // Must be called on origin thread, therefore use CallBack().
214  GetCertificatesCallback callback_;
215};
216
217class ImportCertificateState : public NSSOperationState {
218 public:
219  ImportCertificateState(scoped_refptr<net::X509Certificate> certificate,
220                         const ImportCertificateCallback& callback);
221  virtual ~ImportCertificateState() {}
222
223  virtual void OnError(const tracked_objects::Location& from,
224                       const std::string& error_message) OVERRIDE {
225    CallBack(from, error_message);
226  }
227
228  void CallBack(const tracked_objects::Location& from,
229                const std::string& error_message) {
230    origin_task_runner_->PostTask(from, base::Bind(callback_, error_message));
231  }
232
233  scoped_refptr<net::X509Certificate> certificate_;
234
235 private:
236  // Must be called on origin thread, therefore use CallBack().
237  ImportCertificateCallback callback_;
238};
239
240class RemoveCertificateState : public NSSOperationState {
241 public:
242  RemoveCertificateState(scoped_refptr<net::X509Certificate> certificate,
243                         const RemoveCertificateCallback& callback);
244  virtual ~RemoveCertificateState() {}
245
246  virtual void OnError(const tracked_objects::Location& from,
247                       const std::string& error_message) OVERRIDE {
248    CallBack(from, error_message);
249  }
250
251  void CallBack(const tracked_objects::Location& from,
252                const std::string& error_message) {
253    origin_task_runner_->PostTask(from, base::Bind(callback_, error_message));
254  }
255
256  scoped_refptr<net::X509Certificate> certificate_;
257
258 private:
259  // Must be called on origin thread, therefore use CallBack().
260  RemoveCertificateCallback callback_;
261};
262
263class GetTokensState : public NSSOperationState {
264 public:
265  explicit GetTokensState(const GetTokensCallback& callback);
266  virtual ~GetTokensState() {}
267
268  virtual void OnError(const tracked_objects::Location& from,
269                       const std::string& error_message) OVERRIDE {
270    CallBack(from,
271             scoped_ptr<std::vector<std::string> >() /* no token ids */,
272             error_message);
273  }
274
275  void CallBack(const tracked_objects::Location& from,
276                scoped_ptr<std::vector<std::string> > token_ids,
277                const std::string& error_message) {
278    origin_task_runner_->PostTask(
279        from, base::Bind(callback_, base::Passed(&token_ids), error_message));
280  }
281
282 private:
283  // Must be called on origin thread, therefore use CallBack().
284  GetTokensCallback callback_;
285};
286
287NSSOperationState::NSSOperationState()
288    : origin_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
289}
290
291GenerateRSAKeyState::GenerateRSAKeyState(
292    unsigned int modulus_length_bits,
293    const subtle::GenerateKeyCallback& callback)
294    : modulus_length_bits_(modulus_length_bits), callback_(callback) {
295}
296
297SignState::SignState(const std::string& public_key,
298                     HashAlgorithm hash_algorithm,
299                     const std::string& data,
300                     const subtle::SignCallback& callback)
301    : public_key_(public_key),
302      hash_algorithm_(hash_algorithm),
303      data_(data),
304      callback_(callback) {
305}
306
307GetCertificatesState::GetCertificatesState(
308    const GetCertificatesCallback& callback)
309    : callback_(callback) {
310}
311
312ImportCertificateState::ImportCertificateState(
313    scoped_refptr<net::X509Certificate> certificate,
314    const ImportCertificateCallback& callback)
315    : certificate_(certificate), callback_(callback) {
316}
317
318RemoveCertificateState::RemoveCertificateState(
319    scoped_refptr<net::X509Certificate> certificate,
320    const RemoveCertificateCallback& callback)
321    : certificate_(certificate), callback_(callback) {
322}
323
324GetTokensState::GetTokensState(const GetTokensCallback& callback)
325    : callback_(callback) {
326}
327
328// Does the actual key generation on a worker thread. Used by
329// GenerateRSAKeyWithDB().
330void GenerateRSAKeyOnWorkerThread(scoped_ptr<GenerateRSAKeyState> state) {
331  scoped_ptr<crypto::RSAPrivateKey> rsa_key(
332      crypto::RSAPrivateKey::CreateSensitive(state->slot_.get(),
333                                             state->modulus_length_bits_));
334  if (!rsa_key) {
335    LOG(ERROR) << "Couldn't create key.";
336    state->OnError(FROM_HERE, kErrorInternal);
337    return;
338  }
339
340  std::vector<uint8> public_key_spki_der;
341  if (!rsa_key->ExportPublicKey(&public_key_spki_der)) {
342    // TODO(pneubeck): Remove rsa_key from storage.
343    LOG(ERROR) << "Couldn't export public key.";
344    state->OnError(FROM_HERE, kErrorInternal);
345    return;
346  }
347  state->CallBack(
348      FROM_HERE,
349      std::string(public_key_spki_der.begin(), public_key_spki_der.end()),
350      std::string() /* no error */);
351}
352
353// Continues generating a RSA key with the obtained NSSCertDatabase. Used by
354// GenerateRSAKey().
355void GenerateRSAKeyWithDB(scoped_ptr<GenerateRSAKeyState> state,
356                          net::NSSCertDatabase* cert_db) {
357  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
358  // Only the slot and not the NSSCertDatabase is required. Ignore |cert_db|.
359  base::WorkerPool::PostTask(
360      FROM_HERE,
361      base::Bind(&GenerateRSAKeyOnWorkerThread, base::Passed(&state)),
362      true /*task is slow*/);
363}
364
365// Does the actual signing on a worker thread. Used by RSASignWithDB().
366void RSASignOnWorkerThread(scoped_ptr<SignState> state) {
367  const uint8* public_key_uint8 =
368      reinterpret_cast<const uint8*>(state->public_key_.data());
369  std::vector<uint8> public_key_vector(
370      public_key_uint8, public_key_uint8 + state->public_key_.size());
371
372  // TODO(pneubeck): This searches all slots. Change to look only at |slot_|.
373  scoped_ptr<crypto::RSAPrivateKey> rsa_key(
374      crypto::RSAPrivateKey::FindFromPublicKeyInfo(public_key_vector));
375  if (!rsa_key || rsa_key->key()->pkcs11Slot != state->slot_) {
376    state->OnError(FROM_HERE, kErrorKeyNotFound);
377    return;
378  }
379
380  SECOidTag sign_alg_tag = SEC_OID_UNKNOWN;
381  switch (state->hash_algorithm_) {
382    case HASH_ALGORITHM_SHA1:
383      sign_alg_tag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
384      break;
385    case HASH_ALGORITHM_SHA256:
386      sign_alg_tag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
387      break;
388    case HASH_ALGORITHM_SHA384:
389      sign_alg_tag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION;
390      break;
391    case HASH_ALGORITHM_SHA512:
392      sign_alg_tag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION;
393      break;
394  }
395
396  SECItem sign_result = {siBuffer, NULL, 0};
397  if (SEC_SignData(&sign_result,
398                   reinterpret_cast<const unsigned char*>(state->data_.data()),
399                   state->data_.size(),
400                   rsa_key->key(),
401                   sign_alg_tag) != SECSuccess) {
402    LOG(ERROR) << "Couldn't sign.";
403    state->OnError(FROM_HERE, kErrorInternal);
404    return;
405  }
406
407  std::string signature(reinterpret_cast<const char*>(sign_result.data),
408                        sign_result.len);
409  state->CallBack(FROM_HERE, signature, std::string() /* no error */);
410}
411
412// Continues signing with the obtained NSSCertDatabase. Used by Sign().
413void RSASignWithDB(scoped_ptr<SignState> state, net::NSSCertDatabase* cert_db) {
414  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
415  // Only the slot and not the NSSCertDatabase is required. Ignore |cert_db|.
416  base::WorkerPool::PostTask(
417      FROM_HERE,
418      base::Bind(&RSASignOnWorkerThread, base::Passed(&state)),
419      true /*task is slow*/);
420}
421
422// Filters the obtained certificates on a worker thread. Used by
423// DidGetCertificates().
424void FilterCertificatesOnWorkerThread(scoped_ptr<GetCertificatesState> state) {
425  scoped_ptr<net::CertificateList> client_certs(new net::CertificateList);
426  for (net::CertificateList::const_iterator it = state->certs_->begin();
427       it != state->certs_->end();
428       ++it) {
429    net::X509Certificate::OSCertHandle cert_handle = (*it)->os_cert_handle();
430    crypto::ScopedPK11Slot cert_slot(PK11_KeyForCertExists(cert_handle,
431                                                           NULL,    // keyPtr
432                                                           NULL));  // wincx
433
434    // Keep only user certificates, i.e. certs for which the private key is
435    // present and stored in the queried slot.
436    if (cert_slot != state->slot_)
437      continue;
438
439    client_certs->push_back(*it);
440  }
441
442  state->CallBack(FROM_HERE, client_certs.Pass(), std::string() /* no error */);
443}
444
445// Passes the obtained certificates to the worker thread for filtering. Used by
446// GetCertificatesWithDB().
447void DidGetCertificates(scoped_ptr<GetCertificatesState> state,
448                        scoped_ptr<net::CertificateList> all_certs) {
449  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
450  state->certs_ = all_certs.Pass();
451  base::WorkerPool::PostTask(
452      FROM_HERE,
453      base::Bind(&FilterCertificatesOnWorkerThread, base::Passed(&state)),
454      true /*task is slow*/);
455}
456
457// Continues getting certificates with the obtained NSSCertDatabase. Used by
458// GetCertificates().
459void GetCertificatesWithDB(scoped_ptr<GetCertificatesState> state,
460                           net::NSSCertDatabase* cert_db) {
461  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
462  // Get the pointer to slot before base::Passed releases |state|.
463  PK11SlotInfo* slot = state->slot_.get();
464  cert_db->ListCertsInSlot(
465      base::Bind(&DidGetCertificates, base::Passed(&state)), slot);
466}
467
468// Does the actual certificate importing on the IO thread. Used by
469// ImportCertificate().
470void ImportCertificateWithDB(scoped_ptr<ImportCertificateState> state,
471                             net::NSSCertDatabase* cert_db) {
472  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
473  // TODO(pneubeck): Use |state->slot_| to verify that we're really importing to
474  // the correct token.
475  // |cert_db| is not required, ignore it.
476  net::CertDatabase* db = net::CertDatabase::GetInstance();
477
478  const net::Error cert_status =
479      static_cast<net::Error>(db->CheckUserCert(state->certificate_.get()));
480  if (cert_status == net::ERR_NO_PRIVATE_KEY_FOR_CERT) {
481    state->OnError(FROM_HERE, kErrorKeyNotFound);
482    return;
483  } else if (cert_status != net::OK) {
484    state->OnError(FROM_HERE, net::ErrorToString(cert_status));
485    return;
486  }
487
488  // Check that the private key is in the correct slot.
489  PK11SlotInfo* slot =
490      PK11_KeyForCertExists(state->certificate_->os_cert_handle(), NULL, NULL);
491  if (slot != state->slot_) {
492    state->OnError(FROM_HERE, kErrorKeyNotFound);
493    return;
494  }
495
496  const net::Error import_status =
497      static_cast<net::Error>(db->AddUserCert(state->certificate_.get()));
498  if (import_status != net::OK) {
499    LOG(ERROR) << "Could not import certificate.";
500    state->OnError(FROM_HERE, net::ErrorToString(import_status));
501    return;
502  }
503
504  state->CallBack(FROM_HERE, std::string() /* no error */);
505}
506
507// Called on IO thread after the certificate removal is finished.
508void DidRemoveCertificate(scoped_ptr<RemoveCertificateState> state,
509                          bool certificate_found,
510                          bool success) {
511  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
512  // CertificateNotFound error has precedence over an internal error.
513  if (!certificate_found) {
514    state->OnError(FROM_HERE, kErrorCertificateNotFound);
515    return;
516  }
517  if (!success) {
518    state->OnError(FROM_HERE, kErrorInternal);
519    return;
520  }
521
522  state->CallBack(FROM_HERE, std::string() /* no error */);
523}
524
525// Does the actual certificate removal on the IO thread. Used by
526// RemoveCertificate().
527void RemoveCertificateWithDB(scoped_ptr<RemoveCertificateState> state,
528                             net::NSSCertDatabase* cert_db) {
529  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
530  // Get the pointer before base::Passed clears |state|.
531  scoped_refptr<net::X509Certificate> certificate = state->certificate_;
532  bool certificate_found = certificate->os_cert_handle()->isperm;
533  cert_db->DeleteCertAndKeyAsync(
534      certificate,
535      base::Bind(
536          &DidRemoveCertificate, base::Passed(&state), certificate_found));
537}
538
539// Does the actual work to determine which tokens are available.
540void GetTokensWithDB(scoped_ptr<GetTokensState> state,
541                     net::NSSCertDatabase* cert_db) {
542  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
543  scoped_ptr<std::vector<std::string> > token_ids(new std::vector<std::string>);
544
545  // The user's token is always available.
546  token_ids->push_back(kTokenIdUser);
547  if (cert_db->GetSystemSlot())
548    token_ids->push_back(kTokenIdSystem);
549
550  state->CallBack(FROM_HERE, token_ids.Pass(), std::string() /* no error */);
551}
552
553}  // namespace
554
555namespace subtle {
556
557void GenerateRSAKey(const std::string& token_id,
558                    unsigned int modulus_length_bits,
559                    const GenerateKeyCallback& callback,
560                    BrowserContext* browser_context) {
561  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
562  scoped_ptr<GenerateRSAKeyState> state(
563      new GenerateRSAKeyState(modulus_length_bits, callback));
564
565  if (modulus_length_bits > kMaxRSAModulusLengthBits) {
566    state->OnError(FROM_HERE, kErrorAlgorithmNotSupported);
567    return;
568  }
569
570  // Get the pointer to |state| before base::Passed releases |state|.
571  NSSOperationState* state_ptr = state.get();
572  GetCertDatabase(token_id,
573                  base::Bind(&GenerateRSAKeyWithDB, base::Passed(&state)),
574                  browser_context,
575                  state_ptr);
576}
577
578void Sign(const std::string& token_id,
579          const std::string& public_key,
580          HashAlgorithm hash_algorithm,
581          const std::string& data,
582          const SignCallback& callback,
583          BrowserContext* browser_context) {
584  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
585  scoped_ptr<SignState> state(
586      new SignState(public_key, hash_algorithm, data, callback));
587  // Get the pointer to |state| before base::Passed releases |state|.
588  NSSOperationState* state_ptr = state.get();
589
590  // The NSSCertDatabase object is not required. But in case it's not available
591  // we would get more informative error messages and we can double check that
592  // we use a key of the correct token.
593  GetCertDatabase(token_id,
594                  base::Bind(&RSASignWithDB, base::Passed(&state)),
595                  browser_context,
596                  state_ptr);
597}
598
599}  // namespace subtle
600
601void GetCertificates(const std::string& token_id,
602                     const GetCertificatesCallback& callback,
603                     BrowserContext* browser_context) {
604  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
605  scoped_ptr<GetCertificatesState> state(new GetCertificatesState(callback));
606  // Get the pointer to |state| before base::Passed releases |state|.
607  NSSOperationState* state_ptr = state.get();
608  GetCertDatabase(token_id,
609                  base::Bind(&GetCertificatesWithDB, base::Passed(&state)),
610                  browser_context,
611                  state_ptr);
612}
613
614void ImportCertificate(const std::string& token_id,
615                       scoped_refptr<net::X509Certificate> certificate,
616                       const ImportCertificateCallback& callback,
617                       BrowserContext* browser_context) {
618  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
619  scoped_ptr<ImportCertificateState> state(
620      new ImportCertificateState(certificate, callback));
621  // Get the pointer to |state| before base::Passed releases |state|.
622  NSSOperationState* state_ptr = state.get();
623
624  // The NSSCertDatabase object is not required. But in case it's not available
625  // we would get more informative error messages and we can double check that
626  // we use a key of the correct token.
627  GetCertDatabase(token_id,
628                  base::Bind(&ImportCertificateWithDB, base::Passed(&state)),
629                  browser_context,
630                  state_ptr);
631}
632
633void RemoveCertificate(const std::string& token_id,
634                       scoped_refptr<net::X509Certificate> certificate,
635                       const RemoveCertificateCallback& callback,
636                       BrowserContext* browser_context) {
637  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
638  scoped_ptr<RemoveCertificateState> state(
639      new RemoveCertificateState(certificate, callback));
640  // Get the pointer to |state| before base::Passed releases |state|.
641  NSSOperationState* state_ptr = state.get();
642
643  // The NSSCertDatabase object is not required. But in case it's not available
644  // we would get more informative error messages.
645  GetCertDatabase(token_id,
646                  base::Bind(&RemoveCertificateWithDB, base::Passed(&state)),
647                  browser_context,
648                  state_ptr);
649}
650
651void GetTokens(const GetTokensCallback& callback,
652               content::BrowserContext* browser_context) {
653  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
654  scoped_ptr<GetTokensState> state(new GetTokensState(callback));
655  // Get the pointer to |state| before base::Passed releases |state|.
656  NSSOperationState* state_ptr = state.get();
657  GetCertDatabase(std::string() /* don't get any specific slot */,
658                  base::Bind(&GetTokensWithDB, base::Passed(&state)),
659                  browser_context,
660                  state_ptr);
661}
662
663}  // namespace platform_keys
664
665}  // namespace chromeos
666