• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "chrome/grit/generated_resources.h"
14 #include "components/infobars/core/confirm_infobar_delegate.h"
15 #include "components/infobars/core/infobar.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/render_frame_host.h"
18 #include "content/public/browser/web_contents.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.
Create(InfoBarService * infobar_service,net::X509Certificate * cert)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:
SSLAddCertificateInfoBarDelegate(net::X509Certificate * cert)44   explicit SSLAddCertificateInfoBarDelegate(net::X509Certificate* cert)
45       : cert_(cert) {}
~SSLAddCertificateInfoBarDelegate()46   virtual ~SSLAddCertificateInfoBarDelegate() {}
47 
48   // ConfirmInfoBarDelegate implementation:
GetIconID() const49   virtual int GetIconID() const OVERRIDE {
50     // TODO(davidben): Use a more appropriate icon.
51     return IDR_INFOBAR_SAVE_PASSWORD;
52   }
53 
GetInfoBarType() const54   virtual Type GetInfoBarType() const OVERRIDE {
55     return PAGE_ACTION_TYPE;
56   }
57 
GetMessageText() const58   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 
GetButtons() const65   virtual int GetButtons() const OVERRIDE {
66     return BUTTON_OK;
67   }
68 
GetButtonLabel(InfoBarButton button) const69   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 
Accept()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 
ShowErrorInfoBar(int message_id,int render_process_id,int render_frame_id,int cert_error)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 
ShowSuccessInfoBar(int render_process_id,int render_frame_id,net::X509Certificate * cert)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 
SSLAddCertificate(net::CertificateMimeType cert_type,const void * cert_data,size_t cert_size,int render_process_id,int render_frame_id)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