Home | History | Annotate | Download | only in webui
      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