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

Side by Side Diff: chrome/browser/ssl/ssl_client_auth_handler_gtk.cc

Issue 661241: Linux: implement Client SSL Certificate selection UI (Closed)
Patch Set: fix views and chromeos builds hopefully Created 10 years, 9 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/ssl/ssl_client_auth_handler.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ssl/ssl_client_auth_handler.h" 5 #include "chrome/browser/ssl/ssl_client_auth_handler.h"
6
7 #include <cert.h>
8 #include <gtk/gtk.h>
9
10 #include <string>
11 #include <vector>
12
13 #include "app/gfx/native_widget_types.h"
14 #include "app/l10n_util.h"
15 #include "base/i18n/time_formatting.h"
6 #include "base/logging.h" 16 #include "base/logging.h"
17 #include "base/nss_util.h"
18 #include "chrome/browser/gtk/certificate_viewer.h"
19 #include "chrome/browser/gtk/gtk_util.h"
20 #include "chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h"
21 #include "chrome/third_party/mozilla_security_manager/nsNSSCertificate.h"
22 #include "chrome/third_party/mozilla_security_manager/nsUsageArrayHelper.h"
23 #include "grit/generated_resources.h"
7 #include "net/base/x509_certificate.h" 24 #include "net/base/x509_certificate.h"
8 25
26 // PSM = Mozilla's Personal Security Manager.
27 namespace psm = mozilla_security_manager;
28
29 namespace {
30
31 enum {
32 RESPONSE_SHOW_CERT_INFO = 1,
33 };
34
35
36 ///////////////////////////////////////////////////////////////////////////////
37 // SSLClientCertificateSelector
38
39 class SSLClientCertificateSelector {
40 public:
41 SSLClientCertificateSelector(gfx::NativeWindow parent,
42 net::SSLCertRequestInfo* cert_request_info,
43 SSLClientAuthHandler* delegate);
44
45 void Show();
46
47 private:
48 void PopulateCerts();
49
50 static std::string FormatComboBoxText(CERTCertificate* cert,
51 const char* nickname);
52 static std::string FormatDetailsText(CERTCertificate* cert);
53
54 static void OnComboBoxChanged(GtkComboBox* combo_box,
55 SSLClientCertificateSelector* cert_selector);
56 static void OnResponse(GtkDialog* dialog, gint response_id,
57 SSLClientCertificateSelector* cert_selector);
58 static void OnDestroy(GtkDialog* dialog,
59 SSLClientCertificateSelector* cert_selector);
60
61 SSLClientAuthHandler* delegate_;
62 scoped_refptr<net::SSLCertRequestInfo> cert_request_info_;
63
64 std::vector<std::string> details_strings_;
65
66 GtkWidget* dialog_;
67 GtkWidget* cert_combo_box_;
68 GtkTextBuffer* cert_details_buffer_;
69 };
70
71 SSLClientCertificateSelector::SSLClientCertificateSelector(
72 gfx::NativeWindow parent,
73 net::SSLCertRequestInfo* cert_request_info,
74 SSLClientAuthHandler* delegate)
75 : delegate_(delegate),
76 cert_request_info_(cert_request_info) {
77 dialog_ = gtk_dialog_new_with_buttons(
78 l10n_util::GetStringFUTF8(
79 IDS_CERT_SELECTOR_DIALOG_TITLE,
80 UTF8ToUTF16(cert_request_info->host_and_port)).c_str(),
81 parent,
82 // Non-modal.
83 GTK_DIALOG_NO_SEPARATOR,
84 l10n_util::GetStringUTF8(IDS_PAGEINFO_CERT_INFO_BUTTON).c_str(),
85 RESPONSE_SHOW_CERT_INFO,
86 GTK_STOCK_CANCEL,
87 GTK_RESPONSE_CANCEL,
88 GTK_STOCK_OK,
89 GTK_RESPONSE_OK,
90 NULL);
91 gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog_)->vbox),
92 gtk_util::kContentAreaSpacing);
93 gtk_dialog_set_default_response(GTK_DIALOG(dialog_), GTK_RESPONSE_OK);
94
95 GtkWidget* site_vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
96 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox), site_vbox,
97 FALSE, FALSE, 0);
98
99 GtkWidget* site_description_label = gtk_util::CreateBoldLabel(
100 l10n_util::GetStringUTF8(IDS_CERT_SELECTOR_SITE_DESCRIPTION_LABEL));
101 gtk_box_pack_start(GTK_BOX(site_vbox), site_description_label,
102 FALSE, FALSE, 0);
103
104 GtkWidget* site_label = gtk_label_new(
105 cert_request_info->host_and_port.c_str());
106 gtk_util::LeftAlignMisc(site_label);
107 gtk_box_pack_start(GTK_BOX(site_vbox), site_label, FALSE, FALSE, 0);
108
109 GtkWidget* selector_vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
110 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_)->vbox), selector_vbox,
111 TRUE, TRUE, 0);
112
113 GtkWidget* choose_description_label = gtk_util::CreateBoldLabel(
114 l10n_util::GetStringUTF8(IDS_CERT_SELECTOR_CHOOSE_DESCRIPTION_LABEL));
115 gtk_box_pack_start(GTK_BOX(selector_vbox), choose_description_label,
116 FALSE, FALSE, 0);
117
118
119 cert_combo_box_ = gtk_combo_box_new_text();
120 g_signal_connect(cert_combo_box_, "changed", G_CALLBACK(OnComboBoxChanged),
121 this);
122 gtk_box_pack_start(GTK_BOX(selector_vbox), cert_combo_box_,
123 FALSE, FALSE, 0);
124
125 GtkWidget* details_label = gtk_label_new(l10n_util::GetStringUTF8(
126 IDS_CERT_SELECTOR_DETAILS_DESCRIPTION_LABEL).c_str());
127 gtk_util::LeftAlignMisc(details_label);
128 gtk_box_pack_start(GTK_BOX(selector_vbox), details_label, FALSE, FALSE, 0);
129
130 // TODO(mattm): fix text view coloring (should have grey background).
131 GtkWidget* cert_details_view = gtk_text_view_new();
132 gtk_text_view_set_editable(GTK_TEXT_VIEW(cert_details_view), FALSE);
133 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(cert_details_view), GTK_WRAP_WORD);
134 cert_details_buffer_ = gtk_text_view_get_buffer(
135 GTK_TEXT_VIEW(cert_details_view));
136 // We put the details in a frame instead of a scrolled window so that the
137 // entirety will be visible without requiring scrolling or expanding the
138 // dialog. This does however mean the dialog will grow itself if you switch
139 // to different cert that has longer details text.
140 GtkWidget* details_frame = gtk_frame_new(NULL);
141 gtk_frame_set_shadow_type(GTK_FRAME(details_frame), GTK_SHADOW_ETCHED_IN);
142 gtk_container_add(GTK_CONTAINER(details_frame), cert_details_view);
143 gtk_box_pack_start(GTK_BOX(selector_vbox), details_frame, TRUE, TRUE, 0);
144
145 PopulateCerts();
146
147 g_signal_connect(dialog_, "response", G_CALLBACK(OnResponse), this);
148 g_signal_connect(dialog_, "destroy", G_CALLBACK(OnDestroy), this);
149 }
150
151 void SSLClientCertificateSelector::Show() {
152 gtk_widget_show_all(dialog_);
153 }
154
155 void SSLClientCertificateSelector::PopulateCerts() {
156 CERTCertList* cert_list = CERT_NewCertList();
157 for (size_t i = 0; i < cert_request_info_->client_certs.size(); ++i) {
158 CERT_AddCertToListTail(
159 cert_list,
160 CERT_DupCertificate(
161 cert_request_info_->client_certs[i]->os_cert_handle()));
162 }
163 // Would like to use CERT_GetCertNicknameWithValidity on each cert
164 // individually instead of having to build a CERTCertList for this, but that
165 // function is not exported.
166 CERTCertNicknames* nicknames = CERT_NicknameStringsFromCertList(
167 cert_list,
168 const_cast<char*>(l10n_util::GetStringUTF8(
169 IDS_CERT_SELECTOR_CERT_EXPIRED).c_str()),
170 const_cast<char*>(l10n_util::GetStringUTF8(
171 IDS_CERT_SELECTOR_CERT_NOT_YET_VALID).c_str()));
172 DCHECK_EQ(nicknames->numnicknames,
173 static_cast<int>(cert_request_info_->client_certs.size()));
174
175 for (size_t i = 0; i < cert_request_info_->client_certs.size(); ++i) {
176 CERTCertificate* cert =
177 cert_request_info_->client_certs[i]->os_cert_handle();
178
179 details_strings_.push_back(FormatDetailsText(cert));
180
181 gtk_combo_box_append_text(
182 GTK_COMBO_BOX(cert_combo_box_),
183 FormatComboBoxText(cert, nicknames->nicknames[i]).c_str());
184 }
185
186 CERT_FreeNicknames(nicknames);
187 CERT_DestroyCertList(cert_list);
188
189 // Auto-select the first cert.
190 gtk_combo_box_set_active(GTK_COMBO_BOX(cert_combo_box_), 0);
191 }
192
193 // static
194 std::string SSLClientCertificateSelector::FormatComboBoxText(
195 CERTCertificate* cert, const char* nickname) {
196 std::string rv(nickname);
197 char* serial_hex = CERT_Hexify(&cert->serialNumber, TRUE);
198 rv += " [";
199 rv += serial_hex;
200 rv += ']';
201 PORT_Free(serial_hex);
202 return rv;
203 }
204
205 // static
206 std::string SSLClientCertificateSelector::FormatDetailsText(
207 CERTCertificate* cert) {
208 std::string rv;
209
210 rv += l10n_util::GetStringFUTF8(IDS_CERT_SUBJECTNAME_FORMAT,
211 UTF8ToUTF16(cert->subjectName));
212
213 char* serial_hex = CERT_Hexify(&cert->serialNumber, TRUE);
214 rv += "\n ";
215 rv += l10n_util::GetStringFUTF8(IDS_CERT_SERIAL_NUMBER_FORMAT,
216 UTF8ToUTF16(serial_hex));
217 PORT_Free(serial_hex);
218
219 PRTime issued, expires;
220 if (CERT_GetCertTimes(cert, &issued, &expires) == SECSuccess) {
221 string16 issued_str = WideToUTF16(
222 base::TimeFormatShortDateAndTime(base::PRTimeToBaseTime(issued)));
223 string16 expires_str = WideToUTF16(
224 base::TimeFormatShortDateAndTime(base::PRTimeToBaseTime(expires)));
225 rv += "\n ";
226 rv += l10n_util::GetStringFUTF8(IDS_CERT_VALIDITY_RANGE_FORMAT,
227 issued_str, expires_str);
228 }
229
230 std::vector<std::string> usages;
231 psm::GetCertUsageStrings(cert, &usages);
232 if (usages.size()) {
233 rv += "\n ";
234 rv += l10n_util::GetStringFUTF8(IDS_CERT_X509_EXTENDED_KEY_USAGE_FORMAT,
235 UTF8ToUTF16(JoinString(usages, ',')));
236 }
237
238 SECItem key_usage;
239 key_usage.data = NULL;
240 if (CERT_FindKeyUsageExtension(cert, &key_usage) == SECSuccess) {
241 std::string key_usage_str = psm::ProcessKeyUsageBitString(&key_usage, ',');
242 PORT_Free(key_usage.data);
243 if (!key_usage_str.empty()) {
244 rv += "\n ";
245 rv += l10n_util::GetStringFUTF8(IDS_CERT_X509_KEY_USAGE_FORMAT,
246 UTF8ToUTF16(key_usage_str));
247 }
248 }
249
250 std::vector<std::string> email_addresses;
251 for (const char* addr = CERT_GetFirstEmailAddress(cert);
252 addr; addr = CERT_GetNextEmailAddress(cert, addr)) {
253 // The first email addr (from Subject) may be duplicated in Subject
254 // Alternative Name, so check subsequent addresses are not equal to the
255 // first one before adding to the list.
256 if (!email_addresses.size() || email_addresses[0] != addr)
257 email_addresses.push_back(addr);
258 }
259 if (email_addresses.size()) {
260 rv += "\n ";
261 rv += l10n_util::GetStringFUTF8(
262 IDS_CERT_EMAIL_ADDRESSES_FORMAT,
263 UTF8ToUTF16(JoinString(email_addresses, ',')));
264 }
265
266 rv += '\n';
267 rv += l10n_util::GetStringFUTF8(IDS_CERT_ISSUERNAME_FORMAT,
268 UTF8ToUTF16(cert->issuerName));
269
270 string16 token(UTF8ToUTF16(psm::GetCertTokenName(cert)));
271 if (!token.empty()) {
272 rv += '\n';
273 rv += l10n_util::GetStringFUTF8(IDS_CERT_TOKEN_FORMAT, token);
274 }
275
276 return rv;
277 }
278
279 // static
280 void SSLClientCertificateSelector::OnComboBoxChanged(
281 GtkComboBox* combo_box, SSLClientCertificateSelector* cert_selector) {
282 int selected = gtk_combo_box_get_active(
283 GTK_COMBO_BOX(cert_selector->cert_combo_box_));
284 if (selected < 0)
285 return;
286 gtk_text_buffer_set_text(cert_selector->cert_details_buffer_,
287 cert_selector->details_strings_[selected].c_str(),
288 cert_selector->details_strings_[selected].size());
289 }
290
291 // static
292 void SSLClientCertificateSelector::OnResponse(
293 GtkDialog* dialog, gint response_id,
294 SSLClientCertificateSelector* cert_selector) {
295 net::X509Certificate* cert = NULL;
296 if (response_id == GTK_RESPONSE_OK ||
297 response_id == RESPONSE_SHOW_CERT_INFO) {
298 int selected = gtk_combo_box_get_active(
299 GTK_COMBO_BOX(cert_selector->cert_combo_box_));
300 if (selected >= 0 &&
301 selected < static_cast<int>(
302 cert_selector->cert_request_info_->client_certs.size()))
303 cert = cert_selector->cert_request_info_->client_certs[selected];
304 }
305 if (response_id == RESPONSE_SHOW_CERT_INFO) {
306 if (cert)
307 ShowCertificateViewer(GTK_WINDOW(cert_selector->dialog_),
308 cert->os_cert_handle());
309 return;
310 }
311 cert_selector->delegate_->CertificateSelected(cert);
312 gtk_widget_destroy(GTK_WIDGET(dialog));
313 }
314
315 // static
316 void SSLClientCertificateSelector::OnDestroy(
317 GtkDialog* dialog,
318 SSLClientCertificateSelector* cert_selector) {
319 delete cert_selector;
320 }
321
322 } // namespace
323
324 ///////////////////////////////////////////////////////////////////////////////
325 // SSLClientAuthHandler platform specific implementation:
326
9 void SSLClientAuthHandler::DoSelectCertificate() { 327 void SSLClientAuthHandler::DoSelectCertificate() {
10 NOTIMPLEMENTED(); 328 // TODO(mattm): Pipe parent gfx::NativeWindow param into here somehow.
11 CertificateSelected(NULL); 329 (new SSLClientCertificateSelector(NULL, cert_request_info_, this))->Show();
12 } 330 }
OLDNEW
« no previous file with comments | « chrome/browser/ssl/ssl_client_auth_handler.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698