Commit 6bad505f authored by davidben@chromium.org's avatar davidben@chromium.org

Pass the client certificate into OpenSSL in common code.

The private key's the hard one, but this is a first step
and can be independent of USE_OPENSSL_CERTS.

BUG=362035

Review URL: https://codereview.chromium.org/383003002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@282770 0039d316-1c4b-4281-b951-d872f2087c98
parent 6195ca10
...@@ -332,6 +332,10 @@ NET_ERROR(SOCKET_RECEIVE_BUFFER_SIZE_UNCHANGEABLE, -162) ...@@ -332,6 +332,10 @@ NET_ERROR(SOCKET_RECEIVE_BUFFER_SIZE_UNCHANGEABLE, -162)
// return code from setsockopt. // return code from setsockopt.
NET_ERROR(SOCKET_SEND_BUFFER_SIZE_UNCHANGEABLE, -163) NET_ERROR(SOCKET_SEND_BUFFER_SIZE_UNCHANGEABLE, -163)
// Failed to import a client certificate from the platform store into the SSL
// library.
NET_ERROR(SSL_CLIENT_AUTH_CERT_BAD_FORMAT, -164)
// Certificate error codes // Certificate error codes
// //
// The values of certificate error codes must be consecutive. // The values of certificate error codes must be consecutive.
......
...@@ -52,6 +52,8 @@ const int kNoPendingReadResult = 1; ...@@ -52,6 +52,8 @@ const int kNoPendingReadResult = 1;
// the server supports NPN, choosing "http/1.1" is the best answer. // the server supports NPN, choosing "http/1.1" is the best answer.
const char kDefaultSupportedNPNProtocol[] = "http/1.1"; const char kDefaultSupportedNPNProtocol[] = "http/1.1";
typedef crypto::ScopedOpenSSL<X509, X509_free>::Type ScopedX509;
#if OPENSSL_VERSION_NUMBER < 0x1000103fL #if OPENSSL_VERSION_NUMBER < 0x1000103fL
// This method doesn't seem to have made it into the OpenSSL headers. // This method doesn't seem to have made it into the OpenSSL headers.
unsigned long SSL_CIPHER_get_id(const SSL_CIPHER* cipher) { return cipher->id; } unsigned long SSL_CIPHER_get_id(const SSL_CIPHER* cipher) { return cipher->id; }
...@@ -97,10 +99,23 @@ std::string GetSocketSessionCacheKey(const SSLClientSocketOpenSSL& socket) { ...@@ -97,10 +99,23 @@ std::string GetSocketSessionCacheKey(const SSLClientSocketOpenSSL& socket) {
return result; return result;
} }
static void FreeX509Stack(STACK_OF(X509) * ptr) { void FreeX509Stack(STACK_OF(X509) * ptr) {
sk_X509_pop_free(ptr, X509_free); sk_X509_pop_free(ptr, X509_free);
} }
ScopedX509 OSCertHandleToOpenSSL(
X509Certificate::OSCertHandle os_handle) {
#if defined(USE_OPENSSL_CERTS)
return ScopedX509(X509Certificate::DupOSCertHandle(os_handle));
#else // !defined(USE_OPENSSL_CERTS)
std::string der_encoded;
if (!X509Certificate::GetDEREncoded(os_handle, &der_encoded))
return ScopedX509();
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(der_encoded.data());
return ScopedX509(d2i_X509(NULL, &bytes, der_encoded.size()));
#endif // defined(USE_OPENSSL_CERTS)
}
} // namespace } // namespace
class SSLClientSocketOpenSSL::SSLContext { class SSLClientSocketOpenSSL::SSLContext {
...@@ -1349,31 +1364,40 @@ int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl, ...@@ -1349,31 +1364,40 @@ int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl,
// Second pass: a client certificate should have been selected. // Second pass: a client certificate should have been selected.
if (ssl_config_.client_cert.get()) { 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) {
LOG(WARNING) << "Failed to import certificate";
OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_CERT_BAD_FORMAT);
return -1;
}
crypto::ScopedEVP_PKEY privkey;
#if defined(USE_OPENSSL_CERTS) #if defined(USE_OPENSSL_CERTS)
// A note about ownership: FetchClientCertPrivateKey() increments // A note about ownership: FetchClientCertPrivateKey() increments
// the reference count of the EVP_PKEY. Ownership of this reference // the reference count of the EVP_PKEY. Ownership of this reference
// is passed directly to OpenSSL, which will release the reference // is passed directly to OpenSSL, which will release the reference
// using EVP_PKEY_free() when the SSL object is destroyed. // using EVP_PKEY_free() when the SSL object is destroyed.
crypto::ScopedEVP_PKEY privkey; if (!OpenSSLClientKeyStore::GetInstance()->FetchClientCertPrivateKey(
if (OpenSSLClientKeyStore::GetInstance()->FetchClientCertPrivateKey(
ssl_config_.client_cert.get(), &privkey)) { ssl_config_.client_cert.get(), &privkey)) {
// TODO(joth): (copied from NSS) We should wait for server certificate // Could not find the private key. Fail the handshake and surface an
// verification before sending our credentials. See http://crbug.com/13934 // appropriate error to the caller.
*x509 = X509Certificate::DupOSCertHandle( LOG(WARNING) << "Client cert found without private key";
ssl_config_.client_cert->os_cert_handle()); OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY);
*pkey = privkey.release(); return -1;
return 1;
} }
// Could not find the private key. Fail the handshake and surface an
// appropriate error to the caller.
LOG(WARNING) << "Client cert found without private key";
OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY);
return -1;
#else // !defined(USE_OPENSSL_CERTS) #else // !defined(USE_OPENSSL_CERTS)
// OS handling of client certificates is not yet implemented. // OS handling of private keys is not yet implemented.
NOTIMPLEMENTED(); NOTIMPLEMENTED();
return 0;
#endif // defined(USE_OPENSSL_CERTS) #endif // defined(USE_OPENSSL_CERTS)
// 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();
return 1;
} }
// Send no client certificate. // Send no client certificate.
......
...@@ -42528,6 +42528,7 @@ Therefore, the affected-histogram name has to have at least one dot in it. ...@@ -42528,6 +42528,7 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="161" label="SOCKET_SET_SEND_BUFFER_SIZE_ERROR"/> <int value="161" label="SOCKET_SET_SEND_BUFFER_SIZE_ERROR"/>
<int value="162" label="SOCKET_RECEIVE_BUFFER_SIZE_UNCHANGEABLE"/> <int value="162" label="SOCKET_RECEIVE_BUFFER_SIZE_UNCHANGEABLE"/>
<int value="163" label="SOCKET_SEND_BUFFER_SIZE_UNCHANGEABLE"/> <int value="163" label="SOCKET_SEND_BUFFER_SIZE_UNCHANGEABLE"/>
<int value="164" label="SSL_CLIENT_AUTH_CERT_BAD_FORMAT"/>
<int value="200" label="CERT_COMMON_NAME_INVALID"/> <int value="200" label="CERT_COMMON_NAME_INVALID"/>
<int value="201" label="CERT_DATE_INVALID"/> <int value="201" label="CERT_DATE_INVALID"/>
<int value="202" label="CERT_AUTHORITY_INVALID"/> <int value="202" label="CERT_AUTHORITY_INVALID"/>
...@@ -42602,6 +42603,7 @@ Therefore, the affected-histogram name has to have at least one dot in it. ...@@ -42602,6 +42603,7 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="406" label="CACHE_RACE"/> <int value="406" label="CACHE_RACE"/>
<int value="407" label="CACHE_CHECKSUM_READ_FAILURE"/> <int value="407" label="CACHE_CHECKSUM_READ_FAILURE"/>
<int value="408" label="CACHE_CHECKSUM_MISMATCH"/> <int value="408" label="CACHE_CHECKSUM_MISMATCH"/>
<int value="409" label="CACHE_LOCK_TIMEOUT"/>
<int value="501" label="INSECURE_RESPONSE"/> <int value="501" label="INSECURE_RESPONSE"/>
<int value="502" label="NO_PRIVATE_KEY_FOR_CERT"/> <int value="502" label="NO_PRIVATE_KEY_FOR_CERT"/>
<int value="503" label="ADD_USER_CERT_FAILED"/> <int value="503" label="ADD_USER_CERT_FAILED"/>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment