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_nss.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/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(
96 collator_, a_str, b_str) == UCOL_LESS;
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();
136 ///////////////////////////////////////////////////////////////////////////////
144 std::string CertToId(net::X509Certificate* cert);
145 net::X509Certificate* IdToCert(const std::string& id);
146 net::X509Certificate* CallbackArgsToCert(const base::ListValue* args);
149 typedef std::map<net::X509Certificate*, int32> CertMap;
151 // Creates an ID for cert and looks up the cert for an ID.
152 IDMap<net::X509Certificate>id_map_;
154 // Finds the ID for a cert.
157 DISALLOW_COPY_AND_ASSIGN(CertIdMap);
160 std::string CertIdMap::CertToId(net::X509Certificate* cert) {
161 CertMap::const_iterator iter = cert_map_.find(cert);
162 if (iter != cert_map_.end())
163 return base::IntToString(iter->second);
165 int32 new_id = id_map_.Add(cert);
166 cert_map_[cert] = new_id;
167 return base::IntToString(new_id);
170 net::X509Certificate* CertIdMap::IdToCert(const std::string& id) {
172 if (!base::StringToInt(id, &cert_id))
175 return id_map_.Lookup(cert_id);
178 net::X509Certificate* CertIdMap::CallbackArgsToCert(
179 const base::ListValue* args) {
181 if (!args->GetString(0, &node_id))
184 net::X509Certificate* cert = IdToCert(node_id);
193 ///////////////////////////////////////////////////////////////////////////////
194 // FileAccessProvider
196 // TODO(mattm): Move to some shared location?
197 class FileAccessProvider
198 : public base::RefCountedThreadSafe<FileAccessProvider> {
200 // The first parameter is 0 on success or errno on failure. The second
201 // parameter is read result.
202 typedef base::Callback<void(const int*, const std::string*)> ReadCallback;
204 // The first parameter is 0 on success or errno on failure. The second
205 // parameter is the number of bytes written on success.
206 typedef base::Callback<void(const int*, const int*)> WriteCallback;
208 base::CancelableTaskTracker::TaskId StartRead(
209 const base::FilePath& path,
210 const ReadCallback& callback,
211 base::CancelableTaskTracker* tracker);
212 base::CancelableTaskTracker::TaskId StartWrite(
213 const base::FilePath& path,
214 const std::string& data,
215 const WriteCallback& callback,
216 base::CancelableTaskTracker* tracker);
219 friend class base::RefCountedThreadSafe<FileAccessProvider>;
220 virtual ~FileAccessProvider() {}
222 // Reads file at |path|. |saved_errno| is 0 on success or errno on failure.
223 // When success, |data| has file content.
224 void DoRead(const base::FilePath& path,
227 // Writes data to file at |path|. |saved_errno| is 0 on success or errno on
228 // failure. When success, |bytes_written| has number of bytes written.
229 void DoWrite(const base::FilePath& path,
230 const std::string& data,
235 base::CancelableTaskTracker::TaskId FileAccessProvider::StartRead(
236 const base::FilePath& path,
237 const ReadCallback& callback,
238 base::CancelableTaskTracker* tracker) {
239 // Owned by reply callback posted below.
240 int* saved_errno = new int(0);
241 std::string* data = new std::string();
243 // Post task to file thread to read file.
244 return tracker->PostTaskAndReply(
245 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE).get(),
247 base::Bind(&FileAccessProvider::DoRead, this, path, saved_errno, data),
248 base::Bind(callback, base::Owned(saved_errno), base::Owned(data)));
251 base::CancelableTaskTracker::TaskId FileAccessProvider::StartWrite(
252 const base::FilePath& path,
253 const std::string& data,
254 const WriteCallback& callback,
255 base::CancelableTaskTracker* tracker) {
256 // Owned by reply callback posted below.
257 int* saved_errno = new int(0);
258 int* bytes_written = new int(0);
260 // Post task to file thread to write file.
261 return tracker->PostTaskAndReply(
262 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE).get(),
264 base::Bind(&FileAccessProvider::DoWrite,
271 callback, base::Owned(saved_errno), base::Owned(bytes_written)));
274 void FileAccessProvider::DoRead(const base::FilePath& path,
277 bool success = base::ReadFileToString(path, data);
278 *saved_errno = success ? 0 : errno;
281 void FileAccessProvider::DoWrite(const base::FilePath& path,
282 const std::string& data,
284 int* bytes_written) {
285 *bytes_written = file_util::WriteFile(path, data.data(), data.size());
286 *saved_errno = *bytes_written >= 0 ? 0 : errno;
289 ///////////////////////////////////////////////////////////////////////////////
290 // CertificateManagerHandler
292 CertificateManagerHandler::CertificateManagerHandler()
293 : requested_certificate_manager_model_(false),
294 use_hardware_backed_(false),
295 file_access_provider_(new FileAccessProvider()),
296 cert_id_map_(new CertIdMap),
297 weak_ptr_factory_(this) {}
299 CertificateManagerHandler::~CertificateManagerHandler() {
302 void CertificateManagerHandler::GetLocalizedValues(
303 base::DictionaryValue* localized_strings) {
304 DCHECK(localized_strings);
306 RegisterTitle(localized_strings, "certificateManagerPage",
307 IDS_CERTIFICATE_MANAGER_TITLE);
310 localized_strings->SetString("personalCertsTabTitle",
311 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PERSONAL_CERTS_TAB_LABEL));
312 localized_strings->SetString("serverCertsTabTitle",
313 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_SERVER_CERTS_TAB_LABEL));
314 localized_strings->SetString("caCertsTabTitle",
315 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_CERT_AUTHORITIES_TAB_LABEL));
316 localized_strings->SetString("otherCertsTabTitle",
317 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_OTHER_TAB_LABEL));
320 localized_strings->SetString("personalCertsTabDescription",
321 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_USER_TREE_DESCRIPTION));
322 localized_strings->SetString("serverCertsTabDescription",
323 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_SERVER_TREE_DESCRIPTION));
324 localized_strings->SetString("caCertsTabDescription",
325 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_AUTHORITIES_TREE_DESCRIPTION));
326 localized_strings->SetString("otherCertsTabDescription",
327 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_OTHER_TREE_DESCRIPTION));
330 localized_strings->SetString("view_certificate",
331 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_VIEW_CERT_BUTTON));
332 localized_strings->SetString("import_certificate",
333 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_IMPORT_BUTTON));
334 localized_strings->SetString("export_certificate",
335 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_BUTTON));
336 localized_strings->SetString("edit_certificate",
337 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_BUTTON));
338 localized_strings->SetString("delete_certificate",
339 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_BUTTON));
341 // Certificate Delete overlay strings.
342 localized_strings->SetString("personalCertsTabDeleteConfirm",
343 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_USER_FORMAT));
344 localized_strings->SetString("personalCertsTabDeleteImpact",
345 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_USER_DESCRIPTION));
346 localized_strings->SetString("serverCertsTabDeleteConfirm",
347 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_SERVER_FORMAT));
348 localized_strings->SetString("serverCertsTabDeleteImpact",
349 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_SERVER_DESCRIPTION));
350 localized_strings->SetString("caCertsTabDeleteConfirm",
351 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_CA_FORMAT));
352 localized_strings->SetString("caCertsTabDeleteImpact",
353 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_CA_DESCRIPTION));
354 localized_strings->SetString("otherCertsTabDeleteConfirm",
355 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_OTHER_FORMAT));
356 localized_strings->SetString("otherCertsTabDeleteImpact", std::string());
358 // Certificate Restore overlay strings.
359 localized_strings->SetString("certificateRestorePasswordDescription",
360 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_RESTORE_PASSWORD_DESC));
361 localized_strings->SetString("certificatePasswordLabel",
362 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PASSWORD_LABEL));
364 // Personal Certificate Export overlay strings.
365 localized_strings->SetString("certificateExportPasswordDescription",
366 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_PASSWORD_DESC));
367 localized_strings->SetString("certificateExportPasswordHelp",
368 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_PASSWORD_HELP));
369 localized_strings->SetString("certificateConfirmPasswordLabel",
370 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_CONFIRM_PASSWORD_LABEL));
372 // Edit CA Trust & Import CA overlay strings.
373 localized_strings->SetString("certificateEditCaTitle",
374 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_CA_TITLE));
375 localized_strings->SetString("certificateEditTrustLabel",
376 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_TRUST_LABEL));
377 localized_strings->SetString("certificateEditCaTrustDescriptionFormat",
378 l10n_util::GetStringUTF16(
379 IDS_CERT_MANAGER_EDIT_CA_TRUST_DESCRIPTION_FORMAT));
380 localized_strings->SetString("certificateImportCaDescriptionFormat",
381 l10n_util::GetStringUTF16(
382 IDS_CERT_MANAGER_IMPORT_CA_DESCRIPTION_FORMAT));
383 localized_strings->SetString("certificateCaTrustSSLLabel",
384 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_CA_TRUST_SSL_LABEL));
385 localized_strings->SetString("certificateCaTrustEmailLabel",
386 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_CA_TRUST_EMAIL_LABEL));
387 localized_strings->SetString("certificateCaTrustObjSignLabel",
388 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_CA_TRUST_OBJSIGN_LABEL));
389 localized_strings->SetString("certificateImportErrorFormat",
390 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_IMPORT_ERROR_FORMAT));
392 // Badges next to certificates
393 localized_strings->SetString("badgeCertUntrusted",
394 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_UNTRUSTED));
395 localized_strings->SetString("certPolicyInstalled",
396 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_POLICY_INSTALLED));
398 #if defined(OS_CHROMEOS)
399 localized_strings->SetString("importAndBindCertificate",
400 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_IMPORT_AND_BIND_BUTTON));
401 #endif // defined(OS_CHROMEOS)
404 void CertificateManagerHandler::RegisterMessages() {
405 web_ui()->RegisterMessageCallback(
407 base::Bind(&CertificateManagerHandler::View, base::Unretained(this)));
409 web_ui()->RegisterMessageCallback(
410 "getCaCertificateTrust",
411 base::Bind(&CertificateManagerHandler::GetCATrust,
412 base::Unretained(this)));
413 web_ui()->RegisterMessageCallback(
414 "editCaCertificateTrust",
415 base::Bind(&CertificateManagerHandler::EditCATrust,
416 base::Unretained(this)));
418 web_ui()->RegisterMessageCallback(
419 "editServerCertificate",
420 base::Bind(&CertificateManagerHandler::EditServer,
421 base::Unretained(this)));
423 web_ui()->RegisterMessageCallback(
424 "cancelImportExportCertificate",
425 base::Bind(&CertificateManagerHandler::CancelImportExportProcess,
426 base::Unretained(this)));
428 web_ui()->RegisterMessageCallback(
429 "exportPersonalCertificate",
430 base::Bind(&CertificateManagerHandler::ExportPersonal,
431 base::Unretained(this)));
432 web_ui()->RegisterMessageCallback(
433 "exportAllPersonalCertificates",
434 base::Bind(&CertificateManagerHandler::ExportAllPersonal,
435 base::Unretained(this)));
436 web_ui()->RegisterMessageCallback(
437 "exportPersonalCertificatePasswordSelected",
438 base::Bind(&CertificateManagerHandler::ExportPersonalPasswordSelected,
439 base::Unretained(this)));
441 web_ui()->RegisterMessageCallback(
442 "importPersonalCertificate",
443 base::Bind(&CertificateManagerHandler::StartImportPersonal,
444 base::Unretained(this)));
445 web_ui()->RegisterMessageCallback(
446 "importPersonalCertificatePasswordSelected",
447 base::Bind(&CertificateManagerHandler::ImportPersonalPasswordSelected,
448 base::Unretained(this)));
450 web_ui()->RegisterMessageCallback(
451 "importCaCertificate",
452 base::Bind(&CertificateManagerHandler::ImportCA,
453 base::Unretained(this)));
454 web_ui()->RegisterMessageCallback(
455 "importCaCertificateTrustSelected",
456 base::Bind(&CertificateManagerHandler::ImportCATrustSelected,
457 base::Unretained(this)));
459 web_ui()->RegisterMessageCallback(
460 "importServerCertificate",
461 base::Bind(&CertificateManagerHandler::ImportServer,
462 base::Unretained(this)));
464 web_ui()->RegisterMessageCallback(
466 base::Bind(&CertificateManagerHandler::Export,
467 base::Unretained(this)));
469 web_ui()->RegisterMessageCallback(
471 base::Bind(&CertificateManagerHandler::Delete,
472 base::Unretained(this)));
474 web_ui()->RegisterMessageCallback(
475 "populateCertificateManager",
476 base::Bind(&CertificateManagerHandler::Populate,
477 base::Unretained(this)));
480 void CertificateManagerHandler::CertificatesRefreshed() {
481 net::CertificateList web_trusted_certs;
482 #if defined(OS_CHROMEOS)
483 policy::UserNetworkConfigurationUpdater* service =
484 policy::UserNetworkConfigurationUpdaterFactory::GetForProfile(
485 Profile::FromWebUI(web_ui()));
487 service->GetWebTrustedCertificates(&web_trusted_certs);
489 PopulateTree("personalCertsTab", net::USER_CERT, web_trusted_certs);
490 PopulateTree("serverCertsTab", net::SERVER_CERT, web_trusted_certs);
491 PopulateTree("caCertsTab", net::CA_CERT, web_trusted_certs);
492 PopulateTree("otherCertsTab", net::OTHER_CERT, web_trusted_certs);
495 void CertificateManagerHandler::FileSelected(const base::FilePath& path,
498 switch (reinterpret_cast<intptr_t>(params)) {
499 case EXPORT_PERSONAL_FILE_SELECTED:
500 ExportPersonalFileSelected(path);
502 case IMPORT_PERSONAL_FILE_SELECTED:
503 ImportPersonalFileSelected(path);
505 case IMPORT_SERVER_FILE_SELECTED:
506 ImportServerFileSelected(path);
508 case IMPORT_CA_FILE_SELECTED:
509 ImportCAFileSelected(path);
516 void CertificateManagerHandler::FileSelectionCanceled(void* params) {
517 switch (reinterpret_cast<intptr_t>(params)) {
518 case EXPORT_PERSONAL_FILE_SELECTED:
519 case IMPORT_PERSONAL_FILE_SELECTED:
520 case IMPORT_SERVER_FILE_SELECTED:
521 case IMPORT_CA_FILE_SELECTED:
522 ImportExportCleanup();
529 void CertificateManagerHandler::View(const base::ListValue* args) {
530 net::X509Certificate* cert = cert_id_map_->CallbackArgsToCert(args);
533 ShowCertificateViewer(web_ui()->GetWebContents(), GetParentWindow(), cert);
536 void CertificateManagerHandler::GetCATrust(const base::ListValue* args) {
537 net::X509Certificate* cert = cert_id_map_->CallbackArgsToCert(args);
539 web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
543 net::NSSCertDatabase::TrustBits trust_bits =
544 certificate_manager_model_->cert_db()->GetCertTrust(cert, net::CA_CERT);
545 base::FundamentalValue ssl_value(
546 static_cast<bool>(trust_bits & net::NSSCertDatabase::TRUSTED_SSL));
547 base::FundamentalValue email_value(
548 static_cast<bool>(trust_bits & net::NSSCertDatabase::TRUSTED_EMAIL));
549 base::FundamentalValue obj_sign_value(
550 static_cast<bool>(trust_bits & net::NSSCertDatabase::TRUSTED_OBJ_SIGN));
551 web_ui()->CallJavascriptFunction(
552 "CertificateEditCaTrustOverlay.populateTrust",
553 ssl_value, email_value, obj_sign_value);
556 void CertificateManagerHandler::EditCATrust(const base::ListValue* args) {
557 net::X509Certificate* cert = cert_id_map_->CallbackArgsToCert(args);
559 bool trust_ssl = false;
560 bool trust_email = false;
561 bool trust_obj_sign = false;
562 fail |= !CallbackArgsToBool(args, 1, &trust_ssl);
563 fail |= !CallbackArgsToBool(args, 2, &trust_email);
564 fail |= !CallbackArgsToBool(args, 3, &trust_obj_sign);
566 LOG(ERROR) << "EditCATrust args fail";
567 web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
571 bool result = certificate_manager_model_->SetCertTrust(
574 trust_ssl * net::NSSCertDatabase::TRUSTED_SSL +
575 trust_email * net::NSSCertDatabase::TRUSTED_EMAIL +
576 trust_obj_sign * net::NSSCertDatabase::TRUSTED_OBJ_SIGN);
577 web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
579 // TODO(mattm): better error messages?
581 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SET_TRUST_ERROR_TITLE),
582 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
586 void CertificateManagerHandler::EditServer(const base::ListValue* args) {
590 void CertificateManagerHandler::ExportPersonal(const base::ListValue* args) {
591 net::X509Certificate* cert = cert_id_map_->CallbackArgsToCert(args);
595 selected_cert_list_.push_back(cert);
597 ui::SelectFileDialog::FileTypeInfo file_type_info;
598 file_type_info.extensions.resize(1);
599 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("p12"));
600 file_type_info.extension_description_overrides.push_back(
601 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PKCS12_FILES));
602 file_type_info.include_all_files = true;
603 select_file_dialog_ = ui::SelectFileDialog::Create(
604 this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
605 select_file_dialog_->SelectFile(
606 ui::SelectFileDialog::SELECT_SAVEAS_FILE, base::string16(),
607 base::FilePath(), &file_type_info, 1, FILE_PATH_LITERAL("p12"),
609 reinterpret_cast<void*>(EXPORT_PERSONAL_FILE_SELECTED));
612 void CertificateManagerHandler::ExportAllPersonal(const base::ListValue* args) {
616 void CertificateManagerHandler::ExportPersonalFileSelected(
617 const base::FilePath& path) {
619 web_ui()->CallJavascriptFunction(
620 "CertificateManager.exportPersonalAskPassword");
623 void CertificateManagerHandler::ExportPersonalPasswordSelected(
624 const base::ListValue* args) {
625 if (!args->GetString(0, &password_)) {
626 web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
627 ImportExportCleanup();
631 // Currently, we don't support exporting more than one at a time. If we do,
632 // this would need to either change this to use UnlockSlotsIfNecessary or
633 // change UnlockCertSlotIfNecessary to take a CertificateList.
634 DCHECK_EQ(selected_cert_list_.size(), 1U);
636 // TODO(mattm): do something smarter about non-extractable keys
637 chrome::UnlockCertSlotIfNecessary(
638 selected_cert_list_[0].get(),
639 chrome::kCryptoModulePasswordCertExport,
640 net::HostPortPair(), // unused.
642 base::Bind(&CertificateManagerHandler::ExportPersonalSlotsUnlocked,
643 base::Unretained(this)));
646 void CertificateManagerHandler::ExportPersonalSlotsUnlocked() {
648 int num_exported = certificate_manager_model_->cert_db()->ExportToPKCS12(
653 web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
655 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_EXPORT_ERROR_TITLE),
656 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
657 ImportExportCleanup();
660 file_access_provider_->StartWrite(
663 base::Bind(&CertificateManagerHandler::ExportPersonalFileWritten,
664 base::Unretained(this)),
668 void CertificateManagerHandler::ExportPersonalFileWritten(
669 const int* write_errno, const int* bytes_written) {
670 web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
671 ImportExportCleanup();
674 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_EXPORT_ERROR_TITLE),
675 l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_WRITE_ERROR_FORMAT,
676 UTF8ToUTF16(safe_strerror(*write_errno))));
680 void CertificateManagerHandler::StartImportPersonal(
681 const base::ListValue* args) {
682 ui::SelectFileDialog::FileTypeInfo file_type_info;
683 if (!args->GetBoolean(0, &use_hardware_backed_)) {
684 // Unable to retrieve the hardware backed attribute from the args,
686 web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
687 ImportExportCleanup();
690 file_type_info.extensions.resize(1);
691 file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("p12"));
692 file_type_info.extension_description_overrides.push_back(
693 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PKCS12_FILES));
694 file_type_info.include_all_files = true;
695 select_file_dialog_ = ui::SelectFileDialog::Create(
696 this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
697 select_file_dialog_->SelectFile(
698 ui::SelectFileDialog::SELECT_OPEN_FILE, base::string16(),
699 base::FilePath(), &file_type_info, 1, FILE_PATH_LITERAL("p12"),
701 reinterpret_cast<void*>(IMPORT_PERSONAL_FILE_SELECTED));
704 void CertificateManagerHandler::ImportPersonalFileSelected(
705 const base::FilePath& path) {
707 web_ui()->CallJavascriptFunction(
708 "CertificateManager.importPersonalAskPassword");
711 void CertificateManagerHandler::ImportPersonalPasswordSelected(
712 const base::ListValue* args) {
713 if (!args->GetString(0, &password_)) {
714 web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
715 ImportExportCleanup();
718 file_access_provider_->StartRead(
720 base::Bind(&CertificateManagerHandler::ImportPersonalFileRead,
721 base::Unretained(this)),
725 void CertificateManagerHandler::ImportPersonalFileRead(
726 const int* read_errno, const std::string* data) {
728 ImportExportCleanup();
729 web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
731 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_IMPORT_ERROR_TITLE),
732 l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT,
733 UTF8ToUTF16(safe_strerror(*read_errno))));
739 if (use_hardware_backed_) {
740 module_ = certificate_manager_model_->cert_db()->GetPrivateModule();
742 module_ = certificate_manager_model_->cert_db()->GetPublicModule();
745 net::CryptoModuleList modules;
746 modules.push_back(module_);
747 chrome::UnlockSlotsIfNecessary(
749 chrome::kCryptoModulePasswordCertImport,
750 net::HostPortPair(), // unused.
752 base::Bind(&CertificateManagerHandler::ImportPersonalSlotUnlocked,
753 base::Unretained(this)));
756 void CertificateManagerHandler::ImportPersonalSlotUnlocked() {
757 // Determine if the private key should be unextractable after the import.
758 // We do this by checking the value of |use_hardware_backed_| which is set
759 // to true if importing into a hardware module. Currently, this only happens
760 // for Chrome OS when the "Import and Bind" option is chosen.
761 bool is_extractable = !use_hardware_backed_;
762 int result = certificate_manager_model_->ImportFromPKCS12(
763 module_.get(), file_data_, password_, is_extractable);
764 ImportExportCleanup();
765 web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
770 case net::ERR_PKCS12_IMPORT_BAD_PASSWORD:
771 // TODO(mattm): if the error was a bad password, we should reshow the
772 // password dialog after the user dismisses the error dialog.
773 string_id = IDS_CERT_MANAGER_BAD_PASSWORD;
775 case net::ERR_PKCS12_IMPORT_INVALID_MAC:
776 string_id = IDS_CERT_MANAGER_PKCS12_IMPORT_INVALID_MAC;
778 case net::ERR_PKCS12_IMPORT_INVALID_FILE:
779 string_id = IDS_CERT_MANAGER_PKCS12_IMPORT_INVALID_FILE;
781 case net::ERR_PKCS12_IMPORT_UNSUPPORTED:
782 string_id = IDS_CERT_MANAGER_PKCS12_IMPORT_UNSUPPORTED;
785 string_id = IDS_CERT_MANAGER_UNKNOWN_ERROR;
789 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_IMPORT_ERROR_TITLE),
790 l10n_util::GetStringUTF8(string_id));
793 void CertificateManagerHandler::CancelImportExportProcess(
794 const base::ListValue* args) {
795 ImportExportCleanup();
798 void CertificateManagerHandler::ImportExportCleanup() {
802 use_hardware_backed_ = false;
803 selected_cert_list_.clear();
806 // There may be pending file dialogs, we need to tell them that we've gone
807 // away so they don't try and call back to us.
808 if (select_file_dialog_.get())
809 select_file_dialog_->ListenerDestroyed();
810 select_file_dialog_ = NULL;
813 void CertificateManagerHandler::ImportServer(const base::ListValue* args) {
814 select_file_dialog_ = ui::SelectFileDialog::Create(
815 this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
816 ShowCertSelectFileDialog(
817 select_file_dialog_.get(),
818 ui::SelectFileDialog::SELECT_OPEN_FILE,
821 reinterpret_cast<void*>(IMPORT_SERVER_FILE_SELECTED));
824 void CertificateManagerHandler::ImportServerFileSelected(
825 const base::FilePath& path) {
827 file_access_provider_->StartRead(
829 base::Bind(&CertificateManagerHandler::ImportServerFileRead,
830 base::Unretained(this)),
834 void CertificateManagerHandler::ImportServerFileRead(const int* read_errno,
835 const std::string* data) {
837 ImportExportCleanup();
839 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE),
840 l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT,
841 UTF8ToUTF16(safe_strerror(*read_errno))));
845 selected_cert_list_ = net::X509Certificate::CreateCertificateListFromBytes(
846 data->data(), data->size(), net::X509Certificate::FORMAT_AUTO);
847 if (selected_cert_list_.empty()) {
848 ImportExportCleanup();
850 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE),
851 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CERT_PARSE_ERROR));
855 net::NSSCertDatabase::ImportCertFailureList not_imported;
856 // TODO(mattm): Add UI for trust. http://crbug.com/76274
857 bool result = certificate_manager_model_->ImportServerCert(
859 net::NSSCertDatabase::TRUST_DEFAULT,
863 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE),
864 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
865 } else if (!not_imported.empty()) {
867 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE),
870 ImportExportCleanup();
873 void CertificateManagerHandler::ImportCA(const base::ListValue* args) {
874 select_file_dialog_ = ui::SelectFileDialog::Create(
875 this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
876 ShowCertSelectFileDialog(select_file_dialog_.get(),
877 ui::SelectFileDialog::SELECT_OPEN_FILE,
880 reinterpret_cast<void*>(IMPORT_CA_FILE_SELECTED));
883 void CertificateManagerHandler::ImportCAFileSelected(
884 const base::FilePath& path) {
886 file_access_provider_->StartRead(
888 base::Bind(&CertificateManagerHandler::ImportCAFileRead,
889 base::Unretained(this)),
893 void CertificateManagerHandler::ImportCAFileRead(const int* read_errno,
894 const std::string* data) {
896 ImportExportCleanup();
898 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE),
899 l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT,
900 UTF8ToUTF16(safe_strerror(*read_errno))));
904 selected_cert_list_ = net::X509Certificate::CreateCertificateListFromBytes(
905 data->data(), data->size(), net::X509Certificate::FORMAT_AUTO);
906 if (selected_cert_list_.empty()) {
907 ImportExportCleanup();
909 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE),
910 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CERT_PARSE_ERROR));
914 scoped_refptr<net::X509Certificate> root_cert =
915 certificate_manager_model_->cert_db()->FindRootInList(
916 selected_cert_list_);
918 // TODO(mattm): check here if root_cert is not a CA cert and show error.
920 base::StringValue cert_name(root_cert->subject().GetDisplayName());
921 web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.showImport",
925 void CertificateManagerHandler::ImportCATrustSelected(
926 const base::ListValue* args) {
928 bool trust_ssl = false;
929 bool trust_email = false;
930 bool trust_obj_sign = false;
931 fail |= !CallbackArgsToBool(args, 0, &trust_ssl);
932 fail |= !CallbackArgsToBool(args, 1, &trust_email);
933 fail |= !CallbackArgsToBool(args, 2, &trust_obj_sign);
935 LOG(ERROR) << "ImportCATrustSelected args fail";
936 ImportExportCleanup();
937 web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
941 // TODO(mattm): add UI for setting explicit distrust, too.
942 // http://crbug.com/128411
943 net::NSSCertDatabase::ImportCertFailureList not_imported;
944 bool result = certificate_manager_model_->ImportCACerts(
946 trust_ssl * net::NSSCertDatabase::TRUSTED_SSL +
947 trust_email * net::NSSCertDatabase::TRUSTED_EMAIL +
948 trust_obj_sign * net::NSSCertDatabase::TRUSTED_OBJ_SIGN,
950 web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
953 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE),
954 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
955 } else if (!not_imported.empty()) {
957 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE),
960 ImportExportCleanup();
963 void CertificateManagerHandler::Export(const base::ListValue* args) {
964 net::X509Certificate* cert = cert_id_map_->CallbackArgsToCert(args);
967 ShowCertExportDialog(web_ui()->GetWebContents(), GetParentWindow(),
968 cert->os_cert_handle());
971 void CertificateManagerHandler::Delete(const base::ListValue* args) {
972 net::X509Certificate* cert = cert_id_map_->CallbackArgsToCert(args);
975 bool result = certificate_manager_model_->Delete(cert);
977 // TODO(mattm): better error messages?
979 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_DELETE_CERT_ERROR_TITLE),
980 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
984 void CertificateManagerHandler::OnCertificateManagerModelCreated(
985 scoped_ptr<CertificateManagerModel> model) {
986 certificate_manager_model_ = model.Pass();
987 CertificateManagerModelReady();
990 void CertificateManagerHandler::CertificateManagerModelReady() {
991 base::FundamentalValue tpm_available_value(
992 certificate_manager_model_->is_tpm_available());
993 web_ui()->CallJavascriptFunction("CertificateManager.onModelReady",
994 tpm_available_value);
995 certificate_manager_model_->Refresh();
998 void CertificateManagerHandler::Populate(const base::ListValue* args) {
999 if (certificate_manager_model_) {
1000 // Already have a model, the webui must be re-loading. Just re-run the
1001 // webui initialization.
1002 CertificateManagerModelReady();
1006 if (!requested_certificate_manager_model_) {
1007 // Request that a model be created.
1008 CertificateManagerModel::Create(
1009 Profile::FromWebUI(web_ui()),
1011 base::Bind(&CertificateManagerHandler::OnCertificateManagerModelCreated,
1012 weak_ptr_factory_.GetWeakPtr()));
1013 requested_certificate_manager_model_ = true;
1017 // We are already waiting for a CertificateManagerModel to be created, no need
1021 void CertificateManagerHandler::PopulateTree(
1022 const std::string& tab_name,
1024 const net::CertificateList& web_trust_certs) {
1025 const std::string tree_name = tab_name + "-tree";
1027 scoped_ptr<icu::Collator> collator;
1028 UErrorCode error = U_ZERO_ERROR;
1030 icu::Collator::createInstance(
1031 icu::Locale(g_browser_process->GetApplicationLocale().c_str()),
1033 if (U_FAILURE(error))
1034 collator.reset(NULL);
1035 DictionaryIdComparator comparator(collator.get());
1036 CertificateManagerModel::OrgGroupingMap map;
1038 certificate_manager_model_->FilterAndBuildOrgGroupingMap(type, &map);
1041 base::ListValue* nodes = new base::ListValue;
1042 for (CertificateManagerModel::OrgGroupingMap::iterator i = map.begin();
1043 i != map.end(); ++i) {
1044 // Populate first level (org name).
1045 base::DictionaryValue* dict = new base::DictionaryValue;
1046 dict->SetString(kKeyId, OrgNameToId(i->first));
1047 dict->SetString(kNameId, i->first);
1049 // Populate second level (certs).
1050 base::ListValue* subnodes = new base::ListValue;
1051 for (net::CertificateList::const_iterator org_cert_it = i->second.begin();
1052 org_cert_it != i->second.end(); ++org_cert_it) {
1053 base::DictionaryValue* cert_dict = new base::DictionaryValue;
1054 net::X509Certificate* cert = org_cert_it->get();
1055 cert_dict->SetString(kKeyId, cert_id_map_->CertToId(cert));
1056 cert_dict->SetString(kNameId, certificate_manager_model_->GetColumnText(
1057 *cert, CertificateManagerModel::COL_SUBJECT_NAME));
1058 cert_dict->SetBoolean(
1060 certificate_manager_model_->cert_db()->IsReadOnly(cert));
1061 // Policy-installed certificates with web trust are trusted.
1062 bool policy_trusted =
1063 IsPolicyInstalledWithWebTrust(web_trust_certs, cert);
1064 cert_dict->SetBoolean(
1067 certificate_manager_model_->cert_db()->IsUntrusted(cert));
1068 cert_dict->SetBoolean(kPolicyTrustedId, policy_trusted);
1069 // TODO(hshi): This should be determined by testing for PKCS #11
1070 // CKA_EXTRACTABLE attribute. We may need to use the NSS function
1071 // PK11_ReadRawAttribute to do that.
1072 cert_dict->SetBoolean(
1074 !certificate_manager_model_->IsHardwareBacked(cert));
1075 // TODO(mattm): Other columns.
1076 subnodes->Append(cert_dict);
1078 std::sort(subnodes->begin(), subnodes->end(), comparator);
1080 dict->Set(kSubNodesId, subnodes);
1081 nodes->Append(dict);
1083 std::sort(nodes->begin(), nodes->end(), comparator);
1085 base::ListValue args;
1086 args.Append(new base::StringValue(tree_name));
1088 web_ui()->CallJavascriptFunction("CertificateManager.onPopulateTree", args);
1092 void CertificateManagerHandler::ShowError(const std::string& title,
1093 const std::string& error) const {
1094 ScopedVector<const base::Value> args;
1095 args.push_back(new base::StringValue(title));
1096 args.push_back(new base::StringValue(error));
1097 args.push_back(new base::StringValue(l10n_util::GetStringUTF8(IDS_OK)));
1098 args.push_back(base::Value::CreateNullValue()); // cancelTitle
1099 args.push_back(base::Value::CreateNullValue()); // okCallback
1100 args.push_back(base::Value::CreateNullValue()); // cancelCallback
1101 web_ui()->CallJavascriptFunction("AlertOverlay.show", args.get());
1104 void CertificateManagerHandler::ShowImportErrors(
1105 const std::string& title,
1106 const net::NSSCertDatabase::ImportCertFailureList& not_imported) const {
1108 if (selected_cert_list_.size() == 1)
1109 error = l10n_util::GetStringUTF8(
1110 IDS_CERT_MANAGER_IMPORT_SINGLE_NOT_IMPORTED);
1111 else if (not_imported.size() == selected_cert_list_.size())
1112 error = l10n_util::GetStringUTF8(IDS_CERT_MANAGER_IMPORT_ALL_NOT_IMPORTED);
1114 error = l10n_util::GetStringUTF8(IDS_CERT_MANAGER_IMPORT_SOME_NOT_IMPORTED);
1116 base::ListValue cert_error_list;
1117 for (size_t i = 0; i < not_imported.size(); ++i) {
1118 const net::NSSCertDatabase::ImportCertFailure& failure = not_imported[i];
1119 base::DictionaryValue* dict = new base::DictionaryValue;
1120 dict->SetString(kNameId, failure.certificate->subject().GetDisplayName());
1121 dict->SetString(kErrorId, NetErrorToString(failure.net_error));
1122 cert_error_list.Append(dict);
1125 base::StringValue title_value(title);
1126 base::StringValue error_value(error);
1127 web_ui()->CallJavascriptFunction("CertificateImportErrorOverlay.show",
1133 gfx::NativeWindow CertificateManagerHandler::GetParentWindow() const {
1134 return web_ui()->GetWebContents()->GetView()->GetTopLevelNativeWindow();
1137 } // namespace options