Chromium Code Reviews| OLD | NEW |
|---|---|
| 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/singleton.h" | 8 #include "base/singleton.h" |
| 8 #include "base/string_util.h" | 9 #include "base/string_util.h" |
| 10 #include "net/base/cert_verifier.h" | |
| 9 #include "net/base/io_buffer.h" | 11 #include "net/base/io_buffer.h" |
| 10 #include "net/base/net_errors.h" | 12 #include "net/base/net_errors.h" |
| 11 #include "net/base/ssl_info.h" | 13 #include "net/base/ssl_info.h" |
| 12 | 14 |
| 13 // Welcome to Mac SSL. We've been waiting for you. | 15 // Welcome to Mac SSL. We've been waiting for you. |
| 14 // | 16 // |
| 15 // The Mac SSL implementation is, like the Windows and NSS implementations, a | 17 // The Mac SSL implementation is, like the Windows and NSS implementations, a |
| 16 // giant state machine. This design constraint is due to the asynchronous nature | 18 // giant state machine. This design constraint is due to the asynchronous nature |
| 17 // of our underlying transport mechanism. We can call down to read/write on the | 19 // of our underlying transport mechanism. We can call down to read/write on the |
| 18 // network, but what happens is that either it completes immediately or returns | 20 // network, but what happens is that either it completes immediately or returns |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 269 const std::string& hostname, | 271 const std::string& hostname, |
| 270 const SSLConfig& ssl_config) | 272 const SSLConfig& ssl_config) |
| 271 : io_callback_(this, &SSLClientSocketMac::OnIOComplete), | 273 : io_callback_(this, &SSLClientSocketMac::OnIOComplete), |
| 272 write_callback_(this, &SSLClientSocketMac::OnWriteComplete), | 274 write_callback_(this, &SSLClientSocketMac::OnWriteComplete), |
| 273 transport_(transport_socket), | 275 transport_(transport_socket), |
| 274 hostname_(hostname), | 276 hostname_(hostname), |
| 275 ssl_config_(ssl_config), | 277 ssl_config_(ssl_config), |
| 276 user_callback_(NULL), | 278 user_callback_(NULL), |
| 277 next_state_(STATE_NONE), | 279 next_state_(STATE_NONE), |
| 278 next_io_state_(STATE_NONE), | 280 next_io_state_(STATE_NONE), |
| 279 server_cert_status_(0), | |
| 280 completed_handshake_(false), | 281 completed_handshake_(false), |
| 281 ssl_context_(NULL), | 282 ssl_context_(NULL), |
| 282 pending_send_error_(OK), | 283 pending_send_error_(OK), |
| 283 recv_buffer_head_slop_(0), | 284 recv_buffer_head_slop_(0), |
| 284 recv_buffer_tail_slop_(0) { | 285 recv_buffer_tail_slop_(0) { |
| 285 } | 286 } |
| 286 | 287 |
| 287 SSLClientSocketMac::~SSLClientSocketMac() { | 288 SSLClientSocketMac::~SSLClientSocketMac() { |
| 288 Disconnect(); | 289 Disconnect(); |
| 289 } | 290 } |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 318 return NetErrorFromOSStatus(status); | 319 return NetErrorFromOSStatus(status); |
| 319 | 320 |
| 320 status = SSLSetIOFuncs(ssl_context_, SSLReadCallback, SSLWriteCallback); | 321 status = SSLSetIOFuncs(ssl_context_, SSLReadCallback, SSLWriteCallback); |
| 321 if (status) | 322 if (status) |
| 322 return NetErrorFromOSStatus(status); | 323 return NetErrorFromOSStatus(status); |
| 323 | 324 |
| 324 status = SSLSetConnection(ssl_context_, this); | 325 status = SSLSetConnection(ssl_context_, this); |
| 325 if (status) | 326 if (status) |
| 326 return NetErrorFromOSStatus(status); | 327 return NetErrorFromOSStatus(status); |
| 327 | 328 |
| 328 if (ssl_config_.allowed_bad_certs.empty()) { | 329 // Disable certificate verification within Secure Transport; we'll |
| 329 // We're going to use the default certificate verification that the system | 330 // be handling that ourselves. |
| 330 // does, and accept its answer for the cert status. | 331 status = SSLSetEnableCertVerify(ssl_context_, false); |
| 331 status = SSLSetPeerDomainName(ssl_context_, hostname_.data(), | 332 if (status) |
| 332 hostname_.length()); | 333 return NetErrorFromOSStatus(status); |
| 333 if (status) | |
| 334 return NetErrorFromOSStatus(status); | |
| 335 | |
| 336 // TODO(wtc): for now, always check revocation. | |
| 337 server_cert_status_ = CERT_STATUS_REV_CHECKING_ENABLED; | |
| 338 } else { | |
| 339 // Disable certificate chain validation. We will only allow the certs in | |
| 340 // ssl_config_.allowed_bad_certs. | |
| 341 status = SSLSetEnableCertVerify(ssl_context_, false); | |
| 342 if (status) | |
| 343 return NetErrorFromOSStatus(status); | |
| 344 } | |
| 345 | 334 |
| 346 next_state_ = STATE_HANDSHAKE; | 335 next_state_ = STATE_HANDSHAKE; |
| 347 int rv = DoLoop(OK); | 336 int rv = DoLoop(OK); |
| 348 if (rv == ERR_IO_PENDING) | 337 if (rv == ERR_IO_PENDING) |
| 349 user_callback_ = callback; | 338 user_callback_ = callback; |
| 350 return rv; | 339 return rv; |
| 351 } | 340 } |
| 352 | 341 |
| 353 void SSLClientSocketMac::Disconnect() { | 342 void SSLClientSocketMac::Disconnect() { |
| 354 completed_handshake_ = false; | 343 completed_handshake_ = false; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 423 return rv; | 412 return rv; |
| 424 } | 413 } |
| 425 | 414 |
| 426 void SSLClientSocketMac::GetSSLInfo(SSLInfo* ssl_info) { | 415 void SSLClientSocketMac::GetSSLInfo(SSLInfo* ssl_info) { |
| 427 ssl_info->Reset(); | 416 ssl_info->Reset(); |
| 428 | 417 |
| 429 // set cert | 418 // set cert |
| 430 ssl_info->cert = server_cert_; | 419 ssl_info->cert = server_cert_; |
| 431 | 420 |
| 432 // update status | 421 // update status |
| 433 ssl_info->cert_status = server_cert_status_; | 422 ssl_info->cert_status = server_cert_verify_result_.cert_status; |
| 434 | 423 |
| 435 // security info | 424 // security info |
| 436 SSLCipherSuite suite; | 425 SSLCipherSuite suite; |
| 437 OSStatus status = SSLGetNegotiatedCipher(ssl_context_, &suite); | 426 OSStatus status = SSLGetNegotiatedCipher(ssl_context_, &suite); |
| 438 if (!status) | 427 if (!status) |
| 439 ssl_info->security_bits = KeySizeOfCipherSuite(suite); | 428 ssl_info->security_bits = KeySizeOfCipherSuite(suite); |
| 440 } | 429 } |
| 441 | 430 |
| 442 void SSLClientSocketMac::GetSSLCertRequestInfo( | 431 void SSLClientSocketMac::GetSSLCertRequestInfo( |
| 443 SSLCertRequestInfo* cert_request_info) { | 432 SSLCertRequestInfo* cert_request_info) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 476 DCHECK(next_state_ != STATE_NONE); | 465 DCHECK(next_state_ != STATE_NONE); |
| 477 int rv = last_io_result; | 466 int rv = last_io_result; |
| 478 do { | 467 do { |
| 479 State state = next_state_; | 468 State state = next_state_; |
| 480 next_state_ = STATE_NONE; | 469 next_state_ = STATE_NONE; |
| 481 switch (state) { | 470 switch (state) { |
| 482 case STATE_HANDSHAKE: | 471 case STATE_HANDSHAKE: |
| 483 // Do the SSL/TLS handshake. | 472 // Do the SSL/TLS handshake. |
| 484 rv = DoHandshake(); | 473 rv = DoHandshake(); |
| 485 break; | 474 break; |
| 475 case STATE_VERIFY_CERT: | |
| 476 // Kick off server certificate validation. | |
| 477 rv = DoVerifyCert(); | |
| 478 break; | |
| 479 case STATE_VERIFY_CERT_COMPLETE: | |
| 480 // Check the results of the server certificate validation. | |
| 481 rv = DoVerifyCertComplete(rv); | |
| 482 break; | |
| 486 case STATE_READ_COMPLETE: | 483 case STATE_READ_COMPLETE: |
| 487 // A read off the network is complete; do the paperwork. | 484 // A read off the network is complete; do the paperwork. |
| 488 rv = DoReadComplete(rv); | 485 rv = DoReadComplete(rv); |
| 489 break; | 486 break; |
| 490 case STATE_PAYLOAD_READ: | 487 case STATE_PAYLOAD_READ: |
| 491 // Do a read of data from the network. | 488 // Do a read of data from the network. |
| 492 rv = DoPayloadRead(); | 489 rv = DoPayloadRead(); |
| 493 break; | 490 break; |
| 494 case STATE_PAYLOAD_WRITE: | 491 case STATE_PAYLOAD_WRITE: |
| 495 // Do a write of data to the network. | 492 // Do a write of data to the network. |
| 496 rv = DoPayloadWrite(); | 493 rv = DoPayloadWrite(); |
| 497 break; | 494 break; |
| 498 default: | 495 default: |
| 499 rv = ERR_UNEXPECTED; | 496 rv = ERR_UNEXPECTED; |
| 500 NOTREACHED() << "unexpected state"; | 497 NOTREACHED() << "unexpected state"; |
| 501 break; | 498 break; |
| 502 } | 499 } |
| 503 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); | 500 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE); |
| 504 return rv; | 501 return rv; |
| 505 } | 502 } |
| 506 | 503 |
| 507 int SSLClientSocketMac::DoHandshake() { | 504 int SSLClientSocketMac::DoHandshake() { |
| 508 OSStatus status = SSLHandshake(ssl_context_); | 505 OSStatus status = SSLHandshake(ssl_context_); |
| 509 int net_error = NetErrorFromOSStatus(status); | |
| 510 | 506 |
| 511 if (status == errSSLWouldBlock) { | 507 if (status == errSSLWouldBlock) |
| 512 next_state_ = STATE_HANDSHAKE; | 508 next_state_ = STATE_HANDSHAKE; |
| 513 } else if (status == noErr) { | |
| 514 completed_handshake_ = true; // We have a connection. | |
| 515 | 509 |
| 510 if (status == noErr) { | |
| 516 server_cert_ = GetServerCert(ssl_context_); | 511 server_cert_ = GetServerCert(ssl_context_); |
| 517 DCHECK(server_cert_); | 512 if (!server_cert_) |
| 518 if (!ssl_config_.allowed_bad_certs.empty()) { | 513 return ERR_UNEXPECTED; |
| 519 // Check server_cert_ because SecureTransport didn't verify it. | 514 next_state_ = STATE_VERIFY_CERT; |
| 520 // TODO(wtc): If server_cert_ is not one of the allowed bad certificates, | |
| 521 // we should verify server_cert_ ourselves. Since we don't know how to | |
| 522 // do that yet, treat it as an invalid certificate. | |
| 523 net_error = ERR_CERT_INVALID; | |
| 524 server_cert_status_ |= CERT_STATUS_INVALID; | |
| 525 | |
| 526 for (size_t i = 0; i < ssl_config_.allowed_bad_certs.size(); ++i) { | |
| 527 if (server_cert_ == ssl_config_.allowed_bad_certs[i].cert) { | |
| 528 net_error = OK; | |
| 529 server_cert_status_ = ssl_config_.allowed_bad_certs[i].cert_status; | |
| 530 break; | |
| 531 } | |
| 532 } | |
| 533 } | |
| 534 } else if (IsCertificateError(net_error)) { | |
| 535 server_cert_ = GetServerCert(ssl_context_); | |
| 536 DCHECK(server_cert_); | |
| 537 server_cert_status_ |= MapNetErrorToCertStatus(net_error); | |
| 538 } | 515 } |
| 539 | 516 |
| 540 return net_error; | 517 return NetErrorFromOSStatus(status); |
| 518 } | |
| 519 | |
| 520 int SSLClientSocketMac::DoVerifyCert() { | |
| 521 next_state_ = STATE_VERIFY_CERT_COMPLETE; | |
| 522 | |
| 523 if (!server_cert_) | |
| 524 return ERR_UNEXPECTED; | |
| 525 | |
| 526 // Add each of the intermediate certificates in the server's chain to the | |
| 527 // server's X509Certificate object. This makes them available to | |
| 528 // X509Certificate::Verify() for chain building. | |
| 529 CFArrayRef certs; | |
| 530 OSStatus status = SSLCopyPeerCertificates(ssl_context_, &certs); | |
| 531 if (status != noErr || !certs) | |
| 532 return ERR_UNEXPECTED; | |
| 533 scoped_cftyperef<CFArrayRef> scoped_certs(certs); | |
| 534 CFIndex certs_length = CFArrayGetCount(certs); | |
| 535 for (CFIndex i = 1; i < certs_length; ++i) { | |
| 536 SecCertificateRef cert_ref = reinterpret_cast<SecCertificateRef>( | |
| 537 const_cast<void*>(CFArrayGetValueAtIndex(certs, i))); | |
| 538 server_cert_->AddIntermediateCertificate(cert_ref); | |
| 539 } | |
| 540 | |
| 541 // TODO(hawk): set flags based on the SSLConfig, once SSLConfig is | |
|
wtc
2009/08/27 00:14:18
Nit: the second "SSLConfig" should be "SSLConfigSe
| |
| 542 // fully fleshed out on Mac OS X. | |
| 543 int flags = 0; | |
| 544 verifier_.reset(new CertVerifier); | |
| 545 return verifier_->Verify(server_cert_, hostname_, flags, | |
| 546 &server_cert_verify_result_, &io_callback_); | |
| 547 } | |
| 548 | |
| 549 int SSLClientSocketMac::DoVerifyCertComplete(int result) { | |
| 550 DCHECK(verifier_.get()); | |
| 551 verifier_.reset(); | |
| 552 | |
| 553 if (IsCertificateError(result) && ssl_config_.IsAllowedBadCert(server_cert_)) | |
| 554 result = OK; | |
| 555 | |
| 556 completed_handshake_ = true; | |
| 557 DCHECK(next_state_ == STATE_NONE); | |
| 558 | |
| 559 return result; | |
| 541 } | 560 } |
| 542 | 561 |
| 543 int SSLClientSocketMac::DoReadComplete(int result) { | 562 int SSLClientSocketMac::DoReadComplete(int result) { |
| 544 if (result < 0) { | 563 if (result < 0) { |
| 545 read_io_buf_ = NULL; | 564 read_io_buf_ = NULL; |
| 546 return result; | 565 return result; |
| 547 } | 566 } |
| 548 | 567 |
| 549 char* buffer = &recv_buffer_[recv_buffer_.size() - recv_buffer_tail_slop_]; | 568 char* buffer = &recv_buffer_[recv_buffer_.size() - recv_buffer_tail_slop_]; |
| 550 memcpy(buffer, read_io_buf_->data(), result); | 569 memcpy(buffer, read_io_buf_->data(), result); |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 801 | 820 |
| 802 if (rv < 0 && rv != ERR_IO_PENDING) { | 821 if (rv < 0 && rv != ERR_IO_PENDING) { |
| 803 return OSStatusFromNetError(rv); | 822 return OSStatusFromNetError(rv); |
| 804 } | 823 } |
| 805 | 824 |
| 806 // always lie to our caller | 825 // always lie to our caller |
| 807 return noErr; | 826 return noErr; |
| 808 } | 827 } |
| 809 | 828 |
| 810 } // namespace net | 829 } // namespace net |
| OLD | NEW |