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.
5 #include "chrome/browser/certificate_manager_model.h"
8 #include "base/i18n/time_formatting.h"
9 #include "base/logging.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/net/nss_context.h"
12 #include "chrome/browser/ui/crypto_module_password_dialog_nss.h"
13 #include "chrome/common/net/x509_certificate_model.h"
14 #include "content/public/browser/browser_context.h"
15 #include "content/public/browser/browser_thread.h"
16 #include "content/public/browser/resource_context.h"
17 #include "crypto/nss_util.h"
18 #include "grit/generated_resources.h"
19 #include "net/base/crypto_module.h"
20 #include "net/base/net_errors.h"
21 #include "net/cert/x509_certificate.h"
22 #include "ui/base/l10n/l10n_util.h"
24 using content::BrowserThread
;
26 // CertificateManagerModel is created on the UI thread. It needs a
27 // NSSCertDatabase handle (and on ChromeOS it needs to get the TPM status) which
28 // needs to be done on the IO thread.
30 // The initialization flow is roughly:
32 // UI thread IO Thread
34 // CertificateManagerModel::Create
35 // \--------------------------------------v
36 // CertificateManagerModel::GetCertDBOnIOThread
38 // GetNSSCertDatabaseForResourceContext
40 // CertificateManagerModel::DidGetCertDBOnIOThread
42 // crypto::IsTPMTokenEnabledForNSS
43 // v--------------------------------------/
44 // CertificateManagerModel::DidGetCertDBOnUIThread
46 // new CertificateManagerModel
51 void CertificateManagerModel::Create(
52 content::BrowserContext
* browser_context
,
53 CertificateManagerModel::Observer
* observer
,
54 const CreationCallback
& callback
) {
55 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
56 BrowserThread::PostTask(
59 base::Bind(&CertificateManagerModel::GetCertDBOnIOThread
,
60 browser_context
->GetResourceContext(),
65 CertificateManagerModel::CertificateManagerModel(
66 net::NSSCertDatabase
* nss_cert_database
,
67 bool is_user_db_available
,
68 bool is_tpm_available
,
70 : cert_db_(nss_cert_database
),
71 is_user_db_available_(is_user_db_available
),
72 is_tpm_available_(is_tpm_available
),
74 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
77 CertificateManagerModel::~CertificateManagerModel() {
80 void CertificateManagerModel::Refresh() {
81 DVLOG(1) << "refresh started";
82 net::CryptoModuleList modules
;
83 cert_db_
->ListModules(&modules
, false);
84 DVLOG(1) << "refresh waiting for unlocking...";
85 chrome::UnlockSlotsIfNecessary(
87 chrome::kCryptoModulePasswordListCerts
,
88 net::HostPortPair(), // unused.
89 NULL
, // TODO(mattm): supply parent window.
90 base::Bind(&CertificateManagerModel::RefreshSlotsUnlocked
,
91 base::Unretained(this)));
94 void CertificateManagerModel::RefreshSlotsUnlocked() {
95 DVLOG(1) << "refresh listing certs...";
96 // TODO(tbarzic): Use async |ListCerts|.
97 cert_db_
->ListCertsSync(&cert_list_
);
98 observer_
->CertificatesRefreshed();
99 DVLOG(1) << "refresh finished";
102 void CertificateManagerModel::FilterAndBuildOrgGroupingMap(
103 net::CertType filter_type
,
104 CertificateManagerModel::OrgGroupingMap
* map
) const {
105 for (net::CertificateList::const_iterator i
= cert_list_
.begin();
106 i
!= cert_list_
.end(); ++i
) {
107 net::X509Certificate
* cert
= i
->get();
109 x509_certificate_model::GetType(cert
->os_cert_handle());
110 if (type
!= filter_type
)
114 if (!cert
->subject().organization_names
.empty())
115 org
= cert
->subject().organization_names
[0];
117 org
= cert
->subject().GetDisplayName();
119 (*map
)[org
].push_back(cert
);
123 base::string16
CertificateManagerModel::GetColumnText(
124 const net::X509Certificate
& cert
,
125 Column column
) const {
128 case COL_SUBJECT_NAME
:
129 rv
= base::UTF8ToUTF16(
130 x509_certificate_model::GetCertNameOrNickname(cert
.os_cert_handle()));
132 // TODO(xiyuan): Put this into a column when we have js tree-table.
133 if (IsHardwareBacked(&cert
)) {
134 rv
= l10n_util::GetStringFUTF16(
135 IDS_CERT_MANAGER_HARDWARE_BACKED_KEY_FORMAT
,
137 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_HARDWARE_BACKED
));
140 case COL_CERTIFICATE_STORE
:
141 rv
= base::UTF8ToUTF16(
142 x509_certificate_model::GetTokenName(cert
.os_cert_handle()));
144 case COL_SERIAL_NUMBER
:
145 rv
= base::ASCIIToUTF16(x509_certificate_model::GetSerialNumberHexified(
146 cert
.os_cert_handle(), std::string()));
149 if (!cert
.valid_expiry().is_null())
150 rv
= base::TimeFormatShortDateNumeric(cert
.valid_expiry());
158 int CertificateManagerModel::ImportFromPKCS12(net::CryptoModule
* module
,
159 const std::string
& data
,
160 const base::string16
& password
,
161 bool is_extractable
) {
162 int result
= cert_db_
->ImportFromPKCS12(module
, data
, password
,
163 is_extractable
, NULL
);
164 if (result
== net::OK
)
169 bool CertificateManagerModel::ImportCACerts(
170 const net::CertificateList
& certificates
,
171 net::NSSCertDatabase::TrustBits trust_bits
,
172 net::NSSCertDatabase::ImportCertFailureList
* not_imported
) {
173 bool result
= cert_db_
->ImportCACerts(certificates
, trust_bits
, not_imported
);
174 if (result
&& not_imported
->size() != certificates
.size())
179 bool CertificateManagerModel::ImportServerCert(
180 const net::CertificateList
& certificates
,
181 net::NSSCertDatabase::TrustBits trust_bits
,
182 net::NSSCertDatabase::ImportCertFailureList
* not_imported
) {
183 bool result
= cert_db_
->ImportServerCert(certificates
, trust_bits
,
185 if (result
&& not_imported
->size() != certificates
.size())
190 bool CertificateManagerModel::SetCertTrust(
191 const net::X509Certificate
* cert
,
193 net::NSSCertDatabase::TrustBits trust_bits
) {
194 return cert_db_
->SetCertTrust(cert
, type
, trust_bits
);
197 bool CertificateManagerModel::Delete(net::X509Certificate
* cert
) {
198 bool result
= cert_db_
->DeleteCertAndKey(cert
);
204 bool CertificateManagerModel::IsHardwareBacked(
205 const net::X509Certificate
* cert
) const {
206 return cert_db_
->IsHardwareBacked(cert
);
210 void CertificateManagerModel::DidGetCertDBOnUIThread(
211 net::NSSCertDatabase
* cert_db
,
212 bool is_user_db_available
,
213 bool is_tpm_available
,
214 CertificateManagerModel::Observer
* observer
,
215 const CreationCallback
& callback
) {
216 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
218 scoped_ptr
<CertificateManagerModel
> model(new CertificateManagerModel(
219 cert_db
, is_user_db_available
, is_tpm_available
, observer
));
220 callback
.Run(model
.Pass());
224 void CertificateManagerModel::DidGetCertDBOnIOThread(
225 CertificateManagerModel::Observer
* observer
,
226 const CreationCallback
& callback
,
227 net::NSSCertDatabase
* cert_db
) {
228 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
230 bool is_user_db_available
= cert_db
->GetPublicSlot();
231 bool is_tpm_available
= false;
232 #if defined(OS_CHROMEOS)
233 is_tpm_available
= crypto::IsTPMTokenEnabledForNSS();
235 BrowserThread::PostTask(
238 base::Bind(&CertificateManagerModel::DidGetCertDBOnUIThread
,
240 is_user_db_available
,
247 void CertificateManagerModel::GetCertDBOnIOThread(
248 content::ResourceContext
* context
,
249 CertificateManagerModel::Observer
* observer
,
250 const CreationCallback
& callback
) {
251 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
252 net::NSSCertDatabase
* cert_db
= GetNSSCertDatabaseForResourceContext(
254 base::Bind(&CertificateManagerModel::DidGetCertDBOnIOThread
,
258 DidGetCertDBOnIOThread(observer
, callback
, cert_db
);