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