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/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/safe_strerror_posix.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.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/web_contents.h"
28 #include "content/public/browser/web_contents_view.h"
29 #include "grit/generated_resources.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/policy/profile_policy_connector.h"
37 #include "chrome/browser/policy/profile_policy_connector_factory.h"
38 #include "chromeos/dbus/cryptohome_client.h"
39 #include "chromeos/dbus/dbus_thread_manager.h"
42 using content::BrowserThread;
46 static const char kKeyId[] = "id";
47 static const char kSubNodesId[] = "subnodes";
48 static const char kNameId[] = "name";
49 static const char kReadOnlyId[] = "readonly";
50 static const char kUntrustedId[] = "untrusted";
51 static const char kExtractableId[] = "extractable";
52 static const char kErrorId[] = "error";
53 static const char kPolicyTrustedId[] = "policy";
55 // Enumeration of different callers of SelectFile. (Start counting at 1 so
56 // if SelectFile is accidentally called with params=NULL it won't match any.)
58 EXPORT_PERSONAL_FILE_SELECTED = 1,
59 IMPORT_PERSONAL_FILE_SELECTED,
60 IMPORT_SERVER_FILE_SELECTED,
61 IMPORT_CA_FILE_SELECTED,
64 std::string OrgNameToId(const std::string& org) {
68 bool CallbackArgsToBool(const ListValue* args, int index, bool* result) {
69 std::string string_value;
70 if (!args->GetString(index, &string_value))
73 *result = string_value[0] == 't';
77 struct DictionaryIdComparator {
78 explicit DictionaryIdComparator(icu::Collator* collator)
79 : collator_(collator) {
82 bool operator()(const Value* a,
83 const Value* b) const {
84 DCHECK(a->GetType() == Value::TYPE_DICTIONARY);
85 DCHECK(b->GetType() == Value::TYPE_DICTIONARY);
86 const DictionaryValue* a_dict = reinterpret_cast<const DictionaryValue*>(a);
87 const DictionaryValue* b_dict = reinterpret_cast<const DictionaryValue*>(b);
90 a_dict->GetString(kNameId, &a_str);
91 b_dict->GetString(kNameId, &b_str);
92 if (collator_ == NULL)
94 return base::i18n::CompareString16WithCollator(
95 collator_, a_str, b_str) == UCOL_LESS;
98 icu::Collator* collator_;
101 std::string NetErrorToString(int net_error) {
103 // TODO(mattm): handle more cases.
104 case net::ERR_IMPORT_CA_CERT_NOT_CA:
105 return l10n_util::GetStringUTF8(IDS_CERT_MANAGER_ERROR_NOT_CA);
106 case net::ERR_IMPORT_CERT_ALREADY_EXISTS:
107 return l10n_util::GetStringUTF8(
108 IDS_CERT_MANAGER_ERROR_CERT_ALREADY_EXISTS);
110 return l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR);
114 // Struct to bind the Equals member function to an object for use in find_if.
116 explicit CertEquals(const net::X509Certificate* cert) : cert_(cert) {}
117 bool operator()(const scoped_refptr<net::X509Certificate> cert) const {
118 return cert_->Equals(cert.get());
120 const net::X509Certificate* cert_;
123 // Determine whether a certificate was stored with web trust by a policy.
124 bool IsPolicyInstalledWithWebTrust(
125 const net::CertificateList& web_trust_certs,
126 net::X509Certificate* cert) {
127 return std::find_if(web_trust_certs.begin(), web_trust_certs.end(),
128 CertEquals(cert)) != web_trust_certs.end();
135 ///////////////////////////////////////////////////////////////////////////////
143 std::string CertToId(net::X509Certificate* cert);
144 net::X509Certificate* IdToCert(const std::string& id);
145 net::X509Certificate* CallbackArgsToCert(const base::ListValue* args);
148 typedef std::map<net::X509Certificate*, int32> CertMap;
150 // Creates an ID for cert and looks up the cert for an ID.
151 IDMap<net::X509Certificate>id_map_;
153 // Finds the ID for a cert.
156 DISALLOW_COPY_AND_ASSIGN(CertIdMap);
159 std::string CertIdMap::CertToId(net::X509Certificate* cert) {
160 CertMap::const_iterator iter = cert_map_.find(cert);
161 if (iter != cert_map_.end())
162 return base::IntToString(iter->second);
164 int32 new_id = id_map_.Add(cert);
165 cert_map_[cert] = new_id;
166 return base::IntToString(new_id);
169 net::X509Certificate* CertIdMap::IdToCert(const std::string& id) {
171 if (!base::StringToInt(id, &cert_id))
174 return id_map_.Lookup(cert_id);
177 net::X509Certificate* CertIdMap::CallbackArgsToCert(
178 const ListValue* args) {
180 if (!args->GetString(0, &node_id))
183 net::X509Certificate* cert = IdToCert(node_id);
192 ///////////////////////////////////////////////////////////////////////////////
193 // FileAccessProvider
195 // TODO(mattm): Move to some shared location?
196 class FileAccessProvider
197 : public base::RefCountedThreadSafe<FileAccessProvider> {
199 // The first parameter is 0 on success or errno on failure. The second
200 // parameter is read result.
201 typedef base::Callback<void(const int*, const std::string*)> ReadCallback;
203 // The first parameter is 0 on success or errno on failure. The second
204 // parameter is the number of bytes written on success.
205 typedef base::Callback<void(const int*, const int*)> WriteCallback;
207 CancelableTaskTracker::TaskId StartRead(const base::FilePath& path,
208 const ReadCallback& callback,
209 CancelableTaskTracker* tracker);
210 CancelableTaskTracker::TaskId StartWrite(const base::FilePath& path,
211 const std::string& data,
212 const WriteCallback& callback,
213 CancelableTaskTracker* tracker);
216 friend class base::RefCountedThreadSafe<FileAccessProvider>;
217 virtual ~FileAccessProvider() {}
219 // Reads file at |path|. |saved_errno| is 0 on success or errno on failure.
220 // When success, |data| has file content.
221 void DoRead(const base::FilePath& path,
224 // Writes data to file at |path|. |saved_errno| is 0 on success or errno on
225 // failure. When success, |bytes_written| has number of bytes written.
226 void DoWrite(const base::FilePath& path,
227 const std::string& data,
232 CancelableTaskTracker::TaskId FileAccessProvider::StartRead(
233 const base::FilePath& path,
234 const ReadCallback& callback,
235 CancelableTaskTracker* tracker) {
236 // Owned by reply callback posted below.
237 int* saved_errno = new int(0);
238 std::string* data = new std::string();
240 // Post task to file thread to read file.
241 return tracker->PostTaskAndReply(
242 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE).get(),
244 base::Bind(&FileAccessProvider::DoRead, this, path, saved_errno, data),
245 base::Bind(callback, base::Owned(saved_errno), base::Owned(data)));
248 CancelableTaskTracker::TaskId FileAccessProvider::StartWrite(
249 const base::FilePath& path,
250 const std::string& data,
251 const WriteCallback& callback,
252 CancelableTaskTracker* tracker) {
253 // Owned by reply callback posted below.
254 int* saved_errno = new int(0);
255 int* bytes_written = new int(0);
257 // Post task to file thread to write file.
258 return tracker->PostTaskAndReply(
259 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE).get(),
261 base::Bind(&FileAccessProvider::DoWrite,
268 callback, base::Owned(saved_errno), base::Owned(bytes_written)));
271 void FileAccessProvider::DoRead(const base::FilePath& path,
274 bool success = base::ReadFileToString(path, data);
275 *saved_errno = success ? 0 : errno;
278 void FileAccessProvider::DoWrite(const base::FilePath& path,
279 const std::string& data,
281 int* bytes_written) {
282 *bytes_written = file_util::WriteFile(path, data.data(), data.size());
283 *saved_errno = *bytes_written >= 0 ? 0 : errno;
286 ///////////////////////////////////////////////////////////////////////////////
287 // CertificateManagerHandler
289 CertificateManagerHandler::CertificateManagerHandler()
290 : use_hardware_backed_(false),
291 file_access_provider_(new FileAccessProvider()),
292 cert_id_map_(new CertIdMap),
293 weak_ptr_factory_(this) {
294 certificate_manager_model_.reset(new CertificateManagerModel(this));
297 CertificateManagerHandler::~CertificateManagerHandler() {
300 void CertificateManagerHandler::GetLocalizedValues(
301 DictionaryValue* localized_strings) {
302 DCHECK(localized_strings);
304 RegisterTitle(localized_strings, "certificateManagerPage",
305 IDS_CERTIFICATE_MANAGER_TITLE);
308 localized_strings->SetString("personalCertsTabTitle",
309 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PERSONAL_CERTS_TAB_LABEL));
310 localized_strings->SetString("serverCertsTabTitle",
311 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_SERVER_CERTS_TAB_LABEL));
312 localized_strings->SetString("caCertsTabTitle",
313 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_CERT_AUTHORITIES_TAB_LABEL));
314 localized_strings->SetString("otherCertsTabTitle",
315 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_OTHER_TAB_LABEL));
318 localized_strings->SetString("personalCertsTabDescription",
319 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_USER_TREE_DESCRIPTION));
320 localized_strings->SetString("serverCertsTabDescription",
321 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_SERVER_TREE_DESCRIPTION));
322 localized_strings->SetString("caCertsTabDescription",
323 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_AUTHORITIES_TREE_DESCRIPTION));
324 localized_strings->SetString("otherCertsTabDescription",
325 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_OTHER_TREE_DESCRIPTION));
328 localized_strings->SetString("view_certificate",
329 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_VIEW_CERT_BUTTON));
330 localized_strings->SetString("import_certificate",
331 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_IMPORT_BUTTON));
332 localized_strings->SetString("export_certificate",
333 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_BUTTON));
334 localized_strings->SetString("edit_certificate",
335 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_BUTTON));
336 localized_strings->SetString("delete_certificate",
337 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_BUTTON));
339 // Certificate Delete overlay strings.
340 localized_strings->SetString("personalCertsTabDeleteConfirm",
341 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_USER_FORMAT));
342 localized_strings->SetString("personalCertsTabDeleteImpact",
343 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_USER_DESCRIPTION));
344 localized_strings->SetString("serverCertsTabDeleteConfirm",
345 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_SERVER_FORMAT));
346 localized_strings->SetString("serverCertsTabDeleteImpact",
347 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_SERVER_DESCRIPTION));
348 localized_strings->SetString("caCertsTabDeleteConfirm",
349 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_CA_FORMAT));
350 localized_strings->SetString("caCertsTabDeleteImpact",
351 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_CA_DESCRIPTION));
352 localized_strings->SetString("otherCertsTabDeleteConfirm",
353 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_OTHER_FORMAT));
354 localized_strings->SetString("otherCertsTabDeleteImpact", std::string());
356 // Certificate Restore overlay strings.
357 localized_strings->SetString("certificateRestorePasswordDescription",
358 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_RESTORE_PASSWORD_DESC));
359 localized_strings->SetString("certificatePasswordLabel",
360 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PASSWORD_LABEL));
362 // Personal Certificate Export overlay strings.
363 localized_strings->SetString("certificateExportPasswordDescription",
364 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_PASSWORD_DESC));
365 localized_strings->SetString("certificateExportPasswordHelp",
366 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_PASSWORD_HELP));
367 localized_strings->SetString("certificateConfirmPasswordLabel",
368 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_CONFIRM_PASSWORD_LABEL));
370 // Edit CA Trust & Import CA overlay strings.
371 localized_strings->SetString("certificateEditCaTitle",
372 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_CA_TITLE));
373 localized_strings->SetString("certificateEditTrustLabel",
374 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_TRUST_LABEL));
375 localized_strings->SetString("certificateEditCaTrustDescriptionFormat",
376 l10n_util::GetStringUTF16(
377 IDS_CERT_MANAGER_EDIT_CA_TRUST_DESCRIPTION_FORMAT));
378 localized_strings->SetString("certificateImportCaDescriptionFormat",
379 l10n_util::GetStringUTF16(
380 IDS_CERT_MANAGER_IMPORT_CA_DESCRIPTION_FORMAT));
381 localized_strings->SetString("certificateCaTrustSSLLabel",
382 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_CA_TRUST_SSL_LABEL));
383 localized_strings->SetString("certificateCaTrustEmailLabel",
384 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_CA_TRUST_EMAIL_LABEL));
385 localized_strings->SetString("certificateCaTrustObjSignLabel",
386 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_CA_TRUST_OBJSIGN_LABEL));
387 localized_strings->SetString("certificateImportErrorFormat",
388 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_IMPORT_ERROR_FORMAT));
390 // Badges next to certificates
391 localized_strings->SetString("badgeCertUntrusted",
392 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_UNTRUSTED));
393 localized_strings->SetString("certPolicyInstalled",
394 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_POLICY_INSTALLED));
396 #if defined(OS_CHROMEOS)
397 localized_strings->SetString("importAndBindCertificate",
398 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_IMPORT_AND_BIND_BUTTON));
399 localized_strings->SetString("hardwareBackedKeyFormat",
400 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_HARDWARE_BACKED_KEY_FORMAT));
401 localized_strings->SetString("chromeOSDeviceName",
402 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_HARDWARE_BACKED));
403 #endif // defined(OS_CHROMEOS)
406 void CertificateManagerHandler::RegisterMessages() {
407 web_ui()->RegisterMessageCallback(
409 base::Bind(&CertificateManagerHandler::View, base::Unretained(this)));
411 web_ui()->RegisterMessageCallback(
412 "getCaCertificateTrust",
413 base::Bind(&CertificateManagerHandler::GetCATrust,
414 base::Unretained(this)));
415 web_ui()->RegisterMessageCallback(
416 "editCaCertificateTrust",
417 base::Bind(&CertificateManagerHandler::EditCATrust,
418 base::Unretained(this)));
420 web_ui()->RegisterMessageCallback(
421 "editServerCertificate",
422 base::Bind(&CertificateManagerHandler::EditServer,
423 base::Unretained(this)));
425 web_ui()->RegisterMessageCallback(
426 "cancelImportExportCertificate",
427 base::Bind(&CertificateManagerHandler::CancelImportExportProcess,
428 base::Unretained(this)));
430 web_ui()->RegisterMessageCallback(
431 "exportPersonalCertificate",
432 base::Bind(&CertificateManagerHandler::ExportPersonal,
433 base::Unretained(this)));
434 web_ui()->RegisterMessageCallback(
435 "exportAllPersonalCertificates",
436 base::Bind(&CertificateManagerHandler::ExportAllPersonal,
437 base::Unretained(this)));
438 web_ui()->RegisterMessageCallback(
439 "exportPersonalCertificatePasswordSelected",
440 base::Bind(&CertificateManagerHandler::ExportPersonalPasswordSelected,
441 base::Unretained(this)));
443 web_ui()->RegisterMessageCallback(
444 "importPersonalCertificate",
445 base::Bind(&CertificateManagerHandler::StartImportPersonal,
446 base::Unretained(this)));
447 web_ui()->RegisterMessageCallback(
448 "importPersonalCertificatePasswordSelected",
449 base::Bind(&CertificateManagerHandler::ImportPersonalPasswordSelected,
450 base::Unretained(this)));
452 web_ui()->RegisterMessageCallback(
453 "importCaCertificate",
454 base::Bind(&CertificateManagerHandler::ImportCA,
455 base::Unretained(this)));
456 web_ui()->RegisterMessageCallback(
457 "importCaCertificateTrustSelected",
458 base::Bind(&CertificateManagerHandler::ImportCATrustSelected,
459 base::Unretained(this)));
461 web_ui()->RegisterMessageCallback(
462 "importServerCertificate",
463 base::Bind(&CertificateManagerHandler::ImportServer,
464 base::Unretained(this)));
466 web_ui()->RegisterMessageCallback(
468 base::Bind(&CertificateManagerHandler::Export,
469 base::Unretained(this)));
471 web_ui()->RegisterMessageCallback(
473 base::Bind(&CertificateManagerHandler::Delete,
474 base::Unretained(this)));
476 web_ui()->RegisterMessageCallback(
477 "populateCertificateManager",
478 base::Bind(&CertificateManagerHandler::Populate,
479 base::Unretained(this)));
481 #if defined(OS_CHROMEOS)
482 web_ui()->RegisterMessageCallback(
483 "checkTpmTokenReady",
484 base::Bind(&CertificateManagerHandler::CheckTpmTokenReady,
485 base::Unretained(this)));
489 void CertificateManagerHandler::CertificatesRefreshed() {
490 net::CertificateList web_trusted_certs;
491 #if defined(OS_CHROMEOS)
492 policy::ProfilePolicyConnectorFactory::GetForProfile(
493 Profile::FromWebUI(web_ui()))->GetWebTrustedCertificates(
496 PopulateTree("personalCertsTab", net::USER_CERT, web_trusted_certs);
497 PopulateTree("serverCertsTab", net::SERVER_CERT, web_trusted_certs);
498 PopulateTree("caCertsTab", net::CA_CERT, web_trusted_certs);
499 PopulateTree("otherCertsTab", net::OTHER_CERT, web_trusted_certs);
502 void CertificateManagerHandler::FileSelected(const base::FilePath& path,
505 switch (reinterpret_cast<intptr_t>(params)) {
506 case EXPORT_PERSONAL_FILE_SELECTED:
507 ExportPersonalFileSelected(path);
509 case IMPORT_PERSONAL_FILE_SELECTED:
510 ImportPersonalFileSelected(path);
512 case IMPORT_SERVER_FILE_SELECTED:
513 ImportServerFileSelected(path);
515 case IMPORT_CA_FILE_SELECTED:
516 ImportCAFileSelected(path);
523 void CertificateManagerHandler::FileSelectionCanceled(void* params) {
524 switch (reinterpret_cast<intptr_t>(params)) {
525 case EXPORT_PERSONAL_FILE_SELECTED:
526 case IMPORT_PERSONAL_FILE_SELECTED:
527 case IMPORT_SERVER_FILE_SELECTED:
528 case IMPORT_CA_FILE_SELECTED:
529 ImportExportCleanup();
536 void CertificateManagerHandler::View(const ListValue* args) {
537 net::X509Certificate* cert = cert_id_map_->CallbackArgsToCert(args);
540 ShowCertificateViewer(web_ui()->GetWebContents(), GetParentWindow(), cert);
543 void CertificateManagerHandler::GetCATrust(const ListValue* args) {
544 net::X509Certificate* cert = cert_id_map_->CallbackArgsToCert(args);
546 web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
550 net::NSSCertDatabase::TrustBits trust_bits =
551 certificate_manager_model_->cert_db()->GetCertTrust(cert, net::CA_CERT);
552 base::FundamentalValue ssl_value(
553 static_cast<bool>(trust_bits & net::NSSCertDatabase::TRUSTED_SSL));
554 base::FundamentalValue email_value(
555 static_cast<bool>(trust_bits & net::NSSCertDatabase::TRUSTED_EMAIL));
556 base::FundamentalValue obj_sign_value(
557 static_cast<bool>(trust_bits & net::NSSCertDatabase::TRUSTED_OBJ_SIGN));
558 web_ui()->CallJavascriptFunction(
559 "CertificateEditCaTrustOverlay.populateTrust",
560 ssl_value, email_value, obj_sign_value);
563 void CertificateManagerHandler::EditCATrust(const ListValue* args) {
564 net::X509Certificate* cert = cert_id_map_->CallbackArgsToCert(args);
566 bool trust_ssl = false;
567 bool trust_email = false;
568 bool trust_obj_sign = false;
569 fail |= !CallbackArgsToBool(args, 1, &trust_ssl);
570 fail |= !CallbackArgsToBool(args, 2, &trust_email);
571 fail |= !CallbackArgsToBool(args, 3, &trust_obj_sign);
573 LOG(ERROR) << "EditCATrust args fail";
574 web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
578 bool result = certificate_manager_model_->SetCertTrust(
581 trust_ssl * net::NSSCertDatabase::TRUSTED_SSL +
582 trust_email * net::NSSCertDatabase::TRUSTED_EMAIL +
583 trust_obj_sign * net::NSSCertDatabase::TRUSTED_OBJ_SIGN);
584 web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
586 // TODO(mattm): better error messages?
588 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SET_TRUST_ERROR_TITLE),
589 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
593 void CertificateManagerHandler::EditServer(const ListValue* args) {
597 void CertificateManagerHandler::ExportPersonal(const ListValue* args) {
598 net::X509Certificate* cert = cert_id_map_->CallbackArgsToCert(args);
602 selected_cert_list_.push_back(cert);
604 ui::SelectFileDialog::FileTypeInfo file_type_info;
605 file_type_info.extensions.resize(1);
606 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("p12"));
607 file_type_info.extension_description_overrides.push_back(
608 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PKCS12_FILES));
609 file_type_info.include_all_files = true;
610 select_file_dialog_ = ui::SelectFileDialog::Create(
611 this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
612 select_file_dialog_->SelectFile(
613 ui::SelectFileDialog::SELECT_SAVEAS_FILE, string16(),
614 base::FilePath(), &file_type_info, 1, FILE_PATH_LITERAL("p12"),
616 reinterpret_cast<void*>(EXPORT_PERSONAL_FILE_SELECTED));
619 void CertificateManagerHandler::ExportAllPersonal(const ListValue* args) {
623 void CertificateManagerHandler::ExportPersonalFileSelected(
624 const base::FilePath& path) {
626 web_ui()->CallJavascriptFunction(
627 "CertificateManager.exportPersonalAskPassword");
630 void CertificateManagerHandler::ExportPersonalPasswordSelected(
631 const ListValue* args) {
632 if (!args->GetString(0, &password_)) {
633 web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
634 ImportExportCleanup();
638 // Currently, we don't support exporting more than one at a time. If we do,
639 // this would need to either change this to use UnlockSlotsIfNecessary or
640 // change UnlockCertSlotIfNecessary to take a CertificateList.
641 DCHECK_EQ(selected_cert_list_.size(), 1U);
643 // TODO(mattm): do something smarter about non-extractable keys
644 chrome::UnlockCertSlotIfNecessary(
645 selected_cert_list_[0].get(),
646 chrome::kCryptoModulePasswordCertExport,
647 std::string(), // unused.
648 base::Bind(&CertificateManagerHandler::ExportPersonalSlotsUnlocked,
649 base::Unretained(this)));
652 void CertificateManagerHandler::ExportPersonalSlotsUnlocked() {
654 int num_exported = certificate_manager_model_->cert_db()->ExportToPKCS12(
659 web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
661 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_EXPORT_ERROR_TITLE),
662 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
663 ImportExportCleanup();
666 file_access_provider_->StartWrite(
669 base::Bind(&CertificateManagerHandler::ExportPersonalFileWritten,
670 base::Unretained(this)),
674 void CertificateManagerHandler::ExportPersonalFileWritten(
675 const int* write_errno, const int* bytes_written) {
676 web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
677 ImportExportCleanup();
680 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_EXPORT_ERROR_TITLE),
681 l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_WRITE_ERROR_FORMAT,
682 UTF8ToUTF16(safe_strerror(*write_errno))));
686 void CertificateManagerHandler::StartImportPersonal(const ListValue* args) {
687 ui::SelectFileDialog::FileTypeInfo file_type_info;
688 if (!args->GetBoolean(0, &use_hardware_backed_)) {
689 // Unable to retrieve the hardware backed attribute from the args,
691 web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
692 ImportExportCleanup();
695 file_type_info.extensions.resize(1);
696 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("p12"));
697 file_type_info.extension_description_overrides.push_back(
698 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PKCS12_FILES));
699 file_type_info.include_all_files = true;
700 select_file_dialog_ = ui::SelectFileDialog::Create(
701 this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
702 select_file_dialog_->SelectFile(
703 ui::SelectFileDialog::SELECT_OPEN_FILE, string16(),
704 base::FilePath(), &file_type_info, 1, FILE_PATH_LITERAL("p12"),
706 reinterpret_cast<void*>(IMPORT_PERSONAL_FILE_SELECTED));
709 void CertificateManagerHandler::ImportPersonalFileSelected(
710 const base::FilePath& path) {
712 web_ui()->CallJavascriptFunction(
713 "CertificateManager.importPersonalAskPassword");
716 void CertificateManagerHandler::ImportPersonalPasswordSelected(
717 const ListValue* args) {
718 if (!args->GetString(0, &password_)) {
719 web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
720 ImportExportCleanup();
723 file_access_provider_->StartRead(
725 base::Bind(&CertificateManagerHandler::ImportPersonalFileRead,
726 base::Unretained(this)),
730 void CertificateManagerHandler::ImportPersonalFileRead(
731 const int* read_errno, const std::string* data) {
733 ImportExportCleanup();
734 web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
736 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_IMPORT_ERROR_TITLE),
737 l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT,
738 UTF8ToUTF16(safe_strerror(*read_errno))));
744 if (use_hardware_backed_) {
745 module_ = certificate_manager_model_->cert_db()->GetPrivateModule();
747 module_ = certificate_manager_model_->cert_db()->GetPublicModule();
750 net::CryptoModuleList modules;
751 modules.push_back(module_);
752 chrome::UnlockSlotsIfNecessary(
754 chrome::kCryptoModulePasswordCertImport,
755 std::string(), // unused.
756 base::Bind(&CertificateManagerHandler::ImportPersonalSlotUnlocked,
757 base::Unretained(this)));
760 void CertificateManagerHandler::ImportPersonalSlotUnlocked() {
761 // Determine if the private key should be unextractable after the import.
762 // We do this by checking the value of |use_hardware_backed_| which is set
763 // to true if importing into a hardware module. Currently, this only happens
764 // for Chrome OS when the "Import and Bind" option is chosen.
765 bool is_extractable = !use_hardware_backed_;
766 int result = certificate_manager_model_->ImportFromPKCS12(
767 module_.get(), file_data_, password_, is_extractable);
768 ImportExportCleanup();
769 web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
774 case net::ERR_PKCS12_IMPORT_BAD_PASSWORD:
775 // TODO(mattm): if the error was a bad password, we should reshow the
776 // password dialog after the user dismisses the error dialog.
777 string_id = IDS_CERT_MANAGER_BAD_PASSWORD;
779 case net::ERR_PKCS12_IMPORT_INVALID_MAC:
780 string_id = IDS_CERT_MANAGER_PKCS12_IMPORT_INVALID_MAC;
782 case net::ERR_PKCS12_IMPORT_INVALID_FILE:
783 string_id = IDS_CERT_MANAGER_PKCS12_IMPORT_INVALID_FILE;
785 case net::ERR_PKCS12_IMPORT_UNSUPPORTED:
786 string_id = IDS_CERT_MANAGER_PKCS12_IMPORT_UNSUPPORTED;
789 string_id = IDS_CERT_MANAGER_UNKNOWN_ERROR;
793 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_IMPORT_ERROR_TITLE),
794 l10n_util::GetStringUTF8(string_id));
797 void CertificateManagerHandler::CancelImportExportProcess(
798 const ListValue* args) {
799 ImportExportCleanup();
802 void CertificateManagerHandler::ImportExportCleanup() {
806 use_hardware_backed_ = false;
807 selected_cert_list_.clear();
810 // There may be pending file dialogs, we need to tell them that we've gone
811 // away so they don't try and call back to us.
812 if (select_file_dialog_.get())
813 select_file_dialog_->ListenerDestroyed();
814 select_file_dialog_ = NULL;
817 void CertificateManagerHandler::ImportServer(const ListValue* args) {
818 select_file_dialog_ = ui::SelectFileDialog::Create(
819 this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
820 ShowCertSelectFileDialog(
821 select_file_dialog_.get(),
822 ui::SelectFileDialog::SELECT_OPEN_FILE,
825 reinterpret_cast<void*>(IMPORT_SERVER_FILE_SELECTED));
828 void CertificateManagerHandler::ImportServerFileSelected(
829 const base::FilePath& path) {
831 file_access_provider_->StartRead(
833 base::Bind(&CertificateManagerHandler::ImportServerFileRead,
834 base::Unretained(this)),
838 void CertificateManagerHandler::ImportServerFileRead(const int* read_errno,
839 const std::string* data) {
841 ImportExportCleanup();
843 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE),
844 l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT,
845 UTF8ToUTF16(safe_strerror(*read_errno))));
849 selected_cert_list_ = net::X509Certificate::CreateCertificateListFromBytes(
850 data->data(), data->size(), net::X509Certificate::FORMAT_AUTO);
851 if (selected_cert_list_.empty()) {
852 ImportExportCleanup();
854 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE),
855 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CERT_PARSE_ERROR));
859 net::NSSCertDatabase::ImportCertFailureList not_imported;
860 // TODO(mattm): Add UI for trust. http://crbug.com/76274
861 bool result = certificate_manager_model_->ImportServerCert(
863 net::NSSCertDatabase::TRUST_DEFAULT,
867 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE),
868 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
869 } else if (!not_imported.empty()) {
871 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE),
874 ImportExportCleanup();
877 void CertificateManagerHandler::ImportCA(const ListValue* args) {
878 select_file_dialog_ = ui::SelectFileDialog::Create(
879 this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
880 ShowCertSelectFileDialog(select_file_dialog_.get(),
881 ui::SelectFileDialog::SELECT_OPEN_FILE,
884 reinterpret_cast<void*>(IMPORT_CA_FILE_SELECTED));
887 void CertificateManagerHandler::ImportCAFileSelected(
888 const base::FilePath& path) {
890 file_access_provider_->StartRead(
892 base::Bind(&CertificateManagerHandler::ImportCAFileRead,
893 base::Unretained(this)),
897 void CertificateManagerHandler::ImportCAFileRead(const int* read_errno,
898 const std::string* data) {
900 ImportExportCleanup();
902 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE),
903 l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT,
904 UTF8ToUTF16(safe_strerror(*read_errno))));
908 selected_cert_list_ = net::X509Certificate::CreateCertificateListFromBytes(
909 data->data(), data->size(), net::X509Certificate::FORMAT_AUTO);
910 if (selected_cert_list_.empty()) {
911 ImportExportCleanup();
913 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE),
914 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CERT_PARSE_ERROR));
918 scoped_refptr<net::X509Certificate> root_cert =
919 certificate_manager_model_->cert_db()->FindRootInList(
920 selected_cert_list_);
922 // TODO(mattm): check here if root_cert is not a CA cert and show error.
924 StringValue cert_name(root_cert->subject().GetDisplayName());
925 web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.showImport",
929 void CertificateManagerHandler::ImportCATrustSelected(const ListValue* args) {
931 bool trust_ssl = false;
932 bool trust_email = false;
933 bool trust_obj_sign = false;
934 fail |= !CallbackArgsToBool(args, 0, &trust_ssl);
935 fail |= !CallbackArgsToBool(args, 1, &trust_email);
936 fail |= !CallbackArgsToBool(args, 2, &trust_obj_sign);
938 LOG(ERROR) << "ImportCATrustSelected args fail";
939 ImportExportCleanup();
940 web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
944 // TODO(mattm): add UI for setting explicit distrust, too.
945 // http://crbug.com/128411
946 net::NSSCertDatabase::ImportCertFailureList not_imported;
947 bool result = certificate_manager_model_->ImportCACerts(
949 trust_ssl * net::NSSCertDatabase::TRUSTED_SSL +
950 trust_email * net::NSSCertDatabase::TRUSTED_EMAIL +
951 trust_obj_sign * net::NSSCertDatabase::TRUSTED_OBJ_SIGN,
953 web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
956 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE),
957 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
958 } else if (!not_imported.empty()) {
960 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE),
963 ImportExportCleanup();
966 void CertificateManagerHandler::Export(const ListValue* args) {
967 net::X509Certificate* cert = cert_id_map_->CallbackArgsToCert(args);
970 ShowCertExportDialog(web_ui()->GetWebContents(), GetParentWindow(),
971 cert->os_cert_handle());
974 void CertificateManagerHandler::Delete(const ListValue* args) {
975 net::X509Certificate* cert = cert_id_map_->CallbackArgsToCert(args);
978 bool result = certificate_manager_model_->Delete(cert);
980 // TODO(mattm): better error messages?
982 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_DELETE_CERT_ERROR_TITLE),
983 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
987 void CertificateManagerHandler::Populate(const ListValue* args) {
988 certificate_manager_model_->Refresh();
991 void CertificateManagerHandler::PopulateTree(
992 const std::string& tab_name,
994 const net::CertificateList& web_trust_certs) {
995 const std::string tree_name = tab_name + "-tree";
997 scoped_ptr<icu::Collator> collator;
998 UErrorCode error = U_ZERO_ERROR;
1000 icu::Collator::createInstance(
1001 icu::Locale(g_browser_process->GetApplicationLocale().c_str()),
1003 if (U_FAILURE(error))
1004 collator.reset(NULL);
1005 DictionaryIdComparator comparator(collator.get());
1006 CertificateManagerModel::OrgGroupingMap map;
1008 certificate_manager_model_->FilterAndBuildOrgGroupingMap(type, &map);
1011 ListValue* nodes = new ListValue;
1012 for (CertificateManagerModel::OrgGroupingMap::iterator i = map.begin();
1013 i != map.end(); ++i) {
1014 // Populate first level (org name).
1015 DictionaryValue* dict = new DictionaryValue;
1016 dict->SetString(kKeyId, OrgNameToId(i->first));
1017 dict->SetString(kNameId, i->first);
1019 // Populate second level (certs).
1020 ListValue* subnodes = new ListValue;
1021 for (net::CertificateList::const_iterator org_cert_it = i->second.begin();
1022 org_cert_it != i->second.end(); ++org_cert_it) {
1023 DictionaryValue* cert_dict = new DictionaryValue;
1024 net::X509Certificate* cert = org_cert_it->get();
1025 cert_dict->SetString(kKeyId, cert_id_map_->CertToId(cert));
1026 cert_dict->SetString(kNameId, certificate_manager_model_->GetColumnText(
1027 *cert, CertificateManagerModel::COL_SUBJECT_NAME));
1028 cert_dict->SetBoolean(
1030 certificate_manager_model_->cert_db()->IsReadOnly(cert));
1031 // Policy-installed certificates with web trust are trusted.
1032 bool policy_trusted =
1033 IsPolicyInstalledWithWebTrust(web_trust_certs, cert);
1034 cert_dict->SetBoolean(
1037 certificate_manager_model_->cert_db()->IsUntrusted(cert));
1038 cert_dict->SetBoolean(kPolicyTrustedId, policy_trusted);
1039 // TODO(hshi): This should be determined by testing for PKCS #11
1040 // CKA_EXTRACTABLE attribute. We may need to use the NSS function
1041 // PK11_ReadRawAttribute to do that.
1042 cert_dict->SetBoolean(
1044 !certificate_manager_model_->IsHardwareBacked(cert));
1045 // TODO(mattm): Other columns.
1046 subnodes->Append(cert_dict);
1048 std::sort(subnodes->begin(), subnodes->end(), comparator);
1050 dict->Set(kSubNodesId, subnodes);
1051 nodes->Append(dict);
1053 std::sort(nodes->begin(), nodes->end(), comparator);
1056 args.Append(new base::StringValue(tree_name));
1058 web_ui()->CallJavascriptFunction("CertificateManager.onPopulateTree", args);
1062 void CertificateManagerHandler::ShowError(const std::string& title,
1063 const std::string& error) const {
1064 ScopedVector<const Value> args;
1065 args.push_back(new base::StringValue(title));
1066 args.push_back(new base::StringValue(error));
1067 args.push_back(new base::StringValue(l10n_util::GetStringUTF8(IDS_OK)));
1068 args.push_back(Value::CreateNullValue()); // cancelTitle
1069 args.push_back(Value::CreateNullValue()); // okCallback
1070 args.push_back(Value::CreateNullValue()); // cancelCallback
1071 web_ui()->CallJavascriptFunction("AlertOverlay.show", args.get());
1074 void CertificateManagerHandler::ShowImportErrors(
1075 const std::string& title,
1076 const net::NSSCertDatabase::ImportCertFailureList& not_imported) const {
1078 if (selected_cert_list_.size() == 1)
1079 error = l10n_util::GetStringUTF8(
1080 IDS_CERT_MANAGER_IMPORT_SINGLE_NOT_IMPORTED);
1081 else if (not_imported.size() == selected_cert_list_.size())
1082 error = l10n_util::GetStringUTF8(IDS_CERT_MANAGER_IMPORT_ALL_NOT_IMPORTED);
1084 error = l10n_util::GetStringUTF8(IDS_CERT_MANAGER_IMPORT_SOME_NOT_IMPORTED);
1086 ListValue cert_error_list;
1087 for (size_t i = 0; i < not_imported.size(); ++i) {
1088 const net::NSSCertDatabase::ImportCertFailure& failure = not_imported[i];
1089 DictionaryValue* dict = new DictionaryValue;
1090 dict->SetString(kNameId, failure.certificate->subject().GetDisplayName());
1091 dict->SetString(kErrorId, NetErrorToString(failure.net_error));
1092 cert_error_list.Append(dict);
1095 StringValue title_value(title);
1096 StringValue error_value(error);
1097 web_ui()->CallJavascriptFunction("CertificateImportErrorOverlay.show",
1103 #if defined(OS_CHROMEOS)
1104 void CertificateManagerHandler::CheckTpmTokenReady(const ListValue* args) {
1105 chromeos::CryptohomeClient* cryptohome_client =
1106 chromeos::DBusThreadManager::Get()->GetCryptohomeClient();
1107 cryptohome_client->Pkcs11IsTpmTokenReady(
1108 base::Bind(&CertificateManagerHandler::CheckTpmTokenReadyInternal,
1109 weak_ptr_factory_.GetWeakPtr()));
1112 void CertificateManagerHandler::CheckTpmTokenReadyInternal(
1113 chromeos::DBusMethodCallStatus call_status,
1114 bool is_tpm_token_ready) {
1115 base::FundamentalValue ready(
1116 call_status == chromeos::DBUS_METHOD_CALL_SUCCESS && is_tpm_token_ready);
1117 web_ui()->CallJavascriptFunction("CertificateManager.onCheckTpmTokenReady",
1122 gfx::NativeWindow CertificateManagerHandler::GetParentWindow() const {
1123 return web_ui()->GetWebContents()->GetView()->GetTopLevelNativeWindow();
1126 } // namespace options