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