]> git.saurik.com Git - apple/security.git/blob - SecureTransport/sslTransport.cpp
Security-54.1.3.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 SSL2_HdskStateServerReady:
96 case SSL2_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->protocolSide == SSL_ServerSide) {
315 /* some things the caller really has to have done by now... */
316 if((ctx->localCert == NULL) ||
317 (ctx->signingPrivKey == NULL) ||
318 (ctx->signingPubKey == NULL) ||
319 (ctx->signingKeyCsp == 0)) {
320 sslErrorLog("SSLHandshake: insufficient init\n");
321 return badReqErr;
322 }
323 }
324 if(ctx->validCipherSpecs == NULL) {
325 /* build list of legal cipherSpecs */
326 err = sslBuildCipherSpecArray(ctx);
327 if(err) {
328 return err;
329 }
330 }
331 err = noErr;
332 while (ctx->readCipher.ready == 0 || ctx->writeCipher.ready == 0)
333 { if ((err = SSLHandshakeProceed(ctx)) != 0)
334 return err;
335 }
336
337 /* one more flush at completion of successful handshake */
338 if ((err = SSLServiceWriteQueue(ctx)) != 0) {
339 return err;
340 }
341 return noErr;
342 }
343
344
345 static OSStatus
346 SSLHandshakeProceed(SSLContext *ctx)
347 { OSStatus err;
348 SSLRecord rec;
349
350 if (ctx->state == SSL_HdskStateUninit)
351 if ((err = SSLInitConnection(ctx)) != 0)
352 return err;
353 if ((err = SSLServiceWriteQueue(ctx)) != 0)
354 return err;
355 assert(ctx->readCipher.ready == 0);
356 if ((err = SSLReadRecord(rec, ctx)) != 0)
357 return err;
358 if ((err = SSLProcessProtocolMessage(rec, ctx)) != 0)
359 { SSLFreeBuffer(rec.contents, ctx);
360 return err;
361 }
362 if ((err = SSLFreeBuffer(rec.contents, ctx)) != 0)
363 return err;
364
365 return noErr;
366 }
367
368 static OSStatus
369 SSLInitConnection(SSLContext *ctx)
370 { OSStatus err;
371
372 if (ctx->protocolSide == SSL_ClientSide) {
373 SSLChangeHdskState(ctx, SSL_HdskStateClientUninit);
374 }
375 else
376 { assert(ctx->protocolSide == SSL_ServerSide);
377 SSLChangeHdskState(ctx, SSL_HdskStateServerUninit);
378 }
379
380 if (ctx->peerID.data != 0)
381 { SSLGetSessionData(&ctx->resumableSession, ctx);
382 /* Ignore errors; just treat as uncached session */
383 }
384
385 /*
386 * If we have a cached resumable session, blow it off if it's a higher
387 * version than the max currently allowed. Note that this means that once
388 * a process negotiates a given version with a given server/port, it won't
389 * be able to negotiate a higher version. We might want to revisit this.
390 */
391 if (ctx->resumableSession.data != 0) {
392
393 SSLProtocolVersion savedVersion;
394
395 if ((err = SSLRetrieveSessionProtocolVersion(ctx->resumableSession,
396 &savedVersion, ctx)) != 0) {
397 return err;
398 }
399 if(savedVersion > ctx->maxProtocolVersion) {
400 sslLogResumSessDebug("===Resumable session protocol mismatch");
401 SSLFreeBuffer(ctx->resumableSession, ctx);
402 }
403 else {
404 sslLogResumSessDebug("===attempting to resume session");
405 /*
406 * A bit of a special case for server side here. If currently
407 * configged to allow for SSL3/TLS1 with an SSL2 hello, we
408 * don't want to preclude the possiblity of an SSL2 hello...
409 * so we'll just leave the negProtocolVersion alone in the server case.
410 */
411 if(ctx->protocolSide == SSL_ClientSide) {
412 ctx->negProtocolVersion = savedVersion;
413 }
414 }
415 }
416
417 /*
418 * If we're the client & handshake hasn't yet begun, start it by
419 * pretending we just received a hello request
420 */
421 if (ctx->state == SSL_HdskStateClientUninit && ctx->writeCipher.ready == 0)
422 { switch (ctx->negProtocolVersion)
423 { case SSL_Version_Undetermined:
424 case SSL_Version_3_0_With_2_0_Hello:
425 case SSL_Version_2_0:
426 if ((err = SSL2AdvanceHandshake(
427 SSL2_MsgKickstart, ctx)) != 0)
428 return err;
429 break;
430 case SSL_Version_3_0_Only:
431 case SSL_Version_3_0:
432 case TLS_Version_1_0_Only:
433 case TLS_Version_1_0:
434 if ((err = SSLAdvanceHandshake(SSL_HdskHelloRequest, ctx)) != 0)
435 return err;
436 break;
437 default:
438 sslErrorLog("Bad protocol version\n");
439 return errSSLInternal;
440 }
441 }
442
443 return noErr;
444 }
445
446 static OSStatus
447 SSLServiceWriteQueue(SSLContext *ctx)
448 { OSStatus err = noErr, werr = noErr;
449 UInt32 written = 0;
450 SSLBuffer buf, recBuf;
451 WaitingRecord *rec;
452
453 while (!werr && ((rec = ctx->recordWriteQueue) != 0))
454 { buf.data = rec->data.data + rec->sent;
455 buf.length = rec->data.length - rec->sent;
456 werr = sslIoWrite(buf, &written, ctx);
457 rec->sent += written;
458 if (rec->sent >= rec->data.length)
459 { assert(rec->sent == rec->data.length);
460 assert(err == 0);
461 err = SSLFreeBuffer(rec->data, ctx);
462 assert(err == 0);
463 recBuf.data = (UInt8*)rec;
464 recBuf.length = sizeof(WaitingRecord);
465 ctx->recordWriteQueue = rec->next;
466 err = SSLFreeBuffer(recBuf, ctx);
467 assert(err == 0);
468 }
469 if (err)
470 return err;
471 assert(ctx->recordWriteQueue == 0 || ctx->recordWriteQueue->sent == 0);
472 }
473
474 return werr;
475 }
476
477 static OSStatus
478 SSLProcessProtocolMessage(SSLRecord &rec, SSLContext *ctx)
479 { OSStatus err;
480
481 switch (rec.contentType)
482 { case SSL_RecordTypeHandshake:
483 sslLogRxProtocolDebug("Handshake");
484 err = SSLProcessHandshakeRecord(rec, ctx);
485 break;
486 case SSL_RecordTypeAlert:
487 sslLogRxProtocolDebug("Alert");
488 err = SSLProcessAlert(rec, ctx);
489 break;
490 case SSL_RecordTypeChangeCipher:
491 sslLogRxProtocolDebug("ChangeCipher");
492 err = SSLProcessChangeCipherSpec(rec, ctx);
493 break;
494 case SSL_RecordTypeV2_0:
495 sslLogRxProtocolDebug("RecordTypeV2_0");
496 err = SSL2ProcessMessage(rec, ctx);
497 break;
498 default:
499 sslLogRxProtocolDebug("Bad msg");
500 return errSSLProtocol;
501 }
502
503 return err;
504 }
505
506 OSStatus
507 SSLClose(SSLContext *ctx)
508 {
509 OSStatus err = noErr;
510
511 if(ctx == NULL) {
512 return paramErr;
513 }
514 if (ctx->negProtocolVersion >= SSL_Version_3_0)
515 err = SSLSendAlert(SSL_AlertLevelWarning, SSL_AlertCloseNotify, ctx);
516 if (err == 0)
517 err = SSLServiceWriteQueue(ctx);
518 SSLChangeHdskState(ctx, SSL_HdskStateGracefulClose);
519 if (err == ioErr)
520 err = noErr; /* Ignore errors related to closed streams */
521 return err;
522 }
523
524 /*
525 * Determine how much data the client can be guaranteed to
526 * obtain via SSLRead() without blocking or causing any low-level
527 * read operations to occur.
528 *
529 * Implemented here because the relevant info in SSLContext (receivedDataBuffer
530 * and receivedDataPos) are only used in this file.
531 */
532 OSStatus
533 SSLGetBufferedReadSize(SSLContextRef ctx,
534 size_t *bufSize) /* RETURNED */
535 {
536 if(ctx == NULL) {
537 return paramErr;
538 }
539 if(ctx->receivedDataBuffer.data == NULL) {
540 *bufSize = 0;
541 }
542 else {
543 assert(ctx->receivedDataBuffer.length >= ctx->receivedDataPos);
544 *bufSize = ctx->receivedDataBuffer.length - ctx->receivedDataPos;
545 }
546 return noErr;
547 }