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