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 25using content::BrowserThread; 26using content::RenderFrameHost; 27using content::WebContents; 28 29namespace chrome { 30 31namespace { 32 33class 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 90void 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 111void 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 125void 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