2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
22 Contains: SSLContext transport layer
24 Written by: Doug Mitchell, based on Netscape RSARef 3.0
26 Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved.
29 /* *********************************************************************
32 SSLRef 3.0 Final -- 11/19/96
34 Copyright (c)1996 by Netscape Communications Corp.
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.
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/>.
44 *********************************************************************
46 File: ssltrspt.c Data transportation functionality
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.
53 ****************************************************************** */
84 #ifndef _APPLE_GLUE_H_
85 #include "appleGlue.h"
92 #ifndef _CIPHER_SPECS_H_
93 #include "cipherSpecs.h"
96 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
101 #define SSL_IO_TRACE 0
103 static void sslIoTrace(
109 printf("===%s: req %4d moved %4d status %d\n",
110 op
, req
, moved
, stat
);
114 #define sslIoTrace(op, req, moved, stat)
115 #endif /* SSL_IO_TRACE */
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
);
127 UInt32
*bytesWritten
) /* RETURNED */
131 UInt32 dataLen
, processed
;
133 if((ctx
== NULL
) || (bytesWritten
== NULL
)) {
136 dataLen
= dataLength
;
137 processed
= 0; /* Initialize in case we return with SSLWouldBlockErr */
141 case SSLGracefulClose
:
142 err
= SSLConnectionClosedGraceful
;
145 err
= SSLConnectionClosedError
;
148 /* FIXME - original code didn't check for handshake in progress -
151 sslIoTrace("SSLWrite", dataLength
, 0, badReqErr
);
153 case HandshakeServerReady
:
154 case HandshakeClientReady
:
158 /* First, we have to wait until the session is ready to send data,
159 so the encryption keys and such have been established. */
161 while (ctx
->writeCipher
.ready
== 0)
162 { if ((err
= SSLHandshakeProceed(ctx
)) != 0)
166 /* Attempt to empty the write queue before queueing more data */
167 if ((err
= SSLServiceWriteQueue(ctx
)) != 0)
171 /* Fragment, package and encrypt the data and queue the resulting data for sending */
173 { rec
.contentType
= SSL_application_data
;
174 rec
.protocolVersion
= ctx
->negProtocolVersion
;
175 rec
.contents
.data
= ((UInt8
*)data
) + processed
;
177 if (dataLen
< MAX_RECORD_LENGTH
)
178 rec
.contents
.length
= dataLen
;
180 rec
.contents
.length
= MAX_RECORD_LENGTH
;
182 if (ERR(err
= SSLWriteRecord(rec
, ctx
)) != 0)
185 processed
+= rec
.contents
.length
;
186 dataLen
-= rec
.contents
.length
;
189 /* All the data has been advanced to the write queue */
190 *bytesWritten
= processed
;
191 if (ERR(err
= SSLServiceWriteQueue(ctx
)) != 0)
196 if (err
!= 0 && err
!= SSLWouldBlockErr
&& err
!= SSLConnectionClosedGraceful
) {
197 dprintf1("SSLWrite: going to state errorCLose due to err %d\n",
199 SSLChangeHdskState(ctx
, SSLErrorClose
);
202 sslIoTrace("SSLWrite", dataLength
, *bytesWritten
, sslErrToOsStatus(err
));
203 return sslErrToOsStatus(err
);
211 UInt32
*processed
) /* RETURNED */
215 UInt32 bufSize
, remaining
, count
;
218 if((ctx
== NULL
) || (processed
== NULL
)) {
221 bufSize
= dataLength
;
222 *processed
= 0; /* Initialize in case we return with SSLWouldBlockErr */
224 /* first handle cases in which we know we're finished */
226 case SSLGracefulClose
:
227 err
= SSLConnectionClosedGraceful
;
230 err
= SSLConnectionClosedError
;
232 case SSLNoNotifyClose
:
233 err
= SSLConnectionClosedNoNotify
;
239 /* First, we have to wait until the session is ready to receive data,
240 so the encryption keys and such have been established. */
242 while (ctx
->readCipher
.ready
== 0)
243 { if (ERR(err
= SSLHandshakeProceed(ctx
)) != 0)
247 /* Attempt to service the write queue */
248 if (ERR(err
= SSLServiceWriteQueue(ctx
)) != 0)
249 { if (err
!= SSLWouldBlockErr
)
251 err
= SSLNoErr
; /* Write blocking shouldn't stop attempts to read */
255 progress
= (UInt8
*)data
;
256 if (ctx
->receivedDataBuffer
.data
)
257 { count
= ctx
->receivedDataBuffer
.length
- ctx
->receivedDataPos
;
260 memcpy(data
, ctx
->receivedDataBuffer
.data
+ ctx
->receivedDataPos
, count
);
264 ctx
->receivedDataPos
+= count
;
267 CASSERT(ctx
->receivedDataPos
<= ctx
->receivedDataBuffer
.length
);
268 CASSERT(*processed
+ remaining
== bufSize
);
269 CASSERT(progress
== ((UInt8
*)data
) + *processed
);
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;
278 while (remaining
> 0 && ctx
->state
!= SSLGracefulClose
)
279 { CASSERT(ctx
->receivedDataBuffer
.data
== 0);
280 if (ERR(err
= SSLReadRecord(&rec
, ctx
)) != 0)
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
;
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
298 SSLBuffer
*b
= &rec
.contents
;
299 if (ERR(err
= SSLFreeBuffer(b
, &ctx
->sysCtx
)) != 0) {
305 { memcpy(progress
, rec
.contents
.data
, remaining
);
306 progress
+= remaining
;
307 *processed
+= remaining
;
308 ctx
->receivedDataBuffer
= rec
.contents
;
309 ctx
->receivedDataPos
= remaining
;
314 { if (ERR(err
= SSLProcessProtocolMessage(rec
, ctx
)) != 0)
316 if (ERR(err
= SSLFreeBuffer(&rec
.contents
, &ctx
->sysCtx
)) != 0)
324 /* shut down on serious errors */
327 case SSLWouldBlockErr
:
328 case SSLConnectionClosedGraceful
:
329 case SSLConnectionClosedNoNotify
:
332 dprintf1("SSLRead: going to state errorClose due to err %d\n",
334 SSLChangeHdskState(ctx
, SSLErrorClose
);
338 sslIoTrace("SSLRead ", dataLength
, *processed
, sslErrToOsStatus(err
));
339 return sslErrToOsStatus(err
);
343 #include "appleCdsa.h"
347 SSLHandshake(SSLContext
*ctx
)
354 if (ctx
->state
== SSLGracefulClose
)
355 return sslErrToOsStatus(SSLConnectionClosedGraceful
);
356 if (ctx
->state
== SSLErrorClose
)
357 return sslErrToOsStatus(SSLConnectionClosedError
);
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");
369 if(ctx
->validCipherSpecs
== NULL
) {
370 /* build list of legal cipherSpecs */
371 err
= sslBuildCipherSpecArray(ctx
);
377 while (ctx
->readCipher
.ready
== 0 || ctx
->writeCipher
.ready
== 0)
378 { if (ERR(err
= SSLHandshakeProceed(ctx
)) != 0)
379 return sslErrToOsStatus(err
);
387 SSLHandshakeProceed(SSLContext
*ctx
)
391 if (ctx
->state
== SSLUninitialized
)
392 if (ERR(err
= SSLInitConnection(ctx
)) != 0)
394 if (ERR(err
= SSLServiceWriteQueue(ctx
)) != 0)
396 CASSERT(ctx
->readCipher
.ready
== 0);
397 if (ERR(err
= SSLReadRecord(&rec
, ctx
)) != 0)
399 if (ERR(err
= SSLProcessProtocolMessage(rec
, ctx
)) != 0)
400 { SSLFreeBuffer(&rec
.contents
, &ctx
->sysCtx
);
403 if (ERR(err
= SSLFreeBuffer(&rec
.contents
, &ctx
->sysCtx
)) != 0)
410 SSLInitConnection(SSLContext
*ctx
)
413 if (ctx
->protocolSide
== SSL_ClientSide
) {
414 SSLChangeHdskState(ctx
, HandshakeClientUninit
);
417 { CASSERT(ctx
->protocolSide
== SSL_ServerSide
);
418 SSLChangeHdskState(ctx
, HandshakeServerUninit
);
421 if (ctx
->peerID
.data
!= 0)
422 { ERR(SSLGetSessionID(&ctx
->resumableSession
, ctx
));
423 /* Ignore errors; just treat as uncached session */
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
431 if (ctx
->protocolSide
== SSL_ClientSide
&& ctx
->resumableSession
.data
!= 0)
432 { if (ERR(err
= SSLRetrieveSessionIDProtocolVersion(ctx
->resumableSession
,
433 &ctx
->negProtocolVersion
, ctx
)) != 0)
437 /* If we're the client & handshake hasn't yet begun, start it by
438 * pretending we just received a hello request
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)
448 case SSL_Version_3_0_Only
:
449 case SSL_Version_3_0
:
450 if (ERR(err
= SSLAdvanceHandshake(SSL_hello_request
, ctx
)) != 0)
454 sslPanic("Bad protocol version");
463 SSLServiceWriteQueue(SSLContext
*ctx
)
466 SSLBuffer buf
, recBuf
;
469 while ((rec
= ctx
->recordWriteQueue
) != 0)
470 { buf
.data
= rec
->data
.data
+ rec
->sent
;
471 buf
.length
= rec
->data
.length
- rec
->sent
;
473 err
= sslIoWrite(buf
, &written
, ctx
);
475 err
= ctx
->ioCtx
.write(buf
, &written
, ctx
->ioCtx
.ioRef
);
477 // FIXME - detect & abort ERR(err);
478 rec
->sent
+= written
;
479 if (rec
->sent
>= rec
->data
.length
)
480 { CASSERT(rec
->sent
== rec
->data
.length
);
482 err
= SSLFreeBuffer(&rec
->data
, &ctx
->sysCtx
);
484 recBuf
.data
= (UInt8
*)rec
;
485 recBuf
.length
= sizeof(WaitingRecord
);
486 ctx
->recordWriteQueue
= rec
->next
;
487 err
= SSLFreeBuffer(&recBuf
, &ctx
->sysCtx
);
492 CASSERT(ctx
->recordWriteQueue
== 0 || ctx
->recordWriteQueue
->sent
== 0);
499 static void sslLogRxProto(const char *msgType
)
501 printf("---received protoMsg %s\n", msgType
);
504 #define sslLogRxProto(msgType)
505 #endif /* LOG_RX_PROTOCOL */
508 SSLProcessProtocolMessage(SSLRecord rec
, SSLContext
*ctx
)
511 switch (rec
.contentType
)
512 { case SSL_handshake
:
513 sslLogRxProto("SSL_handshake");
514 ERR(err
= SSLProcessHandshakeRecord(rec
, ctx
));
517 sslLogRxProto("SSL_alert");
518 ERR(err
= SSLProcessAlert(rec
, ctx
));
520 case SSL_change_cipher_spec
:
521 sslLogRxProto("SSL_change_cipher_spec");
522 ERR(err
= SSLProcessChangeCipherSpec(rec
, ctx
));
524 case SSL_version_2_0_record
:
525 sslLogRxProto("SSL_version_2_0_record");
526 ERR(err
= SSL2ProcessMessage(rec
, ctx
));
529 sslLogRxProto("Bad msg");
530 return ERR(SSLProtocolErr
);
537 SSLClose(SSLContext
*ctx
)
539 SSLErr err
= SSLNoErr
; /* _APPLE_CDSA_ bug fix - was uninit'd */
544 if (ctx
->negProtocolVersion
== SSL_Version_3_0
)
545 ERR(err
= SSLSendAlert(alert_warning
, alert_close_notify
, ctx
));
547 ERR(err
= SSLServiceWriteQueue(ctx
));
548 SSLChangeHdskState(ctx
, SSLGracefulClose
);
550 err
= SSLNoErr
; /* Ignore errors related to closed streams */
551 return sslErrToOsStatus(err
);