blob: 0d100307864865c2d4cf4d185906870c127f854e [file] [log] [blame]
[email protected]b75523f2008-10-17 14:49:071// Copyright (c) 2008 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/base/ssl_client_socket_mac.h"
6
7#include "base/singleton.h"
8#include "base/string_util.h"
9#include "net/base/net_errors.h"
10#include "net/base/ssl_info.h"
11
12// Welcome to Mac SSL. We've been waiting for you.
13//
14// The Mac SSL implementation is, like the Windows and NSS implementations, a
15// giant state machine. This design constraint is due to the asynchronous nature
16// of our underlying transport mechanism. We can call down to read/write on the
17// network, but what happens is that either it completes immediately or returns
18// saying that we'll get a callback sometime in the future. In that case, we
19// have to return to our caller but pick up where we left off when we
20// resume. Thus the fun.
21//
22// On Windows, we use Security Contexts, which are driven by us. We fetch data
23// from the network, we call the context to decrypt the data, and so on. On the
24// Mac, however, we provide Secure Transport with callbacks to get data from the
25// network, and it calls us back to fetch the data from the network for
26// it. Therefore, there are different sets of states in our respective state
27// machines, fewer on the Mac because Secure Transport keeps a lot of its own
28// state. The discussion about what each of the states means lives in comments
29// in the DoLoop() function.
30//
31// Secure Transport is designed for use by either blocking or non-blocking
32// network I/O. If, for example, you called SSLRead() to fetch data, Secure
33// Transport will, unless it has some cached data, issue a read to your network
34// callback read function to fetch it some more encrypted data. It's expecting
35// one of two things. If your function is hooked up to a blocking source, then
36// it'll block pending receipt of the data from the other end. That's fine, as
37// when you return with the data, Secure Transport will do its thing. On the
38// other hand, suppose that your socket is non-blocking and tells your function
39// that it would block. Then you let Secure Transport know, and it'll tell the
40// original caller that it would have blocked and that they need to call it
41// "later."
42//
43// When's "later," though? We have fully-asynchronous networking, so we get a
44// callback when our data's ready. But Secure Transport has no way for us to
45// tell it that data has arrived, so we must re-execute the call that triggered
46// the I/O (we rely on our state machine to do this). When we do so Secure
47// Transport will ask once again for the data. Chances are that it'll be the
48// same request as the previous time, but that's not actually guaranteed. But as
49// long as we buffer what we have and keep track of where we were, it works
50// quite well.
51//
52// Except for network writes. They shoot this plan straight to hell.
53//
54// Faking a blocking connection with an asynchronous connection (theoretically
55// more powerful) simply doesn't work for writing. Suppose that Secure Transport
56// requests a write of data to the network. With blocking I/O, we'd just block
57// until the write completed, and with non-blocking I/O we'd know how many bytes
58// we wrote before we would have blocked. But with the asynchronous I/O, the
59// transport underneath us can tell us that it'll let us know sometime "later"
60// whether or not things succeeded, and how many bytes were written. What do we
61// return to Secure Transport? We can't return a byte count, but we can't return
62// "later" as we're not guaranteed to be called in the future with the same data
63// to write.
64//
65// So, like in any good relationship, we're forced to lie. Whenever Secure
66// Transport asks for data to be written, we take it all and lie about it always
67// being written. We spin in a loop (see SSLWriteCallback() and
68// OnWriteComplete()) independent of the main state machine writing the data to
69// the network, and get the data out. The main consequence of this independence
70// from the state machine is that we require a full-duplex transport underneath
71// us since we can't use it to keep our reading and writing
72// straight. Fortunately, the NSS implementation also has this issue to deal
73// with, so we share the same Libevent-based full-duplex TCP socket.
74//
75// A side comment on return values might be in order. Those who haven't taken
76// the time to read the documentation (ahem, header comments) in our various
77// files might be a bit surprised to see result values being treated as both
78// lengths and errors. Like Shimmer, they are both. In both the case of
79// immediate results as well as results returned in callbacks, a negative return
80// value indicates an error, a zero return value indicates end-of-stream (for
81// reads), and a positive return value indicates the number of bytes read or
82// written. Thus, many functions start off with |if (result < 0) return
83// result;|. That gets the error condition out of the way, and from that point
84// forward the result can be treated as a length.
85
86namespace net {
87
88namespace {
89
90int NetErrorFromOSStatus(OSStatus status) {
91 switch (status) {
92 case errSSLWouldBlock:
93 return ERR_IO_PENDING;
94 case errSSLIllegalParam:
95 case errSSLBadCipherSuite:
96 case errSSLBadConfiguration:
97 return ERR_INVALID_ARGUMENT;
98 case errSSLClosedNoNotify:
99 return ERR_CONNECTION_RESET;
100 case errSSLConnectionRefused:
101 return ERR_CONNECTION_REFUSED;
102 case errSSLClosedAbort:
103 return ERR_CONNECTION_ABORTED;
104 case errSSLInternal:
105 case errSSLCrypto:
106 case errSSLFatalAlert:
107 case errSSLProtocol:
108 return ERR_SSL_PROTOCOL_ERROR;
109 case errSSLHostNameMismatch:
110 return ERR_CERT_COMMON_NAME_INVALID;
111 case errSSLCertExpired:
112 case errSSLCertNotYetValid:
113 return ERR_CERT_DATE_INVALID;
114 case errSSLNoRootCert:
115 case errSSLUnknownRootCert:
116 return ERR_CERT_AUTHORITY_INVALID;
117 case errSSLXCertChainInvalid:
118 case errSSLBadCert:
119 return ERR_CERT_INVALID;
120 case errSSLPeerCertRevoked:
121 return ERR_CERT_REVOKED;
[email protected]f0a51fb52009-03-05 12:46:38122
[email protected]b75523f2008-10-17 14:49:07123 case errSSLClosedGraceful:
124 case noErr:
125 return OK;
[email protected]f0a51fb52009-03-05 12:46:38126
[email protected]b75523f2008-10-17 14:49:07127 case errSSLBadRecordMac:
128 case errSSLBufferOverflow:
129 case errSSLDecryptionFail:
130 case errSSLModuleAttach:
131 case errSSLNegotiation:
132 case errSSLRecordOverflow:
133 case errSSLSessionNotFound:
134 default:
135 LOG(WARNING) << "Unknown error " << status <<
136 " mapped to net::ERR_FAILED";
137 return ERR_FAILED;
138 }
139}
140
141OSStatus OSStatusFromNetError(int net_error) {
142 switch (net_error) {
143 case ERR_IO_PENDING:
144 return errSSLWouldBlock;
145 case ERR_INTERNET_DISCONNECTED:
146 case ERR_TIMED_OUT:
147 case ERR_CONNECTION_ABORTED:
148 case ERR_CONNECTION_RESET:
149 case ERR_CONNECTION_REFUSED:
150 case ERR_ADDRESS_UNREACHABLE:
151 case ERR_ADDRESS_INVALID:
152 return errSSLClosedAbort;
153 case OK:
154 return noErr;
155 default:
156 LOG(WARNING) << "Unknown error " << net_error <<
157 " mapped to errSSLIllegalParam";
158 return errSSLIllegalParam;
159 }
160}
161
[email protected]e1593392008-10-20 19:46:33162// Converts from a cipher suite to its key size. If the suite is marked with a
163// **, it's not actually implemented in Secure Transport and won't be returned
164// (but we'll code for it anyway). The reference here is
165// http://www.opensource.apple.com/darwinsource/10.5.5/libsecurity_ssl-32463/lib/cipherSpecs.c
166// Seriously, though, there has to be an API for this, but I can't find one.
167// Anybody?
168int KeySizeOfCipherSuite(SSLCipherSuite suite) {
169 switch (suite) {
170 // SSL 2 only
[email protected]f0a51fb52009-03-05 12:46:38171
[email protected]e1593392008-10-20 19:46:33172 case SSL_RSA_WITH_DES_CBC_MD5:
173 return 56;
174 case SSL_RSA_WITH_3DES_EDE_CBC_MD5:
175 return 112;
176 case SSL_RSA_WITH_RC2_CBC_MD5:
177 case SSL_RSA_WITH_IDEA_CBC_MD5: // **
178 return 128;
179 case SSL_NO_SUCH_CIPHERSUITE: // **
180 return 0;
[email protected]f0a51fb52009-03-05 12:46:38181
[email protected]e1593392008-10-20 19:46:33182 // SSL 2, 3, TLS
[email protected]f0a51fb52009-03-05 12:46:38183
[email protected]e1593392008-10-20 19:46:33184 case SSL_NULL_WITH_NULL_NULL:
185 case SSL_RSA_WITH_NULL_MD5:
186 case SSL_RSA_WITH_NULL_SHA: // **
187 case SSL_FORTEZZA_DMS_WITH_NULL_SHA: // **
188 return 0;
189 case SSL_RSA_EXPORT_WITH_RC4_40_MD5:
190 case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5:
191 case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA:
192 case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA: // **
193 case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA: // **
194 case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA:
195 case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA:
196 case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5:
197 case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA:
198 return 40;
199 case SSL_RSA_WITH_DES_CBC_SHA:
200 case SSL_DH_DSS_WITH_DES_CBC_SHA: // **
201 case SSL_DH_RSA_WITH_DES_CBC_SHA: // **
202 case SSL_DHE_DSS_WITH_DES_CBC_SHA:
203 case SSL_DHE_RSA_WITH_DES_CBC_SHA:
204 case SSL_DH_anon_WITH_DES_CBC_SHA:
205 return 56;
206 case SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA: // **
207 return 80;
208 case SSL_RSA_WITH_3DES_EDE_CBC_SHA:
209 case SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA: // **
210 case SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA: // **
211 case SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
212 case SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
213 case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA:
214 return 112;
215 case SSL_RSA_WITH_RC4_128_MD5:
216 case SSL_RSA_WITH_RC4_128_SHA:
217 case SSL_RSA_WITH_IDEA_CBC_SHA: // **
218 case SSL_DH_anon_WITH_RC4_128_MD5:
219 return 128;
[email protected]f0a51fb52009-03-05 12:46:38220
[email protected]e1593392008-10-20 19:46:33221 // TLS AES options (see RFC 3268)
[email protected]f0a51fb52009-03-05 12:46:38222
[email protected]e1593392008-10-20 19:46:33223 case TLS_RSA_WITH_AES_128_CBC_SHA:
224 case TLS_DH_DSS_WITH_AES_128_CBC_SHA: // **
225 case TLS_DH_RSA_WITH_AES_128_CBC_SHA: // **
226 case TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
227 case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
228 case TLS_DH_anon_WITH_AES_128_CBC_SHA:
229 return 128;
230 case TLS_RSA_WITH_AES_256_CBC_SHA:
231 case TLS_DH_DSS_WITH_AES_256_CBC_SHA: // **
232 case TLS_DH_RSA_WITH_AES_256_CBC_SHA: // **
233 case TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
234 case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
235 case TLS_DH_anon_WITH_AES_256_CBC_SHA:
236 return 256;
[email protected]f0a51fb52009-03-05 12:46:38237
[email protected]e1593392008-10-20 19:46:33238 default:
239 return -1;
240 }
241}
242
[email protected]b75523f2008-10-17 14:49:07243} // namespace
244
245//-----------------------------------------------------------------------------
246
247SSLClientSocketMac::SSLClientSocketMac(ClientSocket* transport_socket,
248 const std::string& hostname,
249 const SSLConfig& ssl_config)
250 : io_callback_(this, &SSLClientSocketMac::OnIOComplete),
251 write_callback_(this, &SSLClientSocketMac::OnWriteComplete),
252 transport_(transport_socket),
253 hostname_(hostname),
254 ssl_config_(ssl_config),
255 user_callback_(NULL),
256 next_state_(STATE_NONE),
257 next_io_state_(STATE_NONE),
[email protected]e1593392008-10-20 19:46:33258 server_cert_status_(0),
[email protected]b75523f2008-10-17 14:49:07259 completed_handshake_(false),
260 ssl_context_(NULL),
261 pending_send_error_(OK),
262 recv_buffer_head_slop_(0),
263 recv_buffer_tail_slop_(0) {
264}
265
266SSLClientSocketMac::~SSLClientSocketMac() {
267 Disconnect();
268}
269
270int SSLClientSocketMac::Connect(CompletionCallback* callback) {
271 DCHECK(transport_.get());
272 DCHECK(next_state_ == STATE_NONE);
273 DCHECK(!user_callback_);
274
275 next_state_ = STATE_CONNECT;
276 int rv = DoLoop(OK);
277 if (rv == ERR_IO_PENDING)
278 user_callback_ = callback;
279 return rv;
280}
281
282int SSLClientSocketMac::ReconnectIgnoringLastError(
283 CompletionCallback* callback) {
284 // TODO(darin): implement me!
285 return ERR_FAILED;
286}
287
288void SSLClientSocketMac::Disconnect() {
289 completed_handshake_ = false;
[email protected]f0a51fb52009-03-05 12:46:38290
[email protected]b75523f2008-10-17 14:49:07291 if (ssl_context_) {
292 SSLClose(ssl_context_);
293 SSLDisposeContext(ssl_context_);
294 ssl_context_ = NULL;
295 }
[email protected]f0a51fb52009-03-05 12:46:38296
[email protected]b75523f2008-10-17 14:49:07297 transport_->Disconnect();
298}
299
300bool SSLClientSocketMac::IsConnected() const {
301 // Ideally, we should also check if we have received the close_notify alert
302 // message from the server, and return false in that case. We're not doing
303 // that, so this function may return a false positive. Since the upper
304 // layer (HttpNetworkTransaction) needs to handle a persistent connection
305 // closed by the server when we send a request anyway, a false positive in
306 // exchange for simpler code is a good trade-off.
307 return completed_handshake_ && transport_->IsConnected();
308}
309
[email protected]b2197852009-02-19 23:27:33310bool SSLClientSocketMac::IsConnectedAndIdle() const {
311 // Unlike IsConnected, this method doesn't return a false positive.
312 //
313 // Strictly speaking, we should check if we have received the close_notify
314 // alert message from the server, and return false in that case. Although
315 // the close_notify alert message means EOF in the SSL layer, it is just
316 // bytes to the transport layer below, so transport_->IsConnectedAndIdle()
317 // returns the desired false when we receive close_notify.
318 return completed_handshake_ && transport_->IsConnectedAndIdle();
319}
320
[email protected]b75523f2008-10-17 14:49:07321int SSLClientSocketMac::Read(char* buf, int buf_len,
322 CompletionCallback* callback) {
323 DCHECK(completed_handshake_);
324 DCHECK(next_state_ == STATE_NONE);
325 DCHECK(!user_callback_);
326
327 user_buf_ = buf;
328 user_buf_len_ = buf_len;
329
330 next_state_ = STATE_PAYLOAD_READ;
331 int rv = DoLoop(OK);
332 if (rv == ERR_IO_PENDING)
333 user_callback_ = callback;
334 return rv;
335}
336
337int SSLClientSocketMac::Write(const char* buf, int buf_len,
338 CompletionCallback* callback) {
339 DCHECK(completed_handshake_);
340 DCHECK(next_state_ == STATE_NONE);
341 DCHECK(!user_callback_);
342
343 user_buf_ = const_cast<char*>(buf);
344 user_buf_len_ = buf_len;
[email protected]f0a51fb52009-03-05 12:46:38345
[email protected]b75523f2008-10-17 14:49:07346 next_state_ = STATE_PAYLOAD_WRITE;
347 int rv = DoLoop(OK);
348 if (rv == ERR_IO_PENDING)
349 user_callback_ = callback;
350 return rv;
351}
352
353void SSLClientSocketMac::GetSSLInfo(SSLInfo* ssl_info) {
[email protected]e1593392008-10-20 19:46:33354 DCHECK(completed_handshake_);
355 OSStatus status;
[email protected]f0a51fb52009-03-05 12:46:38356
[email protected]e1593392008-10-20 19:46:33357 ssl_info->Reset();
[email protected]f0a51fb52009-03-05 12:46:38358
[email protected]e1593392008-10-20 19:46:33359 // set cert
360 CFArrayRef certs;
361 status = SSLCopyPeerCertificates(ssl_context_, &certs);
362 if (!status) {
363 DCHECK(CFArrayGetCount(certs) > 0);
[email protected]f0a51fb52009-03-05 12:46:38364
[email protected]e1593392008-10-20 19:46:33365 SecCertificateRef client_cert =
366 static_cast<SecCertificateRef>(
367 const_cast<void*>(CFArrayGetValueAtIndex(certs, 0)));
368 CFRetain(client_cert);
[email protected]92831162009-01-29 08:32:11369 ssl_info->cert = X509Certificate::CreateFromHandle(
370 client_cert, X509Certificate::SOURCE_FROM_NETWORK);
[email protected]e1593392008-10-20 19:46:33371 CFRelease(certs);
372 }
[email protected]f0a51fb52009-03-05 12:46:38373
[email protected]e1593392008-10-20 19:46:33374 // update status
375 ssl_info->cert_status = server_cert_status_;
[email protected]f0a51fb52009-03-05 12:46:38376
[email protected]e1593392008-10-20 19:46:33377 // security info
378 SSLCipherSuite suite;
379 status = SSLGetNegotiatedCipher(ssl_context_, &suite);
380 if (!status)
381 ssl_info->security_bits = KeySizeOfCipherSuite(suite);
[email protected]b75523f2008-10-17 14:49:07382}
[email protected]f0a51fb52009-03-05 12:46:38383
[email protected]b75523f2008-10-17 14:49:07384void SSLClientSocketMac::DoCallback(int rv) {
385 DCHECK(rv != ERR_IO_PENDING);
386 DCHECK(user_callback_);
387
388 // since Run may result in Read being called, clear user_callback_ up front.
389 CompletionCallback* c = user_callback_;
390 user_callback_ = NULL;
391 c->Run(rv);
392}
393
394void SSLClientSocketMac::OnIOComplete(int result) {
395 if (next_io_state_ != STATE_NONE) {
396 State next_state = next_state_;
397 next_state_ = next_io_state_;
398 next_io_state_ = STATE_NONE;
399 result = DoLoop(result);
400 next_state_ = next_state;
401 }
402 if (next_state_ != STATE_NONE) {
403 int rv = DoLoop(result);
404 if (rv != ERR_IO_PENDING)
405 DoCallback(rv);
406 }
407}
408
409// This is the main loop driving the state machine. Most calls coming from the
410// outside just set up a few variables and jump into here.
411int SSLClientSocketMac::DoLoop(int last_io_result) {
412 DCHECK(next_state_ != STATE_NONE);
413 int rv = last_io_result;
414 do {
415 State state = next_state_;
416 next_state_ = STATE_NONE;
417 switch (state) {
418 case STATE_CONNECT:
419 // We must establish a connection to the other side using our
420 // lower-level transport.
421 rv = DoConnect();
422 break;
423 case STATE_CONNECT_COMPLETE:
424 // We have a connection to the other side; initialize our SSL engine.
425 rv = DoConnectComplete(rv);
426 break;
427 case STATE_HANDSHAKE:
428 // Do the SSL/TLS handshake.
429 rv = DoHandshake();
430 break;
431 case STATE_READ_COMPLETE:
432 // A read off the network is complete; do the paperwork.
433 rv = DoReadComplete(rv);
434 break;
435 case STATE_PAYLOAD_READ:
436 // Do a read of data from the network.
437 rv = DoPayloadRead();
438 break;
439 case STATE_PAYLOAD_WRITE:
440 // Do a write of data to the network.
441 rv = DoPayloadWrite();
442 break;
443 default:
444 rv = ERR_UNEXPECTED;
445 NOTREACHED() << "unexpected state";
446 break;
447 }
448 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
449 return rv;
450}
451
452int SSLClientSocketMac::DoConnect() {
453 next_state_ = STATE_CONNECT_COMPLETE;
454 return transport_->Connect(&io_callback_);
455}
456
457int SSLClientSocketMac::DoConnectComplete(int result) {
458 if (result < 0)
459 return result;
460
461 OSStatus status = noErr;
[email protected]f0a51fb52009-03-05 12:46:38462
[email protected]b75523f2008-10-17 14:49:07463 status = SSLNewContext(false, &ssl_context_);
464 if (status)
465 return NetErrorFromOSStatus(status);
[email protected]f0a51fb52009-03-05 12:46:38466
[email protected]b75523f2008-10-17 14:49:07467 status = SSLSetProtocolVersionEnabled(ssl_context_,
468 kSSLProtocol2,
469 ssl_config_.ssl2_enabled);
470 if (status)
471 return NetErrorFromOSStatus(status);
[email protected]f0a51fb52009-03-05 12:46:38472
[email protected]b75523f2008-10-17 14:49:07473 status = SSLSetProtocolVersionEnabled(ssl_context_,
474 kSSLProtocol3,
475 ssl_config_.ssl3_enabled);
476 if (status)
477 return NetErrorFromOSStatus(status);
[email protected]f0a51fb52009-03-05 12:46:38478
[email protected]b75523f2008-10-17 14:49:07479 status = SSLSetProtocolVersionEnabled(ssl_context_,
480 kTLSProtocol1,
481 ssl_config_.tls1_enabled);
482 if (status)
483 return NetErrorFromOSStatus(status);
[email protected]f0a51fb52009-03-05 12:46:38484
[email protected]b75523f2008-10-17 14:49:07485 status = SSLSetIOFuncs(ssl_context_, SSLReadCallback, SSLWriteCallback);
486 if (status)
487 return NetErrorFromOSStatus(status);
[email protected]f0a51fb52009-03-05 12:46:38488
[email protected]b75523f2008-10-17 14:49:07489 status = SSLSetConnection(ssl_context_, this);
490 if (status)
491 return NetErrorFromOSStatus(status);
[email protected]f0a51fb52009-03-05 12:46:38492
[email protected]b75523f2008-10-17 14:49:07493 status = SSLSetPeerDomainName(ssl_context_, hostname_.c_str(),
494 hostname_.length());
495 if (status)
496 return NetErrorFromOSStatus(status);
[email protected]f0a51fb52009-03-05 12:46:38497
[email protected]b75523f2008-10-17 14:49:07498 next_state_ = STATE_HANDSHAKE;
499 return OK;
500}
501
502int SSLClientSocketMac::DoHandshake() {
503 OSStatus status = SSLHandshake(ssl_context_);
[email protected]f0a51fb52009-03-05 12:46:38504
[email protected]b75523f2008-10-17 14:49:07505 if (status == errSSLWouldBlock)
506 next_state_ = STATE_HANDSHAKE;
[email protected]f0a51fb52009-03-05 12:46:38507
[email protected]b75523f2008-10-17 14:49:07508 if (status == noErr)
509 completed_handshake_ = true;
[email protected]f0a51fb52009-03-05 12:46:38510
[email protected]e1593392008-10-20 19:46:33511 int net_error = NetErrorFromOSStatus(status);
[email protected]f0a51fb52009-03-05 12:46:38512
[email protected]e1593392008-10-20 19:46:33513 // At this point we have a connection. For now, we're going to use the default
514 // certificate verification that the system does, and accept its answer for
515 // the cert status. In the future, we'll need to call SSLSetEnableCertVerify
516 // to disable cert verification and do the verification ourselves. This allows
517 // very fine-grained control over what we'll accept for certification.
518 // TODO(avi): ditto
[email protected]f0a51fb52009-03-05 12:46:38519
[email protected]e1593392008-10-20 19:46:33520 // TODO(wtc): for now, always check revocation.
521 server_cert_status_ = CERT_STATUS_REV_CHECKING_ENABLED;
522 if (net_error)
[email protected]dedb59432009-02-03 16:51:15523 server_cert_status_ |= MapNetErrorToCertStatus(net_error);
[email protected]f0a51fb52009-03-05 12:46:38524
[email protected]e1593392008-10-20 19:46:33525 return net_error;
[email protected]b75523f2008-10-17 14:49:07526}
527
528int SSLClientSocketMac::DoReadComplete(int result) {
529 if (result < 0)
530 return result;
[email protected]f0a51fb52009-03-05 12:46:38531
[email protected]b75523f2008-10-17 14:49:07532 recv_buffer_tail_slop_ -= result;
[email protected]f0a51fb52009-03-05 12:46:38533
[email protected]b75523f2008-10-17 14:49:07534 return result;
535}
536
537void SSLClientSocketMac::OnWriteComplete(int result) {
538 if (result < 0) {
539 pending_send_error_ = result;
540 return;
541 }
[email protected]f0a51fb52009-03-05 12:46:38542
[email protected]b75523f2008-10-17 14:49:07543 send_buffer_.erase(send_buffer_.begin(),
544 send_buffer_.begin() + result);
[email protected]f0a51fb52009-03-05 12:46:38545
[email protected]b75523f2008-10-17 14:49:07546 if (!send_buffer_.empty())
547 SSLWriteCallback(this, NULL, NULL);
548}
549
550int SSLClientSocketMac::DoPayloadRead() {
551 size_t processed;
552 OSStatus status = SSLRead(ssl_context_,
553 user_buf_,
554 user_buf_len_,
555 &processed);
[email protected]f0a51fb52009-03-05 12:46:38556
[email protected]b75523f2008-10-17 14:49:07557 // There's a subtle difference here in semantics of the "would block" errors.
558 // In our code, ERR_IO_PENDING means the whole operation is async, while
559 // errSSLWouldBlock means that the stream isn't ending (and is often returned
560 // along with partial data). So even though "would block" is returned, if we
561 // have data, let's just return it.
[email protected]f0a51fb52009-03-05 12:46:38562
[email protected]b75523f2008-10-17 14:49:07563 if (processed > 0) {
564 next_state_ = STATE_NONE;
565 return processed;
566 }
[email protected]f0a51fb52009-03-05 12:46:38567
[email protected]b75523f2008-10-17 14:49:07568 if (status == errSSLWouldBlock) {
569 next_state_ = STATE_PAYLOAD_READ;
570 }
[email protected]f0a51fb52009-03-05 12:46:38571
[email protected]b75523f2008-10-17 14:49:07572 return NetErrorFromOSStatus(status);
573}
574
575int SSLClientSocketMac::DoPayloadWrite() {
576 size_t processed;
577 OSStatus status = SSLWrite(ssl_context_,
578 user_buf_,
579 user_buf_len_,
580 &processed);
[email protected]f0a51fb52009-03-05 12:46:38581
[email protected]b75523f2008-10-17 14:49:07582 if (processed > 0)
583 return processed;
[email protected]f0a51fb52009-03-05 12:46:38584
[email protected]b75523f2008-10-17 14:49:07585 return NetErrorFromOSStatus(status);
586}
587
588// Handling the reading from the network is one of those things that should be
589// simpler than it is. Ideally, we'd have some kind of ring buffer. For now, a
590// std::vector<char> will have to do.
591//
592// The need for a buffer at all comes from the difference between an
593// asynchronous connection (which is what we have) and a non-blocking connection
594// (which is what we fake for Secure Transport). When Secure Transport calls us
595// to read data, we call our underlying transport, which will likely tell us
596// that it'll do a callback. When that happens, we need to tell Secure Transport
597// that we've "blocked". When the callback happens, we have a chunk of data that
598// we need to feed to Secure Transport, but it's not interested. It'll ask for
599// it again when we call it again, so we need to hold on to the data.
600//
601// Why keep our own buffer? Well, when we execute a read and the underlying
602// transport says that it'll do a callback, it keeps the pointer to the
603// buffer. We can't pass it the buffer that Secure Transport gave us to fill, as
604// we can't guarantee its lifetime.
605//
606// The basic idea, then, is this: we have a buffer filled with the data that
607// we've read from the network but haven't given to Secure Transport
608// yet. Whenever we read from the network the first thing we do is ensure we
609// have enough room in the buffer for the read. We enlarge the buffer to be big
610// enough to hold both our existing data and the new data, and then we mark the
611// extra space at the end as "tail slop." Slop is just space at the ends of the
612// buffer that's going to be used for data but isn't (yet). A diagram:
613//
614// +--------------------------------------+--------------------------------+
615// | existing good data ~~~~~~~~~~~~~~~~~ | tail slop area ~~~~~~~~~~~~~~~ |
616// +--------------------------------------+--------------------------------+
617//
618// When executing a read, we pass a pointer to the beginning of the tail slop
619// area (guaranteed to be contiguous space because it's a vector, unlike, say, a
620// deque (sigh)) and the size of the tail slop. When we get data (either here in
621// SSLReadCallback() or above in DoReadComplete()) we subtract the number of
622// bytes received from the tail slop value. That moves those bytes
623// (conceptually, not physically) from the tail slop area to the area containing
624// real data.
625//
626// The idea is still pretty simple. We enlarge the tail slop, call our
627// underlying network, get data, shrink the slop area to match, copy requested
628// data back into our caller's buffer, and delete the data from the head of the
629// vector.
630//
631// Except for a nasty little problem. Asynchronous I/O calls keep the buffer
632// pointer.
633//
634// This leads to the following scenario: we have a few bytes of good data in our
635// buffer. But our caller requests more than that. We oblige by enlarging the
636// tail slop, and calling our underlying provider, but the provider says that
637// it'll call us back later. So we shrug our shoulders, copy what we do have
638// into our caller's buffer and...
639//
640// Wait. We can't delete the data from the head of our vector. That would
641// invalidate the pointer that we just gave to our provider. So instead, in that
642// case we keep track of where the good data starts by keeping a "head slop"
643// value, which just notes what data we've already sent and that is useless to
644// us but that we can't delete because we have I/O in flight depending on us
645// leaving the buffer alone.
646//
647// I hear what you're saying. "We need to use a ring buffer!" You write it,
648// then, and I'll use it. Here are the features it needs. First, it needs to be
649// able to have contiguous segments of arbitrary length attached to it to create
650// read buffers. Second, each of those segments must have a "used" length
651// indicator, so if it was half-filled by a previous data read, but the next
652// data read is for more than there's space left, a new segment can be created
653// for the new read without leaving an internal gap.
654//
655// Get to it.
656//
657// (sigh) Who am I kidding? TODO(avi): write the aforementioned ring buffer
658
659// static
660OSStatus SSLClientSocketMac::SSLReadCallback(SSLConnectionRef connection,
661 void* data,
662 size_t* data_length) {
663 DCHECK(data);
664 DCHECK(data_length);
665 SSLClientSocketMac* us =
666 const_cast<SSLClientSocketMac*>(
667 static_cast<const SSLClientSocketMac*>(connection));
[email protected]f0a51fb52009-03-05 12:46:38668
[email protected]b75523f2008-10-17 14:49:07669 // If we have I/O in flight, promise we'll get back to them and use the
670 // existing callback to do so
[email protected]f0a51fb52009-03-05 12:46:38671
[email protected]b75523f2008-10-17 14:49:07672 if (us->next_io_state_ == STATE_READ_COMPLETE) {
673 *data_length = 0;
674 return errSSLWouldBlock;
675 }
[email protected]f0a51fb52009-03-05 12:46:38676
[email protected]b75523f2008-10-17 14:49:07677 // Start with what's in the buffer
[email protected]f0a51fb52009-03-05 12:46:38678
[email protected]b75523f2008-10-17 14:49:07679 size_t total_read = us->recv_buffer_.size() - us->recv_buffer_head_slop_ -
680 us->recv_buffer_tail_slop_;
[email protected]f0a51fb52009-03-05 12:46:38681
[email protected]b75523f2008-10-17 14:49:07682 // Resize the buffer if needed
[email protected]f0a51fb52009-03-05 12:46:38683
[email protected]b75523f2008-10-17 14:49:07684 if (us->recv_buffer_.size() - us->recv_buffer_head_slop_ < *data_length) {
685 us->recv_buffer_.resize(us->recv_buffer_head_slop_ + *data_length);
686 us->recv_buffer_tail_slop_ = *data_length - total_read;
687 }
[email protected]f0a51fb52009-03-05 12:46:38688
[email protected]b75523f2008-10-17 14:49:07689 int rv = 1; // any old value to spin the loop below
690 while (rv > 0 && total_read < *data_length) {
691 rv = us->transport_->Read(&us->recv_buffer_[us->recv_buffer_head_slop_ +
692 total_read],
693 us->recv_buffer_tail_slop_,
694 &us->io_callback_);
[email protected]f0a51fb52009-03-05 12:46:38695
[email protected]b75523f2008-10-17 14:49:07696 if (rv > 0) {
697 total_read += rv;
698 us->recv_buffer_tail_slop_ -= rv;
699 }
[email protected]f0a51fb52009-03-05 12:46:38700 }
701
[email protected]b75523f2008-10-17 14:49:07702 *data_length = total_read;
703 if (total_read) {
704 memcpy(data, &us->recv_buffer_[us->recv_buffer_head_slop_], total_read);
705 if (rv == ERR_IO_PENDING) {
706 // We have I/O in flight which is going to land in our buffer. We can't
707 // shuffle things around, so we need to just fiddle with pointers.
708 us->recv_buffer_head_slop_ += total_read;
709 } else {
710 us->recv_buffer_.erase(us->recv_buffer_.begin(),
711 us->recv_buffer_.begin() +
712 total_read +
713 us->recv_buffer_head_slop_);
714 us->recv_buffer_head_slop_ = 0;
715 }
716 }
[email protected]f0a51fb52009-03-05 12:46:38717
[email protected]b75523f2008-10-17 14:49:07718 if (rv == ERR_IO_PENDING) {
719 us->next_io_state_ = STATE_READ_COMPLETE;
720 }
[email protected]f0a51fb52009-03-05 12:46:38721
[email protected]b75523f2008-10-17 14:49:07722 if (rv < 0)
723 return OSStatusFromNetError(rv);
[email protected]f0a51fb52009-03-05 12:46:38724
[email protected]b75523f2008-10-17 14:49:07725 return noErr;
726}
727
728// static
[email protected]f0a51fb52009-03-05 12:46:38729OSStatus SSLClientSocketMac::SSLWriteCallback(SSLConnectionRef connection,
730 const void* data,
[email protected]b75523f2008-10-17 14:49:07731 size_t* data_length) {
732 SSLClientSocketMac* us =
733 const_cast<SSLClientSocketMac*>(
734 static_cast<const SSLClientSocketMac*>(connection));
[email protected]f0a51fb52009-03-05 12:46:38735
[email protected]b75523f2008-10-17 14:49:07736 if (us->pending_send_error_ != OK) {
737 OSStatus status = OSStatusFromNetError(us->pending_send_error_);
738 us->pending_send_error_ = OK;
739 return status;
740 }
[email protected]f0a51fb52009-03-05 12:46:38741
[email protected]b75523f2008-10-17 14:49:07742 if (data)
743 us->send_buffer_.insert(us->send_buffer_.end(),
744 static_cast<const char*>(data),
745 static_cast<const char*>(data) + *data_length);
746 int rv;
747 do {
748 rv = us->transport_->Write(&us->send_buffer_[0],
749 us->send_buffer_.size(),
750 &us->write_callback_);
751 if (rv > 0) {
752 us->send_buffer_.erase(us->send_buffer_.begin(),
753 us->send_buffer_.begin() + rv);
[email protected]f0a51fb52009-03-05 12:46:38754
[email protected]b75523f2008-10-17 14:49:07755 }
756 } while (rv > 0 && !us->send_buffer_.empty());
[email protected]f0a51fb52009-03-05 12:46:38757
[email protected]b75523f2008-10-17 14:49:07758 if (rv < 0 && rv != ERR_IO_PENDING) {
759 return OSStatusFromNetError(rv);
760 }
[email protected]f0a51fb52009-03-05 12:46:38761
[email protected]b75523f2008-10-17 14:49:07762 // always lie to our caller
763 return noErr;
764}
765
766} // namespace net
767