Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/cros/cert_library.h" | 5 #include "chrome/browser/chromeos/cros/cert_library.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/memory/weak_ptr.h" | 10 #include "base/memory/weak_ptr.h" |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 88 issued_to, | 88 issued_to, |
| 89 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_HARDWARE_BACKED)); | 89 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_HARDWARE_BACKED)); |
| 90 } else { | 90 } else { |
| 91 return l10n_util::GetStringFUTF16( | 91 return l10n_util::GetStringFUTF16( |
| 92 IDS_CERT_MANAGER_KEY_FORMAT_LONG, | 92 IDS_CERT_MANAGER_KEY_FORMAT_LONG, |
| 93 issued_by, | 93 issued_by, |
| 94 issued_to); | 94 issued_to); |
| 95 } | 95 } |
| 96 } | 96 } |
| 97 | 97 |
| 98 class RealTPMTokenInfoDelegate : public crypto::TPMTokenInfoDelegate { | |
| 99 public: | |
| 100 RealTPMTokenInfoDelegate(); | |
| 101 virtual ~RealTPMTokenInfoDelegate(); | |
| 102 | |
| 103 // TPMTokenInfoDeleagte overrides: | |
| 104 virtual void RequestIsTokenReady( | |
| 105 base::Callback<void(bool result)> callback) const OVERRIDE; | |
| 106 virtual void GetTokenInfo(std::string* token_name, | |
| 107 std::string* user_pin) const OVERRIDE; | |
| 108 | |
| 109 private: | |
| 110 // This method is used to implement RequestIsTokenReady. | |
| 111 void OnPkcs11IsTpmTokenReady(base::Callback<void(bool result)> callback, | |
| 112 DBusMethodCallStatus call_status, | |
| 113 bool is_tpm_token_ready) const; | |
| 114 | |
| 115 // This method is used to implement RequestIsTokenReady. | |
| 116 void OnPkcs11GetTpmTokenInfo(base::Callback<void(bool result)> callback, | |
| 117 DBusMethodCallStatus call_status, | |
| 118 const std::string& token_name, | |
| 119 const std::string& user_pin) const; | |
| 120 | |
| 121 // These are mutable since we need to cache them in IsTokenReady(). | |
| 122 mutable bool token_ready_; | |
| 123 mutable std::string token_name_; | |
| 124 mutable std::string user_pin_; | |
| 125 mutable base::WeakPtrFactory<RealTPMTokenInfoDelegate> weak_ptr_factory_; | |
| 126 }; | |
| 127 | |
| 128 RealTPMTokenInfoDelegate::RealTPMTokenInfoDelegate() : token_ready_(false), | |
| 129 weak_ptr_factory_(this) { | |
| 130 } | |
| 131 | |
| 132 RealTPMTokenInfoDelegate::~RealTPMTokenInfoDelegate() {} | |
| 133 | |
| 134 void RealTPMTokenInfoDelegate::RequestIsTokenReady( | |
| 135 base::Callback<void(bool result)> callback) const { | |
| 136 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 137 if (token_ready_) { | |
| 138 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 139 base::Bind(callback, true)); | |
| 140 return; | |
| 141 } | |
| 142 DBusThreadManager::Get()->GetCryptohomeClient()->Pkcs11IsTpmTokenReady( | |
| 143 base::Bind(&RealTPMTokenInfoDelegate::OnPkcs11IsTpmTokenReady, | |
| 144 weak_ptr_factory_.GetWeakPtr(), | |
| 145 callback)); | |
| 146 } | |
| 147 | |
| 148 void RealTPMTokenInfoDelegate::GetTokenInfo(std::string* token_name, | |
| 149 std::string* user_pin) const { | |
| 150 // May be called from a non UI thread, but must only be called after | |
| 151 // IsTokenReady() returns true. | |
| 152 CHECK(token_ready_); | |
| 153 if (token_name) | |
| 154 *token_name = token_name_; | |
| 155 if (user_pin) | |
| 156 *user_pin = user_pin_; | |
| 157 } | |
| 158 | |
| 159 void RealTPMTokenInfoDelegate::OnPkcs11IsTpmTokenReady( | |
| 160 base::Callback<void(bool result)> callback, | |
| 161 DBusMethodCallStatus call_status, | |
| 162 bool is_tpm_token_ready) const { | |
| 163 if (call_status != DBUS_METHOD_CALL_SUCCESS || !is_tpm_token_ready) { | |
| 164 callback.Run(false); | |
| 165 return; | |
| 166 } | |
| 167 | |
| 168 // Retrieve token_name_ and user_pin_ here since they will never change | |
| 169 // and CryptohomeClient calls are not thread safe. | |
| 170 DBusThreadManager::Get()->GetCryptohomeClient()->Pkcs11GetTpmTokenInfo( | |
| 171 base::Bind(&RealTPMTokenInfoDelegate::OnPkcs11GetTpmTokenInfo, | |
| 172 weak_ptr_factory_.GetWeakPtr(), | |
| 173 callback)); | |
| 174 } | |
| 175 | |
| 176 void RealTPMTokenInfoDelegate::OnPkcs11GetTpmTokenInfo( | |
| 177 base::Callback<void(bool result)> callback, | |
| 178 DBusMethodCallStatus call_status, | |
| 179 const std::string& token_name, | |
| 180 const std::string& user_pin) const { | |
| 181 if (call_status == DBUS_METHOD_CALL_SUCCESS) { | |
| 182 token_name_ = token_name; | |
| 183 user_pin_ = user_pin; | |
| 184 token_ready_ = true; | |
| 185 } | |
| 186 callback.Run(token_ready_); | |
| 187 } | |
| 188 | |
| 189 } // namespace | 98 } // namespace |
| 190 | 99 |
| 191 ////////////////////////////////////////////////////////////////////////////// | 100 ////////////////////////////////////////////////////////////////////////////// |
| 192 | 101 |
| 193 // base::Unretained(this) in the class is safe. By the time this object is | 102 // base::Unretained(this) in the class is safe. By the time this object is |
| 194 // deleted as part of CrosLibrary, the DB thread and the UI message loop | 103 // deleted as part of CrosLibrary, the DB thread and the UI message loop |
| 195 // are already terminated. | 104 // are already terminated. |
| 196 class CertLibraryImpl | 105 class CertLibraryImpl |
| 197 : public CertLibrary, | 106 : public CertLibrary, |
| 198 public net::CertDatabase::Observer { | 107 public net::CertDatabase::Observer { |
| 199 public: | 108 public: |
| 200 typedef ObserverListThreadSafe<CertLibrary::Observer> CertLibraryObserverList; | 109 typedef ObserverListThreadSafe<CertLibrary::Observer> CertLibraryObserverList; |
| 201 | 110 |
| 202 CertLibraryImpl() : | 111 CertLibraryImpl() : |
| 203 observer_list_(new CertLibraryObserverList), | 112 observer_list_(new CertLibraryObserverList), |
| 113 tpm_token_ready_(false), | |
| 204 user_logged_in_(false), | 114 user_logged_in_(false), |
| 205 certificates_requested_(false), | 115 certificates_requested_(false), |
| 206 certificates_loaded_(false), | 116 certificates_loaded_(false), |
| 207 key_store_loaded_(false), | 117 key_store_loaded_(false), |
| 208 ALLOW_THIS_IN_INITIALIZER_LIST(certs_(this)), | 118 ALLOW_THIS_IN_INITIALIZER_LIST(certs_(this)), |
| 209 ALLOW_THIS_IN_INITIALIZER_LIST(user_certs_(this)), | 119 ALLOW_THIS_IN_INITIALIZER_LIST(user_certs_(this)), |
| 210 ALLOW_THIS_IN_INITIALIZER_LIST(server_certs_(this)), | 120 ALLOW_THIS_IN_INITIALIZER_LIST(server_certs_(this)), |
| 211 ALLOW_THIS_IN_INITIALIZER_LIST(server_ca_certs_(this)), | 121 ALLOW_THIS_IN_INITIALIZER_LIST(server_ca_certs_(this)), |
| 212 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { | 122 ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) { |
| 213 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) | 123 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 239 | 149 |
| 240 // Only load the Opencryptoki library into NSS if we have this switch. | 150 // Only load the Opencryptoki library into NSS if we have this switch. |
| 241 // TODO(gspencer): Remove this switch once cryptohomed work is finished: | 151 // TODO(gspencer): Remove this switch once cryptohomed work is finished: |
| 242 // http://crosbug.com/12295 and 12304 | 152 // http://crosbug.com/12295 and 12304 |
| 243 // Note: ChromeOS login with or without loginmanager will crash when | 153 // Note: ChromeOS login with or without loginmanager will crash when |
| 244 // the CertLibrary is not there (http://crosbug.com/121456). Before removing | 154 // the CertLibrary is not there (http://crosbug.com/121456). Before removing |
| 245 // make sure that that case still works. | 155 // make sure that that case still works. |
| 246 if (CommandLine::ForCurrentProcess()->HasSwitch( | 156 if (CommandLine::ForCurrentProcess()->HasSwitch( |
| 247 switches::kLoadOpencryptoki) || | 157 switches::kLoadOpencryptoki) || |
| 248 CommandLine::ForCurrentProcess()->HasSwitch(switches::kStubCros)) { | 158 CommandLine::ForCurrentProcess()->HasSwitch(switches::kStubCros)) { |
| 249 crypto::EnableTPMTokenForNSS(new RealTPMTokenInfoDelegate()); | 159 crypto::EnableTPMTokenForNSS(); |
|
Ryan Sleevi
2012/05/16 17:02:16
See comments in crypto/
| |
| 250 // Note: this calls crypto::EnsureTPMTokenReady() | 160 // Note: this calls crypto::EnsureTPMTokenReady() |
| 251 RequestCertificates(); | 161 RequestCertificates(); |
| 252 } | 162 } |
| 253 key_store_loaded_ = true; | 163 key_store_loaded_ = true; |
| 254 } | 164 } |
| 255 | 165 |
| 256 virtual bool CertificatesLoading() const OVERRIDE { | 166 virtual bool CertificatesLoading() const OVERRIDE { |
| 257 return certificates_requested_ && !certificates_loaded_; | 167 return certificates_requested_ && !certificates_loaded_; |
| 258 } | 168 } |
| 259 | 169 |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 380 string16 rhs_name = GetDisplayString(rhs.get(), false); | 290 string16 rhs_name = GetDisplayString(rhs.get(), false); |
| 381 if (collator_ == NULL) | 291 if (collator_ == NULL) |
| 382 return lhs_name < rhs_name; | 292 return lhs_name < rhs_name; |
| 383 return l10n_util::CompareString16WithCollator( | 293 return l10n_util::CompareString16WithCollator( |
| 384 collator_, lhs_name, rhs_name) == UCOL_LESS; | 294 collator_, lhs_name, rhs_name) == UCOL_LESS; |
| 385 } | 295 } |
| 386 private: | 296 private: |
| 387 icu::Collator* collator_; | 297 icu::Collator* collator_; |
| 388 }; | 298 }; |
| 389 | 299 |
| 390 void RequestCertificatesTask() { | |
| 391 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) | |
| 392 << __FUNCTION__ << " should be called on UI thread."; | |
| 393 // Reset the task to the initial state so is_null() returns true. | |
| 394 request_task_ = base::Closure(); | |
| 395 RequestCertificates(); | |
| 396 } | |
| 397 | |
| 398 void NotifyCertificatesLoaded(bool initial_load) { | 300 void NotifyCertificatesLoaded(bool initial_load) { |
| 399 observer_list_->Notify( | 301 observer_list_->Notify( |
| 400 &CertLibrary::Observer::OnCertificatesLoaded, initial_load); | 302 &CertLibrary::Observer::OnCertificatesLoaded, initial_load); |
| 401 } | 303 } |
| 402 | 304 |
| 403 // |cert_list| is allocated in LoadCertificates() and must be deleted here. | 305 // |cert_list| is allocated in LoadCertificates() and must be deleted here. |
| 404 void UpdateCertificates(net::CertificateList* cert_list) { | 306 void UpdateCertificates(net::CertificateList* cert_list) { |
| 405 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) | 307 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) |
| 406 << __FUNCTION__ << " should be called on UI thread."; | 308 << __FUNCTION__ << " should be called on UI thread."; |
| 407 DCHECK(cert_list); | 309 DCHECK(cert_list); |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 499 } | 401 } |
| 500 | 402 |
| 501 if (!user_logged_in_) { | 403 if (!user_logged_in_) { |
| 502 user_logged_in_ = true; | 404 user_logged_in_ = true; |
| 503 certificates_loaded_ = false; | 405 certificates_loaded_ = false; |
| 504 supplemental_user_key_.reset(NULL); | 406 supplemental_user_key_.reset(NULL); |
| 505 } | 407 } |
| 506 | 408 |
| 507 VLOG(1) << "Requesting Certificates."; | 409 VLOG(1) << "Requesting Certificates."; |
| 508 DBusThreadManager::Get()->GetCryptohomeClient()->TpmIsEnabled( | 410 DBusThreadManager::Get()->GetCryptohomeClient()->TpmIsEnabled( |
| 509 base::Bind(&CertLibraryImpl::RequestCertificatesInternal, | 411 base::Bind(&CertLibraryImpl::OnTpmIsEnabled, |
| 510 weak_ptr_factory_.GetWeakPtr())); | 412 weak_ptr_factory_.GetWeakPtr())); |
| 511 } | 413 } |
| 512 | 414 |
| 513 // This method is used to implement RequestCertificates. | 415 // This method is used to implement RequestCertificates. |
| 514 void RequestCertificatesInternal(DBusMethodCallStatus call_status, | 416 void OnTpmIsEnabled(DBusMethodCallStatus call_status, bool tpm_is_enabled) { |
| 515 bool tpm_is_enabled) { | |
| 516 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) | 417 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) |
| 517 << __FUNCTION__ << " should be called on UI thread."; | 418 << __FUNCTION__ << " should be called on UI thread."; |
| 518 if (call_status != DBUS_METHOD_CALL_SUCCESS || !tpm_is_enabled) { | 419 if (call_status != DBUS_METHOD_CALL_SUCCESS || !tpm_is_enabled) { |
| 519 // TPM is not enabled, so proceed with empty tpm token name. | 420 // TPM is not enabled, so proceed with empty tpm token name. |
| 520 VLOG(1) << "TPM not available."; | 421 VLOG(1) << "TPM not available."; |
| 521 BrowserThread::PostTask( | 422 BrowserThread::PostTask( |
| 522 BrowserThread::DB, FROM_HERE, | 423 BrowserThread::DB, FROM_HERE, |
| 523 base::Bind(&CertLibraryImpl::LoadCertificates, | 424 base::Bind(&CertLibraryImpl::LoadCertificates, |
| 524 base::Unretained(this))); | 425 base::Unretained(this))); |
| 525 } else if (crypto::IsTPMTokenReady()) { | 426 } else if (tpm_token_ready_) { |
| 526 // Need TPM token name to filter user certificates. | 427 InitializeTPMToken(); |
| 527 const bool tpm_token_ready = true; | |
| 528 GetTPMTokenName(tpm_token_ready); | |
| 529 } else { | 428 } else { |
| 530 crypto::InitializeTPMToken( | 429 DBusThreadManager::Get()->GetCryptohomeClient()->Pkcs11IsTpmTokenReady( |
| 531 base::Bind(&CertLibraryImpl::GetTPMTokenName, | 430 base::Bind(&CertLibraryImpl::OnPkcs11IsTpmTokenReady, |
| 532 weak_ptr_factory_.GetWeakPtr())); | 431 weak_ptr_factory_.GetWeakPtr())); |
| 533 } | 432 } |
| 534 } | 433 } |
| 535 | 434 |
| 536 // This method is used to implement RequestCertificates. | 435 // This method is used to implement RequestCertificates. |
| 537 void GetTPMTokenName(bool tpm_token_ready) { | 436 void OnPkcs11IsTpmTokenReady(DBusMethodCallStatus call_status, |
| 538 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) | 437 bool is_tpm_token_ready) { |
| 539 << __FUNCTION__ << " should be called on UI thread."; | 438 if (call_status != DBUS_METHOD_CALL_SUCCESS || !is_tpm_token_ready) { |
| 540 if (tpm_token_ready) { | 439 MaybeRetryRequestCertificates(); |
| 541 std::string unused_pin; | |
| 542 crypto::GetTPMTokenInfo(&tpm_token_name_, &unused_pin); | |
| 543 } else { | |
| 544 VLOG(1) << "TPM token not ready."; | |
| 545 if (request_task_.is_null()) { | |
| 546 // Cryptohome does not notify us when the token is ready, so call | |
| 547 // this again after a delay. | |
| 548 request_task_ = base::Bind(&CertLibraryImpl::RequestCertificatesTask, | |
| 549 weak_ptr_factory_.GetWeakPtr()); | |
| 550 BrowserThread::PostDelayedTask( | |
| 551 BrowserThread::UI, FROM_HERE, request_task_, | |
| 552 base::TimeDelta::FromMilliseconds(kRequestDelayMs)); | |
| 553 } | |
| 554 return; | 440 return; |
| 555 } | 441 } |
| 556 | 442 |
| 443 // Retrieve token_name_ and user_pin_ here since they will never change | |
| 444 // and CryptohomeClient calls are not thread safe. | |
| 445 DBusThreadManager::Get()->GetCryptohomeClient()->Pkcs11GetTpmTokenInfo( | |
| 446 base::Bind(&CertLibraryImpl::OnPkcs11GetTpmTokenInfo, | |
| 447 weak_ptr_factory_.GetWeakPtr())); | |
| 448 } | |
| 449 | |
| 450 // This method is used to implement RequestCertificates. | |
| 451 void OnPkcs11GetTpmTokenInfo(DBusMethodCallStatus call_status, | |
| 452 const std::string& token_name, | |
| 453 const std::string& user_pin) { | |
| 454 if (call_status != DBUS_METHOD_CALL_SUCCESS) { | |
| 455 MaybeRetryRequestCertificates(); | |
| 456 return; | |
| 457 } | |
| 458 tpm_token_name_ = token_name; | |
| 459 tpm_user_pin_ = user_pin; | |
| 460 tpm_token_ready_ = true; | |
| 461 | |
| 462 InitializeTPMToken(); | |
| 463 } | |
| 464 | |
| 465 // This method is used to implement RequestCertificates. | |
| 466 void InitializeTPMToken() { | |
| 467 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) | |
| 468 << __FUNCTION__ << " should be called on UI thread."; | |
|
Ryan Sleevi
2012/05/16 17:02:16
nit: These strings will not get optimized out in a
hashimoto
2012/05/17 07:35:07
Agree, CHECK itself is sufficient, removed the str
| |
| 469 if (!crypto::InitializeTPMToken(tpm_token_name_, tpm_user_pin_)) { | |
| 470 MaybeRetryRequestCertificates(); | |
| 471 return; | |
| 472 } | |
| 473 | |
| 557 // tpm_token_name_ is set, load the certificates on the DB thread. | 474 // tpm_token_name_ is set, load the certificates on the DB thread. |
| 558 BrowserThread::PostTask( | 475 BrowserThread::PostTask( |
| 559 BrowserThread::DB, FROM_HERE, | 476 BrowserThread::DB, FROM_HERE, |
| 560 base::Bind(&CertLibraryImpl::LoadCertificates, base::Unretained(this))); | 477 base::Bind(&CertLibraryImpl::LoadCertificates, base::Unretained(this))); |
| 561 } | 478 } |
| 562 | 479 |
| 480 void MaybeRetryRequestCertificates() { | |
| 481 if (!request_task_.is_null()) | |
| 482 return; | |
| 483 // Cryptohome does not notify us when the token is ready, so call | |
| 484 // this again after a delay. | |
| 485 request_task_ = base::Bind(&CertLibraryImpl::RequestCertificatesTask, | |
| 486 weak_ptr_factory_.GetWeakPtr()); | |
| 487 BrowserThread::PostDelayedTask( | |
| 488 BrowserThread::UI, FROM_HERE, request_task_, | |
| 489 base::TimeDelta::FromMilliseconds(kRequestDelayMs)); | |
| 490 } | |
| 491 | |
| 492 void RequestCertificatesTask() { | |
| 493 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)) | |
| 494 << __FUNCTION__ << " should be called on UI thread."; | |
| 495 // Reset the task to the initial state so is_null() returns true. | |
| 496 request_task_ = base::Closure(); | |
| 497 RequestCertificates(); | |
| 498 } | |
| 499 | |
| 563 // Observers. | 500 // Observers. |
| 564 const scoped_refptr<CertLibraryObserverList> observer_list_; | 501 const scoped_refptr<CertLibraryObserverList> observer_list_; |
| 565 | 502 |
| 566 // Active request task for re-requests while waiting for TPM init. | 503 // Active request task for re-requests while waiting for TPM init. |
| 567 base::Closure request_task_; | 504 base::Closure request_task_; |
| 568 | 505 |
| 506 bool tpm_token_ready_; | |
| 507 | |
| 569 // Cached TPM token name. | 508 // Cached TPM token name. |
| 570 std::string tpm_token_name_; | 509 std::string tpm_token_name_; |
| 571 | 510 |
| 511 // Cached TPM user pin. | |
| 512 std::string tpm_user_pin_; | |
| 513 | |
| 572 // Supplemental user key. | 514 // Supplemental user key. |
| 573 scoped_ptr<crypto::SymmetricKey> supplemental_user_key_; | 515 scoped_ptr<crypto::SymmetricKey> supplemental_user_key_; |
| 574 | 516 |
| 575 // Local state. | 517 // Local state. |
| 576 bool user_logged_in_; | 518 bool user_logged_in_; |
| 577 bool certificates_requested_; | 519 bool certificates_requested_; |
| 578 bool certificates_loaded_; | 520 bool certificates_loaded_; |
| 579 // The key store for the current user has been loaded. This flag is needed to | 521 // The key store for the current user has been loaded. This flag is needed to |
| 580 // ensure that the key store will not be loaded twice in the policy recovery | 522 // ensure that the key store will not be loaded twice in the policy recovery |
| 581 // "safe-mode". | 523 // "safe-mode". |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 655 net::X509Certificate* cert = GetCertificateAt(index); | 597 net::X509Certificate* cert = GetCertificateAt(index); |
| 656 net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); | 598 net::X509Certificate::OSCertHandle cert_handle = cert->os_cert_handle(); |
| 657 std::string id = x509_certificate_model::GetPkcs11Id(cert_handle); | 599 std::string id = x509_certificate_model::GetPkcs11Id(cert_handle); |
| 658 if (id == pkcs11_id) | 600 if (id == pkcs11_id) |
| 659 return index; | 601 return index; |
| 660 } | 602 } |
| 661 return -1; // Not found. | 603 return -1; // Not found. |
| 662 } | 604 } |
| 663 | 605 |
| 664 } // chromeos | 606 } // chromeos |
| OLD | NEW |