12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ssl/ssl_add_certificate.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/basictypes.h"
846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/strings/utf_string_conversions.h"
1046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "chrome/browser/certificate_viewer.h"
1146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "chrome/browser/infobars/infobar_service.h"
1246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "chrome/browser/infobars/simple_alert_infobar_delegate.h"
1303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/grit/generated_resources.h"
1446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "components/infobars/core/confirm_infobar_delegate.h"
1546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "components/infobars/core/infobar.h"
1646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
1746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "content/public/browser/render_frame_host.h"
1846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "content/public/browser/web_contents.h"
1946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "grit/theme_resources.h"
2046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "net/base/net_errors.h"
2146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "net/cert/cert_database.h"
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/cert/x509_certificate.h"
2346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
2446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
2546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)using content::BrowserThread;
2646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)using content::RenderFrameHost;
2746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)using content::WebContents;
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace chrome {
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)namespace {
3246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
3346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)class SSLAddCertificateInfoBarDelegate : public ConfirmInfoBarDelegate {
3446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) public:
3546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Creates an SSL certificate enrollment result infobar and delegate.
3646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  static void Create(InfoBarService* infobar_service,
3746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                     net::X509Certificate* cert) {
3846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    infobar_service->AddInfoBar(ConfirmInfoBarDelegate::CreateInfoBar(
3946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        scoped_ptr<ConfirmInfoBarDelegate>(
4046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)            new SSLAddCertificateInfoBarDelegate(cert))));
4146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
4246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
4346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) private:
4446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  explicit SSLAddCertificateInfoBarDelegate(net::X509Certificate* cert)
4546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      : cert_(cert) {}
4646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  virtual ~SSLAddCertificateInfoBarDelegate() {}
4746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
4846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // ConfirmInfoBarDelegate implementation:
4946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  virtual int GetIconID() const OVERRIDE {
5046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // TODO(davidben): Use a more appropriate icon.
5146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return IDR_INFOBAR_SAVE_PASSWORD;
5246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
5346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
5446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  virtual Type GetInfoBarType() const OVERRIDE {
5546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return PAGE_ACTION_TYPE;
5646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
5746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
5846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  virtual base::string16 GetMessageText() const OVERRIDE {
5946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // TODO(evanm): GetDisplayName should return UTF-16.
6046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return l10n_util::GetStringFUTF16(IDS_ADD_CERT_SUCCESS_INFOBAR_LABEL,
6146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                      base::UTF8ToUTF16(
6246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                          cert_->issuer().GetDisplayName()));
6346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
6446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
6546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  virtual int GetButtons() const OVERRIDE {
6646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return BUTTON_OK;
6746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
6846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
6946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  virtual base::string16 GetButtonLabel(InfoBarButton button) const OVERRIDE {
7046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    DCHECK_EQ(BUTTON_OK, button);
7146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return l10n_util::GetStringUTF16(IDS_ADD_CERT_SUCCESS_INFOBAR_BUTTON);
7246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
7346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
7446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  virtual bool Accept() OVERRIDE {
7546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    WebContents* web_contents =
7646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        InfoBarService::WebContentsFromInfoBar(infobar());
7746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    ShowCertificateViewer(web_contents,
7846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                          web_contents->GetTopLevelNativeWindow(),
7946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                          cert_.get());
8046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // It looks weird to hide the infobar just as the dialog opens.
8146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return false;
8246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
8346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
8446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // The certificate that was added.
8546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  scoped_refptr<net::X509Certificate> cert_;
8646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
8746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(SSLAddCertificateInfoBarDelegate);
8846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)};
8946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
9046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void ShowErrorInfoBar(int message_id,
9146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      int render_process_id,
9246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      int render_frame_id,
9346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                      int cert_error) {
9446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  WebContents* web_contents = WebContents::FromRenderFrameHost(
9546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      RenderFrameHost::FromID(render_process_id, render_frame_id));
9646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!web_contents)
9746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
9846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
9946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // TODO(davidben): Use a more appropriate icon.
10046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // TODO(davidben): Display a more user-friendly error string.
10146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  SimpleAlertInfoBarDelegate::Create(
10246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      InfoBarService::FromWebContents(web_contents),
10346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      IDR_INFOBAR_SAVE_PASSWORD,
10446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      l10n_util::GetStringFUTF16(IDS_ADD_CERT_ERR_INVALID_CERT,
10546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                 base::IntToString16(-cert_error),
10646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                 base::ASCIIToUTF16(
10746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                     net::ErrorToString(cert_error))),
10846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      true);
10946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
11046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
11146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void ShowSuccessInfoBar(int render_process_id,
11246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                        int render_frame_id,
11346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                        net::X509Certificate* cert) {
11446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  WebContents* web_contents = WebContents::FromRenderFrameHost(
11546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      RenderFrameHost::FromID(render_process_id, render_frame_id));
11646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!web_contents)
11746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
11846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
11946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  SSLAddCertificateInfoBarDelegate::Create(
12046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      InfoBarService::FromWebContents(web_contents), cert);
12146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
12246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
12346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}  // namespace
12446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SSLAddCertificate(
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net::CertificateMimeType cert_type,
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const void* cert_data,
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    size_t cert_size,
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int render_process_id,
13046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    int render_frame_id) {
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Chromium only supports X.509 User certificates on non-Android
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // platforms. Note that this method should not be called for other
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // certificate mime types.
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (cert_type != net::CERTIFICATE_MIME_TYPE_X509_USER_CERT)
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<net::X509Certificate> cert;
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (cert_data != NULL) {
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    cert = net::X509Certificate::CreateFromBytes(
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        reinterpret_cast<const char*>(cert_data), cert_size);
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // NOTE: Passing a NULL cert pointer if |cert_data| was NULL is
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // intentional here.
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Check if we have a corresponding private key.
14646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  int cert_error = net::CertDatabase::GetInstance()->CheckUserCert(cert.get());
14746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (cert_error != net::OK) {
14846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    LOG_IF(ERROR, cert_error == net::ERR_NO_PRIVATE_KEY_FOR_CERT)
14946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        << "No corresponding private key in store for cert: "
15046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        << (cert.get() ? cert->subject().GetDisplayName() : "NULL");
15146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
15246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    BrowserThread::PostTask(
15346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      BrowserThread::UI, FROM_HERE,
15446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      base::Bind(&ShowErrorInfoBar, IDS_ADD_CERT_ERR_INVALID_CERT,
15546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 render_process_id, render_frame_id, cert_error));
15646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
15746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
15846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
15946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Install it.
16046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  cert_error = net::CertDatabase::GetInstance()->AddUserCert(cert.get());
16146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
16246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Show the appropriate infobar.
16346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (cert_error != net::OK) {
16446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    BrowserThread::PostTask(
16546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      BrowserThread::UI, FROM_HERE,
16646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      base::Bind(&ShowErrorInfoBar, IDS_ADD_CERT_ERR_FAILED,
16746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 render_process_id, render_frame_id, cert_error));
16846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  } else {
16946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    BrowserThread::PostTask(
17046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        BrowserThread::UI, FROM_HERE,
17146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        base::Bind(&ShowSuccessInfoBar,
17246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                   render_process_id, render_frame_id, cert));
17346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace chrome
177