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