From 4366a9b7b2726be0dddd6fc2fd265b85e63d2e86 Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Thu, 27 Oct 2016 13:57:12 -0400 Subject: [PATCH] Add callback for custom certificate selection (issue #1824) --- cef_paths.gypi | 4 + include/capi/cef_request_handler_capi.h | 40 ++++++ include/cef_request_handler.h | 40 +++++- include/cef_x509_certificate.h | 2 + libcef/browser/content_browser_client.cc | 90 ++++++++++++- libcef/browser/ssl_info_impl.cc | 2 +- libcef/browser/ssl_status_impl.cc | 2 +- libcef/browser/x509_certificate_impl.cc | 122 ++++++++++-------- libcef/browser/x509_certificate_impl.h | 16 +-- libcef_dll/cpptoc/request_handler_cpptoc.cc | 54 ++++++++ ...lect_client_certificate_callback_cpptoc.cc | 63 +++++++++ ...elect_client_certificate_callback_cpptoc.h | 36 ++++++ libcef_dll/ctocpp/request_handler_ctocpp.cc | 56 ++++++++ libcef_dll/ctocpp/request_handler_ctocpp.h | 4 + ...lect_client_certificate_callback_ctocpp.cc | 58 +++++++++ ...elect_client_certificate_callback_ctocpp.h | 39 ++++++ libcef_dll/libcef_dll.cc | 3 + libcef_dll/wrapper/libcef_dll_wrapper.cc | 3 + libcef_dll/wrapper_types.h | 1 + tests/cefclient/browser/client_handler.cc | 36 ++++++ tests/cefclient/browser/client_handler.h | 7 + tests/cefclient/common/client_switches.cc | 1 + tests/cefclient/common/client_switches.h | 1 + 23 files changed, 613 insertions(+), 67 deletions(-) create mode 100644 libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.cc create mode 100644 libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.h create mode 100644 libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.cc create mode 100644 libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.h diff --git a/cef_paths.gypi b/cef_paths.gypi index 656bcbaeb..ed19176ae 100644 --- a/cef_paths.gypi +++ b/cef_paths.gypi @@ -360,6 +360,8 @@ 'libcef_dll/cpptoc/scheme_registrar_cpptoc.h', 'libcef_dll/cpptoc/views/scroll_view_cpptoc.cc', 'libcef_dll/cpptoc/views/scroll_view_cpptoc.h', + 'libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.cc', + 'libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.h', 'libcef_dll/ctocpp/set_cookie_callback_ctocpp.cc', 'libcef_dll/ctocpp/set_cookie_callback_ctocpp.h', 'libcef_dll/cpptoc/stream_reader_cpptoc.cc', @@ -616,6 +618,8 @@ 'libcef_dll/ctocpp/scheme_registrar_ctocpp.h', 'libcef_dll/ctocpp/views/scroll_view_ctocpp.cc', 'libcef_dll/ctocpp/views/scroll_view_ctocpp.h', + 'libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.cc', + 'libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.h', 'libcef_dll/cpptoc/set_cookie_callback_cpptoc.cc', 'libcef_dll/cpptoc/set_cookie_callback_cpptoc.h', 'libcef_dll/ctocpp/stream_reader_ctocpp.cc', diff --git a/include/capi/cef_request_handler_capi.h b/include/capi/cef_request_handler_capi.h index b1aeb849c..4fa024251 100644 --- a/include/capi/cef_request_handler_capi.h +++ b/include/capi/cef_request_handler_capi.h @@ -47,6 +47,7 @@ #include "include/capi/cef_response_capi.h" #include "include/capi/cef_response_filter_capi.h" #include "include/capi/cef_ssl_info_capi.h" +#include "include/capi/cef_x509_certificate_capi.h" #ifdef __cplusplus extern "C" { @@ -75,6 +76,25 @@ typedef struct _cef_request_callback_t { } cef_request_callback_t; +/// +// Callback structure used to select a client certificate for authentication. +/// +typedef struct _cef_select_client_certificate_callback_t { + /// + // Base structure. + /// + cef_base_t base; + + /// + // Chooses the specified certificate for client certificate authentication. + // NULL value means that no client certificate should be used. + /// + void (CEF_CALLBACK *select)( + struct _cef_select_client_certificate_callback_t* self, + struct _cef_x509certificate_t* cert); +} cef_select_client_certificate_callback_t; + + /// // Implement this structure to handle events related to browser requests. The // functions of this structure will be called on the thread indicated. @@ -241,6 +261,26 @@ typedef struct _cef_request_handler_t { const cef_string_t* request_url, struct _cef_sslinfo_t* ssl_info, struct _cef_request_callback_t* callback); + /// + // Called on the UI thread when a client certificate is being requested for + // authentication. Return false (0) to use the default behavior and + // automatically select the first certificate available. Return true (1) and + // call cef_select_client_certificate_callback_t::Select either in this + // function or at a later time to select a certificate. Do not call Select or + // call it with NULL to continue without using any certificate. |isProxy| + // indicates whether the host is an HTTPS proxy or the origin server. |host| + // and |port| contains the hostname and port of the SSL server. |certificates| + // is the list of certificates to choose from; this list has already been + // pruned by Chromium so that it only contains certificates from issuers that + // the server trusts. + /// + int (CEF_CALLBACK *on_select_client_certificate)( + struct _cef_request_handler_t* self, struct _cef_browser_t* browser, + int isProxy, const cef_string_t* host, int port, + size_t certificatesCount, + struct _cef_x509certificate_t* const* certificates, + struct _cef_select_client_certificate_callback_t* callback); + /// // Called on the browser process UI thread when a plugin has crashed. // |plugin_path| is the path of the plugin that crashed. diff --git a/include/cef_request_handler.h b/include/cef_request_handler.h index a4f097083..fa83a1a36 100644 --- a/include/cef_request_handler.h +++ b/include/cef_request_handler.h @@ -47,7 +47,7 @@ #include "include/cef_response_filter.h" #include "include/cef_request.h" #include "include/cef_ssl_info.h" - +#include "include/cef_x509_certificate.h" /// // Callback interface used for asynchronous continuation of url requests. @@ -70,6 +70,21 @@ class CefRequestCallback : public virtual CefBase { }; +/// +// Callback interface used to select a client certificate for authentication. +/// +/*--cef(source=library)--*/ +class CefSelectClientCertificateCallback : public virtual CefBase { + public: + /// + // Chooses the specified certificate for client certificate authentication. + // NULL value means that no client certificate should be used. + /// + /*--cef(optional_param=cert)--*/ + virtual void Select(CefRefPtr cert) =0; +}; + + /// // Implement this interface to handle events related to browser requests. The // methods of this class will be called on the thread indicated. @@ -282,6 +297,29 @@ class CefRequestHandler : public virtual CefBase { return false; } + /// + // Called on the UI thread when a client certificate is being requested for + // authentication. Return false to use the default behavior and automatically + // select the first certificate available. Return true and call + // CefSelectClientCertificateCallback::Select either in this method or at a + // later time to select a certificate. Do not call Select or call it with NULL + // to continue without using any certificate. |isProxy| indicates whether the + // host is an HTTPS proxy or the origin server. |host| and |port| contains the + // hostname and port of the SSL server. |certificates| is the list of + // certificates to choose from; this list has already been pruned by Chromium + // so that it only contains certificates from issuers that the server trusts. + /// + /*--cef()--*/ + virtual bool OnSelectClientCertificate( + CefRefPtr browser, + bool isProxy, + const CefString& host, + int port, + const CefX509CertificateList& certificates, + CefRefPtr callback) { + return false; + } + /// // Called on the browser process UI thread when a plugin has crashed. // |plugin_path| is the path of the plugin that crashed. diff --git a/include/cef_x509_certificate.h b/include/cef_x509_certificate.h index f036ab5ed..b81839f29 100644 --- a/include/cef_x509_certificate.h +++ b/include/cef_x509_certificate.h @@ -185,4 +185,6 @@ class CefX509Certificate : public virtual CefBase { virtual void GetPEMEncodedIssuerChain(IssuerChainBinaryList& chain) =0; }; +typedef std::vector > CefX509CertificateList; + #endif // CEF_INCLUDE_CEF_X509_CERTIFICATE_H_ diff --git a/libcef/browser/content_browser_client.cc b/libcef/browser/content_browser_client.cc index 11ebfd03f..05555e62f 100644 --- a/libcef/browser/content_browser_client.cc +++ b/libcef/browser/content_browser_client.cc @@ -27,6 +27,7 @@ #include "libcef/browser/speech_recognition_manager_delegate.h" #include "libcef/browser/ssl_info_impl.h" #include "libcef/browser/thread_util.h" +#include "libcef/browser/x509_certificate_impl.h" #include "libcef/common/cef_messages.h" #include "libcef/common/cef_switches.h" #include "libcef/common/command_line_impl.h" @@ -207,6 +208,58 @@ class CefAllowCertificateErrorCallbackImpl : public CefRequestCallback { DISALLOW_COPY_AND_ASSIGN(CefAllowCertificateErrorCallbackImpl); }; +class CefSelectClientCertificateCallbackImpl : + public CefSelectClientCertificateCallback { + public: + explicit CefSelectClientCertificateCallbackImpl( + std::unique_ptr delegate) + : delegate_(std::move(delegate)) { + } + + ~CefSelectClientCertificateCallbackImpl() { + // If Select has not been called, call it with NULL to continue without any + // client certificate. + if (delegate_) + DoSelect(NULL); + } + + void Select(CefRefPtr cert) override { + if (delegate_) + DoSelect(cert); + } + + private: + void DoSelect(CefRefPtr cert) { + if (CEF_CURRENTLY_ON_UIT()) { + RunNow(std::move(delegate_), cert); + } else { + CEF_POST_TASK(CEF_UIT, + base::Bind(&CefSelectClientCertificateCallbackImpl::RunNow, + base::Passed(std::move(delegate_)), cert)); + } + } + + static void RunNow( + std::unique_ptr delegate, + CefRefPtr cert) { + CEF_REQUIRE_UIT(); + + scoped_refptr x509cert = NULL; + if (cert) { + CefX509CertificateImpl* certImpl = + static_cast(cert.get()); + x509cert = certImpl->GetInternalCertObject(); + } + + delegate->ContinueWithCertificate(x509cert.get()); + } + + std::unique_ptr delegate_; + + IMPLEMENT_REFCOUNTING(CefSelectClientCertificateCallbackImpl); + DISALLOW_COPY_AND_ASSIGN(CefSelectClientCertificateCallbackImpl); +}; + class CefQuotaPermissionContext : public content::QuotaPermissionContext { public: CefQuotaPermissionContext() { @@ -711,9 +764,40 @@ void CefContentBrowserClient::SelectClientCertificate( content::WebContents* web_contents, net::SSLCertRequestInfo* cert_request_info, std::unique_ptr delegate) { - if (!cert_request_info->client_certs.empty()) { - // Use the first certificate. - delegate->ContinueWithCertificate(cert_request_info->client_certs[0].get()); + CEF_REQUIRE_UIT(); + + CefRefPtr handler; + CefRefPtr browser = + CefBrowserHostImpl::GetBrowserForContents(web_contents); + if (browser.get()) { + CefRefPtr client = browser->GetClient(); + if (client.get()) + handler = client->GetRequestHandler(); + } + + if (!handler.get()) { + delegate->ContinueWithCertificate(NULL); + return; + } + + CefX509CertificateList certs; + for (std::vector >::iterator iter = + cert_request_info->client_certs.begin(); + iter != cert_request_info->client_certs.end(); iter++) { + certs.push_back(new CefX509CertificateImpl(*iter)); + } + + CefRefPtr callbackImpl( + new CefSelectClientCertificateCallbackImpl(std::move(delegate))); + + bool proceed = handler->OnSelectClientCertificate( + browser.get(), cert_request_info->is_proxy, + cert_request_info->host_and_port.host(), + cert_request_info->host_and_port.port(), + certs, callbackImpl.get()); + + if (!proceed && !certs.empty()) { + callbackImpl->Select(certs[0]); } } diff --git a/libcef/browser/ssl_info_impl.cc b/libcef/browser/ssl_info_impl.cc index 5bd2e2b94..025ef085f 100644 --- a/libcef/browser/ssl_info_impl.cc +++ b/libcef/browser/ssl_info_impl.cc @@ -11,7 +11,7 @@ CefSSLInfoImpl::CefSSLInfoImpl(const net::SSLInfo& value) : cert_status_(CERT_STATUS_NONE) { cert_status_ = static_cast(value.cert_status); if (value.cert.get()) { - cert_ = new CefX509CertificateImpl(*value.cert); + cert_ = new CefX509CertificateImpl(value.cert); } } diff --git a/libcef/browser/ssl_status_impl.cc b/libcef/browser/ssl_status_impl.cc index 1ed4a62f4..8df9217ea 100644 --- a/libcef/browser/ssl_status_impl.cc +++ b/libcef/browser/ssl_status_impl.cc @@ -39,7 +39,7 @@ CefRefPtr CefSSLStatusImpl::GetX509Certificate() { scoped_refptr cert; content::CertStore::GetInstance()->RetrieveCert(cert_id_, &cert); if (cert.get()) - return new CefX509CertificateImpl(*cert); + return new CefX509CertificateImpl(cert); } return nullptr; } diff --git a/libcef/browser/x509_certificate_impl.cc b/libcef/browser/x509_certificate_impl.cc index 81a6e525a..1002d0cb2 100644 --- a/libcef/browser/x509_certificate_impl.cc +++ b/libcef/browser/x509_certificate_impl.cc @@ -8,97 +8,115 @@ namespace { -void EncodeCertificate( - const net::X509Certificate::OSCertHandle& os_handle, - CefRefPtr& der_encoded, - CefRefPtr& pem_encoded) { +CefRefPtr EncodeCertificate( + const net::X509Certificate::OSCertHandle& os_handle, bool der) { + CefRefPtr bin_encoded; std::string encoded; - if (net::X509Certificate::GetDEREncoded(os_handle, &encoded)) { - der_encoded = CefBinaryValue::Create(encoded.c_str(), - encoded.size()); - } - encoded.clear(); - if (net::X509Certificate::GetPEMEncoded(os_handle, &encoded)) { - pem_encoded = CefBinaryValue::Create(encoded.c_str(), - encoded.size()); + + if (( der && net::X509Certificate::GetDEREncoded(os_handle, &encoded)) || + (!der && net::X509Certificate::GetPEMEncoded(os_handle, &encoded))) { + bin_encoded = CefBinaryValue::Create(encoded.c_str(), encoded.size()); } + + return bin_encoded; } } // namespace CefX509CertificateImpl::CefX509CertificateImpl( - const net::X509Certificate& value) { - subject_ = new CefX509CertPrincipalImpl(value.subject()); - issuer_ = new CefX509CertPrincipalImpl(value.issuer()); - - const std::string& serial_number = value.serial_number(); - serial_number_ = CefBinaryValue::Create(serial_number.c_str(), - serial_number.size()); - - const base::Time& valid_start = value.valid_start(); - if (!valid_start.is_null()) - cef_time_from_basetime(valid_start, valid_start_); - - const base::Time& valid_expiry = value.valid_expiry(); - if (!valid_expiry.is_null()) - cef_time_from_basetime(valid_expiry, valid_expiry_); - - net::X509Certificate::OSCertHandle os_handle = value.os_cert_handle(); - if (os_handle) - EncodeCertificate(os_handle, der_encoded_, pem_encoded_); - - const net::X509Certificate::OSCertHandles& issuer_chain = - value.GetIntermediateCertificates(); - for (net::X509Certificate::OSCertHandles::const_iterator it = - issuer_chain.begin(); it != issuer_chain.end(); it++) { - CefRefPtr der_encoded, pem_encoded; - EncodeCertificate(*it, der_encoded, pem_encoded); - - // Add each to the chain, even if one conversion unexpectedly failed. - // GetIssuerChainSize depends on these being the same length. - der_encoded_issuer_chain_.push_back(der_encoded); - pem_encoded_issuer_chain_.push_back(pem_encoded); - } + scoped_refptr cert) + :cert_(cert) { } CefRefPtr CefX509CertificateImpl::GetSubject() { - return subject_; + if (cert_) + return new CefX509CertPrincipalImpl(cert_->subject()); + return nullptr; } CefRefPtr CefX509CertificateImpl::GetIssuer() { - return issuer_; + if (cert_) + return new CefX509CertPrincipalImpl(cert_->issuer()); + return nullptr; } CefRefPtr CefX509CertificateImpl::GetSerialNumber() { - return serial_number_; + if (cert_) { + const std::string& serial = cert_->serial_number(); + return CefBinaryValue::Create(serial.c_str(), serial.size()); + } + return nullptr; } CefTime CefX509CertificateImpl::GetValidStart() { - return valid_start_; + CefTime validity; + if (cert_) { + const base::Time& valid_time = cert_->valid_start(); + if (!valid_time.is_null()) + cef_time_from_basetime(valid_time, validity); + } + return validity; } CefTime CefX509CertificateImpl::GetValidExpiry() { - return valid_expiry_; + CefTime validity; + if (cert_) { + const base::Time& valid_time = cert_->valid_expiry(); + if (!valid_time.is_null()) + cef_time_from_basetime(valid_time, validity); + } + return validity; } CefRefPtr CefX509CertificateImpl::GetDEREncoded() { - return der_encoded_; + if (cert_) { + net::X509Certificate::OSCertHandle os_handle = cert_->os_cert_handle(); + if (os_handle) + return EncodeCertificate(os_handle, true); + } + return nullptr; } CefRefPtr CefX509CertificateImpl::GetPEMEncoded() { - return pem_encoded_; + if (cert_) { + net::X509Certificate::OSCertHandle os_handle = cert_->os_cert_handle(); + if (os_handle) + return EncodeCertificate(os_handle, false); + } + return nullptr; } size_t CefX509CertificateImpl::GetIssuerChainSize() { - return der_encoded_issuer_chain_.size(); + if (cert_) + return cert_->GetIntermediateCertificates().size(); + return 0; +} + +void CefX509CertificateImpl::GetEncodedIssuerChain( + CefX509Certificate::IssuerChainBinaryList& chain, bool der) { + chain.clear(); + if (cert_) { + const net::X509Certificate::OSCertHandles& handles = + cert_->GetIntermediateCertificates(); + for (net::X509Certificate::OSCertHandles::const_iterator it = + handles.begin(); it != handles.end(); it++) { + // Add each to the chain, even if one conversion unexpectedly failed. + // GetIssuerChainSize depends on these being the same length. + chain.push_back(EncodeCertificate(*it, der)); + } + } } void CefX509CertificateImpl::GetDEREncodedIssuerChain( CefX509Certificate::IssuerChainBinaryList& chain) { + if (der_encoded_issuer_chain_.empty()) + GetEncodedIssuerChain(der_encoded_issuer_chain_, true); chain = der_encoded_issuer_chain_; } void CefX509CertificateImpl::GetPEMEncodedIssuerChain( CefX509Certificate::IssuerChainBinaryList& chain) { + if (pem_encoded_issuer_chain_.empty()) + GetEncodedIssuerChain(pem_encoded_issuer_chain_, false); chain = pem_encoded_issuer_chain_; } diff --git a/libcef/browser/x509_certificate_impl.h b/libcef/browser/x509_certificate_impl.h index 9d0acb9bf..b7dd48391 100644 --- a/libcef/browser/x509_certificate_impl.h +++ b/libcef/browser/x509_certificate_impl.h @@ -13,7 +13,7 @@ // CefX509Certificate implementation class CefX509CertificateImpl : public CefX509Certificate { public: - explicit CefX509CertificateImpl(const net::X509Certificate& value); + explicit CefX509CertificateImpl(scoped_refptr cert); // CefX509Certificate methods. CefRefPtr GetSubject() override; @@ -27,16 +27,14 @@ class CefX509CertificateImpl : public CefX509Certificate { void GetDEREncodedIssuerChain(IssuerChainBinaryList& chain) override; void GetPEMEncodedIssuerChain(IssuerChainBinaryList& chain) override; + scoped_refptr GetInternalCertObject() { return cert_; } + private: - CefRefPtr subject_; - CefRefPtr issuer_; - CefRefPtr serial_number_; - CefTime valid_start_; - CefTime valid_expiry_; - CefRefPtr der_encoded_; - CefRefPtr pem_encoded_; - IssuerChainBinaryList der_encoded_issuer_chain_; + void GetEncodedIssuerChain(IssuerChainBinaryList& chain, bool der); + + scoped_refptr cert_; IssuerChainBinaryList pem_encoded_issuer_chain_; + IssuerChainBinaryList der_encoded_issuer_chain_; IMPLEMENT_REFCOUNTING(CefX509CertificateImpl); DISALLOW_COPY_AND_ASSIGN(CefX509CertificateImpl); diff --git a/libcef_dll/cpptoc/request_handler_cpptoc.cc b/libcef_dll/cpptoc/request_handler_cpptoc.cc index 97e22cc1b..6720527e1 100644 --- a/libcef_dll/cpptoc/request_handler_cpptoc.cc +++ b/libcef_dll/cpptoc/request_handler_cpptoc.cc @@ -20,6 +20,8 @@ #include "libcef_dll/ctocpp/request_callback_ctocpp.h" #include "libcef_dll/ctocpp/response_ctocpp.h" #include "libcef_dll/ctocpp/sslinfo_ctocpp.h" +#include "libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.h" +#include "libcef_dll/ctocpp/x509certificate_ctocpp.h" namespace { @@ -466,6 +468,56 @@ int CEF_CALLBACK request_handler_on_certificate_error( return _retval; } +int CEF_CALLBACK request_handler_on_select_client_certificate( + struct _cef_request_handler_t* self, cef_browser_t* browser, int isProxy, + const cef_string_t* host, int port, size_t certificatesCount, + struct _cef_x509certificate_t* const* certificates, + cef_select_client_certificate_callback_t* callback) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + // Verify param: browser; type: refptr_diff + DCHECK(browser); + if (!browser) + return 0; + // Verify param: host; type: string_byref_const + DCHECK(host); + if (!host) + return 0; + // Verify param: certificates; type: refptr_vec_diff_byref_const + DCHECK(certificatesCount == 0 || certificates); + if (certificatesCount > 0 && !certificates) + return 0; + // Verify param: callback; type: refptr_diff + DCHECK(callback); + if (!callback) + return 0; + + // Translate param: certificates; type: refptr_vec_diff_byref_const + std::vector > certificatesList; + if (certificatesCount > 0) { + for (size_t i = 0; i < certificatesCount; ++i) { + CefRefPtr certificatesVal = + CefX509CertificateCToCpp::Wrap(certificates[i]); + certificatesList.push_back(certificatesVal); + } + } + + // Execute + bool _retval = CefRequestHandlerCppToC::Get(self)->OnSelectClientCertificate( + CefBrowserCToCpp::Wrap(browser), + isProxy?true:false, + CefString(host), + port, + certificatesList, + CefSelectClientCertificateCallbackCToCpp::Wrap(callback)); + + // Return type: bool + return _retval; +} + void CEF_CALLBACK request_handler_on_plugin_crashed( struct _cef_request_handler_t* self, cef_browser_t* browser, const cef_string_t* plugin_path) { @@ -546,6 +598,8 @@ CefRequestHandlerCppToC::CefRequestHandlerCppToC() { GetStruct()->on_quota_request = request_handler_on_quota_request; GetStruct()->on_protocol_execution = request_handler_on_protocol_execution; GetStruct()->on_certificate_error = request_handler_on_certificate_error; + GetStruct()->on_select_client_certificate = + request_handler_on_select_client_certificate; GetStruct()->on_plugin_crashed = request_handler_on_plugin_crashed; GetStruct()->on_render_view_ready = request_handler_on_render_view_ready; GetStruct()->on_render_process_terminated = diff --git a/libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.cc b/libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.cc new file mode 100644 index 000000000..db74f8f1c --- /dev/null +++ b/libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.cc @@ -0,0 +1,63 @@ +// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#include "libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.h" +#include "libcef_dll/cpptoc/x509certificate_cpptoc.h" + + +namespace { + +// MEMBER FUNCTIONS - Body may be edited by hand. + +void CEF_CALLBACK select_client_certificate_callback_select( + struct _cef_select_client_certificate_callback_t* self, + struct _cef_x509certificate_t* cert) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Unverified params: cert + + // Execute + CefSelectClientCertificateCallbackCppToC::Get(self)->Select( + CefX509CertificateCppToC::Unwrap(cert)); +} + +} // namespace + + +// CONSTRUCTOR - Do not edit by hand. + +CefSelectClientCertificateCallbackCppToC::CefSelectClientCertificateCallbackCppToC( + ) { + GetStruct()->select = select_client_certificate_callback_select; +} + +template<> CefRefPtr CefCppToC::UnwrapDerived( + CefWrapperType type, cef_select_client_certificate_callback_t* s) { + NOTREACHED() << "Unexpected class type: " << type; + return NULL; +} + +#if DCHECK_IS_ON() +template<> base::AtomicRefCount CefCppToC::DebugObjCt = 0; +#endif + +template<> CefWrapperType CefCppToC::kWrapperType = + WT_SELECT_CLIENT_CERTIFICATE_CALLBACK; diff --git a/libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.h b/libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.h new file mode 100644 index 000000000..6c7906122 --- /dev/null +++ b/libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.h @@ -0,0 +1,36 @@ +// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#ifndef CEF_LIBCEF_DLL_CPPTOC_SELECT_CLIENT_CERTIFICATE_CALLBACK_CPPTOC_H_ +#define CEF_LIBCEF_DLL_CPPTOC_SELECT_CLIENT_CERTIFICATE_CALLBACK_CPPTOC_H_ +#pragma once + +#ifndef BUILDING_CEF_SHARED +#pragma message("Warning: "__FILE__" may be accessed DLL-side only") +#else // BUILDING_CEF_SHARED + +#include "include/cef_request_handler.h" +#include "include/capi/cef_request_handler_capi.h" +#include "libcef_dll/cpptoc/cpptoc.h" + +// Wrap a C++ class with a C structure. +// This class may be instantiated and accessed DLL-side only. +class CefSelectClientCertificateCallbackCppToC + : public CefCppToC { + public: + CefSelectClientCertificateCallbackCppToC(); +}; + +#endif // BUILDING_CEF_SHARED +#endif // CEF_LIBCEF_DLL_CPPTOC_SELECT_CLIENT_CERTIFICATE_CALLBACK_CPPTOC_H_ diff --git a/libcef_dll/ctocpp/request_handler_ctocpp.cc b/libcef_dll/ctocpp/request_handler_ctocpp.cc index e118fdc74..805daa0fd 100644 --- a/libcef_dll/ctocpp/request_handler_ctocpp.cc +++ b/libcef_dll/ctocpp/request_handler_ctocpp.cc @@ -17,6 +17,8 @@ #include "libcef_dll/cpptoc/request_callback_cpptoc.h" #include "libcef_dll/cpptoc/response_cpptoc.h" #include "libcef_dll/cpptoc/sslinfo_cpptoc.h" +#include "libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.h" +#include "libcef_dll/cpptoc/x509certificate_cpptoc.h" #include "libcef_dll/ctocpp/request_handler_ctocpp.h" #include "libcef_dll/ctocpp/resource_handler_ctocpp.h" #include "libcef_dll/ctocpp/response_filter_ctocpp.h" @@ -451,6 +453,60 @@ bool CefRequestHandlerCToCpp::OnCertificateError(CefRefPtr browser, return _retval?true:false; } +bool CefRequestHandlerCToCpp::OnSelectClientCertificate( + CefRefPtr browser, bool isProxy, const CefString& host, + int port, const CefX509CertificateList& certificates, + CefRefPtr callback) { + cef_request_handler_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, on_select_client_certificate)) + return false; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: browser; type: refptr_diff + DCHECK(browser.get()); + if (!browser.get()) + return false; + // Verify param: host; type: string_byref_const + DCHECK(!host.empty()); + if (host.empty()) + return false; + // Verify param: callback; type: refptr_diff + DCHECK(callback.get()); + if (!callback.get()) + return false; + + // Translate param: certificates; type: refptr_vec_diff_byref_const + const size_t certificatesCount = certificates.size(); + cef_x509certificate_t** certificatesList = NULL; + if (certificatesCount > 0) { + certificatesList = new cef_x509certificate_t*[certificatesCount]; + DCHECK(certificatesList); + if (certificatesList) { + for (size_t i = 0; i < certificatesCount; ++i) { + certificatesList[i] = CefX509CertificateCppToC::Wrap(certificates[i]); + } + } + } + + // Execute + int _retval = _struct->on_select_client_certificate(_struct, + CefBrowserCppToC::Wrap(browser), + isProxy, + host.GetStruct(), + port, + certificatesCount, + certificatesList, + CefSelectClientCertificateCallbackCppToC::Wrap(callback)); + + // Restore param:certificates; type: refptr_vec_diff_byref_const + if (certificatesList) + delete [] certificatesList; + + // Return type: bool + return _retval?true:false; +} + void CefRequestHandlerCToCpp::OnPluginCrashed(CefRefPtr browser, const CefString& plugin_path) { cef_request_handler_t* _struct = GetStruct(); diff --git a/libcef_dll/ctocpp/request_handler_ctocpp.h b/libcef_dll/ctocpp/request_handler_ctocpp.h index 2e8faf04c..326296475 100644 --- a/libcef_dll/ctocpp/request_handler_ctocpp.h +++ b/libcef_dll/ctocpp/request_handler_ctocpp.h @@ -69,6 +69,10 @@ class CefRequestHandlerCToCpp cef_errorcode_t cert_error, const CefString& request_url, CefRefPtr ssl_info, CefRefPtr callback) override; + bool OnSelectClientCertificate(CefRefPtr browser, bool isProxy, + const CefString& host, int port, + const CefX509CertificateList& certificates, + CefRefPtr callback) override; void OnPluginCrashed(CefRefPtr browser, const CefString& plugin_path) override; void OnRenderViewReady(CefRefPtr browser) override; diff --git a/libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.cc b/libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.cc new file mode 100644 index 000000000..320fe3877 --- /dev/null +++ b/libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.cc @@ -0,0 +1,58 @@ +// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#include "libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.h" +#include "libcef_dll/ctocpp/x509certificate_ctocpp.h" + + +// VIRTUAL METHODS - Body may be edited by hand. + +void CefSelectClientCertificateCallbackCToCpp::Select( + CefRefPtr cert) { + cef_select_client_certificate_callback_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, select)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Unverified params: cert + + // Execute + _struct->select(_struct, + CefX509CertificateCToCpp::Unwrap(cert)); +} + + +// CONSTRUCTOR - Do not edit by hand. + +CefSelectClientCertificateCallbackCToCpp::CefSelectClientCertificateCallbackCToCpp( + ) { +} + +template<> cef_select_client_certificate_callback_t* CefCToCpp::UnwrapDerived( + CefWrapperType type, CefSelectClientCertificateCallback* c) { + NOTREACHED() << "Unexpected class type: " << type; + return NULL; +} + +#if DCHECK_IS_ON() +template<> base::AtomicRefCount CefCToCpp::DebugObjCt = 0; +#endif + +template<> CefWrapperType CefCToCpp::kWrapperType = + WT_SELECT_CLIENT_CERTIFICATE_CALLBACK; diff --git a/libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.h b/libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.h new file mode 100644 index 000000000..a5e4c0567 --- /dev/null +++ b/libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.h @@ -0,0 +1,39 @@ +// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#ifndef CEF_LIBCEF_DLL_CTOCPP_SELECT_CLIENT_CERTIFICATE_CALLBACK_CTOCPP_H_ +#define CEF_LIBCEF_DLL_CTOCPP_SELECT_CLIENT_CERTIFICATE_CALLBACK_CTOCPP_H_ +#pragma once + +#ifndef USING_CEF_SHARED +#pragma message("Warning: "__FILE__" may be accessed wrapper-side only") +#else // USING_CEF_SHARED + +#include "include/cef_request_handler.h" +#include "include/capi/cef_request_handler_capi.h" +#include "libcef_dll/ctocpp/ctocpp.h" + +// Wrap a C structure with a C++ class. +// This class may be instantiated and accessed wrapper-side only. +class CefSelectClientCertificateCallbackCToCpp + : public CefCToCpp { + public: + CefSelectClientCertificateCallbackCToCpp(); + + // CefSelectClientCertificateCallback methods. + void Select(CefRefPtr cert) OVERRIDE; +}; + +#endif // USING_CEF_SHARED +#endif // CEF_LIBCEF_DLL_CTOCPP_SELECT_CLIENT_CERTIFICATE_CALLBACK_CTOCPP_H_ diff --git a/libcef_dll/libcef_dll.cc b/libcef_dll/libcef_dll.cc index 2478fc2a9..496c9b067 100644 --- a/libcef_dll/libcef_dll.cc +++ b/libcef_dll/libcef_dll.cc @@ -75,6 +75,7 @@ #include "libcef_dll/cpptoc/sslstatus_cpptoc.h" #include "libcef_dll/cpptoc/scheme_registrar_cpptoc.h" #include "libcef_dll/cpptoc/views/scroll_view_cpptoc.h" +#include "libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.h" #include "libcef_dll/cpptoc/stream_reader_cpptoc.h" #include "libcef_dll/cpptoc/stream_writer_cpptoc.h" #include "libcef_dll/cpptoc/task_runner_cpptoc.h" @@ -310,6 +311,8 @@ CEF_EXPORT void cef_shutdown() { &CefSchemeHandlerFactoryCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefSchemeRegistrarCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefScrollViewCppToC::DebugObjCt)); + DCHECK(base::AtomicRefCountIsZero( + &CefSelectClientCertificateCallbackCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefSetCookieCallbackCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefStreamReaderCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefStreamWriterCppToC::DebugObjCt)); diff --git a/libcef_dll/wrapper/libcef_dll_wrapper.cc b/libcef_dll/wrapper/libcef_dll_wrapper.cc index 189d7f6c8..3a5d30fdf 100644 --- a/libcef_dll/wrapper/libcef_dll_wrapper.cc +++ b/libcef_dll/wrapper/libcef_dll_wrapper.cc @@ -129,6 +129,7 @@ #include "libcef_dll/ctocpp/sslstatus_ctocpp.h" #include "libcef_dll/ctocpp/scheme_registrar_ctocpp.h" #include "libcef_dll/ctocpp/views/scroll_view_ctocpp.h" +#include "libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.h" #include "libcef_dll/ctocpp/stream_reader_ctocpp.h" #include "libcef_dll/ctocpp/stream_writer_ctocpp.h" #include "libcef_dll/ctocpp/task_runner_ctocpp.h" @@ -302,6 +303,8 @@ CEF_GLOBAL void CefShutdown() { &CefSchemeHandlerFactoryCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefSchemeRegistrarCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefScrollViewCToCpp::DebugObjCt)); + DCHECK(base::AtomicRefCountIsZero( + &CefSelectClientCertificateCallbackCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefSetCookieCallbackCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefStreamReaderCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefStreamWriterCToCpp::DebugObjCt)); diff --git a/libcef_dll/wrapper_types.h b/libcef_dll/wrapper_types.h index 12531300e..ac7de8e77 100644 --- a/libcef_dll/wrapper_types.h +++ b/libcef_dll/wrapper_types.h @@ -106,6 +106,7 @@ enum CefWrapperType { WT_SCHEME_HANDLER_FACTORY, WT_SCHEME_REGISTRAR, WT_SCROLL_VIEW, + WT_SELECT_CLIENT_CERTIFICATE_CALLBACK, WT_SET_COOKIE_CALLBACK, WT_STREAM_READER, WT_STREAM_WRITER, diff --git a/tests/cefclient/browser/client_handler.cc b/tests/cefclient/browser/client_handler.cc index dfa2698eb..75ccb8d53 100644 --- a/tests/cefclient/browser/client_handler.cc +++ b/tests/cefclient/browser/client_handler.cc @@ -700,6 +700,42 @@ bool ClientHandler::OnCertificateError( return false; // Cancel the request. } +bool ClientHandler::OnSelectClientCertificate( + CefRefPtr browser, + bool isProxy, + const CefString& host, + int port, + const CefX509CertificateList& certificates, + CefRefPtr callback) { + CEF_REQUIRE_UI_THREAD(); + + CefRefPtr command_line = + CefCommandLine::GetGlobalCommandLine(); + if (!command_line->HasSwitch(switches::kSslClientCertificate)) { + return false; + } + + const std::string& cert_name = + command_line->GetSwitchValue(switches::kSslClientCertificate); + + if (cert_name.empty()) { + callback->Select(NULL); + return true; + } + + std::vector >::const_iterator it = + certificates.begin(); + for (; it != certificates.end(); ++it) { + CefString subject((*it)->GetSubject()->GetDisplayName()); + if (subject == cert_name) { + callback->Select(*it); + return true; + } + } + + return true; +} + void ClientHandler::OnRenderProcessTerminated(CefRefPtr browser, TerminationStatus status) { CEF_REQUIRE_UI_THREAD(); diff --git a/tests/cefclient/browser/client_handler.h b/tests/cefclient/browser/client_handler.h index cfdce0912..0b013b8e9 100644 --- a/tests/cefclient/browser/client_handler.h +++ b/tests/cefclient/browser/client_handler.h @@ -252,6 +252,13 @@ class ClientHandler : public CefClient, const CefString& request_url, CefRefPtr ssl_info, CefRefPtr callback) OVERRIDE; + bool OnSelectClientCertificate( + CefRefPtr browser, + bool isProxy, + const CefString& host, + int port, + const CefX509CertificateList& certificates, + CefRefPtr callback) OVERRIDE; void OnRenderProcessTerminated(CefRefPtr browser, TerminationStatus status) OVERRIDE; diff --git a/tests/cefclient/common/client_switches.cc b/tests/cefclient/common/client_switches.cc index 310ded20e..7239ae8b0 100644 --- a/tests/cefclient/common/client_switches.cc +++ b/tests/cefclient/common/client_switches.cc @@ -35,6 +35,7 @@ const char kUseViews[] = "use-views"; const char kHideFrame[] = "hide-frame"; const char kHideControls[] = "hide-controls"; const char kWidevineCdmPath[] = "widevine-cdm-path"; +const char kSslClientCertificate[] = "ssl-client-certificate"; } // namespace switches } // namespace client diff --git a/tests/cefclient/common/client_switches.h b/tests/cefclient/common/client_switches.h index 1cdad730e..6d5637301 100644 --- a/tests/cefclient/common/client_switches.h +++ b/tests/cefclient/common/client_switches.h @@ -29,6 +29,7 @@ extern const char kUseViews[]; extern const char kHideFrame[]; extern const char kHideControls[]; extern const char kWidevineCdmPath[]; +extern const char kSslClientCertificate[]; } // namespace switches } // namespace client