2 * Copyright (c) 1999-2001,2005-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * sslTransport.c - SSL transport layer
29 #include "sslMemory.h"
30 #include "sslContext.h"
31 #include "sslRecord.h"
32 #include "sslAlertMessage.h"
33 #include "sslSession.h"
35 #include "sslCipherSpecs.h"
41 #include <utilities/SecIOFormat.h>
44 static inline void sslIoTrace(
51 sslLogRecordIo("[%p] ===%s: req %4lu moved %4lu status %d",
52 ctx
, op
, req
, moved
, (int)stat
);
55 #define sslIoTrace(ctx, op, req, moved, stat)
58 extern int kSplitDefaultValue
;
60 static OSStatus
SSLProcessProtocolMessage(SSLRecord
*rec
, SSLContext
*ctx
);
61 static OSStatus
SSLHandshakeProceed(SSLContext
*ctx
);
62 //static OSStatus SSLInitConnection(SSLContext *ctx);
69 size_t *bytesWritten
) /* RETURNED */
73 size_t dataLen
, processed
;
75 sslLogRecordIo("[%p] SSLWrite top", ctx
);
76 if((ctx
== NULL
) || (bytesWritten
== NULL
)) {
80 processed
= 0; /* Initialize in case we return with errSSLWouldBlock */
84 case SSL_HdskStateGracefulClose
:
85 err
= errSSLClosedGraceful
;
87 case SSL_HdskStateErrorClose
:
88 err
= errSSLClosedAbort
;
90 case SSL_HdskStateReady
:
92 case SSL_HdskStateUninit
:
93 /* not ready for I/O, and handshake not in progress */
94 sslIoTrace(ctx
, "SSLWrite(1)", dataLength
, 0, errSecBadReq
);
97 /* handshake in progress or done. Will call SSLHandshakeProceed below if necessary */
101 /* First, we have to wait until the session is ready to send data,
102 so the encryption keys and such have been established. */
104 while (!(ctx
->writeCipher_ready
))
105 { if ((err
= SSLHandshakeProceed(ctx
)) != 0)
109 /* Attempt to empty the write queue before queueing more data */
110 if ((err
= SSLServiceWriteQueue(ctx
)) != 0)
115 /* Skip empty writes, fragmentation is done at the coreTLS layer */
117 rec
.contentType
= SSL_RecordTypeAppData
;
118 rec
.protocolVersion
= ctx
->negProtocolVersion
;
119 rec
.contents
.data
= ((uint8_t *)data
) + processed
;
120 rec
.contents
.length
= dataLen
;
121 if ((err
= SSLWriteRecord(rec
, ctx
)) != 0)
123 processed
+= rec
.contents
.length
;
126 /* All the data has been advanced to the write queue */
127 *bytesWritten
= processed
;
128 if ((err
= SSLServiceWriteQueue(ctx
)) == 0) {
134 case errSSLWouldBlock
:
135 case errSSLUnexpectedRecord
:
136 case errSSLServerAuthCompleted
: /* == errSSLClientAuthCompleted */
137 case errSSLClientCertRequested
:
138 case errSSLClosedGraceful
:
141 sslErrorLog("SSLWrite: going to state errorClose due to err %d\n",
143 SSLChangeHdskState(ctx
, SSL_HdskStateErrorClose
);
147 sslIoTrace(ctx
, "SSLWrite(2)", dataLength
, *bytesWritten
, err
);
156 size_t *processed
) /* RETURNED */
160 size_t bufSize
, remaining
, count
;
163 sslLogRecordIo("[%p] SSLRead top (dataLength=%ld)", ctx
, dataLength
);
164 if((ctx
== NULL
) || (data
== NULL
) || (processed
== NULL
)) {
167 bufSize
= dataLength
;
168 *processed
= 0; /* Initialize in case we return with errSSLWouldBlock */
171 /* first handle cases in which we know we're finished */
173 case SSL_HdskStateGracefulClose
:
174 err
= errSSLClosedGraceful
;
176 case SSL_HdskStateErrorClose
:
177 err
= errSSLClosedAbort
;
179 case SSL_HdskStateNoNotifyClose
:
180 err
= errSSLClosedNoNotify
;
186 /* First, we have to wait until the session is ready to receive data,
187 so the encryption keys and such have been established. */
189 while (ctx
->readCipher_ready
== 0) {
190 if ((err
= SSLHandshakeProceed(ctx
)) != 0) {
195 /* Attempt to service the write queue */
196 if ((err
= SSLServiceWriteQueue(ctx
)) != 0) {
197 if (err
!= errSSLWouldBlock
) {
200 err
= errSecSuccess
; /* Write blocking shouldn't stop attempts to read */
204 charPtr
= (uint8_t *)data
;
205 if (ctx
->receivedDataBuffer
.data
)
206 { count
= ctx
->receivedDataBuffer
.length
- ctx
->receivedDataPos
;
209 memcpy(data
, ctx
->receivedDataBuffer
.data
+ ctx
->receivedDataPos
, count
);
213 ctx
->receivedDataPos
+= count
;
216 assert(ctx
->receivedDataPos
<= ctx
->receivedDataBuffer
.length
);
217 assert(*processed
+ remaining
== bufSize
);
218 assert(charPtr
== ((uint8_t *)data
) + *processed
);
220 if (ctx
->receivedDataBuffer
.data
!= 0 &&
221 ctx
->receivedDataPos
>= ctx
->receivedDataBuffer
.length
)
222 { SSLFreeBuffer(&ctx
->receivedDataBuffer
);
223 ctx
->receivedDataBuffer
.data
= 0;
224 ctx
->receivedDataPos
= 0;
228 * This while statement causes a hang when using nonblocking low-level I/O!
229 while (remaining > 0 && ctx->state != SSL_HdskStateGracefulClose)
230 ..what we really have to do is just return as soon as we read one
231 record. A performance hit in the nonblocking case, but that is
232 the only way this code can work in both modes...
234 if (remaining
> 0 && ctx
->state
!= SSL_HdskStateGracefulClose
)
235 { assert(ctx
->receivedDataBuffer
.data
== 0);
236 if ((err
= SSLReadRecord(&rec
, ctx
)) != 0) {
239 if (rec
.contentType
== SSL_RecordTypeAppData
||
240 rec
.contentType
== SSL_RecordTypeV2_0
)
241 { if (rec
.contents
.length
<= remaining
)
242 { memcpy(charPtr
, rec
.contents
.data
, rec
.contents
.length
);
243 remaining
-= rec
.contents
.length
;
244 charPtr
+= rec
.contents
.length
;
245 *processed
+= rec
.contents
.length
;
247 if ((err
= SSLFreeRecord(rec
, ctx
))) {
253 { memcpy(charPtr
, rec
.contents
.data
, remaining
);
254 charPtr
+= remaining
;
255 *processed
+= remaining
;
256 ctx
->receivedDataBuffer
= rec
.contents
;
257 ctx
->receivedDataPos
= remaining
;
262 if ((err
= SSLProcessProtocolMessage(&rec
, ctx
)) != 0) {
263 /* This may not make much sense, but this is required so that we
264 process the write queue. This replicate exactly the behavior
265 before the coreTLS adoption */
266 if(err
== errSSLClosedGraceful
) {
272 if ((err
= SSLFreeRecord(rec
, ctx
))) {
281 /* test for renegotiate: loop until something useful happens */
282 if(((err
== errSecSuccess
) && (*processed
== 0) && dataLength
) || (err
== errSSLUnexpectedRecord
)) {
283 sslLogNegotiateDebug("SSLRead recursion");
286 /* shut down on serious errors */
289 case errSSLWouldBlock
:
290 case errSSLUnexpectedRecord
:
291 case errSSLServerAuthCompleted
: /* == errSSLClientAuthCompleted */
292 case errSSLClientCertRequested
:
293 case errSSLClosedGraceful
:
294 case errSSLClosedNoNotify
:
297 sslErrorLog("SSLRead: going to state errorClose due to err %d\n",
299 SSLChangeHdskState(ctx
, SSL_HdskStateErrorClose
);
303 sslIoTrace(ctx
, "SSLRead returns", dataLength
, *processed
, err
);
308 #include "sslCrypto.h"
312 SSLHandshake(SSLContext
*ctx
)
319 if (ctx
->state
== SSL_HdskStateGracefulClose
)
320 return errSSLClosedGraceful
;
321 if (ctx
->state
== SSL_HdskStateErrorClose
)
322 return errSSLClosedAbort
;
324 if(ctx
->validCipherSuites
== NULL
) {
325 /* build list of legal cipherSpecs */
326 err
= sslBuildCipherSuiteArray(ctx
);
334 if(ctx
->isDTLS
&& ctx
->timeout_deadline
) {
335 CFAbsoluteTime current
= CFAbsoluteTimeGetCurrent();
337 if (ctx
->timeout_deadline
<current
) {
338 sslDebugLog("%p, retransmition deadline expired\n", ctx
);
339 err
= tls_handshake_retransmit_timer_expired(ctx
->hdsk
);
346 while (ctx
->readCipher_ready
== 0 || ctx
->writeCipher_ready
== 0)
348 err
= SSLHandshakeProceed(ctx
);
349 if((err
!= 0) && (err
!= errSSLUnexpectedRecord
))
353 /* one more flush at completion of successful handshake */
354 if ((err
= SSLServiceWriteQueue(ctx
)) != 0) {
358 return errSecSuccess
;
363 SSLHandshakeProceed(SSLContext
*ctx
)
368 if(ctx
->state
==SSL_HdskStateUninit
) {
369 /* If we are the client, we start the negotiation */
370 if(ctx
->protocolSide
== kSSLClientSide
) {
371 err
= tls_handshake_negotiate(ctx
->hdsk
, &ctx
->peerID
);
375 SSLChangeHdskState(ctx
, SSL_HdskStatePending
);
378 if ((err
= tls_handshake_continue(ctx
->hdsk
)) != 0)
381 if ((err
= SSLServiceWriteQueue(ctx
)) != 0)
386 err
= SSLReadRecord(&rec
, ctx
);
389 sslDebugLog("%p going to process a record (rec.len=%zd, ct=%d)\n", ctx
, rec
.contents
.length
, rec
.contentType
);
390 err
= tls_handshake_process(ctx
->hdsk
, rec
.contents
, rec
.contentType
);
391 sslDebugLog("%p processed a record (rec.len=%zd, ct=%d, err=%d)\n", ctx
, rec
.contents
.length
, rec
.contentType
, (int)err
);
392 SSLFreeRecord(rec
, ctx
);
393 } else if(err
!=errSSLWouldBlock
) {
394 sslDebugLog("%p Read error err=%d\n\n", ctx
, (int)err
);
401 SSLProcessProtocolMessage(SSLRecord
*rec
, SSLContext
*ctx
)
403 return tls_handshake_process(ctx
->hdsk
, rec
->contents
, rec
->contentType
);
407 SSLClose(SSLContext
*ctx
)
409 OSStatus err
= errSecSuccess
;
411 sslHdskStateDebug("SSLClose");
416 err
= tls_handshake_close(ctx
->hdsk
);
419 err
= SSLServiceWriteQueue(ctx
);
421 SSLChangeHdskState(ctx
, SSL_HdskStateGracefulClose
);
423 err
= errSecSuccess
; /* Ignore errors related to closed streams */
428 * Determine how much data the client can be guaranteed to
429 * obtain via SSLRead() without blocking or causing any low-level
430 * read operations to occur.
432 * Implemented here because the relevant info in SSLContext (receivedDataBuffer
433 * and receivedDataPos) are only used in this file.
436 SSLGetBufferedReadSize(SSLContextRef ctx
,
437 size_t *bufSize
) /* RETURNED */
442 if(ctx
->receivedDataBuffer
.data
== NULL
) {
446 assert(ctx
->receivedDataBuffer
.length
>= ctx
->receivedDataPos
);
447 *bufSize
= ctx
->receivedDataBuffer
.length
- ctx
->receivedDataPos
;
449 return errSecSuccess
;