Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(23)

Side by Side Diff: chrome/browser/gtk/certificate_manager.cc

Issue 3565006: Decouples certificates viewers from NSS to prepare support for OpenSSL. (Closed)
Patch Set: Comments / ProcessIDN Created 10 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/gtk/certificate_manager.h ('k') | chrome/browser/gtk/certificate_viewer.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2010 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/gtk/certificate_manager.h"
6
7 #include <cert.h>
8 #include <gtk/gtk.h>
9 #include <pk11pub.h>
10
11 #include <map>
12 #include <string>
13
14 #include "app/gtk_signal.h"
15 #include "app/l10n_util.h"
16 #include "app/l10n_util_collator.h"
17 #include "base/gtk_util.h"
18 #include "base/i18n/time_formatting.h"
19 #include "base/nss_util.h"
20 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/gtk/certificate_viewer.h"
22 #include "chrome/browser/gtk/gtk_util.h"
23 #include "chrome/browser/prefs/pref_member.h"
24 #include "chrome/browser/prefs/pref_service.h"
25 #include "chrome/browser/profile.h"
26 #include "chrome/common/pref_names.h"
27 #include "chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h"
28 #include "chrome/third_party/mozilla_security_manager/nsNSSCertificate.h"
29 #include "grit/generated_resources.h"
30
31 // PSM = Mozilla's Personal Security Manager.
32 namespace psm = mozilla_security_manager;
33
34 namespace {
35
36 // Convert a char* return value from NSS into a std::string and free the NSS
37 // memory. If the arg is NULL, an empty string will be returned instead.
38 std::string Stringize(char* nss_text) {
39 std::string s;
40 if (nss_text) {
41 s = nss_text;
42 PORT_Free(nss_text);
43 }
44 return s;
45 }
46
47 ////////////////////////////////////////////////////////////////////////////////
48 // CertificatePage class definition.
49
50 class CertificatePage {
51 public:
52 explicit CertificatePage(net::CertType type);
53 virtual ~CertificatePage() {}
54
55 void PopulateTree(CERTCertList* cert_list);
56
57 // Get the top-level widget of this page.
58 GtkWidget* widget() { return vbox_; }
59
60 private:
61 // Columns of the tree store.
62 enum {
63 CERT_NAME,
64 CERT_SECURITY_DEVICE,
65 CERT_SERIAL_NUMBER,
66 CERT_EXPIRES_ON,
67 CERT_EXPIRES_ON_INT,
68 CERT_ADDRESS,
69 CERT_POINTER,
70 CERT_STORE_NUM_COLUMNS
71 };
72
73 gint LocaleSortFunc(GtkTreeModel* model, GtkTreeIter* a, GtkTreeIter* b,
74 int col);
75
76 // Gtk event callbacks.
77 CHROMEG_CALLBACK_2(CertificatePage, gint, SortNameFunc, GtkTreeModel*,
78 GtkTreeIter*, GtkTreeIter*);
79 CHROMEG_CALLBACK_2(CertificatePage, gint, SortDeviceFunc, GtkTreeModel*,
80 GtkTreeIter*, GtkTreeIter*);
81 CHROMEG_CALLBACK_0(CertificatePage, void, OnSelectionChanged,
82 GtkTreeSelection*);
83 CHROMEGTK_CALLBACK_0(CertificatePage, void, OnViewClicked);
84
85 net::CertType type_;
86
87 // The top-level widget of this page.
88 GtkWidget* vbox_;
89
90 GtkWidget* tree_;
91 GtkTreeStore* store_;
92 GtkTreeSelection* selection_;
93 scoped_ptr<icu::Collator> collator_;
94
95 GtkWidget* view_button_;
96 };
97
98 ////////////////////////////////////////////////////////////////////////////////
99 // CertificatePage implementation.
100
101 CertificatePage::CertificatePage(net::CertType type) : type_(type) {
102 vbox_ = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
103 gtk_container_set_border_width(GTK_CONTAINER(vbox_),
104 gtk_util::kContentAreaBorder);
105
106 static const int kDescriptionIds[] = {
107 IDS_CERT_MANAGER_USER_TREE_DESCRIPTION,
108 IDS_CERT_MANAGER_OTHER_PEOPLE_TREE_DESCRIPTION,
109 IDS_CERT_MANAGER_SERVER_TREE_DESCRIPTION,
110 IDS_CERT_MANAGER_AUTHORITIES_TREE_DESCRIPTION,
111 IDS_CERT_MANAGER_UNKNOWN_TREE_DESCRIPTION,
112 };
113 DCHECK_EQ(arraysize(kDescriptionIds),
114 static_cast<size_t>(net::NUM_CERT_TYPES));
115 GtkWidget* description_label = gtk_label_new(l10n_util::GetStringUTF8(
116 kDescriptionIds[type]).c_str());
117 gtk_util::LeftAlignMisc(description_label);
118 gtk_box_pack_start(GTK_BOX(vbox_), description_label, FALSE, FALSE, 0);
119
120 store_ = gtk_tree_store_new(CERT_STORE_NUM_COLUMNS,
121 G_TYPE_STRING,
122 G_TYPE_STRING,
123 G_TYPE_STRING,
124 G_TYPE_STRING,
125 G_TYPE_INT64,
126 G_TYPE_STRING,
127 G_TYPE_POINTER);
128 tree_ = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store_));
129 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_), TRUE);
130 selection_ = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_));
131 gtk_tree_selection_set_mode(selection_, GTK_SELECTION_SINGLE);
132 g_signal_connect(selection_, "changed", G_CALLBACK(OnSelectionChangedThunk),
133 this);
134
135 GtkTreeViewColumn* name_col = gtk_tree_view_column_new_with_attributes(
136 l10n_util::GetStringUTF8(IDS_CERT_MANAGER_NAME_COLUMN_LABEL).c_str(),
137 gtk_cell_renderer_text_new(),
138 "text", CERT_NAME,
139 NULL);
140 gtk_tree_view_column_set_sort_column_id(name_col, CERT_NAME);
141 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_), name_col);
142
143 if (type == net::USER_CERT || type == net::CA_CERT ||
144 type == net::UNKNOWN_CERT) {
145 GtkTreeViewColumn* device_col = gtk_tree_view_column_new_with_attributes(
146 l10n_util::GetStringUTF8(
147 IDS_CERT_MANAGER_DEVICE_COLUMN_LABEL).c_str(),
148 gtk_cell_renderer_text_new(),
149 "text", CERT_SECURITY_DEVICE,
150 NULL);
151 gtk_tree_view_column_set_sort_column_id(device_col, CERT_SECURITY_DEVICE);
152 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_), device_col);
153 }
154
155 if (type == net::USER_CERT) {
156 GtkTreeViewColumn* serial_col = gtk_tree_view_column_new_with_attributes(
157 l10n_util::GetStringUTF8(
158 IDS_CERT_MANAGER_SERIAL_NUMBER_COLUMN_LABEL).c_str(),
159 gtk_cell_renderer_text_new(),
160 "text", CERT_SERIAL_NUMBER,
161 NULL);
162 gtk_tree_view_column_set_sort_column_id(serial_col, CERT_SERIAL_NUMBER);
163 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_), serial_col);
164 }
165
166 if (type == net::USER_CERT || type == net::EMAIL_CERT ||
167 type == net::SERVER_CERT) {
168 GtkTreeViewColumn* expires_col = gtk_tree_view_column_new_with_attributes(
169 l10n_util::GetStringUTF8(
170 IDS_CERT_MANAGER_EXPIRES_COLUMN_LABEL).c_str(),
171 gtk_cell_renderer_text_new(),
172 "text", CERT_EXPIRES_ON,
173 NULL);
174 gtk_tree_view_column_set_sort_column_id(expires_col, CERT_EXPIRES_ON_INT);
175 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_), expires_col);
176 }
177
178 if (type == net::EMAIL_CERT) {
179 GtkTreeViewColumn* addr_col = gtk_tree_view_column_new_with_attributes(
180 l10n_util::GetStringUTF8(
181 IDS_CERT_MANAGER_EMAIL_ADDRESS_COLUMN_LABEL).c_str(),
182 gtk_cell_renderer_text_new(),
183 "text", CERT_ADDRESS,
184 NULL);
185 gtk_tree_view_column_set_sort_column_id(addr_col, CERT_ADDRESS);
186 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_), addr_col);
187 }
188
189 UErrorCode error = U_ZERO_ERROR;
190 collator_.reset(
191 icu::Collator::createInstance(
192 icu::Locale(g_browser_process->GetApplicationLocale().c_str()),
193 error));
194 if (U_FAILURE(error))
195 collator_.reset(NULL);
196 if (collator_ != NULL) {
197 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store_), CERT_NAME,
198 SortNameFuncThunk, this, NULL);
199 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store_),
200 CERT_SECURITY_DEVICE, SortDeviceFuncThunk,
201 this, NULL);
202 }
203
204 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store_), CERT_NAME,
205 GTK_SORT_ASCENDING);
206
207 GtkWidget* scroll_window = gtk_scrolled_window_new(NULL, NULL);
208 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_window),
209 GTK_POLICY_AUTOMATIC,
210 GTK_POLICY_AUTOMATIC);
211 gtk_scrolled_window_set_shadow_type(
212 GTK_SCROLLED_WINDOW(scroll_window), GTK_SHADOW_ETCHED_IN);
213 gtk_container_add(GTK_CONTAINER(scroll_window), tree_);
214 gtk_box_pack_start(GTK_BOX(vbox_), scroll_window, TRUE, TRUE, 0);
215
216 GtkWidget* button_box = gtk_hbox_new(FALSE, gtk_util::kControlSpacing);
217 gtk_box_pack_start(GTK_BOX(vbox_), button_box, FALSE, FALSE, 0);
218
219 view_button_ = gtk_button_new_with_mnemonic(
220 gtk_util::ConvertAcceleratorsFromWindowsStyle(
221 l10n_util::GetStringUTF8(
222 IDS_CERT_MANAGER_VIEW_CERT_BUTTON)).c_str());
223 gtk_widget_set_sensitive(view_button_, FALSE);
224 g_signal_connect(view_button_, "clicked",
225 G_CALLBACK(OnViewClickedThunk), this);
226 gtk_box_pack_start(GTK_BOX(button_box), view_button_, FALSE, FALSE, 0);
227
228 // TODO(mattm): Add buttons for import, export, delete, etc
229 }
230
231 void CertificatePage::PopulateTree(CERTCertList* cert_list) {
232 DCHECK(gtk_tree_model_get_flags(GTK_TREE_MODEL(store_)) &
233 GTK_TREE_MODEL_ITERS_PERSIST);
234
235 typedef std::map<std::string, GtkTreeIter> OrgTreeMap;
236 OrgTreeMap org_tree_map;
237
238 CERTCertListNode* node;
239 for (node = CERT_LIST_HEAD(cert_list);
240 !CERT_LIST_END(node, cert_list);
241 node = CERT_LIST_NEXT(node)) {
242 CERTCertificate* cert = node->cert;
243 net::CertType type = psm::GetCertType(cert);
244 if (type == type_) {
245 std::string org = Stringize(CERT_GetOrgName(&cert->subject));
246 if (org.empty())
247 org = Stringize(CERT_GetCommonName(&cert->subject));
248 OrgTreeMap::iterator org_tree_map_iter = org_tree_map.find(org);
249 if (org_tree_map_iter == org_tree_map.end()) {
250 GtkTreeIter iter;
251 gtk_tree_store_append(store_, &iter, NULL);
252 gtk_tree_store_set(store_, &iter, CERT_NAME, org.c_str(), -1);
253 org_tree_map_iter = org_tree_map.insert(std::make_pair(org,
254 iter)).first;
255 }
256 std::string name = psm::ProcessIDN(
257 Stringize(CERT_GetCommonName(&cert->subject)));
258 if (name.empty() && cert->nickname) {
259 name = cert->nickname;
260 // Hack copied from mozilla: Cut off text before first :, which seems to
261 // just be the token name.
262 size_t colon_pos = name.find(':');
263 if (colon_pos != std::string::npos)
264 name = name.substr(colon_pos + 1);
265 }
266 GtkTreeIter iter;
267 gtk_tree_store_append(store_, &iter, &org_tree_map_iter->second);
268 gtk_tree_store_set(store_, &iter,
269 CERT_NAME, name.c_str(),
270 CERT_SECURITY_DEVICE,
271 psm::GetCertTokenName(cert).c_str(),
272 CERT_SERIAL_NUMBER,
273 Stringize(CERT_Hexify(
274 &cert->serialNumber, TRUE)).c_str(),
275 CERT_ADDRESS, cert->emailAddr,
276 CERT_POINTER, cert,
277 -1);
278
279 PRTime issued, expires;
280 if (CERT_GetCertTimes(cert, &issued, &expires) == SECSuccess) {
281 gtk_tree_store_set(store_, &iter,
282 CERT_EXPIRES_ON,
283 WideToUTF8(base::TimeFormatShortDateNumeric(
284 base::PRTimeToBaseTime(expires))).c_str(),
285 CERT_EXPIRES_ON_INT, expires,
286 -1);
287 }
288 }
289 }
290
291 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree_));
292 }
293
294 gint CertificatePage::LocaleSortFunc(GtkTreeModel* model,
295 GtkTreeIter* a,
296 GtkTreeIter* b,
297 int col) {
298 gchar* value1 = NULL;
299 gchar* value2 = NULL;
300 gtk_tree_model_get(model, a, col, &value1, -1);
301 gtk_tree_model_get(model, b, col, &value2, -1);
302 if (!value1 || !value2) {
303 if (value1)
304 return 1;
305 if (value2)
306 return -1;
307 return 0;
308 }
309
310 return l10n_util::CompareStringWithCollator(collator_.get(),
311 UTF8ToWide(value1),
312 UTF8ToWide(value2));
313 }
314
315 gint CertificatePage::SortNameFunc(GtkTreeModel* model, GtkTreeIter* a,
316 GtkTreeIter* b) {
317 return LocaleSortFunc(model, a, b, CERT_NAME);
318 }
319
320 gint CertificatePage::SortDeviceFunc(GtkTreeModel* model, GtkTreeIter* a,
321 GtkTreeIter* b) {
322 return LocaleSortFunc(model, a, b, CERT_SECURITY_DEVICE);
323 }
324
325 void CertificatePage::OnSelectionChanged(GtkTreeSelection* selection) {
326 CERTCertificate* cert = NULL;
327 GtkTreeIter iter;
328 GtkTreeModel* model;
329 if (gtk_tree_selection_get_selected(selection_, &model, &iter))
330 gtk_tree_model_get(model, &iter, CERT_POINTER, &cert, -1);
331
332 gtk_widget_set_sensitive(view_button_, cert ? TRUE : FALSE);
333 }
334
335 void CertificatePage::OnViewClicked(GtkWidget* button) {
336 GtkTreeIter iter;
337 GtkTreeModel* model;
338 if (!gtk_tree_selection_get_selected(selection_, &model, &iter))
339 return;
340
341 CERTCertificate* cert = NULL;
342 gtk_tree_model_get(model, &iter, CERT_POINTER, &cert, -1);
343 if (cert)
344 ShowCertificateViewer(GTK_WINDOW(gtk_widget_get_toplevel(widget())), cert);
345 }
346
347 ////////////////////////////////////////////////////////////////////////////////
348 // CertificateManager class definition.
349
350 class CertificateManager {
351 public:
352 explicit CertificateManager(gfx::NativeWindow parent, Profile* profile);
353 virtual ~CertificateManager();
354
355 // Shows the Tab corresponding to the specified |page|.
356 void ShowCertificatePage(CertificateManagerPage page);
357
358 private:
359 CHROMEGTK_CALLBACK_2(CertificateManager, void, OnSwitchPage,
360 GtkNotebookPage*, guint);
361
362 CERTCertList* cert_list_;
363
364 CertificatePage user_page_;
365 CertificatePage email_page_;
366 CertificatePage server_page_;
367 CertificatePage ca_page_;
368 CertificatePage unknown_page_;
369
370 GtkWidget* dialog_;
371
372 GtkWidget* notebook_;
373
374 // The last page the user was on when they opened the CertificateManager
375 // window.
376 IntegerPrefMember last_selected_page_;
377
378 DISALLOW_COPY_AND_ASSIGN(CertificateManager);
379 };
380
381 ////////////////////////////////////////////////////////////////////////////////
382 // CertificateManager implementation.
383
384 void OnDestroy(GtkDialog* dialog, CertificateManager* cert_manager) {
385 delete cert_manager;
386 }
387
388 CertificateManager::CertificateManager(gfx::NativeWindow parent,
389 Profile* profile)
390 : user_page_(net::USER_CERT),
391 email_page_(net::EMAIL_CERT),
392 server_page_(net::SERVER_CERT),
393 ca_page_(net::CA_CERT),
394 unknown_page_(net::UNKNOWN_CERT) {
395 // We don't need to observe changes in this value.
396 last_selected_page_.Init(prefs::kCertificateManagerWindowLastTabIndex,
397 profile->GetPrefs(), NULL);
398
399 dialog_ = gtk_dialog_new_with_buttons(
400 l10n_util::GetStringUTF8(IDS_CERTIFICATE_MANAGER_TITLE).c_str(),
401 parent,
402 // Non-modal.
403 GTK_DIALOG_NO_SEPARATOR,
404 GTK_STOCK_CLOSE,
405 GTK_RESPONSE_CLOSE,
406 NULL);
407 gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog_)->vbox),
408 gtk_util::kContentAreaSpacing);
409 gtk_window_set_default_size(GTK_WINDOW(dialog_), 600, 440);
410
411 notebook_ = gtk_notebook_new();
412 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog_)->vbox), notebook_);
413
414 gtk_notebook_append_page(
415 GTK_NOTEBOOK(notebook_),
416 user_page_.widget(),
417 gtk_label_new_with_mnemonic(
418 l10n_util::GetStringUTF8(
419 IDS_CERT_MANAGER_PERSONAL_CERTS_TAB_LABEL).c_str()));
420
421 gtk_notebook_append_page(
422 GTK_NOTEBOOK(notebook_),
423 email_page_.widget(),
424 gtk_label_new_with_mnemonic(
425 l10n_util::GetStringUTF8(
426 IDS_CERT_MANAGER_OTHER_PEOPLES_CERTS_TAB_LABEL).c_str()));
427
428 gtk_notebook_append_page(
429 GTK_NOTEBOOK(notebook_),
430 server_page_.widget(),
431 gtk_label_new_with_mnemonic(
432 l10n_util::GetStringUTF8(
433 IDS_CERT_MANAGER_SERVER_CERTS_TAB_LABEL).c_str()));
434
435 gtk_notebook_append_page(
436 GTK_NOTEBOOK(notebook_),
437 ca_page_.widget(),
438 gtk_label_new_with_mnemonic(
439 l10n_util::GetStringUTF8(
440 IDS_CERT_MANAGER_CERT_AUTHORITIES_TAB_LABEL).c_str()));
441
442 gtk_notebook_append_page(
443 GTK_NOTEBOOK(notebook_),
444 unknown_page_.widget(),
445 gtk_label_new_with_mnemonic(
446 l10n_util::GetStringUTF8(
447 IDS_CERT_MANAGER_UNKNOWN_TAB_LABEL).c_str()));
448
449 cert_list_ = PK11_ListCerts(PK11CertListUnique, NULL);
450 user_page_.PopulateTree(cert_list_);
451 email_page_.PopulateTree(cert_list_);
452 server_page_.PopulateTree(cert_list_);
453 ca_page_.PopulateTree(cert_list_);
454 unknown_page_.PopulateTree(cert_list_);
455
456 // Need to show the notebook before connecting switch-page signal, otherwise
457 // we'll immediately get a signal switching to page 0 and overwrite our
458 // last_selected_page_ value.
459 gtk_util::ShowDialogWithLocalizedSize(dialog_, -1, -1, true);
460
461 g_signal_connect(notebook_, "switch-page",
462 G_CALLBACK(OnSwitchPageThunk), this);
463
464 g_signal_connect(dialog_, "response", G_CALLBACK(gtk_widget_destroy), NULL);
465 g_signal_connect(dialog_, "destroy", G_CALLBACK(OnDestroy), this);
466 }
467
468 CertificateManager::~CertificateManager() {
469 CERT_DestroyCertList(cert_list_);
470 }
471
472 void CertificateManager::OnSwitchPage(GtkWidget* notebook,
473 GtkNotebookPage* page,
474 guint page_num) {
475 int index = static_cast<int>(page_num);
476 DCHECK(index > CERT_MANAGER_PAGE_DEFAULT && index < CERT_MANAGER_PAGE_COUNT);
477 last_selected_page_.SetValue(index);
478 }
479
480 void CertificateManager::ShowCertificatePage(CertificateManagerPage page) {
481 // Bring options window to front if it already existed and isn't already
482 // in front
483 gtk_window_present_with_time(GTK_WINDOW(dialog_),
484 gtk_get_current_event_time());
485
486 if (page == CERT_MANAGER_PAGE_DEFAULT) {
487 // Remember the last visited page from local state.
488 page = static_cast<CertificateManagerPage>(last_selected_page_.GetValue());
489 if (page == CERT_MANAGER_PAGE_DEFAULT)
490 page = CERT_MANAGER_PAGE_USER;
491 }
492 // If the page number is out of bounds, reset to the first tab.
493 if (page < 0 || page >= gtk_notebook_get_n_pages(GTK_NOTEBOOK(notebook_)))
494 page = CERT_MANAGER_PAGE_USER;
495
496 gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook_), page);
497 }
498
499 } // namespace
500
501 namespace certificate_manager_util {
502
503 void RegisterUserPrefs(PrefService* prefs) {
504 prefs->RegisterIntegerPref(prefs::kCertificateManagerWindowLastTabIndex, 0);
505 }
506
507 } // namespace certificate_manager_util
508
509 void ShowCertificateManager(gfx::NativeWindow parent, Profile* profile,
510 CertificateManagerPage page) {
511 base::EnsureNSSInit();
512 CertificateManager* manager = new CertificateManager(parent, profile);
513 manager->ShowCertificatePage(page);
514 }
OLDNEW
« no previous file with comments | « chrome/browser/gtk/certificate_manager.h ('k') | chrome/browser/gtk/certificate_viewer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698