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_tab_helper.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "base/basictypes.h"
     11 #include "base/command_line.h"
     12 #include "base/strings/string_number_conversions.h"
     13 #include "base/strings/utf_string_conversions.h"
     14 #include "base/values.h"
     15 #include "chrome/browser/certificate_viewer.h"
     16 #include "chrome/browser/chrome_notification_types.h"
     17 #include "chrome/browser/content_settings/host_content_settings_map.h"
     18 #include "chrome/browser/infobars/confirm_infobar_delegate.h"
     19 #include "chrome/browser/infobars/infobar.h"
     20 #include "chrome/browser/infobars/infobar_service.h"
     21 #include "chrome/browser/profiles/profile.h"
     22 #include "chrome/browser/ssl/ssl_add_cert_handler.h"
     23 #include "chrome/browser/ssl/ssl_client_certificate_selector.h"
     24 #include "chrome/browser/ui/browser_finder.h"
     25 #include "chrome/common/chrome_switches.h"
     26 #include "content/public/browser/notification_details.h"
     27 #include "content/public/browser/notification_observer.h"
     28 #include "content/public/browser/notification_registrar.h"
     29 #include "content/public/browser/notification_source.h"
     30 #include "content/public/browser/web_contents.h"
     31 #include "content/public/browser/web_contents_view.h"
     32 #include "grit/generated_resources.h"
     33 #include "grit/theme_resources.h"
     34 #include "net/base/net_errors.h"
     35 #include "net/cert/x509_certificate.h"
     36 #include "ui/base/l10n/l10n_util.h"
     37 
     38 
     39 // SSLCertResultInfoBarDelegate -----------------------------------------------
     40 
     41 namespace {
     42 
     43 class SSLCertResultInfoBarDelegate : public ConfirmInfoBarDelegate {
     44  public:
     45   // Creates an SSL cert result infobar delegate.  If |previous_infobar| is
     46   // NULL, adds the infobar to |infobar_service|; otherwise, replaces
     47   // |previous_infobar|.  Returns the new infobar if it was successfully added.
     48   // |cert| is valid iff cert addition was successful.
     49   static InfoBarDelegate* Create(InfoBarService* infobar_service,
     50                                  InfoBarDelegate* previous_infobar,
     51                                  const string16& message,
     52                                  net::X509Certificate* cert);
     53 
     54  private:
     55   SSLCertResultInfoBarDelegate(InfoBarService* infobar_service,
     56                                const string16& message,
     57                                net::X509Certificate* cert);
     58   virtual ~SSLCertResultInfoBarDelegate();
     59 
     60   // ConfirmInfoBarDelegate:
     61   virtual int GetIconID() const OVERRIDE;
     62   virtual Type GetInfoBarType() const OVERRIDE;
     63   virtual string16 GetMessageText() const OVERRIDE;
     64   virtual int GetButtons() const OVERRIDE;
     65   virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
     66   virtual bool Accept() OVERRIDE;
     67 
     68   string16 message_;
     69   scoped_refptr<net::X509Certificate> cert_;  // The cert we added, if any.
     70 
     71   DISALLOW_COPY_AND_ASSIGN(SSLCertResultInfoBarDelegate);
     72 };
     73 
     74 // static
     75 InfoBarDelegate* SSLCertResultInfoBarDelegate::Create(
     76     InfoBarService* infobar_service,
     77     InfoBarDelegate* previous_infobar,
     78     const string16& message,
     79     net::X509Certificate* cert) {
     80   scoped_ptr<InfoBarDelegate> infobar(
     81      new SSLCertResultInfoBarDelegate(infobar_service, message, cert));
     82   return previous_infobar ?
     83       infobar_service->ReplaceInfoBar(previous_infobar, infobar.Pass()) :
     84       infobar_service->AddInfoBar(infobar.Pass());
     85 }
     86 
     87 SSLCertResultInfoBarDelegate::SSLCertResultInfoBarDelegate(
     88     InfoBarService* infobar_service,
     89     const string16& message,
     90     net::X509Certificate* cert)
     91     : ConfirmInfoBarDelegate(infobar_service),
     92       message_(message),
     93       cert_(cert) {
     94 }
     95 
     96 SSLCertResultInfoBarDelegate::~SSLCertResultInfoBarDelegate() {
     97 }
     98 
     99 int SSLCertResultInfoBarDelegate::GetIconID() const {
    100   // TODO(davidben): use a more appropriate icon.
    101   return IDR_INFOBAR_SAVE_PASSWORD;
    102 }
    103 
    104 InfoBarDelegate::Type SSLCertResultInfoBarDelegate::GetInfoBarType() const {
    105   return cert_.get() ? PAGE_ACTION_TYPE : WARNING_TYPE;
    106 }
    107 
    108 string16 SSLCertResultInfoBarDelegate::GetMessageText() const {
    109   return message_;
    110 }
    111 
    112 int SSLCertResultInfoBarDelegate::GetButtons() const {
    113   return cert_.get() ? BUTTON_OK : BUTTON_NONE;
    114 }
    115 
    116 string16 SSLCertResultInfoBarDelegate::GetButtonLabel(
    117     InfoBarButton button) const {
    118   DCHECK_EQ(BUTTON_OK, button);
    119   return l10n_util::GetStringUTF16(IDS_ADD_CERT_SUCCESS_INFOBAR_BUTTON);
    120 }
    121 
    122 bool SSLCertResultInfoBarDelegate::Accept() {
    123   ShowCertificateViewer(web_contents(),
    124                         web_contents()->GetView()->GetTopLevelNativeWindow(),
    125                         cert_.get());
    126   return false;  // Hiding the infobar just as the dialog opens looks weird.
    127 }
    128 
    129 }  // namespace
    130 
    131 
    132 // SSLTabHelper::SSLAddCertData ------------------------------------------------
    133 
    134 class SSLTabHelper::SSLAddCertData
    135     : public content::NotificationObserver {
    136  public:
    137   explicit SSLAddCertData(InfoBarService* infobar_service);
    138   virtual ~SSLAddCertData();
    139 
    140   // Displays an infobar, replacing |infobar_| if it exists.
    141   void ShowInfoBar(const string16& message, net::X509Certificate* cert);
    142 
    143  private:
    144   // content::NotificationObserver:
    145   virtual void Observe(int type,
    146                        const content::NotificationSource& source,
    147                        const content::NotificationDetails& details) OVERRIDE;
    148 
    149   InfoBarService* infobar_service_;
    150   InfoBarDelegate* infobar_;
    151   content::NotificationRegistrar registrar_;
    152 
    153   DISALLOW_COPY_AND_ASSIGN(SSLAddCertData);
    154 };
    155 
    156 SSLTabHelper::SSLAddCertData::SSLAddCertData(InfoBarService* infobar_service)
    157     : infobar_service_(infobar_service),
    158       infobar_(NULL) {
    159   content::Source<InfoBarService> source(infobar_service_);
    160   registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
    161                  source);
    162   registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REPLACED,
    163                  source);
    164 }
    165 
    166 SSLTabHelper::SSLAddCertData::~SSLAddCertData() {
    167 }
    168 
    169 void SSLTabHelper::SSLAddCertData::ShowInfoBar(const string16& message,
    170                                                net::X509Certificate* cert) {
    171   infobar_ = SSLCertResultInfoBarDelegate::Create(infobar_service_, infobar_,
    172                                                   message, cert);
    173 }
    174 
    175 void SSLTabHelper::SSLAddCertData::Observe(
    176     int type,
    177     const content::NotificationSource& source,
    178     const content::NotificationDetails& details) {
    179   DCHECK(type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED ||
    180          type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REPLACED);
    181   if (infobar_ ==
    182       ((type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED) ?
    183           content::Details<InfoBarRemovedDetails>(details)->first :
    184           content::Details<InfoBarReplacedDetails>(details)->first))
    185     infobar_ = NULL;
    186 }
    187 
    188 
    189 // SSLTabHelper ----------------------------------------------------------------
    190 
    191 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SSLTabHelper);
    192 
    193 SSLTabHelper::SSLTabHelper(content::WebContents* contents)
    194     : WebContentsObserver(contents),
    195       web_contents_(contents) {
    196 }
    197 
    198 SSLTabHelper::~SSLTabHelper() {
    199 }
    200 
    201 void SSLTabHelper::DidChangeVisibleSSLState() {
    202 #if !defined(OS_ANDROID)
    203   Browser* browser = chrome::FindBrowserWithWebContents(web_contents_);
    204   if (browser)
    205     browser->VisibleSSLStateChanged(web_contents_);
    206 #endif  // !defined(OS_ANDROID)
    207 }
    208 
    209 void SSLTabHelper::ShowClientCertificateRequestDialog(
    210     const net::HttpNetworkSession* network_session,
    211     net::SSLCertRequestInfo* cert_request_info,
    212     const base::Callback<void(net::X509Certificate*)>& callback) {
    213   chrome::ShowSSLClientCertificateSelector(web_contents_, network_session,
    214                                            cert_request_info, callback);
    215 }
    216 
    217 void SSLTabHelper::OnVerifyClientCertificateError(
    218     scoped_refptr<SSLAddCertHandler> handler, int error_code) {
    219   // Display an infobar with the error message.
    220   // TODO(davidben): Display a more user-friendly error string.
    221   GetAddCertData(handler.get())->ShowInfoBar(
    222       l10n_util::GetStringFUTF16(IDS_ADD_CERT_ERR_INVALID_CERT,
    223                                  base::IntToString16(-error_code),
    224                                  ASCIIToUTF16(net::ErrorToString(error_code))),
    225       NULL);
    226 }
    227 
    228 void SSLTabHelper::AskToAddClientCertificate(
    229     scoped_refptr<SSLAddCertHandler> handler) {
    230   NOTREACHED();  // Not implemented yet.
    231 }
    232 
    233 void SSLTabHelper::OnAddClientCertificateSuccess(
    234     scoped_refptr<SSLAddCertHandler> handler) {
    235   net::X509Certificate* cert = handler->cert();
    236   // TODO(evanm): GetDisplayName should return UTF-16.
    237   GetAddCertData(handler.get())->ShowInfoBar(
    238       l10n_util::GetStringFUTF16(IDS_ADD_CERT_SUCCESS_INFOBAR_LABEL,
    239                                  UTF8ToUTF16(cert->issuer().GetDisplayName())),
    240       cert);
    241 }
    242 
    243 void SSLTabHelper::OnAddClientCertificateError(
    244     scoped_refptr<SSLAddCertHandler> handler,
    245     int error_code) {
    246   // TODO(davidben): Display a more user-friendly error string.
    247   GetAddCertData(handler.get())->ShowInfoBar(
    248       l10n_util::GetStringFUTF16(IDS_ADD_CERT_ERR_FAILED,
    249                                  base::IntToString16(-error_code),
    250                                  ASCIIToUTF16(net::ErrorToString(error_code))),
    251       NULL);
    252 }
    253 
    254 void SSLTabHelper::OnAddClientCertificateFinished(
    255     scoped_refptr<SSLAddCertHandler> handler) {
    256   // Clean up.
    257   request_id_to_add_cert_data_.erase(handler->network_request_id());
    258 }
    259 
    260 SSLTabHelper::SSLAddCertData*
    261     SSLTabHelper::GetAddCertData(SSLAddCertHandler* handler) {
    262   // Find/create the slot.
    263   linked_ptr<SSLAddCertData>& ptr_ref =
    264       request_id_to_add_cert_data_[handler->network_request_id()];
    265   // Fill it if necessary.
    266   if (!ptr_ref.get()) {
    267     ptr_ref.reset(
    268         new SSLAddCertData(InfoBarService::FromWebContents(web_contents_)));
    269   }
    270   return ptr_ref.get();
    271 }
    272