blob: dd86c2353047f781097f6f7919bbae66bbf4a143 [file] [log] [blame]
[email protected]e0ad0892012-05-22 19:16:591// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]0fd776c42010-09-29 21:59:172// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]4f242962011-05-13 22:25:225#include "chrome/browser/certificate_manager_model.h"
[email protected]0fd776c42010-09-29 21:59:176
dchenge73d8520c2015-12-27 01:19:097#include <utility>
8
[email protected]289838c2011-09-29 22:12:279#include "base/bind.h"
[email protected]0fd776c42010-09-29 21:59:1710#include "base/i18n/time_formatting.h"
11#include "base/logging.h"
isandrk20c70a22016-09-22 21:41:1012#include "base/stl_util.h"
[email protected]135cb802013-06-09 16:44:2013#include "base/strings/utf_string_conversions.h"
avie4d7b6f2015-12-26 00:59:1814#include "build/build_config.h"
isandrk20c70a22016-09-22 21:41:1015#include "chrome/browser/chromeos/certificate_provider/certificate_provider.h"
16#include "chrome/browser/chromeos/certificate_provider/certificate_provider_service.h"
17#include "chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.h"
[email protected]3065a1f2014-01-22 08:56:3518#include "chrome/browser/net/nss_context.h"
[email protected]99e5e9522013-12-16 13:05:2719#include "chrome/browser/ui/crypto_module_password_dialog_nss.h"
[email protected]b1c2a5542010-10-08 12:44:4020#include "chrome/common/net/x509_certificate_model.h"
[email protected]af39f002014-08-22 10:18:1821#include "chrome/grit/generated_resources.h"
[email protected]3065a1f2014-01-22 08:56:3522#include "content/public/browser/browser_context.h"
23#include "content/public/browser/browser_thread.h"
24#include "content/public/browser/resource_context.h"
25#include "crypto/nss_util.h"
[email protected]4c4f7cd2011-03-05 02:20:4426#include "net/base/crypto_module.h"
[email protected]06dc3202010-10-06 21:18:0727#include "net/base/net_errors.h"
[email protected]6e7845ae2013-03-29 21:48:1128#include "net/cert/x509_certificate.h"
[email protected]1d77c3e2011-06-08 16:34:4729#include "ui/base/l10n/l10n_util.h"
[email protected]1d77c3e2011-06-08 16:34:4730
[email protected]3065a1f2014-01-22 08:56:3531using content::BrowserThread;
32
33// CertificateManagerModel is created on the UI thread. It needs a
34// NSSCertDatabase handle (and on ChromeOS it needs to get the TPM status) which
35// needs to be done on the IO thread.
36//
37// The initialization flow is roughly:
38//
39// UI thread IO Thread
40//
41// CertificateManagerModel::Create
42// \--------------------------------------v
43// CertificateManagerModel::GetCertDBOnIOThread
44// |
45// GetNSSCertDatabaseForResourceContext
46// |
47// CertificateManagerModel::DidGetCertDBOnIOThread
48// |
49// crypto::IsTPMTokenEnabledForNSS
50// v--------------------------------------/
51// CertificateManagerModel::DidGetCertDBOnUIThread
52// |
53// new CertificateManagerModel
54// |
55// callback
56
isandrk20c70a22016-09-22 21:41:1057namespace {
58
59std::string GetCertificateOrg(net::X509Certificate* cert) {
60 std::string org;
61 if (!cert->subject().organization_names.empty())
62 org = cert->subject().organization_names[0];
63 if (org.empty())
64 org = cert->subject().GetDisplayName();
65
66 return org;
67}
68
69} // namespace
70
[email protected]3065a1f2014-01-22 08:56:3571// static
72void CertificateManagerModel::Create(
73 content::BrowserContext* browser_context,
74 CertificateManagerModel::Observer* observer,
75 const CreationCallback& callback) {
thestig00844cea2015-09-08 21:44:5276 DCHECK_CURRENTLY_ON(BrowserThread::UI);
isandrk20c70a22016-09-22 21:41:1077
78 std::unique_ptr<chromeos::CertificateProvider> extension_certificate_provider;
79#if defined(OS_CHROMEOS)
80 chromeos::CertificateProviderService* service =
81 chromeos::CertificateProviderServiceFactory::GetForBrowserContext(
82 browser_context);
83 extension_certificate_provider = service->CreateCertificateProvider();
84#endif
85
[email protected]3065a1f2014-01-22 08:56:3586 BrowserThread::PostTask(
87 BrowserThread::IO,
88 FROM_HERE,
89 base::Bind(&CertificateManagerModel::GetCertDBOnIOThread,
90 browser_context->GetResourceContext(),
91 observer,
isandrk20c70a22016-09-22 21:41:1092 base::Passed(&extension_certificate_provider),
[email protected]3065a1f2014-01-22 08:56:3593 callback));
94}
95
96CertificateManagerModel::CertificateManagerModel(
97 net::NSSCertDatabase* nss_cert_database,
[email protected]16dad0962014-03-18 01:29:1198 bool is_user_db_available,
[email protected]3065a1f2014-01-22 08:56:3599 bool is_tpm_available,
isandrk20c70a22016-09-22 21:41:10100 Observer* observer,
101 std::unique_ptr<chromeos::CertificateProvider>
102 extension_certificate_provider)
[email protected]3065a1f2014-01-22 08:56:35103 : cert_db_(nss_cert_database),
[email protected]16dad0962014-03-18 01:29:11104 is_user_db_available_(is_user_db_available),
[email protected]3065a1f2014-01-22 08:56:35105 is_tpm_available_(is_tpm_available),
isandrk20c70a22016-09-22 21:41:10106 observer_(observer),
107 extension_certificate_provider_(std::move(
108 extension_certificate_provider)),
109 weak_ptr_factory_(this) {
thestig00844cea2015-09-08 21:44:52110 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]0fd776c42010-09-29 21:59:17111}
112
113CertificateManagerModel::~CertificateManagerModel() {
114}
115
116void CertificateManagerModel::Refresh() {
[email protected]3f1719b2013-11-14 00:34:54117 DVLOG(1) << "refresh started";
[email protected]4c4f7cd2011-03-05 02:20:44118 net::CryptoModuleList modules;
[email protected]7fda9a402012-09-10 14:11:07119 cert_db_->ListModules(&modules, false);
[email protected]3f1719b2013-11-14 00:34:54120 DVLOG(1) << "refresh waiting for unlocking...";
[email protected]6246ac52012-09-24 01:55:29121 chrome::UnlockSlotsIfNecessary(
[email protected]4c4f7cd2011-03-05 02:20:44122 modules,
[email protected]6246ac52012-09-24 01:55:29123 chrome::kCryptoModulePasswordListCerts,
[email protected]791879c2013-12-17 07:22:41124 net::HostPortPair(), // unused.
[email protected]3f1719b2013-11-14 00:34:54125 NULL, // TODO(mattm): supply parent window.
[email protected]289838c2011-09-29 22:12:27126 base::Bind(&CertificateManagerModel::RefreshSlotsUnlocked,
127 base::Unretained(this)));
isandrk20c70a22016-09-22 21:41:10128
129#if defined(OS_CHROMEOS)
130 extension_certificate_provider_->GetCertificates(base::Bind(
131 &CertificateManagerModel::RefreshExtensionCertificates,
132 weak_ptr_factory_.GetWeakPtr()));
133#endif
[email protected]4c4f7cd2011-03-05 02:20:44134}
135
136void CertificateManagerModel::RefreshSlotsUnlocked() {
[email protected]3f1719b2013-11-14 00:34:54137 DVLOG(1) << "refresh listing certs...";
[email protected]9e818932014-02-06 10:24:11138 // TODO(tbarzic): Use async |ListCerts|.
139 cert_db_->ListCertsSync(&cert_list_);
[email protected]06dc3202010-10-06 21:18:07140 observer_->CertificatesRefreshed();
isandrk20c70a22016-09-22 21:41:10141 DVLOG(1) << "refresh finished for platform provided certificates";
142}
143
144void CertificateManagerModel::RefreshExtensionCertificates(
145 const net::CertificateList& new_certs) {
146 extension_cert_list_ = new_certs;
147 observer_->CertificatesRefreshed();
148 DVLOG(1) << "refresh finished for extension provided certificates";
[email protected]0fd776c42010-09-29 21:59:17149}
150
151void CertificateManagerModel::FilterAndBuildOrgGroupingMap(
152 net::CertType filter_type,
153 CertificateManagerModel::OrgGroupingMap* map) const {
154 for (net::CertificateList::const_iterator i = cert_list_.begin();
155 i != cert_list_.end(); ++i) {
156 net::X509Certificate* cert = i->get();
[email protected]b1c2a5542010-10-08 12:44:40157 net::CertType type =
158 x509_certificate_model::GetType(cert->os_cert_handle());
[email protected]0fd776c42010-09-29 21:59:17159 if (type != filter_type)
160 continue;
161
isandrk20c70a22016-09-22 21:41:10162 std::string org = GetCertificateOrg(cert);
[email protected]0fd776c42010-09-29 21:59:17163 (*map)[org].push_back(cert);
164 }
isandrk20c70a22016-09-22 21:41:10165
166 // Display extension provided certificates under the "Your Certificates" tab.
167 if (filter_type == net::USER_CERT) {
168 for (const auto& cert : extension_cert_list_) {
169 std::string org = GetCertificateOrg(cert.get());
170 (*map)[org].push_back(cert);
171 }
172 }
[email protected]0fd776c42010-09-29 21:59:17173}
174
[email protected]96920152013-12-04 21:00:16175base::string16 CertificateManagerModel::GetColumnText(
[email protected]0fd776c42010-09-29 21:59:17176 const net::X509Certificate& cert,
177 Column column) const {
[email protected]96920152013-12-04 21:00:16178 base::string16 rv;
[email protected]0fd776c42010-09-29 21:59:17179 switch (column) {
180 case COL_SUBJECT_NAME:
[email protected]cc2a2a22013-12-24 23:12:15181 rv = base::UTF8ToUTF16(
[email protected]b1c2a5542010-10-08 12:44:40182 x509_certificate_model::GetCertNameOrNickname(cert.os_cert_handle()));
[email protected]1d77c3e2011-06-08 16:34:47183
isandrk20c70a22016-09-22 21:41:10184 // Mark extension provided certificates.
185 if (base::ContainsValue(extension_cert_list_, &cert)) {
186 rv = l10n_util::GetStringFUTF16(
187 IDS_CERT_MANAGER_EXTENSION_PROVIDED_FORMAT,
188 rv);
189 } else if (IsHardwareBacked(&cert)) {
190 // TODO(xiyuan): Put this into a column when we have js tree-table.
[email protected]1d77c3e2011-06-08 16:34:47191 rv = l10n_util::GetStringFUTF16(
192 IDS_CERT_MANAGER_HARDWARE_BACKED_KEY_FORMAT,
193 rv,
194 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_HARDWARE_BACKED));
195 }
[email protected]0fd776c42010-09-29 21:59:17196 break;
197 case COL_CERTIFICATE_STORE:
[email protected]cc2a2a22013-12-24 23:12:15198 rv = base::UTF8ToUTF16(
[email protected]b1c2a5542010-10-08 12:44:40199 x509_certificate_model::GetTokenName(cert.os_cert_handle()));
[email protected]0fd776c42010-09-29 21:59:17200 break;
201 case COL_SERIAL_NUMBER:
[email protected]cc2a2a22013-12-24 23:12:15202 rv = base::ASCIIToUTF16(x509_certificate_model::GetSerialNumberHexified(
[email protected]007b3f82013-04-09 08:46:45203 cert.os_cert_handle(), std::string()));
[email protected]0fd776c42010-09-29 21:59:17204 break;
205 case COL_EXPIRES_ON:
[email protected]1b6dc3e2010-12-22 15:08:08206 if (!cert.valid_expiry().is_null())
207 rv = base::TimeFormatShortDateNumeric(cert.valid_expiry());
[email protected]0fd776c42010-09-29 21:59:17208 break;
[email protected]0fd776c42010-09-29 21:59:17209 default:
210 NOTREACHED();
211 }
212 return rv;
213}
[email protected]06dc3202010-10-06 21:18:07214
[email protected]88b9db72011-01-13 01:48:43215int CertificateManagerModel::ImportFromPKCS12(net::CryptoModule* module,
216 const std::string& data,
[email protected]96920152013-12-04 21:00:16217 const base::string16& password,
[email protected]6a18d072011-06-29 00:25:40218 bool is_extractable) {
[email protected]7fda9a402012-09-10 14:11:07219 int result = cert_db_->ImportFromPKCS12(module, data, password,
220 is_extractable, NULL);
[email protected]06dc3202010-10-06 21:18:07221 if (result == net::OK)
222 Refresh();
223 return result;
224}
225
svaldez3e98a712015-11-23 16:21:57226int CertificateManagerModel::ImportUserCert(const std::string& data) {
227 int result = cert_db_->ImportUserCert(data);
228 if (result == net::OK)
229 Refresh();
230 return result;
231}
232
[email protected]2feacc342010-10-12 22:52:52233bool CertificateManagerModel::ImportCACerts(
234 const net::CertificateList& certificates,
[email protected]7fda9a402012-09-10 14:11:07235 net::NSSCertDatabase::TrustBits trust_bits,
236 net::NSSCertDatabase::ImportCertFailureList* not_imported) {
237 bool result = cert_db_->ImportCACerts(certificates, trust_bits, not_imported);
[email protected]2feacc342010-10-12 22:52:52238 if (result && not_imported->size() != certificates.size())
239 Refresh();
240 return result;
[email protected]72a8d0d72010-10-08 00:36:57241}
242
[email protected]7a3a9652010-10-13 01:21:13243bool CertificateManagerModel::ImportServerCert(
244 const net::CertificateList& certificates,
[email protected]7fda9a402012-09-10 14:11:07245 net::NSSCertDatabase::TrustBits trust_bits,
246 net::NSSCertDatabase::ImportCertFailureList* not_imported) {
247 bool result = cert_db_->ImportServerCert(certificates, trust_bits,
248 not_imported);
[email protected]7a3a9652010-10-13 01:21:13249 if (result && not_imported->size() != certificates.size())
250 Refresh();
251 return result;
252}
253
[email protected]c79b784d12011-09-20 18:44:54254bool CertificateManagerModel::SetCertTrust(
255 const net::X509Certificate* cert,
256 net::CertType type,
[email protected]7fda9a402012-09-10 14:11:07257 net::NSSCertDatabase::TrustBits trust_bits) {
258 return cert_db_->SetCertTrust(cert, type, trust_bits);
[email protected]72a8d0d72010-10-08 00:36:57259}
260
[email protected]06dc3202010-10-06 21:18:07261bool CertificateManagerModel::Delete(net::X509Certificate* cert) {
[email protected]7fda9a402012-09-10 14:11:07262 bool result = cert_db_->DeleteCertAndKey(cert);
[email protected]06dc3202010-10-06 21:18:07263 if (result)
264 Refresh();
265 return result;
266}
[email protected]e0ad0892012-05-22 19:16:59267
268bool CertificateManagerModel::IsHardwareBacked(
269 const net::X509Certificate* cert) const {
[email protected]e764bea2013-11-20 05:07:01270 return cert_db_->IsHardwareBacked(cert);
[email protected]e0ad0892012-05-22 19:16:59271}
[email protected]3065a1f2014-01-22 08:56:35272
273// static
274void CertificateManagerModel::DidGetCertDBOnUIThread(
275 net::NSSCertDatabase* cert_db,
[email protected]16dad0962014-03-18 01:29:11276 bool is_user_db_available,
[email protected]3065a1f2014-01-22 08:56:35277 bool is_tpm_available,
278 CertificateManagerModel::Observer* observer,
isandrk20c70a22016-09-22 21:41:10279 std::unique_ptr<chromeos::CertificateProvider>
280 extension_certificate_provider,
[email protected]3065a1f2014-01-22 08:56:35281 const CreationCallback& callback) {
thestig00844cea2015-09-08 21:44:52282 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]3065a1f2014-01-22 08:56:35283
dcheng4af48582016-04-19 00:29:35284 std::unique_ptr<CertificateManagerModel> model(new CertificateManagerModel(
isandrk20c70a22016-09-22 21:41:10285 cert_db, is_user_db_available, is_tpm_available, observer,
286 std::move(extension_certificate_provider)));
dchenge73d8520c2015-12-27 01:19:09287 callback.Run(std::move(model));
[email protected]3065a1f2014-01-22 08:56:35288}
289
290// static
291void CertificateManagerModel::DidGetCertDBOnIOThread(
292 CertificateManagerModel::Observer* observer,
isandrk20c70a22016-09-22 21:41:10293 std::unique_ptr<chromeos::CertificateProvider>
294 extension_certificate_provider,
[email protected]3065a1f2014-01-22 08:56:35295 const CreationCallback& callback,
296 net::NSSCertDatabase* cert_db) {
thestig00844cea2015-09-08 21:44:52297 DCHECK_CURRENTLY_ON(BrowserThread::IO);
[email protected]3065a1f2014-01-22 08:56:35298
dcheng5d64b522016-01-20 01:41:02299 bool is_user_db_available = !!cert_db->GetPublicSlot();
[email protected]3065a1f2014-01-22 08:56:35300 bool is_tpm_available = false;
301#if defined(OS_CHROMEOS)
302 is_tpm_available = crypto::IsTPMTokenEnabledForNSS();
303#endif
304 BrowserThread::PostTask(
305 BrowserThread::UI,
306 FROM_HERE,
307 base::Bind(&CertificateManagerModel::DidGetCertDBOnUIThread,
308 cert_db,
[email protected]16dad0962014-03-18 01:29:11309 is_user_db_available,
[email protected]3065a1f2014-01-22 08:56:35310 is_tpm_available,
311 observer,
isandrk20c70a22016-09-22 21:41:10312 base::Passed(&extension_certificate_provider),
[email protected]3065a1f2014-01-22 08:56:35313 callback));
314}
315
316// static
317void CertificateManagerModel::GetCertDBOnIOThread(
318 content::ResourceContext* context,
319 CertificateManagerModel::Observer* observer,
isandrk20c70a22016-09-22 21:41:10320 std::unique_ptr<chromeos::CertificateProvider>
321 extension_certificate_provider,
[email protected]3065a1f2014-01-22 08:56:35322 const CreationCallback& callback) {
thestig00844cea2015-09-08 21:44:52323 DCHECK_CURRENTLY_ON(BrowserThread::IO);
isandrk20c70a22016-09-22 21:41:10324
325 auto did_get_cert_db_callback = base::Bind(
326 &CertificateManagerModel::DidGetCertDBOnIOThread, observer,
327 base::Passed(&extension_certificate_provider), callback);
328
[email protected]3065a1f2014-01-22 08:56:35329 net::NSSCertDatabase* cert_db = GetNSSCertDatabaseForResourceContext(
isandrk20c70a22016-09-22 21:41:10330 context, did_get_cert_db_callback);
331
332 // The callback is run here instead of the actual function call because of
333 // extension_certificate_provider ownership semantics, ie. ownership can only
334 // be released once. The callback will only be run once (either inside the
335 // function above or here).
[email protected]3065a1f2014-01-22 08:56:35336 if (cert_db)
isandrk20c70a22016-09-22 21:41:10337 did_get_cert_db_callback.Run(cert_db);
[email protected]3065a1f2014-01-22 08:56:35338}