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/ui/webui/options/certificate_manager_handler.h"
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/files/file_util.h" // for FileAccessProvider
13 #include "base/i18n/string_compare.h"
14 #include "base/id_map.h"
15 #include "base/memory/scoped_vector.h"
16 #include "base/posix/safe_strerror.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "base/values.h"
20 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/certificate_viewer.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/browser/ui/certificate_dialogs.h"
24 #include "chrome/browser/ui/chrome_select_file_policy.h"
25 #include "chrome/browser/ui/crypto_module_password_dialog_nss.h"
26 #include "chrome/browser/ui/webui/certificate_viewer_webui.h"
27 #include "chrome/grit/generated_resources.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/web_contents.h"
30 #include "net/base/crypto_module.h"
31 #include "net/base/net_errors.h"
32 #include "net/cert/x509_certificate.h"
33 #include "ui/base/l10n/l10n_util.h"
35 #if defined(OS_CHROMEOS)
36 #include "chrome/browser/chromeos/policy/user_network_configuration_updater.h"
37 #include "chrome/browser/chromeos/policy/user_network_configuration_updater_factory.h"
40 using base::UTF8ToUTF16
;
41 using content::BrowserThread
;
45 static const char kKeyId
[] = "id";
46 static const char kSubNodesId
[] = "subnodes";
47 static const char kNameId
[] = "name";
48 static const char kReadOnlyId
[] = "readonly";
49 static const char kUntrustedId
[] = "untrusted";
50 static const char kExtractableId
[] = "extractable";
51 static const char kErrorId
[] = "error";
52 static const char kPolicyTrustedId
[] = "policy";
54 // Enumeration of different callers of SelectFile. (Start counting at 1 so
55 // if SelectFile is accidentally called with params=NULL it won't match any.)
57 EXPORT_PERSONAL_FILE_SELECTED
= 1,
58 IMPORT_PERSONAL_FILE_SELECTED
,
59 IMPORT_SERVER_FILE_SELECTED
,
60 IMPORT_CA_FILE_SELECTED
,
63 std::string
OrgNameToId(const std::string
& org
) {
67 bool CallbackArgsToBool(const base::ListValue
* args
, int index
, bool* result
) {
68 std::string string_value
;
69 if (!args
->GetString(index
, &string_value
))
72 *result
= string_value
[0] == 't';
76 struct DictionaryIdComparator
{
77 explicit DictionaryIdComparator(icu::Collator
* collator
)
78 : collator_(collator
) {
81 bool operator()(const base::Value
* a
,
82 const base::Value
* b
) const {
83 DCHECK(a
->GetType() == base::Value::TYPE_DICTIONARY
);
84 DCHECK(b
->GetType() == base::Value::TYPE_DICTIONARY
);
85 const base::DictionaryValue
* a_dict
=
86 reinterpret_cast<const base::DictionaryValue
*>(a
);
87 const base::DictionaryValue
* b_dict
=
88 reinterpret_cast<const base::DictionaryValue
*>(b
);
91 a_dict
->GetString(kNameId
, &a_str
);
92 b_dict
->GetString(kNameId
, &b_str
);
93 if (collator_
== NULL
)
95 return base::i18n::CompareString16WithCollator(*collator_
, a_str
, b_str
) ==
99 icu::Collator
* collator_
;
102 std::string
NetErrorToString(int net_error
) {
104 // TODO(mattm): handle more cases.
105 case net::ERR_IMPORT_CA_CERT_NOT_CA
:
106 return l10n_util::GetStringUTF8(IDS_CERT_MANAGER_ERROR_NOT_CA
);
107 case net::ERR_IMPORT_CERT_ALREADY_EXISTS
:
108 return l10n_util::GetStringUTF8(
109 IDS_CERT_MANAGER_ERROR_CERT_ALREADY_EXISTS
);
111 return l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR
);
115 // Struct to bind the Equals member function to an object for use in find_if.
117 explicit CertEquals(const net::X509Certificate
* cert
) : cert_(cert
) {}
118 bool operator()(const scoped_refptr
<net::X509Certificate
> cert
) const {
119 return cert_
->Equals(cert
.get());
121 const net::X509Certificate
* cert_
;
124 // Determine whether a certificate was stored with web trust by a policy.
125 bool IsPolicyInstalledWithWebTrust(
126 const net::CertificateList
& web_trust_certs
,
127 net::X509Certificate
* cert
) {
128 return std::find_if(web_trust_certs
.begin(), web_trust_certs
.end(),
129 CertEquals(cert
)) != web_trust_certs
.end();
132 #if defined(OS_CHROMEOS)
133 void ShowCertificateViewerModalDialog(content::WebContents
* web_contents
,
134 gfx::NativeWindow parent
,
135 net::X509Certificate
* cert
) {
136 CertificateViewerModalDialog
* dialog
= new CertificateViewerModalDialog(cert
);
137 dialog
->Show(web_contents
, parent
);
145 ///////////////////////////////////////////////////////////////////////////////
153 std::string
CertToId(net::X509Certificate
* cert
);
154 net::X509Certificate
* IdToCert(const std::string
& id
);
155 net::X509Certificate
* CallbackArgsToCert(const base::ListValue
* args
);
158 typedef std::map
<net::X509Certificate
*, int32
> CertMap
;
160 // Creates an ID for cert and looks up the cert for an ID.
161 IDMap
<net::X509Certificate
>id_map_
;
163 // Finds the ID for a cert.
166 DISALLOW_COPY_AND_ASSIGN(CertIdMap
);
169 std::string
CertIdMap::CertToId(net::X509Certificate
* cert
) {
170 CertMap::const_iterator iter
= cert_map_
.find(cert
);
171 if (iter
!= cert_map_
.end())
172 return base::IntToString(iter
->second
);
174 int32 new_id
= id_map_
.Add(cert
);
175 cert_map_
[cert
] = new_id
;
176 return base::IntToString(new_id
);
179 net::X509Certificate
* CertIdMap::IdToCert(const std::string
& id
) {
181 if (!base::StringToInt(id
, &cert_id
))
184 return id_map_
.Lookup(cert_id
);
187 net::X509Certificate
* CertIdMap::CallbackArgsToCert(
188 const base::ListValue
* args
) {
190 if (!args
->GetString(0, &node_id
))
193 net::X509Certificate
* cert
= IdToCert(node_id
);
202 ///////////////////////////////////////////////////////////////////////////////
203 // FileAccessProvider
205 // TODO(mattm): Move to some shared location?
206 class FileAccessProvider
207 : public base::RefCountedThreadSafe
<FileAccessProvider
> {
209 // The first parameter is 0 on success or errno on failure. The second
210 // parameter is read result.
211 typedef base::Callback
<void(const int*, const std::string
*)> ReadCallback
;
213 // The first parameter is 0 on success or errno on failure. The second
214 // parameter is the number of bytes written on success.
215 typedef base::Callback
<void(const int*, const int*)> WriteCallback
;
217 base::CancelableTaskTracker::TaskId
StartRead(
218 const base::FilePath
& path
,
219 const ReadCallback
& callback
,
220 base::CancelableTaskTracker
* tracker
);
221 base::CancelableTaskTracker::TaskId
StartWrite(
222 const base::FilePath
& path
,
223 const std::string
& data
,
224 const WriteCallback
& callback
,
225 base::CancelableTaskTracker
* tracker
);
228 friend class base::RefCountedThreadSafe
<FileAccessProvider
>;
229 virtual ~FileAccessProvider() {}
231 // Reads file at |path|. |saved_errno| is 0 on success or errno on failure.
232 // When success, |data| has file content.
233 void DoRead(const base::FilePath
& path
,
236 // Writes data to file at |path|. |saved_errno| is 0 on success or errno on
237 // failure. When success, |bytes_written| has number of bytes written.
238 void DoWrite(const base::FilePath
& path
,
239 const std::string
& data
,
244 base::CancelableTaskTracker::TaskId
FileAccessProvider::StartRead(
245 const base::FilePath
& path
,
246 const ReadCallback
& callback
,
247 base::CancelableTaskTracker
* tracker
) {
248 // Owned by reply callback posted below.
249 int* saved_errno
= new int(0);
250 std::string
* data
= new std::string();
252 // Post task to file thread to read file.
253 return tracker
->PostTaskAndReply(
254 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE).get(),
256 base::Bind(&FileAccessProvider::DoRead
, this, path
, saved_errno
, data
),
257 base::Bind(callback
, base::Owned(saved_errno
), base::Owned(data
)));
260 base::CancelableTaskTracker::TaskId
FileAccessProvider::StartWrite(
261 const base::FilePath
& path
,
262 const std::string
& data
,
263 const WriteCallback
& callback
,
264 base::CancelableTaskTracker
* tracker
) {
265 // Owned by reply callback posted below.
266 int* saved_errno
= new int(0);
267 int* bytes_written
= new int(0);
269 // Post task to file thread to write file.
270 return tracker
->PostTaskAndReply(
271 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE).get(),
273 base::Bind(&FileAccessProvider::DoWrite
,
280 callback
, base::Owned(saved_errno
), base::Owned(bytes_written
)));
283 void FileAccessProvider::DoRead(const base::FilePath
& path
,
286 bool success
= base::ReadFileToString(path
, data
);
287 *saved_errno
= success
? 0 : errno
;
290 void FileAccessProvider::DoWrite(const base::FilePath
& path
,
291 const std::string
& data
,
293 int* bytes_written
) {
294 *bytes_written
= base::WriteFile(path
, data
.data(), data
.size());
295 *saved_errno
= *bytes_written
>= 0 ? 0 : errno
;
298 ///////////////////////////////////////////////////////////////////////////////
299 // CertificateManagerHandler
301 CertificateManagerHandler::CertificateManagerHandler(
302 bool show_certs_in_modal_dialog
)
303 : show_certs_in_modal_dialog_(show_certs_in_modal_dialog
),
304 requested_certificate_manager_model_(false),
305 use_hardware_backed_(false),
306 file_access_provider_(new FileAccessProvider()),
307 cert_id_map_(new CertIdMap
),
308 weak_ptr_factory_(this) {}
310 CertificateManagerHandler::~CertificateManagerHandler() {
313 void CertificateManagerHandler::GetLocalizedValues(
314 base::DictionaryValue
* localized_strings
) {
315 DCHECK(localized_strings
);
317 RegisterTitle(localized_strings
, "certificateManagerPage",
318 IDS_CERTIFICATE_MANAGER_TITLE
);
321 localized_strings
->SetString("personalCertsTabTitle",
322 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PERSONAL_CERTS_TAB_LABEL
));
323 localized_strings
->SetString("serverCertsTabTitle",
324 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_SERVER_CERTS_TAB_LABEL
));
325 localized_strings
->SetString("caCertsTabTitle",
326 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_CERT_AUTHORITIES_TAB_LABEL
));
327 localized_strings
->SetString("otherCertsTabTitle",
328 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_OTHER_TAB_LABEL
));
331 localized_strings
->SetString("personalCertsTabDescription",
332 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_USER_TREE_DESCRIPTION
));
333 localized_strings
->SetString("serverCertsTabDescription",
334 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_SERVER_TREE_DESCRIPTION
));
335 localized_strings
->SetString("caCertsTabDescription",
336 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_AUTHORITIES_TREE_DESCRIPTION
));
337 localized_strings
->SetString("otherCertsTabDescription",
338 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_OTHER_TREE_DESCRIPTION
));
341 localized_strings
->SetString("view_certificate",
342 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_VIEW_CERT_BUTTON
));
343 localized_strings
->SetString("import_certificate",
344 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_IMPORT_BUTTON
));
345 localized_strings
->SetString("export_certificate",
346 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_BUTTON
));
347 localized_strings
->SetString("edit_certificate",
348 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_BUTTON
));
349 localized_strings
->SetString("delete_certificate",
350 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_BUTTON
));
352 // Certificate Delete overlay strings.
353 localized_strings
->SetString("personalCertsTabDeleteConfirm",
354 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_USER_FORMAT
));
355 localized_strings
->SetString("personalCertsTabDeleteImpact",
356 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_USER_DESCRIPTION
));
357 localized_strings
->SetString("serverCertsTabDeleteConfirm",
358 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_SERVER_FORMAT
));
359 localized_strings
->SetString("serverCertsTabDeleteImpact",
360 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_SERVER_DESCRIPTION
));
361 localized_strings
->SetString("caCertsTabDeleteConfirm",
362 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_CA_FORMAT
));
363 localized_strings
->SetString("caCertsTabDeleteImpact",
364 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_CA_DESCRIPTION
));
365 localized_strings
->SetString("otherCertsTabDeleteConfirm",
366 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_OTHER_FORMAT
));
367 localized_strings
->SetString("otherCertsTabDeleteImpact", std::string());
369 // Certificate Restore overlay strings.
370 localized_strings
->SetString("certificateRestorePasswordDescription",
371 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_RESTORE_PASSWORD_DESC
));
372 localized_strings
->SetString("certificatePasswordLabel",
373 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PASSWORD_LABEL
));
375 // Personal Certificate Export overlay strings.
376 localized_strings
->SetString("certificateExportPasswordDescription",
377 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_PASSWORD_DESC
));
378 localized_strings
->SetString("certificateExportPasswordHelp",
379 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_PASSWORD_HELP
));
380 localized_strings
->SetString("certificateConfirmPasswordLabel",
381 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_CONFIRM_PASSWORD_LABEL
));
383 // Edit CA Trust & Import CA overlay strings.
384 localized_strings
->SetString("certificateEditCaTitle",
385 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_CA_TITLE
));
386 localized_strings
->SetString("certificateEditTrustLabel",
387 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_TRUST_LABEL
));
388 localized_strings
->SetString("certificateEditCaTrustDescriptionFormat",
389 l10n_util::GetStringUTF16(
390 IDS_CERT_MANAGER_EDIT_CA_TRUST_DESCRIPTION_FORMAT
));
391 localized_strings
->SetString("certificateImportCaDescriptionFormat",
392 l10n_util::GetStringUTF16(
393 IDS_CERT_MANAGER_IMPORT_CA_DESCRIPTION_FORMAT
));
394 localized_strings
->SetString("certificateCaTrustSSLLabel",
395 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_CA_TRUST_SSL_LABEL
));
396 localized_strings
->SetString("certificateCaTrustEmailLabel",
397 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_CA_TRUST_EMAIL_LABEL
));
398 localized_strings
->SetString("certificateCaTrustObjSignLabel",
399 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_CA_TRUST_OBJSIGN_LABEL
));
400 localized_strings
->SetString("certificateImportErrorFormat",
401 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_IMPORT_ERROR_FORMAT
));
403 // Badges next to certificates
404 localized_strings
->SetString("badgeCertUntrusted",
405 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_UNTRUSTED
));
406 localized_strings
->SetString("certPolicyInstalled",
407 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_POLICY_INSTALLED
));
409 #if defined(OS_CHROMEOS)
410 localized_strings
->SetString("importAndBindCertificate",
411 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_IMPORT_AND_BIND_BUTTON
));
412 #endif // defined(OS_CHROMEOS)
415 void CertificateManagerHandler::RegisterMessages() {
416 web_ui()->RegisterMessageCallback(
418 base::Bind(&CertificateManagerHandler::View
, base::Unretained(this)));
420 web_ui()->RegisterMessageCallback(
421 "getCaCertificateTrust",
422 base::Bind(&CertificateManagerHandler::GetCATrust
,
423 base::Unretained(this)));
424 web_ui()->RegisterMessageCallback(
425 "editCaCertificateTrust",
426 base::Bind(&CertificateManagerHandler::EditCATrust
,
427 base::Unretained(this)));
429 web_ui()->RegisterMessageCallback(
430 "editServerCertificate",
431 base::Bind(&CertificateManagerHandler::EditServer
,
432 base::Unretained(this)));
434 web_ui()->RegisterMessageCallback(
435 "cancelImportExportCertificate",
436 base::Bind(&CertificateManagerHandler::CancelImportExportProcess
,
437 base::Unretained(this)));
439 web_ui()->RegisterMessageCallback(
440 "exportPersonalCertificate",
441 base::Bind(&CertificateManagerHandler::ExportPersonal
,
442 base::Unretained(this)));
443 web_ui()->RegisterMessageCallback(
444 "exportAllPersonalCertificates",
445 base::Bind(&CertificateManagerHandler::ExportAllPersonal
,
446 base::Unretained(this)));
447 web_ui()->RegisterMessageCallback(
448 "exportPersonalCertificatePasswordSelected",
449 base::Bind(&CertificateManagerHandler::ExportPersonalPasswordSelected
,
450 base::Unretained(this)));
452 web_ui()->RegisterMessageCallback(
453 "importPersonalCertificate",
454 base::Bind(&CertificateManagerHandler::StartImportPersonal
,
455 base::Unretained(this)));
456 web_ui()->RegisterMessageCallback(
457 "importPersonalCertificatePasswordSelected",
458 base::Bind(&CertificateManagerHandler::ImportPersonalPasswordSelected
,
459 base::Unretained(this)));
461 web_ui()->RegisterMessageCallback(
462 "importCaCertificate",
463 base::Bind(&CertificateManagerHandler::ImportCA
,
464 base::Unretained(this)));
465 web_ui()->RegisterMessageCallback(
466 "importCaCertificateTrustSelected",
467 base::Bind(&CertificateManagerHandler::ImportCATrustSelected
,
468 base::Unretained(this)));
470 web_ui()->RegisterMessageCallback(
471 "importServerCertificate",
472 base::Bind(&CertificateManagerHandler::ImportServer
,
473 base::Unretained(this)));
475 web_ui()->RegisterMessageCallback(
477 base::Bind(&CertificateManagerHandler::Export
,
478 base::Unretained(this)));
480 web_ui()->RegisterMessageCallback(
482 base::Bind(&CertificateManagerHandler::Delete
,
483 base::Unretained(this)));
485 web_ui()->RegisterMessageCallback(
486 "populateCertificateManager",
487 base::Bind(&CertificateManagerHandler::Populate
,
488 base::Unretained(this)));
491 void CertificateManagerHandler::CertificatesRefreshed() {
492 net::CertificateList web_trusted_certs
;
493 #if defined(OS_CHROMEOS)
494 policy::UserNetworkConfigurationUpdater
* service
=
495 policy::UserNetworkConfigurationUpdaterFactory::GetForProfile(
496 Profile::FromWebUI(web_ui()));
498 service
->GetWebTrustedCertificates(&web_trusted_certs
);
500 PopulateTree("personalCertsTab", net::USER_CERT
, web_trusted_certs
);
501 PopulateTree("serverCertsTab", net::SERVER_CERT
, web_trusted_certs
);
502 PopulateTree("caCertsTab", net::CA_CERT
, web_trusted_certs
);
503 PopulateTree("otherCertsTab", net::OTHER_CERT
, web_trusted_certs
);
506 void CertificateManagerHandler::FileSelected(const base::FilePath
& path
,
509 switch (reinterpret_cast<intptr_t>(params
)) {
510 case EXPORT_PERSONAL_FILE_SELECTED
:
511 ExportPersonalFileSelected(path
);
513 case IMPORT_PERSONAL_FILE_SELECTED
:
514 ImportPersonalFileSelected(path
);
516 case IMPORT_SERVER_FILE_SELECTED
:
517 ImportServerFileSelected(path
);
519 case IMPORT_CA_FILE_SELECTED
:
520 ImportCAFileSelected(path
);
527 void CertificateManagerHandler::FileSelectionCanceled(void* params
) {
528 switch (reinterpret_cast<intptr_t>(params
)) {
529 case EXPORT_PERSONAL_FILE_SELECTED
:
530 case IMPORT_PERSONAL_FILE_SELECTED
:
531 case IMPORT_SERVER_FILE_SELECTED
:
532 case IMPORT_CA_FILE_SELECTED
:
533 ImportExportCleanup();
540 void CertificateManagerHandler::View(const base::ListValue
* args
) {
541 net::X509Certificate
* cert
= cert_id_map_
->CallbackArgsToCert(args
);
544 #if defined(OS_CHROMEOS)
545 if (show_certs_in_modal_dialog_
) {
546 ShowCertificateViewerModalDialog(web_ui()->GetWebContents(),
552 ShowCertificateViewer(web_ui()->GetWebContents(), GetParentWindow(), cert
);
555 void CertificateManagerHandler::GetCATrust(const base::ListValue
* args
) {
556 net::X509Certificate
* cert
= cert_id_map_
->CallbackArgsToCert(args
);
558 web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
562 net::NSSCertDatabase::TrustBits trust_bits
=
563 certificate_manager_model_
->cert_db()->GetCertTrust(cert
, net::CA_CERT
);
564 base::FundamentalValue
ssl_value(
565 static_cast<bool>(trust_bits
& net::NSSCertDatabase::TRUSTED_SSL
));
566 base::FundamentalValue
email_value(
567 static_cast<bool>(trust_bits
& net::NSSCertDatabase::TRUSTED_EMAIL
));
568 base::FundamentalValue
obj_sign_value(
569 static_cast<bool>(trust_bits
& net::NSSCertDatabase::TRUSTED_OBJ_SIGN
));
570 web_ui()->CallJavascriptFunction(
571 "CertificateEditCaTrustOverlay.populateTrust",
572 ssl_value
, email_value
, obj_sign_value
);
575 void CertificateManagerHandler::EditCATrust(const base::ListValue
* args
) {
576 net::X509Certificate
* cert
= cert_id_map_
->CallbackArgsToCert(args
);
578 bool trust_ssl
= false;
579 bool trust_email
= false;
580 bool trust_obj_sign
= false;
581 fail
|= !CallbackArgsToBool(args
, 1, &trust_ssl
);
582 fail
|= !CallbackArgsToBool(args
, 2, &trust_email
);
583 fail
|= !CallbackArgsToBool(args
, 3, &trust_obj_sign
);
585 LOG(ERROR
) << "EditCATrust args fail";
586 web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
590 bool result
= certificate_manager_model_
->SetCertTrust(
593 trust_ssl
* net::NSSCertDatabase::TRUSTED_SSL
+
594 trust_email
* net::NSSCertDatabase::TRUSTED_EMAIL
+
595 trust_obj_sign
* net::NSSCertDatabase::TRUSTED_OBJ_SIGN
);
596 web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
598 // TODO(mattm): better error messages?
600 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SET_TRUST_ERROR_TITLE
),
601 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR
));
605 void CertificateManagerHandler::EditServer(const base::ListValue
* args
) {
609 void CertificateManagerHandler::ExportPersonal(const base::ListValue
* args
) {
610 net::X509Certificate
* cert
= cert_id_map_
->CallbackArgsToCert(args
);
614 selected_cert_list_
.push_back(cert
);
616 ui::SelectFileDialog::FileTypeInfo file_type_info
;
617 file_type_info
.extensions
.resize(1);
618 file_type_info
.extensions
[0].push_back(FILE_PATH_LITERAL("p12"));
619 file_type_info
.extension_description_overrides
.push_back(
620 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PKCS12_FILES
));
621 file_type_info
.include_all_files
= true;
622 select_file_dialog_
= ui::SelectFileDialog::Create(
623 this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
624 select_file_dialog_
->SelectFile(
625 ui::SelectFileDialog::SELECT_SAVEAS_FILE
, base::string16(),
626 base::FilePath(), &file_type_info
, 1, FILE_PATH_LITERAL("p12"),
628 reinterpret_cast<void*>(EXPORT_PERSONAL_FILE_SELECTED
));
631 void CertificateManagerHandler::ExportAllPersonal(const base::ListValue
* args
) {
635 void CertificateManagerHandler::ExportPersonalFileSelected(
636 const base::FilePath
& path
) {
638 web_ui()->CallJavascriptFunction(
639 "CertificateManager.exportPersonalAskPassword");
642 void CertificateManagerHandler::ExportPersonalPasswordSelected(
643 const base::ListValue
* args
) {
644 if (!args
->GetString(0, &password_
)) {
645 web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
646 ImportExportCleanup();
650 // Currently, we don't support exporting more than one at a time. If we do,
651 // this would need to either change this to use UnlockSlotsIfNecessary or
652 // change UnlockCertSlotIfNecessary to take a CertificateList.
653 DCHECK_EQ(selected_cert_list_
.size(), 1U);
655 // TODO(mattm): do something smarter about non-extractable keys
656 chrome::UnlockCertSlotIfNecessary(
657 selected_cert_list_
[0].get(),
658 chrome::kCryptoModulePasswordCertExport
,
659 net::HostPortPair(), // unused.
661 base::Bind(&CertificateManagerHandler::ExportPersonalSlotsUnlocked
,
662 base::Unretained(this)));
665 void CertificateManagerHandler::ExportPersonalSlotsUnlocked() {
667 int num_exported
= certificate_manager_model_
->cert_db()->ExportToPKCS12(
672 web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
674 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_EXPORT_ERROR_TITLE
),
675 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR
));
676 ImportExportCleanup();
679 file_access_provider_
->StartWrite(
682 base::Bind(&CertificateManagerHandler::ExportPersonalFileWritten
,
683 base::Unretained(this)),
687 void CertificateManagerHandler::ExportPersonalFileWritten(
688 const int* write_errno
, const int* bytes_written
) {
689 web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
690 ImportExportCleanup();
693 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_EXPORT_ERROR_TITLE
),
694 l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_WRITE_ERROR_FORMAT
,
696 base::safe_strerror(*write_errno
))));
700 void CertificateManagerHandler::StartImportPersonal(
701 const base::ListValue
* args
) {
702 ui::SelectFileDialog::FileTypeInfo file_type_info
;
703 if (!args
->GetBoolean(0, &use_hardware_backed_
)) {
704 // Unable to retrieve the hardware backed attribute from the args,
706 web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
707 ImportExportCleanup();
710 file_type_info
.extensions
.resize(1);
711 file_type_info
.extensions
[0].push_back(FILE_PATH_LITERAL("p12"));
712 file_type_info
.extension_description_overrides
.push_back(
713 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PKCS12_FILES
));
714 file_type_info
.include_all_files
= true;
715 select_file_dialog_
= ui::SelectFileDialog::Create(
716 this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
717 select_file_dialog_
->SelectFile(
718 ui::SelectFileDialog::SELECT_OPEN_FILE
, base::string16(),
719 base::FilePath(), &file_type_info
, 1, FILE_PATH_LITERAL("p12"),
721 reinterpret_cast<void*>(IMPORT_PERSONAL_FILE_SELECTED
));
724 void CertificateManagerHandler::ImportPersonalFileSelected(
725 const base::FilePath
& path
) {
727 web_ui()->CallJavascriptFunction(
728 "CertificateManager.importPersonalAskPassword");
731 void CertificateManagerHandler::ImportPersonalPasswordSelected(
732 const base::ListValue
* args
) {
733 if (!args
->GetString(0, &password_
)) {
734 web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
735 ImportExportCleanup();
738 file_access_provider_
->StartRead(
740 base::Bind(&CertificateManagerHandler::ImportPersonalFileRead
,
741 base::Unretained(this)),
745 void CertificateManagerHandler::ImportPersonalFileRead(
746 const int* read_errno
, const std::string
* data
) {
748 ImportExportCleanup();
749 web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
751 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_IMPORT_ERROR_TITLE
),
752 l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT
,
754 base::safe_strerror(*read_errno
))));
760 if (use_hardware_backed_
) {
761 module_
= certificate_manager_model_
->cert_db()->GetPrivateModule();
763 module_
= certificate_manager_model_
->cert_db()->GetPublicModule();
766 net::CryptoModuleList modules
;
767 modules
.push_back(module_
);
768 chrome::UnlockSlotsIfNecessary(
770 chrome::kCryptoModulePasswordCertImport
,
771 net::HostPortPair(), // unused.
773 base::Bind(&CertificateManagerHandler::ImportPersonalSlotUnlocked
,
774 base::Unretained(this)));
777 void CertificateManagerHandler::ImportPersonalSlotUnlocked() {
778 // Determine if the private key should be unextractable after the import.
779 // We do this by checking the value of |use_hardware_backed_| which is set
780 // to true if importing into a hardware module. Currently, this only happens
781 // for Chrome OS when the "Import and Bind" option is chosen.
782 bool is_extractable
= !use_hardware_backed_
;
783 int result
= certificate_manager_model_
->ImportFromPKCS12(
784 module_
.get(), file_data_
, password_
, is_extractable
);
785 ImportExportCleanup();
786 web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
791 case net::ERR_PKCS12_IMPORT_BAD_PASSWORD
:
792 // TODO(mattm): if the error was a bad password, we should reshow the
793 // password dialog after the user dismisses the error dialog.
794 string_id
= IDS_CERT_MANAGER_BAD_PASSWORD
;
796 case net::ERR_PKCS12_IMPORT_INVALID_MAC
:
797 string_id
= IDS_CERT_MANAGER_PKCS12_IMPORT_INVALID_MAC
;
799 case net::ERR_PKCS12_IMPORT_INVALID_FILE
:
800 string_id
= IDS_CERT_MANAGER_PKCS12_IMPORT_INVALID_FILE
;
802 case net::ERR_PKCS12_IMPORT_UNSUPPORTED
:
803 string_id
= IDS_CERT_MANAGER_PKCS12_IMPORT_UNSUPPORTED
;
806 string_id
= IDS_CERT_MANAGER_UNKNOWN_ERROR
;
810 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_IMPORT_ERROR_TITLE
),
811 l10n_util::GetStringUTF8(string_id
));
814 void CertificateManagerHandler::CancelImportExportProcess(
815 const base::ListValue
* args
) {
816 ImportExportCleanup();
819 void CertificateManagerHandler::ImportExportCleanup() {
823 use_hardware_backed_
= false;
824 selected_cert_list_
.clear();
827 // There may be pending file dialogs, we need to tell them that we've gone
828 // away so they don't try and call back to us.
829 if (select_file_dialog_
.get())
830 select_file_dialog_
->ListenerDestroyed();
831 select_file_dialog_
= NULL
;
834 void CertificateManagerHandler::ImportServer(const base::ListValue
* args
) {
835 select_file_dialog_
= ui::SelectFileDialog::Create(
836 this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
837 ShowCertSelectFileDialog(
838 select_file_dialog_
.get(),
839 ui::SelectFileDialog::SELECT_OPEN_FILE
,
842 reinterpret_cast<void*>(IMPORT_SERVER_FILE_SELECTED
));
845 void CertificateManagerHandler::ImportServerFileSelected(
846 const base::FilePath
& path
) {
848 file_access_provider_
->StartRead(
850 base::Bind(&CertificateManagerHandler::ImportServerFileRead
,
851 base::Unretained(this)),
855 void CertificateManagerHandler::ImportServerFileRead(const int* read_errno
,
856 const std::string
* data
) {
858 ImportExportCleanup();
860 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE
),
861 l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT
,
863 base::safe_strerror(*read_errno
))));
867 selected_cert_list_
= net::X509Certificate::CreateCertificateListFromBytes(
868 data
->data(), data
->size(), net::X509Certificate::FORMAT_AUTO
);
869 if (selected_cert_list_
.empty()) {
870 ImportExportCleanup();
872 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE
),
873 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CERT_PARSE_ERROR
));
877 net::NSSCertDatabase::ImportCertFailureList not_imported
;
878 // TODO(mattm): Add UI for trust. http://crbug.com/76274
879 bool result
= certificate_manager_model_
->ImportServerCert(
881 net::NSSCertDatabase::TRUST_DEFAULT
,
885 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE
),
886 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR
));
887 } else if (!not_imported
.empty()) {
889 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE
),
892 ImportExportCleanup();
895 void CertificateManagerHandler::ImportCA(const base::ListValue
* args
) {
896 select_file_dialog_
= ui::SelectFileDialog::Create(
897 this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
898 ShowCertSelectFileDialog(select_file_dialog_
.get(),
899 ui::SelectFileDialog::SELECT_OPEN_FILE
,
902 reinterpret_cast<void*>(IMPORT_CA_FILE_SELECTED
));
905 void CertificateManagerHandler::ImportCAFileSelected(
906 const base::FilePath
& path
) {
908 file_access_provider_
->StartRead(
910 base::Bind(&CertificateManagerHandler::ImportCAFileRead
,
911 base::Unretained(this)),
915 void CertificateManagerHandler::ImportCAFileRead(const int* read_errno
,
916 const std::string
* data
) {
918 ImportExportCleanup();
920 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE
),
921 l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT
,
923 base::safe_strerror(*read_errno
))));
927 selected_cert_list_
= net::X509Certificate::CreateCertificateListFromBytes(
928 data
->data(), data
->size(), net::X509Certificate::FORMAT_AUTO
);
929 if (selected_cert_list_
.empty()) {
930 ImportExportCleanup();
932 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE
),
933 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CERT_PARSE_ERROR
));
937 scoped_refptr
<net::X509Certificate
> root_cert
=
938 certificate_manager_model_
->cert_db()->FindRootInList(
939 selected_cert_list_
);
941 // TODO(mattm): check here if root_cert is not a CA cert and show error.
943 base::StringValue
cert_name(root_cert
->subject().GetDisplayName());
944 web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.showImport",
948 void CertificateManagerHandler::ImportCATrustSelected(
949 const base::ListValue
* args
) {
951 bool trust_ssl
= false;
952 bool trust_email
= false;
953 bool trust_obj_sign
= false;
954 fail
|= !CallbackArgsToBool(args
, 0, &trust_ssl
);
955 fail
|= !CallbackArgsToBool(args
, 1, &trust_email
);
956 fail
|= !CallbackArgsToBool(args
, 2, &trust_obj_sign
);
958 LOG(ERROR
) << "ImportCATrustSelected args fail";
959 ImportExportCleanup();
960 web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
964 // TODO(mattm): add UI for setting explicit distrust, too.
965 // http://crbug.com/128411
966 net::NSSCertDatabase::ImportCertFailureList not_imported
;
967 bool result
= certificate_manager_model_
->ImportCACerts(
969 trust_ssl
* net::NSSCertDatabase::TRUSTED_SSL
+
970 trust_email
* net::NSSCertDatabase::TRUSTED_EMAIL
+
971 trust_obj_sign
* net::NSSCertDatabase::TRUSTED_OBJ_SIGN
,
973 web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
976 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE
),
977 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR
));
978 } else if (!not_imported
.empty()) {
980 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE
),
983 ImportExportCleanup();
986 void CertificateManagerHandler::Export(const base::ListValue
* args
) {
987 net::X509Certificate
* cert
= cert_id_map_
->CallbackArgsToCert(args
);
990 ShowCertExportDialog(web_ui()->GetWebContents(), GetParentWindow(), cert
);
993 void CertificateManagerHandler::Delete(const base::ListValue
* args
) {
994 net::X509Certificate
* cert
= cert_id_map_
->CallbackArgsToCert(args
);
997 bool result
= certificate_manager_model_
->Delete(cert
);
999 // TODO(mattm): better error messages?
1001 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_DELETE_CERT_ERROR_TITLE
),
1002 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR
));
1006 void CertificateManagerHandler::OnCertificateManagerModelCreated(
1007 scoped_ptr
<CertificateManagerModel
> model
) {
1008 certificate_manager_model_
= model
.Pass();
1009 CertificateManagerModelReady();
1012 void CertificateManagerHandler::CertificateManagerModelReady() {
1013 base::FundamentalValue
user_db_available_value(
1014 certificate_manager_model_
->is_user_db_available());
1015 base::FundamentalValue
tpm_available_value(
1016 certificate_manager_model_
->is_tpm_available());
1017 web_ui()->CallJavascriptFunction("CertificateManager.onModelReady",
1018 user_db_available_value
,
1019 tpm_available_value
);
1020 certificate_manager_model_
->Refresh();
1023 void CertificateManagerHandler::Populate(const base::ListValue
* args
) {
1024 if (certificate_manager_model_
) {
1025 // Already have a model, the webui must be re-loading. Just re-run the
1026 // webui initialization.
1027 CertificateManagerModelReady();
1031 if (!requested_certificate_manager_model_
) {
1032 // Request that a model be created.
1033 CertificateManagerModel::Create(
1034 Profile::FromWebUI(web_ui()),
1036 base::Bind(&CertificateManagerHandler::OnCertificateManagerModelCreated
,
1037 weak_ptr_factory_
.GetWeakPtr()));
1038 requested_certificate_manager_model_
= true;
1042 // We are already waiting for a CertificateManagerModel to be created, no need
1046 void CertificateManagerHandler::PopulateTree(
1047 const std::string
& tab_name
,
1049 const net::CertificateList
& web_trust_certs
) {
1050 const std::string tree_name
= tab_name
+ "-tree";
1052 scoped_ptr
<icu::Collator
> collator
;
1053 UErrorCode error
= U_ZERO_ERROR
;
1055 icu::Collator::createInstance(
1056 icu::Locale(g_browser_process
->GetApplicationLocale().c_str()),
1058 if (U_FAILURE(error
))
1059 collator
.reset(NULL
);
1060 DictionaryIdComparator
comparator(collator
.get());
1061 CertificateManagerModel::OrgGroupingMap map
;
1063 certificate_manager_model_
->FilterAndBuildOrgGroupingMap(type
, &map
);
1066 base::ListValue
* nodes
= new base::ListValue
;
1067 for (CertificateManagerModel::OrgGroupingMap::iterator i
= map
.begin();
1068 i
!= map
.end(); ++i
) {
1069 // Populate first level (org name).
1070 base::DictionaryValue
* dict
= new base::DictionaryValue
;
1071 dict
->SetString(kKeyId
, OrgNameToId(i
->first
));
1072 dict
->SetString(kNameId
, i
->first
);
1074 // Populate second level (certs).
1075 base::ListValue
* subnodes
= new base::ListValue
;
1076 for (net::CertificateList::const_iterator org_cert_it
= i
->second
.begin();
1077 org_cert_it
!= i
->second
.end(); ++org_cert_it
) {
1078 base::DictionaryValue
* cert_dict
= new base::DictionaryValue
;
1079 net::X509Certificate
* cert
= org_cert_it
->get();
1080 cert_dict
->SetString(kKeyId
, cert_id_map_
->CertToId(cert
));
1081 cert_dict
->SetString(kNameId
, certificate_manager_model_
->GetColumnText(
1082 *cert
, CertificateManagerModel::COL_SUBJECT_NAME
));
1083 cert_dict
->SetBoolean(
1085 certificate_manager_model_
->cert_db()->IsReadOnly(cert
));
1086 // Policy-installed certificates with web trust are trusted.
1087 bool policy_trusted
=
1088 IsPolicyInstalledWithWebTrust(web_trust_certs
, cert
);
1089 cert_dict
->SetBoolean(
1092 certificate_manager_model_
->cert_db()->IsUntrusted(cert
));
1093 cert_dict
->SetBoolean(kPolicyTrustedId
, policy_trusted
);
1094 // TODO(hshi): This should be determined by testing for PKCS #11
1095 // CKA_EXTRACTABLE attribute. We may need to use the NSS function
1096 // PK11_ReadRawAttribute to do that.
1097 cert_dict
->SetBoolean(
1099 !certificate_manager_model_
->IsHardwareBacked(cert
));
1100 // TODO(mattm): Other columns.
1101 subnodes
->Append(cert_dict
);
1103 std::sort(subnodes
->begin(), subnodes
->end(), comparator
);
1105 dict
->Set(kSubNodesId
, subnodes
);
1106 nodes
->Append(dict
);
1108 std::sort(nodes
->begin(), nodes
->end(), comparator
);
1110 base::ListValue args
;
1111 args
.Append(new base::StringValue(tree_name
));
1113 web_ui()->CallJavascriptFunction("CertificateManager.onPopulateTree", args
);
1117 void CertificateManagerHandler::ShowError(const std::string
& title
,
1118 const std::string
& error
) const {
1119 ScopedVector
<const base::Value
> args
;
1120 args
.push_back(new base::StringValue(title
));
1121 args
.push_back(new base::StringValue(error
));
1122 args
.push_back(new base::StringValue(l10n_util::GetStringUTF8(IDS_OK
)));
1123 args
.push_back(base::Value::CreateNullValue().release()); // cancelTitle
1124 args
.push_back(base::Value::CreateNullValue().release()); // okCallback
1125 args
.push_back(base::Value::CreateNullValue().release()); // cancelCallback
1126 web_ui()->CallJavascriptFunction("AlertOverlay.show", args
.get());
1129 void CertificateManagerHandler::ShowImportErrors(
1130 const std::string
& title
,
1131 const net::NSSCertDatabase::ImportCertFailureList
& not_imported
) const {
1133 if (selected_cert_list_
.size() == 1)
1134 error
= l10n_util::GetStringUTF8(
1135 IDS_CERT_MANAGER_IMPORT_SINGLE_NOT_IMPORTED
);
1136 else if (not_imported
.size() == selected_cert_list_
.size())
1137 error
= l10n_util::GetStringUTF8(IDS_CERT_MANAGER_IMPORT_ALL_NOT_IMPORTED
);
1139 error
= l10n_util::GetStringUTF8(IDS_CERT_MANAGER_IMPORT_SOME_NOT_IMPORTED
);
1141 base::ListValue cert_error_list
;
1142 for (size_t i
= 0; i
< not_imported
.size(); ++i
) {
1143 const net::NSSCertDatabase::ImportCertFailure
& failure
= not_imported
[i
];
1144 base::DictionaryValue
* dict
= new base::DictionaryValue
;
1145 dict
->SetString(kNameId
, failure
.certificate
->subject().GetDisplayName());
1146 dict
->SetString(kErrorId
, NetErrorToString(failure
.net_error
));
1147 cert_error_list
.Append(dict
);
1150 base::StringValue
title_value(title
);
1151 base::StringValue
error_value(error
);
1152 web_ui()->CallJavascriptFunction("CertificateImportErrorOverlay.show",
1158 gfx::NativeWindow
CertificateManagerHandler::GetParentWindow() const {
1159 return web_ui()->GetWebContents()->GetTopLevelNativeWindow();
1162 } // namespace options