diff options
author | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-20 22:14:07 +0000 |
---|---|---|
committer | mattm@chromium.org <mattm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-20 22:14:07 +0000 |
commit | 1e507001a1f4b7e9f96ad4faffd0448a586ac304 (patch) | |
tree | 3981374091abf45e8ca46a64e678efadc7c1ab38 /chrome/browser | |
parent | d64b07bf98e4f27da4c22da6c615b75d4b2e16bc (diff) | |
download | chromium_src-1e507001a1f4b7e9f96ad4faffd0448a586ac304.zip chromium_src-1e507001a1f4b7e9f96ad4faffd0448a586ac304.tar.gz chromium_src-1e507001a1f4b7e9f96ad4faffd0448a586ac304.tar.bz2 |
Linux: Populate certificate manager with certificates.
BUG=19991
TEST=manual
Review URL: http://codereview.chromium.org/1660007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@45095 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/gtk/certificate_manager.cc | 328 |
1 files changed, 241 insertions, 87 deletions
diff --git a/chrome/browser/gtk/certificate_manager.cc b/chrome/browser/gtk/certificate_manager.cc index 5ce7440..9b9c03e 100644 --- a/chrome/browser/gtk/certificate_manager.cc +++ b/chrome/browser/gtk/certificate_manager.cc @@ -5,32 +5,48 @@ #include "chrome/browser/gtk/certificate_manager.h" #include <cert.h> - #include <gtk/gtk.h> +#include <pk11pub.h> + +#include <map> +#include <string> +#include "app/gtk_signal.h" #include "app/l10n_util.h" +#include "app/l10n_util_collator.h" +#include "base/i18n/time_formatting.h" +#include "base/nss_util.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/gtk/certificate_viewer.h" #include "chrome/browser/gtk/gtk_util.h" +#include "chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h" +#include "chrome/third_party/mozilla_security_manager/nsNSSCertificate.h" #include "grit/generated_resources.h" +// PSM = Mozilla's Personal Security Manager. +namespace psm = mozilla_security_manager; + namespace { +// Convert a char* return value from NSS into a std::string and free the NSS +// memory. If the arg is NULL, an empty string will be returned instead. +std::string Stringize(char* nss_text) { + std::string s; + if (nss_text) { + s = nss_text; + PORT_Free(nss_text); + } + return s; +} + //////////////////////////////////////////////////////////////////////////////// // CertificatePage class definition. class CertificatePage { public: - // The categories of certificates that can be displayed. - enum CertType { - USER_CERTS = 0, - EMAIL_CERTS, - SERVER_CERTS, - CA_CERTS, - UNKNOWN_CERTS, - NUM_CERT_TYPES - }; + explicit CertificatePage(psm::CertType type); - explicit CertificatePage(CertType type); + void PopulateTree(CERTCertList* cert_list); // Get the top-level widget of this page. GtkWidget* widget() { @@ -44,21 +60,33 @@ class CertificatePage { CERT_SECURITY_DEVICE, CERT_SERIAL_NUMBER, CERT_EXPIRES_ON, + CERT_EXPIRES_ON_INT, CERT_ADDRESS, CERT_POINTER, CERT_STORE_NUM_COLUMNS }; + gint LocaleSortFunc(GtkTreeModel* model, GtkTreeIter* a, GtkTreeIter* b, + int col); + // Gtk event callbacks. - static void OnSelectionChanged(GtkTreeSelection* selection, - CertificatePage* page); - static void OnViewClicked(GtkButton *button, CertificatePage* page); + CHROMEG_CALLBACK_2(CertificatePage, gint, SortNameFunc, GtkTreeModel*, + GtkTreeIter*, GtkTreeIter*); + CHROMEG_CALLBACK_2(CertificatePage, gint, SortDeviceFunc, GtkTreeModel*, + GtkTreeIter*, GtkTreeIter*); + CHROMEG_CALLBACK_0(CertificatePage, void, OnSelectionChanged, + GtkTreeSelection*); + CHROMEGTK_CALLBACK_0(CertificatePage, void, OnViewClicked); + + psm::CertType type_; // The top-level widget of this page. GtkWidget* vbox_; + GtkWidget* tree_; GtkTreeStore* store_; GtkTreeSelection* selection_; + scoped_ptr<icu::Collator> collator_; GtkWidget* view_button_; }; @@ -66,7 +94,7 @@ class CertificatePage { //////////////////////////////////////////////////////////////////////////////// // CertificatePage implementation. -CertificatePage::CertificatePage(CertType type) { +CertificatePage::CertificatePage(psm::CertType type) : type_(type) { vbox_ = gtk_vbox_new(FALSE, gtk_util::kControlSpacing); gtk_container_set_border_width(GTK_CONTAINER(vbox_), gtk_util::kContentAreaBorder); @@ -79,10 +107,10 @@ CertificatePage::CertificatePage(CertType type) { IDS_CERT_MANAGER_UNKNOWN_TREE_DESCRIPTION, }; DCHECK_EQ(arraysize(kDescriptionIds), - static_cast<size_t>(NUM_CERT_TYPES)); + static_cast<size_t>(psm::NUM_CERT_TYPES)); GtkWidget* description_label = gtk_label_new(l10n_util::GetStringUTF8( kDescriptionIds[type]).c_str()); - gtk_misc_set_alignment(GTK_MISC(description_label), 0, 0.5); + gtk_util::LeftAlignMisc(description_label); gtk_box_pack_start(GTK_BOX(vbox_), description_label, FALSE, FALSE, 0); store_ = gtk_tree_store_new(CERT_STORE_NUM_COLUMNS, @@ -90,61 +118,87 @@ CertificatePage::CertificatePage(CertType type) { G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_INT64, G_TYPE_STRING, G_TYPE_POINTER); - GtkWidget* tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store_)); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree), TRUE); - selection_ = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)); + tree_ = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store_)); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_), TRUE); + selection_ = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_)); gtk_tree_selection_set_mode(selection_, GTK_SELECTION_SINGLE); - g_signal_connect(selection_, "changed", G_CALLBACK(OnSelectionChanged), this); - - gtk_tree_view_append_column( - GTK_TREE_VIEW(tree), - gtk_tree_view_column_new_with_attributes( - l10n_util::GetStringUTF8(IDS_CERT_MANAGER_NAME_COLUMN_LABEL).c_str(), - gtk_cell_renderer_text_new(), - "text", CERT_NAME, - NULL)); - - if (type == USER_CERTS || type == CA_CERTS || type == UNKNOWN_CERTS) - gtk_tree_view_append_column( - GTK_TREE_VIEW(tree), - gtk_tree_view_column_new_with_attributes( - l10n_util::GetStringUTF8( - IDS_CERT_MANAGER_DEVICE_COLUMN_LABEL).c_str(), - gtk_cell_renderer_text_new(), - "text", CERT_SECURITY_DEVICE, - NULL)); - - if (type == USER_CERTS) - gtk_tree_view_append_column( - GTK_TREE_VIEW(tree), - gtk_tree_view_column_new_with_attributes( - l10n_util::GetStringUTF8( - IDS_CERT_MANAGER_SERIAL_NUMBER_COLUMN_LABEL).c_str(), - gtk_cell_renderer_text_new(), - "text", CERT_SERIAL_NUMBER, - NULL)); - - if (type == USER_CERTS || type == EMAIL_CERTS || type == SERVER_CERTS) - gtk_tree_view_append_column( - GTK_TREE_VIEW(tree), - gtk_tree_view_column_new_with_attributes( - l10n_util::GetStringUTF8( - IDS_CERT_MANAGER_EXPIRES_COLUMN_LABEL).c_str(), - gtk_cell_renderer_text_new(), - "text", CERT_EXPIRES_ON, - NULL)); - - if (type == EMAIL_CERTS) - gtk_tree_view_append_column( - GTK_TREE_VIEW(tree), - gtk_tree_view_column_new_with_attributes( - l10n_util::GetStringUTF8( - IDS_CERT_MANAGER_EMAIL_ADDRESS_COLUMN_LABEL).c_str(), - gtk_cell_renderer_text_new(), - "text", CERT_ADDRESS, - NULL)); + g_signal_connect(selection_, "changed", G_CALLBACK(OnSelectionChangedThunk), + this); + + GtkTreeViewColumn* name_col = gtk_tree_view_column_new_with_attributes( + l10n_util::GetStringUTF8(IDS_CERT_MANAGER_NAME_COLUMN_LABEL).c_str(), + gtk_cell_renderer_text_new(), + "text", CERT_NAME, + NULL); + gtk_tree_view_column_set_sort_column_id(name_col, CERT_NAME); + gtk_tree_view_append_column(GTK_TREE_VIEW(tree_), name_col); + + if (type == psm::USER_CERT || type == psm::CA_CERT || + type == psm::UNKNOWN_CERT) { + GtkTreeViewColumn* device_col = gtk_tree_view_column_new_with_attributes( + l10n_util::GetStringUTF8( + IDS_CERT_MANAGER_DEVICE_COLUMN_LABEL).c_str(), + gtk_cell_renderer_text_new(), + "text", CERT_SECURITY_DEVICE, + NULL); + gtk_tree_view_column_set_sort_column_id(device_col, CERT_SECURITY_DEVICE); + gtk_tree_view_append_column(GTK_TREE_VIEW(tree_), device_col); + } + + if (type == psm::USER_CERT) { + GtkTreeViewColumn* serial_col = gtk_tree_view_column_new_with_attributes( + l10n_util::GetStringUTF8( + IDS_CERT_MANAGER_SERIAL_NUMBER_COLUMN_LABEL).c_str(), + gtk_cell_renderer_text_new(), + "text", CERT_SERIAL_NUMBER, + NULL); + gtk_tree_view_column_set_sort_column_id(serial_col, CERT_SERIAL_NUMBER); + gtk_tree_view_append_column(GTK_TREE_VIEW(tree_), serial_col); + } + + if (type == psm::USER_CERT || type == psm::EMAIL_CERT || + type == psm::SERVER_CERT) { + GtkTreeViewColumn* expires_col = gtk_tree_view_column_new_with_attributes( + l10n_util::GetStringUTF8( + IDS_CERT_MANAGER_EXPIRES_COLUMN_LABEL).c_str(), + gtk_cell_renderer_text_new(), + "text", CERT_EXPIRES_ON, + NULL); + gtk_tree_view_column_set_sort_column_id(expires_col, CERT_EXPIRES_ON_INT); + gtk_tree_view_append_column(GTK_TREE_VIEW(tree_), expires_col); + } + + if (type == psm::EMAIL_CERT) { + GtkTreeViewColumn* addr_col = gtk_tree_view_column_new_with_attributes( + l10n_util::GetStringUTF8( + IDS_CERT_MANAGER_EMAIL_ADDRESS_COLUMN_LABEL).c_str(), + gtk_cell_renderer_text_new(), + "text", CERT_ADDRESS, + NULL); + gtk_tree_view_column_set_sort_column_id(addr_col, CERT_ADDRESS); + gtk_tree_view_append_column(GTK_TREE_VIEW(tree_), addr_col); + } + + UErrorCode error = U_ZERO_ERROR; + collator_.reset( + icu::Collator::createInstance( + icu::Locale(g_browser_process->GetApplicationLocale().c_str()), + error)); + if (U_FAILURE(error)) + collator_.reset(NULL); + if (collator_ != NULL) { + gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store_), CERT_NAME, + SortNameFuncThunk, this, NULL); + gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store_), + CERT_SECURITY_DEVICE, SortDeviceFuncThunk, + this, NULL); + } + + gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store_), CERT_NAME, + GTK_SORT_ASCENDING); GtkWidget* scroll_window = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_window), @@ -152,7 +206,7 @@ CertificatePage::CertificatePage(CertType type) { GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(scroll_window), GTK_SHADOW_ETCHED_IN); - gtk_container_add(GTK_CONTAINER(scroll_window), tree); + gtk_container_add(GTK_CONTAINER(scroll_window), tree_); gtk_box_pack_start(GTK_BOX(vbox_), scroll_window, TRUE, TRUE, 0); GtkWidget* button_box = gtk_hbox_new(FALSE, gtk_util::kControlSpacing); @@ -164,38 +218,123 @@ CertificatePage::CertificatePage(CertType type) { IDS_CERT_MANAGER_VIEW_CERT_BUTTON)).c_str()); gtk_widget_set_sensitive(view_button_, FALSE); g_signal_connect(view_button_, "clicked", - G_CALLBACK(OnViewClicked), this); + G_CALLBACK(OnViewClickedThunk), this); gtk_box_pack_start(GTK_BOX(button_box), view_button_, FALSE, FALSE, 0); // TODO(mattm): Add buttons for import, export, delete, etc +} + +void CertificatePage::PopulateTree(CERTCertList* cert_list) { + DCHECK(gtk_tree_model_get_flags(GTK_TREE_MODEL(store_)) & + GTK_TREE_MODEL_ITERS_PERSIST); + + typedef std::map<std::string, GtkTreeIter> OrgTreeMap; + OrgTreeMap org_tree_map; + + CERTCertListNode* node; + for (node = CERT_LIST_HEAD(cert_list); + !CERT_LIST_END(node, cert_list); + node = CERT_LIST_NEXT(node)) { + CERTCertificate* cert = node->cert; + psm::CertType type = psm::GetCertType(cert); + if (type == type_) { + std::string org = Stringize(CERT_GetOrgName(&cert->subject)); + if (org.empty()) + org = Stringize(CERT_GetCommonName(&cert->subject)); + OrgTreeMap::iterator org_tree_map_iter = org_tree_map.find(org); + if (org_tree_map_iter == org_tree_map.end()) { + GtkTreeIter iter; + gtk_tree_store_append(store_, &iter, NULL); + gtk_tree_store_set(store_, &iter, CERT_NAME, org.c_str(), -1); + org_tree_map_iter = org_tree_map.insert(std::make_pair(org, + iter)).first; + } + std::string name = Stringize(CERT_GetCommonName(&cert->subject)); + if (name.empty() && cert->nickname) { + name = cert->nickname; + // Hack copied from mozilla: Cut off text before first :, which seems to + // just be the token name. + size_t colon_pos = name.find(':'); + if (colon_pos != std::string::npos) + name = name.substr(colon_pos + 1); + } + GtkTreeIter iter; + gtk_tree_store_append(store_, &iter, &org_tree_map_iter->second); + gtk_tree_store_set(store_, &iter, + CERT_NAME, name.c_str(), + CERT_SECURITY_DEVICE, psm::GetCertTokenName(cert).c_str(), + CERT_SERIAL_NUMBER, + Stringize(CERT_Hexify(&cert->serialNumber, TRUE)).c_str(), + CERT_ADDRESS, cert->emailAddr, + CERT_POINTER, cert, + -1); + + PRTime issued, expires; + if (CERT_GetCertTimes(cert, &issued, &expires) == SECSuccess) { + gtk_tree_store_set(store_, &iter, + CERT_EXPIRES_ON, + WideToUTF8(base::TimeFormatShortDateNumeric( + base::PRTimeToBaseTime(expires))).c_str(), + CERT_EXPIRES_ON_INT, expires, + -1); + } + } + } + + gtk_tree_view_expand_all(GTK_TREE_VIEW(tree_)); +} + +gint CertificatePage::LocaleSortFunc(GtkTreeModel* model, + GtkTreeIter* a, + GtkTreeIter* b, + int col) { + gchar* value1 = NULL; + gchar* value2 = NULL; + gtk_tree_model_get(model, a, col, &value1, -1); + gtk_tree_model_get(model, b, col, &value2, -1); + if (!value1 || !value2) { + if (value1) + return 1; + if (value2) + return -1; + return 0; + } + + return l10n_util::CompareStringWithCollator(collator_.get(), + UTF8ToWide(value1), + UTF8ToWide(value2)); +} + +gint CertificatePage::SortNameFunc(GtkTreeModel* model, GtkTreeIter* a, + GtkTreeIter* b) { + return LocaleSortFunc(model, a, b, CERT_NAME); +} - // TODO(mattm): Populate the tree. +gint CertificatePage::SortDeviceFunc(GtkTreeModel* model, GtkTreeIter* a, + GtkTreeIter* b) { + return LocaleSortFunc(model, a, b, CERT_SECURITY_DEVICE); } -// static -void CertificatePage::OnSelectionChanged(GtkTreeSelection* selection, - CertificatePage* page) { +void CertificatePage::OnSelectionChanged(GtkTreeSelection* selection) { CERTCertificate* cert = NULL; GtkTreeIter iter; GtkTreeModel* model; - if (gtk_tree_selection_get_selected(page->selection_, &model, &iter)) + if (gtk_tree_selection_get_selected(selection_, &model, &iter)) gtk_tree_model_get(model, &iter, CERT_POINTER, &cert, -1); - gtk_widget_set_sensitive(page->view_button_, cert ? TRUE : FALSE); + gtk_widget_set_sensitive(view_button_, cert ? TRUE : FALSE); } -// static -void CertificatePage::OnViewClicked(GtkButton *button, CertificatePage* page) { +void CertificatePage::OnViewClicked(GtkWidget* button) { GtkTreeIter iter; GtkTreeModel* model; - if (!gtk_tree_selection_get_selected(page->selection_, &model, &iter)) + if (!gtk_tree_selection_get_selected(selection_, &model, &iter)) return; CERTCertificate* cert = NULL; gtk_tree_model_get(model, &iter, CERT_POINTER, &cert, -1); if (cert) - ShowCertificateViewer(GTK_WINDOW(gtk_widget_get_toplevel(page->widget())), - cert); + ShowCertificateViewer(GTK_WINDOW(gtk_widget_get_toplevel(widget())), cert); } //////////////////////////////////////////////////////////////////////////////// @@ -204,10 +343,13 @@ void CertificatePage::OnViewClicked(GtkButton *button, CertificatePage* page) { class CertificateManager { public: explicit CertificateManager(gfx::NativeWindow parent); + ~CertificateManager(); void Show(); private: + CERTCertList* cert_list_; + CertificatePage user_page_; CertificatePage email_page_; CertificatePage server_page_; @@ -225,11 +367,11 @@ void OnDestroy(GtkDialog* dialog, CertificateManager* cert_manager) { } CertificateManager::CertificateManager(gfx::NativeWindow parent) - : user_page_(CertificatePage::USER_CERTS), - email_page_(CertificatePage::EMAIL_CERTS), - server_page_(CertificatePage::SERVER_CERTS), - ca_page_(CertificatePage::CA_CERTS), - unknown_page_(CertificatePage::UNKNOWN_CERTS) { + : user_page_(psm::USER_CERT), + email_page_(psm::EMAIL_CERT), + server_page_(psm::SERVER_CERT), + ca_page_(psm::CA_CERT), + unknown_page_(psm::UNKNOWN_CERT) { dialog_ = gtk_dialog_new_with_buttons( l10n_util::GetStringUTF8(IDS_CERTIFICATE_MANAGER_TITLE).c_str(), parent, @@ -281,10 +423,21 @@ CertificateManager::CertificateManager(gfx::NativeWindow parent) l10n_util::GetStringUTF8( IDS_CERT_MANAGER_UNKNOWN_TAB_LABEL).c_str())); + cert_list_ = PK11_ListCerts(PK11CertListUnique, NULL); + user_page_.PopulateTree(cert_list_); + email_page_.PopulateTree(cert_list_); + server_page_.PopulateTree(cert_list_); + ca_page_.PopulateTree(cert_list_); + unknown_page_.PopulateTree(cert_list_); + g_signal_connect(dialog_, "response", G_CALLBACK(gtk_widget_destroy), NULL); g_signal_connect(dialog_, "destroy", G_CALLBACK(OnDestroy), this); } +CertificateManager::~CertificateManager() { + CERT_DestroyCertList(cert_list_); +} + void CertificateManager::Show() { gtk_widget_show_all(dialog_); } @@ -292,5 +445,6 @@ void CertificateManager::Show() { } // namespace void ShowCertificateManager(gfx::NativeWindow parent) { + base::EnsureNSSInit(); (new CertificateManager(parent))->Show(); } |