5 // Created by Fabrice Gautier on 10/25/11.
6 // Copyright (c) 2011 Apple, Inc. All rights reserved.
9 /* THIS FILE CONTAINS KERNEL CODE */
11 #include "sslBuildFlags.h"
12 #include "SSLRecordInternal.h"
14 #include "cipherSpecs.h"
15 #include "symCipher.h"
17 #include "tls_record.h"
19 #include <AssertMacros.h>
24 #define DEFAULT_BUFFER_SIZE 4096
28 * Redirect SSLBuffer-based I/O call to user-supplied I/O.
31 int sslIoRead(SSLBuffer buf
,
33 struct SSLRecordInternalContext
*ctx
)
35 size_t dataLength
= buf
.length
;
39 ortn
= (ctx
->read
)(ctx
->ioRef
,
42 *actualLength
= dataLength
;
47 int sslIoWrite(SSLBuffer buf
,
49 struct SSLRecordInternalContext
*ctx
)
51 size_t dataLength
= buf
.length
;
55 ortn
= (ctx
->write
)(ctx
->ioRef
,
58 *actualLength
= dataLength
;
64 SSLDisposeCipherSuite(CipherContext
*cipher
, struct SSLRecordInternalContext
*ctx
)
67 /* symmetric encryption context */
68 if(cipher
->symCipher
) {
69 if ((err
= cipher
->symCipher
->finish(cipher
->cipherCtx
)) != 0) {
74 /* per-record hash/hmac context */
75 ctx
->sslTslCalls
->freeMac(cipher
);
82 /* common for sslv3 and tlsv1, except for the computeMac callout */
83 int SSLVerifyMac(uint8_t type
,
86 struct SSLRecordInternalContext
*ctx
)
89 uint8_t macData
[SSL_MAX_DIGEST_LEN
];
90 SSLBuffer secret
, mac
;
92 secret
.data
= ctx
->readCipher
.macSecret
;
93 secret
.length
= ctx
->readCipher
.macRef
->hash
->digestSize
;
95 mac
.length
= ctx
->readCipher
.macRef
->hash
->digestSize
;
97 check(ctx
->sslTslCalls
!= NULL
);
98 if ((err
= ctx
->sslTslCalls
->computeMac(type
,
102 ctx
->readCipher
.sequenceNum
,
106 if ((memcmp(mac
.data
, compareMAC
, mac
.length
)) != 0) {
107 sslErrorLog("SSLVerifyMac: Mac verify failure\n");
108 return errSSLRecordProtocol
;
113 #include "cipherSpecs.h"
114 #include "symCipher.h"
116 static const HashHmacReference
*sslCipherSuiteGetHashHmacReference(uint16_t selectedCipher
)
118 HMAC_Algs alg
= sslCipherSuiteGetMacAlgorithm(selectedCipher
);
122 return &HashHmacNull
;
126 return &HashHmacSHA1
;
128 return &HashHmacSHA256
;
130 return &HashHmacSHA384
;
132 sslErrorLog("Invalid hashAlgorithm %d", alg
);
134 return &HashHmacNull
;
138 static const SSLSymmetricCipher
*sslCipherSuiteGetSymmetricCipher(uint16_t selectedCipher
)
141 SSL_CipherAlgorithm alg
= sslCipherSuiteGetSymmetricCipherAlgorithm(selectedCipher
);
143 case SSL_CipherAlgorithmNull
:
144 return &SSLCipherNull
;
146 case SSL_CipherAlgorithmRC2_128
:
147 return &SSLCipherRC2_128
;
150 case SSL_CipherAlgorithmRC4_128
:
151 return &SSLCipherRC4_128
;
154 case SSL_CipherAlgorithmDES_CBC
:
155 return &SSLCipherDES_CBC
;
157 case SSL_CipherAlgorithm3DES_CBC
:
158 return &SSLCipher3DES_CBC
;
159 case SSL_CipherAlgorithmAES_128_CBC
:
160 return &SSLCipherAES_128_CBC
;
161 case SSL_CipherAlgorithmAES_256_CBC
:
162 return &SSLCipherAES_256_CBC
;
164 case SSL_CipherAlgorithmAES_128_GCM
:
165 return &SSLCipherAES_128_GCM
;
166 case SSL_CipherAlgorithmAES_256_GCM
:
167 return &SSLCipherAES_256_GCM
;
171 return &SSLCipherNull
;
175 static void InitCipherSpec(struct SSLRecordInternalContext
*ctx
, uint16_t selectedCipher
)
177 SSLRecordCipherSpec
*dst
= &ctx
->selectedCipherSpec
;
179 ctx
->selectedCipher
= selectedCipher
;
180 dst
->cipher
= sslCipherSuiteGetSymmetricCipher(selectedCipher
);
181 dst
->macAlgorithm
= sslCipherSuiteGetHashHmacReference(selectedCipher
);
184 /* Entry points to Record Layer */
186 static int SSLRecordReadInternal(SSLRecordContextRef ref
, SSLRecord
*rec
)
188 size_t len
, contentLen
;
190 SSLBuffer readData
, cipherFragment
;
193 struct SSLRecordInternalContext
*ctx
= ref
;
198 if (!ctx
->partialReadBuffer
.data
|| ctx
->partialReadBuffer
.length
< head
)
199 { if (ctx
->partialReadBuffer
.data
)
200 if ((err
= SSLFreeBuffer(&ctx
->partialReadBuffer
)) != 0)
204 if ((err
= SSLAllocBuffer(&ctx
->partialReadBuffer
,
205 DEFAULT_BUFFER_SIZE
)) != 0)
211 if (ctx
->negProtocolVersion
== SSL_Version_Undetermined
) {
212 if (ctx
->amountRead
< 1)
213 { readData
.length
= 1 - ctx
->amountRead
;
214 readData
.data
= ctx
->partialReadBuffer
.data
+ ctx
->amountRead
;
215 len
= readData
.length
;
216 err
= sslIoRead(readData
, &len
, ctx
);
218 { if (err
== errSSLRecordWouldBlock
) {
219 ctx
->amountRead
+= len
;
224 err
= errSSLRecordClosedAbort
;
225 #if 0 // TODO: revisit this in the transport layer
226 if((ctx
->protocolSide
== kSSLClientSide
) &&
227 (ctx
->amountRead
== 0) &&
230 * Detect "server refused to even try to negotiate"
231 * error, when the server drops the connection before
232 * sending a single byte.
235 case SSL_HdskStateServerHello
:
236 sslHdskStateDebug("Server dropped initial connection\n");
237 err
= errSSLConnectionRefused
;
247 ctx
->amountRead
+= len
;
251 if (ctx
->amountRead
< head
)
252 { readData
.length
= head
- ctx
->amountRead
;
253 readData
.data
= ctx
->partialReadBuffer
.data
+ ctx
->amountRead
;
254 len
= readData
.length
;
255 err
= sslIoRead(readData
, &len
, ctx
);
259 case errSSLRecordWouldBlock
:
260 ctx
->amountRead
+= len
;
262 #if SSL_ALLOW_UNNOTICED_DISCONNECT
263 case errSSLClosedGraceful
:
264 /* legal if we're on record boundary and we've gotten past
266 if((ctx
->amountRead
== 0) && /* nothing pending */
267 (len
== 0) && /* nothing new */
268 (ctx
->state
== SSL_HdskStateClientReady
)) { /* handshake done */
270 * This means that the server has disconnected without
271 * sending a closure alert notice. This is technically
272 * illegal per the SSL3 spec, but about half of the
273 * servers out there do it, so we report it as a separate
274 * error which most clients - including (currently)
275 * URLAccess - ignore by treating it the same as
276 * a errSSLClosedGraceful error. Paranoid
277 * clients can detect it and handle it however they
280 SSLChangeHdskState(ctx
, SSL_HdskStateNoNotifyClose
);
281 err
= errSSLClosedNoNotify
;
285 /* illegal disconnect */
286 err
= errSSLClosedAbort
;
287 /* and drop thru to default: fatal alert */
289 #endif /* SSL_ALLOW_UNNOTICED_DISCONNECT */
295 ctx
->amountRead
+= len
;
298 check(ctx
->amountRead
>= head
);
300 charPtr
= ctx
->partialReadBuffer
.data
;
301 rec
->contentType
= *charPtr
++;
302 if (rec
->contentType
< SSL_RecordTypeV3_Smallest
||
303 rec
->contentType
> SSL_RecordTypeV3_Largest
)
304 return errSSLRecordProtocol
;
306 rec
->protocolVersion
= (SSLProtocolVersion
)SSLDecodeInt(charPtr
, 2);
309 if(rec
->protocolVersion
== DTLS_Version_1_0
)
312 SSLDecodeUInt64(charPtr
, 8, &seqNum
);
314 sslLogRecordIo("Read DTLS Record %016llx (seq is: %016llx)",
315 seqNum
, ctx
->readCipher
.sequenceNum
);
317 /* if the epoch of the record is different of current read cipher, just drop it */
318 if((seqNum
>>48)!=(ctx
->readCipher
.sequenceNum
>>48)) {
321 ctx
->readCipher
.sequenceNum
=seqNum
;
325 contentLen
= SSLDecodeInt(charPtr
, 2);
327 if (contentLen
> (16384 + 2048)) /* Maximum legal length of an
328 * SSLCipherText payload */
330 return errSSLRecordRecordOverflow
;
333 if (ctx
->partialReadBuffer
.length
< head
+ contentLen
)
334 { if ((err
= SSLReallocBuffer(&ctx
->partialReadBuffer
, head
+ contentLen
)) != 0)
340 if (ctx
->amountRead
< head
+ contentLen
)
341 { readData
.length
= head
+ contentLen
- ctx
->amountRead
;
342 readData
.data
= ctx
->partialReadBuffer
.data
+ ctx
->amountRead
;
343 len
= readData
.length
;
344 err
= sslIoRead(readData
, &len
, ctx
);
346 { if (err
== errSSLRecordWouldBlock
)
347 ctx
->amountRead
+= len
;
350 ctx
->amountRead
+= len
;
353 check(ctx
->amountRead
>= head
+ contentLen
);
355 cipherFragment
.data
= ctx
->partialReadBuffer
.data
+ head
;
356 cipherFragment
.length
= contentLen
;
358 ctx
->amountRead
= 0; /* We've used all the data in the cache */
360 /* We dont decrypt if we were told to skip this record */
362 return errSSLRecordUnexpectedRecord
;
365 * Decrypt the payload & check the MAC, modifying the length of the
366 * buffer to indicate the amount of plaintext data after adjusting
367 * for the block size and removing the MAC */
368 check(ctx
->sslTslCalls
!= NULL
);
369 if ((err
= ctx
->sslTslCalls
->decryptRecord(rec
->contentType
,
370 &cipherFragment
, ctx
)) != 0)
374 * We appear to have sucessfully received a record; increment the
377 IncrementUInt64(&ctx
->readCipher
.sequenceNum
);
379 /* Allocate a buffer to return the plaintext in and return it */
380 if ((err
= SSLAllocBuffer(&rec
->contents
, cipherFragment
.length
)) != 0)
384 memcpy(rec
->contents
.data
, cipherFragment
.data
, cipherFragment
.length
);
390 static int SSLRecordWriteInternal(SSLRecordContextRef ref
, SSLRecord rec
)
393 struct SSLRecordInternalContext
*ctx
= ref
;
395 err
=ctx
->sslTslCalls
->writeRecord(rec
, ctx
);
402 /* Record Layer Entry Points */
405 SSLRollbackInternalRecordLayerWriteCipher(SSLRecordContextRef ref
)
408 struct SSLRecordInternalContext
*ctx
= ref
;
410 if ((err
= SSLDisposeCipherSuite(&ctx
->writePending
, ctx
)) != 0)
413 ctx
->writePending
= ctx
->writeCipher
;
414 ctx
->writeCipher
= ctx
->prevCipher
;
416 /* Zero out old data */
417 memset(&ctx
->prevCipher
, 0, sizeof(CipherContext
));
423 SSLAdvanceInternalRecordLayerWriteCipher(SSLRecordContextRef ref
)
426 struct SSLRecordInternalContext
*ctx
= ref
;
428 if ((err
= SSLDisposeCipherSuite(&ctx
->prevCipher
, ctx
)) != 0)
431 ctx
->prevCipher
= ctx
->writeCipher
;
432 ctx
->writeCipher
= ctx
->writePending
;
434 /* Zero out old data */
435 memset(&ctx
->writePending
, 0, sizeof(CipherContext
));
441 SSLAdvanceInternalRecordLayerReadCipher(SSLRecordContextRef ref
)
443 struct SSLRecordInternalContext
*ctx
= ref
;
446 if ((err
= SSLDisposeCipherSuite(&ctx
->readCipher
, ctx
)) != 0)
449 ctx
->readCipher
= ctx
->readPending
;
450 memset(&ctx
->readPending
, 0, sizeof(CipherContext
)); /* Zero out old data */
456 SSLInitInternalRecordLayerPendingCiphers(SSLRecordContextRef ref
, uint16_t selectedCipher
, bool isServer
, SSLBuffer key
)
458 uint8_t *keyDataProgress
, *keyPtr
, *ivPtr
;
459 CipherContext
*serverPending
, *clientPending
;
461 struct SSLRecordInternalContext
*ctx
= ref
;
463 InitCipherSpec(ctx
, selectedCipher
);
465 ctx
->readPending
.macRef
= ctx
->selectedCipherSpec
.macAlgorithm
;
466 ctx
->writePending
.macRef
= ctx
->selectedCipherSpec
.macAlgorithm
;
467 ctx
->readPending
.symCipher
= ctx
->selectedCipherSpec
.cipher
;
468 ctx
->writePending
.symCipher
= ctx
->selectedCipherSpec
.cipher
;
469 /* This need to be reinitialized because the whole thing is zeroed sometimes */
470 ctx
->readPending
.encrypting
= 0;
471 ctx
->writePending
.encrypting
= 1;
473 if(ctx
->negProtocolVersion
== DTLS_Version_1_0
)
475 ctx
->readPending
.sequenceNum
= (ctx
->readPending
.sequenceNum
& (0xffffULL
<<48)) + (1ULL<<48);
476 ctx
->writePending
.sequenceNum
= (ctx
->writePending
.sequenceNum
& (0xffffULL
<<48)) + (1ULL<<48);
478 ctx
->writePending
.sequenceNum
= 0;
479 ctx
->readPending
.sequenceNum
= 0;
483 { serverPending
= &ctx
->writePending
;
484 clientPending
= &ctx
->readPending
;
487 { serverPending
= &ctx
->readPending
;
488 clientPending
= &ctx
->writePending
;
491 /* Check the size of the 'key' buffer - <rdar://problem/11204357> */
492 if(key
.length
!= ctx
->selectedCipherSpec
.macAlgorithm
->hash
->digestSize
*2
493 + ctx
->selectedCipherSpec
.cipher
->params
->keySize
*2
494 + ctx
->selectedCipherSpec
.cipher
->params
->ivSize
*2)
496 return errSSLRecordInternal
;
499 keyDataProgress
= key
.data
;
500 memcpy(clientPending
->macSecret
, keyDataProgress
,
501 ctx
->selectedCipherSpec
.macAlgorithm
->hash
->digestSize
);
502 keyDataProgress
+= ctx
->selectedCipherSpec
.macAlgorithm
->hash
->digestSize
;
503 memcpy(serverPending
->macSecret
, keyDataProgress
,
504 ctx
->selectedCipherSpec
.macAlgorithm
->hash
->digestSize
);
505 keyDataProgress
+= ctx
->selectedCipherSpec
.macAlgorithm
->hash
->digestSize
;
507 if (ctx
->selectedCipherSpec
.cipher
->params
->cipherType
== aeadCipherType
)
510 /* init the reusable-per-record MAC contexts */
511 err
= ctx
->sslTslCalls
->initMac(clientPending
);
515 err
= ctx
->sslTslCalls
->initMac(serverPending
);
520 keyPtr
= keyDataProgress
;
521 keyDataProgress
+= ctx
->selectedCipherSpec
.cipher
->params
->keySize
;
522 /* Skip server write key to get to IV */
523 ivPtr
= keyDataProgress
+ ctx
->selectedCipherSpec
.cipher
->params
->keySize
;
524 if ((err
= ctx
->selectedCipherSpec
.cipher
->c
.cipher
.initialize(clientPending
->symCipher
->params
, clientPending
->encrypting
, keyPtr
, ivPtr
,
525 &clientPending
->cipherCtx
)) != 0)
527 keyPtr
= keyDataProgress
;
528 keyDataProgress
+= ctx
->selectedCipherSpec
.cipher
->params
->keySize
;
529 /* Skip client write IV to get to server write IV */
530 ivPtr
= keyDataProgress
+ ctx
->selectedCipherSpec
.cipher
->params
->ivSize
;
531 if ((err
= ctx
->selectedCipherSpec
.cipher
->c
.cipher
.initialize(serverPending
->symCipher
->params
, serverPending
->encrypting
, keyPtr
, ivPtr
,
532 &serverPending
->cipherCtx
)) != 0)
536 /* Ciphers are ready for use */
537 ctx
->writePending
.ready
= 1;
538 ctx
->readPending
.ready
= 1;
540 /* Ciphers get swapped by sending or receiving a change cipher spec message */
548 SSLSetInternalRecordLayerProtocolVersion(SSLRecordContextRef ref
, SSLProtocolVersion negVersion
)
550 struct SSLRecordInternalContext
*ctx
= ref
;
553 case SSL_Version_3_0
:
554 ctx
->sslTslCalls
= &Ssl3RecordCallouts
;
556 case TLS_Version_1_0
:
557 case TLS_Version_1_1
:
558 case DTLS_Version_1_0
:
559 case TLS_Version_1_2
:
560 ctx
->sslTslCalls
= &Tls1RecordCallouts
;
562 case SSL_Version_2_0
:
563 case SSL_Version_Undetermined
:
565 return errSSLRecordNegotiation
;
567 ctx
->negProtocolVersion
= negVersion
;
573 SSLRecordFreeInternal(SSLRecordContextRef ref
, SSLRecord rec
)
575 return SSLFreeBuffer(&rec
.contents
);
579 SSLRecordServiceWriteQueueInternal(SSLRecordContextRef ref
)
581 int err
= 0, werr
= 0;
585 struct SSLRecordInternalContext
*ctx
= ref
;
587 while (!werr
&& ((rec
= ctx
->recordWriteQueue
) != 0))
588 { buf
.data
= rec
->data
+ rec
->sent
;
589 buf
.length
= rec
->length
- rec
->sent
;
590 werr
= sslIoWrite(buf
, &written
, ctx
);
591 rec
->sent
+= written
;
592 if (rec
->sent
>= rec
->length
)
594 check(rec
->sent
== rec
->length
);
596 ctx
->recordWriteQueue
= rec
->next
;
608 /***** Internal Record Layer APIs *****/
611 SSLCreateInternalRecordLayer(bool dtls
)
613 struct SSLRecordInternalContext
*ctx
;
615 ctx
= sslMalloc(sizeof(struct SSLRecordInternalContext
));
619 memset(ctx
, 0, sizeof(struct SSLRecordInternalContext
));
621 ctx
->negProtocolVersion
= SSL_Version_Undetermined
;
623 ctx
->sslTslCalls
= &Ssl3RecordCallouts
;
624 ctx
->recordWriteQueue
= NULL
;
626 InitCipherSpec(ctx
, TLS_NULL_WITH_NULL_NULL
);
628 ctx
->writeCipher
.macRef
= ctx
->selectedCipherSpec
.macAlgorithm
;
629 ctx
->readCipher
.macRef
= ctx
->selectedCipherSpec
.macAlgorithm
;
630 ctx
->readCipher
.symCipher
= ctx
->selectedCipherSpec
.cipher
;
631 ctx
->writeCipher
.symCipher
= ctx
->selectedCipherSpec
.cipher
;
632 ctx
->readCipher
.encrypting
= 0;
633 ctx
->writeCipher
.encrypting
= 1;
642 SSLSetInternalRecordLayerIOFuncs(
643 SSLRecordContextRef ref
,
644 SSLIOReadFunc readFunc
,
645 SSLIOWriteFunc writeFunc
)
647 struct SSLRecordInternalContext
*ctx
= ref
;
649 ctx
->read
= readFunc
;
650 ctx
->write
= writeFunc
;
656 SSLSetInternalRecordLayerConnection(
657 SSLRecordContextRef ref
,
658 SSLIOConnectionRef ioRef
)
660 struct SSLRecordInternalContext
*ctx
= ref
;
668 SSLDestroyInternalRecordLayer(SSLRecordContextRef ref
)
670 struct SSLRecordInternalContext
*ctx
= ref
;
671 WaitingRecord
*waitRecord
, *next
;
673 /* RecordContext cleanup : */
674 SSLFreeBuffer(&ctx
->partialReadBuffer
);
675 waitRecord
= ctx
->recordWriteQueue
;
677 { next
= waitRecord
->next
;
683 /* Cleanup cipher structs */
684 SSLDisposeCipherSuite(&ctx
->readCipher
, ctx
);
685 SSLDisposeCipherSuite(&ctx
->writeCipher
, ctx
);
686 SSLDisposeCipherSuite(&ctx
->readPending
, ctx
);
687 SSLDisposeCipherSuite(&ctx
->writePending
, ctx
);
688 SSLDisposeCipherSuite(&ctx
->prevCipher
, ctx
);
694 struct SSLRecordFuncs SSLRecordLayerInternal
=
696 .read
= SSLRecordReadInternal
,
697 .write
= SSLRecordWriteInternal
,
698 .initPendingCiphers
= SSLInitInternalRecordLayerPendingCiphers
,
699 .advanceWriteCipher
= SSLAdvanceInternalRecordLayerWriteCipher
,
700 .advanceReadCipher
= SSLAdvanceInternalRecordLayerReadCipher
,
701 .rollbackWriteCipher
= SSLRollbackInternalRecordLayerWriteCipher
,
702 .setProtocolVersion
= SSLSetInternalRecordLayerProtocolVersion
,
703 .free
= SSLRecordFreeInternal
,
704 .serviceWriteQueue
= SSLRecordServiceWriteQueueInternal
,