]> git.saurik.com Git - apple/security.git/blob - SecureTransport/sslTransport.cpp
Security-163.tar.gz
[apple/security.git] / SecureTransport / sslTransport.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 /*
20 File: sslTransport.c
21
22 Contains: SSL transport layer
23
24 Written by: Doug Mitchell
25
26 Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved.
27
28 */
29
30 #include "sslMemory.h"
31 #include "sslContext.h"
32 #include "sslRecord.h"
33 #include "sslAlertMessage.h"
34 #include "sslSession.h"
35 #include "ssl2.h"
36 #include "sslDebug.h"
37 #include "cipherSpecs.h"
38 #include "sslUtils.h"
39
40 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
41
42 #include <assert.h>
43 #include <string.h>
44
45 #ifndef NDEBUG
46 static void inline sslIoTrace(
47 const char *op,
48 UInt32 req,
49 UInt32 moved,
50 OSStatus stat)
51 {
52 sslLogRecordIo("===%s: req %4lu moved %4lu status %ld\n",
53 op, req, moved, stat);
54 }
55 #else
56 #define sslIoTrace(op, req, moved, stat)
57 #endif /* NDEBUG */
58
59 static OSStatus SSLProcessProtocolMessage(SSLRecord &rec, SSLContext *ctx);
60 static OSStatus SSLHandshakeProceed(SSLContext *ctx);
61 static OSStatus SSLInitConnection(SSLContext *ctx);
62 static OSStatus SSLServiceWriteQueue(SSLContext *ctx);
63
64 OSStatus
65 SSLWrite(
66 SSLContext *ctx,
67 const void * data,
68 UInt32 dataLength,
69 UInt32 *bytesWritten) /* RETURNED */
70 {
71 OSStatus err;
72 SSLRecord rec;
73 UInt32 dataLen, processed;
74
75 if((ctx == NULL) || (bytesWritten == NULL)) {
76 return paramErr;
77 }
78 dataLen = dataLength;
79 processed = 0; /* Initialize in case we return with errSSLWouldBlock */
80 *bytesWritten = 0;
81
82 switch(ctx->state) {
83 case SSL_HdskStateGracefulClose:
84 err = errSSLClosedGraceful;
85 goto abort;
86 case SSL_HdskStateErrorClose:
87 err = errSSLClosedAbort;
88 goto abort;
89 default:
90 /* FIXME - original code didn't check for pending handshake -
91 * should we?
92 */
93 sslIoTrace("SSLWrite", dataLength, 0, badReqErr);
94 return badReqErr;
95 case SSL_HdskStateServerReady:
96 case SSL_HdskStateClientReady:
97 break;
98 }
99
100 /* First, we have to wait until the session is ready to send data,
101 so the encryption keys and such have been established. */
102 err = noErr;
103 while (ctx->writeCipher.ready == 0)
104 { if ((err = SSLHandshakeProceed(ctx)) != 0)
105 goto exit;
106 }
107
108 /* Attempt to empty the write queue before queueing more data */
109 if ((err = SSLServiceWriteQueue(ctx)) != 0)
110 goto abort;
111
112 processed = 0;
113 /*
114 * Fragment, package and encrypt the data and queue the resulting data
115 * for sending
116 */
117 while (dataLen > 0)
118 { rec.contentType = SSL_RecordTypeAppData;
119 rec.protocolVersion = ctx->negProtocolVersion;
120 rec.contents.data = ((UInt8*)data) + processed;
121
122 if (dataLen < MAX_RECORD_LENGTH)
123 rec.contents.length = dataLen;
124 else
125 rec.contents.length = MAX_RECORD_LENGTH;
126
127 assert(ctx->sslTslCalls != NULL);
128 if ((err = ctx->sslTslCalls->writeRecord(rec, ctx)) != 0)
129 goto exit;
130 processed += rec.contents.length;
131 dataLen -= rec.contents.length;
132 }
133
134 /* All the data has been advanced to the write queue */
135 *bytesWritten = processed;
136 if ((err = SSLServiceWriteQueue(ctx)) == 0) {
137 err = noErr;
138 }
139 exit:
140 if (err != 0 && err != errSSLWouldBlock && err != errSSLClosedGraceful) {
141 sslErrorLog("SSLWrite: going to state errorCLose due to err %d\n",
142 (int)err);
143 SSLChangeHdskState(ctx, SSL_HdskStateErrorClose);
144 }
145 abort:
146 sslIoTrace("SSLWrite", dataLength, *bytesWritten, err);
147 return err;
148 }
149
150 OSStatus
151 SSLRead (
152 SSLContext *ctx,
153 void * data,
154 UInt32 dataLength,
155 UInt32 *processed) /* RETURNED */
156 {
157 OSStatus err;
158 UInt8 *charPtr;
159 UInt32 bufSize, remaining, count;
160 SSLRecord rec;
161
162 if((ctx == NULL) || (processed == NULL)) {
163 return paramErr;
164 }
165 bufSize = dataLength;
166 *processed = 0; /* Initialize in case we return with errSSLWouldBlock */
167
168 /* first handle cases in which we know we're finished */
169 switch(ctx->state) {
170 case SSL_HdskStateGracefulClose:
171 err = errSSLClosedGraceful;
172 goto abort;
173 case SSL_HdskStateErrorClose:
174 err = errSSLClosedAbort;
175 goto abort;
176 case SSL_HdskStateNoNotifyClose:
177 err = errSSLClosedNoNotify;
178 goto abort;
179 default:
180 break;
181 }
182
183 /* First, we have to wait until the session is ready to receive data,
184 so the encryption keys and such have been established. */
185 err = noErr;
186 while (ctx->readCipher.ready == 0) {
187 if ((err = SSLHandshakeProceed(ctx)) != 0) {
188 goto exit;
189 }
190 }
191
192 /* Attempt to service the write queue */
193 if ((err = SSLServiceWriteQueue(ctx)) != 0) {
194 if (err != errSSLWouldBlock) {
195 goto exit;
196 }
197 err = noErr; /* Write blocking shouldn't stop attempts to read */
198 }
199
200 remaining = bufSize;
201 charPtr = (UInt8*)data;
202 if (ctx->receivedDataBuffer.data)
203 { count = ctx->receivedDataBuffer.length - ctx->receivedDataPos;
204 if (count > bufSize)
205 count = bufSize;
206 memcpy(data, ctx->receivedDataBuffer.data + ctx->receivedDataPos, count);
207 remaining -= count;
208 charPtr += count;
209 *processed += count;
210 ctx->receivedDataPos += count;
211 }
212
213 assert(ctx->receivedDataPos <= ctx->receivedDataBuffer.length);
214 assert(*processed + remaining == bufSize);
215 assert(charPtr == ((UInt8*)data) + *processed);
216
217 if (ctx->receivedDataBuffer.data != 0 &&
218 ctx->receivedDataPos >= ctx->receivedDataBuffer.length)
219 { SSLFreeBuffer(ctx->receivedDataBuffer, ctx);
220 ctx->receivedDataBuffer.data = 0;
221 ctx->receivedDataPos = 0;
222 }
223
224 /*
225 * This while statement causes a hang when using nonblocking low-level I/O!
226 while (remaining > 0 && ctx->state != SSL_HdskStateGracefulClose)
227 ..what we really have to do is just return as soon as we read one
228 record. A performance hit in the nonblocking case, but that is
229 the only way this code can work in both modes...
230 */
231 if (remaining > 0 && ctx->state != SSL_HdskStateGracefulClose)
232 { assert(ctx->receivedDataBuffer.data == 0);
233 if ((err = SSLReadRecord(rec, ctx)) != 0) {
234 goto exit;
235 }
236 if (rec.contentType == SSL_RecordTypeAppData ||
237 rec.contentType == SSL_RecordTypeV2_0)
238 { if (rec.contents.length <= remaining)
239 { memcpy(charPtr, rec.contents.data, rec.contents.length);
240 remaining -= rec.contents.length;
241 charPtr += rec.contents.length;
242 *processed += rec.contents.length;
243 /* COMPILER BUG!
244 * This:
245 * if ((err = SSLFreeBuffer(rec.contents, ctx)) != 0)
246 * passes the address of rec to SSLFreeBuffer, not the address
247 * of the contents field (which should be offset 8 from the start
248 * of rec).
249 */
250 {
251 SSLBuffer *b = &rec.contents;
252 if ((err = SSLFreeBuffer(*b, ctx)) != 0) {
253 goto exit;
254 }
255 }
256 }
257 else
258 { memcpy(charPtr, rec.contents.data, remaining);
259 charPtr += remaining;
260 *processed += remaining;
261 ctx->receivedDataBuffer = rec.contents;
262 ctx->receivedDataPos = remaining;
263 remaining = 0;
264 }
265 }
266 else {
267 if ((err = SSLProcessProtocolMessage(rec, ctx)) != 0) {
268 goto exit;
269 }
270 if ((err = SSLFreeBuffer(rec.contents, ctx)) != 0) {
271 goto exit;
272 }
273 }
274 }
275
276 err = noErr;
277
278 exit:
279 /* shut down on serious errors */
280 switch(err) {
281 case noErr:
282 case errSSLWouldBlock:
283 case errSSLClosedGraceful:
284 case errSSLClosedNoNotify:
285 break;
286 default:
287 sslErrorLog("SSLRead: going to state errorClose due to err %d\n",
288 (int)err);
289 SSLChangeHdskState(ctx, SSL_HdskStateErrorClose);
290 break;
291 }
292 abort:
293 sslIoTrace("SSLRead ", dataLength, *processed, err);
294 return err;
295 }
296
297 #if SSL_DEBUG
298 #include "appleCdsa.h"
299 #endif
300
301 OSStatus
302 SSLHandshake(SSLContext *ctx)
303 {
304 OSStatus err;
305
306 if(ctx == NULL) {
307 return paramErr;
308 }
309 if (ctx->state == SSL_HdskStateGracefulClose)
310 return errSSLClosedGraceful;
311 if (ctx->state == SSL_HdskStateErrorClose)
312 return errSSLClosedAbort;
313
314 if(ctx->validCipherSpecs == NULL) {
315 /* build list of legal cipherSpecs */
316 err = sslBuildCipherSpecArray(ctx);
317 if(err) {
318 return err;
319 }
320 }
321 err = noErr;
322 while (ctx->readCipher.ready == 0 || ctx->writeCipher.ready == 0)
323 { if ((err = SSLHandshakeProceed(ctx)) != 0)
324 return err;
325 }
326
327 /* one more flush at completion of successful handshake */
328 if ((err = SSLServiceWriteQueue(ctx)) != 0) {
329 return err;
330 }
331 return noErr;
332 }
333
334
335 static OSStatus
336 SSLHandshakeProceed(SSLContext *ctx)
337 { OSStatus err;
338 SSLRecord rec;
339
340 if (ctx->state == SSL_HdskStateUninit)
341 if ((err = SSLInitConnection(ctx)) != 0)
342 return err;
343 if ((err = SSLServiceWriteQueue(ctx)) != 0)
344 return err;
345 assert(ctx->readCipher.ready == 0);
346 if ((err = SSLReadRecord(rec, ctx)) != 0)
347 return err;
348 if ((err = SSLProcessProtocolMessage(rec, ctx)) != 0)
349 { SSLFreeBuffer(rec.contents, ctx);
350 return err;
351 }
352 if ((err = SSLFreeBuffer(rec.contents, ctx)) != 0)
353 return err;
354
355 return noErr;
356 }
357
358 static OSStatus
359 SSLInitConnection(SSLContext *ctx)
360 { OSStatus err = noErr;
361
362 if (ctx->protocolSide == SSL_ClientSide) {
363 SSLChangeHdskState(ctx, SSL_HdskStateClientUninit);
364 }
365 else
366 { assert(ctx->protocolSide == SSL_ServerSide);
367 SSLChangeHdskState(ctx, SSL_HdskStateServerUninit);
368 }
369
370 if (ctx->peerID.data != 0)
371 { SSLGetSessionData(&ctx->resumableSession, ctx);
372 /* Ignore errors; just treat as uncached session */
373 }
374
375 /*
376 * If we have a cached resumable session, blow it off if it's a version
377 * which is not currently enabled.
378 */
379 Boolean cachedV3OrTls1 = false;
380
381 if (ctx->resumableSession.data != 0) {
382
383 SSLProtocolVersion savedVersion;
384 Boolean enable;
385
386 if ((err = SSLRetrieveSessionProtocolVersion(ctx->resumableSession,
387 &savedVersion, ctx)) != 0) {
388 return err;
389 }
390 switch(savedVersion) {
391 case SSL_Version_2_0:
392 enable = ctx->versionSsl2Enable;
393 break;
394 case SSL_Version_3_0:
395 enable = ctx->versionSsl3Enable;
396 cachedV3OrTls1 = true; // avoid V2 hello
397 break;
398 case TLS_Version_1_0:
399 enable = ctx->versionTls1Enable;
400 cachedV3OrTls1 = true;
401 break;
402 default:
403 assert(0);
404 return errSSLInternal;
405 }
406 if(!enable) {
407 sslLogResumSessDebug("===Resumable session protocol mismatch");
408 SSLFreeBuffer(ctx->resumableSession, ctx);
409 cachedV3OrTls1 = false;
410 }
411 else {
412 sslLogResumSessDebug("===attempting to resume session");
413 }
414 }
415
416 /*
417 * If we're the client & handshake hasn't yet begun, start it by
418 * pretending we just received a hello request
419 */
420 if (ctx->state == SSL_HdskStateClientUninit && ctx->writeCipher.ready == 0)
421 {
422 assert(ctx->negProtocolVersion == SSL_Version_Undetermined);
423 if(ctx->versionSsl2Enable && !cachedV3OrTls1) {
424 /* SSL2 client hello with possible upgrade */
425 err = SSL2AdvanceHandshake(SSL2_MsgKickstart, ctx);
426 }
427 else {
428 err = SSLAdvanceHandshake(SSL_HdskHelloRequest, ctx);
429 }
430 }
431
432 return err;
433 }
434
435 static OSStatus
436 SSLServiceWriteQueue(SSLContext *ctx)
437 { OSStatus err = noErr, werr = noErr;
438 UInt32 written = 0;
439 SSLBuffer buf, recBuf;
440 WaitingRecord *rec;
441
442 while (!werr && ((rec = ctx->recordWriteQueue) != 0))
443 { buf.data = rec->data.data + rec->sent;
444 buf.length = rec->data.length - rec->sent;
445 werr = sslIoWrite(buf, &written, ctx);
446 rec->sent += written;
447 if (rec->sent >= rec->data.length)
448 { assert(rec->sent == rec->data.length);
449 assert(err == 0);
450 err = SSLFreeBuffer(rec->data, ctx);
451 assert(err == 0);
452 recBuf.data = (UInt8*)rec;
453 recBuf.length = sizeof(WaitingRecord);
454 ctx->recordWriteQueue = rec->next;
455 err = SSLFreeBuffer(recBuf, ctx);
456 assert(err == 0);
457 }
458 if (err)
459 return err;
460 }
461
462 return werr;
463 }
464
465 static OSStatus
466 SSLProcessProtocolMessage(SSLRecord &rec, SSLContext *ctx)
467 { OSStatus err;
468
469 switch (rec.contentType)
470 { case SSL_RecordTypeHandshake:
471 sslLogRxProtocolDebug("Handshake");
472 err = SSLProcessHandshakeRecord(rec, ctx);
473 break;
474 case SSL_RecordTypeAlert:
475 sslLogRxProtocolDebug("Alert");
476 err = SSLProcessAlert(rec, ctx);
477 break;
478 case SSL_RecordTypeChangeCipher:
479 sslLogRxProtocolDebug("ChangeCipher");
480 err = SSLProcessChangeCipherSpec(rec, ctx);
481 break;
482 case SSL_RecordTypeV2_0:
483 sslLogRxProtocolDebug("RecordTypeV2_0");
484 err = SSL2ProcessMessage(rec, ctx);
485 break;
486 default:
487 sslLogRxProtocolDebug("Bad msg");
488 return errSSLProtocol;
489 }
490
491 return err;
492 }
493
494 OSStatus
495 SSLClose(SSLContext *ctx)
496 {
497 OSStatus err = noErr;
498
499 if(ctx == NULL) {
500 return paramErr;
501 }
502 if (ctx->negProtocolVersion >= SSL_Version_3_0)
503 err = SSLSendAlert(SSL_AlertLevelWarning, SSL_AlertCloseNotify, ctx);
504 if (err == 0)
505 err = SSLServiceWriteQueue(ctx);
506 SSLChangeHdskState(ctx, SSL_HdskStateGracefulClose);
507 if (err == ioErr)
508 err = noErr; /* Ignore errors related to closed streams */
509 return err;
510 }
511
512 /*
513 * Determine how much data the client can be guaranteed to
514 * obtain via SSLRead() without blocking or causing any low-level
515 * read operations to occur.
516 *
517 * Implemented here because the relevant info in SSLContext (receivedDataBuffer
518 * and receivedDataPos) are only used in this file.
519 */
520 OSStatus
521 SSLGetBufferedReadSize(SSLContextRef ctx,
522 size_t *bufSize) /* RETURNED */
523 {
524 if(ctx == NULL) {
525 return paramErr;
526 }
527 if(ctx->receivedDataBuffer.data == NULL) {
528 *bufSize = 0;
529 }
530 else {
531 assert(ctx->receivedDataBuffer.length >= ctx->receivedDataPos);
532 *bufSize = ctx->receivedDataBuffer.length - ctx->receivedDataPos;
533 }
534 return noErr;
535 }