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

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

Issue 174102: Enable SSLClientSocketTest unit tests on Mac OS X by implementing our own cer... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 3 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
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/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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698