Home | History | Annotate | Download | only in ssl
      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/ssl/ssl_add_certificate.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "base/strings/string_number_conversions.h"
      9 #include "base/strings/utf_string_conversions.h"
     10 #include "chrome/browser/certificate_viewer.h"
     11 #include "chrome/browser/infobars/infobar_service.h"
     12 #include "chrome/browser/infobars/simple_alert_infobar_delegate.h"
     13 #include "components/infobars/core/confirm_infobar_delegate.h"
     14 #include "components/infobars/core/infobar.h"
     15 #include "content/public/browser/browser_thread.h"
     16 #include "content/public/browser/render_frame_host.h"
     17 #include "content/public/browser/web_contents.h"
     18 #include "grit/generated_resources.h"
     19 #include "grit/theme_resources.h"
     20 #include "net/base/net_errors.h"
     21 #include "net/cert/cert_database.h"
     22 #include "net/cert/x509_certificate.h"
     23 #include "ui/base/l10n/l10n_util.h"
     24 
     25 using content::BrowserThread;
     26 using content::RenderFrameHost;
     27 using content::WebContents;
     28 
     29 namespace chrome {
     30 
     31 namespace {
     32 
     33 class SSLAddCertificateInfoBarDelegate : public ConfirmInfoBarDelegate {
     34  public:
     35   // Creates an SSL certificate enrollment result infobar and delegate.
     36   static void Create(InfoBarService* infobar_service,
     37                      net::X509Certificate* cert) {
     38     infobar_service->AddInfoBar(ConfirmInfoBarDelegate::CreateInfoBar(
     39         scoped_ptr<ConfirmInfoBarDelegate>(
     40             new SSLAddCertificateInfoBarDelegate(cert))));
     41   }
     42 
     43  private:
     44   explicit SSLAddCertificateInfoBarDelegate(net::X509Certificate* cert)
     45       : cert_(cert) {}
     46   virtual ~SSLAddCertificateInfoBarDelegate() {}
     47 
     48   // ConfirmInfoBarDelegate implementation:
     49   virtual int GetIconID() const OVERRIDE {
     50     // TODO(davidben): Use a more appropriate icon.
     51     return IDR_INFOBAR_SAVE_PASSWORD;
     52   }
     53 
     54   virtual Type GetInfoBarType() const OVERRIDE {
     55     return PAGE_ACTION_TYPE;
     56   }
     57 
     58   virtual base::string16 GetMessageText() const OVERRIDE {
     59     // TODO(evanm): GetDisplayName should return UTF-16.
     60     return l10n_util::GetStringFUTF16(IDS_ADD_CERT_SUCCESS_INFOBAR_LABEL,
     61                                       base::UTF8ToUTF16(
     62                                           cert_->issuer().GetDisplayName()));
     63   }
     64 
     65   virtual int GetButtons() const OVERRIDE {
     66     return BUTTON_OK;
     67   }
     68 
     69   virtual base::string16 GetButtonLabel(InfoBarButton button) const OVERRIDE {
     70     DCHECK_EQ(BUTTON_OK, button);
     71     return l10n_util::GetStringUTF16(IDS_ADD_CERT_SUCCESS_INFOBAR_BUTTON);
     72   }
     73 
     74   virtual bool Accept() OVERRIDE {
     75     WebContents* web_contents =
     76         InfoBarService::WebContentsFromInfoBar(infobar());
     77     ShowCertificateViewer(web_contents,
     78                           web_contents->GetTopLevelNativeWindow(),
     79                           cert_.get());
     80     // It looks weird to hide the infobar just as the dialog opens.
     81     return false;
     82   }
     83 
     84   // The certificate that was added.
     85   scoped_refptr<net::X509Certificate> cert_;
     86 
     87   DISALLOW_COPY_AND_ASSIGN(SSLAddCertificateInfoBarDelegate);
     88 };
     89 
     90 void ShowErrorInfoBar(int message_id,
     91                       int render_process_id,
     92                       int render_frame_id,
     93                       int cert_error) {
     94   WebContents* web_contents = WebContents::FromRenderFrameHost(
     95       RenderFrameHost::FromID(render_process_id, render_frame_id));
     96   if (!web_contents)
     97     return;
     98 
     99   // TODO(davidben): Use a more appropriate icon.
    100   // TODO(davidben): Display a more user-friendly error string.
    101   SimpleAlertInfoBarDelegate::Create(
    102       InfoBarService::FromWebContents(web_contents),
    103       IDR_INFOBAR_SAVE_PASSWORD,
    104       l10n_util::GetStringFUTF16(IDS_ADD_CERT_ERR_INVALID_CERT,
    105                                  base::IntToString16(-cert_error),
    106                                  base::ASCIIToUTF16(
    107                                      net::ErrorToString(cert_error))),
    108       true);
    109 }
    110 
    111 void ShowSuccessInfoBar(int render_process_id,
    112                         int render_frame_id,
    113                         net::X509Certificate* cert) {
    114   WebContents* web_contents = WebContents::FromRenderFrameHost(
    115       RenderFrameHost::FromID(render_process_id, render_frame_id));
    116   if (!web_contents)
    117     return;
    118 
    119   SSLAddCertificateInfoBarDelegate::Create(
    120       InfoBarService::FromWebContents(web_contents), cert);
    121 }
    122 
    123 }  // namespace
    124 
    125 void SSLAddCertificate(
    126     net::CertificateMimeType cert_type,
    127     const void* cert_data,
    128     size_t cert_size,
    129     int render_process_id,
    130     int render_frame_id) {
    131   // Chromium only supports X.509 User certificates on non-Android
    132   // platforms. Note that this method should not be called for other
    133   // certificate mime types.
    134   if (cert_type != net::CERTIFICATE_MIME_TYPE_X509_USER_CERT)
    135     return;
    136 
    137   scoped_refptr<net::X509Certificate> cert;
    138   if (cert_data != NULL) {
    139     cert = net::X509Certificate::CreateFromBytes(
    140         reinterpret_cast<const char*>(cert_data), cert_size);
    141   }
    142   // NOTE: Passing a NULL cert pointer if |cert_data| was NULL is
    143   // intentional here.
    144 
    145   // Check if we have a corresponding private key.
    146   int cert_error = net::CertDatabase::GetInstance()->CheckUserCert(cert.get());
    147   if (cert_error != net::OK) {
    148     LOG_IF(ERROR, cert_error == net::ERR_NO_PRIVATE_KEY_FOR_CERT)
    149         << "No corresponding private key in store for cert: "
    150         << (cert.get() ? cert->subject().GetDisplayName() : "NULL");
    151 
    152     BrowserThread::PostTask(
    153       BrowserThread::UI, FROM_HERE,
    154       base::Bind(&ShowErrorInfoBar, IDS_ADD_CERT_ERR_INVALID_CERT,
    155                  render_process_id, render_frame_id, cert_error));
    156     return;
    157   }
    158 
    159   // Install it.
    160   cert_error = net::CertDatabase::GetInstance()->AddUserCert(cert.get());
    161 
    162   // Show the appropriate infobar.
    163   if (cert_error != net::OK) {
    164     BrowserThread::PostTask(
    165       BrowserThread::UI, FROM_HERE,
    166       base::Bind(&ShowErrorInfoBar, IDS_ADD_CERT_ERR_FAILED,
    167                  render_process_id, render_frame_id, cert_error));
    168   } else {
    169     BrowserThread::PostTask(
    170         BrowserThread::UI, FROM_HERE,
    171         base::Bind(&ShowSuccessInfoBar,
    172                    render_process_id, render_frame_id, cert));
    173   }
    174 }
    175 
    176 }  // namespace chrome
    177