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 "chrome/browser/ui/webui/certificate_viewer_webui.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/i18n/time_formatting.h"
10 #include "base/json/json_writer.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/certificate_viewer.h"
14 #include "chrome/browser/platform_util.h"
15 #include "chrome/browser/ui/browser_dialogs.h"
16 #include "chrome/browser/ui/certificate_dialogs.h"
17 #include "chrome/browser/ui/webui/certificate_viewer_ui.h"
18 #include "chrome/browser/ui/webui/constrained_web_dialog_ui.h"
19 #include "chrome/common/net/x509_certificate_model.h"
20 #include "chrome/common/url_constants.h"
21 #include "chrome/grit/generated_resources.h"
22 #include "content/public/browser/web_contents.h"
23 #include "ui/base/l10n/l10n_util.h"
24 #include "ui/gfx/size.h"
25
26 using content::WebContents;
27 using content::WebUIMessageHandler;
28 using web_modal::NativeWebContentsModalDialog;
29
30 // Shows a certificate using the WebUI certificate viewer.
ShowCertificateViewer(WebContents * web_contents,gfx::NativeWindow parent,net::X509Certificate * cert)31 void ShowCertificateViewer(WebContents* web_contents,
32 gfx::NativeWindow parent,
33 net::X509Certificate* cert) {
34 CertificateViewerDialog* dialog = new CertificateViewerDialog(cert);
35 dialog->Show(web_contents, parent);
36 }
37
38 ////////////////////////////////////////////////////////////////////////////////
39 // CertificateViewerDialog
40
CertificateViewerModalDialog(net::X509Certificate * cert)41 CertificateViewerModalDialog::CertificateViewerModalDialog(
42 net::X509Certificate* cert)
43 : cert_(cert), webui_(NULL), window_(NULL) {
44 // Construct the dialog title from the certificate.
45 title_ = l10n_util::GetStringFUTF16(
46 IDS_CERT_INFO_DIALOG_TITLE,
47 base::UTF8ToUTF16(
48 x509_certificate_model::GetTitle(cert_->os_cert_handle())));
49 }
50
~CertificateViewerModalDialog()51 CertificateViewerModalDialog::~CertificateViewerModalDialog() {
52 }
53
Show(content::WebContents * web_contents,gfx::NativeWindow parent)54 void CertificateViewerModalDialog::Show(content::WebContents* web_contents,
55 gfx::NativeWindow parent) {
56 window_ = chrome::ShowWebDialog(parent,
57 web_contents->GetBrowserContext(),
58 this);
59 }
60
61 NativeWebContentsModalDialog
GetNativeWebContentsModalDialog()62 CertificateViewerModalDialog::GetNativeWebContentsModalDialog() {
63 #if defined(USE_AURA)
64 return window_;
65 #else
66 NOTREACHED();
67 return NULL;
68 #endif
69 }
70
GetDialogModalType() const71 ui::ModalType CertificateViewerModalDialog::GetDialogModalType() const {
72 return ui::MODAL_TYPE_SYSTEM;
73 }
74
GetDialogTitle() const75 base::string16 CertificateViewerModalDialog::GetDialogTitle() const {
76 return title_;
77 }
78
GetDialogContentURL() const79 GURL CertificateViewerModalDialog::GetDialogContentURL() const {
80 return GURL(chrome::kChromeUICertificateViewerDialogURL);
81 }
82
GetWebUIMessageHandlers(std::vector<WebUIMessageHandler * > * handlers) const83 void CertificateViewerModalDialog::GetWebUIMessageHandlers(
84 std::vector<WebUIMessageHandler*>* handlers) const {
85 handlers->push_back(new CertificateViewerDialogHandler(
86 const_cast<CertificateViewerModalDialog*>(this), cert_.get()));
87 }
88
GetDialogSize(gfx::Size * size) const89 void CertificateViewerModalDialog::GetDialogSize(gfx::Size* size) const {
90 const int kDefaultWidth = 544;
91 const int kDefaultHeight = 628;
92 size->SetSize(kDefaultWidth, kDefaultHeight);
93 }
94
GetDialogArgs() const95 std::string CertificateViewerModalDialog::GetDialogArgs() const {
96 std::string data;
97
98 // Certificate information. The keys in this dictionary's general key
99 // correspond to the IDs in the Html page.
100 base::DictionaryValue cert_info;
101 net::X509Certificate::OSCertHandle cert_hnd = cert_->os_cert_handle();
102
103 // Get the certificate chain.
104 net::X509Certificate::OSCertHandles cert_chain;
105 cert_chain.push_back(cert_->os_cert_handle());
106 const net::X509Certificate::OSCertHandles& certs =
107 cert_->GetIntermediateCertificates();
108 cert_chain.insert(cert_chain.end(), certs.begin(), certs.end());
109
110 // Certificate usage.
111 std::vector<std::string> usages;
112 x509_certificate_model::GetUsageStrings(cert_hnd, &usages);
113 std::string usagestr;
114 for (std::vector<std::string>::iterator it = usages.begin();
115 it != usages.end(); ++it) {
116 if (usagestr.length() > 0) {
117 usagestr += "\n";
118 }
119 usagestr += *it;
120 }
121 cert_info.SetString("general.usages", usagestr);
122
123 // Standard certificate details.
124 const std::string alternative_text =
125 l10n_util::GetStringUTF8(IDS_CERT_INFO_FIELD_NOT_PRESENT);
126 cert_info.SetString("general.title", l10n_util::GetStringFUTF8(
127 IDS_CERT_INFO_DIALOG_TITLE,
128 base::UTF8ToUTF16(x509_certificate_model::GetTitle(
129 cert_chain.front()))));
130
131 // Issued to information.
132 cert_info.SetString("general.issued-cn",
133 x509_certificate_model::GetSubjectCommonName(cert_hnd, alternative_text));
134 cert_info.SetString("general.issued-o",
135 x509_certificate_model::GetSubjectOrgName(cert_hnd, alternative_text));
136 cert_info.SetString("general.issued-ou",
137 x509_certificate_model::GetSubjectOrgUnitName(cert_hnd,
138 alternative_text));
139 cert_info.SetString("general.issued-sn",
140 x509_certificate_model::GetSerialNumberHexified(cert_hnd,
141 alternative_text));
142
143 // Issuer information.
144 cert_info.SetString("general.issuer-cn",
145 x509_certificate_model::GetIssuerCommonName(cert_hnd, alternative_text));
146 cert_info.SetString("general.issuer-o",
147 x509_certificate_model::GetIssuerOrgName(cert_hnd, alternative_text));
148 cert_info.SetString("general.issuer-ou",
149 x509_certificate_model::GetIssuerOrgUnitName(cert_hnd, alternative_text));
150
151 // Validity period.
152 base::Time issued, expires;
153 std::string issued_str, expires_str;
154 if (x509_certificate_model::GetTimes(cert_hnd, &issued, &expires)) {
155 issued_str = base::UTF16ToUTF8(
156 base::TimeFormatShortDateNumeric(issued));
157 expires_str = base::UTF16ToUTF8(
158 base::TimeFormatShortDateNumeric(expires));
159 } else {
160 issued_str = alternative_text;
161 expires_str = alternative_text;
162 }
163 cert_info.SetString("general.issue-date", issued_str);
164 cert_info.SetString("general.expiry-date", expires_str);
165
166 cert_info.SetString("general.sha256",
167 x509_certificate_model::HashCertSHA256(cert_hnd));
168 cert_info.SetString("general.sha1",
169 x509_certificate_model::HashCertSHA1(cert_hnd));
170
171 // Certificate hierarchy is constructed from bottom up.
172 base::ListValue* children = NULL;
173 int index = 0;
174 for (net::X509Certificate::OSCertHandles::const_iterator i =
175 cert_chain.begin(); i != cert_chain.end(); ++i, ++index) {
176 base::DictionaryValue* cert_node = new base::DictionaryValue();
177 base::ListValue cert_details;
178 cert_node->SetString("label", x509_certificate_model::GetTitle(*i).c_str());
179 cert_node->SetDouble("payload.index", index);
180 // Add the child from the previous iteration.
181 if (children)
182 cert_node->Set("children", children);
183
184 // Add this node to the children list for the next iteration.
185 children = new base::ListValue();
186 children->Append(cert_node);
187 }
188 // Set the last node as the top of the certificate hierarchy.
189 cert_info.Set("hierarchy", children);
190
191 base::JSONWriter::Write(&cert_info, &data);
192
193 return data;
194 }
195
OnDialogShown(content::WebUI * webui,content::RenderViewHost * render_view_host)196 void CertificateViewerModalDialog::OnDialogShown(
197 content::WebUI* webui,
198 content::RenderViewHost* render_view_host) {
199 webui_ = webui;
200 }
201
OnDialogClosed(const std::string & json_retval)202 void CertificateViewerModalDialog::OnDialogClosed(
203 const std::string& json_retval) {
204 }
205
OnCloseContents(WebContents * source,bool * out_close_dialog)206 void CertificateViewerModalDialog::OnCloseContents(WebContents* source,
207 bool* out_close_dialog) {
208 if (out_close_dialog)
209 *out_close_dialog = true;
210 }
211
ShouldShowDialogTitle() const212 bool CertificateViewerModalDialog::ShouldShowDialogTitle() const {
213 return true;
214 }
215
216 ////////////////////////////////////////////////////////////////////////////////
217 // CertificateViewerDialog
218
CertificateViewerDialog(net::X509Certificate * cert)219 CertificateViewerDialog::CertificateViewerDialog(net::X509Certificate* cert)
220 : CertificateViewerModalDialog(cert),
221 dialog_(NULL) {
222 }
223
~CertificateViewerDialog()224 CertificateViewerDialog::~CertificateViewerDialog() {
225 }
226
Show(WebContents * web_contents,gfx::NativeWindow parent)227 void CertificateViewerDialog::Show(WebContents* web_contents,
228 gfx::NativeWindow parent) {
229 // TODO(bshe): UI tweaks needed for Aura HTML Dialog, such as adding padding
230 // on the title for Aura ConstrainedWebDialogUI.
231 dialog_ = CreateConstrainedWebDialog(web_contents->GetBrowserContext(), this,
232 web_contents);
233 }
234
235 NativeWebContentsModalDialog
GetNativeWebContentsModalDialog()236 CertificateViewerDialog::GetNativeWebContentsModalDialog() {
237 return dialog_->GetNativeDialog();
238 }
239
GetDialogContentURL() const240 GURL CertificateViewerDialog::GetDialogContentURL() const {
241 return GURL(chrome::kChromeUICertificateViewerURL);
242 }
243
GetDialogModalType() const244 ui::ModalType CertificateViewerDialog::GetDialogModalType() const {
245 return ui::MODAL_TYPE_NONE;
246 }
247
248 ////////////////////////////////////////////////////////////////////////////////
249 // CertificateViewerDialogHandler
250
CertificateViewerDialogHandler(CertificateViewerModalDialog * dialog,net::X509Certificate * cert)251 CertificateViewerDialogHandler::CertificateViewerDialogHandler(
252 CertificateViewerModalDialog* dialog,
253 net::X509Certificate* cert)
254 : cert_(cert), dialog_(dialog) {
255 cert_chain_.push_back(cert_->os_cert_handle());
256 const net::X509Certificate::OSCertHandles& certs =
257 cert_->GetIntermediateCertificates();
258 cert_chain_.insert(cert_chain_.end(), certs.begin(), certs.end());
259 }
260
~CertificateViewerDialogHandler()261 CertificateViewerDialogHandler::~CertificateViewerDialogHandler() {
262 }
263
RegisterMessages()264 void CertificateViewerDialogHandler::RegisterMessages() {
265 web_ui()->RegisterMessageCallback("exportCertificate",
266 base::Bind(&CertificateViewerDialogHandler::ExportCertificate,
267 base::Unretained(this)));
268 web_ui()->RegisterMessageCallback("requestCertificateFields",
269 base::Bind(&CertificateViewerDialogHandler::RequestCertificateFields,
270 base::Unretained(this)));
271 }
272
ExportCertificate(const base::ListValue * args)273 void CertificateViewerDialogHandler::ExportCertificate(
274 const base::ListValue* args) {
275 int cert_index = GetCertificateIndex(args);
276 if (cert_index < 0)
277 return;
278
279 NativeWebContentsModalDialog window =
280 platform_util::GetTopLevel(dialog_->GetNativeWebContentsModalDialog());
281 ShowCertExportDialog(web_ui()->GetWebContents(),
282 window,
283 cert_chain_.begin() + cert_index,
284 cert_chain_.end());
285 }
286
RequestCertificateFields(const base::ListValue * args)287 void CertificateViewerDialogHandler::RequestCertificateFields(
288 const base::ListValue* args) {
289 int cert_index = GetCertificateIndex(args);
290 if (cert_index < 0)
291 return;
292
293 net::X509Certificate::OSCertHandle cert = cert_chain_[cert_index];
294
295 base::ListValue root_list;
296 base::DictionaryValue* node_details;
297 base::DictionaryValue* alt_node_details;
298 base::ListValue* cert_sub_fields;
299 root_list.Append(node_details = new base::DictionaryValue());
300 node_details->SetString("label", x509_certificate_model::GetTitle(cert));
301
302 base::ListValue* cert_fields;
303 node_details->Set("children", cert_fields = new base::ListValue());
304 cert_fields->Append(node_details = new base::DictionaryValue());
305
306 node_details->SetString("label",
307 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_CERTIFICATE));
308 node_details->Set("children", cert_fields = new base::ListValue());
309
310 // Main certificate fields.
311 cert_fields->Append(node_details = new base::DictionaryValue());
312 node_details->SetString("label",
313 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_VERSION));
314 std::string version = x509_certificate_model::GetVersion(cert);
315 if (!version.empty())
316 node_details->SetString("payload.val",
317 l10n_util::GetStringFUTF8(IDS_CERT_DETAILS_VERSION_FORMAT,
318 base::UTF8ToUTF16(version)));
319
320 cert_fields->Append(node_details = new base::DictionaryValue());
321 node_details->SetString("label",
322 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_SERIAL_NUMBER));
323 node_details->SetString("payload.val",
324 x509_certificate_model::GetSerialNumberHexified(cert,
325 l10n_util::GetStringUTF8(IDS_CERT_INFO_FIELD_NOT_PRESENT)));
326
327 cert_fields->Append(node_details = new base::DictionaryValue());
328 node_details->SetString("label",
329 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_CERTIFICATE_SIG_ALG));
330 node_details->SetString("payload.val",
331 x509_certificate_model::ProcessSecAlgorithmSignature(cert));
332
333 cert_fields->Append(node_details = new base::DictionaryValue());
334 node_details->SetString("label",
335 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_ISSUER));
336 node_details->SetString("payload.val",
337 x509_certificate_model::GetIssuerName(cert));
338
339 // Validity period.
340 cert_fields->Append(node_details = new base::DictionaryValue());
341 node_details->SetString("label",
342 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_VALIDITY));
343
344 node_details->Set("children", cert_sub_fields = new base::ListValue());
345 cert_sub_fields->Append(node_details = new base::DictionaryValue());
346 node_details->SetString("label",
347 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_NOT_BEFORE));
348 cert_sub_fields->Append(alt_node_details = new base::DictionaryValue());
349 alt_node_details->SetString("label",
350 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_NOT_AFTER));
351 base::Time issued, expires;
352 if (x509_certificate_model::GetTimes(cert, &issued, &expires)) {
353 // The object Time internally saves the time in UTC timezone. This is why we
354 // do a simple UTC string concatenation.
355 node_details->SetString(
356 "payload.val",
357 base::UTF16ToUTF8(base::TimeFormatShortDateAndTime(issued)) + " " +
358 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_UTC_TIMEZONE));
359 alt_node_details->SetString(
360 "payload.val",
361 base::UTF16ToUTF8(base::TimeFormatShortDateAndTime(expires)) + " " +
362 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_UTC_TIMEZONE));
363 }
364
365 cert_fields->Append(node_details = new base::DictionaryValue());
366 node_details->SetString("label",
367 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_SUBJECT));
368 node_details->SetString("payload.val",
369 x509_certificate_model::GetSubjectName(cert));
370
371 // Subject key information.
372 cert_fields->Append(node_details = new base::DictionaryValue());
373 node_details->SetString("label",
374 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_SUBJECT_KEY_INFO));
375
376 node_details->Set("children", cert_sub_fields = new base::ListValue());
377 cert_sub_fields->Append(node_details = new base::DictionaryValue());
378 node_details->SetString("label",
379 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_SUBJECT_KEY_ALG));
380 node_details->SetString("payload.val",
381 x509_certificate_model::ProcessSecAlgorithmSubjectPublicKey(cert));
382 cert_sub_fields->Append(node_details = new base::DictionaryValue());
383 node_details->SetString("label",
384 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_SUBJECT_KEY));
385 node_details->SetString("payload.val",
386 x509_certificate_model::ProcessSubjectPublicKeyInfo(cert));
387
388 // Extensions.
389 x509_certificate_model::Extensions extensions;
390 x509_certificate_model::GetExtensions(
391 l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_CRITICAL),
392 l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_NON_CRITICAL),
393 cert, &extensions);
394
395 if (!extensions.empty()) {
396 cert_fields->Append(node_details = new base::DictionaryValue());
397 node_details->SetString("label",
398 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_EXTENSIONS));
399
400 node_details->Set("children", cert_sub_fields = new base::ListValue());
401 for (x509_certificate_model::Extensions::const_iterator i =
402 extensions.begin(); i != extensions.end(); ++i) {
403 cert_sub_fields->Append(node_details = new base::DictionaryValue());
404 node_details->SetString("label", i->name);
405 node_details->SetString("payload.val", i->value);
406 }
407 }
408
409 cert_fields->Append(node_details = new base::DictionaryValue());
410 node_details->SetString("label",
411 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_CERTIFICATE_SIG_ALG));
412 node_details->SetString("payload.val",
413 x509_certificate_model::ProcessSecAlgorithmSignatureWrap(cert));
414
415 cert_fields->Append(node_details = new base::DictionaryValue());
416 node_details->SetString("label",
417 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_CERTIFICATE_SIG_VALUE));
418 node_details->SetString("payload.val",
419 x509_certificate_model::ProcessRawBitsSignatureWrap(cert));
420
421 cert_fields->Append(node_details = new base::DictionaryValue());
422 node_details->SetString("label",
423 l10n_util::GetStringUTF8(IDS_CERT_INFO_FINGERPRINTS_GROUP));
424 node_details->Set("children", cert_sub_fields = new base::ListValue());
425
426 cert_sub_fields->Append(node_details = new base::DictionaryValue());
427 node_details->SetString("label",
428 l10n_util::GetStringUTF8(IDS_CERT_INFO_SHA256_FINGERPRINT_LABEL));
429 node_details->SetString("payload.val",
430 x509_certificate_model::HashCertSHA256(cert));
431 cert_sub_fields->Append(node_details = new base::DictionaryValue());
432 node_details->SetString("label",
433 l10n_util::GetStringUTF8(IDS_CERT_INFO_SHA1_FINGERPRINT_LABEL));
434 node_details->SetString("payload.val",
435 x509_certificate_model::HashCertSHA1(cert));
436
437 // Send certificate information to javascript.
438 web_ui()->CallJavascriptFunction("cert_viewer.getCertificateFields",
439 root_list);
440 }
441
GetCertificateIndex(const base::ListValue * args) const442 int CertificateViewerDialogHandler::GetCertificateIndex(
443 const base::ListValue* args) const {
444 int cert_index;
445 double val;
446 if (!(args->GetDouble(0, &val)))
447 return -1;
448 cert_index = static_cast<int>(val);
449 if (cert_index < 0 || cert_index >= static_cast<int>(cert_chain_.size()))
450 return -1;
451 return cert_index;
452 }
453