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