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 SSLRef 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 ****************************************************************** */
83 #ifndef _APPLE_GLUE_H_
84 #include "appleGlue.h"
91 #ifndef _CIPHER_SPECS_H_
92 #include "cipherSpecs.h"
95 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
100 #define SSL_IO_TRACE 0
102 static void sslIoTrace(
108 printf("===%s: req %4d moved %4d status %d\n",
109 op
, req
, moved
, stat
);
113 #define sslIoTrace(op, req, moved, stat)
114 #endif /* SSL_IO_TRACE */
116 static SSLErr
SSLProcessProtocolMessage(SSLRecord rec
, SSLContext
*ctx
);
117 static SSLErr
SSLHandshakeProceed(SSLContext
*ctx
);
118 static SSLErr
SSLInitConnection(SSLContext
*ctx
);
119 static SSLErr
SSLServiceWriteQueue(SSLContext
*ctx
);
126 UInt32
*bytesWritten
) /* RETURNED */
130 UInt32 dataLen
, processed
;
132 if((ctx
== NULL
) || (bytesWritten
== NULL
)) {
135 dataLen
= dataLength
;
136 processed
= 0; /* Initialize in case we return with SSLWouldBlockErr */
140 case SSLGracefulClose
:
141 err
= SSLConnectionClosedGraceful
;
144 err
= SSLConnectionClosedError
;
147 /* FIXME - original code didn't check for handshake in progress -
150 sslIoTrace("SSLWrite", dataLength
, 0, badReqErr
);
152 case HandshakeServerReady
:
153 case HandshakeClientReady
:
157 /* First, we have to wait until the session is ready to send data,
158 so the encryption keys and such have been established. */
160 while (ctx
->writeCipher
.ready
== 0)
161 { if ((err
= SSLHandshakeProceed(ctx
)) != 0)
165 /* Attempt to empty the write queue before queueing more data */
166 if ((err
= SSLServiceWriteQueue(ctx
)) != 0)
170 /* Fragment, package and encrypt the data and queue the resulting data for sending */
172 { rec
.contentType
= SSL_application_data
;
173 rec
.protocolVersion
= ctx
->negProtocolVersion
;
174 rec
.contents
.data
= ((UInt8
*)data
) + processed
;
176 if (dataLen
< MAX_RECORD_LENGTH
)
177 rec
.contents
.length
= dataLen
;
179 rec
.contents
.length
= MAX_RECORD_LENGTH
;
181 assert(ctx
->sslTslCalls
!= NULL
);
182 if (ERR(err
= ctx
->sslTslCalls
->writeRecord(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;
279 * This while statement causes a hang when using nonblocking low-level I/O!
280 while (remaining > 0 && ctx->state != SSLGracefulClose)
281 ..what we really have to do is just return as soon as we read one
282 record. A performance hit in the nonblocking case, but that is
283 the only way this code can work in both modes...
285 if (remaining
> 0 && ctx
->state
!= SSLGracefulClose
)
286 { CASSERT(ctx
->receivedDataBuffer
.data
== 0);
287 if (ERR(err
= SSLReadRecord(&rec
, ctx
)) != 0)
290 if (rec
.contentType
== SSL_application_data
||
291 rec
.contentType
== SSL_version_2_0_record
)
292 { if (rec
.contents
.length
<= remaining
)
293 { memcpy(progress
, rec
.contents
.data
, rec
.contents
.length
);
294 remaining
-= rec
.contents
.length
;
295 progress
+= rec
.contents
.length
;
296 *processed
+= rec
.contents
.length
;
299 * if (ERR(err = SSLFreeBuffer(&rec.contents, &ctx->sysCtx)) != 0)
300 * passes the address of rec to SSLFreeBuffer, not the address
301 * of the contents field (which should be offset 8 from the start
305 SSLBuffer
*b
= &rec
.contents
;
306 if (ERR(err
= SSLFreeBuffer(b
, &ctx
->sysCtx
)) != 0) {
312 { memcpy(progress
, rec
.contents
.data
, remaining
);
313 progress
+= remaining
;
314 *processed
+= remaining
;
315 ctx
->receivedDataBuffer
= rec
.contents
;
316 ctx
->receivedDataPos
= remaining
;
321 { if (ERR(err
= SSLProcessProtocolMessage(rec
, ctx
)) != 0)
323 if (ERR(err
= SSLFreeBuffer(&rec
.contents
, &ctx
->sysCtx
)) != 0)
331 /* shut down on serious errors */
334 case SSLWouldBlockErr
:
335 case SSLConnectionClosedGraceful
:
336 case SSLConnectionClosedNoNotify
:
339 dprintf1("SSLRead: going to state errorClose due to err %d\n",
341 SSLChangeHdskState(ctx
, SSLErrorClose
);
345 sslIoTrace("SSLRead ", dataLength
, *processed
, sslErrToOsStatus(err
));
346 return sslErrToOsStatus(err
);
350 #include "appleCdsa.h"
354 SSLHandshake(SSLContext
*ctx
)
361 if (ctx
->state
== SSLGracefulClose
)
362 return sslErrToOsStatus(SSLConnectionClosedGraceful
);
363 if (ctx
->state
== SSLErrorClose
)
364 return sslErrToOsStatus(SSLConnectionClosedError
);
366 if(ctx
->protocolSide
== SSL_ServerSide
) {
367 /* some things the caller really has to have done by now... */
368 if((ctx
->localCert
== NULL
) ||
369 (ctx
->signingPrivKey
== NULL
) ||
370 (ctx
->signingPubKey
== NULL
) ||
371 (ctx
->signingKeyCsp
== 0)) {
372 errorLog0("SSLHandshake: insufficient init\n");
376 if(ctx
->validCipherSpecs
== NULL
) {
377 /* build list of legal cipherSpecs */
378 err
= sslBuildCipherSpecArray(ctx
);
384 while (ctx
->readCipher
.ready
== 0 || ctx
->writeCipher
.ready
== 0)
385 { if (ERR(err
= SSLHandshakeProceed(ctx
)) != 0)
386 return sslErrToOsStatus(err
);
389 /* one more flush at completion of successful handshake */
390 if ((err
= SSLServiceWriteQueue(ctx
)) != 0) {
391 return sslErrToOsStatus(err
);
398 SSLHandshakeProceed(SSLContext
*ctx
)
402 if (ctx
->state
== SSLUninitialized
)
403 if (ERR(err
= SSLInitConnection(ctx
)) != 0)
405 if (ERR(err
= SSLServiceWriteQueue(ctx
)) != 0)
407 CASSERT(ctx
->readCipher
.ready
== 0);
408 if (ERR(err
= SSLReadRecord(&rec
, ctx
)) != 0)
410 if (ERR(err
= SSLProcessProtocolMessage(rec
, ctx
)) != 0)
411 { SSLFreeBuffer(&rec
.contents
, &ctx
->sysCtx
);
414 if (ERR(err
= SSLFreeBuffer(&rec
.contents
, &ctx
->sysCtx
)) != 0)
421 SSLInitConnection(SSLContext
*ctx
)
424 if (ctx
->protocolSide
== SSL_ClientSide
) {
425 SSLChangeHdskState(ctx
, HandshakeClientUninit
);
428 { CASSERT(ctx
->protocolSide
== SSL_ServerSide
);
429 SSLChangeHdskState(ctx
, HandshakeServerUninit
);
432 if (ctx
->peerID
.data
!= 0)
433 { ERR(SSLGetSessionData(&ctx
->resumableSession
, ctx
));
434 /* Ignore errors; just treat as uncached session */
438 * If we have a cached resumable session, blow it off if it's a higher
439 * version than the max currently allowed. Note that this means that once
440 * a process negotiates a given version with a given server/port, it won't
441 * be able to negotiate a higher version. We might want to revisit this.
443 if (ctx
->resumableSession
.data
!= 0) {
445 SSLProtocolVersion savedVersion
;
447 if (ERR(err
= SSLRetrieveSessionProtocolVersion(ctx
->resumableSession
,
448 &savedVersion
, ctx
)) != 0) {
451 if(savedVersion
> ctx
->maxProtocolVersion
) {
452 SSLLogResumSess("===Resumable session protocol mismatch\n");
453 SSLFreeBuffer(&ctx
->resumableSession
, &ctx
->sysCtx
);
456 SSLLogResumSess("===attempting to resume session\n");
458 * A bit of a special case for server side here. If currently
459 * configged to allow for SSL3/TLS1 with an SSL2 hello, we
460 * don't want to preclude the possiblity of an SSL2 hello...
461 * so we'll just leave the negProtocolVersion alone in the server case.
463 if(ctx
->protocolSide
== SSL_ClientSide
) {
464 ctx
->negProtocolVersion
= savedVersion
;
469 /* If we're the client & handshake hasn't yet begun, start it by
470 * pretending we just received a hello request
472 if (ctx
->state
== HandshakeClientUninit
&& ctx
->writeCipher
.ready
== 0)
473 { switch (ctx
->negProtocolVersion
)
474 { case SSL_Version_Undetermined
:
475 case SSL_Version_3_0_With_2_0_Hello
:
476 case SSL_Version_2_0
:
477 if (ERR(err
= SSL2AdvanceHandshake(ssl2_mt_kickstart_handshake
, ctx
)) != 0)
480 case SSL_Version_3_0_Only
:
481 case SSL_Version_3_0
:
482 case TLS_Version_1_0_Only
:
483 case TLS_Version_1_0
:
484 if (ERR(err
= SSLAdvanceHandshake(SSL_hello_request
, ctx
)) != 0)
488 sslPanic("Bad protocol version");
497 SSLServiceWriteQueue(SSLContext
*ctx
)
498 { SSLErr err
= SSLNoErr
, werr
= SSLNoErr
;
500 SSLBuffer buf
, recBuf
;
503 while (!werr
&& ((rec
= ctx
->recordWriteQueue
) != 0))
504 { buf
.data
= rec
->data
.data
+ rec
->sent
;
505 buf
.length
= rec
->data
.length
- rec
->sent
;
506 werr
= sslIoWrite(buf
, &written
, ctx
);
507 rec
->sent
+= written
;
508 if (rec
->sent
>= rec
->data
.length
)
509 { CASSERT(rec
->sent
== rec
->data
.length
);
511 err
= SSLFreeBuffer(&rec
->data
, &ctx
->sysCtx
);
513 recBuf
.data
= (UInt8
*)rec
;
514 recBuf
.length
= sizeof(WaitingRecord
);
515 ctx
->recordWriteQueue
= rec
->next
;
516 err
= SSLFreeBuffer(&recBuf
, &ctx
->sysCtx
);
521 CASSERT(ctx
->recordWriteQueue
== 0 || ctx
->recordWriteQueue
->sent
== 0);
528 static void sslLogRxProto(const char *msgType
)
530 printf("---received protoMsg %s\n", msgType
);
533 #define sslLogRxProto(msgType)
534 #endif /* LOG_RX_PROTOCOL */
537 SSLProcessProtocolMessage(SSLRecord rec
, SSLContext
*ctx
)
540 switch (rec
.contentType
)
541 { case SSL_handshake
:
542 sslLogRxProto("SSL_handshake");
543 ERR(err
= SSLProcessHandshakeRecord(rec
, ctx
));
546 sslLogRxProto("SSL_alert");
547 ERR(err
= SSLProcessAlert(rec
, ctx
));
549 case SSL_change_cipher_spec
:
550 sslLogRxProto("SSL_change_cipher_spec");
551 ERR(err
= SSLProcessChangeCipherSpec(rec
, ctx
));
553 case SSL_version_2_0_record
:
554 sslLogRxProto("SSL_version_2_0_record");
555 ERR(err
= SSL2ProcessMessage(rec
, ctx
));
558 sslLogRxProto("Bad msg");
559 return ERR(SSLProtocolErr
);
566 SSLClose(SSLContext
*ctx
)
568 SSLErr err
= SSLNoErr
;
573 if (ctx
->negProtocolVersion
>= SSL_Version_3_0
)
574 ERR(err
= SSLSendAlert(alert_warning
, alert_close_notify
, ctx
));
576 ERR(err
= SSLServiceWriteQueue(ctx
));
577 SSLChangeHdskState(ctx
, SSLGracefulClose
);
579 err
= SSLNoErr
; /* Ignore errors related to closed streams */
580 return sslErrToOsStatus(err
);
584 * Determine how much data the client can be guaranteed to
585 * obtain via SSLRead() without blocking or causing any low-level
586 * read operations to occur.
588 * Implemented here because the relevant info in SSLContext (receivedDataBuffer
589 * and receivedDataPos) are only used in this file.
592 SSLGetBufferedReadSize(SSLContextRef ctx
,
593 size_t *bufSize
) /* RETURNED */
598 if(ctx
->receivedDataBuffer
.data
== NULL
) {
602 CASSERT(ctx
->receivedDataBuffer
.length
>= ctx
->receivedDataPos
);
603 *bufSize
= ctx
->receivedDataBuffer
.length
- ctx
->receivedDataPos
;