]> git.saurik.com Git - apple/security.git/blob - SecureTransport/ssltrspt.c
Security-29.tar.gz
[apple/security.git] / SecureTransport / ssltrspt.c
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: ssltrspt.c
21
22 Contains: SSLContext transport layer
23
24 Written by: Doug Mitchell, based on Netscape RSARef 3.0
25
26 Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved.
27
28 */
29 /* *********************************************************************
30 File: ssltrspt.c
31
32 SSLRef 3.0 Final -- 11/19/96
33
34 Copyright (c)1996 by Netscape Communications Corp.
35
36 By retrieving this software you are bound by the licensing terms
37 disclosed in the file "LICENSE.txt". Please read it, and if you don't
38 accept the terms, delete this software.
39
40 SSLRef 3.0 was developed by Netscape Communications Corp. of Mountain
41 View, California <http://home.netscape.com/> and Consensus Development
42 Corporation of Berkeley, California <http://www.consensus.com/>.
43
44 *********************************************************************
45
46 File: ssltrspt.c Data transportation functionality
47
48 Transports data between the application and the record layer; also
49 hands off handshake, alert, and change cipher spec messages to their
50 handlers. Also, ensures that negotiation happens before application
51 data goes out on the wire.
52
53 ****************************************************************** */
54
55 #ifndef _SSLTRSPT_H_
56 #include "ssltrspt.h"
57 #endif
58
59 #ifndef _SSLALLOC_H_
60 #include "sslalloc.h"
61 #endif
62
63 #ifndef _SSLCTX_H_
64 #include "sslctx.h"
65 #endif
66
67 #ifndef _SSLCTX_H_
68 #include "sslrec.h"
69 #endif
70
71 #ifndef _SSLALERT_H_
72 #include "sslalert.h"
73 #endif
74
75 #ifndef _SSLSESS_H_
76 #include "sslsess.h"
77 #endif
78
79 #ifndef _SSL2_H_
80 #include "ssl2.h"
81 #endif
82
83 #ifdef _APPLE_CDSA_
84 #ifndef _APPLE_GLUE_H_
85 #include "appleGlue.h"
86 #endif
87
88 #ifndef _SSL_DEBUG_H_
89 #include "sslDebug.h"
90 #endif
91
92 #ifndef _CIPHER_SPECS_H_
93 #include "cipherSpecs.h"
94 #endif
95
96 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
97 #endif
98
99 #include <string.h>
100
101 #define SSL_IO_TRACE 0
102 #if SSL_IO_TRACE
103 static void sslIoTrace(
104 const char *op,
105 UInt32 req,
106 UInt32 moved,
107 OSStatus stat)
108 {
109 printf("===%s: req %4d moved %4d status %d\n",
110 op, req, moved, stat);
111 }
112
113 #else
114 #define sslIoTrace(op, req, moved, stat)
115 #endif /* SSL_IO_TRACE */
116
117 static SSLErr SSLProcessProtocolMessage(SSLRecord rec, SSLContext *ctx);
118 static SSLErr SSLHandshakeProceed(SSLContext *ctx);
119 static SSLErr SSLInitConnection(SSLContext *ctx);
120 static SSLErr SSLServiceWriteQueue(SSLContext *ctx);
121
122 OSStatus
123 SSLWrite(
124 SSLContext *ctx,
125 const void * data,
126 UInt32 dataLength,
127 UInt32 *bytesWritten) /* RETURNED */
128 {
129 SSLErr err;
130 SSLRecord rec;
131 UInt32 dataLen, processed;
132
133 if((ctx == NULL) || (bytesWritten == NULL)) {
134 return paramErr;
135 }
136 dataLen = dataLength;
137 processed = 0; /* Initialize in case we return with SSLWouldBlockErr */
138 *bytesWritten = 0;
139
140 switch(ctx->state) {
141 case SSLGracefulClose:
142 err = SSLConnectionClosedGraceful;
143 goto abort;
144 case SSLErrorClose:
145 err = SSLConnectionClosedError;
146 goto abort;
147 default:
148 /* FIXME - original code didn't check for handshake in progress -
149 * should we?
150 */
151 sslIoTrace("SSLWrite", dataLength, 0, badReqErr);
152 return badReqErr;
153 case HandshakeServerReady:
154 case HandshakeClientReady:
155 break;
156 }
157
158 /* First, we have to wait until the session is ready to send data,
159 so the encryption keys and such have been established. */
160 err = SSLNoErr;
161 while (ctx->writeCipher.ready == 0)
162 { if ((err = SSLHandshakeProceed(ctx)) != 0)
163 goto exit;
164 }
165
166 /* Attempt to empty the write queue before queueing more data */
167 if ((err = SSLServiceWriteQueue(ctx)) != 0)
168 goto abort;
169
170 processed = 0;
171 /* Fragment, package and encrypt the data and queue the resulting data for sending */
172 while (dataLen > 0)
173 { rec.contentType = SSL_application_data;
174 rec.protocolVersion = ctx->negProtocolVersion;
175 rec.contents.data = ((UInt8*)data) + processed;
176
177 if (dataLen < MAX_RECORD_LENGTH)
178 rec.contents.length = dataLen;
179 else
180 rec.contents.length = MAX_RECORD_LENGTH;
181
182 if (ERR(err = SSLWriteRecord(rec, ctx)) != 0)
183 goto exit;
184
185 processed += rec.contents.length;
186 dataLen -= rec.contents.length;
187 }
188
189 /* All the data has been advanced to the write queue */
190 *bytesWritten = processed;
191 if (ERR(err = SSLServiceWriteQueue(ctx)) != 0)
192 goto exit;
193
194 err = SSLNoErr;
195 exit:
196 if (err != 0 && err != SSLWouldBlockErr && err != SSLConnectionClosedGraceful) {
197 dprintf1("SSLWrite: going to state errorCLose due to err %d\n",
198 err);
199 SSLChangeHdskState(ctx, SSLErrorClose);
200 }
201 abort:
202 sslIoTrace("SSLWrite", dataLength, *bytesWritten, sslErrToOsStatus(err));
203 return sslErrToOsStatus(err);
204 }
205
206 OSStatus
207 SSLRead (
208 SSLContext *ctx,
209 void * data,
210 UInt32 dataLength,
211 UInt32 *processed) /* RETURNED */
212 {
213 SSLErr err;
214 UInt8 *progress;
215 UInt32 bufSize, remaining, count;
216 SSLRecord rec;
217
218 if((ctx == NULL) || (processed == NULL)) {
219 return paramErr;
220 }
221 bufSize = dataLength;
222 *processed = 0; /* Initialize in case we return with SSLWouldBlockErr */
223
224 /* first handle cases in which we know we're finished */
225 switch(ctx->state) {
226 case SSLGracefulClose:
227 err = SSLConnectionClosedGraceful;
228 goto abort;
229 case SSLErrorClose:
230 err = SSLConnectionClosedError;
231 goto abort;
232 case SSLNoNotifyClose:
233 err = SSLConnectionClosedNoNotify;
234 goto abort;
235 default:
236 break;
237 }
238
239 /* First, we have to wait until the session is ready to receive data,
240 so the encryption keys and such have been established. */
241 err = SSLNoErr;
242 while (ctx->readCipher.ready == 0)
243 { if (ERR(err = SSLHandshakeProceed(ctx)) != 0)
244 goto exit;
245 }
246
247 /* Attempt to service the write queue */
248 if (ERR(err = SSLServiceWriteQueue(ctx)) != 0)
249 { if (err != SSLWouldBlockErr)
250 goto exit;
251 err = SSLNoErr; /* Write blocking shouldn't stop attempts to read */
252 }
253
254 remaining = bufSize;
255 progress = (UInt8*)data;
256 if (ctx->receivedDataBuffer.data)
257 { count = ctx->receivedDataBuffer.length - ctx->receivedDataPos;
258 if (count > bufSize)
259 count = bufSize;
260 memcpy(data, ctx->receivedDataBuffer.data + ctx->receivedDataPos, count);
261 remaining -= count;
262 progress += count;
263 *processed += count;
264 ctx->receivedDataPos += count;
265 }
266
267 CASSERT(ctx->receivedDataPos <= ctx->receivedDataBuffer.length);
268 CASSERT(*processed + remaining == bufSize);
269 CASSERT(progress == ((UInt8*)data) + *processed);
270
271 if (ctx->receivedDataBuffer.data != 0 &&
272 ctx->receivedDataPos >= ctx->receivedDataBuffer.length)
273 { SSLFreeBuffer(&ctx->receivedDataBuffer, &ctx->sysCtx);
274 ctx->receivedDataBuffer.data = 0;
275 ctx->receivedDataPos = 0;
276 }
277
278 while (remaining > 0 && ctx->state != SSLGracefulClose)
279 { CASSERT(ctx->receivedDataBuffer.data == 0);
280 if (ERR(err = SSLReadRecord(&rec, ctx)) != 0)
281 goto exit;
282
283 if (rec.contentType == SSL_application_data ||
284 rec.contentType == SSL_version_2_0_record)
285 { if (rec.contents.length <= remaining)
286 { memcpy(progress, rec.contents.data, rec.contents.length);
287 remaining -= rec.contents.length;
288 progress += rec.contents.length;
289 *processed += rec.contents.length;
290 /* COMPILER BUG!
291 * This:
292 * if (ERR(err = SSLFreeBuffer(&rec.contents, &ctx->sysCtx)) != 0)
293 * passes the address of rec to SSLFreeBuffer, not the address
294 * of the contents field (which should be offset 8 from the start
295 * of rec).
296 */
297 {
298 SSLBuffer *b = &rec.contents;
299 if (ERR(err = SSLFreeBuffer(b, &ctx->sysCtx)) != 0) {
300 goto exit;
301 }
302 }
303 }
304 else
305 { memcpy(progress, rec.contents.data, remaining);
306 progress += remaining;
307 *processed += remaining;
308 ctx->receivedDataBuffer = rec.contents;
309 ctx->receivedDataPos = remaining;
310 remaining = 0;
311 }
312 }
313 else
314 { if (ERR(err = SSLProcessProtocolMessage(rec, ctx)) != 0)
315 goto exit;
316 if (ERR(err = SSLFreeBuffer(&rec.contents, &ctx->sysCtx)) != 0)
317 goto exit;
318 }
319 }
320
321 err = SSLNoErr;
322
323 exit:
324 /* shut down on serious errors */
325 switch(err) {
326 case SSLNoErr:
327 case SSLWouldBlockErr:
328 case SSLConnectionClosedGraceful:
329 case SSLConnectionClosedNoNotify:
330 break;
331 default:
332 dprintf1("SSLRead: going to state errorClose due to err %d\n",
333 err);
334 SSLChangeHdskState(ctx, SSLErrorClose);
335 break;
336 }
337 abort:
338 sslIoTrace("SSLRead ", dataLength, *processed, sslErrToOsStatus(err));
339 return sslErrToOsStatus(err);
340 }
341
342 #if SSL_DEBUG
343 #include "appleCdsa.h"
344 #endif
345
346 OSStatus
347 SSLHandshake(SSLContext *ctx)
348 {
349 SSLErr err;
350
351 if(ctx == NULL) {
352 return paramErr;
353 }
354 if (ctx->state == SSLGracefulClose)
355 return sslErrToOsStatus(SSLConnectionClosedGraceful);
356 if (ctx->state == SSLErrorClose)
357 return sslErrToOsStatus(SSLConnectionClosedError);
358
359 if(ctx->protocolSide == SSL_ServerSide) {
360 /* some things the caller really has to have done by now... */
361 if((ctx->localCert == NULL) ||
362 (ctx->signingPrivKey == NULL) ||
363 (ctx->signingPubKey == NULL) ||
364 (ctx->signingKeyCsp == 0)) {
365 errorLog0("SSLHandshake: insufficient init\n");
366 return badReqErr;
367 }
368 }
369 if(ctx->validCipherSpecs == NULL) {
370 /* build list of legal cipherSpecs */
371 err = sslBuildCipherSpecArray(ctx);
372 if(err) {
373 return err;
374 }
375 }
376 err = SSLNoErr;
377 while (ctx->readCipher.ready == 0 || ctx->writeCipher.ready == 0)
378 { if (ERR(err = SSLHandshakeProceed(ctx)) != 0)
379 return sslErrToOsStatus(err);
380 }
381
382 return noErr;
383 }
384
385
386 static SSLErr
387 SSLHandshakeProceed(SSLContext *ctx)
388 { SSLErr err;
389 SSLRecord rec;
390
391 if (ctx->state == SSLUninitialized)
392 if (ERR(err = SSLInitConnection(ctx)) != 0)
393 return err;
394 if (ERR(err = SSLServiceWriteQueue(ctx)) != 0)
395 return err;
396 CASSERT(ctx->readCipher.ready == 0);
397 if (ERR(err = SSLReadRecord(&rec, ctx)) != 0)
398 return err;
399 if (ERR(err = SSLProcessProtocolMessage(rec, ctx)) != 0)
400 { SSLFreeBuffer(&rec.contents, &ctx->sysCtx);
401 return err;
402 }
403 if (ERR(err = SSLFreeBuffer(&rec.contents, &ctx->sysCtx)) != 0)
404 return err;
405
406 return SSLNoErr;
407 }
408
409 static SSLErr
410 SSLInitConnection(SSLContext *ctx)
411 { SSLErr err;
412
413 if (ctx->protocolSide == SSL_ClientSide) {
414 SSLChangeHdskState(ctx, HandshakeClientUninit);
415 }
416 else
417 { CASSERT(ctx->protocolSide == SSL_ServerSide);
418 SSLChangeHdskState(ctx, HandshakeServerUninit);
419 }
420
421 if (ctx->peerID.data != 0)
422 { ERR(SSLGetSessionID(&ctx->resumableSession, ctx));
423 /* Ignore errors; just treat as uncached session */
424 }
425
426 /* If we're a client, and we have a cached resumable session, we want
427 * to try to negotiate the same session type we negotiated before,
428 * because an SSL 3.0 session can only be resumed with an SSL 3.0
429 * hello message.
430 */
431 if (ctx->protocolSide == SSL_ClientSide && ctx->resumableSession.data != 0)
432 { if (ERR(err = SSLRetrieveSessionIDProtocolVersion(ctx->resumableSession,
433 &ctx->negProtocolVersion, ctx)) != 0)
434 return err;
435 }
436
437 /* If we're the client & handshake hasn't yet begun, start it by
438 * pretending we just received a hello request
439 */
440 if (ctx->state == HandshakeClientUninit && ctx->writeCipher.ready == 0)
441 { switch (ctx->negProtocolVersion)
442 { case SSL_Version_Undetermined:
443 case SSL_Version_3_0_With_2_0_Hello:
444 case SSL_Version_2_0:
445 if (ERR(err = SSL2AdvanceHandshake(ssl2_mt_kickstart_handshake, ctx)) != 0)
446 return err;
447 break;
448 case SSL_Version_3_0_Only:
449 case SSL_Version_3_0:
450 if (ERR(err = SSLAdvanceHandshake(SSL_hello_request, ctx)) != 0)
451 return err;
452 break;
453 default:
454 sslPanic("Bad protocol version");
455 break;
456 }
457 }
458
459 return SSLNoErr;
460 }
461
462 static SSLErr
463 SSLServiceWriteQueue(SSLContext *ctx)
464 { SSLErr err;
465 UInt32 written;
466 SSLBuffer buf, recBuf;
467 WaitingRecord *rec;
468
469 while ((rec = ctx->recordWriteQueue) != 0)
470 { buf.data = rec->data.data + rec->sent;
471 buf.length = rec->data.length - rec->sent;
472 #ifdef _APPLE_CDSA_
473 err = sslIoWrite(buf, &written, ctx);
474 #else
475 err = ctx->ioCtx.write(buf, &written, ctx->ioCtx.ioRef);
476 #endif
477 // FIXME - detect & abort ERR(err);
478 rec->sent += written;
479 if (rec->sent >= rec->data.length)
480 { CASSERT(rec->sent == rec->data.length);
481 CASSERT(err == 0);
482 err = SSLFreeBuffer(&rec->data, &ctx->sysCtx);
483 CASSERT(err == 0);
484 recBuf.data = (UInt8*)rec;
485 recBuf.length = sizeof(WaitingRecord);
486 ctx->recordWriteQueue = rec->next;
487 err = SSLFreeBuffer(&recBuf, &ctx->sysCtx);
488 CASSERT(err == 0);
489 }
490 if (ERR(err))
491 return err;
492 CASSERT(ctx->recordWriteQueue == 0 || ctx->recordWriteQueue->sent == 0);
493 }
494
495 return SSLNoErr;
496 }
497
498 #if LOG_RX_PROTOCOL
499 static void sslLogRxProto(const char *msgType)
500 {
501 printf("---received protoMsg %s\n", msgType);
502 }
503 #else
504 #define sslLogRxProto(msgType)
505 #endif /* LOG_RX_PROTOCOL */
506
507 static SSLErr
508 SSLProcessProtocolMessage(SSLRecord rec, SSLContext *ctx)
509 { SSLErr err;
510
511 switch (rec.contentType)
512 { case SSL_handshake:
513 sslLogRxProto("SSL_handshake");
514 ERR(err = SSLProcessHandshakeRecord(rec, ctx));
515 break;
516 case SSL_alert:
517 sslLogRxProto("SSL_alert");
518 ERR(err = SSLProcessAlert(rec, ctx));
519 break;
520 case SSL_change_cipher_spec:
521 sslLogRxProto("SSL_change_cipher_spec");
522 ERR(err = SSLProcessChangeCipherSpec(rec, ctx));
523 break;
524 case SSL_version_2_0_record:
525 sslLogRxProto("SSL_version_2_0_record");
526 ERR(err = SSL2ProcessMessage(rec, ctx));
527 break;
528 default:
529 sslLogRxProto("Bad msg");
530 return ERR(SSLProtocolErr);
531 }
532
533 return err;
534 }
535
536 OSStatus
537 SSLClose(SSLContext *ctx)
538 {
539 SSLErr err = SSLNoErr; /* _APPLE_CDSA_ bug fix - was uninit'd */
540
541 if(ctx == NULL) {
542 return paramErr;
543 }
544 if (ctx->negProtocolVersion == SSL_Version_3_0)
545 ERR(err = SSLSendAlert(alert_warning, alert_close_notify, ctx));
546 if (err == 0)
547 ERR(err = SSLServiceWriteQueue(ctx));
548 SSLChangeHdskState(ctx, SSLGracefulClose);
549 if (err == SSLIOErr)
550 err = SSLNoErr; /* Ignore errors related to closed streams */
551 return sslErrToOsStatus(err);
552 }