certificate_manager_model.cc 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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
  3. // found in the LICENSE file.
  4. #include "shell/browser/certificate_manager_model.h"
  5. #include <utility>
  6. #include "base/bind.h"
  7. #include "base/logging.h"
  8. #include "base/strings/utf_string_conversions.h"
  9. #include "base/task/post_task.h"
  10. #include "content/public/browser/browser_context.h"
  11. #include "content/public/browser/browser_task_traits.h"
  12. #include "content/public/browser/browser_thread.h"
  13. #include "content/public/browser/resource_context.h"
  14. #include "crypto/nss_util.h"
  15. #include "crypto/nss_util_internal.h"
  16. #include "net/base/net_errors.h"
  17. #include "net/cert/nss_cert_database.h"
  18. #include "net/cert/x509_certificate.h"
  19. using content::BrowserThread;
  20. namespace {
  21. net::NSSCertDatabase* g_nss_cert_database = nullptr;
  22. net::NSSCertDatabase* GetNSSCertDatabaseForResourceContext(
  23. content::ResourceContext* context,
  24. base::OnceCallback<void(net::NSSCertDatabase*)> callback) {
  25. // This initialization is not thread safe. This CHECK ensures that this code
  26. // is only run on a single thread.
  27. CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
  28. if (!g_nss_cert_database) {
  29. // Linux has only a single persistent slot compared to ChromeOS's separate
  30. // public and private slot.
  31. // Redirect any slot usage to this persistent slot on Linux.
  32. crypto::EnsureNSSInit();
  33. g_nss_cert_database = new net::NSSCertDatabase(
  34. crypto::ScopedPK11Slot(PK11_GetInternalKeySlot()) /* public slot */,
  35. crypto::ScopedPK11Slot(PK11_GetInternalKeySlot()) /* private slot */);
  36. }
  37. return g_nss_cert_database;
  38. }
  39. } // namespace
  40. // CertificateManagerModel is created on the UI thread. It needs a
  41. // NSSCertDatabase handle (and on ChromeOS it needs to get the TPM status) which
  42. // needs to be done on the IO thread.
  43. //
  44. // The initialization flow is roughly:
  45. //
  46. // UI thread IO Thread
  47. //
  48. // CertificateManagerModel::Create
  49. // \--------------------------------------v
  50. // CertificateManagerModel::GetCertDBOnIOThread
  51. // |
  52. // GetNSSCertDatabaseForResourceContext
  53. // |
  54. // CertificateManagerModel::DidGetCertDBOnIOThread
  55. // v--------------------------------------/
  56. // CertificateManagerModel::DidGetCertDBOnUIThread
  57. // |
  58. // new CertificateManagerModel
  59. // |
  60. // callback
  61. // static
  62. void CertificateManagerModel::Create(content::BrowserContext* browser_context,
  63. CreationCallback callback) {
  64. DCHECK_CURRENTLY_ON(BrowserThread::UI);
  65. base::PostTask(FROM_HERE, {BrowserThread::IO},
  66. base::BindOnce(&CertificateManagerModel::GetCertDBOnIOThread,
  67. browser_context->GetResourceContext(),
  68. std::move(callback)));
  69. }
  70. CertificateManagerModel::CertificateManagerModel(
  71. net::NSSCertDatabase* nss_cert_database,
  72. bool is_user_db_available)
  73. : cert_db_(nss_cert_database), is_user_db_available_(is_user_db_available) {
  74. DCHECK_CURRENTLY_ON(BrowserThread::UI);
  75. }
  76. CertificateManagerModel::~CertificateManagerModel() = default;
  77. int CertificateManagerModel::ImportFromPKCS12(
  78. PK11SlotInfo* slot_info,
  79. const std::string& data,
  80. const std::u16string& password,
  81. bool is_extractable,
  82. net::ScopedCERTCertificateList* imported_certs) {
  83. return cert_db_->ImportFromPKCS12(slot_info, data, password, is_extractable,
  84. imported_certs);
  85. }
  86. int CertificateManagerModel::ImportUserCert(const std::string& data) {
  87. return cert_db_->ImportUserCert(data);
  88. }
  89. bool CertificateManagerModel::ImportCACerts(
  90. const net::ScopedCERTCertificateList& certificates,
  91. net::NSSCertDatabase::TrustBits trust_bits,
  92. net::NSSCertDatabase::ImportCertFailureList* not_imported) {
  93. return cert_db_->ImportCACerts(certificates, trust_bits, not_imported);
  94. }
  95. bool CertificateManagerModel::ImportServerCert(
  96. const net::ScopedCERTCertificateList& certificates,
  97. net::NSSCertDatabase::TrustBits trust_bits,
  98. net::NSSCertDatabase::ImportCertFailureList* not_imported) {
  99. return cert_db_->ImportServerCert(certificates, trust_bits, not_imported);
  100. }
  101. bool CertificateManagerModel::SetCertTrust(
  102. CERTCertificate* cert,
  103. net::CertType type,
  104. net::NSSCertDatabase::TrustBits trust_bits) {
  105. return cert_db_->SetCertTrust(cert, type, trust_bits);
  106. }
  107. bool CertificateManagerModel::Delete(CERTCertificate* cert) {
  108. return cert_db_->DeleteCertAndKey(cert);
  109. }
  110. // static
  111. void CertificateManagerModel::DidGetCertDBOnUIThread(
  112. net::NSSCertDatabase* cert_db,
  113. bool is_user_db_available,
  114. CreationCallback callback) {
  115. DCHECK_CURRENTLY_ON(BrowserThread::UI);
  116. auto model = base::WrapUnique(
  117. new CertificateManagerModel(cert_db, is_user_db_available));
  118. std::move(callback).Run(std::move(model));
  119. }
  120. // static
  121. void CertificateManagerModel::DidGetCertDBOnIOThread(
  122. CreationCallback callback,
  123. net::NSSCertDatabase* cert_db) {
  124. DCHECK_CURRENTLY_ON(BrowserThread::IO);
  125. bool is_user_db_available = !!cert_db->GetPublicSlot();
  126. base::PostTask(
  127. FROM_HERE, {BrowserThread::UI},
  128. base::BindOnce(&CertificateManagerModel::DidGetCertDBOnUIThread, cert_db,
  129. is_user_db_available, std::move(callback)));
  130. }
  131. // static
  132. void CertificateManagerModel::GetCertDBOnIOThread(
  133. content::ResourceContext* context,
  134. CreationCallback callback) {
  135. DCHECK_CURRENTLY_ON(BrowserThread::IO);
  136. auto split_callback = base::SplitOnceCallback(base::BindOnce(
  137. &CertificateManagerModel::DidGetCertDBOnIOThread, std::move(callback)));
  138. net::NSSCertDatabase* cert_db = GetNSSCertDatabaseForResourceContext(
  139. context, std::move(split_callback.first));
  140. // If the NSS database was already available, |cert_db| is non-null and
  141. // |did_get_cert_db_callback| has not been called. Call it explicitly.
  142. if (cert_db)
  143. std::move(split_callback.second).Run(cert_db);
  144. }