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/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" 24 25 using content::WebContents; 26 using content::WebUIMessageHandler; 27 using web_modal::NativeWebContentsModalDialog; 28 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); 35 } 36 37 //////////////////////////////////////////////////////////////////////////////// 38 // CertificateViewerDialog 39 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(), 45 &cert_chain); 46 title_ = l10n_util::GetStringFUTF16(IDS_CERT_INFO_DIALOG_TITLE, 47 UTF8ToUTF16(x509_certificate_model::GetTitle(cert_chain.front()))); 48 } 49 50 CertificateViewerDialog::~CertificateViewerDialog() { 51 } 52 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(), 59 this, 60 NULL, 61 web_contents); 62 } 63 64 ui::ModalType CertificateViewerDialog::GetDialogModalType() const { 65 return ui::MODAL_TYPE_NONE; 66 } 67 68 base::string16 CertificateViewerDialog::GetDialogTitle() const { 69 return title_; 70 } 71 72 GURL CertificateViewerDialog::GetDialogContentURL() const { 73 return GURL(chrome::kChromeUICertificateViewerURL); 74 } 75 76 void CertificateViewerDialog::GetWebUIMessageHandlers( 77 std::vector<WebUIMessageHandler*>* handlers) const { 78 handlers->push_back(new CertificateViewerDialogHandler( 79 const_cast<CertificateViewerDialog*>(this), cert_.get())); 80 } 81 82 void CertificateViewerDialog::GetDialogSize(gfx::Size* size) const { 83 const int kDefaultWidth = 544; 84 const int kDefaultHeight = 628; 85 size->SetSize(kDefaultWidth, kDefaultHeight); 86 } 87 88 std::string CertificateViewerDialog::GetDialogArgs() const { 89 std::string data; 90 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(); 95 96 // Get the certificate chain. 97 net::X509Certificate::OSCertHandles cert_chain; 98 x509_certificate_model::GetCertChainFromCert(cert_hnd, &cert_chain); 99 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) { 107 usagestr += "\n"; 108 } 109 usagestr += *it; 110 } 111 cert_info.SetString("general.usages", usagestr); 112 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())))); 119 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, 127 alternative_text)); 128 cert_info.SetString("general.issued-sn", 129 x509_certificate_model::GetSerialNumberHexified(cert_hnd, 130 alternative_text)); 131 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)); 139 140 // Validity period. 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)); 148 } else { 149 issued_str = alternative_text; 150 expires_str = alternative_text; 151 } 152 cert_info.SetString("general.issue-date", issued_str); 153 cert_info.SetString("general.expiry-date", expires_str); 154 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)); 159 160 // Certificate hierarchy is constructed from bottom up. 161 ListValue* children = NULL; 162 int index = 0; 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. 170 if (children) 171 cert_node->Set("children", children); 172 173 // Add this node to the children list for the next iteration. 174 children = new ListValue(); 175 children->Append(cert_node); 176 } 177 // Set the last node as the top of the certificate hierarchy. 178 cert_info.Set("hierarchy", children); 179 180 base::JSONWriter::Write(&cert_info, &data); 181 182 return data; 183 } 184 185 void CertificateViewerDialog::OnDialogShown( 186 content::WebUI* webui, 187 content::RenderViewHost* render_view_host) { 188 } 189 190 void CertificateViewerDialog::OnDialogClosed(const std::string& json_retval) { 191 } 192 193 void CertificateViewerDialog::OnCloseContents(WebContents* source, 194 bool* out_close_dialog) { 195 if (out_close_dialog) 196 *out_close_dialog = true; 197 } 198 199 bool CertificateViewerDialog::ShouldShowDialogTitle() const { 200 return true; 201 } 202 203 //////////////////////////////////////////////////////////////////////////////// 204 // CertificateViewerDialogHandler 205 206 CertificateViewerDialogHandler::CertificateViewerDialogHandler( 207 CertificateViewerDialog* dialog, 208 net::X509Certificate* cert) : cert_(cert), dialog_(dialog) { 209 x509_certificate_model::GetCertChainFromCert(cert_->os_cert_handle(), 210 &cert_chain_); 211 } 212 213 CertificateViewerDialogHandler::~CertificateViewerDialogHandler() { 214 } 215 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))); 223 } 224 225 void CertificateViewerDialogHandler::ExportCertificate( 226 const base::ListValue* args) { 227 int cert_index = GetCertificateIndex(args); 228 if (cert_index < 0) 229 return; 230 231 NativeWebContentsModalDialog window = 232 platform_util::GetTopLevel(dialog_->dialog()->GetNativeDialog()); 233 ShowCertExportDialog(web_ui()->GetWebContents(), 234 window, 235 cert_chain_[cert_index]); 236 } 237 238 void CertificateViewerDialogHandler::RequestCertificateFields( 239 const base::ListValue* args) { 240 int cert_index = GetCertificateIndex(args); 241 if (cert_index < 0) 242 return; 243 244 net::X509Certificate::OSCertHandle cert = cert_chain_[cert_index]; 245 246 ListValue root_list; 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)); 252 253 ListValue* cert_fields; 254 node_details->Set("children", cert_fields = new ListValue()); 255 cert_fields->Append(node_details = new DictionaryValue()); 256 257 node_details->SetString("label", 258 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_CERTIFICATE)); 259 node_details->Set("children", cert_fields = new ListValue()); 260 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))); 270 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))); 277 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)); 283 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)); 289 290 // Validity period. 291 cert_fields->Append(node_details = new DictionaryValue()); 292 node_details->SetString("label", 293 l10n_util::GetStringUTF8(IDS_CERT_DETAILS_VALIDITY)); 294 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))); 308 } 309 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)); 315 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)); 320 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)); 332 333 // Extensions. 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), 338 cert, &extensions); 339 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)); 344 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); 351 } 352 } 353 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)); 359 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)); 365 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()); 370 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)); 381 382 // Send certificate information to javascript. 383 web_ui()->CallJavascriptFunction("cert_viewer.getCertificateFields", 384 root_list); 385 } 386 387 int CertificateViewerDialogHandler::GetCertificateIndex( 388 const base::ListValue* args) const { 389 int cert_index; 390 double val; 391 if (!(args->GetDouble(0, &val))) 392 return -1; 393 cert_index = static_cast<int>(val); 394 if (cert_index < 0 || cert_index >= static_cast<int>(cert_chain_.size())) 395 return -1; 396 return cert_index; 397 } 398