- Add support for client SSL certificates (issue #1608).

- Remember OnCertificateError approvals (issue #1590).
This commit is contained in:
Marshall Greenblatt 2015-05-19 13:55:58 -04:00
parent 2a308f2a05
commit 0d905e3744
9 changed files with 215 additions and 1 deletions

View File

@ -1018,6 +1018,8 @@
'libcef/browser/speech_recognition_manager_delegate.h',
'libcef/browser/ssl_cert_principal_impl.cc',
'libcef/browser/ssl_cert_principal_impl.h',
'libcef/browser/ssl_host_state_delegate.cc',
'libcef/browser/ssl_host_state_delegate.h',
'libcef/browser/ssl_info_impl.cc',
'libcef/browser/ssl_info_impl.h',
'libcef/browser/stream_impl.cc',

View File

@ -10,6 +10,7 @@
#include "libcef/browser/context.h"
#include "libcef/browser/download_manager_delegate.h"
#include "libcef/browser/permission_manager.h"
#include "libcef/browser/ssl_host_state_delegate.h"
#include "libcef/browser/thread_util.h"
#include "base/files/file_util.h"
@ -195,7 +196,9 @@ content::PushMessagingService*
content::SSLHostStateDelegate*
CefBrowserContextImpl::GetSSLHostStateDelegate() {
return NULL;
if (!ssl_host_state_delegate_.get())
ssl_host_state_delegate_.reset(new CefSSLHostStateDelegate());
return ssl_host_state_delegate_.get();
}
content::PermissionManager* CefBrowserContextImpl::GetPermissionManager() {

View File

@ -21,6 +21,7 @@ class SpeechRecognitionPreferences;
}
class CefDownloadManagerDelegate;
class CefSSLHostStateDelegate;
// Isolated BrowserContext implementation. Life span is controlled by
// CefRequestContextImpl and (for the main context) CefBrowserMainParts. Only
@ -97,6 +98,7 @@ class CefBrowserContextImpl : public CefBrowserContext {
scoped_ptr<CefDownloadManagerDelegate> download_manager_delegate_;
scoped_refptr<CefURLRequestContextGetterImpl> url_request_getter_;
scoped_ptr<content::PermissionManager> permission_manager_;
scoped_ptr<CefSSLHostStateDelegate> ssl_host_state_delegate_;
DISALLOW_COPY_AND_ASSIGN(CefBrowserContextImpl);
};

View File

@ -37,6 +37,7 @@
#include "content/public/browser/access_token_store.h"
#include "content/public/browser/browser_url_handler.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/client_certificate_delegate.h"
#include "content/public/browser/plugin_service_filter.h"
#include "content/public/browser/quota_permission_context.h"
#include "content/public/browser/render_process_host.h"
@ -46,6 +47,7 @@
#include "content/public/common/storage_quota_params.h"
#include "content/public/common/web_preferences.h"
#include "gin/v8_initializer.h"
#include "net/ssl/ssl_cert_request_info.h"
#include "third_party/WebKit/public/web/WebWindowFeatures.h"
#include "ui/base/ui_base_switches.h"
#include "url/gurl.h"
@ -755,6 +757,16 @@ void CefContentBrowserClient::AllowCertificateError(
content::CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL;
}
void CefContentBrowserClient::SelectClientCertificate(
content::WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info,
scoped_ptr<content::ClientCertificateDelegate> delegate) {
if (!cert_request_info->client_certs.empty()) {
// Use the first certificate.
delegate->ContinueWithCertificate(cert_request_info->client_certs[0].get());
}
}
content::AccessTokenStore* CefContentBrowserClient::CreateAccessTokenStore() {
return new CefAccessTokenStore(
browser_main_parts_->browser_context()->request_context().get());

View File

@ -105,6 +105,10 @@ class CefContentBrowserClient : public content::ContentBrowserClient {
bool expired_previous_decision,
const base::Callback<void(bool)>& callback,
content::CertificateRequestResultType* result) override;
void SelectClientCertificate(
content::WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info,
scoped_ptr<content::ClientCertificateDelegate> delegate) override;
content::AccessTokenStore* CreateAccessTokenStore() override;
bool CanCreateWindow(const GURL& opener_url,
const GURL& opener_top_level_frame_url,

View File

@ -8,6 +8,18 @@
#include "base/logging.h"
#include "content/public/browser/browser_thread.h"
#if defined(USE_NSS_CERTS)
#include "net/ssl/client_cert_store_nss.h"
#endif
#if defined(OS_WIN)
#include "net/ssl/client_cert_store_win.h"
#endif
#if defined(OS_MACOSX)
#include "net/ssl/client_cert_store_mac.h"
#endif
CefResourceContext::CefResourceContext() {
}
@ -35,6 +47,24 @@ net::URLRequestContext* CefResourceContext::GetRequestContext() {
return getter_->GetURLRequestContext();
}
scoped_ptr<net::ClientCertStore> CefResourceContext::CreateClientCertStore() {
#if defined(USE_NSS_CERTS)
return scoped_ptr<net::ClientCertStore>(new net::ClientCertStoreNSS(
net::ClientCertStoreNSS::PasswordDelegateFactory()));
#elif defined(OS_WIN)
return scoped_ptr<net::ClientCertStore>(new net::ClientCertStoreWin());
#elif defined(OS_MACOSX)
return scoped_ptr<net::ClientCertStore>(new net::ClientCertStoreMac());
#elif defined(USE_OPENSSL)
// OpenSSL does not use the ClientCertStore infrastructure. On Android client
// cert matching is done by the OS as part of the call to show the cert
// selection dialog.
return scoped_ptr<net::ClientCertStore>();
#else
#error Unknown platform.
#endif
}
void CefResourceContext::set_url_request_context_getter(
scoped_refptr<CefURLRequestContextGetter> getter) {
DCHECK(!getter_.get());

View File

@ -26,6 +26,7 @@ class CefResourceContext : public content::ResourceContext {
// ResourceContext implementation.
net::HostResolver* GetHostResolver() override;
net::URLRequestContext* GetRequestContext() override;
scoped_ptr<net::ClientCertStore> CreateClientCertStore() override;
void set_url_request_context_getter(
scoped_refptr<CefURLRequestContextGetter> getter);

View File

@ -0,0 +1,86 @@
// Copyright (c) 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libcef/browser/ssl_host_state_delegate.h"
#include "net/base/hash_value.h"
using content::SSLHostStateDelegate;
namespace internal {
net::SHA256HashValue getChainFingerprint256(const net::X509Certificate& cert) {
net::SHA256HashValue fingerprint =
net::X509Certificate::CalculateChainFingerprint256(
cert.os_cert_handle(), cert.GetIntermediateCertificates());
return fingerprint;
}
CertPolicy::CertPolicy() {
}
CertPolicy::~CertPolicy() {
}
// For an allowance, we consider a given |cert| to be a match to a saved
// allowed cert if the |error| is an exact match to or subset of the errors
// in the saved CertStatus.
bool CertPolicy::Check(const net::X509Certificate& cert,
net::CertStatus error) const {
net::SHA256HashValue fingerprint = getChainFingerprint256(cert);
std::map<net::SHA256HashValue, net::CertStatus,
net::SHA256HashValueLessThan>::const_iterator allowed_iter =
allowed_.find(fingerprint);
if ((allowed_iter != allowed_.end()) && (allowed_iter->second & error) &&
((allowed_iter->second & error) == error)) {
return true;
}
return false;
}
void CertPolicy::Allow(const net::X509Certificate& cert,
net::CertStatus error) {
// If this same cert had already been saved with a different error status,
// this will replace it with the new error status.
net::SHA256HashValue fingerprint = getChainFingerprint256(cert);
allowed_[fingerprint] = error;
}
} // namespace internal
CefSSLHostStateDelegate::CefSSLHostStateDelegate() {
}
CefSSLHostStateDelegate::~CefSSLHostStateDelegate() {
}
void CefSSLHostStateDelegate::HostRanInsecureContent(const std::string& host,
int pid) {
// Intentional no-op.
}
bool CefSSLHostStateDelegate::DidHostRunInsecureContent(const std::string& host,
int pid) const {
// Intentional no-op.
return false;
}
void CefSSLHostStateDelegate::AllowCert(const std::string& host,
const net::X509Certificate& cert,
net::CertStatus error) {
cert_policy_for_host_[host].Allow(cert, error);
}
void CefSSLHostStateDelegate::Clear() {
cert_policy_for_host_.clear();
}
SSLHostStateDelegate::CertJudgment CefSSLHostStateDelegate::QueryPolicy(
const std::string& host,
const net::X509Certificate& cert,
net::CertStatus error,
bool* expired_previous_decision) {
return cert_policy_for_host_[host].Check(cert, error)
? SSLHostStateDelegate::ALLOWED
: SSLHostStateDelegate::DENIED;
}

View File

@ -0,0 +1,74 @@
// Copyright (c) 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CEF_LIBCEF_BROWSER_SSL_HOST_STATE_DELEGATE_H_
#define CEF_LIBCEF_BROWSER_SSL_HOST_STATE_DELEGATE_H_
#include <map>
#include <string>
#include "content/public/browser/ssl_host_state_delegate.h"
#include "net/base/hash_value.h"
#include "net/cert/cert_status_flags.h"
#include "net/cert/x509_certificate.h"
namespace internal {
// This class maintains the policy for storing actions on certificate errors.
class CertPolicy {
public:
CertPolicy();
~CertPolicy();
// Returns true if the user has decided to proceed through the ssl error
// before. For a certificate to be allowed, it must not have any
// *additional* errors from when it was allowed.
bool Check(const net::X509Certificate& cert, net::CertStatus error) const;
// Causes the policy to allow this certificate for a given |error|. And
// remember the user's choice.
void Allow(const net::X509Certificate& cert, net::CertStatus error);
private:
// The set of fingerprints of allowed certificates.
std::map<net::SHA256HashValue, net::CertStatus, net::SHA256HashValueLessThan>
allowed_;
};
} // namespace internal
class CefSSLHostStateDelegate : public content::SSLHostStateDelegate {
public:
CefSSLHostStateDelegate();
~CefSSLHostStateDelegate() override;
// Records that |cert| is permitted to be used for |host| in the future, for
// a specified |error| type.
void AllowCert(const std::string& host,
const net::X509Certificate& cert,
net::CertStatus error) override;
void Clear() override;
// Queries whether |cert| is allowed or denied for |host| and |error|.
content::SSLHostStateDelegate::CertJudgment QueryPolicy(
const std::string& host,
const net::X509Certificate& cert,
net::CertStatus error,
bool* expired_previous_decision) override;
// Records that a host has run insecure content.
void HostRanInsecureContent(const std::string& host, int pid) override;
// Returns whether the specified host ran insecure content.
bool DidHostRunInsecureContent(const std::string& host,
int pid) const override;
private:
// Certificate policies for each host.
std::map<std::string, internal::CertPolicy> cert_policy_for_host_;
DISALLOW_COPY_AND_ASSIGN(CefSSLHostStateDelegate);
};
#endif // CEF_LIBCEF_BROWSER_SSL_HOST_STATE_DELEGATE_H_