Add callback for custom certificate selection (issue #1824)

This commit is contained in:
Marshall Greenblatt
2016-10-27 13:57:12 -04:00
parent e006ec0ab5
commit 676cb1f07d
23 changed files with 613 additions and 67 deletions

View File

@@ -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<content::ClientCertificateDelegate> 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<CefX509Certificate> cert) override {
if (delegate_)
DoSelect(cert);
}
private:
void DoSelect(CefRefPtr<CefX509Certificate> 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<content::ClientCertificateDelegate> delegate,
CefRefPtr<CefX509Certificate> cert) {
CEF_REQUIRE_UIT();
scoped_refptr<net::X509Certificate> x509cert = NULL;
if (cert) {
CefX509CertificateImpl* certImpl =
static_cast<CefX509CertificateImpl*>(cert.get());
x509cert = certImpl->GetInternalCertObject();
}
delegate->ContinueWithCertificate(x509cert.get());
}
std::unique_ptr<content::ClientCertificateDelegate> 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<content::ClientCertificateDelegate> 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<CefRequestHandler> handler;
CefRefPtr<CefBrowserHostImpl> browser =
CefBrowserHostImpl::GetBrowserForContents(web_contents);
if (browser.get()) {
CefRefPtr<CefClient> client = browser->GetClient();
if (client.get())
handler = client->GetRequestHandler();
}
if (!handler.get()) {
delegate->ContinueWithCertificate(NULL);
return;
}
CefX509CertificateList certs;
for (std::vector<scoped_refptr<net::X509Certificate> >::iterator iter =
cert_request_info->client_certs.begin();
iter != cert_request_info->client_certs.end(); iter++) {
certs.push_back(new CefX509CertificateImpl(*iter));
}
CefRefPtr<CefSelectClientCertificateCallbackImpl> 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]);
}
}

View File

@@ -11,7 +11,7 @@ CefSSLInfoImpl::CefSSLInfoImpl(const net::SSLInfo& value)
: cert_status_(CERT_STATUS_NONE) {
cert_status_ = static_cast<cef_cert_status_t>(value.cert_status);
if (value.cert.get()) {
cert_ = new CefX509CertificateImpl(*value.cert);
cert_ = new CefX509CertificateImpl(value.cert);
}
}

View File

@@ -34,6 +34,6 @@ cef_ssl_content_status_t CefSSLStatusImpl::GetContentStatus() {
CefRefPtr<CefX509Certificate> CefSSLStatusImpl::GetX509Certificate() {
if (certificate_ && !cef_certificate_)
cef_certificate_ = new CefX509CertificateImpl(*certificate_);
cef_certificate_ = new CefX509CertificateImpl(certificate_);
return cef_certificate_;
}

View File

@@ -8,97 +8,115 @@
namespace {
void EncodeCertificate(
const net::X509Certificate::OSCertHandle& os_handle,
CefRefPtr<CefBinaryValue>& der_encoded,
CefRefPtr<CefBinaryValue>& pem_encoded) {
CefRefPtr<CefBinaryValue> EncodeCertificate(
const net::X509Certificate::OSCertHandle& os_handle, bool der) {
CefRefPtr<CefBinaryValue> 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<CefBinaryValue> 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<net::X509Certificate> cert)
:cert_(cert) {
}
CefRefPtr<CefX509CertPrincipal> CefX509CertificateImpl::GetSubject() {
return subject_;
if (cert_)
return new CefX509CertPrincipalImpl(cert_->subject());
return nullptr;
}
CefRefPtr<CefX509CertPrincipal> CefX509CertificateImpl::GetIssuer() {
return issuer_;
if (cert_)
return new CefX509CertPrincipalImpl(cert_->issuer());
return nullptr;
}
CefRefPtr<CefBinaryValue> 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<CefBinaryValue> 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<CefBinaryValue> 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_;
}

View File

@@ -13,7 +13,7 @@
// CefX509Certificate implementation
class CefX509CertificateImpl : public CefX509Certificate {
public:
explicit CefX509CertificateImpl(const net::X509Certificate& value);
explicit CefX509CertificateImpl(scoped_refptr<net::X509Certificate> cert);
// CefX509Certificate methods.
CefRefPtr<CefX509CertPrincipal> GetSubject() override;
@@ -27,16 +27,14 @@ class CefX509CertificateImpl : public CefX509Certificate {
void GetDEREncodedIssuerChain(IssuerChainBinaryList& chain) override;
void GetPEMEncodedIssuerChain(IssuerChainBinaryList& chain) override;
scoped_refptr<net::X509Certificate> GetInternalCertObject() { return cert_; }
private:
CefRefPtr<CefX509CertPrincipal> subject_;
CefRefPtr<CefX509CertPrincipal> issuer_;
CefRefPtr<CefBinaryValue> serial_number_;
CefTime valid_start_;
CefTime valid_expiry_;
CefRefPtr<CefBinaryValue> der_encoded_;
CefRefPtr<CefBinaryValue> pem_encoded_;
IssuerChainBinaryList der_encoded_issuer_chain_;
void GetEncodedIssuerChain(IssuerChainBinaryList& chain, bool der);
scoped_refptr<net::X509Certificate> cert_;
IssuerChainBinaryList pem_encoded_issuer_chain_;
IssuerChainBinaryList der_encoded_issuer_chain_;
IMPLEMENT_REFCOUNTING(CefX509CertificateImpl);
DISALLOW_COPY_AND_ASSIGN(CefX509CertificateImpl);