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 #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