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 4ff8d438e965b1fdf0b5b7f8b4ecdb75e1d14d66..68d7e5f50d0ec4469b0d44195c60efa275078e25 100644 |
--- a/net/socket/ssl_client_socket_openssl.cc |
+++ b/net/socket/ssl_client_socket_openssl.cc |
@@ -127,7 +127,6 @@ class SSLClientSocketOpenSSL::SSLContext { |
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_channel_id_cb(ssl_ctx_.get(), ChannelIDCallback); |
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, |
@@ -150,12 +149,6 @@ class SSLClientSocketOpenSSL::SSLContext { |
return socket->ClientCertRequestCallback(ssl, x509, pkey); |
} |
- static void ChannelIDCallback(SSL* ssl, EVP_PKEY** pkey) { |
- SSLClientSocketOpenSSL* socket = GetInstance()->GetClientSocketFromSSL(ssl); |
- CHECK(socket); |
- socket->ChannelIDRequestCallback(ssl, pkey); |
- } |
- |
static int CertVerifyCallback(X509_STORE_CTX *store_ctx, void *arg) { |
SSL* ssl = reinterpret_cast<SSL*>(X509_STORE_CTX_get_ex_data( |
store_ctx, SSL_get_ex_data_X509_STORE_CTX_idx())); |
@@ -358,7 +351,6 @@ SSLClientSocketOpenSSL::SSLClientSocketOpenSSL( |
trying_cached_session_(false), |
next_handshake_state_(STATE_NONE), |
npn_status_(kNextProtoUnsupported), |
- channel_id_request_return_value_(ERR_UNEXPECTED), |
channel_id_xtn_negotiated_(false), |
net_log_(transport_->socket()->NetLog()) {} |
@@ -476,6 +468,9 @@ void SSLClientSocketOpenSSL::Disconnect() { |
cert_authorities_.clear(); |
cert_key_types_.clear(); |
client_auth_cert_needed_ = false; |
+ |
+ channel_id_xtn_negotiated_ = false; |
+ channel_id_request_handle_.Cancel(); |
} |
bool SSLClientSocketOpenSSL::IsConnected() const { |
@@ -827,13 +822,15 @@ int SSLClientSocketOpenSSL::DoHandshake() { |
int ssl_error = SSL_get_error(ssl_, rv); |
if (ssl_error == SSL_ERROR_WANT_CHANNEL_ID_LOOKUP) { |
- // The server supports TLS channel id and the lookup is asynchronous. |
- // Retrieve the error from the call to |server_bound_cert_service_|. |
- net_error = channel_id_request_return_value_; |
- } else { |
- net_error = MapOpenSSLError(ssl_error, err_tracer); |
+ // The server supports channel ID. Stop to look one up before returning to |
+ // the handshake. |
+ channel_id_xtn_negotiated_ = true; |
+ GotoState(STATE_CHANNEL_ID_LOOKUP); |
+ return OK; |
} |
+ net_error = MapOpenSSLError(ssl_error, err_tracer); |
+ |
// If not done, stay in this state |
if (net_error == ERR_IO_PENDING) { |
GotoState(STATE_HANDSHAKE); |
@@ -849,6 +846,57 @@ int SSLClientSocketOpenSSL::DoHandshake() { |
return net_error; |
} |
+int SSLClientSocketOpenSSL::DoChannelIDLookup() { |
+ GotoState(STATE_CHANNEL_ID_LOOKUP_COMPLETE); |
+ return server_bound_cert_service_->GetOrCreateDomainBoundCert( |
+ host_and_port_.host(), |
+ &channel_id_private_key_, |
+ &channel_id_cert_, |
+ base::Bind(&SSLClientSocketOpenSSL::OnHandshakeIOComplete, |
+ base::Unretained(this)), |
+ &channel_id_request_handle_); |
+} |
+ |
+int SSLClientSocketOpenSSL::DoChannelIDLookupComplete(int result) { |
+ if (result < 0) |
+ return result; |
+ |
+ DCHECK_LT(0u, channel_id_private_key_.size()); |
+ // Decode key. |
+ std::vector<uint8> encrypted_private_key_info; |
+ std::vector<uint8> subject_public_key_info; |
+ encrypted_private_key_info.assign( |
+ channel_id_private_key_.data(), |
+ channel_id_private_key_.data() + channel_id_private_key_.size()); |
+ subject_public_key_info.assign( |
+ channel_id_cert_.data(), |
+ channel_id_cert_.data() + channel_id_cert_.size()); |
+ scoped_ptr<crypto::ECPrivateKey> ec_private_key( |
+ crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( |
+ ServerBoundCertService::kEPKIPassword, |
+ encrypted_private_key_info, |
+ subject_public_key_info)); |
+ if (!ec_private_key) { |
+ LOG(ERROR) << "Failed to import Channel ID."; |
+ return ERR_CHANNEL_ID_IMPORT_FAILED; |
+ } |
+ |
+ // Hand the key to OpenSSL. Check for error in case OpenSSL rejects the key |
+ // type. |
+ crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); |
+ int rv = SSL_set1_tls_channel_id(ssl_, ec_private_key->key()); |
+ if (!rv) { |
+ LOG(ERROR) << "Failed to set Channel ID."; |
+ int err = SSL_get_error(ssl_, rv); |
+ return MapOpenSSLError(err, err_tracer); |
+ } |
+ |
+ // Return to the handshake. |
+ set_channel_id_sent(true); |
+ GotoState(STATE_HANDSHAKE); |
+ return OK; |
+} |
+ |
int SSLClientSocketOpenSSL::DoVerifyCert(int result) { |
DCHECK(server_cert_.get()); |
GotoState(STATE_VERIFY_CERT_COMPLETE); |
@@ -993,8 +1041,15 @@ int SSLClientSocketOpenSSL::DoHandshakeLoop(int last_io_result) { |
case STATE_HANDSHAKE: |
rv = DoHandshake(); |
break; |
+ case STATE_CHANNEL_ID_LOOKUP: |
+ DCHECK_EQ(OK, rv); |
+ rv = DoChannelIDLookup(); |
+ break; |
+ case STATE_CHANNEL_ID_LOOKUP_COMPLETE: |
+ rv = DoChannelIDLookupComplete(rv); |
+ break; |
case STATE_VERIFY_CERT: |
- DCHECK(rv == OK); |
+ DCHECK_EQ(OK, rv); |
rv = DoVerifyCert(rv); |
break; |
case STATE_VERIFY_CERT_COMPLETE: |
@@ -1321,46 +1376,6 @@ int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl, |
return 0; |
} |
-void SSLClientSocketOpenSSL::ChannelIDRequestCallback(SSL* ssl, |
- EVP_PKEY** pkey) { |
- DVLOG(3) << "OpenSSL ChannelIDRequestCallback called"; |
- DCHECK_EQ(ssl, ssl_); |
- DCHECK(!*pkey); |
- |
- channel_id_xtn_negotiated_ = true; |
- if (!channel_id_private_key_.size()) { |
- channel_id_request_return_value_ = |
- server_bound_cert_service_->GetOrCreateDomainBoundCert( |
- host_and_port_.host(), |
- &channel_id_private_key_, |
- &channel_id_cert_, |
- base::Bind(&SSLClientSocketOpenSSL::OnHandshakeIOComplete, |
- base::Unretained(this)), |
- &channel_id_request_handle_); |
- if (channel_id_request_return_value_ != OK) |
- return; |
- } |
- |
- // Decode key. |
- std::vector<uint8> encrypted_private_key_info; |
- std::vector<uint8> subject_public_key_info; |
- encrypted_private_key_info.assign( |
- channel_id_private_key_.data(), |
- channel_id_private_key_.data() + channel_id_private_key_.size()); |
- subject_public_key_info.assign( |
- channel_id_cert_.data(), |
- channel_id_cert_.data() + channel_id_cert_.size()); |
- scoped_ptr<crypto::ECPrivateKey> ec_private_key( |
- crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo( |
- ServerBoundCertService::kEPKIPassword, |
- encrypted_private_key_info, |
- subject_public_key_info)); |
- if (!ec_private_key) |
- return; |
- set_channel_id_sent(true); |
- *pkey = EVP_PKEY_dup(ec_private_key->key()); |
-} |
- |
int SSLClientSocketOpenSSL::CertVerifyCallback(X509_STORE_CTX* store_ctx) { |
if (!completed_handshake_) { |
// If the first handshake hasn't completed then we accept any certificates |