Home | History | Annotate | Download | only in gtk
      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 }
    728