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)
// return code from setsockopt.
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
//
// The values of certificate error codes must be consecutive.
......
......@@ -52,6 +52,8 @@ const int kNoPendingReadResult = 1;
// the server supports NPN, choosing "http/1.1" is the best answer.
const char kDefaultSupportedNPNProtocol[] = "http/1.1";
typedef crypto::ScopedOpenSSL<X509, X509_free>::Type ScopedX509;
#if OPENSSL_VERSION_NUMBER < 0x1000103fL
// 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; }
......@@ -97,10 +99,23 @@ std::string GetSocketSessionCacheKey(const SSLClientSocketOpenSSL& socket) {
return result;
}
static void FreeX509Stack(STACK_OF(X509) * ptr) {
void FreeX509Stack(STACK_OF(X509) * ptr) {
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
class SSLClientSocketOpenSSL::SSLContext {
......@@ -1349,31 +1364,40 @@ 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) {
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)
// A note about ownership: FetchClientCertPrivateKey() increments
// the reference count of the EVP_PKEY. Ownership of this reference
// is passed directly to OpenSSL, which will release the reference
// 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)) {
// TODO(joth): (copied from NSS) We should wait for server certificate
// verification before sending our credentials. See http://crbug.com/13934
*x509 = X509Certificate::DupOSCertHandle(
ssl_config_.client_cert->os_cert_handle());
*pkey = privkey.release();
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;
}
// 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)
// OS handling of client certificates is not yet implemented.
// OS handling of private keys is not yet implemented.
NOTIMPLEMENTED();
return 0;
#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.
......
......@@ -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="162" label="SOCKET_RECEIVE_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="201" label="CERT_DATE_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.
<int value="406" label="CACHE_RACE"/>
<int value="407" label="CACHE_CHECKSUM_READ_FAILURE"/>
<int value="408" label="CACHE_CHECKSUM_MISMATCH"/>
<int value="409" label="CACHE_LOCK_TIMEOUT"/>
<int value="501" label="INSECURE_RESPONSE"/>
<int value="502" label="NO_PRIVATE_KEY_FOR_CERT"/>
<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