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

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

Issue 344026: Add LoadLog to ClientSocket::Connect(). (Closed)
Patch Set: Minor build fixups and fixed mac bug. Created 11 years, 1 month 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
« no previous file with comments | « net/socket/ssl_client_socket_mac.h ('k') | net/socket/ssl_client_socket_nss.h » ('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) 2008-2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2008-2009 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 #include "net/socket/ssl_client_socket_mac.h" 5 #include "net/socket/ssl_client_socket_mac.h"
6 6
7 #include "base/scoped_cftyperef.h" 7 #include "base/scoped_cftyperef.h"
8 #include "base/singleton.h" 8 #include "base/singleton.h"
9 #include "base/string_util.h" 9 #include "base/string_util.h"
10 #include "net/base/cert_verifier.h" 10 #include "net/base/cert_verifier.h"
11 #include "net/base/io_buffer.h" 11 #include "net/base/io_buffer.h"
12 #include "net/base/load_log.h"
12 #include "net/base/net_errors.h" 13 #include "net/base/net_errors.h"
13 #include "net/base/ssl_info.h" 14 #include "net/base/ssl_info.h"
14 15
15 // Welcome to Mac SSL. We've been waiting for you. 16 // Welcome to Mac SSL. We've been waiting for you.
16 // 17 //
17 // The Mac SSL implementation is, like the Windows and NSS implementations, a 18 // The Mac SSL implementation is, like the Windows and NSS implementations, a
18 // giant state machine. This design constraint is due to the asynchronous nature 19 // giant state machine. This design constraint is due to the asynchronous nature
19 // of our underlying transport mechanism. We can call down to read/write on the 20 // of our underlying transport mechanism. We can call down to read/write on the
20 // network, but what happens is that either it completes immediately or returns 21 // network, but what happens is that either it completes immediately or returns
21 // saying that we'll get a callback sometime in the future. In that case, we 22 // saying that we'll get a callback sometime in the future. In that case, we
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after
319 ssl_context_(NULL), 320 ssl_context_(NULL),
320 pending_send_error_(OK), 321 pending_send_error_(OK),
321 recv_buffer_head_slop_(0), 322 recv_buffer_head_slop_(0),
322 recv_buffer_tail_slop_(0) { 323 recv_buffer_tail_slop_(0) {
323 } 324 }
324 325
325 SSLClientSocketMac::~SSLClientSocketMac() { 326 SSLClientSocketMac::~SSLClientSocketMac() {
326 Disconnect(); 327 Disconnect();
327 } 328 }
328 329
329 int SSLClientSocketMac::Connect(CompletionCallback* callback) { 330 int SSLClientSocketMac::Connect(CompletionCallback* callback,
331 LoadLog* load_log) {
330 DCHECK(transport_.get()); 332 DCHECK(transport_.get());
331 DCHECK(next_handshake_state_ == STATE_NONE); 333 DCHECK(next_handshake_state_ == STATE_NONE);
332 DCHECK(!user_connect_callback_); 334 DCHECK(!user_connect_callback_);
333 335
334 OSStatus status = noErr; 336 LoadLog::BeginEvent(load_log, LoadLog::TYPE_SSL_CONNECT);
335 337
336 status = SSLNewContext(false, &ssl_context_); 338 int rv = InitializeSSLContext();
337 if (status) 339 if (rv != OK) {
338 return NetErrorFromOSStatus(status); 340 LoadLog::EndEvent(load_log, LoadLog::TYPE_SSL_CONNECT);
339 341 return rv;
340 status = SSLSetProtocolVersionEnabled(ssl_context_,
341 kSSLProtocol2,
342 ssl_config_.ssl2_enabled);
343 if (status)
344 return NetErrorFromOSStatus(status);
345
346 status = SSLSetProtocolVersionEnabled(ssl_context_,
347 kSSLProtocol3,
348 ssl_config_.ssl3_enabled);
349 if (status)
350 return NetErrorFromOSStatus(status);
351
352 status = SSLSetProtocolVersionEnabled(ssl_context_,
353 kTLSProtocol1,
354 ssl_config_.tls1_enabled);
355 if (status)
356 return NetErrorFromOSStatus(status);
357
358 status = SSLSetIOFuncs(ssl_context_, SSLReadCallback, SSLWriteCallback);
359 if (status)
360 return NetErrorFromOSStatus(status);
361
362 status = SSLSetConnection(ssl_context_, this);
363 if (status)
364 return NetErrorFromOSStatus(status);
365
366 // Disable certificate verification within Secure Transport; we'll
367 // be handling that ourselves.
368 status = SSLSetEnableCertVerify(ssl_context_, false);
369 if (status)
370 return NetErrorFromOSStatus(status);
371
372 // SSLSetSessionOption() was introduced in Mac OS X 10.5.7. It allows us
373 // to perform certificate validation during the handshake, which is
374 // required in order to properly enable session resumption.
375 //
376 // With the kSSLSessionOptionBreakOnServerAuth option set, SSLHandshake()
377 // will return errSSLServerAuthCompleted after receiving the server's
378 // Certificate during the handshake. That gives us an opportunity to verify
379 // the server certificate and then re-enter that handshake (assuming the
380 // certificate successfully validated).
381 //
382 // If SSLSetSessionOption() is not present, we do not enable session
383 // resumption, because in that case we are verifying the server's certificate
384 // after the handshake completes (but before any application data is
385 // exchanged). If we were to enable session resumption in this situation,
386 // the session would be cached before we verified the certificate, leaving
387 // the potential for a session in which the certificate failed to validate
388 // to still be able to be resumed.
389 CFBundleRef bundle =
390 CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security"));
391 if (bundle) {
392 SSLSetSessionOptionFuncPtr ssl_set_session_options =
393 reinterpret_cast<SSLSetSessionOptionFuncPtr>(
394 CFBundleGetFunctionPointerForName(bundle,
395 CFSTR("SSLSetSessionOption")));
396 if (ssl_set_session_options) {
397 status = ssl_set_session_options(ssl_context_,
398 kSSLSessionOptionBreakOnServerAuthFlag,
399 true);
400 if (status)
401 return NetErrorFromOSStatus(status);
402
403 // Concatenate the hostname and peer address to use as the peer ID. To
404 // resume a session, we must connect to the same server on the same port
405 // using the same hostname (i.e., localhost and 127.0.0.1 are considered
406 // different peers, which puts us through certificate validation again
407 // and catches hostname/certificate name mismatches.
408 struct sockaddr_storage addr;
409 socklen_t addr_length = sizeof(struct sockaddr_storage);
410 memset(&addr, 0, sizeof(addr));
411 if (!transport_->GetPeerName(reinterpret_cast<struct sockaddr*>(&addr),
412 &addr_length)) {
413 // Assemble the socket hostname and address into a single buffer.
414 std::vector<char> peer_id(hostname_.begin(), hostname_.end());
415 peer_id.insert(peer_id.end(), reinterpret_cast<char*>(&addr),
416 reinterpret_cast<char*>(&addr) + addr_length);
417
418 // SSLSetPeerID() treats peer_id as a binary blob, and makes its
419 // own copy.
420 status = SSLSetPeerID(ssl_context_, &peer_id[0], peer_id.size());
421 if (status)
422 return NetErrorFromOSStatus(status);
423 }
424 }
425 } 342 }
426 343
427 next_handshake_state_ = STATE_HANDSHAKE_START; 344 next_handshake_state_ = STATE_HANDSHAKE_START;
428 int rv = DoHandshakeLoop(OK); 345 rv = DoHandshakeLoop(OK);
429 if (rv == ERR_IO_PENDING) 346 if (rv == ERR_IO_PENDING) {
347 load_log_ = load_log;
430 user_connect_callback_ = callback; 348 user_connect_callback_ = callback;
349 } else {
350 LoadLog::EndEvent(load_log, LoadLog::TYPE_SSL_CONNECT);
351 }
431 return rv; 352 return rv;
432 } 353 }
433 354
434 void SSLClientSocketMac::Disconnect() { 355 void SSLClientSocketMac::Disconnect() {
435 completed_handshake_ = false; 356 completed_handshake_ = false;
436 357
437 if (ssl_context_) { 358 if (ssl_context_) {
438 SSLClose(ssl_context_); 359 SSLClose(ssl_context_);
439 SSLDisposeContext(ssl_context_); 360 SSLDisposeContext(ssl_context_);
440 ssl_context_ = NULL; 361 ssl_context_ = NULL;
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
528 OSStatus status = SSLGetNegotiatedCipher(ssl_context_, &suite); 449 OSStatus status = SSLGetNegotiatedCipher(ssl_context_, &suite);
529 if (!status) 450 if (!status)
530 ssl_info->security_bits = KeySizeOfCipherSuite(suite); 451 ssl_info->security_bits = KeySizeOfCipherSuite(suite);
531 } 452 }
532 453
533 void SSLClientSocketMac::GetSSLCertRequestInfo( 454 void SSLClientSocketMac::GetSSLCertRequestInfo(
534 SSLCertRequestInfo* cert_request_info) { 455 SSLCertRequestInfo* cert_request_info) {
535 // TODO(wtc): implement this. 456 // TODO(wtc): implement this.
536 } 457 }
537 458
459 int SSLClientSocketMac::InitializeSSLContext() {
460 OSStatus status = noErr;
461
462 status = SSLNewContext(false, &ssl_context_);
463 if (status)
464 return NetErrorFromOSStatus(status);
465
466 status = SSLSetProtocolVersionEnabled(ssl_context_,
467 kSSLProtocol2,
468 ssl_config_.ssl2_enabled);
469 if (status)
470 return NetErrorFromOSStatus(status);
471
472 status = SSLSetProtocolVersionEnabled(ssl_context_,
473 kSSLProtocol3,
474 ssl_config_.ssl3_enabled);
475 if (status)
476 return NetErrorFromOSStatus(status);
477
478 status = SSLSetProtocolVersionEnabled(ssl_context_,
479 kTLSProtocol1,
480 ssl_config_.tls1_enabled);
481 if (status)
482 return NetErrorFromOSStatus(status);
483
484 status = SSLSetIOFuncs(ssl_context_, SSLReadCallback, SSLWriteCallback);
485 if (status)
486 return NetErrorFromOSStatus(status);
487
488 status = SSLSetConnection(ssl_context_, this);
489 if (status)
490 return NetErrorFromOSStatus(status);
491
492 // Disable certificate verification within Secure Transport; we'll
493 // be handling that ourselves.
494 status = SSLSetEnableCertVerify(ssl_context_, false);
495 if (status)
496 return NetErrorFromOSStatus(status);
497
498 // SSLSetSessionOption() was introduced in Mac OS X 10.5.7. It allows us
499 // to perform certificate validation during the handshake, which is
500 // required in order to properly enable session resumption.
501 //
502 // With the kSSLSessionOptionBreakOnServerAuth option set, SSLHandshake()
503 // will return errSSLServerAuthCompleted after receiving the server's
504 // Certificate during the handshake. That gives us an opportunity to verify
505 // the server certificate and then re-enter that handshake (assuming the
506 // certificate successfully validated).
507 //
508 // If SSLSetSessionOption() is not present, we do not enable session
509 // resumption, because in that case we are verifying the server's certificate
510 // after the handshake completes (but before any application data is
511 // exchanged). If we were to enable session resumption in this situation,
512 // the session would be cached before we verified the certificate, leaving
513 // the potential for a session in which the certificate failed to validate
514 // to still be able to be resumed.
515 CFBundleRef bundle =
516 CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security"));
517 if (bundle) {
518 SSLSetSessionOptionFuncPtr ssl_set_session_options =
519 reinterpret_cast<SSLSetSessionOptionFuncPtr>(
520 CFBundleGetFunctionPointerForName(bundle,
521 CFSTR("SSLSetSessionOption")));
522 if (ssl_set_session_options) {
523 status = ssl_set_session_options(ssl_context_,
524 kSSLSessionOptionBreakOnServerAuthFlag,
525 true);
526 if (status)
527 return NetErrorFromOSStatus(status);
528
529 // Concatenate the hostname and peer address to use as the peer ID. To
530 // resume a session, we must connect to the same server on the same port
531 // using the same hostname (i.e., localhost and 127.0.0.1 are considered
532 // different peers, which puts us through certificate validation again
533 // and catches hostname/certificate name mismatches.
534 struct sockaddr_storage addr;
535 socklen_t addr_length = sizeof(struct sockaddr_storage);
536 memset(&addr, 0, sizeof(addr));
537 if (!transport_->GetPeerName(reinterpret_cast<struct sockaddr*>(&addr),
538 &addr_length)) {
539 // Assemble the socket hostname and address into a single buffer.
540 std::vector<char> peer_id(hostname_.begin(), hostname_.end());
541 peer_id.insert(peer_id.end(), reinterpret_cast<char*>(&addr),
542 reinterpret_cast<char*>(&addr) + addr_length);
543
544 // SSLSetPeerID() treats peer_id as a binary blob, and makes its
545 // own copy.
546 status = SSLSetPeerID(ssl_context_, &peer_id[0], peer_id.size());
547 if (status)
548 return NetErrorFromOSStatus(status);
549 }
550 }
551 }
552
553 return OK;
554 }
555
538 void SSLClientSocketMac::DoConnectCallback(int rv) { 556 void SSLClientSocketMac::DoConnectCallback(int rv) {
539 DCHECK(rv != ERR_IO_PENDING); 557 DCHECK(rv != ERR_IO_PENDING);
540 DCHECK(user_connect_callback_); 558 DCHECK(user_connect_callback_);
541 DCHECK(next_handshake_state_ == STATE_NONE); 559 DCHECK(next_handshake_state_ == STATE_NONE);
542 560
543 CompletionCallback* c = user_connect_callback_; 561 CompletionCallback* c = user_connect_callback_;
544 user_connect_callback_ = NULL; 562 user_connect_callback_ = NULL;
545 c->Run(rv > OK ? OK : rv); 563 c->Run(rv > OK ? OK : rv);
546 } 564 }
547 565
(...skipping 19 matching lines...) Expand all
567 CompletionCallback* c = user_write_callback_; 585 CompletionCallback* c = user_write_callback_;
568 user_write_callback_ = NULL; 586 user_write_callback_ = NULL;
569 user_write_buf_ = NULL; 587 user_write_buf_ = NULL;
570 user_write_buf_len_ = 0; 588 user_write_buf_len_ = 0;
571 c->Run(rv); 589 c->Run(rv);
572 } 590 }
573 591
574 void SSLClientSocketMac::OnHandshakeIOComplete(int result) { 592 void SSLClientSocketMac::OnHandshakeIOComplete(int result) {
575 DCHECK(next_handshake_state_ != STATE_NONE); 593 DCHECK(next_handshake_state_ != STATE_NONE);
576 int rv = DoHandshakeLoop(result); 594 int rv = DoHandshakeLoop(result);
577 if (rv != ERR_IO_PENDING) 595 if (rv != ERR_IO_PENDING) {
596 LoadLog::EndEvent(load_log_, LoadLog::TYPE_SSL_CONNECT);
597 load_log_ = NULL;
578 DoConnectCallback(rv); 598 DoConnectCallback(rv);
599 }
579 } 600 }
580 601
581 void SSLClientSocketMac::OnTransportReadComplete(int result) { 602 void SSLClientSocketMac::OnTransportReadComplete(int result) {
582 if (result > 0) { 603 if (result > 0) {
583 char* buffer = 604 char* buffer =
584 &recv_buffer_[recv_buffer_.size() - recv_buffer_tail_slop_]; 605 &recv_buffer_[recv_buffer_.size() - recv_buffer_tail_slop_];
585 memcpy(buffer, read_io_buf_->data(), result); 606 memcpy(buffer, read_io_buf_->data(), result);
586 recv_buffer_tail_slop_ -= result; 607 recv_buffer_tail_slop_ -= result;
587 } 608 }
588 read_io_buf_ = NULL; 609 read_io_buf_ = NULL;
589 610
590 if (next_handshake_state_ != STATE_NONE) { 611 if (next_handshake_state_ != STATE_NONE) {
591 int rv = DoHandshakeLoop(result); 612 int rv = DoHandshakeLoop(result);
592 if (rv != ERR_IO_PENDING) 613 if (rv != ERR_IO_PENDING) {
614 LoadLog::EndEvent(load_log_, LoadLog::TYPE_SSL_CONNECT);
615 load_log_ = NULL;
593 DoConnectCallback(rv); 616 DoConnectCallback(rv);
617 }
594 return; 618 return;
595 } 619 }
596 if (user_read_buf_) { 620 if (user_read_buf_) {
597 if (result < 0) { 621 if (result < 0) {
598 DoReadCallback(result); 622 DoReadCallback(result);
599 return; 623 return;
600 } 624 }
601 int rv = DoPayloadRead(); 625 int rv = DoPayloadRead();
602 if (rv != ERR_IO_PENDING) 626 if (rv != ERR_IO_PENDING)
603 DoReadCallback(rv); 627 DoReadCallback(rv);
(...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after
961 985
962 if (rv < 0 && rv != ERR_IO_PENDING) { 986 if (rv < 0 && rv != ERR_IO_PENDING) {
963 return OSStatusFromNetError(rv); 987 return OSStatusFromNetError(rv);
964 } 988 }
965 989
966 // always lie to our caller 990 // always lie to our caller
967 return noErr; 991 return noErr;
968 } 992 }
969 993
970 } // namespace net 994 } // namespace net
OLDNEW
« no previous file with comments | « net/socket/ssl_client_socket_mac.h ('k') | net/socket/ssl_client_socket_nss.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698