1// Copyright (c) 2011 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.
4
5#include "chrome/browser/ui/webui/options/certificate_manager_handler.h"
6
7#include "base/file_util.h"  // for FileAccessProvider
8#include "base/memory/scoped_vector.h"
9#include "base/safe_strerror_posix.h"
10#include "base/string_number_conversions.h"
11#include "base/values.h"
12#include "chrome/browser/browser_process.h"
13#include "chrome/browser/ui/crypto_module_password_dialog.h"
14#include "chrome/browser/ui/gtk/certificate_dialogs.h"
15#include "content/browser/browser_thread.h"  // for FileAccessProvider
16#include "content/browser/certificate_viewer.h"
17#include "content/browser/tab_contents/tab_contents.h"
18#include "content/browser/tab_contents/tab_contents_view.h"
19#include "grit/generated_resources.h"
20#include "net/base/crypto_module.h"
21#include "net/base/x509_certificate.h"
22#include "ui/base/l10n/l10n_util.h"
23#include "ui/base/l10n/l10n_util_collator.h"
24
25#if defined(OS_CHROMEOS)
26#include "chrome/browser/chromeos/cros/cros_library.h"
27#include "chrome/browser/chromeos/cros/cryptohome_library.h"
28#endif
29
30namespace {
31
32static const char kKeyId[] = "id";
33static const char kSubNodesId[] = "subnodes";
34static const char kNameId[] = "name";
35static const char kReadOnlyId[] = "readonly";
36static const char kIconId[] = "icon";
37static const char kSecurityDeviceId[] = "device";
38static const char kErrorId[] = "error";
39
40// Enumeration of different callers of SelectFile.  (Start counting at 1 so
41// if SelectFile is accidentally called with params=NULL it won't match any.)
42enum {
43  EXPORT_PERSONAL_FILE_SELECTED = 1,
44  IMPORT_PERSONAL_FILE_SELECTED,
45  IMPORT_SERVER_FILE_SELECTED,
46  IMPORT_CA_FILE_SELECTED,
47};
48
49// TODO(mattm): These are duplicated from cookies_view_handler.cc
50// Encodes a pointer value into a hex string.
51std::string PointerToHexString(const void* pointer) {
52  return base::HexEncode(&pointer, sizeof(pointer));
53}
54
55// Decodes a pointer from a hex string.
56void* HexStringToPointer(const std::string& str) {
57  std::vector<uint8> buffer;
58  if (!base::HexStringToBytes(str, &buffer) ||
59      buffer.size() != sizeof(void*)) {
60    return NULL;
61  }
62
63  return *reinterpret_cast<void**>(&buffer[0]);
64}
65
66std::string OrgNameToId(const std::string& org) {
67  return "org-" + org;
68}
69
70std::string CertToId(const net::X509Certificate& cert) {
71  return "cert-" + PointerToHexString(&cert);
72}
73
74net::X509Certificate* IdToCert(const std::string& id) {
75  if (!StartsWithASCII(id, "cert-", true))
76    return NULL;
77  return reinterpret_cast<net::X509Certificate*>(
78      HexStringToPointer(id.substr(5)));
79}
80
81net::X509Certificate* CallbackArgsToCert(const ListValue* args) {
82  std::string node_id;
83  if (!args->GetString(0, &node_id)){
84    return NULL;
85  }
86  net::X509Certificate* cert = IdToCert(node_id);
87  if (!cert) {
88    NOTREACHED();
89    return NULL;
90  }
91  return cert;
92}
93
94bool CallbackArgsToBool(const ListValue* args, int index, bool* result) {
95  std::string string_value;
96  if (!args->GetString(index, &string_value))
97    return false;
98
99  *result = string_value[0] == 't';
100  return true;
101}
102
103struct DictionaryIdComparator {
104  explicit DictionaryIdComparator(icu::Collator* collator)
105      : collator_(collator) {
106  }
107
108  bool operator()(const Value* a,
109                  const Value* b) const {
110    DCHECK(a->GetType() == Value::TYPE_DICTIONARY);
111    DCHECK(b->GetType() == Value::TYPE_DICTIONARY);
112    const DictionaryValue* a_dict = reinterpret_cast<const DictionaryValue*>(a);
113    const DictionaryValue* b_dict = reinterpret_cast<const DictionaryValue*>(b);
114    string16 a_str;
115    string16 b_str;
116    a_dict->GetString(kNameId, &a_str);
117    b_dict->GetString(kNameId, &b_str);
118    if (collator_ == NULL)
119      return a_str < b_str;
120    return l10n_util::CompareString16WithCollator(
121        collator_, a_str, b_str) == UCOL_LESS;
122  }
123
124  icu::Collator* collator_;
125};
126
127std::string NetErrorToString(int net_error) {
128  switch (net_error) {
129    // TODO(mattm): handle more cases.
130    case net::ERR_IMPORT_CA_CERT_NOT_CA:
131      return l10n_util::GetStringUTF8(IDS_CERT_MANAGER_ERROR_NOT_CA);
132    default:
133      return l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR);
134  }
135}
136
137}  // namespace
138
139///////////////////////////////////////////////////////////////////////////////
140//  FileAccessProvider
141
142// TODO(mattm): Move to some shared location?
143class FileAccessProvider
144    : public base::RefCountedThreadSafe<FileAccessProvider>,
145      public CancelableRequestProvider {
146 public:
147  // Reports 0 on success or errno on failure, and the data of the file upon
148  // success.
149  // TODO(mattm): don't pass std::string by value.. could use RefCountedBytes
150  // but it's a vector.  Maybe do the derive from CancelableRequest thing
151  // described in cancelable_request.h?
152  typedef Callback2<int, std::string>::Type ReadCallback;
153
154  // Reports 0 on success or errno on failure, and the number of bytes written,
155  // on success.
156  typedef Callback2<int, int>::Type WriteCallback;
157
158  Handle StartRead(const FilePath& path,
159                   CancelableRequestConsumerBase* consumer,
160                   ReadCallback* callback);
161  Handle StartWrite(const FilePath& path,
162                    const std::string& data,
163                    CancelableRequestConsumerBase* consumer,
164                    WriteCallback* callback);
165
166 private:
167  void DoRead(scoped_refptr<CancelableRequest<ReadCallback> > request,
168              FilePath path);
169  void DoWrite(scoped_refptr<CancelableRequest<WriteCallback> > request,
170              FilePath path,
171              std::string data);
172};
173
174CancelableRequestProvider::Handle FileAccessProvider::StartRead(
175    const FilePath& path,
176    CancelableRequestConsumerBase* consumer,
177    FileAccessProvider::ReadCallback* callback) {
178  scoped_refptr<CancelableRequest<ReadCallback> > request(
179      new CancelableRequest<ReadCallback>(callback));
180  AddRequest(request, consumer);
181
182  // Send the parameters and the request to the file thread.
183  BrowserThread::PostTask(
184      BrowserThread::FILE, FROM_HERE,
185      NewRunnableMethod(this, &FileAccessProvider::DoRead, request, path));
186
187  // The handle will have been set by AddRequest.
188  return request->handle();
189}
190
191CancelableRequestProvider::Handle FileAccessProvider::StartWrite(
192    const FilePath& path,
193    const std::string& data,
194    CancelableRequestConsumerBase* consumer,
195    WriteCallback* callback) {
196  scoped_refptr<CancelableRequest<WriteCallback> > request(
197      new CancelableRequest<WriteCallback>(callback));
198  AddRequest(request, consumer);
199
200  // Send the parameters and the request to the file thWrite.
201  BrowserThread::PostTask(
202      BrowserThread::FILE, FROM_HERE,
203      NewRunnableMethod(
204          this, &FileAccessProvider::DoWrite, request, path, data));
205
206  // The handle will have been set by AddRequest.
207  return request->handle();
208}
209
210void FileAccessProvider::DoRead(
211    scoped_refptr<CancelableRequest<ReadCallback> > request,
212    FilePath path) {
213  if (request->canceled())
214    return;
215
216  std::string data;
217  VLOG(1) << "DoRead starting read";
218  bool success = file_util::ReadFileToString(path, &data);
219  int saved_errno = success ? 0 : errno;
220  VLOG(1) << "DoRead done read: " << success << " " << data.size();
221  request->ForwardResult(ReadCallback::TupleType(saved_errno, data));
222}
223
224void FileAccessProvider::DoWrite(
225    scoped_refptr<CancelableRequest<WriteCallback> > request,
226    FilePath path,
227    std::string data) {
228  VLOG(1) << "DoWrite starting write";
229  int bytes_written = file_util::WriteFile(path, data.data(), data.size());
230  int saved_errno = bytes_written >= 0 ? 0 : errno;
231  VLOG(1) << "DoWrite done write " << bytes_written;
232
233  if (request->canceled())
234    return;
235
236  request->ForwardResult(WriteCallback::TupleType(saved_errno, bytes_written));
237}
238
239///////////////////////////////////////////////////////////////////////////////
240//  CertificateManagerHandler
241
242CertificateManagerHandler::CertificateManagerHandler()
243    : file_access_provider_(new FileAccessProvider) {
244  certificate_manager_model_.reset(new CertificateManagerModel(this));
245}
246
247CertificateManagerHandler::~CertificateManagerHandler() {
248}
249
250void CertificateManagerHandler::GetLocalizedValues(
251    DictionaryValue* localized_strings) {
252  DCHECK(localized_strings);
253
254  RegisterTitle(localized_strings, "certificateManagerPage",
255                IDS_CERTIFICATE_MANAGER_TITLE);
256
257  // Tabs.
258  localized_strings->SetString("personalCertsTabTitle",
259      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PERSONAL_CERTS_TAB_LABEL));
260  localized_strings->SetString("serverCertsTabTitle",
261      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_SERVER_CERTS_TAB_LABEL));
262  localized_strings->SetString("caCertsTabTitle",
263      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_CERT_AUTHORITIES_TAB_LABEL));
264  localized_strings->SetString("unknownCertsTabTitle",
265      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_UNKNOWN_TAB_LABEL));
266
267  // Tab descriptions.
268  localized_strings->SetString("personalCertsTabDescription",
269      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_USER_TREE_DESCRIPTION));
270  localized_strings->SetString("serverCertsTabDescription",
271      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_SERVER_TREE_DESCRIPTION));
272  localized_strings->SetString("caCertsTabDescription",
273      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_AUTHORITIES_TREE_DESCRIPTION));
274  localized_strings->SetString("unknownCertsTabDescription",
275      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_UNKNOWN_TREE_DESCRIPTION));
276
277  // Tree columns.
278  localized_strings->SetString("certNameColumn",
279      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_NAME_COLUMN_LABEL));
280  localized_strings->SetString("certDeviceColumn",
281      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DEVICE_COLUMN_LABEL));
282  localized_strings->SetString("certSerialColumn",
283      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_SERIAL_NUMBER_COLUMN_LABEL));
284  localized_strings->SetString("certExpiresColumn",
285      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPIRES_COLUMN_LABEL));
286
287  // Buttons.
288  localized_strings->SetString("view_certificate",
289      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_VIEW_CERT_BUTTON));
290  localized_strings->SetString("import_certificate",
291      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_IMPORT_BUTTON));
292  localized_strings->SetString("export_certificate",
293      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_BUTTON));
294  localized_strings->SetString("export_all_certificates",
295      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_ALL_BUTTON));
296  localized_strings->SetString("edit_certificate",
297      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_BUTTON));
298  localized_strings->SetString("delete_certificate",
299      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_BUTTON));
300
301  // Certificate Delete overlay strings.
302  localized_strings->SetString("personalCertsTabDeleteConfirm",
303      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_USER_FORMAT));
304  localized_strings->SetString("personalCertsTabDeleteImpact",
305      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_USER_DESCRIPTION));
306  localized_strings->SetString("serverCertsTabDeleteConfirm",
307      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_SERVER_FORMAT));
308  localized_strings->SetString("serverCertsTabDeleteImpact",
309      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_SERVER_DESCRIPTION));
310  localized_strings->SetString("caCertsTabDeleteConfirm",
311      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_CA_FORMAT));
312  localized_strings->SetString("caCertsTabDeleteImpact",
313      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_CA_DESCRIPTION));
314  localized_strings->SetString("unknownCertsTabDeleteConfirm",
315      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_DELETE_UNKNOWN_FORMAT));
316  localized_strings->SetString("unknownCertsTabDeleteImpact", "");
317
318  // Certificate Restore overlay strings.
319  localized_strings->SetString("certificateRestorePasswordDescription",
320      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_RESTORE_PASSWORD_DESC));
321  localized_strings->SetString("certificatePasswordLabel",
322      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PASSWORD_LABEL));
323
324  // Personal Certificate Export overlay strings.
325  localized_strings->SetString("certificateExportPasswordDescription",
326      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_PASSWORD_DESC));
327  localized_strings->SetString("certificateExportPasswordHelp",
328      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EXPORT_PASSWORD_HELP));
329  localized_strings->SetString("certificateConfirmPasswordLabel",
330      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_CONFIRM_PASSWORD_LABEL));
331
332  // Edit CA Trust & Import CA overlay strings.
333  localized_strings->SetString("certificateEditTrustLabel",
334      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_TRUST_LABEL));
335  localized_strings->SetString("certificateEditCaTrustDescriptionFormat",
336      l10n_util::GetStringUTF16(
337          IDS_CERT_MANAGER_EDIT_CA_TRUST_DESCRIPTION_FORMAT));
338  localized_strings->SetString("certificateImportCaDescriptionFormat",
339      l10n_util::GetStringUTF16(
340          IDS_CERT_MANAGER_IMPORT_CA_DESCRIPTION_FORMAT));
341  localized_strings->SetString("certificateCaTrustSSLLabel",
342      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_CA_TRUST_SSL_LABEL));
343  localized_strings->SetString("certificateCaTrustEmailLabel",
344      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_CA_TRUST_EMAIL_LABEL));
345  localized_strings->SetString("certificateCaTrustObjSignLabel",
346      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_EDIT_CA_TRUST_OBJSIGN_LABEL));
347  localized_strings->SetString("certificateImportErrorFormat",
348      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_IMPORT_ERROR_FORMAT));
349
350#if defined(OS_CHROMEOS)
351  localized_strings->SetString("importAndBindCertificate",
352      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_IMPORT_AND_BIND_BUTTON));
353  localized_strings->SetString("hardwareBackedKeyFormat",
354      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_HARDWARE_BACKED_KEY_FORMAT));
355  localized_strings->SetString("chromeOSDeviceName",
356      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_HARDWARE_BACKED));
357#endif  // defined(OS_CHROMEOS)
358}
359
360void CertificateManagerHandler::RegisterMessages() {
361  web_ui_->RegisterMessageCallback("viewCertificate",
362      NewCallback(this, &CertificateManagerHandler::View));
363
364  web_ui_->RegisterMessageCallback("getCaCertificateTrust",
365      NewCallback(this, &CertificateManagerHandler::GetCATrust));
366  web_ui_->RegisterMessageCallback("editCaCertificateTrust",
367      NewCallback(this, &CertificateManagerHandler::EditCATrust));
368
369  web_ui_->RegisterMessageCallback("editServerCertificate",
370      NewCallback(this, &CertificateManagerHandler::EditServer));
371
372  web_ui_->RegisterMessageCallback("cancelImportExportCertificate",
373      NewCallback(this, &CertificateManagerHandler::CancelImportExportProcess));
374
375  web_ui_->RegisterMessageCallback("exportPersonalCertificate",
376      NewCallback(this, &CertificateManagerHandler::ExportPersonal));
377  web_ui_->RegisterMessageCallback("exportAllPersonalCertificates",
378      NewCallback(this, &CertificateManagerHandler::ExportAllPersonal));
379  web_ui_->RegisterMessageCallback("exportPersonalCertificatePasswordSelected",
380      NewCallback(this,
381                  &CertificateManagerHandler::ExportPersonalPasswordSelected));
382
383  web_ui_->RegisterMessageCallback("importPersonalCertificate",
384      NewCallback(this, &CertificateManagerHandler::StartImportPersonal));
385  web_ui_->RegisterMessageCallback("importPersonalCertificatePasswordSelected",
386      NewCallback(this,
387                  &CertificateManagerHandler::ImportPersonalPasswordSelected));
388
389  web_ui_->RegisterMessageCallback("importCaCertificate",
390      NewCallback(this, &CertificateManagerHandler::ImportCA));
391  web_ui_->RegisterMessageCallback("importCaCertificateTrustSelected",
392      NewCallback(this, &CertificateManagerHandler::ImportCATrustSelected));
393
394  web_ui_->RegisterMessageCallback("importServerCertificate",
395      NewCallback(this, &CertificateManagerHandler::ImportServer));
396
397  web_ui_->RegisterMessageCallback("exportCertificate",
398      NewCallback(this, &CertificateManagerHandler::Export));
399
400  web_ui_->RegisterMessageCallback("deleteCertificate",
401      NewCallback(this, &CertificateManagerHandler::Delete));
402
403  web_ui_->RegisterMessageCallback("populateCertificateManager",
404      NewCallback(this, &CertificateManagerHandler::Populate));
405
406#if defined(OS_CHROMEOS)
407  web_ui_->RegisterMessageCallback("checkTpmTokenReady",
408      NewCallback(this, &CertificateManagerHandler::CheckTpmTokenReady));
409#endif
410}
411
412void CertificateManagerHandler::CertificatesRefreshed() {
413  PopulateTree("personalCertsTab", net::USER_CERT);
414  PopulateTree("serverCertsTab", net::SERVER_CERT);
415  PopulateTree("caCertsTab", net::CA_CERT);
416  PopulateTree("otherCertsTab", net::UNKNOWN_CERT);
417  VLOG(1) << "populating finished";
418}
419
420void CertificateManagerHandler::FileSelected(const FilePath& path, int index,
421                                             void* params) {
422  switch (reinterpret_cast<intptr_t>(params)) {
423    case EXPORT_PERSONAL_FILE_SELECTED:
424      ExportPersonalFileSelected(path);
425      break;
426    case IMPORT_PERSONAL_FILE_SELECTED:
427      ImportPersonalFileSelected(path);
428      break;
429    case IMPORT_SERVER_FILE_SELECTED:
430      ImportServerFileSelected(path);
431      break;
432    case IMPORT_CA_FILE_SELECTED:
433      ImportCAFileSelected(path);
434      break;
435    default:
436      NOTREACHED();
437  }
438}
439
440void CertificateManagerHandler::FileSelectionCanceled(void* params) {
441  switch (reinterpret_cast<intptr_t>(params)) {
442    case EXPORT_PERSONAL_FILE_SELECTED:
443    case IMPORT_PERSONAL_FILE_SELECTED:
444    case IMPORT_SERVER_FILE_SELECTED:
445    case IMPORT_CA_FILE_SELECTED:
446      ImportExportCleanup();
447      break;
448    default:
449      NOTREACHED();
450  }
451}
452
453void CertificateManagerHandler::View(const ListValue* args) {
454  net::X509Certificate* cert = CallbackArgsToCert(args);
455  if (!cert)
456    return;
457  ShowCertificateViewer(GetParentWindow(), cert);
458}
459
460void CertificateManagerHandler::GetCATrust(const ListValue* args) {
461  net::X509Certificate* cert = CallbackArgsToCert(args);
462  if (!cert) {
463    web_ui_->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
464    return;
465  }
466
467  int trust = certificate_manager_model_->cert_db().GetCertTrust(
468      cert, net::CA_CERT);
469  FundamentalValue ssl_value(bool(trust & net::CertDatabase::TRUSTED_SSL));
470  FundamentalValue email_value(bool(trust & net::CertDatabase::TRUSTED_EMAIL));
471  FundamentalValue obj_sign_value(
472      bool(trust & net::CertDatabase::TRUSTED_OBJ_SIGN));
473  web_ui_->CallJavascriptFunction(
474      "CertificateEditCaTrustOverlay.populateTrust",
475      ssl_value, email_value, obj_sign_value);
476}
477
478void CertificateManagerHandler::EditCATrust(const ListValue* args) {
479  net::X509Certificate* cert = CallbackArgsToCert(args);
480  bool fail = !cert;
481  bool trust_ssl = false;
482  bool trust_email = false;
483  bool trust_obj_sign = false;
484  fail |= !CallbackArgsToBool(args, 1, &trust_ssl);
485  fail |= !CallbackArgsToBool(args, 2, &trust_email);
486  fail |= !CallbackArgsToBool(args, 3, &trust_obj_sign);
487  if (fail) {
488    LOG(ERROR) << "EditCATrust args fail";
489    web_ui_->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
490    return;
491  }
492
493  bool result = certificate_manager_model_->SetCertTrust(
494      cert,
495      net::CA_CERT,
496      trust_ssl * net::CertDatabase::TRUSTED_SSL +
497          trust_email * net::CertDatabase::TRUSTED_EMAIL +
498          trust_obj_sign * net::CertDatabase::TRUSTED_OBJ_SIGN);
499  web_ui_->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
500  if (!result) {
501    // TODO(mattm): better error messages?
502    ShowError(
503        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SET_TRUST_ERROR_TITLE),
504        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
505  }
506}
507
508void CertificateManagerHandler::EditServer(const ListValue* args) {
509  NOTIMPLEMENTED();
510}
511
512void CertificateManagerHandler::ExportPersonal(const ListValue* args) {
513  net::X509Certificate* cert = CallbackArgsToCert(args);
514  if (!cert)
515    return;
516
517  selected_cert_list_.push_back(cert);
518
519  SelectFileDialog::FileTypeInfo file_type_info;
520  file_type_info.extensions.resize(1);
521  file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("p12"));
522  file_type_info.extension_description_overrides.push_back(
523      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PKCS12_FILES));
524  file_type_info.include_all_files = true;
525  select_file_dialog_ = SelectFileDialog::Create(this);
526  select_file_dialog_->SelectFile(
527      SelectFileDialog::SELECT_SAVEAS_FILE, string16(),
528      FilePath(), &file_type_info, 1, FILE_PATH_LITERAL("p12"),
529      web_ui_->tab_contents(), GetParentWindow(),
530      reinterpret_cast<void*>(EXPORT_PERSONAL_FILE_SELECTED));
531}
532
533void CertificateManagerHandler::ExportAllPersonal(const ListValue* args) {
534  NOTIMPLEMENTED();
535}
536
537void CertificateManagerHandler::ExportPersonalFileSelected(
538    const FilePath& path) {
539  file_path_ = path;
540  web_ui_->CallJavascriptFunction(
541      "CertificateManager.exportPersonalAskPassword");
542}
543
544void CertificateManagerHandler::ExportPersonalPasswordSelected(
545    const ListValue* args) {
546  if (!args->GetString(0, &password_)){
547    web_ui_->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
548    ImportExportCleanup();
549    return;
550  }
551
552  // Currently, we don't support exporting more than one at a time.  If we do,
553  // this would need to either change this to use UnlockSlotsIfNecessary or
554  // change UnlockCertSlotIfNecessary to take a CertificateList.
555  DCHECK_EQ(selected_cert_list_.size(), 1U);
556
557  // TODO(mattm): do something smarter about non-extractable keys
558  browser::UnlockCertSlotIfNecessary(
559      selected_cert_list_[0].get(),
560      browser::kCryptoModulePasswordCertExport,
561      "",  // unused.
562      NewCallback(this,
563                  &CertificateManagerHandler::ExportPersonalSlotsUnlocked));
564}
565
566void CertificateManagerHandler::ExportPersonalSlotsUnlocked() {
567  std::string output;
568  int num_exported = certificate_manager_model_->cert_db().ExportToPKCS12(
569      selected_cert_list_,
570      password_,
571      &output);
572  if (!num_exported) {
573    web_ui_->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
574    ShowError(
575        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_EXPORT_ERROR_TITLE),
576        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
577    ImportExportCleanup();
578    return;
579  }
580  file_access_provider_->StartWrite(
581      file_path_,
582      output,
583      &consumer_,
584      NewCallback(this, &CertificateManagerHandler::ExportPersonalFileWritten));
585}
586
587void CertificateManagerHandler::ExportPersonalFileWritten(int write_errno,
588                                                          int bytes_written) {
589  web_ui_->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
590  ImportExportCleanup();
591  if (write_errno) {
592    ShowError(
593        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_EXPORT_ERROR_TITLE),
594        l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_WRITE_ERROR_FORMAT,
595                                  UTF8ToUTF16(safe_strerror(write_errno))));
596  }
597}
598
599void CertificateManagerHandler::StartImportPersonal(const ListValue* args) {
600  SelectFileDialog::FileTypeInfo file_type_info;
601  if (!args->GetBoolean(0, &use_hardware_backed_)){
602    // Unable to retrieve the hardware backed attribute from the args,
603    // so bail.
604    web_ui_->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
605    ImportExportCleanup();
606    return;
607  }
608  file_type_info.extensions.resize(1);
609  file_type_info.extensions[0].push_back(FILE_PATH_LITERAL("p12"));
610  file_type_info.extension_description_overrides.push_back(
611      l10n_util::GetStringUTF16(IDS_CERT_MANAGER_PKCS12_FILES));
612  file_type_info.include_all_files = true;
613  select_file_dialog_ = SelectFileDialog::Create(this);
614  select_file_dialog_->SelectFile(
615      SelectFileDialog::SELECT_OPEN_FILE, string16(),
616      FilePath(), &file_type_info, 1, FILE_PATH_LITERAL("p12"),
617      web_ui_->tab_contents(), GetParentWindow(),
618      reinterpret_cast<void*>(IMPORT_PERSONAL_FILE_SELECTED));
619}
620
621void CertificateManagerHandler::ImportPersonalFileSelected(
622    const FilePath& path) {
623  file_path_ = path;
624  web_ui_->CallJavascriptFunction(
625      "CertificateManager.importPersonalAskPassword");
626}
627
628void CertificateManagerHandler::ImportPersonalPasswordSelected(
629    const ListValue* args) {
630  if (!args->GetString(0, &password_)){
631    web_ui_->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
632    ImportExportCleanup();
633    return;
634  }
635  file_access_provider_->StartRead(
636      file_path_,
637      &consumer_,
638      NewCallback(this, &CertificateManagerHandler::ImportPersonalFileRead));
639}
640
641void CertificateManagerHandler::ImportPersonalFileRead(
642    int read_errno, std::string data) {
643  if (read_errno) {
644    ImportExportCleanup();
645    web_ui_->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
646    ShowError(
647        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_IMPORT_ERROR_TITLE),
648        l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT,
649                                  UTF8ToUTF16(safe_strerror(read_errno))));
650    return;
651  }
652
653  file_data_ = data;
654
655  if (use_hardware_backed_) {
656    module_ = certificate_manager_model_->cert_db().GetPrivateModule();
657  } else {
658    module_ = certificate_manager_model_->cert_db().GetPublicModule();
659  }
660
661  net::CryptoModuleList modules;
662  modules.push_back(module_);
663  browser::UnlockSlotsIfNecessary(
664      modules,
665      browser::kCryptoModulePasswordCertImport,
666      "",  // unused.
667      NewCallback(this,
668                  &CertificateManagerHandler::ImportPersonalSlotUnlocked));
669}
670
671void CertificateManagerHandler::ImportPersonalSlotUnlocked() {
672  int result = certificate_manager_model_->ImportFromPKCS12(
673      module_, file_data_, password_);
674  ImportExportCleanup();
675  web_ui_->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
676  switch (result) {
677    case net::OK:
678      break;
679    case net::ERR_PKCS12_IMPORT_BAD_PASSWORD:
680      ShowError(
681          l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_IMPORT_ERROR_TITLE),
682          l10n_util::GetStringUTF8(IDS_CERT_MANAGER_BAD_PASSWORD));
683      // TODO(mattm): if the error was a bad password, we should reshow the
684      // password dialog after the user dismisses the error dialog.
685      break;
686    default:
687      ShowError(
688          l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_IMPORT_ERROR_TITLE),
689          l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
690      break;
691  }
692}
693
694void CertificateManagerHandler::CancelImportExportProcess(
695    const ListValue* args) {
696  ImportExportCleanup();
697}
698
699void CertificateManagerHandler::ImportExportCleanup() {
700  file_path_.clear();
701  password_.clear();
702  file_data_.clear();
703  use_hardware_backed_ = false;
704  selected_cert_list_.clear();
705  module_ = NULL;
706
707  // There may be pending file dialogs, we need to tell them that we've gone
708  // away so they don't try and call back to us.
709  if (select_file_dialog_.get())
710    select_file_dialog_->ListenerDestroyed();
711  select_file_dialog_ = NULL;
712}
713
714void CertificateManagerHandler::ImportServer(const ListValue* args) {
715  select_file_dialog_ = SelectFileDialog::Create(this);
716  ShowCertSelectFileDialog(
717      select_file_dialog_.get(),
718      SelectFileDialog::SELECT_OPEN_FILE,
719      FilePath(),
720      web_ui_->tab_contents(),
721      GetParentWindow(),
722      reinterpret_cast<void*>(IMPORT_SERVER_FILE_SELECTED));
723}
724
725void CertificateManagerHandler::ImportServerFileSelected(const FilePath& path) {
726  file_path_ = path;
727  file_access_provider_->StartRead(
728      file_path_,
729      &consumer_,
730      NewCallback(this, &CertificateManagerHandler::ImportServerFileRead));
731}
732
733void CertificateManagerHandler::ImportServerFileRead(int read_errno,
734                                                     std::string data) {
735  if (read_errno) {
736    ImportExportCleanup();
737    ShowError(
738        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE),
739        l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT,
740                                  UTF8ToUTF16(safe_strerror(read_errno))));
741    return;
742  }
743
744  selected_cert_list_ = net::X509Certificate::CreateCertificateListFromBytes(
745          data.data(), data.size(), net::X509Certificate::FORMAT_AUTO);
746  if (selected_cert_list_.empty()) {
747    ImportExportCleanup();
748    ShowError(
749        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE),
750        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CERT_PARSE_ERROR));
751    return;
752  }
753
754  net::CertDatabase::ImportCertFailureList not_imported;
755  bool result = certificate_manager_model_->ImportServerCert(
756      selected_cert_list_,
757      &not_imported);
758  if (!result) {
759    ShowError(
760        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE),
761        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
762  } else if (!not_imported.empty()) {
763    ShowImportErrors(
764        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE),
765        not_imported);
766  }
767  ImportExportCleanup();
768}
769
770void CertificateManagerHandler::ImportCA(const ListValue* args) {
771  select_file_dialog_ = SelectFileDialog::Create(this);
772  ShowCertSelectFileDialog(select_file_dialog_.get(),
773                           SelectFileDialog::SELECT_OPEN_FILE,
774                           FilePath(),
775                           web_ui_->tab_contents(),
776                           GetParentWindow(),
777                           reinterpret_cast<void*>(IMPORT_CA_FILE_SELECTED));
778}
779
780void CertificateManagerHandler::ImportCAFileSelected(const FilePath& path) {
781  file_path_ = path;
782  file_access_provider_->StartRead(
783      file_path_,
784      &consumer_,
785      NewCallback(this, &CertificateManagerHandler::ImportCAFileRead));
786}
787
788void CertificateManagerHandler::ImportCAFileRead(int read_errno,
789                                                 std::string data) {
790  if (read_errno) {
791    ImportExportCleanup();
792    ShowError(
793        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE),
794        l10n_util::GetStringFUTF8(IDS_CERT_MANAGER_READ_ERROR_FORMAT,
795                                  UTF8ToUTF16(safe_strerror(read_errno))));
796    return;
797  }
798
799  selected_cert_list_ = net::X509Certificate::CreateCertificateListFromBytes(
800          data.data(), data.size(), net::X509Certificate::FORMAT_AUTO);
801  if (selected_cert_list_.empty()) {
802    ImportExportCleanup();
803    ShowError(
804        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE),
805        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CERT_PARSE_ERROR));
806    return;
807  }
808
809  scoped_refptr<net::X509Certificate> root_cert =
810      certificate_manager_model_->cert_db().FindRootInList(selected_cert_list_);
811
812  // TODO(mattm): check here if root_cert is not a CA cert and show error.
813
814  StringValue cert_name(root_cert->subject().GetDisplayName());
815  web_ui_->CallJavascriptFunction("CertificateEditCaTrustOverlay.showImport",
816                                  cert_name);
817}
818
819void CertificateManagerHandler::ImportCATrustSelected(const ListValue* args) {
820  bool fail = false;
821  bool trust_ssl = false;
822  bool trust_email = false;
823  bool trust_obj_sign = false;
824  fail |= !CallbackArgsToBool(args, 0, &trust_ssl);
825  fail |= !CallbackArgsToBool(args, 1, &trust_email);
826  fail |= !CallbackArgsToBool(args, 2, &trust_obj_sign);
827  if (fail) {
828    LOG(ERROR) << "ImportCATrustSelected args fail";
829    ImportExportCleanup();
830    web_ui_->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
831    return;
832  }
833
834  net::CertDatabase::ImportCertFailureList not_imported;
835  bool result = certificate_manager_model_->ImportCACerts(
836      selected_cert_list_,
837      trust_ssl * net::CertDatabase::TRUSTED_SSL +
838          trust_email * net::CertDatabase::TRUSTED_EMAIL +
839          trust_obj_sign * net::CertDatabase::TRUSTED_OBJ_SIGN,
840      &not_imported);
841  web_ui_->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
842  if (!result) {
843    ShowError(
844        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE),
845        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
846  } else if (!not_imported.empty()) {
847    ShowImportErrors(
848        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE),
849        not_imported);
850  }
851  ImportExportCleanup();
852}
853
854void CertificateManagerHandler::Export(const ListValue* args) {
855  net::X509Certificate* cert = CallbackArgsToCert(args);
856  if (!cert)
857    return;
858  ShowCertExportDialog(web_ui_->tab_contents(), GetParentWindow(),
859                       cert->os_cert_handle());
860}
861
862void CertificateManagerHandler::Delete(const ListValue* args) {
863  net::X509Certificate* cert = CallbackArgsToCert(args);
864  if (!cert)
865    return;
866  bool result = certificate_manager_model_->Delete(cert);
867  if (!result) {
868    // TODO(mattm): better error messages?
869    ShowError(
870        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_DELETE_CERT_ERROR_TITLE),
871        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
872  }
873}
874
875void CertificateManagerHandler::Populate(const ListValue* args) {
876  certificate_manager_model_->Refresh();
877}
878
879void CertificateManagerHandler::PopulateTree(const std::string& tab_name,
880                                             net::CertType type) {
881  const std::string tree_name = tab_name + "-tree";
882
883  scoped_ptr<icu::Collator> collator;
884  UErrorCode error = U_ZERO_ERROR;
885  collator.reset(
886      icu::Collator::createInstance(
887          icu::Locale(g_browser_process->GetApplicationLocale().c_str()),
888          error));
889  if (U_FAILURE(error))
890    collator.reset(NULL);
891  DictionaryIdComparator comparator(collator.get());
892  CertificateManagerModel::OrgGroupingMap map;
893
894  certificate_manager_model_->FilterAndBuildOrgGroupingMap(type, &map);
895
896  {
897    ListValue* nodes = new ListValue;
898    for (CertificateManagerModel::OrgGroupingMap::iterator i = map.begin();
899         i != map.end(); ++i) {
900      // Populate first level (org name).
901      DictionaryValue* dict = new DictionaryValue;
902      dict->SetString(kKeyId, OrgNameToId(i->first));
903      dict->SetString(kNameId, i->first);
904
905      // Populate second level (certs).
906      ListValue* subnodes = new ListValue;
907      for (net::CertificateList::const_iterator org_cert_it = i->second.begin();
908           org_cert_it != i->second.end(); ++org_cert_it) {
909        DictionaryValue* cert_dict = new DictionaryValue;
910        net::X509Certificate* cert = org_cert_it->get();
911        cert_dict->SetString(kKeyId, CertToId(*cert));
912        cert_dict->SetString(kNameId, certificate_manager_model_->GetColumnText(
913            *cert, CertificateManagerModel::COL_SUBJECT_NAME));
914        cert_dict->SetBoolean(
915            kReadOnlyId,
916            certificate_manager_model_->cert_db().IsReadOnly(cert));
917        // TODO(mattm): Other columns.
918        cert_dict->SetString(kIconId, "none");
919        subnodes->Append(cert_dict);
920      }
921      std::sort(subnodes->begin(), subnodes->end(), comparator);
922
923      dict->Set(kSubNodesId, subnodes);
924      nodes->Append(dict);
925    }
926    std::sort(nodes->begin(), nodes->end(), comparator);
927
928    ListValue args;
929    args.Append(Value::CreateStringValue(tree_name));
930    args.Append(nodes);
931    web_ui_->CallJavascriptFunction("CertificateManager.onPopulateTree", args);
932  }
933}
934
935void CertificateManagerHandler::ShowError(const std::string& title,
936                                          const std::string& error) const {
937  ScopedVector<const Value> args;
938  args.push_back(Value::CreateStringValue(title));
939  args.push_back(Value::CreateStringValue(error));
940  args.push_back(Value::CreateStringValue(l10n_util::GetStringUTF8(IDS_OK)));
941  args.push_back(Value::CreateNullValue());  // cancelTitle
942  args.push_back(Value::CreateNullValue());  // okCallback
943  args.push_back(Value::CreateNullValue());  // cancelCallback
944  web_ui_->CallJavascriptFunction("AlertOverlay.show", args.get());
945}
946
947void CertificateManagerHandler::ShowImportErrors(
948    const std::string& title,
949    const net::CertDatabase::ImportCertFailureList& not_imported) const {
950  std::string error;
951  if (selected_cert_list_.size() == 1)
952    error = l10n_util::GetStringUTF8(
953        IDS_CERT_MANAGER_IMPORT_SINGLE_NOT_IMPORTED);
954  else if (not_imported.size() == selected_cert_list_.size())
955    error = l10n_util::GetStringUTF8(IDS_CERT_MANAGER_IMPORT_ALL_NOT_IMPORTED);
956  else
957    error = l10n_util::GetStringUTF8(IDS_CERT_MANAGER_IMPORT_SOME_NOT_IMPORTED);
958
959  ListValue cert_error_list;
960  for (size_t i = 0; i < not_imported.size(); ++i) {
961    const net::CertDatabase::ImportCertFailure& failure = not_imported[i];
962    DictionaryValue* dict = new DictionaryValue;
963    dict->SetString(kNameId, failure.certificate->subject().GetDisplayName());
964    dict->SetString(kErrorId, NetErrorToString(failure.net_error));
965    cert_error_list.Append(dict);
966  }
967
968  StringValue title_value(title);
969  StringValue error_value(error);
970  web_ui_->CallJavascriptFunction("CertificateImportErrorOverlay.show",
971                                  title_value,
972                                  error_value,
973                                  cert_error_list);
974}
975
976#if defined(OS_CHROMEOS)
977void CertificateManagerHandler::CheckTpmTokenReady(const ListValue* args) {
978  chromeos::CryptohomeLibrary* cryptohome =
979      chromeos::CrosLibrary::Get()->GetCryptohomeLibrary();
980
981  // TODO(xiyuan): Use async way when underlying supports it.
982  FundamentalValue ready(cryptohome->Pkcs11IsTpmTokenReady());
983  web_ui_->CallJavascriptFunction("CertificateManager.onCheckTpmTokenReady",
984                                  ready);
985}
986#endif
987
988gfx::NativeWindow CertificateManagerHandler::GetParentWindow() const {
989  return web_ui_->tab_contents()->view()->GetTopLevelNativeWindow();
990}
991