blob: 2fe97436434b16bdbdc2b556aa6972d940cf7849 [file] [log] [blame]
[email protected]0b45559b2009-06-12 21:45:111// Copyright (c) 2008-2009 The Chromium Authors. All rights reserved.
[email protected]b75523f2008-10-17 14:49:072// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]f7984fc62009-06-22 23:26:445#include "net/socket/ssl_client_socket_mac.h"
[email protected]b75523f2008-10-17 14:49:076
7#include "base/singleton.h"
8#include "base/string_util.h"
[email protected]597cf6e2009-05-29 09:43:269#include "net/base/io_buffer.h"
[email protected]b75523f2008-10-17 14:49:0710#include "net/base/net_errors.h"
11#include "net/base/ssl_info.h"
12
13// Welcome to Mac SSL. We've been waiting for you.
14//
15// 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
17// 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
19// saying that we'll get a callback sometime in the future. In that case, we
20// have to return to our caller but pick up where we left off when we
21// resume. Thus the fun.
22//
23// On Windows, we use Security Contexts, which are driven by us. We fetch data
24// from the network, we call the context to decrypt the data, and so on. On the
25// Mac, however, we provide Secure Transport with callbacks to get data from the
26// network, and it calls us back to fetch the data from the network for
27// it. Therefore, there are different sets of states in our respective state
28// machines, fewer on the Mac because Secure Transport keeps a lot of its own
29// state. The discussion about what each of the states means lives in comments
30// in the DoLoop() function.
31//
32// Secure Transport is designed for use by either blocking or non-blocking
33// network I/O. If, for example, you called SSLRead() to fetch data, Secure
34// Transport will, unless it has some cached data, issue a read to your network
35// callback read function to fetch it some more encrypted data. It's expecting
36// one of two things. If your function is hooked up to a blocking source, then
37// it'll block pending receipt of the data from the other end. That's fine, as
38// when you return with the data, Secure Transport will do its thing. On the
39// other hand, suppose that your socket is non-blocking and tells your function
40// that it would block. Then you let Secure Transport know, and it'll tell the
41// original caller that it would have blocked and that they need to call it
42// "later."
43//
44// When's "later," though? We have fully-asynchronous networking, so we get a
45// callback when our data's ready. But Secure Transport has no way for us to
46// tell it that data has arrived, so we must re-execute the call that triggered
47// the I/O (we rely on our state machine to do this). When we do so Secure
48// Transport will ask once again for the data. Chances are that it'll be the
49// same request as the previous time, but that's not actually guaranteed. But as
50// long as we buffer what we have and keep track of where we were, it works
51// quite well.
52//
53// Except for network writes. They shoot this plan straight to hell.
54//
55// Faking a blocking connection with an asynchronous connection (theoretically
56// more powerful) simply doesn't work for writing. Suppose that Secure Transport
57// requests a write of data to the network. With blocking I/O, we'd just block
58// until the write completed, and with non-blocking I/O we'd know how many bytes
59// we wrote before we would have blocked. But with the asynchronous I/O, the
60// transport underneath us can tell us that it'll let us know sometime "later"
61// whether or not things succeeded, and how many bytes were written. What do we
62// return to Secure Transport? We can't return a byte count, but we can't return
63// "later" as we're not guaranteed to be called in the future with the same data
64// to write.
65//
66// So, like in any good relationship, we're forced to lie. Whenever Secure
67// Transport asks for data to be written, we take it all and lie about it always
68// being written. We spin in a loop (see SSLWriteCallback() and
69// OnWriteComplete()) independent of the main state machine writing the data to
70// the network, and get the data out. The main consequence of this independence
71// from the state machine is that we require a full-duplex transport underneath
72// us since we can't use it to keep our reading and writing
73// straight. Fortunately, the NSS implementation also has this issue to deal
74// with, so we share the same Libevent-based full-duplex TCP socket.
75//
76// A side comment on return values might be in order. Those who haven't taken
77// the time to read the documentation (ahem, header comments) in our various
78// files might be a bit surprised to see result values being treated as both
79// lengths and errors. Like Shimmer, they are both. In both the case of
80// immediate results as well as results returned in callbacks, a negative return
81// value indicates an error, a zero return value indicates end-of-stream (for
82// reads), and a positive return value indicates the number of bytes read or
83// written. Thus, many functions start off with |if (result < 0) return
84// result;|. That gets the error condition out of the way, and from that point
85// forward the result can be treated as a length.
86
87namespace net {
88
89namespace {
90
91int NetErrorFromOSStatus(OSStatus status) {
92 switch (status) {
93 case errSSLWouldBlock:
94 return ERR_IO_PENDING;
95 case errSSLIllegalParam:
96 case errSSLBadCipherSuite:
97 case errSSLBadConfiguration:
98 return ERR_INVALID_ARGUMENT;
99 case errSSLClosedNoNotify:
100 return ERR_CONNECTION_RESET;
101 case errSSLConnectionRefused:
102 return ERR_CONNECTION_REFUSED;
103 case errSSLClosedAbort:
104 return ERR_CONNECTION_ABORTED;
105 case errSSLInternal:
106 case errSSLCrypto:
107 case errSSLFatalAlert:
108 case errSSLProtocol:
109 return ERR_SSL_PROTOCOL_ERROR;
110 case errSSLHostNameMismatch:
111 return ERR_CERT_COMMON_NAME_INVALID;
112 case errSSLCertExpired:
113 case errSSLCertNotYetValid:
114 return ERR_CERT_DATE_INVALID;
115 case errSSLNoRootCert:
116 case errSSLUnknownRootCert:
117 return ERR_CERT_AUTHORITY_INVALID;
118 case errSSLXCertChainInvalid:
119 case errSSLBadCert:
120 return ERR_CERT_INVALID;
121 case errSSLPeerCertRevoked:
122 return ERR_CERT_REVOKED;
[email protected]f0a51fb52009-03-05 12:46:38123
[email protected]b75523f2008-10-17 14:49:07124 case errSSLClosedGraceful:
125 case noErr:
126 return OK;
[email protected]f0a51fb52009-03-05 12:46:38127
[email protected]b75523f2008-10-17 14:49:07128 case errSSLBadRecordMac:
129 case errSSLBufferOverflow:
130 case errSSLDecryptionFail:
131 case errSSLModuleAttach:
132 case errSSLNegotiation:
133 case errSSLRecordOverflow:
134 case errSSLSessionNotFound:
135 default:
136 LOG(WARNING) << "Unknown error " << status <<
137 " mapped to net::ERR_FAILED";
138 return ERR_FAILED;
139 }
140}
141
142OSStatus OSStatusFromNetError(int net_error) {
143 switch (net_error) {
144 case ERR_IO_PENDING:
145 return errSSLWouldBlock;
146 case ERR_INTERNET_DISCONNECTED:
147 case ERR_TIMED_OUT:
148 case ERR_CONNECTION_ABORTED:
149 case ERR_CONNECTION_RESET:
150 case ERR_CONNECTION_REFUSED:
151 case ERR_ADDRESS_UNREACHABLE:
152 case ERR_ADDRESS_INVALID:
153 return errSSLClosedAbort;
154 case OK:
155 return noErr;
156 default:
157 LOG(WARNING) << "Unknown error " << net_error <<
158 " mapped to errSSLIllegalParam";
159 return errSSLIllegalParam;
160 }
161}
162
[email protected]e1593392008-10-20 19:46:33163// Converts from a cipher suite to its key size. If the suite is marked with a
164// **, it's not actually implemented in Secure Transport and won't be returned
165// (but we'll code for it anyway). The reference here is
166// http://www.opensource.apple.com/darwinsource/10.5.5/libsecurity_ssl-32463/lib/cipherSpecs.c
167// Seriously, though, there has to be an API for this, but I can't find one.
168// Anybody?
169int KeySizeOfCipherSuite(SSLCipherSuite suite) {
170 switch (suite) {
171 // SSL 2 only
[email protected]f0a51fb52009-03-05 12:46:38172
[email protected]e1593392008-10-20 19:46:33173 case SSL_RSA_WITH_DES_CBC_MD5:
174 return 56;
175 case SSL_RSA_WITH_3DES_EDE_CBC_MD5:
176 return 112;
177 case SSL_RSA_WITH_RC2_CBC_MD5:
178 case SSL_RSA_WITH_IDEA_CBC_MD5: // **
179 return 128;
180 case SSL_NO_SUCH_CIPHERSUITE: // **
181 return 0;
[email protected]f0a51fb52009-03-05 12:46:38182
[email protected]e1593392008-10-20 19:46:33183 // SSL 2, 3, TLS
[email protected]f0a51fb52009-03-05 12:46:38184
[email protected]e1593392008-10-20 19:46:33185 case SSL_NULL_WITH_NULL_NULL:
186 case SSL_RSA_WITH_NULL_MD5:
187 case SSL_RSA_WITH_NULL_SHA: // **
188 case SSL_FORTEZZA_DMS_WITH_NULL_SHA: // **
189 return 0;
190 case SSL_RSA_EXPORT_WITH_RC4_40_MD5:
191 case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5:
192 case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA:
193 case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA: // **
194 case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA: // **
195 case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA:
196 case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA:
197 case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5:
198 case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA:
199 return 40;
200 case SSL_RSA_WITH_DES_CBC_SHA:
201 case SSL_DH_DSS_WITH_DES_CBC_SHA: // **
202 case SSL_DH_RSA_WITH_DES_CBC_SHA: // **
203 case SSL_DHE_DSS_WITH_DES_CBC_SHA:
204 case SSL_DHE_RSA_WITH_DES_CBC_SHA:
205 case SSL_DH_anon_WITH_DES_CBC_SHA:
206 return 56;
207 case SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA: // **
208 return 80;
209 case SSL_RSA_WITH_3DES_EDE_CBC_SHA:
210 case SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA: // **
211 case SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA: // **
212 case SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
213 case SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
214 case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA:
215 return 112;
216 case SSL_RSA_WITH_RC4_128_MD5:
217 case SSL_RSA_WITH_RC4_128_SHA:
218 case SSL_RSA_WITH_IDEA_CBC_SHA: // **
219 case SSL_DH_anon_WITH_RC4_128_MD5:
220 return 128;
[email protected]f0a51fb52009-03-05 12:46:38221
[email protected]e1593392008-10-20 19:46:33222 // TLS AES options (see RFC 3268)
[email protected]f0a51fb52009-03-05 12:46:38223
[email protected]e1593392008-10-20 19:46:33224 case TLS_RSA_WITH_AES_128_CBC_SHA:
225 case TLS_DH_DSS_WITH_AES_128_CBC_SHA: // **
226 case TLS_DH_RSA_WITH_AES_128_CBC_SHA: // **
227 case TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
228 case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
229 case TLS_DH_anon_WITH_AES_128_CBC_SHA:
230 return 128;
231 case TLS_RSA_WITH_AES_256_CBC_SHA:
232 case TLS_DH_DSS_WITH_AES_256_CBC_SHA: // **
233 case TLS_DH_RSA_WITH_AES_256_CBC_SHA: // **
234 case TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
235 case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
236 case TLS_DH_anon_WITH_AES_256_CBC_SHA:
237 return 256;
[email protected]f0a51fb52009-03-05 12:46:38238
[email protected]e1593392008-10-20 19:46:33239 default:
240 return -1;
241 }
242}
243
[email protected]127017872009-08-13 17:54:42244// Returns the server's certificate. The caller must release a reference
245// to the return value when done. Returns NULL on failure.
246X509Certificate* GetServerCert(SSLContextRef ssl_context) {
247 CFArrayRef certs;
248 OSStatus status = SSLCopyPeerCertificates(ssl_context, &certs);
249 if (status != noErr)
250 return NULL;
251
252 DCHECK_GT(CFArrayGetCount(certs), 0);
253
254 SecCertificateRef server_cert = static_cast<SecCertificateRef>(
255 const_cast<void*>(CFArrayGetValueAtIndex(certs, 0)));
256 CFRetain(server_cert);
257 CFRelease(certs);
258 return X509Certificate::CreateFromHandle(
259 server_cert, X509Certificate::SOURCE_FROM_NETWORK);
260}
261
[email protected]b75523f2008-10-17 14:49:07262} // namespace
263
264//-----------------------------------------------------------------------------
265
266SSLClientSocketMac::SSLClientSocketMac(ClientSocket* transport_socket,
267 const std::string& hostname,
268 const SSLConfig& ssl_config)
269 : io_callback_(this, &SSLClientSocketMac::OnIOComplete),
270 write_callback_(this, &SSLClientSocketMac::OnWriteComplete),
271 transport_(transport_socket),
272 hostname_(hostname),
273 ssl_config_(ssl_config),
274 user_callback_(NULL),
275 next_state_(STATE_NONE),
276 next_io_state_(STATE_NONE),
[email protected]e1593392008-10-20 19:46:33277 server_cert_status_(0),
[email protected]b75523f2008-10-17 14:49:07278 completed_handshake_(false),
279 ssl_context_(NULL),
280 pending_send_error_(OK),
281 recv_buffer_head_slop_(0),
282 recv_buffer_tail_slop_(0) {
283}
284
285SSLClientSocketMac::~SSLClientSocketMac() {
286 Disconnect();
287}
288
289int SSLClientSocketMac::Connect(CompletionCallback* callback) {
290 DCHECK(transport_.get());
291 DCHECK(next_state_ == STATE_NONE);
292 DCHECK(!user_callback_);
293
[email protected]0ef0bcf2009-04-03 20:39:43294 OSStatus status = noErr;
295
296 status = SSLNewContext(false, &ssl_context_);
297 if (status)
298 return NetErrorFromOSStatus(status);
299
300 status = SSLSetProtocolVersionEnabled(ssl_context_,
301 kSSLProtocol2,
302 ssl_config_.ssl2_enabled);
303 if (status)
304 return NetErrorFromOSStatus(status);
305
306 status = SSLSetProtocolVersionEnabled(ssl_context_,
307 kSSLProtocol3,
308 ssl_config_.ssl3_enabled);
309 if (status)
310 return NetErrorFromOSStatus(status);
311
312 status = SSLSetProtocolVersionEnabled(ssl_context_,
313 kTLSProtocol1,
314 ssl_config_.tls1_enabled);
315 if (status)
316 return NetErrorFromOSStatus(status);
317
318 status = SSLSetIOFuncs(ssl_context_, SSLReadCallback, SSLWriteCallback);
319 if (status)
320 return NetErrorFromOSStatus(status);
321
322 status = SSLSetConnection(ssl_context_, this);
323 if (status)
324 return NetErrorFromOSStatus(status);
325
[email protected]127017872009-08-13 17:54:42326 if (ssl_config_.allowed_bad_certs.empty()) {
327 // We're going to use the default certificate verification that the system
328 // does, and accept its answer for the cert status.
329 status = SSLSetPeerDomainName(ssl_context_, hostname_.data(),
330 hostname_.length());
331 if (status)
332 return NetErrorFromOSStatus(status);
333
334 // TODO(wtc): for now, always check revocation.
335 server_cert_status_ = CERT_STATUS_REV_CHECKING_ENABLED;
336 } else {
337 // Disable certificate chain validation. We will only allow the certs in
338 // ssl_config_.allowed_bad_certs.
339 status = SSLSetEnableCertVerify(ssl_context_, false);
340 if (status)
341 return NetErrorFromOSStatus(status);
342 }
[email protected]0ef0bcf2009-04-03 20:39:43343
344 next_state_ = STATE_HANDSHAKE;
[email protected]b75523f2008-10-17 14:49:07345 int rv = DoLoop(OK);
346 if (rv == ERR_IO_PENDING)
347 user_callback_ = callback;
348 return rv;
349}
350
[email protected]b75523f2008-10-17 14:49:07351void SSLClientSocketMac::Disconnect() {
352 completed_handshake_ = false;
[email protected]f0a51fb52009-03-05 12:46:38353
[email protected]b75523f2008-10-17 14:49:07354 if (ssl_context_) {
355 SSLClose(ssl_context_);
356 SSLDisposeContext(ssl_context_);
357 ssl_context_ = NULL;
358 }
[email protected]f0a51fb52009-03-05 12:46:38359
[email protected]b75523f2008-10-17 14:49:07360 transport_->Disconnect();
361}
362
363bool SSLClientSocketMac::IsConnected() const {
364 // Ideally, we should also check if we have received the close_notify alert
365 // message from the server, and return false in that case. We're not doing
366 // that, so this function may return a false positive. Since the upper
367 // layer (HttpNetworkTransaction) needs to handle a persistent connection
368 // closed by the server when we send a request anyway, a false positive in
369 // exchange for simpler code is a good trade-off.
370 return completed_handshake_ && transport_->IsConnected();
371}
372
[email protected]b2197852009-02-19 23:27:33373bool SSLClientSocketMac::IsConnectedAndIdle() const {
374 // Unlike IsConnected, this method doesn't return a false positive.
375 //
376 // Strictly speaking, we should check if we have received the close_notify
377 // alert message from the server, and return false in that case. Although
378 // the close_notify alert message means EOF in the SSL layer, it is just
379 // bytes to the transport layer below, so transport_->IsConnectedAndIdle()
380 // returns the desired false when we receive close_notify.
381 return completed_handshake_ && transport_->IsConnectedAndIdle();
382}
383
[email protected]ffeb0882009-04-30 21:51:25384int SSLClientSocketMac::Read(IOBuffer* buf, int buf_len,
[email protected]b75523f2008-10-17 14:49:07385 CompletionCallback* callback) {
386 DCHECK(completed_handshake_);
387 DCHECK(next_state_ == STATE_NONE);
388 DCHECK(!user_callback_);
[email protected]ffeb0882009-04-30 21:51:25389 DCHECK(!user_buf_);
[email protected]b75523f2008-10-17 14:49:07390
391 user_buf_ = buf;
392 user_buf_len_ = buf_len;
393
394 next_state_ = STATE_PAYLOAD_READ;
395 int rv = DoLoop(OK);
[email protected]ffeb0882009-04-30 21:51:25396 if (rv == ERR_IO_PENDING) {
[email protected]b75523f2008-10-17 14:49:07397 user_callback_ = callback;
[email protected]ffeb0882009-04-30 21:51:25398 } else {
399 user_buf_ = NULL;
400 }
[email protected]b75523f2008-10-17 14:49:07401 return rv;
402}
403
[email protected]ffeb0882009-04-30 21:51:25404int SSLClientSocketMac::Write(IOBuffer* buf, int buf_len,
[email protected]b75523f2008-10-17 14:49:07405 CompletionCallback* callback) {
406 DCHECK(completed_handshake_);
407 DCHECK(next_state_ == STATE_NONE);
408 DCHECK(!user_callback_);
[email protected]ffeb0882009-04-30 21:51:25409 DCHECK(!user_buf_);
[email protected]b75523f2008-10-17 14:49:07410
[email protected]ffeb0882009-04-30 21:51:25411 user_buf_ = buf;
[email protected]b75523f2008-10-17 14:49:07412 user_buf_len_ = buf_len;
[email protected]f0a51fb52009-03-05 12:46:38413
[email protected]b75523f2008-10-17 14:49:07414 next_state_ = STATE_PAYLOAD_WRITE;
415 int rv = DoLoop(OK);
[email protected]ffeb0882009-04-30 21:51:25416 if (rv == ERR_IO_PENDING) {
[email protected]b75523f2008-10-17 14:49:07417 user_callback_ = callback;
[email protected]ffeb0882009-04-30 21:51:25418 } else {
419 user_buf_ = NULL;
420 }
[email protected]b75523f2008-10-17 14:49:07421 return rv;
422}
423
424void SSLClientSocketMac::GetSSLInfo(SSLInfo* ssl_info) {
[email protected]e1593392008-10-20 19:46:33425 ssl_info->Reset();
[email protected]f0a51fb52009-03-05 12:46:38426
[email protected]e1593392008-10-20 19:46:33427 // set cert
[email protected]127017872009-08-13 17:54:42428 ssl_info->cert = server_cert_;
[email protected]f0a51fb52009-03-05 12:46:38429
[email protected]e1593392008-10-20 19:46:33430 // update status
431 ssl_info->cert_status = server_cert_status_;
[email protected]f0a51fb52009-03-05 12:46:38432
[email protected]e1593392008-10-20 19:46:33433 // security info
434 SSLCipherSuite suite;
[email protected]127017872009-08-13 17:54:42435 OSStatus status = SSLGetNegotiatedCipher(ssl_context_, &suite);
[email protected]e1593392008-10-20 19:46:33436 if (!status)
437 ssl_info->security_bits = KeySizeOfCipherSuite(suite);
[email protected]b75523f2008-10-17 14:49:07438}
[email protected]f0a51fb52009-03-05 12:46:38439
[email protected]0b45559b2009-06-12 21:45:11440void SSLClientSocketMac::GetSSLCertRequestInfo(
441 SSLCertRequestInfo* cert_request_info) {
442 // TODO(wtc): implement this.
443}
444
[email protected]b75523f2008-10-17 14:49:07445void SSLClientSocketMac::DoCallback(int rv) {
446 DCHECK(rv != ERR_IO_PENDING);
447 DCHECK(user_callback_);
448
449 // since Run may result in Read being called, clear user_callback_ up front.
450 CompletionCallback* c = user_callback_;
451 user_callback_ = NULL;
[email protected]ffeb0882009-04-30 21:51:25452 user_buf_ = NULL;
[email protected]b75523f2008-10-17 14:49:07453 c->Run(rv);
454}
455
456void SSLClientSocketMac::OnIOComplete(int result) {
457 if (next_io_state_ != STATE_NONE) {
458 State next_state = next_state_;
459 next_state_ = next_io_state_;
460 next_io_state_ = STATE_NONE;
461 result = DoLoop(result);
462 next_state_ = next_state;
463 }
464 if (next_state_ != STATE_NONE) {
465 int rv = DoLoop(result);
466 if (rv != ERR_IO_PENDING)
467 DoCallback(rv);
468 }
469}
470
471// This is the main loop driving the state machine. Most calls coming from the
472// outside just set up a few variables and jump into here.
473int SSLClientSocketMac::DoLoop(int last_io_result) {
474 DCHECK(next_state_ != STATE_NONE);
475 int rv = last_io_result;
476 do {
477 State state = next_state_;
478 next_state_ = STATE_NONE;
479 switch (state) {
[email protected]b75523f2008-10-17 14:49:07480 case STATE_HANDSHAKE:
481 // Do the SSL/TLS handshake.
482 rv = DoHandshake();
483 break;
484 case STATE_READ_COMPLETE:
485 // A read off the network is complete; do the paperwork.
486 rv = DoReadComplete(rv);
487 break;
488 case STATE_PAYLOAD_READ:
489 // Do a read of data from the network.
490 rv = DoPayloadRead();
491 break;
492 case STATE_PAYLOAD_WRITE:
493 // Do a write of data to the network.
494 rv = DoPayloadWrite();
495 break;
496 default:
497 rv = ERR_UNEXPECTED;
498 NOTREACHED() << "unexpected state";
499 break;
500 }
501 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
502 return rv;
503}
504
[email protected]b75523f2008-10-17 14:49:07505int SSLClientSocketMac::DoHandshake() {
506 OSStatus status = SSLHandshake(ssl_context_);
[email protected]e1593392008-10-20 19:46:33507 int net_error = NetErrorFromOSStatus(status);
[email protected]f0a51fb52009-03-05 12:46:38508
[email protected]127017872009-08-13 17:54:42509 if (status == errSSLWouldBlock) {
510 next_state_ = STATE_HANDSHAKE;
511 } else if (status == noErr) {
512 completed_handshake_ = true; // We have a connection.
[email protected]f0a51fb52009-03-05 12:46:38513
[email protected]127017872009-08-13 17:54:42514 server_cert_ = GetServerCert(ssl_context_);
515 DCHECK(server_cert_);
516 if (!ssl_config_.allowed_bad_certs.empty()) {
517 // Check server_cert_ because SecureTransport didn't verify it.
518 // TODO(wtc): If server_cert_ is not one of the allowed bad certificates,
519 // we should verify server_cert_ ourselves. Since we don't know how to
520 // do that yet, treat it as an invalid certificate.
521 net_error = ERR_CERT_INVALID;
522 server_cert_status_ |= CERT_STATUS_INVALID;
523
524 for (size_t i = 0; i < ssl_config_.allowed_bad_certs.size(); ++i) {
525 if (server_cert_ == ssl_config_.allowed_bad_certs[i].cert) {
526 net_error = OK;
527 server_cert_status_ = ssl_config_.allowed_bad_certs[i].cert_status;
528 break;
529 }
530 }
531 }
532 } else if (IsCertStatusError(net_error)) {
533 server_cert_ = GetServerCert(ssl_context_);
534 DCHECK(server_cert_);
[email protected]dedb59432009-02-03 16:51:15535 server_cert_status_ |= MapNetErrorToCertStatus(net_error);
[email protected]127017872009-08-13 17:54:42536 }
[email protected]f0a51fb52009-03-05 12:46:38537
[email protected]e1593392008-10-20 19:46:33538 return net_error;
[email protected]b75523f2008-10-17 14:49:07539}
540
541int SSLClientSocketMac::DoReadComplete(int result) {
[email protected]ffeb0882009-04-30 21:51:25542 if (result < 0) {
543 read_io_buf_ = NULL;
[email protected]b75523f2008-10-17 14:49:07544 return result;
[email protected]ffeb0882009-04-30 21:51:25545 }
546
547 char* buffer = &recv_buffer_[recv_buffer_.size() - recv_buffer_tail_slop_];
548 memcpy(buffer, read_io_buf_->data(), result);
549 read_io_buf_ = NULL;
[email protected]f0a51fb52009-03-05 12:46:38550
[email protected]b75523f2008-10-17 14:49:07551 recv_buffer_tail_slop_ -= result;
[email protected]f0a51fb52009-03-05 12:46:38552
[email protected]b75523f2008-10-17 14:49:07553 return result;
554}
555
556void SSLClientSocketMac::OnWriteComplete(int result) {
557 if (result < 0) {
558 pending_send_error_ = result;
559 return;
560 }
[email protected]f0a51fb52009-03-05 12:46:38561
[email protected]b75523f2008-10-17 14:49:07562 send_buffer_.erase(send_buffer_.begin(),
563 send_buffer_.begin() + result);
[email protected]f0a51fb52009-03-05 12:46:38564
[email protected]b75523f2008-10-17 14:49:07565 if (!send_buffer_.empty())
566 SSLWriteCallback(this, NULL, NULL);
567}
568
569int SSLClientSocketMac::DoPayloadRead() {
[email protected]e05c55d2009-08-06 18:21:14570 size_t processed = 0;
[email protected]b75523f2008-10-17 14:49:07571 OSStatus status = SSLRead(ssl_context_,
[email protected]ffeb0882009-04-30 21:51:25572 user_buf_->data(),
[email protected]b75523f2008-10-17 14:49:07573 user_buf_len_,
574 &processed);
[email protected]f0a51fb52009-03-05 12:46:38575
[email protected]b75523f2008-10-17 14:49:07576 // There's a subtle difference here in semantics of the "would block" errors.
577 // In our code, ERR_IO_PENDING means the whole operation is async, while
578 // errSSLWouldBlock means that the stream isn't ending (and is often returned
579 // along with partial data). So even though "would block" is returned, if we
580 // have data, let's just return it.
[email protected]f0a51fb52009-03-05 12:46:38581
[email protected]e05c55d2009-08-06 18:21:14582 if (processed > 0)
[email protected]b75523f2008-10-17 14:49:07583 return processed;
[email protected]e05c55d2009-08-06 18:21:14584
585 if (status == errSSLClosedNoNotify) {
586 // TODO(wtc): Unless we have received the close_notify alert, we need to
587 // return an error code indicating that the SSL connection ended
588 // uncleanly, a potential truncation attack. See http://crbug.com/18586.
589 return OK;
[email protected]b75523f2008-10-17 14:49:07590 }
[email protected]f0a51fb52009-03-05 12:46:38591
[email protected]e05c55d2009-08-06 18:21:14592 if (status == errSSLWouldBlock)
[email protected]b75523f2008-10-17 14:49:07593 next_state_ = STATE_PAYLOAD_READ;
[email protected]f0a51fb52009-03-05 12:46:38594
[email protected]b75523f2008-10-17 14:49:07595 return NetErrorFromOSStatus(status);
596}
597
598int SSLClientSocketMac::DoPayloadWrite() {
[email protected]e05c55d2009-08-06 18:21:14599 size_t processed = 0;
[email protected]b75523f2008-10-17 14:49:07600 OSStatus status = SSLWrite(ssl_context_,
[email protected]ffeb0882009-04-30 21:51:25601 user_buf_->data(),
[email protected]b75523f2008-10-17 14:49:07602 user_buf_len_,
603 &processed);
[email protected]f0a51fb52009-03-05 12:46:38604
[email protected]b75523f2008-10-17 14:49:07605 if (processed > 0)
606 return processed;
[email protected]f0a51fb52009-03-05 12:46:38607
[email protected]b75523f2008-10-17 14:49:07608 return NetErrorFromOSStatus(status);
609}
610
611// Handling the reading from the network is one of those things that should be
612// simpler than it is. Ideally, we'd have some kind of ring buffer. For now, a
613// std::vector<char> will have to do.
614//
615// The need for a buffer at all comes from the difference between an
616// asynchronous connection (which is what we have) and a non-blocking connection
617// (which is what we fake for Secure Transport). When Secure Transport calls us
618// to read data, we call our underlying transport, which will likely tell us
619// that it'll do a callback. When that happens, we need to tell Secure Transport
620// that we've "blocked". When the callback happens, we have a chunk of data that
621// we need to feed to Secure Transport, but it's not interested. It'll ask for
622// it again when we call it again, so we need to hold on to the data.
623//
624// Why keep our own buffer? Well, when we execute a read and the underlying
625// transport says that it'll do a callback, it keeps the pointer to the
626// buffer. We can't pass it the buffer that Secure Transport gave us to fill, as
627// we can't guarantee its lifetime.
628//
629// The basic idea, then, is this: we have a buffer filled with the data that
630// we've read from the network but haven't given to Secure Transport
631// yet. Whenever we read from the network the first thing we do is ensure we
632// have enough room in the buffer for the read. We enlarge the buffer to be big
633// enough to hold both our existing data and the new data, and then we mark the
634// extra space at the end as "tail slop." Slop is just space at the ends of the
635// buffer that's going to be used for data but isn't (yet). A diagram:
636//
637// +--------------------------------------+--------------------------------+
638// | existing good data ~~~~~~~~~~~~~~~~~ | tail slop area ~~~~~~~~~~~~~~~ |
639// +--------------------------------------+--------------------------------+
640//
641// When executing a read, we pass a pointer to the beginning of the tail slop
642// area (guaranteed to be contiguous space because it's a vector, unlike, say, a
643// deque (sigh)) and the size of the tail slop. When we get data (either here in
644// SSLReadCallback() or above in DoReadComplete()) we subtract the number of
645// bytes received from the tail slop value. That moves those bytes
646// (conceptually, not physically) from the tail slop area to the area containing
647// real data.
648//
649// The idea is still pretty simple. We enlarge the tail slop, call our
650// underlying network, get data, shrink the slop area to match, copy requested
651// data back into our caller's buffer, and delete the data from the head of the
652// vector.
653//
654// Except for a nasty little problem. Asynchronous I/O calls keep the buffer
655// pointer.
656//
657// This leads to the following scenario: we have a few bytes of good data in our
658// buffer. But our caller requests more than that. We oblige by enlarging the
659// tail slop, and calling our underlying provider, but the provider says that
660// it'll call us back later. So we shrug our shoulders, copy what we do have
661// into our caller's buffer and...
662//
663// Wait. We can't delete the data from the head of our vector. That would
664// invalidate the pointer that we just gave to our provider. So instead, in that
665// case we keep track of where the good data starts by keeping a "head slop"
666// value, which just notes what data we've already sent and that is useless to
667// us but that we can't delete because we have I/O in flight depending on us
668// leaving the buffer alone.
669//
670// I hear what you're saying. "We need to use a ring buffer!" You write it,
671// then, and I'll use it. Here are the features it needs. First, it needs to be
672// able to have contiguous segments of arbitrary length attached to it to create
673// read buffers. Second, each of those segments must have a "used" length
674// indicator, so if it was half-filled by a previous data read, but the next
675// data read is for more than there's space left, a new segment can be created
676// for the new read without leaving an internal gap.
677//
678// Get to it.
679//
680// (sigh) Who am I kidding? TODO(avi): write the aforementioned ring buffer
681
682// static
683OSStatus SSLClientSocketMac::SSLReadCallback(SSLConnectionRef connection,
684 void* data,
685 size_t* data_length) {
686 DCHECK(data);
687 DCHECK(data_length);
688 SSLClientSocketMac* us =
689 const_cast<SSLClientSocketMac*>(
690 static_cast<const SSLClientSocketMac*>(connection));
[email protected]f0a51fb52009-03-05 12:46:38691
[email protected]b75523f2008-10-17 14:49:07692 // If we have I/O in flight, promise we'll get back to them and use the
693 // existing callback to do so
[email protected]f0a51fb52009-03-05 12:46:38694
[email protected]b75523f2008-10-17 14:49:07695 if (us->next_io_state_ == STATE_READ_COMPLETE) {
696 *data_length = 0;
697 return errSSLWouldBlock;
698 }
[email protected]f0a51fb52009-03-05 12:46:38699
[email protected]b75523f2008-10-17 14:49:07700 // Start with what's in the buffer
[email protected]f0a51fb52009-03-05 12:46:38701
[email protected]b75523f2008-10-17 14:49:07702 size_t total_read = us->recv_buffer_.size() - us->recv_buffer_head_slop_ -
703 us->recv_buffer_tail_slop_;
[email protected]f0a51fb52009-03-05 12:46:38704
[email protected]b75523f2008-10-17 14:49:07705 // Resize the buffer if needed
[email protected]f0a51fb52009-03-05 12:46:38706
[email protected]b75523f2008-10-17 14:49:07707 if (us->recv_buffer_.size() - us->recv_buffer_head_slop_ < *data_length) {
708 us->recv_buffer_.resize(us->recv_buffer_head_slop_ + *data_length);
709 us->recv_buffer_tail_slop_ = *data_length - total_read;
710 }
[email protected]f0a51fb52009-03-05 12:46:38711
[email protected]b75523f2008-10-17 14:49:07712 int rv = 1; // any old value to spin the loop below
713 while (rv > 0 && total_read < *data_length) {
[email protected]ffeb0882009-04-30 21:51:25714 char* buffer = &us->recv_buffer_[us->recv_buffer_head_slop_ + total_read];
715 us->read_io_buf_ = new IOBuffer(*data_length - total_read);
716 rv = us->transport_->Read(us->read_io_buf_,
717 *data_length - total_read,
[email protected]b75523f2008-10-17 14:49:07718 &us->io_callback_);
[email protected]f0a51fb52009-03-05 12:46:38719
[email protected]ffeb0882009-04-30 21:51:25720 if (rv >= 0) {
721 memcpy(buffer, us->read_io_buf_->data(), rv);
722 us->read_io_buf_ = NULL;
[email protected]b75523f2008-10-17 14:49:07723 total_read += rv;
724 us->recv_buffer_tail_slop_ -= rv;
725 }
[email protected]f0a51fb52009-03-05 12:46:38726 }
727
[email protected]b75523f2008-10-17 14:49:07728 *data_length = total_read;
729 if (total_read) {
730 memcpy(data, &us->recv_buffer_[us->recv_buffer_head_slop_], total_read);
731 if (rv == ERR_IO_PENDING) {
732 // We have I/O in flight which is going to land in our buffer. We can't
733 // shuffle things around, so we need to just fiddle with pointers.
734 us->recv_buffer_head_slop_ += total_read;
735 } else {
736 us->recv_buffer_.erase(us->recv_buffer_.begin(),
737 us->recv_buffer_.begin() +
738 total_read +
739 us->recv_buffer_head_slop_);
740 us->recv_buffer_head_slop_ = 0;
741 }
742 }
[email protected]f0a51fb52009-03-05 12:46:38743
[email protected]b75523f2008-10-17 14:49:07744 if (rv == ERR_IO_PENDING) {
745 us->next_io_state_ = STATE_READ_COMPLETE;
[email protected]ffeb0882009-04-30 21:51:25746 } else {
747 us->read_io_buf_ = NULL;
[email protected]b75523f2008-10-17 14:49:07748 }
[email protected]f0a51fb52009-03-05 12:46:38749
[email protected]b75523f2008-10-17 14:49:07750 if (rv < 0)
751 return OSStatusFromNetError(rv);
[email protected]34c9dff2009-07-16 12:25:32752 else if (rv == 0) // stream closed
753 return errSSLClosedGraceful;
754 else
755 return noErr;
[email protected]b75523f2008-10-17 14:49:07756}
757
758// static
[email protected]f0a51fb52009-03-05 12:46:38759OSStatus SSLClientSocketMac::SSLWriteCallback(SSLConnectionRef connection,
760 const void* data,
[email protected]b75523f2008-10-17 14:49:07761 size_t* data_length) {
762 SSLClientSocketMac* us =
763 const_cast<SSLClientSocketMac*>(
764 static_cast<const SSLClientSocketMac*>(connection));
[email protected]f0a51fb52009-03-05 12:46:38765
[email protected]b75523f2008-10-17 14:49:07766 if (us->pending_send_error_ != OK) {
767 OSStatus status = OSStatusFromNetError(us->pending_send_error_);
768 us->pending_send_error_ = OK;
769 return status;
770 }
[email protected]f0a51fb52009-03-05 12:46:38771
[email protected]a482bb02009-07-29 19:57:46772 bool send_pending = !us->send_buffer_.empty();
773
[email protected]b75523f2008-10-17 14:49:07774 if (data)
775 us->send_buffer_.insert(us->send_buffer_.end(),
776 static_cast<const char*>(data),
777 static_cast<const char*>(data) + *data_length);
[email protected]a482bb02009-07-29 19:57:46778
779 if (send_pending) {
780 // If we have I/O in flight, just add the data to the end of the buffer and
781 // return to our caller. The existing callback will trigger the write of the
782 // new data when it sees that data remains in the buffer after removing the
783 // sent data. As always, lie to our caller.
784 return noErr;
785 }
786
[email protected]b75523f2008-10-17 14:49:07787 int rv;
788 do {
[email protected]ffeb0882009-04-30 21:51:25789 scoped_refptr<IOBuffer> buffer = new IOBuffer(us->send_buffer_.size());
790 memcpy(buffer->data(), &us->send_buffer_[0], us->send_buffer_.size());
791 rv = us->transport_->Write(buffer,
[email protected]b75523f2008-10-17 14:49:07792 us->send_buffer_.size(),
793 &us->write_callback_);
794 if (rv > 0) {
795 us->send_buffer_.erase(us->send_buffer_.begin(),
796 us->send_buffer_.begin() + rv);
[email protected]b75523f2008-10-17 14:49:07797 }
798 } while (rv > 0 && !us->send_buffer_.empty());
[email protected]f0a51fb52009-03-05 12:46:38799
[email protected]b75523f2008-10-17 14:49:07800 if (rv < 0 && rv != ERR_IO_PENDING) {
801 return OSStatusFromNetError(rv);
802 }
[email protected]f0a51fb52009-03-05 12:46:38803
[email protected]b75523f2008-10-17 14:49:07804 // always lie to our caller
805 return noErr;
806}
807
808} // namespace net