OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/err.h> | 10 #include <openssl/err.h> |
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
322 context->session_cache()->Flush(); | 322 context->session_cache()->Flush(); |
323 } | 323 } |
324 | 324 |
325 SSLClientSocketOpenSSL::SSLClientSocketOpenSSL( | 325 SSLClientSocketOpenSSL::SSLClientSocketOpenSSL( |
326 scoped_ptr<ClientSocketHandle> transport_socket, | 326 scoped_ptr<ClientSocketHandle> transport_socket, |
327 const HostPortPair& host_and_port, | 327 const HostPortPair& host_and_port, |
328 const SSLConfig& ssl_config, | 328 const SSLConfig& ssl_config, |
329 const SSLClientSocketContext& context) | 329 const SSLClientSocketContext& context) |
330 : transport_send_busy_(false), | 330 : transport_send_busy_(false), |
331 transport_recv_busy_(false), | 331 transport_recv_busy_(false), |
332 transport_recv_eof_(false), | |
333 weak_factory_(this), | 332 weak_factory_(this), |
334 pending_read_error_(kNoPendingReadResult), | 333 pending_read_error_(kNoPendingReadResult), |
| 334 transport_read_error_(OK), |
335 transport_write_error_(OK), | 335 transport_write_error_(OK), |
336 server_cert_chain_(new PeerCertificateChain(NULL)), | 336 server_cert_chain_(new PeerCertificateChain(NULL)), |
337 completed_handshake_(false), | 337 completed_handshake_(false), |
338 was_ever_used_(false), | 338 was_ever_used_(false), |
339 client_auth_cert_needed_(false), | 339 client_auth_cert_needed_(false), |
340 cert_verifier_(context.cert_verifier), | 340 cert_verifier_(context.cert_verifier), |
341 server_bound_cert_service_(context.server_bound_cert_service), | 341 server_bound_cert_service_(context.server_bound_cert_service), |
342 ssl_(NULL), | 342 ssl_(NULL), |
343 transport_bio_(NULL), | 343 transport_bio_(NULL), |
344 transport_(transport_socket.Pass()), | 344 transport_(transport_socket.Pass()), |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
438 } | 438 } |
439 | 439 |
440 // Shut down anything that may call us back. | 440 // Shut down anything that may call us back. |
441 verifier_.reset(); | 441 verifier_.reset(); |
442 transport_->socket()->Disconnect(); | 442 transport_->socket()->Disconnect(); |
443 | 443 |
444 // Null all callbacks, delete all buffers. | 444 // Null all callbacks, delete all buffers. |
445 transport_send_busy_ = false; | 445 transport_send_busy_ = false; |
446 send_buffer_ = NULL; | 446 send_buffer_ = NULL; |
447 transport_recv_busy_ = false; | 447 transport_recv_busy_ = false; |
448 transport_recv_eof_ = false; | |
449 recv_buffer_ = NULL; | 448 recv_buffer_ = NULL; |
450 | 449 |
451 user_connect_callback_.Reset(); | 450 user_connect_callback_.Reset(); |
452 user_read_callback_.Reset(); | 451 user_read_callback_.Reset(); |
453 user_write_callback_.Reset(); | 452 user_write_callback_.Reset(); |
454 user_read_buf_ = NULL; | 453 user_read_buf_ = NULL; |
455 user_read_buf_len_ = 0; | 454 user_read_buf_len_ = 0; |
456 user_write_buf_ = NULL; | 455 user_write_buf_ = NULL; |
457 user_write_buf_len_ = 0; | 456 user_write_buf_len_ = 0; |
458 | 457 |
459 pending_read_error_ = kNoPendingReadResult; | 458 pending_read_error_ = kNoPendingReadResult; |
| 459 transport_read_error_ = OK; |
460 transport_write_error_ = OK; | 460 transport_write_error_ = OK; |
461 | 461 |
462 server_cert_verify_result_.Reset(); | 462 server_cert_verify_result_.Reset(); |
463 completed_handshake_ = false; | 463 completed_handshake_ = false; |
464 | 464 |
465 cert_authorities_.clear(); | 465 cert_authorities_.clear(); |
466 cert_key_types_.clear(); | 466 cert_key_types_.clear(); |
467 client_auth_cert_needed_ = false; | 467 client_auth_cert_needed_ = false; |
468 | 468 |
469 channel_id_xtn_negotiated_ = false; | 469 channel_id_xtn_negotiated_ = false; |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
652 trying_cached_session_ = context->session_cache()->SetSSLSessionWithKey( | 652 trying_cached_session_ = context->session_cache()->SetSSLSessionWithKey( |
653 ssl_, GetSocketSessionCacheKey(*this)); | 653 ssl_, GetSocketSessionCacheKey(*this)); |
654 | 654 |
655 BIO* ssl_bio = NULL; | 655 BIO* ssl_bio = NULL; |
656 // 0 => use default buffer sizes. | 656 // 0 => use default buffer sizes. |
657 if (!BIO_new_bio_pair(&ssl_bio, 0, &transport_bio_, 0)) | 657 if (!BIO_new_bio_pair(&ssl_bio, 0, &transport_bio_, 0)) |
658 return ERR_UNEXPECTED; | 658 return ERR_UNEXPECTED; |
659 DCHECK(ssl_bio); | 659 DCHECK(ssl_bio); |
660 DCHECK(transport_bio_); | 660 DCHECK(transport_bio_); |
661 | 661 |
| 662 // Install a callback on OpenSSL's end to plumb transport errors through. |
| 663 BIO_set_callback(ssl_bio, &SSLClientSocketOpenSSL::BIOCallback); |
| 664 BIO_set_callback_arg(ssl_bio, reinterpret_cast<char*>(this)); |
| 665 |
662 SSL_set_bio(ssl_, ssl_bio, ssl_bio); | 666 SSL_set_bio(ssl_, ssl_bio, ssl_bio); |
663 | 667 |
664 // OpenSSL defaults some options to on, others to off. To avoid ambiguity, | 668 // OpenSSL defaults some options to on, others to off. To avoid ambiguity, |
665 // set everything we care about to an absolute value. | 669 // set everything we care about to an absolute value. |
666 SslSetClearMask options; | 670 SslSetClearMask options; |
667 options.ConfigureFlag(SSL_OP_NO_SSLv2, true); | 671 options.ConfigureFlag(SSL_OP_NO_SSLv2, true); |
668 bool ssl3_enabled = (ssl_config_.version_min == SSL_PROTOCOL_VERSION_SSL3); | 672 bool ssl3_enabled = (ssl_config_.version_min == SSL_PROTOCOL_VERSION_SSL3); |
669 options.ConfigureFlag(SSL_OP_NO_SSLv3, !ssl3_enabled); | 673 options.ConfigureFlag(SSL_OP_NO_SSLv3, !ssl3_enabled); |
670 bool tls1_enabled = (ssl_config_.version_min <= SSL_PROTOCOL_VERSION_TLS1 && | 674 bool tls1_enabled = (ssl_config_.version_min <= SSL_PROTOCOL_VERSION_TLS1 && |
671 ssl_config_.version_max >= SSL_PROTOCOL_VERSION_TLS1); | 675 ssl_config_.version_max >= SSL_PROTOCOL_VERSION_TLS1); |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
770 bool SSLClientSocketOpenSSL::DoTransportIO() { | 774 bool SSLClientSocketOpenSSL::DoTransportIO() { |
771 bool network_moved = false; | 775 bool network_moved = false; |
772 int rv; | 776 int rv; |
773 // Read and write as much data as possible. The loop is necessary because | 777 // Read and write as much data as possible. The loop is necessary because |
774 // Write() may return synchronously. | 778 // Write() may return synchronously. |
775 do { | 779 do { |
776 rv = BufferSend(); | 780 rv = BufferSend(); |
777 if (rv != ERR_IO_PENDING && rv != 0) | 781 if (rv != ERR_IO_PENDING && rv != 0) |
778 network_moved = true; | 782 network_moved = true; |
779 } while (rv > 0); | 783 } while (rv > 0); |
780 if (!transport_recv_eof_ && BufferRecv() != ERR_IO_PENDING) | 784 if (transport_read_error_ == OK && BufferRecv() != ERR_IO_PENDING) |
781 network_moved = true; | 785 network_moved = true; |
782 return network_moved; | 786 return network_moved; |
783 } | 787 } |
784 | 788 |
785 int SSLClientSocketOpenSSL::DoHandshake() { | 789 int SSLClientSocketOpenSSL::DoHandshake() { |
786 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); | 790 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); |
787 int net_error = OK; | 791 int net_error = OK; |
788 int rv = SSL_do_handshake(ssl_); | 792 int rv = SSL_do_handshake(ssl_); |
789 | 793 |
790 if (client_auth_cert_needed_) { | 794 if (client_auth_cert_needed_) { |
(...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1254 } | 1258 } |
1255 | 1259 |
1256 void SSLClientSocketOpenSSL::BufferRecvComplete(int result) { | 1260 void SSLClientSocketOpenSSL::BufferRecvComplete(int result) { |
1257 result = TransportReadComplete(result); | 1261 result = TransportReadComplete(result); |
1258 OnRecvComplete(result); | 1262 OnRecvComplete(result); |
1259 } | 1263 } |
1260 | 1264 |
1261 void SSLClientSocketOpenSSL::TransportWriteComplete(int result) { | 1265 void SSLClientSocketOpenSSL::TransportWriteComplete(int result) { |
1262 DCHECK(ERR_IO_PENDING != result); | 1266 DCHECK(ERR_IO_PENDING != result); |
1263 if (result < 0) { | 1267 if (result < 0) { |
1264 // Got a socket write error; close the BIO to indicate this upward. | 1268 // Record the error. Save it to be reported in a future read or write on |
1265 // | 1269 // transport_bio_'s peer. |
1266 // TODO(davidben): The value of |result| gets lost. Feed the error back into | |
1267 // the BIO so it gets (re-)detected in OnSendComplete. Perhaps with | |
1268 // BIO_set_callback. | |
1269 DVLOG(1) << "TransportWriteComplete error " << result; | |
1270 (void)BIO_shutdown_wr(SSL_get_wbio(ssl_)); | |
1271 | |
1272 // Match the fix for http://crbug.com/249848 in NSS by erroring future reads | |
1273 // from the socket after a write error. | |
1274 // | |
1275 // TODO(davidben): Avoid having read and write ends interact this way. | |
1276 transport_write_error_ = result; | 1270 transport_write_error_ = result; |
1277 (void)BIO_shutdown_wr(transport_bio_); | |
1278 send_buffer_ = NULL; | 1271 send_buffer_ = NULL; |
1279 } else { | 1272 } else { |
1280 DCHECK(send_buffer_.get()); | 1273 DCHECK(send_buffer_.get()); |
1281 send_buffer_->DidConsume(result); | 1274 send_buffer_->DidConsume(result); |
1282 DCHECK_GE(send_buffer_->BytesRemaining(), 0); | 1275 DCHECK_GE(send_buffer_->BytesRemaining(), 0); |
1283 if (send_buffer_->BytesRemaining() <= 0) | 1276 if (send_buffer_->BytesRemaining() <= 0) |
1284 send_buffer_ = NULL; | 1277 send_buffer_ = NULL; |
1285 } | 1278 } |
1286 } | 1279 } |
1287 | 1280 |
1288 int SSLClientSocketOpenSSL::TransportReadComplete(int result) { | 1281 int SSLClientSocketOpenSSL::TransportReadComplete(int result) { |
1289 DCHECK(ERR_IO_PENDING != result); | 1282 DCHECK(ERR_IO_PENDING != result); |
1290 if (result <= 0) { | 1283 // If an EOF, canonicalize to ERR_CONNECTION_CLOSED here so MapOpenSSLError |
| 1284 // does not report success. |
| 1285 if (result == 0) |
| 1286 result = ERR_CONNECTION_CLOSED; |
| 1287 if (result < 0) { |
1291 DVLOG(1) << "TransportReadComplete result " << result; | 1288 DVLOG(1) << "TransportReadComplete result " << result; |
1292 // Received 0 (end of file) or an error. Either way, bubble it up to the | 1289 // Received an error. Save it to be reported in a future read on |
1293 // SSL layer via the BIO. TODO(joth): consider stashing the error code, to | 1290 // transport_bio_'s peer. |
1294 // relay up to the SSL socket client (i.e. via DoReadCallback). | 1291 transport_read_error_ = result; |
1295 if (result == 0) | |
1296 transport_recv_eof_ = true; | |
1297 (void)BIO_shutdown_wr(transport_bio_); | |
1298 } else if (transport_write_error_ < 0) { | |
1299 // Mirror transport write errors as read failures; transport_bio_ has been | |
1300 // shut down by TransportWriteComplete, so the BIO_write will fail, failing | |
1301 // the CHECK. http://crbug.com/335557. | |
1302 result = transport_write_error_; | |
1303 } else { | 1292 } else { |
1304 DCHECK(recv_buffer_.get()); | 1293 DCHECK(recv_buffer_.get()); |
1305 int ret = BIO_write(transport_bio_, recv_buffer_->data(), result); | 1294 int ret = BIO_write(transport_bio_, recv_buffer_->data(), result); |
1306 // A write into a memory BIO should always succeed. | 1295 // A write into a memory BIO should always succeed. |
1307 DCHECK_EQ(result, ret); | 1296 DCHECK_EQ(result, ret); |
1308 } | 1297 } |
1309 recv_buffer_ = NULL; | 1298 recv_buffer_ = NULL; |
1310 transport_recv_busy_ = false; | 1299 transport_recv_busy_ = false; |
1311 return result; | 1300 return result; |
1312 } | 1301 } |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1441 ssl_config_.next_protos[0].data())); | 1430 ssl_config_.next_protos[0].data())); |
1442 *outlen = ssl_config_.next_protos[0].size(); | 1431 *outlen = ssl_config_.next_protos[0].size(); |
1443 } | 1432 } |
1444 | 1433 |
1445 npn_proto_.assign(reinterpret_cast<const char*>(*out), *outlen); | 1434 npn_proto_.assign(reinterpret_cast<const char*>(*out), *outlen); |
1446 server_protos_.assign(reinterpret_cast<const char*>(in), inlen); | 1435 server_protos_.assign(reinterpret_cast<const char*>(in), inlen); |
1447 DVLOG(2) << "next protocol: '" << npn_proto_ << "' status: " << npn_status_; | 1436 DVLOG(2) << "next protocol: '" << npn_proto_ << "' status: " << npn_status_; |
1448 return SSL_TLSEXT_ERR_OK; | 1437 return SSL_TLSEXT_ERR_OK; |
1449 } | 1438 } |
1450 | 1439 |
| 1440 long SSLClientSocketOpenSSL::MaybeReplayTransportError( |
| 1441 BIO *bio, |
| 1442 int cmd, |
| 1443 const char *argp, int argi, long argl, |
| 1444 long retvalue) { |
| 1445 if (cmd == (BIO_CB_READ|BIO_CB_RETURN) && retvalue <= 0) { |
| 1446 // If there is no more data in the buffer, report any pending errors that |
| 1447 // were observed. Note that both the readbuf and the writebuf are checked |
| 1448 // for errors, since the application may have encountered a socket error |
| 1449 // while writing that would otherwise not be reported until the application |
| 1450 // attempted to write again - which it may never do. See |
| 1451 // https://crbug.com/249848. |
| 1452 if (transport_read_error_ != OK) { |
| 1453 OpenSSLPutNetError(FROM_HERE, transport_read_error_); |
| 1454 return -1; |
| 1455 } |
| 1456 if (transport_write_error_ != OK) { |
| 1457 OpenSSLPutNetError(FROM_HERE, transport_write_error_); |
| 1458 return -1; |
| 1459 } |
| 1460 } else if (cmd == BIO_CB_WRITE) { |
| 1461 // Because of the write buffer, this reports a failure from the previous |
| 1462 // write payload. If the current payload fails to write, the error will be |
| 1463 // reported in a future write or read to |bio|. |
| 1464 if (transport_write_error_ != OK) { |
| 1465 OpenSSLPutNetError(FROM_HERE, transport_write_error_); |
| 1466 return -1; |
| 1467 } |
| 1468 } |
| 1469 return retvalue; |
| 1470 } |
| 1471 |
| 1472 // static |
| 1473 long SSLClientSocketOpenSSL::BIOCallback( |
| 1474 BIO *bio, |
| 1475 int cmd, |
| 1476 const char *argp, int argi, long argl, |
| 1477 long retvalue) { |
| 1478 SSLClientSocketOpenSSL* socket = reinterpret_cast<SSLClientSocketOpenSSL*>( |
| 1479 BIO_get_callback_arg(bio)); |
| 1480 CHECK(socket); |
| 1481 return socket->MaybeReplayTransportError( |
| 1482 bio, cmd, argp, argi, argl, retvalue); |
| 1483 } |
| 1484 |
1451 scoped_refptr<X509Certificate> | 1485 scoped_refptr<X509Certificate> |
1452 SSLClientSocketOpenSSL::GetUnverifiedServerCertificateChain() const { | 1486 SSLClientSocketOpenSSL::GetUnverifiedServerCertificateChain() const { |
1453 return server_cert_; | 1487 return server_cert_; |
1454 } | 1488 } |
1455 | 1489 |
1456 } // namespace net | 1490 } // namespace net |
OLD | NEW |