Index: net/socket/ssl_client_socket_openssl.cc |
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc |
index a6f5caf188d96dac7c1a339e732990cb05ebd6f3..cb491f5a94b755c15426542d36ab4714bdb5c30a 100644 |
--- a/net/socket/ssl_client_socket_openssl.cc |
+++ b/net/socket/ssl_client_socket_openssl.cc |
@@ -57,7 +57,13 @@ const int kNoPendingReadResult = 1; |
// the server supports NPN, choosing "http/1.1" is the best answer. |
const char kDefaultSupportedNPNProtocol[] = "http/1.1"; |
+void FreeX509Stack(STACK_OF(X509)* ptr) { |
+ sk_X509_pop_free(ptr, X509_free); |
+} |
+ |
typedef crypto::ScopedOpenSSL<X509, X509_free>::Type ScopedX509; |
+typedef crypto::ScopedOpenSSL<STACK_OF(X509), FreeX509Stack>::Type |
+ ScopedX509Stack; |
#if OPENSSL_VERSION_NUMBER < 0x1000103fL |
// This method doesn't seem to have made it into the OpenSSL headers. |
@@ -95,10 +101,6 @@ int GetNetSSLVersion(SSL* ssl) { |
} |
} |
-void FreeX509Stack(STACK_OF(X509) * ptr) { |
- sk_X509_pop_free(ptr, X509_free); |
-} |
- |
ScopedX509 OSCertHandleToOpenSSL( |
X509Certificate::OSCertHandle os_handle) { |
#if defined(USE_OPENSSL_CERTS) |
@@ -112,6 +114,18 @@ ScopedX509 OSCertHandleToOpenSSL( |
#endif // defined(USE_OPENSSL_CERTS) |
} |
+ScopedX509Stack OSCertHandlesToOpenSSL( |
+ const X509Certificate::OSCertHandles& os_handles) { |
+ ScopedX509Stack stack(sk_X509_new_null()); |
+ for (size_t i = 0; i < os_handles.size(); i++) { |
+ ScopedX509 x509 = OSCertHandleToOpenSSL(os_handles[i]); |
+ if (!x509) |
+ return ScopedX509Stack(); |
+ sk_X509_push(stack.get(), x509.release()); |
+ } |
+ return stack.Pass(); |
+} |
+ |
} // namespace |
class SSLClientSocketOpenSSL::SSLContext { |
@@ -142,7 +156,7 @@ class SSLClientSocketOpenSSL::SSLContext { |
ssl_ctx_.reset(SSL_CTX_new(SSLv23_client_method())); |
session_cache_.Reset(ssl_ctx_.get(), kDefaultSessionCacheConfig); |
SSL_CTX_set_cert_verify_callback(ssl_ctx_.get(), CertVerifyCallback, NULL); |
- SSL_CTX_set_client_cert_cb(ssl_ctx_.get(), ClientCertCallback); |
+ SSL_CTX_set_cert_cb(ssl_ctx_.get(), ClientCertRequestCallback, NULL); |
SSL_CTX_set_verify(ssl_ctx_.get(), SSL_VERIFY_PEER, NULL); |
// TODO(kristianm): Only select this if ssl_config_.next_proto is not empty. |
// It would be better if the callback were not a global setting, |
@@ -160,10 +174,10 @@ class SSLClientSocketOpenSSL::SSLContext { |
static SSLSessionCacheOpenSSL::Config kDefaultSessionCacheConfig; |
- static int ClientCertCallback(SSL* ssl, X509** x509, EVP_PKEY** pkey) { |
+ static int ClientCertRequestCallback(SSL* ssl, void* arg) { |
SSLClientSocketOpenSSL* socket = GetInstance()->GetClientSocketFromSSL(ssl); |
CHECK(socket); |
agl
2014/08/14 17:06:46
could probably be a DCHECK.
davidben
2014/08/14 17:50:07
Done. (*shrug* I suppose it'd crash immediately af
|
- return socket->ClientCertRequestCallback(ssl, x509, pkey); |
+ return socket->ClientCertRequestCallback(ssl); |
} |
static int CertVerifyCallback(X509_STORE_CTX *store_ctx, void *arg) { |
@@ -226,9 +240,6 @@ class SSLClientSocketOpenSSL::PeerCertificateChain { |
bool IsValid() { return os_chain_.get() && openssl_chain_.get(); } |
private: |
- typedef crypto::ScopedOpenSSL<STACK_OF(X509), FreeX509Stack>::Type |
- ScopedX509Stack; |
- |
ScopedX509Stack openssl_chain_; |
scoped_refptr<X509Certificate> os_chain_; |
@@ -1395,13 +1406,12 @@ int SSLClientSocketOpenSSL::TransportReadComplete(int result) { |
return result; |
} |
-int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl, |
- X509** x509, |
- EVP_PKEY** pkey) { |
+int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl) { |
DVLOG(3) << "OpenSSL ClientCertRequestCallback called"; |
DCHECK(ssl == ssl_); |
- DCHECK(*x509 == NULL); |
- DCHECK(*pkey == NULL); |
+ |
+ // Clear any currently configured certificates. |
+ SSL_certs_clear(ssl_); |
#if defined(OS_IOS) |
// TODO(droger): Support client auth on iOS. See http://crbug.com/145954). |
@@ -1435,7 +1445,6 @@ int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl, |
// Second pass: a client certificate should have been selected. |
if (ssl_config_.client_cert.get()) { |
- // TODO(davidben): Configure OpenSSL to also send the intermediates. |
ScopedX509 leaf_x509 = |
OSCertHandleToOpenSSL(ssl_config_.client_cert->os_cert_handle()); |
if (!leaf_x509) { |
@@ -1444,6 +1453,14 @@ int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl, |
return -1; |
} |
+ ScopedX509Stack chain = OSCertHandlesToOpenSSL( |
+ ssl_config_.client_cert->GetIntermediateCertificates()); |
+ if (!chain) { |
+ LOG(WARNING) << "Failed to import intermediate certificates"; |
+ OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_CERT_BAD_FORMAT); |
+ return -1; |
+ } |
+ |
// TODO(davidben): With Linux client auth support, this should be |
// conditioned on OS_ANDROID and then, with https://crbug.com/394131, |
// removed altogether. OpenSSLClientKeyStore is mostly an artifact of the |
@@ -1464,16 +1481,18 @@ int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl, |
return -1; |
} |
- // TODO(joth): (copied from NSS) We should wait for server certificate |
- // verification before sending our credentials. See http://crbug.com/13934 |
- *x509 = leaf_x509.release(); |
- *pkey = privkey.release(); |
+ if (!SSL_use_certificate(ssl_, leaf_x509.get()) || |
+ !SSL_use_PrivateKey(ssl_, privkey.get()) || |
+ !SSL_set1_chain(ssl_, chain.get())) { |
+ LOG(WARNING) << "Failed to set client certificate"; |
+ return -1; |
+ } |
return 1; |
} |
#endif // defined(OS_IOS) |
// Send no client certificate. |
- return 0; |
+ return 1; |
} |
int SSLClientSocketOpenSSL::CertVerifyCallback(X509_STORE_CTX* store_ctx) { |