blob: ce279a0d26ae0fbe5043bfe5cc2eac24bec7d718 [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"
[email protected]3065a1f2014-01-22 08:56:3515#include "chrome/browser/net/nss_context.h"
[email protected]99e5e9522013-12-16 13:05:2716#include "chrome/browser/ui/crypto_module_password_dialog_nss.h"
Matt Mueller381b1772017-08-18 06:22:5817#include "chrome/common/net/x509_certificate_model_nss.h"
[email protected]af39f002014-08-22 10:18:1818#include "chrome/grit/generated_resources.h"
[email protected]3065a1f2014-01-22 08:56:3519#include "content/public/browser/browser_context.h"
20#include "content/public/browser/browser_thread.h"
21#include "content/public/browser/resource_context.h"
22#include "crypto/nss_util.h"
[email protected]06dc3202010-10-06 21:18:0723#include "net/base/net_errors.h"
[email protected]6e7845ae2013-03-29 21:48:1124#include "net/cert/x509_certificate.h"
Matt Mueller917b4e12017-09-01 19:15:3525#include "net/cert/x509_util_nss.h"
[email protected]1d77c3e2011-06-08 16:34:4726#include "ui/base/l10n/l10n_util.h"
[email protected]1d77c3e2011-06-08 16:34:4727
wychene120c2fd2017-05-10 07:37:0728// TODO(wychen): ChromeOS headers should only be included when building
29// ChromeOS, and the following headers should be guarded by
30// #if defined(OS_CHROMEOS). However, the types are actually
31// used, and it takes another CL to clean them up.
32// Reference: crbug.com/720159
33#include "chrome/browser/chromeos/certificate_provider/certificate_provider.h"
34#include "chrome/browser/chromeos/certificate_provider/certificate_provider_service.h"
35#include "chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.h"
36
[email protected]3065a1f2014-01-22 08:56:3537using content::BrowserThread;
38
39// CertificateManagerModel is created on the UI thread. It needs a
40// NSSCertDatabase handle (and on ChromeOS it needs to get the TPM status) which
41// needs to be done on the IO thread.
42//
43// The initialization flow is roughly:
44//
45// UI thread IO Thread
46//
47// CertificateManagerModel::Create
48// \--------------------------------------v
49// CertificateManagerModel::GetCertDBOnIOThread
50// |
51// GetNSSCertDatabaseForResourceContext
52// |
53// CertificateManagerModel::DidGetCertDBOnIOThread
54// |
55// crypto::IsTPMTokenEnabledForNSS
56// v--------------------------------------/
57// CertificateManagerModel::DidGetCertDBOnUIThread
58// |
59// new CertificateManagerModel
60// |
61// callback
62
isandrk20c70a22016-09-22 21:41:1063namespace {
64
Matt Mueller917b4e12017-09-01 19:15:3565std::string GetCertificateOrg(CERTCertificate* cert) {
66 std::string org =
67 x509_certificate_model::GetSubjectOrgName(cert, std::string());
68 if (org.empty())
69 org = x509_certificate_model::GetSubjectDisplayName(cert);
isandrk20c70a22016-09-22 21:41:1070
Matt Mueller917b4e12017-09-01 19:15:3571 return org;
isandrk20c70a22016-09-22 21:41:1072}
73
74} // namespace
75
[email protected]3065a1f2014-01-22 08:56:3576// static
77void CertificateManagerModel::Create(
78 content::BrowserContext* browser_context,
79 CertificateManagerModel::Observer* observer,
80 const CreationCallback& callback) {
thestig00844cea2015-09-08 21:44:5281 DCHECK_CURRENTLY_ON(BrowserThread::UI);
isandrk20c70a22016-09-22 21:41:1082
83 std::unique_ptr<chromeos::CertificateProvider> extension_certificate_provider;
84#if defined(OS_CHROMEOS)
85 chromeos::CertificateProviderService* service =
86 chromeos::CertificateProviderServiceFactory::GetForBrowserContext(
87 browser_context);
88 extension_certificate_provider = service->CreateCertificateProvider();
89#endif
90
[email protected]3065a1f2014-01-22 08:56:3591 BrowserThread::PostTask(
tzik29ea5c72017-04-20 02:16:5192 BrowserThread::IO, FROM_HERE,
93 base::BindOnce(&CertificateManagerModel::GetCertDBOnIOThread,
94 browser_context->GetResourceContext(), observer,
tzik6d3cd7562018-02-21 12:07:2295 std::move(extension_certificate_provider), callback));
[email protected]3065a1f2014-01-22 08:56:3596}
97
98CertificateManagerModel::CertificateManagerModel(
99 net::NSSCertDatabase* nss_cert_database,
[email protected]16dad0962014-03-18 01:29:11100 bool is_user_db_available,
[email protected]3065a1f2014-01-22 08:56:35101 bool is_tpm_available,
isandrk20c70a22016-09-22 21:41:10102 Observer* observer,
103 std::unique_ptr<chromeos::CertificateProvider>
104 extension_certificate_provider)
[email protected]3065a1f2014-01-22 08:56:35105 : cert_db_(nss_cert_database),
[email protected]16dad0962014-03-18 01:29:11106 is_user_db_available_(is_user_db_available),
[email protected]3065a1f2014-01-22 08:56:35107 is_tpm_available_(is_tpm_available),
isandrk20c70a22016-09-22 21:41:10108 observer_(observer),
109 extension_certificate_provider_(std::move(
110 extension_certificate_provider)),
111 weak_ptr_factory_(this) {
thestig00844cea2015-09-08 21:44:52112 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]0fd776c42010-09-29 21:59:17113}
114
115CertificateManagerModel::~CertificateManagerModel() {
116}
117
118void CertificateManagerModel::Refresh() {
[email protected]3f1719b2013-11-14 00:34:54119 DVLOG(1) << "refresh started";
tfarinaa55b26892017-02-28 11:47:30120 std::vector<crypto::ScopedPK11Slot> modules;
[email protected]7fda9a402012-09-10 14:11:07121 cert_db_->ListModules(&modules, false);
[email protected]3f1719b2013-11-14 00:34:54122 DVLOG(1) << "refresh waiting for unlocking...";
[email protected]6246ac52012-09-24 01:55:29123 chrome::UnlockSlotsIfNecessary(
cm.sanchi61124032017-12-02 00:17:22124 std::move(modules), kCryptoModulePasswordListCerts,
[email protected]791879c2013-12-17 07:22:41125 net::HostPortPair(), // unused.
tfarinaa55b26892017-02-28 11:47:30126 NULL, // TODO(mattm): supply parent window.
[email protected]289838c2011-09-29 22:12:27127 base::Bind(&CertificateManagerModel::RefreshSlotsUnlocked,
128 base::Unretained(this)));
isandrk20c70a22016-09-22 21:41:10129
130#if defined(OS_CHROMEOS)
131 extension_certificate_provider_->GetCertificates(base::Bind(
132 &CertificateManagerModel::RefreshExtensionCertificates,
133 weak_ptr_factory_.GetWeakPtr()));
134#endif
[email protected]4c4f7cd2011-03-05 02:20:44135}
136
137void CertificateManagerModel::RefreshSlotsUnlocked() {
[email protected]3f1719b2013-11-14 00:34:54138 DVLOG(1) << "refresh listing certs...";
[email protected]9e818932014-02-06 10:24:11139 // TODO(tbarzic): Use async |ListCerts|.
Matt Mueller917b4e12017-09-01 19:15:35140 cert_list_ = cert_db_->ListCertsSync();
[email protected]06dc3202010-10-06 21:18:07141 observer_->CertificatesRefreshed();
isandrk20c70a22016-09-22 21:41:10142 DVLOG(1) << "refresh finished for platform provided certificates";
143}
144
145void CertificateManagerModel::RefreshExtensionCertificates(
mattmbbf7fc02017-06-19 23:38:19146 net::ClientCertIdentityList new_cert_identities) {
147 extension_cert_list_.clear();
148 extension_cert_list_.reserve(new_cert_identities.size());
Matt Mueller917b4e12017-09-01 19:15:35149 for (const auto& identity : new_cert_identities) {
150 net::ScopedCERTCertificate nss_cert(
151 net::x509_util::CreateCERTCertificateFromX509Certificate(
152 identity->certificate()));
153 if (nss_cert)
154 extension_cert_list_.push_back(std::move(nss_cert));
155 }
isandrk20c70a22016-09-22 21:41:10156 observer_->CertificatesRefreshed();
157 DVLOG(1) << "refresh finished for extension provided certificates";
[email protected]0fd776c42010-09-29 21:59:17158}
159
160void CertificateManagerModel::FilterAndBuildOrgGroupingMap(
161 net::CertType filter_type,
162 CertificateManagerModel::OrgGroupingMap* map) const {
Matt Mueller917b4e12017-09-01 19:15:35163 for (const net::ScopedCERTCertificate& cert : cert_list_) {
164 net::CertType type = x509_certificate_model::GetType(cert.get());
[email protected]0fd776c42010-09-29 21:59:17165 if (type != filter_type)
166 continue;
167
Matt Mueller917b4e12017-09-01 19:15:35168 std::string org = GetCertificateOrg(cert.get());
169 (*map)[org].push_back(net::x509_util::DupCERTCertificate(cert.get()));
[email protected]0fd776c42010-09-29 21:59:17170 }
isandrk20c70a22016-09-22 21:41:10171
172 // Display extension provided certificates under the "Your Certificates" tab.
173 if (filter_type == net::USER_CERT) {
174 for (const auto& cert : extension_cert_list_) {
175 std::string org = GetCertificateOrg(cert.get());
Matt Mueller917b4e12017-09-01 19:15:35176 (*map)[org].push_back(net::x509_util::DupCERTCertificate(cert.get()));
isandrk20c70a22016-09-22 21:41:10177 }
178 }
[email protected]0fd776c42010-09-29 21:59:17179}
180
Matt Mueller917b4e12017-09-01 19:15:35181base::string16 CertificateManagerModel::GetColumnText(CERTCertificate* cert,
182 Column column) const {
[email protected]96920152013-12-04 21:00:16183 base::string16 rv;
[email protected]0fd776c42010-09-29 21:59:17184 switch (column) {
185 case COL_SUBJECT_NAME:
[email protected]cc2a2a22013-12-24 23:12:15186 rv = base::UTF8ToUTF16(
Matt Mueller917b4e12017-09-01 19:15:35187 x509_certificate_model::GetCertNameOrNickname(cert));
[email protected]1d77c3e2011-06-08 16:34:47188
isandrk20c70a22016-09-22 21:41:10189 // Mark extension provided certificates.
Matt Mueller917b4e12017-09-01 19:15:35190 if (std::find_if(extension_cert_list_.begin(), extension_cert_list_.end(),
191 [cert](const net::ScopedCERTCertificate& element) {
192 return element.get() == cert;
193 }) != extension_cert_list_.end()) {
isandrk20c70a22016-09-22 21:41:10194 rv = l10n_util::GetStringFUTF16(
195 IDS_CERT_MANAGER_EXTENSION_PROVIDED_FORMAT,
196 rv);
Matt Mueller917b4e12017-09-01 19:15:35197 } else if (IsHardwareBacked(cert)) {
isandrk20c70a22016-09-22 21:41:10198 // TODO(xiyuan): Put this into a column when we have js tree-table.
[email protected]1d77c3e2011-06-08 16:34:47199 rv = l10n_util::GetStringFUTF16(
200 IDS_CERT_MANAGER_HARDWARE_BACKED_KEY_FORMAT,
201 rv,
202 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_HARDWARE_BACKED));
203 }
[email protected]0fd776c42010-09-29 21:59:17204 break;
205 case COL_CERTIFICATE_STORE:
Matt Mueller917b4e12017-09-01 19:15:35206 rv = base::UTF8ToUTF16(x509_certificate_model::GetTokenName(cert));
[email protected]0fd776c42010-09-29 21:59:17207 break;
208 case COL_SERIAL_NUMBER:
Matt Mueller917b4e12017-09-01 19:15:35209 rv = base::ASCIIToUTF16(
210 x509_certificate_model::GetSerialNumberHexified(cert, std::string()));
[email protected]0fd776c42010-09-29 21:59:17211 break;
Matt Mueller917b4e12017-09-01 19:15:35212 case COL_EXPIRES_ON: {
Matt Mueller0d0c1422017-09-07 18:08:38213 base::Time not_after;
214 if (net::x509_util::GetValidityTimes(cert, nullptr, &not_after))
Matt Mueller917b4e12017-09-01 19:15:35215 rv = base::TimeFormatShortDateNumeric(not_after);
[email protected]0fd776c42010-09-29 21:59:17216 break;
Matt Mueller917b4e12017-09-01 19:15:35217 }
[email protected]0fd776c42010-09-29 21:59:17218 default:
219 NOTREACHED();
220 }
221 return rv;
222}
[email protected]06dc3202010-10-06 21:18:07223
tfarinaf58077a2017-01-13 11:40:05224int CertificateManagerModel::ImportFromPKCS12(PK11SlotInfo* slot_info,
[email protected]88b9db72011-01-13 01:48:43225 const std::string& data,
[email protected]96920152013-12-04 21:00:16226 const base::string16& password,
[email protected]6a18d072011-06-29 00:25:40227 bool is_extractable) {
Matt Muellerebbb1532017-09-01 01:42:45228 int result = cert_db_->ImportFromPKCS12(slot_info, data, password,
229 is_extractable, nullptr);
[email protected]06dc3202010-10-06 21:18:07230 if (result == net::OK)
231 Refresh();
232 return result;
233}
234
svaldez3e98a712015-11-23 16:21:57235int CertificateManagerModel::ImportUserCert(const std::string& data) {
236 int result = cert_db_->ImportUserCert(data);
237 if (result == net::OK)
238 Refresh();
239 return result;
240}
241
[email protected]2feacc342010-10-12 22:52:52242bool CertificateManagerModel::ImportCACerts(
Matt Mueller917b4e12017-09-01 19:15:35243 const net::ScopedCERTCertificateList& certificates,
[email protected]7fda9a402012-09-10 14:11:07244 net::NSSCertDatabase::TrustBits trust_bits,
245 net::NSSCertDatabase::ImportCertFailureList* not_imported) {
Matt Mueller917b4e12017-09-01 19:15:35246 const size_t num_certs = certificates.size();
[email protected]7fda9a402012-09-10 14:11:07247 bool result = cert_db_->ImportCACerts(certificates, trust_bits, not_imported);
Matt Mueller917b4e12017-09-01 19:15:35248 if (result && not_imported->size() != num_certs)
[email protected]2feacc342010-10-12 22:52:52249 Refresh();
250 return result;
[email protected]72a8d0d72010-10-08 00:36:57251}
252
[email protected]7a3a9652010-10-13 01:21:13253bool CertificateManagerModel::ImportServerCert(
Matt Mueller917b4e12017-09-01 19:15:35254 const net::ScopedCERTCertificateList& certificates,
[email protected]7fda9a402012-09-10 14:11:07255 net::NSSCertDatabase::TrustBits trust_bits,
256 net::NSSCertDatabase::ImportCertFailureList* not_imported) {
Matt Mueller917b4e12017-09-01 19:15:35257 const size_t num_certs = certificates.size();
258 bool result =
259 cert_db_->ImportServerCert(certificates, trust_bits, not_imported);
260 if (result && not_imported->size() != num_certs)
[email protected]7a3a9652010-10-13 01:21:13261 Refresh();
262 return result;
263}
264
[email protected]c79b784d12011-09-20 18:44:54265bool CertificateManagerModel::SetCertTrust(
Matt Mueller917b4e12017-09-01 19:15:35266 CERTCertificate* cert,
[email protected]c79b784d12011-09-20 18:44:54267 net::CertType type,
[email protected]7fda9a402012-09-10 14:11:07268 net::NSSCertDatabase::TrustBits trust_bits) {
269 return cert_db_->SetCertTrust(cert, type, trust_bits);
[email protected]72a8d0d72010-10-08 00:36:57270}
271
Matt Mueller917b4e12017-09-01 19:15:35272bool CertificateManagerModel::Delete(CERTCertificate* cert) {
[email protected]7fda9a402012-09-10 14:11:07273 bool result = cert_db_->DeleteCertAndKey(cert);
[email protected]06dc3202010-10-06 21:18:07274 if (result)
275 Refresh();
276 return result;
277}
[email protected]e0ad0892012-05-22 19:16:59278
Matt Mueller917b4e12017-09-01 19:15:35279bool CertificateManagerModel::IsHardwareBacked(CERTCertificate* cert) const {
[email protected]e764bea2013-11-20 05:07:01280 return cert_db_->IsHardwareBacked(cert);
[email protected]e0ad0892012-05-22 19:16:59281}
[email protected]3065a1f2014-01-22 08:56:35282
283// static
284void CertificateManagerModel::DidGetCertDBOnUIThread(
285 net::NSSCertDatabase* cert_db,
[email protected]16dad0962014-03-18 01:29:11286 bool is_user_db_available,
[email protected]3065a1f2014-01-22 08:56:35287 bool is_tpm_available,
288 CertificateManagerModel::Observer* observer,
isandrk20c70a22016-09-22 21:41:10289 std::unique_ptr<chromeos::CertificateProvider>
290 extension_certificate_provider,
[email protected]3065a1f2014-01-22 08:56:35291 const CreationCallback& callback) {
thestig00844cea2015-09-08 21:44:52292 DCHECK_CURRENTLY_ON(BrowserThread::UI);
[email protected]3065a1f2014-01-22 08:56:35293
dcheng4af48582016-04-19 00:29:35294 std::unique_ptr<CertificateManagerModel> model(new CertificateManagerModel(
isandrk20c70a22016-09-22 21:41:10295 cert_db, is_user_db_available, is_tpm_available, observer,
296 std::move(extension_certificate_provider)));
dchenge73d8520c2015-12-27 01:19:09297 callback.Run(std::move(model));
[email protected]3065a1f2014-01-22 08:56:35298}
299
300// static
301void CertificateManagerModel::DidGetCertDBOnIOThread(
302 CertificateManagerModel::Observer* observer,
isandrk20c70a22016-09-22 21:41:10303 std::unique_ptr<chromeos::CertificateProvider>
304 extension_certificate_provider,
[email protected]3065a1f2014-01-22 08:56:35305 const CreationCallback& callback,
306 net::NSSCertDatabase* cert_db) {
thestig00844cea2015-09-08 21:44:52307 DCHECK_CURRENTLY_ON(BrowserThread::IO);
[email protected]3065a1f2014-01-22 08:56:35308
dcheng5d64b522016-01-20 01:41:02309 bool is_user_db_available = !!cert_db->GetPublicSlot();
[email protected]3065a1f2014-01-22 08:56:35310 bool is_tpm_available = false;
311#if defined(OS_CHROMEOS)
312 is_tpm_available = crypto::IsTPMTokenEnabledForNSS();
313#endif
314 BrowserThread::PostTask(
tzik29ea5c72017-04-20 02:16:51315 BrowserThread::UI, FROM_HERE,
316 base::BindOnce(&CertificateManagerModel::DidGetCertDBOnUIThread, cert_db,
317 is_user_db_available, is_tpm_available, observer,
tzik6d3cd7562018-02-21 12:07:22318 std::move(extension_certificate_provider), callback));
[email protected]3065a1f2014-01-22 08:56:35319}
320
321// static
322void CertificateManagerModel::GetCertDBOnIOThread(
323 content::ResourceContext* context,
324 CertificateManagerModel::Observer* observer,
isandrk20c70a22016-09-22 21:41:10325 std::unique_ptr<chromeos::CertificateProvider>
326 extension_certificate_provider,
[email protected]3065a1f2014-01-22 08:56:35327 const CreationCallback& callback) {
thestig00844cea2015-09-08 21:44:52328 DCHECK_CURRENTLY_ON(BrowserThread::IO);
isandrk20c70a22016-09-22 21:41:10329
330 auto did_get_cert_db_callback = base::Bind(
331 &CertificateManagerModel::DidGetCertDBOnIOThread, observer,
332 base::Passed(&extension_certificate_provider), callback);
333
[email protected]3065a1f2014-01-22 08:56:35334 net::NSSCertDatabase* cert_db = GetNSSCertDatabaseForResourceContext(
isandrk20c70a22016-09-22 21:41:10335 context, did_get_cert_db_callback);
336
337 // The callback is run here instead of the actual function call because of
338 // extension_certificate_provider ownership semantics, ie. ownership can only
339 // be released once. The callback will only be run once (either inside the
340 // function above or here).
[email protected]3065a1f2014-01-22 08:56:35341 if (cert_db)
isandrk20c70a22016-09-22 21:41:10342 did_get_cert_db_callback.Run(cert_db);
[email protected]3065a1f2014-01-22 08:56:35343}