certificate_manager_handler.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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.
4
5#include "chrome/browser/ui/webui/options/certificate_manager_handler.h"
6
7#include <algorithm>
8#include <map>
9
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"
34
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"
38#endif
39
40using base::UTF8ToUTF16;
41using content::BrowserThread;
42
43namespace {
44
45static const char kKeyId[] = "id";
46static const char kSubNodesId[] = "subnodes";
47static const char kNameId[] = "name";
48static const char kReadOnlyId[] = "readonly";
49static const char kUntrustedId[] = "untrusted";
50static const char kExtractableId[] = "extractable";
51static const char kErrorId[] = "error";
52static const char kPolicyTrustedId[] = "policy";
53
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.)
56enum {
57  EXPORT_PERSONAL_FILE_SELECTED = 1,
58  IMPORT_PERSONAL_FILE_SELECTED,
59  IMPORT_SERVER_FILE_SELECTED,
60  IMPORT_CA_FILE_SELECTED,
61};
62
63std::string OrgNameToId(const std::string& org) {
64  return "org-" + org;
65}
66
67bool CallbackArgsToBool(const base::ListValue* args, int index, bool* result) {
68  std::string string_value;
69  if (!args->GetString(index, &string_value))
70    return false;
71
72  *result = string_value[0] == 't';
73  return true;
74}
75
76struct DictionaryIdComparator {
77  explicit DictionaryIdComparator(icu::Collator* collator)
78      : collator_(collator) {
79  }
80
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);
89    base::string16 a_str;
90    base::string16 b_str;
91    a_dict->GetString(kNameId, &a_str);
92    b_dict->GetString(kNameId, &b_str);
93    if (collator_ == NULL)
94      return a_str < b_str;
95    return base::i18n::CompareString16WithCollator(
96        collator_, a_str, b_str) == UCOL_LESS;
97  }
98
99  icu::Collator* collator_;
100};
101
102std::string NetErrorToString(int net_error) {
103  switch (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);
110    default:
111      return l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR);
112  }
113}
114
115// Struct to bind the Equals member function to an object for use in find_if.
116struct CertEquals {
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());
120  }
121  const net::X509Certificate* cert_;
122};
123
124// Determine whether a certificate was stored with web trust by a policy.
125bool 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();
130}
131
132}  // namespace
133
134namespace options {
135
136///////////////////////////////////////////////////////////////////////////////
137//  CertIdMap
138
139class CertIdMap {
140 public:
141  CertIdMap() {}
142  ~CertIdMap() {}
143
144  std::string CertToId(net::X509Certificate* cert);
145  net::X509Certificate* IdToCert(const std::string& id);
146  net::X509Certificate* CallbackArgsToCert(const base::ListValue* args);
147
148 private:
149  typedef std::map<net::X509Certificate*, int32> CertMap;
150
151  // Creates an ID for cert and looks up the cert for an ID.
152  IDMap<net::X509Certificate>id_map_;
153
154  // Finds the ID for a cert.
155  CertMap cert_map_;
156
157  DISALLOW_COPY_AND_ASSIGN(CertIdMap);
158};
159
160std::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);
164
165  int32 new_id = id_map_.Add(cert);
166  cert_map_[cert] = new_id;
167  return base::IntToString(new_id);
168}
169
170net::X509Certificate* CertIdMap::IdToCert(const std::string& id) {
171  int32 cert_id = 0;
172  if (!base::StringToInt(id, &cert_id))
173    return NULL;
174
175  return id_map_.Lookup(cert_id);
176}
177
178net::X509Certificate* CertIdMap::CallbackArgsToCert(
179    const base::ListValue* args) {
180  std::string node_id;
181  if (!args->GetString(0, &node_id))
182    return NULL;
183
184  net::X509Certificate* cert = IdToCert(node_id);
185  if (!cert) {
186    NOTREACHED();
187    return NULL;
188  }
189
190  return cert;
191}
192
193///////////////////////////////////////////////////////////////////////////////
194//  FileAccessProvider
195
196// TODO(mattm): Move to some shared location?
197class FileAccessProvider
198    : public base::RefCountedThreadSafe<FileAccessProvider> {
199 public:
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;
203
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;
207
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);
217
218 private:
219  friend class base::RefCountedThreadSafe<FileAccessProvider>;
220  virtual ~FileAccessProvider() {}
221
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,
225              int* saved_errno,
226              std::string* data);
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,
231               int* saved_errno,
232               int* bytes_written);
233};
234
235base::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();
242
243  // Post task to file thread to read file.
244  return tracker->PostTaskAndReply(
245      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE).get(),
246      FROM_HERE,
247      base::Bind(&FileAccessProvider::DoRead, this, path, saved_errno, data),
248      base::Bind(callback, base::Owned(saved_errno), base::Owned(data)));
249}
250
251base::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);
259
260  // Post task to file thread to write file.
261  return tracker->PostTaskAndReply(
262      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE).get(),
263      FROM_HERE,
264      base::Bind(&FileAccessProvider::DoWrite,
265                 this,
266                 path,
267                 data,
268                 saved_errno,
269                 bytes_written),
270      base::Bind(
271          callback, base::Owned(saved_errno), base::Owned(bytes_written)));
272}
273
274void FileAccessProvider::DoRead(const base::FilePath& path,
275                                int* saved_errno,
276                                std::string* data) {
277  bool success = base::ReadFileToString(path, data);
278  *saved_errno = success ? 0 : errno;
279}
280
281void FileAccessProvider::DoWrite(const base::FilePath& path,
282                                 const std::string& data,
283                                 int* saved_errno,
284                                 int* bytes_written) {
285  *bytes_written = file_util::WriteFile(path, data.data(), data.size());
286  *saved_errno = *bytes_written >= 0 ? 0 : errno;
287}
288
289///////////////////////////////////////////////////////////////////////////////
290//  CertificateManagerHandler
291
292CertificateManagerHandler::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) {}
298
299CertificateManagerHandler::~CertificateManagerHandler() {
300}
301
302void CertificateManagerHandler::GetLocalizedValues(
303    base::DictionaryValue* localized_strings) {
304  DCHECK(localized_strings);
305
306  RegisterTitle(localized_strings, "certificateManagerPage",
307                IDS_CERTIFICATE_MANAGER_TITLE);
308
309  // Tabs.
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));
318
319  // Tab descriptions.
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));
328
329  // Buttons.
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));
340
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());
357
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));
363
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));
371
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));
391
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));
397
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)
402}
403
404void CertificateManagerHandler::RegisterMessages() {
405  web_ui()->RegisterMessageCallback(
406      "viewCertificate",
407      base::Bind(&CertificateManagerHandler::View, base::Unretained(this)));
408
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)));
417
418  web_ui()->RegisterMessageCallback(
419      "editServerCertificate",
420      base::Bind(&CertificateManagerHandler::EditServer,
421                 base::Unretained(this)));
422
423  web_ui()->RegisterMessageCallback(
424      "cancelImportExportCertificate",
425      base::Bind(&CertificateManagerHandler::CancelImportExportProcess,
426                 base::Unretained(this)));
427
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)));
440
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)));
449
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)));
458
459  web_ui()->RegisterMessageCallback(
460      "importServerCertificate",
461      base::Bind(&CertificateManagerHandler::ImportServer,
462                 base::Unretained(this)));
463
464  web_ui()->RegisterMessageCallback(
465      "exportCertificate",
466      base::Bind(&CertificateManagerHandler::Export,
467                 base::Unretained(this)));
468
469  web_ui()->RegisterMessageCallback(
470      "deleteCertificate",
471      base::Bind(&CertificateManagerHandler::Delete,
472                 base::Unretained(this)));
473
474  web_ui()->RegisterMessageCallback(
475      "populateCertificateManager",
476      base::Bind(&CertificateManagerHandler::Populate,
477                 base::Unretained(this)));
478}
479
480void 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()));
486  if (service)
487    service->GetWebTrustedCertificates(&web_trusted_certs);
488#endif
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);
493}
494
495void CertificateManagerHandler::FileSelected(const base::FilePath& path,
496                                             int index,
497                                             void* params) {
498  switch (reinterpret_cast<intptr_t>(params)) {
499    case EXPORT_PERSONAL_FILE_SELECTED:
500      ExportPersonalFileSelected(path);
501      break;
502    case IMPORT_PERSONAL_FILE_SELECTED:
503      ImportPersonalFileSelected(path);
504      break;
505    case IMPORT_SERVER_FILE_SELECTED:
506      ImportServerFileSelected(path);
507      break;
508    case IMPORT_CA_FILE_SELECTED:
509      ImportCAFileSelected(path);
510      break;
511    default:
512      NOTREACHED();
513  }
514}
515
516void 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();
523      break;
524    default:
525      NOTREACHED();
526  }
527}
528
529void CertificateManagerHandler::View(const base::ListValue* args) {
530  net::X509Certificate* cert = cert_id_map_->CallbackArgsToCert(args);
531  if (!cert)
532    return;
533  ShowCertificateViewer(web_ui()->GetWebContents(), GetParentWindow(), cert);
534}
535
536void CertificateManagerHandler::GetCATrust(const base::ListValue* args) {
537  net::X509Certificate* cert = cert_id_map_->CallbackArgsToCert(args);
538  if (!cert) {
539    web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
540    return;
541  }
542
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);
554}
555
556void CertificateManagerHandler::EditCATrust(const base::ListValue* args) {
557  net::X509Certificate* cert = cert_id_map_->CallbackArgsToCert(args);
558  bool fail = !cert;
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);
565  if (fail) {
566    LOG(ERROR) << "EditCATrust args fail";
567    web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
568    return;
569  }
570
571  bool result = certificate_manager_model_->SetCertTrust(
572      cert,
573      net::CA_CERT,
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");
578  if (!result) {
579    // TODO(mattm): better error messages?
580    ShowError(
581        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SET_TRUST_ERROR_TITLE),
582        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
583  }
584}
585
586void CertificateManagerHandler::EditServer(const base::ListValue* args) {
587  NOTIMPLEMENTED();
588}
589
590void CertificateManagerHandler::ExportPersonal(const base::ListValue* args) {
591  net::X509Certificate* cert = cert_id_map_->CallbackArgsToCert(args);
592  if (!cert)
593    return;
594
595  selected_cert_list_.push_back(cert);
596
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"),
608      GetParentWindow(),
609      reinterpret_cast<void*>(EXPORT_PERSONAL_FILE_SELECTED));
610}
611
612void CertificateManagerHandler::ExportAllPersonal(const base::ListValue* args) {
613  NOTIMPLEMENTED();
614}
615
616void CertificateManagerHandler::ExportPersonalFileSelected(
617    const base::FilePath& path) {
618  file_path_ = path;
619  web_ui()->CallJavascriptFunction(
620      "CertificateManager.exportPersonalAskPassword");
621}
622
623void CertificateManagerHandler::ExportPersonalPasswordSelected(
624    const base::ListValue* args) {
625  if (!args->GetString(0, &password_)) {
626    web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
627    ImportExportCleanup();
628    return;
629  }
630
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);
635
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.
641      GetParentWindow(),
642      base::Bind(&CertificateManagerHandler::ExportPersonalSlotsUnlocked,
643                 base::Unretained(this)));
644}
645
646void CertificateManagerHandler::ExportPersonalSlotsUnlocked() {
647  std::string output;
648  int num_exported = certificate_manager_model_->cert_db()->ExportToPKCS12(
649      selected_cert_list_,
650      password_,
651      &output);
652  if (!num_exported) {
653    web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
654    ShowError(
655        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_EXPORT_ERROR_TITLE),
656        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
657    ImportExportCleanup();
658    return;
659  }
660  file_access_provider_->StartWrite(
661      file_path_,
662      output,
663      base::Bind(&CertificateManagerHandler::ExportPersonalFileWritten,
664                 base::Unretained(this)),
665      &tracker_);
666}
667
668void CertificateManagerHandler::ExportPersonalFileWritten(
669    const int* write_errno, const int* bytes_written) {
670  web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
671  ImportExportCleanup();
672  if (*write_errno) {
673    ShowError(
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))));
677  }
678}
679
680void 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,
685    // so bail.
686    web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
687    ImportExportCleanup();
688    return;
689  }
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"),
700      GetParentWindow(),
701      reinterpret_cast<void*>(IMPORT_PERSONAL_FILE_SELECTED));
702}
703
704void CertificateManagerHandler::ImportPersonalFileSelected(
705    const base::FilePath& path) {
706  file_path_ = path;
707  web_ui()->CallJavascriptFunction(
708      "CertificateManager.importPersonalAskPassword");
709}
710
711void CertificateManagerHandler::ImportPersonalPasswordSelected(
712    const base::ListValue* args) {
713  if (!args->GetString(0, &password_)) {
714    web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
715    ImportExportCleanup();
716    return;
717  }
718  file_access_provider_->StartRead(
719      file_path_,
720      base::Bind(&CertificateManagerHandler::ImportPersonalFileRead,
721                 base::Unretained(this)),
722      &tracker_);
723}
724
725void CertificateManagerHandler::ImportPersonalFileRead(
726    const int* read_errno, const std::string* data) {
727  if (*read_errno) {
728    ImportExportCleanup();
729    web_ui()->CallJavascriptFunction("CertificateRestoreOverlay.dismiss");
730    ShowError(
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))));
734    return;
735  }
736
737  file_data_ = *data;
738
739  if (use_hardware_backed_) {
740    module_ = certificate_manager_model_->cert_db()->GetPrivateModule();
741  } else {
742    module_ = certificate_manager_model_->cert_db()->GetPublicModule();
743  }
744
745  net::CryptoModuleList modules;
746  modules.push_back(module_);
747  chrome::UnlockSlotsIfNecessary(
748      modules,
749      chrome::kCryptoModulePasswordCertImport,
750      net::HostPortPair(),  // unused.
751      GetParentWindow(),
752      base::Bind(&CertificateManagerHandler::ImportPersonalSlotUnlocked,
753                 base::Unretained(this)));
754}
755
756void 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");
766  int string_id;
767  switch (result) {
768    case net::OK:
769      return;
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;
774      break;
775    case net::ERR_PKCS12_IMPORT_INVALID_MAC:
776      string_id = IDS_CERT_MANAGER_PKCS12_IMPORT_INVALID_MAC;
777      break;
778    case net::ERR_PKCS12_IMPORT_INVALID_FILE:
779      string_id = IDS_CERT_MANAGER_PKCS12_IMPORT_INVALID_FILE;
780      break;
781    case net::ERR_PKCS12_IMPORT_UNSUPPORTED:
782      string_id = IDS_CERT_MANAGER_PKCS12_IMPORT_UNSUPPORTED;
783      break;
784    default:
785      string_id = IDS_CERT_MANAGER_UNKNOWN_ERROR;
786      break;
787  }
788  ShowError(
789      l10n_util::GetStringUTF8(IDS_CERT_MANAGER_PKCS12_IMPORT_ERROR_TITLE),
790      l10n_util::GetStringUTF8(string_id));
791}
792
793void CertificateManagerHandler::CancelImportExportProcess(
794    const base::ListValue* args) {
795  ImportExportCleanup();
796}
797
798void CertificateManagerHandler::ImportExportCleanup() {
799  file_path_.clear();
800  password_.clear();
801  file_data_.clear();
802  use_hardware_backed_ = false;
803  selected_cert_list_.clear();
804  module_ = NULL;
805
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;
811}
812
813void 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,
819      base::FilePath(),
820      GetParentWindow(),
821      reinterpret_cast<void*>(IMPORT_SERVER_FILE_SELECTED));
822}
823
824void CertificateManagerHandler::ImportServerFileSelected(
825    const base::FilePath& path) {
826  file_path_ = path;
827  file_access_provider_->StartRead(
828      file_path_,
829      base::Bind(&CertificateManagerHandler::ImportServerFileRead,
830                 base::Unretained(this)),
831      &tracker_);
832}
833
834void CertificateManagerHandler::ImportServerFileRead(const int* read_errno,
835                                                     const std::string* data) {
836  if (*read_errno) {
837    ImportExportCleanup();
838    ShowError(
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))));
842    return;
843  }
844
845  selected_cert_list_ = net::X509Certificate::CreateCertificateListFromBytes(
846          data->data(), data->size(), net::X509Certificate::FORMAT_AUTO);
847  if (selected_cert_list_.empty()) {
848    ImportExportCleanup();
849    ShowError(
850        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE),
851        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CERT_PARSE_ERROR));
852    return;
853  }
854
855  net::NSSCertDatabase::ImportCertFailureList not_imported;
856  // TODO(mattm): Add UI for trust. http://crbug.com/76274
857  bool result = certificate_manager_model_->ImportServerCert(
858      selected_cert_list_,
859      net::NSSCertDatabase::TRUST_DEFAULT,
860      &not_imported);
861  if (!result) {
862    ShowError(
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()) {
866    ShowImportErrors(
867        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_SERVER_IMPORT_ERROR_TITLE),
868        not_imported);
869  }
870  ImportExportCleanup();
871}
872
873void 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,
878                           base::FilePath(),
879                           GetParentWindow(),
880                           reinterpret_cast<void*>(IMPORT_CA_FILE_SELECTED));
881}
882
883void CertificateManagerHandler::ImportCAFileSelected(
884    const base::FilePath& path) {
885  file_path_ = path;
886  file_access_provider_->StartRead(
887      file_path_,
888      base::Bind(&CertificateManagerHandler::ImportCAFileRead,
889                 base::Unretained(this)),
890      &tracker_);
891}
892
893void CertificateManagerHandler::ImportCAFileRead(const int* read_errno,
894                                                const std::string* data) {
895  if (*read_errno) {
896    ImportExportCleanup();
897    ShowError(
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))));
901    return;
902  }
903
904  selected_cert_list_ = net::X509Certificate::CreateCertificateListFromBytes(
905          data->data(), data->size(), net::X509Certificate::FORMAT_AUTO);
906  if (selected_cert_list_.empty()) {
907    ImportExportCleanup();
908    ShowError(
909        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE),
910        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CERT_PARSE_ERROR));
911    return;
912  }
913
914  scoped_refptr<net::X509Certificate> root_cert =
915      certificate_manager_model_->cert_db()->FindRootInList(
916          selected_cert_list_);
917
918  // TODO(mattm): check here if root_cert is not a CA cert and show error.
919
920  base::StringValue cert_name(root_cert->subject().GetDisplayName());
921  web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.showImport",
922                                   cert_name);
923}
924
925void CertificateManagerHandler::ImportCATrustSelected(
926    const base::ListValue* args) {
927  bool fail = false;
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);
934  if (fail) {
935    LOG(ERROR) << "ImportCATrustSelected args fail";
936    ImportExportCleanup();
937    web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
938    return;
939  }
940
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(
945      selected_cert_list_,
946      trust_ssl * net::NSSCertDatabase::TRUSTED_SSL +
947          trust_email * net::NSSCertDatabase::TRUSTED_EMAIL +
948          trust_obj_sign * net::NSSCertDatabase::TRUSTED_OBJ_SIGN,
949      &not_imported);
950  web_ui()->CallJavascriptFunction("CertificateEditCaTrustOverlay.dismiss");
951  if (!result) {
952    ShowError(
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()) {
956    ShowImportErrors(
957        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_CA_IMPORT_ERROR_TITLE),
958        not_imported);
959  }
960  ImportExportCleanup();
961}
962
963void CertificateManagerHandler::Export(const base::ListValue* args) {
964  net::X509Certificate* cert = cert_id_map_->CallbackArgsToCert(args);
965  if (!cert)
966    return;
967  ShowCertExportDialog(web_ui()->GetWebContents(), GetParentWindow(),
968                       cert->os_cert_handle());
969}
970
971void CertificateManagerHandler::Delete(const base::ListValue* args) {
972  net::X509Certificate* cert = cert_id_map_->CallbackArgsToCert(args);
973  if (!cert)
974    return;
975  bool result = certificate_manager_model_->Delete(cert);
976  if (!result) {
977    // TODO(mattm): better error messages?
978    ShowError(
979        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_DELETE_CERT_ERROR_TITLE),
980        l10n_util::GetStringUTF8(IDS_CERT_MANAGER_UNKNOWN_ERROR));
981  }
982}
983
984void CertificateManagerHandler::OnCertificateManagerModelCreated(
985    scoped_ptr<CertificateManagerModel> model) {
986  certificate_manager_model_ = model.Pass();
987  CertificateManagerModelReady();
988}
989
990void 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();
996}
997
998void 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();
1003    return;
1004  }
1005
1006  if (!requested_certificate_manager_model_) {
1007    // Request that a model be created.
1008    CertificateManagerModel::Create(
1009        Profile::FromWebUI(web_ui()),
1010        this,
1011        base::Bind(&CertificateManagerHandler::OnCertificateManagerModelCreated,
1012                   weak_ptr_factory_.GetWeakPtr()));
1013    requested_certificate_manager_model_ = true;
1014    return;
1015  }
1016
1017  // We are already waiting for a CertificateManagerModel to be created, no need
1018  // to do anything.
1019}
1020
1021void CertificateManagerHandler::PopulateTree(
1022    const std::string& tab_name,
1023    net::CertType type,
1024    const net::CertificateList& web_trust_certs) {
1025  const std::string tree_name = tab_name + "-tree";
1026
1027  scoped_ptr<icu::Collator> collator;
1028  UErrorCode error = U_ZERO_ERROR;
1029  collator.reset(
1030      icu::Collator::createInstance(
1031          icu::Locale(g_browser_process->GetApplicationLocale().c_str()),
1032          error));
1033  if (U_FAILURE(error))
1034    collator.reset(NULL);
1035  DictionaryIdComparator comparator(collator.get());
1036  CertificateManagerModel::OrgGroupingMap map;
1037
1038  certificate_manager_model_->FilterAndBuildOrgGroupingMap(type, &map);
1039
1040  {
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);
1048
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(
1059            kReadOnlyId,
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(
1065            kUntrustedId,
1066            !policy_trusted &&
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(
1073            kExtractableId,
1074            !certificate_manager_model_->IsHardwareBacked(cert));
1075        // TODO(mattm): Other columns.
1076        subnodes->Append(cert_dict);
1077      }
1078      std::sort(subnodes->begin(), subnodes->end(), comparator);
1079
1080      dict->Set(kSubNodesId, subnodes);
1081      nodes->Append(dict);
1082    }
1083    std::sort(nodes->begin(), nodes->end(), comparator);
1084
1085    base::ListValue args;
1086    args.Append(new base::StringValue(tree_name));
1087    args.Append(nodes);
1088    web_ui()->CallJavascriptFunction("CertificateManager.onPopulateTree", args);
1089  }
1090}
1091
1092void 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());
1102}
1103
1104void CertificateManagerHandler::ShowImportErrors(
1105    const std::string& title,
1106    const net::NSSCertDatabase::ImportCertFailureList& not_imported) const {
1107  std::string error;
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);
1113  else
1114    error = l10n_util::GetStringUTF8(IDS_CERT_MANAGER_IMPORT_SOME_NOT_IMPORTED);
1115
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);
1123  }
1124
1125  base::StringValue title_value(title);
1126  base::StringValue error_value(error);
1127  web_ui()->CallJavascriptFunction("CertificateImportErrorOverlay.show",
1128                                   title_value,
1129                                   error_value,
1130                                   cert_error_list);
1131}
1132
1133gfx::NativeWindow CertificateManagerHandler::GetParentWindow() const {
1134  return web_ui()->GetWebContents()->GetView()->GetTopLevelNativeWindow();
1135}
1136
1137}  // namespace options
1138