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...) 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...) 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...) 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...) 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 |