Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // OpenSSL binding for SSLClientSocket. The class layout and general principle | 5 // OpenSSL binding for SSLClientSocket. The class layout and general principle |
| 6 // of operation is derived from SSLClientSocketNSS. | 6 // of operation is derived from SSLClientSocketNSS. |
| 7 | 7 |
| 8 #include "net/socket/ssl_client_socket_openssl.h" | 8 #include "net/socket/ssl_client_socket_openssl.h" |
| 9 | 9 |
| 10 #include <openssl/ssl.h> | 10 #include <openssl/ssl.h> |
| 11 #include <openssl/err.h> | 11 #include <openssl/err.h> |
| 12 | 12 |
| 13 #include "base/lock.h" | 13 #include "base/lock.h" |
| 14 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
| 15 #include "base/openssl_util.h" | 15 #include "base/openssl_util.h" |
| 16 #include "base/singleton.h" | 16 #include "base/singleton.h" |
| 17 #include "net/base/cert_verifier.h" | 17 #include "net/base/cert_verifier.h" |
| 18 #include "net/base/net_errors.h" | 18 #include "net/base/net_errors.h" |
| 19 #include "net/base/ssl_cert_request_info.h" | 19 #include "net/base/ssl_cert_request_info.h" |
| 20 #include "net/base/ssl_connection_status_flags.h" | 20 #include "net/base/ssl_connection_status_flags.h" |
| 21 #include "net/base/ssl_info.h" | 21 #include "net/base/ssl_info.h" |
| 22 // TODO(willchan): Fix this dependency. It's ugly for net/socket to depend on | |
| 23 // net/http. | |
|
joth
2010/12/02 17:46:55
overlength line
Kristian_
2010/12/03 14:58:56
Done.
| |
| 24 #include "net/http/http_stream_factory.h" | |
|
joth
2010/12/02 17:46:55
Istead of doing this please see if we can use SSLC
willchan no longer on Chromium
2010/12/03 01:35:06
Agreed, this is preferable, primarily in terms of
Kristian_
2010/12/03 14:58:56
Done
| |
| 22 | 25 |
| 23 namespace net { | 26 namespace net { |
| 24 | 27 |
| 25 namespace { | 28 namespace { |
| 26 | 29 |
| 27 // Enable this to see logging for state machine state transitions. | 30 // Enable this to see logging for state machine state transitions. |
| 28 #if 0 | 31 #if 0 |
| 29 #define GotoState(s) do { DVLOG(2) << (void *)this << " " << __FUNCTION__ << \ | 32 #define GotoState(s) do { DVLOG(2) << (void *)this << " " << __FUNCTION__ << \ |
| 30 " jump to state " << s; \ | 33 " jump to state " << s; \ |
| 31 next_handshake_state_ = s; } while (0) | 34 next_handshake_state_ = s; } while (0) |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 168 ssl_socket_data_index_ = SSL_get_ex_new_index(0, 0, 0, 0, 0); | 171 ssl_socket_data_index_ = SSL_get_ex_new_index(0, 0, 0, 0, 0); |
| 169 DCHECK_NE(ssl_socket_data_index_, -1); | 172 DCHECK_NE(ssl_socket_data_index_, -1); |
| 170 ssl_ctx_.reset(SSL_CTX_new(SSLv23_client_method())); | 173 ssl_ctx_.reset(SSL_CTX_new(SSLv23_client_method())); |
| 171 SSL_CTX_set_cert_verify_callback(ssl_ctx_.get(), NoOpVerifyCallback, NULL); | 174 SSL_CTX_set_cert_verify_callback(ssl_ctx_.get(), NoOpVerifyCallback, NULL); |
| 172 SSL_CTX_set_session_cache_mode(ssl_ctx_.get(), SSL_SESS_CACHE_CLIENT); | 175 SSL_CTX_set_session_cache_mode(ssl_ctx_.get(), SSL_SESS_CACHE_CLIENT); |
| 173 SSL_CTX_sess_set_new_cb(ssl_ctx_.get(), NewSessionCallbackStatic); | 176 SSL_CTX_sess_set_new_cb(ssl_ctx_.get(), NewSessionCallbackStatic); |
| 174 SSL_CTX_sess_set_remove_cb(ssl_ctx_.get(), RemoveSessionCallbackStatic); | 177 SSL_CTX_sess_set_remove_cb(ssl_ctx_.get(), RemoveSessionCallbackStatic); |
| 175 SSL_CTX_set_timeout(ssl_ctx_.get(), kSessionCacheTimeoutSeconds); | 178 SSL_CTX_set_timeout(ssl_ctx_.get(), kSessionCacheTimeoutSeconds); |
| 176 SSL_CTX_sess_set_cache_size(ssl_ctx_.get(), kSessionCacheMaxEntires); | 179 SSL_CTX_sess_set_cache_size(ssl_ctx_.get(), kSessionCacheMaxEntires); |
| 177 SSL_CTX_set_client_cert_cb(ssl_ctx_.get(), ClientCertCallback); | 180 SSL_CTX_set_client_cert_cb(ssl_ctx_.get(), ClientCertCallback); |
| 181 #ifdef OPENSSL_NPN_NEGOTIATED | |
|
willchan no longer on Chromium
2010/12/03 01:35:06
In Chromium code, we usually do #if defined(OPENSS
Kristian_
2010/12/03 14:58:56
Done.
| |
| 182 SSL_CTX_set_next_proto_select_cb(ssl_ctx_.get(), &SelectNextProtoCallback, | |
|
joth
2010/12/02 17:46:55
nit: other calls don't use & to get function addre
joth
2010/12/02 17:46:55
Problem: a side effect of calling SSL_CTX_set_next
willchan no longer on Chromium
2010/12/03 01:35:06
NPN next protos are decided on Chrome startup and
Kristian_
2010/12/03 14:58:56
I'm not sure if setting on first run gives us much
| |
| 183 NULL); | |
|
joth
2010/12/02 17:46:55
align NULL with first param
Kristian_
2010/12/03 14:58:56
Done.
| |
| 184 #endif | |
| 178 } | 185 } |
| 179 | 186 |
| 180 static int NewSessionCallbackStatic(SSL* ssl, SSL_SESSION* session) { | 187 static int NewSessionCallbackStatic(SSL* ssl, SSL_SESSION* session) { |
| 181 return Get()->NewSessionCallback(ssl, session); | 188 return Get()->NewSessionCallback(ssl, session); |
| 182 } | 189 } |
| 183 | 190 |
| 184 int NewSessionCallback(SSL* ssl, SSL_SESSION* session) { | 191 int NewSessionCallback(SSL* ssl, SSL_SESSION* session) { |
| 185 SSLClientSocketOpenSSL* socket = GetClientSocketFromSSL(ssl); | 192 SSLClientSocketOpenSSL* socket = GetClientSocketFromSSL(ssl); |
| 186 session_cache_.OnSessionAdded(socket->host_and_port(), session); | 193 session_cache_.OnSessionAdded(socket->host_and_port(), session); |
| 187 return 1; // 1 => We took ownership of |session|. | 194 return 1; // 1 => We took ownership of |session|. |
| 188 } | 195 } |
| 189 | 196 |
| 190 static void RemoveSessionCallbackStatic(SSL_CTX* ctx, SSL_SESSION* session) { | 197 static void RemoveSessionCallbackStatic(SSL_CTX* ctx, SSL_SESSION* session) { |
| 191 return Get()->RemoveSessionCallback(ctx, session); | 198 return Get()->RemoveSessionCallback(ctx, session); |
| 192 } | 199 } |
| 193 | 200 |
| 194 void RemoveSessionCallback(SSL_CTX* ctx, SSL_SESSION* session) { | 201 void RemoveSessionCallback(SSL_CTX* ctx, SSL_SESSION* session) { |
| 195 DCHECK(ctx == ssl_ctx()); | 202 DCHECK(ctx == ssl_ctx()); |
| 196 session_cache_.OnSessionRemoved(session); | 203 session_cache_.OnSessionRemoved(session); |
| 197 } | 204 } |
| 198 | 205 |
| 199 static int ClientCertCallback(SSL* ssl, X509** x509, EVP_PKEY** pkey) { | 206 static int ClientCertCallback(SSL* ssl, X509** x509, EVP_PKEY** pkey) { |
| 200 SSLClientSocketOpenSSL* socket = Get()->GetClientSocketFromSSL(ssl); | 207 SSLClientSocketOpenSSL* socket = Get()->GetClientSocketFromSSL(ssl); |
| 201 CHECK(socket); | 208 CHECK(socket); |
| 202 return socket->ClientCertRequestCallback(ssl, x509, pkey); | 209 return socket->ClientCertRequestCallback(ssl, x509, pkey); |
| 203 } | 210 } |
| 204 | 211 |
| 212 #ifdef OPENSSL_NPN_NEGOTIATED | |
| 213 static int SelectNextProtoCallback(SSL* ssl, | |
| 214 unsigned char** out, unsigned char* outlen, | |
| 215 const unsigned char* in, | |
| 216 unsigned int inlen, void* arg) { | |
| 217 if (!HttpStreamFactory::next_protos() || | |
| 218 HttpStreamFactory::next_protos()->empty()) | |
| 219 return SSL_TLSEXT_ERR_OK; | |
|
joth
2010/12/02 17:46:55
The docs for SSL_CTX_set_next_proto_select_cb stat
willchan no longer on Chromium
2010/12/03 01:35:06
You're right. That'd be better, but if it's too m
Kristian_
2010/12/03 14:58:56
The problem is that the contents of SSLConfig::nex
| |
| 220 | |
| 221 const std::string& next_protos = *HttpStreamFactory::next_protos(); | |
|
joth
2010/12/02 17:46:55
maybe add a comment:
CARE: |*out| maybe set to poi
| |
| 222 SSLClientSocketOpenSSL* socket = Get()->GetClientSocketFromSSL(ssl); | |
| 223 | |
| 224 int status = SSL_select_next_proto( | |
| 225 out, outlen, in, inlen, | |
| 226 reinterpret_cast<const unsigned char*>(next_protos.data()), | |
| 227 next_protos.size()); | |
| 228 | |
| 229 socket->set_npn_proto(reinterpret_cast<const char*>(*out), *outlen); | |
| 230 switch (status) { | |
| 231 case OPENSSL_NPN_UNSUPPORTED: | |
| 232 socket->set_npn_status(SSLClientSocket::kNextProtoUnsupported); | |
| 233 break; | |
| 234 case OPENSSL_NPN_NEGOTIATED: | |
| 235 socket->set_npn_status(SSLClientSocket::kNextProtoNegotiated); | |
| 236 break; | |
| 237 case OPENSSL_NPN_NO_OVERLAP: | |
| 238 socket->set_npn_status(SSLClientSocket::kNextProtoNoOverlap); | |
| 239 break; | |
| 240 default: | |
| 241 NOTREACHED(); | |
|
joth
2010/12/02 17:46:55
nit: NOTREACHED() << status;
Kristian_
2010/12/03 14:58:56
Done.
| |
| 242 break; | |
| 243 } | |
| 244 return SSL_TLSEXT_ERR_OK; | |
| 245 } | |
| 246 #endif | |
| 247 | |
| 205 // This is the index used with SSL_get_ex_data to retrieve the owner | 248 // This is the index used with SSL_get_ex_data to retrieve the owner |
| 206 // SSLClientSocketOpenSSL object from an SSL instance. | 249 // SSLClientSocketOpenSSL object from an SSL instance. |
| 207 int ssl_socket_data_index_; | 250 int ssl_socket_data_index_; |
| 208 | 251 |
| 209 base::ScopedOpenSSL<SSL_CTX, SSL_CTX_free> ssl_ctx_; | 252 base::ScopedOpenSSL<SSL_CTX, SSL_CTX_free> ssl_ctx_; |
| 210 SSLSessionCache session_cache_; | 253 SSLSessionCache session_cache_; |
| 211 }; | 254 }; |
| 212 | 255 |
| 213 // Utility to construct the appropriate set & clear masks for use the OpenSSL | 256 // Utility to construct the appropriate set & clear masks for use the OpenSSL |
| 214 // options and mode configuration functions. (SSL_set_options etc) | 257 // options and mode configuration functions. (SSL_set_options etc) |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 241 completed_handshake_(false), | 284 completed_handshake_(false), |
| 242 client_auth_cert_needed_(false), | 285 client_auth_cert_needed_(false), |
| 243 ALLOW_THIS_IN_INITIALIZER_LIST(handshake_io_callback_( | 286 ALLOW_THIS_IN_INITIALIZER_LIST(handshake_io_callback_( |
| 244 this, &SSLClientSocketOpenSSL::OnHandshakeIOComplete)), | 287 this, &SSLClientSocketOpenSSL::OnHandshakeIOComplete)), |
| 245 ssl_(NULL), | 288 ssl_(NULL), |
| 246 transport_bio_(NULL), | 289 transport_bio_(NULL), |
| 247 transport_(transport_socket), | 290 transport_(transport_socket), |
| 248 host_and_port_(host_and_port), | 291 host_and_port_(host_and_port), |
| 249 ssl_config_(ssl_config), | 292 ssl_config_(ssl_config), |
| 250 trying_cached_session_(false), | 293 trying_cached_session_(false), |
| 294 npn_status_(kNextProtoUnsupported), | |
| 251 net_log_(transport_socket->socket()->NetLog()) { | 295 net_log_(transport_socket->socket()->NetLog()) { |
| 252 } | 296 } |
| 253 | 297 |
| 254 SSLClientSocketOpenSSL::~SSLClientSocketOpenSSL() { | 298 SSLClientSocketOpenSSL::~SSLClientSocketOpenSSL() { |
| 255 Disconnect(); | 299 Disconnect(); |
| 256 } | 300 } |
| 257 | 301 |
| 258 bool SSLClientSocketOpenSSL::Init() { | 302 bool SSLClientSocketOpenSSL::Init() { |
| 259 DCHECK(!ssl_); | 303 DCHECK(!ssl_); |
| 260 DCHECK(!transport_bio_); | 304 DCHECK(!transport_bio_); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 363 } | 407 } |
| 364 | 408 |
| 365 void SSLClientSocketOpenSSL::GetSSLCertRequestInfo( | 409 void SSLClientSocketOpenSSL::GetSSLCertRequestInfo( |
| 366 SSLCertRequestInfo* cert_request_info) { | 410 SSLCertRequestInfo* cert_request_info) { |
| 367 cert_request_info->host_and_port = host_and_port_.ToString(); | 411 cert_request_info->host_and_port = host_and_port_.ToString(); |
| 368 cert_request_info->client_certs = client_certs_; | 412 cert_request_info->client_certs = client_certs_; |
| 369 } | 413 } |
| 370 | 414 |
| 371 SSLClientSocket::NextProtoStatus SSLClientSocketOpenSSL::GetNextProto( | 415 SSLClientSocket::NextProtoStatus SSLClientSocketOpenSSL::GetNextProto( |
| 372 std::string* proto) { | 416 std::string* proto) { |
| 373 proto->clear(); | 417 proto->assign(npn_proto_); |
|
joth
2010/12/02 17:46:55
nit: *proto = npn_proto_;
(probably just slightly
Kristian_
2010/12/03 14:58:56
Done.
| |
| 374 return kNextProtoUnsupported; | 418 return npn_status_; |
| 375 } | 419 } |
| 376 | 420 |
| 377 void SSLClientSocketOpenSSL::DoReadCallback(int rv) { | 421 void SSLClientSocketOpenSSL::DoReadCallback(int rv) { |
| 378 // Since Run may result in Read being called, clear |user_read_callback_| | 422 // Since Run may result in Read being called, clear |user_read_callback_| |
| 379 // up front. | 423 // up front. |
| 380 CompletionCallback* c = user_read_callback_; | 424 CompletionCallback* c = user_read_callback_; |
| 381 user_read_callback_ = NULL; | 425 user_read_callback_ = NULL; |
| 382 user_read_buf_ = NULL; | 426 user_read_buf_ = NULL; |
| 383 user_read_buf_len_ = 0; | 427 user_read_buf_len_ = 0; |
| 384 c->Run(rv); | 428 c->Run(rv); |
| (...skipping 559 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 944 int rv = SSL_write(ssl_, user_write_buf_->data(), user_write_buf_len_); | 988 int rv = SSL_write(ssl_, user_write_buf_->data(), user_write_buf_len_); |
| 945 | 989 |
| 946 if (rv >= 0) | 990 if (rv >= 0) |
| 947 return rv; | 991 return rv; |
| 948 | 992 |
| 949 int err = SSL_get_error(ssl_, rv); | 993 int err = SSL_get_error(ssl_, rv); |
| 950 return MapOpenSSLError(err); | 994 return MapOpenSSLError(err); |
| 951 } | 995 } |
| 952 | 996 |
| 953 } // namespace net | 997 } // namespace net |
| OLD | NEW |