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.
5 #include "chrome/browser/ui/webui/certificate_viewer_webui.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/constrained_web_dialog_ui.h"
18 #include "chrome/common/net/x509_certificate_model.h"
19 #include "chrome/common/url_constants.h"
20 #include "content/public/browser/web_contents.h"
21 #include "grit/generated_resources.h"
22 #include "ui/base/l10n/l10n_util.h"
23 #include "ui/gfx/size.h"
25 using content::WebContents;
26 using content::WebUIMessageHandler;
27 using web_modal::NativeWebContentsModalDialog;
29 // Shows a certificate using the WebUI certificate viewer.
30 void ShowCertificateViewer(WebContents* web_contents,
31 gfx::NativeWindow parent,
32 net::X509Certificate* cert) {
33 CertificateViewerDialog* dialog = new CertificateViewerDialog(cert);
34 dialog->Show(web_contents, parent);
37 ////////////////////////////////////////////////////////////////////////////////
38 // CertificateViewerDialog
40 CertificateViewerDialog::CertificateViewerDialog(net::X509Certificate* cert)
41 : cert_(cert), dialog_(NULL) {
42 // Construct the dialog title from the certificate.
43 net::X509Certificate::OSCertHandles cert_chain;
44 x509_certificate_model::GetCertChainFromCert(cert_->os_cert_handle(),
46 title_ = l10n_util::GetStringFUTF16(IDS_CERT_INFO_DIALOG_TITLE,
47 UTF8ToUTF16(x509_certificate_model::GetTitle(cert_chain.front())));
50 CertificateViewerDialog::~CertificateViewerDialog() {
53 void CertificateViewerDialog::Show(WebContents* web_contents,
54 gfx::NativeWindow parent) {
55 // TODO(bshe): UI tweaks needed for Aura HTML Dialog, such as adding padding
56 // on the title for Aura ConstrainedWebDialogUI.
57 dialog_ = CreateConstrainedWebDialog(
58 web_contents->GetBrowserContext(),
64 ui::ModalType CertificateViewerDialog::GetDialogModalType() const {
65 return ui::MODAL_TYPE_NONE;
68 string16 CertificateViewerDialog::GetDialogTitle() const {
72 GURL CertificateViewerDialog::GetDialogContentURL() const {
73 return GURL(chrome::kChromeUICertificateViewerURL);
76 void CertificateViewerDialog::GetWebUIMessageHandlers(
77 std::vector<WebUIMessageHandler*>* handlers) const {
78 handlers->push_back(new CertificateViewerDialogHandler(
79 const_cast<CertificateViewerDialog*>(this), cert_.get()));
82 void CertificateViewerDialog::GetDialogSize(gfx::Size* size) const {
83 const int kDefaultWidth = 544;
84 const int kDefaultHeight = 628;
85 size->SetSize(kDefaultWidth, kDefaultHeight);
88 std::string CertificateViewerDialog::GetDialogArgs() const {
91 // Certificate information. The keys in this dictionary's general key
92 // correspond to the IDs in the Html page.
93 DictionaryValue cert_info;
94 net::X509Certificate::OSCertHandle cert_hnd = cert_->os_cert_handle();
96 // Get the certificate chain.
97 net::X509Certificate::OSCertHandles cert_chain;
98 x509_certificate_model::GetCertChainFromCert(cert_hnd, &cert_chain);
100 // Certificate usage.
101 std::vector<std::string> usages;
102 x509_certificate_model::GetUsageStrings(cert_hnd, &usages);
103 std::string usagestr;
104 for (std::vector<std::string>::iterator it = usages.begin();
105 it != usages.end(); ++it) {
106 if (usagestr.length() > 0) {
111 cert_info.SetString("general.usages", usagestr);
113 // Standard certificate details.
114 const std::string alternative_text =
115 l10n_util::GetStringUTF8(IDS_CERT_INFO_FIELD_NOT_PRESENT);
116 cert_info.SetString("general.title", l10n_util::GetStringFUTF8(
117 IDS_CERT_INFO_DIALOG_TITLE, UTF8ToUTF16(x509_certificate_model::GetTitle(
118 cert_chain.front()))));
120 // Issued to information.
121 cert_info.SetString("general.issued-cn",
122 x509_certificate_model::GetSubjectCommonName(cert_hnd, alternative_text));
123 cert_info.SetString("general.issued-o",
124 x509_certificate_model::GetSubjectOrgName(cert_hnd, alternative_text));
125 cert_info.SetString("general.issued-ou",
126 x509_certificate_model::GetSubjectOrgUnitName(cert_hnd,
128 cert_info.SetString("general.issued-sn",
129 x509_certificate_model::GetSerialNumberHexified(cert_hnd,
132 // Issuer information.
133 cert_info.SetString("general.issuer-cn",
134 x509_certificate_model::GetIssuerCommonName(cert_hnd, alternative_text));
135 cert_info.SetString("general.issuer-o",
136 x509_certificate_model::GetIssuerOrgName(cert_hnd, alternative_text));
137 cert_info.SetString("general.issuer-ou",
138 x509_certificate_model::GetIssuerOrgUnitName(cert_hnd, alternative_text));
141 base::Time issued, expires;
142 std::string issued_str, expires_str;
143 if (x509_certificate_model::GetTimes(cert_hnd, &issued, &expires)) {
144 issued_str = UTF16ToUTF8(
145 base::TimeFormatShortDateNumeric(issued));
146 expires_str = UTF16ToUTF8(
147 base::TimeFormatShortDateNumeric(expires));
149 issued_str = alternative_text;
150 expires_str = alternative_text;
152 cert_info.SetString("general.issue-date", issued_str);
153 cert_info.SetString("general.expiry-date", expires_str);
155 cert_info.SetString("general.sha256",
156 x509_certificate_model::HashCertSHA256(cert_hnd));
157 cert_info.SetString("general.sha1",
158 x509_certificate_model::HashCertSHA1(cert_hnd));
160 // Certificate hierarchy is constructed from bottom up.
161 ListValue* children = NULL;
163 for (net::X509Certificate::OSCertHandles::const_iterator i =
164 cert_chain.begin(); i != cert_chain.end(); ++i, ++index) {
165 DictionaryValue* cert_node = new DictionaryValue();
166 ListValue cert_details;
167 cert_node->SetString("label", x509_certificate_model::GetTitle(*i).c_str());
168 cert_node->SetDouble("payload.index", index);
169 // Add the child from the previous iteration.
171 cert_node->Set("children", children);
173 // Add this node to the children list for the next iteration.
174 children = new ListValue();
175 children->Append(cert_node);
177 // Set the last node as the top of the certificate hierarchy.
178 cert_info.Set("hierarchy", children);
180 base::JSONWriter::Write(&cert_info, &data);
185 void CertificateViewerDialog::OnDialogShown(
186 content::WebUI* webui,
187 content::RenderViewHost* render_view_host) {
190 void CertificateViewerDialog::OnDialogClosed(const std::string& json_retval) {
193 void CertificateViewerDialog::OnCloseContents(WebContents* source,
194 bool* out_close_dialog) {
195 if (out_close_dialog)
196 *out_close_dialog = true;
199 bool CertificateViewerDialog::ShouldShowDialogTitle() const {
203 ////////////////////////////////////////////////////////////////////////////////
204 // CertificateViewerDialogHandler
206 CertificateViewerDialogHandler::CertificateViewerDialogHandler(
207 CertificateViewerDialog* dialog,
208 net::X509Certificate* cert) : cert_(cert), dialog_(dialog) {
209 x509_certificate_model::GetCertChainFromCert(cert_->os_cert_handle(),
213 CertificateViewerDialogHandler::~CertificateViewerDialogHandler() {
216 void CertificateViewerDialogHandler::RegisterMessages() {
217 web_ui()->RegisterMessageCallback("exportCertificate",
218 base::Bind(&CertificateViewerDialogHandler::ExportCertificate,
219 base::Unretained(this)));
220 web_ui()->RegisterMessageCallback("requestCertificateFields",
221 base::Bind(&CertificateViewerDialogHandler::RequestCertificateFields,
222 base::Unretained(this)));
225 void CertificateViewerDialogHandler::ExportCertificate(
226 const base::ListValue* args) {
227 int cert_index = GetCertificateIndex(args);
231 NativeWebContentsModalDialog window =
232 platform_util::GetTopLevel(dialog_->dialog()->GetNativeDialog());
233 ShowCertExportDialog(web_ui()->GetWebContents(),
235 cert_chain_[cert_index]);
238 void CertificateViewerDialogHandler::RequestCertificateFields(
239 const base::ListValue* args) {
240 int cert_index = GetCertificateIndex(args);
244 net::X509Certificate::OSCertHandle cert = cert_chain_[cert_index];
247 DictionaryValue* node_details;
248 DictionaryValue* alt_node_details;
249 ListValue* cert_sub_fields;
250 root_list.Append(node_details = new DictionaryValue());
251 node_details->SetString("label", x509_certificate_model::GetTitle(cert));
253 ListValue* cert_fields;
254 node_details->Set("children", cert_fields = new ListValue());
255 cert_fields->Append(node_details = new DictionaryValue());
257 node_details->SetString("label",
258 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_CERTIFICATE));
259 node_details->Set("children", cert_fields = new ListValue());
261 // Main certificate fields.
262 cert_fields->Append(node_details = new DictionaryValue());
263 node_details->SetString("label",
264 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_VERSION));
265 std::string version = x509_certificate_model::GetVersion(cert);
266 if (!version.empty())
267 node_details->SetString("payload.val",
268 l10n_util::GetStringFUTF8(IDS_CERT_DETAILS_VERSION_FORMAT,
269 UTF8ToUTF16(version)));
271 cert_fields->Append(node_details = new DictionaryValue());
272 node_details->SetString("label",
273 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_SERIAL_NUMBER));
274 node_details->SetString("payload.val",
275 x509_certificate_model::GetSerialNumberHexified(cert,
276 l10n_util::GetStringUTF8(IDS_CERT_INFO_FIELD_NOT_PRESENT)));
278 cert_fields->Append(node_details = new DictionaryValue());
279 node_details->SetString("label",
280 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_CERTIFICATE_SIG_ALG));
281 node_details->SetString("payload.val",
282 x509_certificate_model::ProcessSecAlgorithmSignature(cert));
284 cert_fields->Append(node_details = new DictionaryValue());
285 node_details->SetString("label",
286 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_ISSUER));
287 node_details->SetString("payload.val",
288 x509_certificate_model::GetIssuerName(cert));
291 cert_fields->Append(node_details = new DictionaryValue());
292 node_details->SetString("label",
293 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_VALIDITY));
295 node_details->Set("children", cert_sub_fields = new ListValue());
296 cert_sub_fields->Append(node_details = new DictionaryValue());
297 node_details->SetString("label",
298 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_NOT_BEFORE));
299 cert_sub_fields->Append(alt_node_details = new DictionaryValue());
300 alt_node_details->SetString("label",
301 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_NOT_AFTER));
302 base::Time issued, expires;
303 if (x509_certificate_model::GetTimes(cert, &issued, &expires)) {
304 node_details->SetString("payload.val",
305 UTF16ToUTF8(base::TimeFormatShortDateAndTime(issued)));
306 alt_node_details->SetString("payload.val",
307 UTF16ToUTF8(base::TimeFormatShortDateAndTime(expires)));
310 cert_fields->Append(node_details = new DictionaryValue());
311 node_details->SetString("label",
312 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_SUBJECT));
313 node_details->SetString("payload.val",
314 x509_certificate_model::GetSubjectName(cert));
316 // Subject key information.
317 cert_fields->Append(node_details = new DictionaryValue());
318 node_details->SetString("label",
319 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_SUBJECT_KEY_INFO));
321 node_details->Set("children", cert_sub_fields = new ListValue());
322 cert_sub_fields->Append(node_details = new DictionaryValue());
323 node_details->SetString("label",
324 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_SUBJECT_KEY_ALG));
325 node_details->SetString("payload.val",
326 x509_certificate_model::ProcessSecAlgorithmSubjectPublicKey(cert));
327 cert_sub_fields->Append(node_details = new DictionaryValue());
328 node_details->SetString("label",
329 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_SUBJECT_KEY));
330 node_details->SetString("payload.val",
331 x509_certificate_model::ProcessSubjectPublicKeyInfo(cert));
334 x509_certificate_model::Extensions extensions;
335 x509_certificate_model::GetExtensions(
336 l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_CRITICAL),
337 l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_NON_CRITICAL),
340 if (!extensions.empty()) {
341 cert_fields->Append(node_details = new DictionaryValue());
342 node_details->SetString("label",
343 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_EXTENSIONS));
345 node_details->Set("children", cert_sub_fields = new ListValue());
346 for (x509_certificate_model::Extensions::const_iterator i =
347 extensions.begin(); i != extensions.end(); ++i) {
348 cert_sub_fields->Append(node_details = new DictionaryValue());
349 node_details->SetString("label", i->name);
350 node_details->SetString("payload.val", i->value);
354 cert_fields->Append(node_details = new DictionaryValue());
355 node_details->SetString("label",
356 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_CERTIFICATE_SIG_ALG));
357 node_details->SetString("payload.val",
358 x509_certificate_model::ProcessSecAlgorithmSignatureWrap(cert));
360 cert_fields->Append(node_details = new DictionaryValue());
361 node_details->SetString("label",
362 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_CERTIFICATE_SIG_VALUE));
363 node_details->SetString("payload.val",
364 x509_certificate_model::ProcessRawBitsSignatureWrap(cert));
366 cert_fields->Append(node_details = new DictionaryValue());
367 node_details->SetString("label",
368 l10n_util::GetStringUTF8(IDS_CERT_INFO_FINGERPRINTS_GROUP));
369 node_details->Set("children", cert_sub_fields = new ListValue());
371 cert_sub_fields->Append(node_details = new DictionaryValue());
372 node_details->SetString("label",
373 l10n_util::GetStringUTF8(IDS_CERT_INFO_SHA256_FINGERPRINT_LABEL));
374 node_details->SetString("payload.val",
375 x509_certificate_model::HashCertSHA256(cert));
376 cert_sub_fields->Append(node_details = new DictionaryValue());
377 node_details->SetString("label",
378 l10n_util::GetStringUTF8(IDS_CERT_INFO_SHA1_FINGERPRINT_LABEL));
379 node_details->SetString("payload.val",
380 x509_certificate_model::HashCertSHA1(cert));
382 // Send certificate information to javascript.
383 web_ui()->CallJavascriptFunction("cert_viewer.getCertificateFields",
387 int CertificateViewerDialogHandler::GetCertificateIndex(
388 const base::ListValue* args) const {
391 if (!(args->GetDouble(0, &val)))
393 cert_index = static_cast<int>(val);
394 if (cert_index < 0 || cert_index >= static_cast<int>(cert_chain_.size()))