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