certificate_viewer.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
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/nss_util.h" 14#include "base/scoped_ptr.h" 15#include "base/string_number_conversions.h" 16#include "base/time.h" 17#include "base/utf_string_conversions.h" 18#include "chrome/browser/ui/gtk/certificate_dialogs.h" 19#include "chrome/browser/ui/gtk/gtk_util.h" 20#include "chrome/common/net/x509_certificate_model.h" 21#include "grit/generated_resources.h" 22#include "net/base/x509_certificate.h" 23#include "ui/base/l10n/l10n_util.h" 24#include "ui/gfx/gtk_util.h" 25 26namespace { 27 28const char kDetailsFontFamily[] = "monospace"; 29 30//////////////////////////////////////////////////////////////////////////////// 31// Gtk utility functions. 32 33void AddTitle(GtkTable* table, int row, const std::string& text) { 34 gtk_table_attach_defaults(table, 35 gtk_util::CreateBoldLabel(text), 36 0, 2, 37 row, row + 1); 38} 39 40void AddKeyValue(GtkTable* table, int row, const std::string& text, 41 const std::string& value) { 42 gtk_table_attach_defaults( 43 table, 44 gtk_util::IndentWidget( 45 gtk_util::LeftAlignMisc(gtk_label_new(text.c_str()))), 46 0, 1, row, row + 1); 47 gtk_table_attach_defaults( 48 table, 49 gtk_util::LeftAlignMisc(gtk_label_new(value.c_str())), 50 1, 2, row, row + 1); 51} 52 53//////////////////////////////////////////////////////////////////////////////// 54// CertificateViewer class definition. 55 56class CertificateViewer { 57 public: 58 CertificateViewer(gfx::NativeWindow parent, 59 const net::X509Certificate::OSCertHandles& cert_chain_list); 60 ~CertificateViewer(); 61 62 void InitGeneralPage(); 63 void InitDetailsPage(); 64 65 void Show(); 66 67 private: 68 // Indices and column count for the certificate chain hierarchy tree store. 69 enum { 70 HIERARCHY_NAME, 71 HIERARCHY_OBJECT, 72 HIERARCHY_INDEX, 73 HIERARCHY_COLUMNS 74 }; 75 76 // Indices and column count for the certificate fields tree store. 77 enum { 78 FIELDS_NAME, 79 FIELDS_VALUE, 80 FIELDS_COLUMNS 81 }; 82 83 // Fill the tree store with the certificate hierarchy, and set |leaf| to the 84 // iter of the leaf node. 85 void FillHierarchyStore(GtkTreeStore* hierarchy_store, 86 GtkTreeIter* leaf) const; 87 88 // Fill the tree store with the details of the given certificate. 89 static void FillTreeStoreWithCertFields( 90 GtkTreeStore* store, net::X509Certificate::OSCertHandle cert); 91 92 // Create a tree store filled with the details of the given certificate. 93 static GtkTreeStore* CreateFieldsTreeStore( 94 net::X509Certificate::OSCertHandle cert); 95 96 // Callbacks for user selecting elements in the trees. 97 static void OnHierarchySelectionChanged(GtkTreeSelection* selection, 98 CertificateViewer* viewer); 99 static void OnFieldsSelectionChanged(GtkTreeSelection* selection, 100 CertificateViewer* viewer); 101 102 // Callback for export button. 103 static void OnExportClicked(GtkButton *button, CertificateViewer* viewer); 104 105 // The certificate hierarchy (leaf cert first). 106 net::X509Certificate::OSCertHandles cert_chain_list_; 107 108 GtkWidget* dialog_; 109 GtkWidget* notebook_; 110 GtkWidget* general_page_vbox_; 111 GtkWidget* details_page_vbox_; 112 GtkTreeSelection* hierarchy_selection_; 113 GtkWidget* fields_tree_; 114 GtkTextBuffer* field_value_buffer_; 115 GtkWidget* export_button_; 116 117 DISALLOW_COPY_AND_ASSIGN(CertificateViewer); 118}; 119 120//////////////////////////////////////////////////////////////////////////////// 121// CertificateViewer implementation. 122 123// Close button callback. 124void OnDialogResponse(GtkDialog* dialog, gint response_id, 125 gpointer user_data) { 126 // "Close" was clicked. 127 gtk_widget_destroy(GTK_WIDGET(dialog)); 128} 129 130void OnDestroy(GtkDialog* dialog, CertificateViewer* cert_viewer) { 131 delete cert_viewer; 132} 133 134CertificateViewer::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(OnDialogResponse), NULL); 177 g_signal_connect(dialog_, "destroy", G_CALLBACK(OnDestroy), this); 178} 179 180CertificateViewer::~CertificateViewer() { 181 x509_certificate_model::DestroyCertChain(&cert_chain_list_); 182} 183 184void 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 294void 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 319void 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 491// static 492GtkTreeStore* CertificateViewer::CreateFieldsTreeStore( 493 net::X509Certificate::OSCertHandle cert) { 494 GtkTreeStore* fields_store = gtk_tree_store_new(FIELDS_COLUMNS, G_TYPE_STRING, 495 G_TYPE_STRING); 496 FillTreeStoreWithCertFields(fields_store, cert); 497 return fields_store; 498} 499 500void CertificateViewer::InitDetailsPage() { 501 details_page_vbox_ = gtk_vbox_new(FALSE, gtk_util::kContentAreaSpacing); 502 gtk_container_set_border_width(GTK_CONTAINER(details_page_vbox_), 503 gtk_util::kContentAreaBorder); 504 505 GtkWidget* hierarchy_vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); 506 gtk_box_pack_start(GTK_BOX(details_page_vbox_), hierarchy_vbox, 507 FALSE, FALSE, 0); 508 509 gtk_box_pack_start(GTK_BOX(hierarchy_vbox), 510 gtk_util::CreateBoldLabel(l10n_util::GetStringUTF8( 511 IDS_CERT_DETAILS_CERTIFICATE_HIERARCHY_LABEL)), 512 FALSE, FALSE, 0); 513 514 GtkTreeStore* hierarchy_store = gtk_tree_store_new(HIERARCHY_COLUMNS, 515 G_TYPE_STRING, 516 G_TYPE_OBJECT, 517 G_TYPE_INT); 518 GtkTreeIter hierarchy_leaf_iter; 519 FillHierarchyStore(hierarchy_store, &hierarchy_leaf_iter); 520 GtkWidget* hierarchy_tree = gtk_tree_view_new_with_model( 521 GTK_TREE_MODEL(hierarchy_store)); 522 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(hierarchy_tree), FALSE); 523 gtk_tree_view_append_column( 524 GTK_TREE_VIEW(hierarchy_tree), 525 gtk_tree_view_column_new_with_attributes("", gtk_cell_renderer_text_new(), 526 "text", HIERARCHY_NAME, 527 NULL)); 528 gtk_tree_view_expand_all(GTK_TREE_VIEW(hierarchy_tree)); 529 hierarchy_selection_ = gtk_tree_view_get_selection( 530 GTK_TREE_VIEW(hierarchy_tree)); 531 gtk_tree_selection_set_mode(hierarchy_selection_, GTK_SELECTION_SINGLE); 532 g_signal_connect(hierarchy_selection_, "changed", 533 G_CALLBACK(OnHierarchySelectionChanged), this); 534 GtkWidget* hierarchy_scroll_window = gtk_scrolled_window_new(NULL, NULL); 535 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(hierarchy_scroll_window), 536 GTK_POLICY_AUTOMATIC, 537 GTK_POLICY_NEVER); 538 gtk_scrolled_window_set_shadow_type( 539 GTK_SCROLLED_WINDOW(hierarchy_scroll_window), GTK_SHADOW_ETCHED_IN); 540 gtk_container_add(GTK_CONTAINER(hierarchy_scroll_window), hierarchy_tree); 541 gtk_box_pack_start(GTK_BOX(hierarchy_vbox), 542 hierarchy_scroll_window, FALSE, FALSE, 0); 543 544 GtkWidget* fields_vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); 545 gtk_box_pack_start(GTK_BOX(details_page_vbox_), fields_vbox, 546 TRUE, TRUE, 0); 547 gtk_box_pack_start(GTK_BOX(fields_vbox), 548 gtk_util::CreateBoldLabel(l10n_util::GetStringUTF8( 549 IDS_CERT_DETAILS_CERTIFICATE_FIELDS_LABEL)), 550 FALSE, FALSE, 0); 551 552 fields_tree_ = gtk_tree_view_new(); 553 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(fields_tree_), FALSE); 554 gtk_tree_view_append_column( 555 GTK_TREE_VIEW(fields_tree_), 556 gtk_tree_view_column_new_with_attributes("", gtk_cell_renderer_text_new(), 557 "text", FIELDS_NAME, 558 NULL)); 559 GtkTreeSelection* fields_selection = gtk_tree_view_get_selection( 560 GTK_TREE_VIEW(fields_tree_)); 561 gtk_tree_selection_set_mode(fields_selection, GTK_SELECTION_SINGLE); 562 g_signal_connect(fields_selection, "changed", 563 G_CALLBACK(OnFieldsSelectionChanged), this); 564 GtkWidget* fields_scroll_window = gtk_scrolled_window_new(NULL, NULL); 565 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(fields_scroll_window), 566 GTK_POLICY_AUTOMATIC, 567 GTK_POLICY_AUTOMATIC); 568 gtk_scrolled_window_set_shadow_type( 569 GTK_SCROLLED_WINDOW(fields_scroll_window), GTK_SHADOW_ETCHED_IN); 570 gtk_container_add(GTK_CONTAINER(fields_scroll_window), fields_tree_); 571 gtk_box_pack_start(GTK_BOX(fields_vbox), 572 fields_scroll_window, TRUE, TRUE, 0); 573 574 GtkWidget* value_vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); 575 gtk_box_pack_start(GTK_BOX(details_page_vbox_), value_vbox, 576 TRUE, TRUE, 0); 577 gtk_box_pack_start(GTK_BOX(value_vbox), 578 gtk_util::CreateBoldLabel(l10n_util::GetStringUTF8( 579 IDS_CERT_DETAILS_CERTIFICATE_FIELD_VALUE_LABEL)), 580 FALSE, FALSE, 0); 581 582 // TODO(mattm): fix text view coloring (should have grey background). 583 GtkWidget* field_value_view = gtk_text_view_new(); 584 gtk_text_view_set_editable(GTK_TEXT_VIEW(field_value_view), FALSE); 585 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(field_value_view), GTK_WRAP_NONE); 586 field_value_buffer_ = gtk_text_view_get_buffer( 587 GTK_TEXT_VIEW(field_value_view)); 588 GtkWidget* value_scroll_window = gtk_scrolled_window_new(NULL, NULL); 589 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(value_scroll_window), 590 GTK_POLICY_AUTOMATIC, 591 GTK_POLICY_AUTOMATIC); 592 gtk_scrolled_window_set_shadow_type( 593 GTK_SCROLLED_WINDOW(value_scroll_window), GTK_SHADOW_ETCHED_IN); 594 gtk_container_add(GTK_CONTAINER(value_scroll_window), field_value_view); 595 gtk_box_pack_start(GTK_BOX(value_vbox), 596 value_scroll_window, TRUE, TRUE, 0); 597 598 gtk_widget_ensure_style(field_value_view); 599 PangoFontDescription* font_desc = pango_font_description_copy( 600 gtk_widget_get_style(field_value_view)->font_desc); 601 pango_font_description_set_family(font_desc, kDetailsFontFamily); 602 gtk_widget_modify_font(field_value_view, font_desc); 603 pango_font_description_free(font_desc); 604 605 GtkWidget* export_hbox = gtk_hbox_new(FALSE, 0); 606 gtk_box_pack_start(GTK_BOX(details_page_vbox_), export_hbox, 607 FALSE, FALSE, 0); 608 export_button_ = gtk_button_new_with_mnemonic( 609 gfx::ConvertAcceleratorsFromWindowsStyle( 610 l10n_util::GetStringUTF8( 611 IDS_CERT_DETAILS_EXPORT_CERTIFICATE)).c_str()); 612 g_signal_connect(export_button_, "clicked", 613 G_CALLBACK(OnExportClicked), this); 614 gtk_box_pack_start(GTK_BOX(export_hbox), export_button_, 615 FALSE, FALSE, 0); 616 617 // Select the initial certificate in the hierarchy. 618 gtk_tree_selection_select_iter(hierarchy_selection_, &hierarchy_leaf_iter); 619} 620 621// static 622void CertificateViewer::OnHierarchySelectionChanged( 623 GtkTreeSelection* selection, CertificateViewer* viewer) { 624 GtkTreeIter iter; 625 GtkTreeModel* model; 626 if (gtk_tree_selection_get_selected(selection, &model, &iter)) { 627 GtkTreeStore* fields_store = NULL; 628 gtk_tree_model_get(model, &iter, HIERARCHY_OBJECT, &fields_store, -1); 629 gtk_tree_view_set_model(GTK_TREE_VIEW(viewer->fields_tree_), 630 GTK_TREE_MODEL(fields_store)); 631 gtk_tree_view_expand_all(GTK_TREE_VIEW(viewer->fields_tree_)); 632 gtk_widget_set_sensitive(viewer->export_button_, TRUE); 633 } else { 634 gtk_tree_view_set_model(GTK_TREE_VIEW(viewer->fields_tree_), NULL); 635 gtk_widget_set_sensitive(viewer->export_button_, FALSE); 636 } 637} 638 639// static 640void CertificateViewer::OnFieldsSelectionChanged(GtkTreeSelection* selection, 641 CertificateViewer* viewer) { 642 GtkTreeIter iter; 643 GtkTreeModel* model; 644 if (gtk_tree_selection_get_selected(selection, &model, &iter)) { 645 gchar* value_string = NULL; 646 gtk_tree_model_get(model, &iter, FIELDS_VALUE, &value_string, -1); 647 if (value_string) { 648 gtk_text_buffer_set_text(viewer->field_value_buffer_, value_string, -1); 649 g_free(value_string); 650 } else { 651 gtk_text_buffer_set_text(viewer->field_value_buffer_, "", 0); 652 } 653 } else { 654 gtk_text_buffer_set_text(viewer->field_value_buffer_, "", 0); 655 } 656} 657 658// static 659void CertificateViewer::OnExportClicked(GtkButton *button, 660 CertificateViewer* viewer) { 661 GtkTreeIter iter; 662 GtkTreeModel* model; 663 if (!gtk_tree_selection_get_selected(viewer->hierarchy_selection_, &model, 664 &iter)) 665 return; 666 gint cert_index = -1; 667 gtk_tree_model_get(model, &iter, HIERARCHY_INDEX, &cert_index, -1); 668 669 if (cert_index < 0) { 670 NOTREACHED(); 671 return; 672 } 673 674 ShowCertExportDialog(GTK_WINDOW(viewer->dialog_), 675 viewer->cert_chain_list_[cert_index]); 676} 677 678void CertificateViewer::Show() { 679 gtk_util::ShowDialog(dialog_); 680} 681 682} // namespace 683 684void ShowCertificateViewer(gfx::NativeWindow parent, 685 net::X509Certificate::OSCertHandle cert) { 686 net::X509Certificate::OSCertHandles cert_chain; 687 x509_certificate_model::GetCertChainFromCert(cert, &cert_chain); 688 (new CertificateViewer(parent, cert_chain))->Show(); 689} 690 691void ShowCertificateViewer(gfx::NativeWindow parent, 692 net::X509Certificate* cert) { 693 ShowCertificateViewer(parent, cert->os_cert_handle()); 694} 695