Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(45)

Side by Side Diff: net/socket/ssl_client_socket_openssl.cc

Issue 367963007: Preserve transport errors for OpenSSL sockets. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: sleevi comments; also fix last-minute bug introduced in patch set 2 (oops) Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/socket/ssl_client_socket_openssl.h ('k') | net/socket/ssl_client_socket_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « net/socket/ssl_client_socket_openssl.h ('k') | net/socket/ssl_client_socket_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698