- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / gtk / certificate_viewer_gtk.cc
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 <gtk/gtk.h>
6 #include <pango/pango-font.h>
7
8 #include <algorithm>
9 #include <vector>
10
11 #include "base/i18n/time_formatting.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/time/time.h"
16 #include "chrome/browser/certificate_viewer.h"
17 #include "chrome/browser/ui/certificate_dialogs.h"
18 #include "chrome/browser/ui/gtk/gtk_util.h"
19 #include "chrome/common/net/x509_certificate_model.h"
20 #include "grit/generated_resources.h"
21 #include "net/cert/x509_certificate.h"
22 #include "ui/base/accelerators/menu_label_accelerator_util_linux.h"
23 #include "ui/base/gtk/gtk_hig_constants.h"
24 #include "ui/base/l10n/l10n_util.h"
25 #include "ui/gfx/native_widget_types.h"
26 #include "ui/gfx/pango_util.h"
27
28 namespace {
29
30 const char kDetailsFontFamily[] = "monospace";
31
32 ////////////////////////////////////////////////////////////////////////////////
33 // Gtk utility functions.
34
35 void AddTitle(GtkTable* table, int row, const std::string& text) {
36   gtk_table_attach_defaults(table,
37                             gtk_util::CreateBoldLabel(text),
38                             0, 2,
39                             row, row + 1);
40 }
41
42 void AddKeyValue(GtkTable* table, int row, const std::string& text,
43                  const std::string& value) {
44   gtk_table_attach_defaults(
45       table,
46       gtk_util::IndentWidget(
47           gtk_util::LeftAlignMisc(gtk_label_new(text.c_str()))),
48       0, 1, row, row + 1);
49   GtkWidget* label = gtk_label_new(value.c_str());
50   gtk_label_set_selectable(GTK_LABEL(label), TRUE);
51   gtk_table_attach_defaults(
52       table,
53       gtk_util::LeftAlignMisc(label),
54       1, 2, row, row + 1);
55 }
56
57 ////////////////////////////////////////////////////////////////////////////////
58 // CertificateViewer class definition.
59
60 class CertificateViewer {
61  public:
62   CertificateViewer(gfx::NativeWindow parent,
63                     net::X509Certificate* certificate);
64   ~CertificateViewer();
65
66   void InitGeneralPage();
67   void InitDetailsPage();
68
69   void Show();
70
71  private:
72   // Indices and column count for the certificate chain hierarchy tree store.
73   enum {
74     HIERARCHY_NAME,
75     HIERARCHY_OBJECT,
76     HIERARCHY_INDEX,
77     HIERARCHY_COLUMNS
78   };
79
80   // Indices and column count for the certificate fields tree store.
81   enum {
82     FIELDS_NAME,
83     FIELDS_VALUE,
84     FIELDS_COLUMNS
85   };
86
87   // Fill the tree store with the certificate hierarchy, and set |leaf| to the
88   // iter of the leaf node.
89   void FillHierarchyStore(GtkTreeStore* hierarchy_store,
90                           GtkTreeIter* leaf) const;
91
92   // Fill the tree store with the details of the given certificate.
93   static void FillTreeStoreWithCertFields(
94       GtkTreeStore* store, net::X509Certificate::OSCertHandle cert);
95
96   // Create a tree store filled with the details of the given certificate.
97   static GtkTreeStore* CreateFieldsTreeStore(
98       net::X509Certificate::OSCertHandle cert);
99
100   // Callbacks for user selecting elements in the trees.
101   static void OnHierarchySelectionChanged(GtkTreeSelection* selection,
102                                           CertificateViewer* viewer);
103   static void OnFieldsSelectionChanged(GtkTreeSelection* selection,
104                                        CertificateViewer* viewer);
105
106   // Callback for export button.
107   static void OnExportClicked(GtkButton *button, CertificateViewer* viewer);
108
109   // The certificate hierarchy (leaf cert first).
110   net::X509Certificate::OSCertHandles cert_chain_list_;
111   scoped_refptr<net::X509Certificate> certificate_;
112
113   GtkWidget* dialog_;
114   GtkWidget* notebook_;
115   GtkWidget* general_page_vbox_;
116   GtkWidget* details_page_vbox_;
117   GtkTreeSelection* hierarchy_selection_;
118   GtkWidget* fields_tree_;
119   GtkTextBuffer* field_value_buffer_;
120   GtkWidget* export_button_;
121
122   DISALLOW_COPY_AND_ASSIGN(CertificateViewer);
123 };
124
125 ////////////////////////////////////////////////////////////////////////////////
126 // CertificateViewer implementation.
127
128 // Close button callback.
129 void OnResponse(GtkWidget* dialog, int response_id) {
130   // "Close" was clicked.
131   gtk_widget_destroy(dialog);
132 }
133
134 void OnDestroy(GtkDialog* dialog, CertificateViewer* cert_viewer) {
135   delete cert_viewer;
136 }
137
138 CertificateViewer::CertificateViewer(
139     gfx::NativeWindow parent,
140     net::X509Certificate* certificate)
141     : certificate_(certificate) {
142   cert_chain_list_.insert(cert_chain_list_.begin(),
143                           certificate_->os_cert_handle());
144   const net::X509Certificate::OSCertHandles& certs =
145       certificate_->GetIntermediateCertificates();
146   cert_chain_list_.insert(cert_chain_list_.end(), certs.begin(), certs.end());
147
148   dialog_ = gtk_dialog_new_with_buttons(
149       l10n_util::GetStringFUTF8(
150           IDS_CERT_INFO_DIALOG_TITLE,
151           UTF8ToUTF16(
152               x509_certificate_model::GetTitle(
153                   cert_chain_list_.front()))).c_str(),
154       parent,
155       // Non-modal.
156       GTK_DIALOG_NO_SEPARATOR,
157       GTK_STOCK_CLOSE,
158       GTK_RESPONSE_CLOSE,
159       NULL);
160
161   GtkWidget* content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog_));
162   gtk_box_set_spacing(GTK_BOX(content_area), ui::kContentAreaSpacing);
163
164   x509_certificate_model::RegisterDynamicOids();
165   InitGeneralPage();
166   InitDetailsPage();
167
168   notebook_ = gtk_notebook_new();
169   gtk_container_add(GTK_CONTAINER(content_area), notebook_);
170
171   gtk_notebook_append_page(
172       GTK_NOTEBOOK(notebook_),
173       general_page_vbox_,
174       gtk_label_new_with_mnemonic(
175           ui::ConvertAcceleratorsFromWindowsStyle(
176               l10n_util::GetStringUTF8(
177                   IDS_CERT_INFO_GENERAL_TAB_LABEL)).c_str()));
178
179   gtk_notebook_append_page(
180       GTK_NOTEBOOK(notebook_),
181       details_page_vbox_,
182       gtk_label_new_with_mnemonic(
183           ui::ConvertAcceleratorsFromWindowsStyle(
184               l10n_util::GetStringUTF8(
185                   IDS_CERT_INFO_DETAILS_TAB_LABEL)).c_str()));
186
187   g_signal_connect(dialog_, "response", G_CALLBACK(OnResponse), NULL);
188   g_signal_connect(dialog_, "destroy", G_CALLBACK(OnDestroy), this);
189 }
190
191 CertificateViewer::~CertificateViewer() {
192 }
193
194 void CertificateViewer::InitGeneralPage() {
195   net::X509Certificate::OSCertHandle cert = cert_chain_list_.front();
196   general_page_vbox_ = gtk_vbox_new(FALSE, ui::kContentAreaSpacing);
197   gtk_container_set_border_width(GTK_CONTAINER(general_page_vbox_),
198                                  ui::kContentAreaBorder);
199
200   GtkWidget* uses_vbox = gtk_vbox_new(FALSE, ui::kControlSpacing);
201   gtk_box_pack_start(GTK_BOX(general_page_vbox_), uses_vbox, FALSE, FALSE, 0);
202   gtk_box_pack_start(
203       GTK_BOX(uses_vbox),
204       gtk_util::CreateBoldLabel(
205           l10n_util::GetStringUTF8(IDS_CERT_INFO_VERIFIED_USAGES_GROUP)),
206       FALSE, FALSE, 0);
207
208   std::vector<std::string> usages;
209   x509_certificate_model::GetUsageStrings(cert, &usages);
210   for (size_t i = 0; i < usages.size(); ++i)
211     gtk_box_pack_start(
212         GTK_BOX(uses_vbox),
213         gtk_util::IndentWidget(gtk_util::LeftAlignMisc(gtk_label_new(
214             usages[i].c_str()))),
215         FALSE, FALSE, 0);
216
217   gtk_box_pack_start(GTK_BOX(general_page_vbox_), gtk_hseparator_new(),
218                      FALSE, FALSE, 0);
219
220   const int num_rows = 21;
221   GtkTable* table = GTK_TABLE(gtk_table_new(num_rows, 2, FALSE));
222   gtk_table_set_col_spacing(table, 0, ui::kLabelSpacing);
223   gtk_table_set_row_spacings(table, ui::kControlSpacing);
224
225   gtk_box_pack_start(GTK_BOX(general_page_vbox_), GTK_WIDGET(table),
226                      FALSE, FALSE, 0);
227   int row = 0;
228   const std::string alternative_text =
229       l10n_util::GetStringUTF8(IDS_CERT_INFO_FIELD_NOT_PRESENT);
230   AddTitle(table, row++,
231            l10n_util::GetStringUTF8(IDS_CERT_INFO_SUBJECT_GROUP));
232   AddKeyValue(table, row++,
233               l10n_util::GetStringUTF8(IDS_CERT_INFO_COMMON_NAME_LABEL),
234               x509_certificate_model::ProcessIDN(
235                   x509_certificate_model::GetSubjectCommonName(
236                       cert, alternative_text)));
237   AddKeyValue(table, row++,
238               l10n_util::GetStringUTF8(IDS_CERT_INFO_ORGANIZATION_LABEL),
239               x509_certificate_model::GetSubjectOrgName(
240                   cert, alternative_text));
241   AddKeyValue(table, row++,
242               l10n_util::GetStringUTF8(IDS_CERT_INFO_ORGANIZATIONAL_UNIT_LABEL),
243               x509_certificate_model::GetSubjectOrgUnitName(
244                   cert, alternative_text));
245   AddKeyValue(table, row++,
246               l10n_util::GetStringUTF8(IDS_CERT_INFO_SERIAL_NUMBER_LABEL),
247               x509_certificate_model::GetSerialNumberHexified(
248                   cert, alternative_text));
249
250   row += 2;  // Add spacing (kControlSpacing * 3 == kContentAreaSpacing).
251
252   AddTitle(table, row++,
253            l10n_util::GetStringUTF8(IDS_CERT_INFO_ISSUER_GROUP));
254   AddKeyValue(table, row++,
255               l10n_util::GetStringUTF8(IDS_CERT_INFO_COMMON_NAME_LABEL),
256               x509_certificate_model::ProcessIDN(
257                   x509_certificate_model::GetIssuerCommonName(
258                       cert, alternative_text)));
259   AddKeyValue(table, row++,
260               l10n_util::GetStringUTF8(IDS_CERT_INFO_ORGANIZATION_LABEL),
261               x509_certificate_model::GetIssuerOrgName(
262                   cert, alternative_text));
263   AddKeyValue(table, row++,
264               l10n_util::GetStringUTF8(IDS_CERT_INFO_ORGANIZATIONAL_UNIT_LABEL),
265               x509_certificate_model::GetIssuerOrgUnitName(
266                   cert, alternative_text));
267
268   row += 2;  // Add spacing (kControlSpacing * 3 == kContentAreaSpacing).
269
270   base::Time issued, expires;
271   std::string issued_str, expires_str;
272   if (x509_certificate_model::GetTimes(cert, &issued, &expires)) {
273     issued_str = UTF16ToUTF8(
274         base::TimeFormatShortDateNumeric(issued));
275     expires_str = UTF16ToUTF8(
276         base::TimeFormatShortDateNumeric(expires));
277   } else {
278     issued_str = alternative_text;
279     expires_str = alternative_text;
280   }
281   AddTitle(table, row++,
282            l10n_util::GetStringUTF8(IDS_CERT_INFO_VALIDITY_GROUP));
283   AddKeyValue(table, row++,
284               l10n_util::GetStringUTF8(IDS_CERT_INFO_ISSUED_ON_LABEL),
285               issued_str);
286   AddKeyValue(table, row++,
287               l10n_util::GetStringUTF8(IDS_CERT_INFO_EXPIRES_ON_LABEL),
288               expires_str);
289
290   row += 2;  // Add spacing (kControlSpacing * 3 == kContentAreaSpacing).
291
292   AddTitle(table, row++,
293            l10n_util::GetStringUTF8(IDS_CERT_INFO_FINGERPRINTS_GROUP));
294   AddKeyValue(table, row++,
295               l10n_util::GetStringUTF8(IDS_CERT_INFO_SHA256_FINGERPRINT_LABEL),
296               x509_certificate_model::HashCertSHA256(cert));
297   AddKeyValue(table, row++,
298               l10n_util::GetStringUTF8(IDS_CERT_INFO_SHA1_FINGERPRINT_LABEL),
299               x509_certificate_model::HashCertSHA1(cert));
300
301   DCHECK_EQ(row, num_rows);
302 }
303
304 void CertificateViewer::FillHierarchyStore(GtkTreeStore* hierarchy_store,
305                                            GtkTreeIter* leaf) const {
306   GtkTreeIter parent;
307   GtkTreeIter* parent_ptr = NULL;
308   GtkTreeIter iter;
309
310   gint index = cert_chain_list_.size() - 1;
311   DCHECK_NE(-1, index);
312
313   for (net::X509Certificate::OSCertHandles::const_reverse_iterator i =
314           cert_chain_list_.rbegin();
315        i != cert_chain_list_.rend(); ++i, --index) {
316     gtk_tree_store_append(hierarchy_store, &iter, parent_ptr);
317     GtkTreeStore* fields_store = CreateFieldsTreeStore(*i);
318     gtk_tree_store_set(
319         hierarchy_store, &iter,
320         HIERARCHY_NAME, x509_certificate_model::GetTitle(*i).c_str(),
321         HIERARCHY_OBJECT, fields_store,
322         HIERARCHY_INDEX, index,
323         -1);
324     g_object_unref(fields_store);
325     parent = iter;
326     parent_ptr = &parent;
327   }
328
329   *leaf = iter;
330 }
331
332 // static
333 void CertificateViewer::FillTreeStoreWithCertFields(
334     GtkTreeStore* store, net::X509Certificate::OSCertHandle cert) {
335   GtkTreeIter top;
336   gtk_tree_store_append(store, &top, NULL);
337   gtk_tree_store_set(
338       store, &top,
339       FIELDS_NAME, x509_certificate_model::GetTitle(cert).c_str(),
340       FIELDS_VALUE, "",
341       -1);
342
343   GtkTreeIter cert_iter;
344   gtk_tree_store_append(store, &cert_iter, &top);
345   gtk_tree_store_set(
346       store, &cert_iter,
347       FIELDS_NAME,
348       l10n_util::GetStringUTF8(IDS_CERT_DETAILS_CERTIFICATE).c_str(),
349       FIELDS_VALUE, "",
350       -1);
351
352   std::string version_str;
353   std::string version = x509_certificate_model::GetVersion(cert);
354   if (!version.empty())
355     version_str = l10n_util::GetStringFUTF8(IDS_CERT_DETAILS_VERSION_FORMAT,
356                                             UTF8ToUTF16(version));
357   GtkTreeIter iter;
358   gtk_tree_store_append(store, &iter, &cert_iter);
359   gtk_tree_store_set(
360       store, &iter,
361       FIELDS_NAME,
362       l10n_util::GetStringUTF8(IDS_CERT_DETAILS_VERSION).c_str(),
363       FIELDS_VALUE, version_str.c_str(),
364       -1);
365
366   gtk_tree_store_append(store, &iter, &cert_iter);
367   gtk_tree_store_set(
368       store, &iter,
369       FIELDS_NAME,
370       l10n_util::GetStringUTF8(IDS_CERT_DETAILS_SERIAL_NUMBER).c_str(),
371       FIELDS_VALUE,
372       x509_certificate_model::GetSerialNumberHexified(
373           cert,
374           l10n_util::GetStringUTF8(IDS_CERT_INFO_FIELD_NOT_PRESENT)).c_str(),
375       -1);
376
377   gtk_tree_store_append(store, &iter, &cert_iter);
378   gtk_tree_store_set(
379       store, &iter,
380       FIELDS_NAME,
381       l10n_util::GetStringUTF8(IDS_CERT_DETAILS_CERTIFICATE_SIG_ALG).c_str(),
382       FIELDS_VALUE,
383       x509_certificate_model::ProcessSecAlgorithmSignature(cert).c_str(),
384       -1);
385
386   gtk_tree_store_append(store, &iter, &cert_iter);
387   gtk_tree_store_set(
388       store, &iter,
389       FIELDS_NAME,
390       l10n_util::GetStringUTF8(IDS_CERT_DETAILS_ISSUER).c_str(),
391       FIELDS_VALUE, x509_certificate_model::GetIssuerName(cert).c_str(),
392       -1);
393
394   GtkTreeIter validity_iter;
395   gtk_tree_store_append(store, &validity_iter, &cert_iter);
396   gtk_tree_store_set(
397       store, &validity_iter,
398       FIELDS_NAME,
399       l10n_util::GetStringUTF8(IDS_CERT_DETAILS_VALIDITY).c_str(),
400       FIELDS_VALUE, "",
401       -1);
402
403   base::Time issued, expires;
404   std::string issued_str, expires_str;
405   if (x509_certificate_model::GetTimes(cert, &issued, &expires)) {
406     issued_str = UTF16ToUTF8(base::TimeFormatShortDateAndTime(issued));
407     expires_str = UTF16ToUTF8(base::TimeFormatShortDateAndTime(expires));
408   }
409   gtk_tree_store_append(store, &iter, &validity_iter);
410   gtk_tree_store_set(
411       store, &iter,
412       FIELDS_NAME,
413       l10n_util::GetStringUTF8(IDS_CERT_DETAILS_NOT_BEFORE).c_str(),
414       FIELDS_VALUE, issued_str.c_str(),
415       -1);
416   gtk_tree_store_append(store, &iter, &validity_iter);
417   gtk_tree_store_set(
418       store, &iter,
419       FIELDS_NAME,
420       l10n_util::GetStringUTF8(IDS_CERT_DETAILS_NOT_AFTER).c_str(),
421       FIELDS_VALUE, expires_str.c_str(),
422       -1);
423
424   gtk_tree_store_append(store, &iter, &cert_iter);
425   gtk_tree_store_set(
426       store, &iter,
427       FIELDS_NAME,
428       l10n_util::GetStringUTF8(IDS_CERT_DETAILS_SUBJECT).c_str(),
429       FIELDS_VALUE, x509_certificate_model::GetSubjectName(cert).c_str(),
430       -1);
431
432   GtkTreeIter subject_public_key_iter;
433   gtk_tree_store_append(store, &subject_public_key_iter, &cert_iter);
434   gtk_tree_store_set(
435       store, &subject_public_key_iter,
436       FIELDS_NAME,
437       l10n_util::GetStringUTF8(IDS_CERT_DETAILS_SUBJECT_KEY_INFO).c_str(),
438       FIELDS_VALUE, "",
439       -1);
440
441   gtk_tree_store_append(store, &iter, &subject_public_key_iter);
442   gtk_tree_store_set(
443       store, &iter,
444       FIELDS_NAME,
445       l10n_util::GetStringUTF8(IDS_CERT_DETAILS_SUBJECT_KEY_ALG).c_str(),
446       FIELDS_VALUE,
447       x509_certificate_model::ProcessSecAlgorithmSubjectPublicKey(cert).c_str(),
448       -1);
449
450   gtk_tree_store_append(store, &iter, &subject_public_key_iter);
451   gtk_tree_store_set(
452       store, &iter,
453       FIELDS_NAME,
454       l10n_util::GetStringUTF8(IDS_CERT_DETAILS_SUBJECT_KEY).c_str(),
455       FIELDS_VALUE,
456       x509_certificate_model::ProcessSubjectPublicKeyInfo(cert).c_str(),
457       -1);
458
459   x509_certificate_model::Extensions extensions;
460   x509_certificate_model::GetExtensions(
461       l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_CRITICAL),
462       l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_NON_CRITICAL),
463       cert, &extensions);
464
465   if (!extensions.empty()) {
466     GtkTreeIter extensions_iter;
467     gtk_tree_store_append(store, &extensions_iter, &cert_iter);
468     gtk_tree_store_set(
469         store, &extensions_iter,
470         FIELDS_NAME,
471         l10n_util::GetStringUTF8(IDS_CERT_DETAILS_EXTENSIONS).c_str(),
472         FIELDS_VALUE, "",
473         -1);
474
475     for (x509_certificate_model::Extensions::const_iterator i =
476          extensions.begin(); i != extensions.end(); ++i) {
477       gtk_tree_store_append(store, &iter, &extensions_iter);
478       gtk_tree_store_set(
479           store, &iter,
480           FIELDS_NAME, i->name.c_str(),
481           FIELDS_VALUE, i->value.c_str(),
482           -1);
483     }
484   }
485
486   gtk_tree_store_append(store, &iter, &top);
487   gtk_tree_store_set(
488       store, &iter,
489       FIELDS_NAME,
490       l10n_util::GetStringUTF8(IDS_CERT_DETAILS_CERTIFICATE_SIG_ALG).c_str(),
491       FIELDS_VALUE,
492       x509_certificate_model::ProcessSecAlgorithmSignatureWrap(cert).c_str(),
493       -1);
494
495   gtk_tree_store_append(store, &iter, &top);
496   gtk_tree_store_set(
497       store, &iter,
498       FIELDS_NAME,
499       l10n_util::GetStringUTF8(IDS_CERT_DETAILS_CERTIFICATE_SIG_VALUE).c_str(),
500       FIELDS_VALUE,
501       x509_certificate_model::ProcessRawBitsSignatureWrap(cert).c_str(),
502       -1);
503
504   GtkTreeIter top_fingerprints_iter;
505   gtk_tree_store_append(store, &top_fingerprints_iter, &top);
506   gtk_tree_store_set(
507       store, &top_fingerprints_iter,
508       FIELDS_NAME,
509       l10n_util::GetStringUTF8(IDS_CERT_INFO_FINGERPRINTS_GROUP).c_str(),
510       FIELDS_VALUE, "",
511       -1);
512
513   GtkTreeIter fingerprints_iter;
514   gtk_tree_store_append(store, &fingerprints_iter, &top_fingerprints_iter);
515   gtk_tree_store_set(
516       store, &fingerprints_iter,
517       FIELDS_NAME,
518       l10n_util::GetStringUTF8(IDS_CERT_INFO_SHA256_FINGERPRINT_LABEL).c_str(),
519       FIELDS_VALUE, x509_certificate_model::HashCertSHA256(cert).c_str(),
520       -1);
521
522   gtk_tree_store_append(store, &fingerprints_iter, &top_fingerprints_iter);
523   gtk_tree_store_set(
524       store, &fingerprints_iter,
525       FIELDS_NAME,
526       l10n_util::GetStringUTF8(IDS_CERT_INFO_SHA1_FINGERPRINT_LABEL).c_str(),
527       FIELDS_VALUE, x509_certificate_model::HashCertSHA1(cert).c_str(),
528       -1);
529 }
530
531 // static
532 GtkTreeStore* CertificateViewer::CreateFieldsTreeStore(
533     net::X509Certificate::OSCertHandle cert) {
534   GtkTreeStore* fields_store = gtk_tree_store_new(FIELDS_COLUMNS, G_TYPE_STRING,
535                                                   G_TYPE_STRING);
536   FillTreeStoreWithCertFields(fields_store, cert);
537   return fields_store;
538 }
539
540 void CertificateViewer::InitDetailsPage() {
541   details_page_vbox_ = gtk_vbox_new(FALSE, ui::kContentAreaSpacing);
542   gtk_container_set_border_width(GTK_CONTAINER(details_page_vbox_),
543                                  ui::kContentAreaBorder);
544
545   GtkWidget* hierarchy_vbox = gtk_vbox_new(FALSE, ui::kControlSpacing);
546   gtk_box_pack_start(GTK_BOX(details_page_vbox_), hierarchy_vbox,
547                      FALSE, FALSE, 0);
548
549   gtk_box_pack_start(GTK_BOX(hierarchy_vbox),
550                      gtk_util::CreateBoldLabel(l10n_util::GetStringUTF8(
551                          IDS_CERT_DETAILS_CERTIFICATE_HIERARCHY_LABEL)),
552                      FALSE, FALSE, 0);
553
554   GtkTreeStore* hierarchy_store = gtk_tree_store_new(HIERARCHY_COLUMNS,
555                                                      G_TYPE_STRING,
556                                                      G_TYPE_OBJECT,
557                                                      G_TYPE_INT);
558   GtkTreeIter hierarchy_leaf_iter;
559   FillHierarchyStore(hierarchy_store, &hierarchy_leaf_iter);
560   GtkWidget* hierarchy_tree = gtk_tree_view_new_with_model(
561       GTK_TREE_MODEL(hierarchy_store));
562   gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(hierarchy_tree), FALSE);
563   gtk_tree_view_append_column(
564       GTK_TREE_VIEW(hierarchy_tree),
565       gtk_tree_view_column_new_with_attributes("", gtk_cell_renderer_text_new(),
566                                                "text", HIERARCHY_NAME,
567                                                NULL));
568   gtk_tree_view_expand_all(GTK_TREE_VIEW(hierarchy_tree));
569   hierarchy_selection_ = gtk_tree_view_get_selection(
570       GTK_TREE_VIEW(hierarchy_tree));
571   gtk_tree_selection_set_mode(hierarchy_selection_, GTK_SELECTION_SINGLE);
572   g_signal_connect(hierarchy_selection_, "changed",
573                    G_CALLBACK(OnHierarchySelectionChanged), this);
574   GtkWidget* hierarchy_scroll_window = gtk_scrolled_window_new(NULL, NULL);
575   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(hierarchy_scroll_window),
576                                  GTK_POLICY_AUTOMATIC,
577                                  GTK_POLICY_NEVER);
578   gtk_scrolled_window_set_shadow_type(
579       GTK_SCROLLED_WINDOW(hierarchy_scroll_window), GTK_SHADOW_ETCHED_IN);
580   gtk_container_add(GTK_CONTAINER(hierarchy_scroll_window), hierarchy_tree);
581   gtk_box_pack_start(GTK_BOX(hierarchy_vbox),
582                      hierarchy_scroll_window, FALSE, FALSE, 0);
583
584   GtkWidget* fields_vbox = gtk_vbox_new(FALSE, ui::kControlSpacing);
585   gtk_box_pack_start(GTK_BOX(details_page_vbox_), fields_vbox,
586                      TRUE, TRUE, 0);
587   gtk_box_pack_start(GTK_BOX(fields_vbox),
588                      gtk_util::CreateBoldLabel(l10n_util::GetStringUTF8(
589                          IDS_CERT_DETAILS_CERTIFICATE_FIELDS_LABEL)),
590                      FALSE, FALSE, 0);
591
592   fields_tree_ = gtk_tree_view_new();
593   gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(fields_tree_), FALSE);
594   gtk_tree_view_append_column(
595       GTK_TREE_VIEW(fields_tree_),
596       gtk_tree_view_column_new_with_attributes("", gtk_cell_renderer_text_new(),
597                                                "text", FIELDS_NAME,
598                                                NULL));
599   GtkTreeSelection* fields_selection = gtk_tree_view_get_selection(
600       GTK_TREE_VIEW(fields_tree_));
601   gtk_tree_selection_set_mode(fields_selection, GTK_SELECTION_SINGLE);
602   g_signal_connect(fields_selection, "changed",
603                    G_CALLBACK(OnFieldsSelectionChanged), this);
604   GtkWidget* fields_scroll_window = gtk_scrolled_window_new(NULL, NULL);
605   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(fields_scroll_window),
606                                  GTK_POLICY_AUTOMATIC,
607                                  GTK_POLICY_AUTOMATIC);
608   gtk_scrolled_window_set_shadow_type(
609       GTK_SCROLLED_WINDOW(fields_scroll_window), GTK_SHADOW_ETCHED_IN);
610   gtk_container_add(GTK_CONTAINER(fields_scroll_window), fields_tree_);
611   gtk_box_pack_start(GTK_BOX(fields_vbox),
612                      fields_scroll_window, TRUE, TRUE, 0);
613
614   GtkWidget* value_vbox = gtk_vbox_new(FALSE, ui::kControlSpacing);
615   gtk_box_pack_start(GTK_BOX(details_page_vbox_), value_vbox,
616                      TRUE, TRUE, 0);
617   gtk_box_pack_start(GTK_BOX(value_vbox),
618                      gtk_util::CreateBoldLabel(l10n_util::GetStringUTF8(
619                          IDS_CERT_DETAILS_CERTIFICATE_FIELD_VALUE_LABEL)),
620                      FALSE, FALSE, 0);
621
622   // TODO(mattm): fix text view coloring (should have grey background).
623   GtkWidget* field_value_view = gtk_text_view_new();
624   gtk_text_view_set_editable(GTK_TEXT_VIEW(field_value_view), FALSE);
625   gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(field_value_view), GTK_WRAP_NONE);
626   field_value_buffer_ = gtk_text_view_get_buffer(
627       GTK_TEXT_VIEW(field_value_view));
628   GtkWidget* value_scroll_window = gtk_scrolled_window_new(NULL, NULL);
629   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(value_scroll_window),
630                                  GTK_POLICY_AUTOMATIC,
631                                  GTK_POLICY_AUTOMATIC);
632   gtk_scrolled_window_set_shadow_type(
633       GTK_SCROLLED_WINDOW(value_scroll_window), GTK_SHADOW_ETCHED_IN);
634   gtk_container_add(GTK_CONTAINER(value_scroll_window), field_value_view);
635   gtk_box_pack_start(GTK_BOX(value_vbox),
636                      value_scroll_window, TRUE, TRUE, 0);
637
638   gtk_widget_ensure_style(field_value_view);
639   gfx::ScopedPangoFontDescription font_desc(pango_font_description_copy(
640       gtk_widget_get_style(field_value_view)->font_desc));
641   pango_font_description_set_family(font_desc.get(), kDetailsFontFamily);
642   gtk_widget_modify_font(field_value_view, font_desc.get());
643
644   GtkWidget* export_hbox = gtk_hbox_new(FALSE, 0);
645   gtk_box_pack_start(GTK_BOX(details_page_vbox_), export_hbox,
646                      FALSE, FALSE, 0);
647   export_button_ = gtk_button_new_with_mnemonic(
648       ui::ConvertAcceleratorsFromWindowsStyle(
649           l10n_util::GetStringUTF8(
650               IDS_CERT_DETAILS_EXPORT_CERTIFICATE)).c_str());
651   g_signal_connect(export_button_, "clicked",
652                    G_CALLBACK(OnExportClicked), this);
653   gtk_box_pack_start(GTK_BOX(export_hbox), export_button_,
654                      FALSE, FALSE, 0);
655
656   // Select the initial certificate in the hierarchy.
657   gtk_tree_selection_select_iter(hierarchy_selection_, &hierarchy_leaf_iter);
658 }
659
660 // static
661 void CertificateViewer::OnHierarchySelectionChanged(
662     GtkTreeSelection* selection, CertificateViewer* viewer) {
663   GtkTreeIter iter;
664   GtkTreeModel* model;
665   if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
666     GtkTreeStore* fields_store = NULL;
667     gtk_tree_model_get(model, &iter, HIERARCHY_OBJECT, &fields_store, -1);
668     gtk_tree_view_set_model(GTK_TREE_VIEW(viewer->fields_tree_),
669                             GTK_TREE_MODEL(fields_store));
670     gtk_tree_view_expand_all(GTK_TREE_VIEW(viewer->fields_tree_));
671     gtk_widget_set_sensitive(viewer->export_button_, TRUE);
672   } else {
673     gtk_tree_view_set_model(GTK_TREE_VIEW(viewer->fields_tree_), NULL);
674     gtk_widget_set_sensitive(viewer->export_button_, FALSE);
675   }
676 }
677
678 // static
679 void CertificateViewer::OnFieldsSelectionChanged(GtkTreeSelection* selection,
680                                                  CertificateViewer* viewer) {
681   GtkTreeIter iter;
682   GtkTreeModel* model;
683   if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
684     gchar* value_string = NULL;
685     gtk_tree_model_get(model, &iter, FIELDS_VALUE, &value_string, -1);
686     if (value_string) {
687       gtk_text_buffer_set_text(viewer->field_value_buffer_, value_string, -1);
688       g_free(value_string);
689     } else {
690       gtk_text_buffer_set_text(viewer->field_value_buffer_, "", 0);
691     }
692   } else {
693     gtk_text_buffer_set_text(viewer->field_value_buffer_, "", 0);
694   }
695 }
696
697 // static
698 void CertificateViewer::OnExportClicked(GtkButton *button,
699                                         CertificateViewer* viewer) {
700   GtkTreeIter iter;
701   GtkTreeModel* model;
702   if (!gtk_tree_selection_get_selected(viewer->hierarchy_selection_, &model,
703                                        &iter))
704     return;
705   gint cert_index = -1;
706   gtk_tree_model_get(model, &iter, HIERARCHY_INDEX, &cert_index, -1);
707
708   if (cert_index < 0) {
709     NOTREACHED();
710     return;
711   }
712
713   ShowCertExportDialog(NULL, GTK_WINDOW(viewer->dialog_),
714                        viewer->cert_chain_list_[cert_index]);
715 }
716
717 void CertificateViewer::Show() {
718   gtk_util::ShowDialog(dialog_);
719 }
720
721 } // namespace
722
723 void ShowCertificateViewer(content::WebContents* web_contents,
724                            gfx::NativeWindow parent,
725                            net::X509Certificate* cert) {
726   (new CertificateViewer(parent, cert))->Show();
727 }