]>
Commit | Line | Data |
---|---|---|
427c49bc A |
1 | // |
2 | // SSLRecordInternal.c | |
3 | // Security | |
4 | // | |
5 | // Created by Fabrice Gautier on 10/25/11. | |
6 | // Copyright (c) 2011 Apple, Inc. All rights reserved. | |
7 | // | |
8 | ||
9 | /* THIS FILE CONTAINS KERNEL CODE */ | |
10 | ||
11 | #include "sslBuildFlags.h" | |
12 | #include "SSLRecordInternal.h" | |
13 | #include "sslDebug.h" | |
14 | #include "cipherSpecs.h" | |
15 | #include "symCipher.h" | |
16 | #include "sslUtils.h" | |
17 | #include "tls_record.h" | |
18 | ||
19 | #include <AssertMacros.h> | |
20 | #include <string.h> | |
21 | ||
22 | #include <inttypes.h> | |
23 | ||
24 | #define DEFAULT_BUFFER_SIZE 4096 | |
25 | ||
26 | ||
27 | /* | |
28 | * Redirect SSLBuffer-based I/O call to user-supplied I/O. | |
29 | */ | |
30 | static | |
31 | int sslIoRead(SSLBuffer buf, | |
32 | size_t *actualLength, | |
33 | struct SSLRecordInternalContext *ctx) | |
34 | { | |
35 | size_t dataLength = buf.length; | |
36 | int ortn; | |
37 | ||
38 | *actualLength = 0; | |
39 | ortn = (ctx->read)(ctx->ioRef, | |
40 | buf.data, | |
41 | &dataLength); | |
42 | *actualLength = dataLength; | |
43 | return ortn; | |
44 | } | |
45 | ||
46 | static | |
47 | int sslIoWrite(SSLBuffer buf, | |
48 | size_t *actualLength, | |
49 | struct SSLRecordInternalContext *ctx) | |
50 | { | |
51 | size_t dataLength = buf.length; | |
52 | int ortn; | |
53 | ||
54 | *actualLength = 0; | |
55 | ortn = (ctx->write)(ctx->ioRef, | |
56 | buf.data, | |
57 | &dataLength); | |
58 | *actualLength = dataLength; | |
59 | return ortn; | |
60 | } | |
61 | ||
62 | ||
63 | static int | |
64 | SSLDisposeCipherSuite(CipherContext *cipher, struct SSLRecordInternalContext *ctx) | |
65 | { int err; | |
66 | ||
67 | /* symmetric encryption context */ | |
68 | if(cipher->symCipher) { | |
69 | if ((err = cipher->symCipher->finish(cipher->cipherCtx)) != 0) { | |
70 | return err; | |
71 | } | |
72 | } | |
73 | ||
74 | /* per-record hash/hmac context */ | |
75 | ctx->sslTslCalls->freeMac(cipher); | |
76 | ||
77 | return 0; | |
78 | } | |
79 | ||
80 | ||
81 | ||
82 | /* common for sslv3 and tlsv1, except for the computeMac callout */ | |
83 | int SSLVerifyMac(uint8_t type, | |
84 | SSLBuffer *data, | |
85 | uint8_t *compareMAC, | |
86 | struct SSLRecordInternalContext *ctx) | |
87 | { | |
88 | int err; | |
89 | uint8_t macData[SSL_MAX_DIGEST_LEN]; | |
90 | SSLBuffer secret, mac; | |
91 | ||
92 | secret.data = ctx->readCipher.macSecret; | |
93 | secret.length = ctx->readCipher.macRef->hash->digestSize; | |
94 | mac.data = macData; | |
95 | mac.length = ctx->readCipher.macRef->hash->digestSize; | |
96 | ||
97 | check(ctx->sslTslCalls != NULL); | |
98 | if ((err = ctx->sslTslCalls->computeMac(type, | |
99 | *data, | |
100 | mac, | |
101 | &ctx->readCipher, | |
102 | ctx->readCipher.sequenceNum, | |
103 | ctx)) != 0) | |
104 | return err; | |
105 | ||
106 | if ((memcmp(mac.data, compareMAC, mac.length)) != 0) { | |
107 | sslErrorLog("SSLVerifyMac: Mac verify failure\n"); | |
108 | return errSSLRecordProtocol; | |
109 | } | |
110 | return 0; | |
111 | } | |
112 | ||
113 | #include "cipherSpecs.h" | |
114 | #include "symCipher.h" | |
115 | ||
116 | static const HashHmacReference *sslCipherSuiteGetHashHmacReference(uint16_t selectedCipher) | |
117 | { | |
118 | HMAC_Algs alg = sslCipherSuiteGetMacAlgorithm(selectedCipher); | |
119 | ||
120 | switch (alg) { | |
121 | case HA_Null: | |
122 | return &HashHmacNull; | |
123 | case HA_MD5: | |
124 | return &HashHmacMD5; | |
125 | case HA_SHA1: | |
126 | return &HashHmacSHA1; | |
127 | case HA_SHA256: | |
128 | return &HashHmacSHA256; | |
129 | case HA_SHA384: | |
130 | return &HashHmacSHA384; | |
131 | default: | |
132 | sslErrorLog("Invalid hashAlgorithm %d", alg); | |
133 | check(0); | |
134 | return &HashHmacNull; | |
135 | } | |
136 | } | |
137 | ||
138 | static const SSLSymmetricCipher *sslCipherSuiteGetSymmetricCipher(uint16_t selectedCipher) | |
139 | { | |
140 | ||
141 | SSL_CipherAlgorithm alg = sslCipherSuiteGetSymmetricCipherAlgorithm(selectedCipher); | |
142 | switch(alg) { | |
143 | case SSL_CipherAlgorithmNull: | |
144 | return &SSLCipherNull; | |
145 | #if ENABLE_RC2 | |
146 | case SSL_CipherAlgorithmRC2_128: | |
147 | return &SSLCipherRC2_128; | |
148 | #endif | |
149 | #if ENABLE_RC4 | |
150 | case SSL_CipherAlgorithmRC4_128: | |
151 | return &SSLCipherRC4_128; | |
152 | #endif | |
153 | #if ENABLE_DES | |
154 | case SSL_CipherAlgorithmDES_CBC: | |
155 | return &SSLCipherDES_CBC; | |
156 | #endif | |
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; | |
163 | #if ENABLE_AES_GCM | |
164 | case SSL_CipherAlgorithmAES_128_GCM: | |
165 | return &SSLCipherAES_128_GCM; | |
166 | case SSL_CipherAlgorithmAES_256_GCM: | |
167 | return &SSLCipherAES_256_GCM; | |
168 | #endif | |
169 | default: | |
170 | check(0); | |
171 | return &SSLCipherNull; | |
172 | } | |
173 | } | |
174 | ||
175 | static void InitCipherSpec(struct SSLRecordInternalContext *ctx, uint16_t selectedCipher) | |
176 | { | |
177 | SSLRecordCipherSpec *dst = &ctx->selectedCipherSpec; | |
178 | ||
179 | ctx->selectedCipher = selectedCipher; | |
180 | dst->cipher = sslCipherSuiteGetSymmetricCipher(selectedCipher); | |
181 | dst->macAlgorithm = sslCipherSuiteGetHashHmacReference(selectedCipher); | |
182 | }; | |
183 | ||
184 | /* Entry points to Record Layer */ | |
185 | ||
186 | static int SSLRecordReadInternal(SSLRecordContextRef ref, SSLRecord *rec) | |
187 | { int err; | |
188 | size_t len, contentLen; | |
189 | uint8_t *charPtr; | |
190 | SSLBuffer readData, cipherFragment; | |
191 | size_t head=5; | |
192 | int skipit=0; | |
193 | struct SSLRecordInternalContext *ctx = ref; | |
194 | ||
195 | if(ctx->isDTLS) | |
196 | head+=8; | |
197 | ||
198 | if (!ctx->partialReadBuffer.data || ctx->partialReadBuffer.length < head) | |
199 | { if (ctx->partialReadBuffer.data) | |
200 | if ((err = SSLFreeBuffer(&ctx->partialReadBuffer)) != 0) | |
201 | { | |
202 | return err; | |
203 | } | |
204 | if ((err = SSLAllocBuffer(&ctx->partialReadBuffer, | |
205 | DEFAULT_BUFFER_SIZE)) != 0) | |
206 | { | |
207 | return err; | |
208 | } | |
209 | } | |
210 | ||
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); | |
217 | if(err != 0) | |
218 | { if (err == errSSLRecordWouldBlock) { | |
219 | ctx->amountRead += len; | |
220 | return err; | |
221 | } | |
222 | else { | |
223 | /* abort */ | |
224 | err = errSSLRecordClosedAbort; | |
225 | #if 0 // TODO: revisit this in the transport layer | |
226 | if((ctx->protocolSide == kSSLClientSide) && | |
227 | (ctx->amountRead == 0) && | |
228 | (len == 0)) { | |
229 | /* | |
230 | * Detect "server refused to even try to negotiate" | |
231 | * error, when the server drops the connection before | |
232 | * sending a single byte. | |
233 | */ | |
234 | switch(ctx->state) { | |
235 | case SSL_HdskStateServerHello: | |
236 | sslHdskStateDebug("Server dropped initial connection\n"); | |
237 | err = errSSLConnectionRefused; | |
238 | break; | |
239 | default: | |
240 | break; | |
241 | } | |
242 | } | |
243 | #endif | |
244 | return err; | |
245 | } | |
246 | } | |
247 | ctx->amountRead += len; | |
248 | } | |
249 | } | |
250 | ||
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); | |
256 | if(err != 0) | |
257 | { | |
258 | switch(err) { | |
259 | case errSSLRecordWouldBlock: | |
260 | ctx->amountRead += len; | |
261 | break; | |
262 | #if SSL_ALLOW_UNNOTICED_DISCONNECT | |
263 | case errSSLClosedGraceful: | |
264 | /* legal if we're on record boundary and we've gotten past | |
265 | * the handshake */ | |
266 | if((ctx->amountRead == 0) && /* nothing pending */ | |
267 | (len == 0) && /* nothing new */ | |
268 | (ctx->state == SSL_HdskStateClientReady)) { /* handshake done */ | |
269 | /* | |
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 | |
278 | * want to. | |
279 | */ | |
280 | SSLChangeHdskState(ctx, SSL_HdskStateNoNotifyClose); | |
281 | err = errSSLClosedNoNotify; | |
282 | break; | |
283 | } | |
284 | else { | |
285 | /* illegal disconnect */ | |
286 | err = errSSLClosedAbort; | |
287 | /* and drop thru to default: fatal alert */ | |
288 | } | |
289 | #endif /* SSL_ALLOW_UNNOTICED_DISCONNECT */ | |
290 | default: | |
291 | break; | |
292 | } | |
293 | return err; | |
294 | } | |
295 | ctx->amountRead += len; | |
296 | } | |
297 | ||
298 | check(ctx->amountRead >= head); | |
299 | ||
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; | |
305 | ||
306 | rec->protocolVersion = (SSLProtocolVersion)SSLDecodeInt(charPtr, 2); | |
307 | charPtr += 2; | |
308 | ||
309 | if(rec->protocolVersion == DTLS_Version_1_0) | |
310 | { | |
311 | sslUint64 seqNum; | |
312 | SSLDecodeUInt64(charPtr, 8, &seqNum); | |
313 | charPtr += 8; | |
314 | sslLogRecordIo("Read DTLS Record %016llx (seq is: %016llx)", | |
315 | seqNum, ctx->readCipher.sequenceNum); | |
316 | ||
317 | /* if the epoch of the record is different of current read cipher, just drop it */ | |
318 | if((seqNum>>48)!=(ctx->readCipher.sequenceNum>>48)) { | |
319 | skipit=1; | |
320 | } else { | |
321 | ctx->readCipher.sequenceNum=seqNum; | |
322 | } | |
323 | } | |
324 | ||
325 | contentLen = SSLDecodeInt(charPtr, 2); | |
326 | charPtr += 2; | |
327 | if (contentLen > (16384 + 2048)) /* Maximum legal length of an | |
328 | * SSLCipherText payload */ | |
329 | { | |
330 | return errSSLRecordRecordOverflow; | |
331 | } | |
332 | ||
333 | if (ctx->partialReadBuffer.length < head + contentLen) | |
334 | { if ((err = SSLReallocBuffer(&ctx->partialReadBuffer, head + contentLen)) != 0) | |
335 | { | |
336 | return err; | |
337 | } | |
338 | } | |
339 | ||
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); | |
345 | if(err != 0) | |
346 | { if (err == errSSLRecordWouldBlock) | |
347 | ctx->amountRead += len; | |
348 | return err; | |
349 | } | |
350 | ctx->amountRead += len; | |
351 | } | |
352 | ||
353 | check(ctx->amountRead >= head + contentLen); | |
354 | ||
355 | cipherFragment.data = ctx->partialReadBuffer.data + head; | |
356 | cipherFragment.length = contentLen; | |
357 | ||
358 | ctx->amountRead = 0; /* We've used all the data in the cache */ | |
359 | ||
360 | /* We dont decrypt if we were told to skip this record */ | |
361 | if(skipit) { | |
362 | return errSSLRecordUnexpectedRecord; | |
363 | } | |
364 | /* | |
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) | |
371 | return err; | |
372 | ||
373 | /* | |
374 | * We appear to have sucessfully received a record; increment the | |
375 | * sequence number | |
376 | */ | |
377 | IncrementUInt64(&ctx->readCipher.sequenceNum); | |
378 | ||
379 | /* Allocate a buffer to return the plaintext in and return it */ | |
380 | if ((err = SSLAllocBuffer(&rec->contents, cipherFragment.length)) != 0) | |
381 | { | |
382 | return err; | |
383 | } | |
384 | memcpy(rec->contents.data, cipherFragment.data, cipherFragment.length); | |
385 | ||
386 | ||
387 | return 0; | |
388 | } | |
389 | ||
390 | static int SSLRecordWriteInternal(SSLRecordContextRef ref, SSLRecord rec) | |
391 | { | |
392 | int err; | |
393 | struct SSLRecordInternalContext *ctx = ref; | |
394 | ||
395 | err=ctx->sslTslCalls->writeRecord(rec, ctx); | |
396 | ||
397 | check_noerr(err); | |
398 | ||
399 | return err; | |
400 | } | |
401 | ||
402 | /* Record Layer Entry Points */ | |
403 | ||
404 | static int | |
405 | SSLRollbackInternalRecordLayerWriteCipher(SSLRecordContextRef ref) | |
406 | { | |
407 | int err; | |
408 | struct SSLRecordInternalContext *ctx = ref; | |
409 | ||
410 | if ((err = SSLDisposeCipherSuite(&ctx->writePending, ctx)) != 0) | |
411 | return err; | |
412 | ||
413 | ctx->writePending = ctx->writeCipher; | |
414 | ctx->writeCipher = ctx->prevCipher; | |
415 | ||
416 | /* Zero out old data */ | |
417 | memset(&ctx->prevCipher, 0, sizeof(CipherContext)); | |
418 | ||
419 | return 0; | |
420 | } | |
421 | ||
422 | static int | |
423 | SSLAdvanceInternalRecordLayerWriteCipher(SSLRecordContextRef ref) | |
424 | { | |
425 | int err; | |
426 | struct SSLRecordInternalContext *ctx = ref; | |
427 | ||
428 | if ((err = SSLDisposeCipherSuite(&ctx->prevCipher, ctx)) != 0) | |
429 | return err; | |
430 | ||
431 | ctx->prevCipher = ctx->writeCipher; | |
432 | ctx->writeCipher = ctx->writePending; | |
433 | ||
434 | /* Zero out old data */ | |
435 | memset(&ctx->writePending, 0, sizeof(CipherContext)); | |
436 | ||
437 | return 0; | |
438 | } | |
439 | ||
440 | static int | |
441 | SSLAdvanceInternalRecordLayerReadCipher(SSLRecordContextRef ref) | |
442 | { | |
443 | struct SSLRecordInternalContext *ctx = ref; | |
444 | int err; | |
445 | ||
446 | if ((err = SSLDisposeCipherSuite(&ctx->readCipher, ctx)) != 0) | |
447 | return err; | |
448 | ||
449 | ctx->readCipher = ctx->readPending; | |
450 | memset(&ctx->readPending, 0, sizeof(CipherContext)); /* Zero out old data */ | |
451 | ||
452 | return 0; | |
453 | } | |
454 | ||
455 | static int | |
456 | SSLInitInternalRecordLayerPendingCiphers(SSLRecordContextRef ref, uint16_t selectedCipher, bool isServer, SSLBuffer key) | |
457 | { int err; | |
458 | uint8_t *keyDataProgress, *keyPtr, *ivPtr; | |
459 | CipherContext *serverPending, *clientPending; | |
460 | ||
461 | struct SSLRecordInternalContext *ctx = ref; | |
462 | ||
463 | InitCipherSpec(ctx, selectedCipher); | |
464 | ||
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; | |
472 | ||
473 | if(ctx->negProtocolVersion == DTLS_Version_1_0) | |
474 | { | |
475 | ctx->readPending.sequenceNum = (ctx->readPending.sequenceNum & (0xffffULL<<48)) + (1ULL<<48); | |
476 | ctx->writePending.sequenceNum = (ctx->writePending.sequenceNum & (0xffffULL<<48)) + (1ULL<<48); | |
477 | } else { | |
478 | ctx->writePending.sequenceNum = 0; | |
479 | ctx->readPending.sequenceNum = 0; | |
480 | } | |
481 | ||
482 | if (isServer) | |
483 | { serverPending = &ctx->writePending; | |
484 | clientPending = &ctx->readPending; | |
485 | } | |
486 | else | |
487 | { serverPending = &ctx->readPending; | |
488 | clientPending = &ctx->writePending; | |
489 | } | |
490 | ||
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) | |
495 | { | |
496 | return errSSLRecordInternal; | |
497 | } | |
498 | ||
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; | |
506 | ||
507 | if (ctx->selectedCipherSpec.cipher->params->cipherType == aeadCipherType) | |
508 | goto skipInit; | |
509 | ||
510 | /* init the reusable-per-record MAC contexts */ | |
511 | err = ctx->sslTslCalls->initMac(clientPending); | |
512 | if(err) { | |
513 | goto fail; | |
514 | } | |
515 | err = ctx->sslTslCalls->initMac(serverPending); | |
516 | if(err) { | |
517 | goto fail; | |
518 | } | |
519 | ||
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) | |
526 | goto fail; | |
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) | |
533 | goto fail; | |
534 | ||
535 | skipInit: | |
536 | /* Ciphers are ready for use */ | |
537 | ctx->writePending.ready = 1; | |
538 | ctx->readPending.ready = 1; | |
539 | ||
540 | /* Ciphers get swapped by sending or receiving a change cipher spec message */ | |
541 | err = 0; | |
542 | ||
543 | fail: | |
544 | return err; | |
545 | } | |
546 | ||
547 | static int | |
548 | SSLSetInternalRecordLayerProtocolVersion(SSLRecordContextRef ref, SSLProtocolVersion negVersion) | |
549 | { | |
550 | struct SSLRecordInternalContext *ctx = ref; | |
551 | ||
552 | switch(negVersion) { | |
553 | case SSL_Version_3_0: | |
554 | ctx->sslTslCalls = &Ssl3RecordCallouts; | |
555 | break; | |
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; | |
561 | break; | |
562 | case SSL_Version_2_0: | |
563 | case SSL_Version_Undetermined: | |
564 | default: | |
565 | return errSSLRecordNegotiation; | |
566 | } | |
567 | ctx->negProtocolVersion = negVersion; | |
568 | ||
569 | return 0; | |
570 | } | |
571 | ||
572 | static int | |
573 | SSLRecordFreeInternal(SSLRecordContextRef ref, SSLRecord rec) | |
574 | { | |
575 | return SSLFreeBuffer(&rec.contents); | |
576 | } | |
577 | ||
578 | static int | |
579 | SSLRecordServiceWriteQueueInternal(SSLRecordContextRef ref) | |
580 | { | |
581 | int err = 0, werr = 0; | |
582 | size_t written = 0; | |
583 | SSLBuffer buf; | |
584 | WaitingRecord *rec; | |
585 | struct SSLRecordInternalContext *ctx= ref; | |
586 | ||
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) | |
593 | { | |
594 | check(rec->sent == rec->length); | |
595 | check(err == 0); | |
596 | ctx->recordWriteQueue = rec->next; | |
597 | sslFree(rec); | |
598 | } | |
599 | if (err) { | |
600 | check_noerr(err); | |
601 | return err; | |
602 | } | |
603 | } | |
604 | ||
605 | return werr; | |
606 | } | |
607 | ||
608 | /***** Internal Record Layer APIs *****/ | |
609 | ||
610 | SSLRecordContextRef | |
611 | SSLCreateInternalRecordLayer(bool dtls) | |
612 | { | |
613 | struct SSLRecordInternalContext *ctx; | |
614 | ||
615 | ctx = sslMalloc(sizeof(struct SSLRecordInternalContext)); | |
616 | if(ctx==NULL) | |
617 | return NULL; | |
618 | ||
619 | memset(ctx, 0, sizeof(struct SSLRecordInternalContext)); | |
620 | ||
621 | ctx->negProtocolVersion = SSL_Version_Undetermined; | |
622 | ||
623 | ctx->sslTslCalls = &Ssl3RecordCallouts; | |
624 | ctx->recordWriteQueue = NULL; | |
625 | ||
626 | InitCipherSpec(ctx, TLS_NULL_WITH_NULL_NULL); | |
627 | ||
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; | |
634 | ||
635 | ctx->isDTLS = dtls; | |
636 | ||
637 | return ctx; | |
638 | ||
639 | } | |
640 | ||
641 | int | |
642 | SSLSetInternalRecordLayerIOFuncs( | |
643 | SSLRecordContextRef ref, | |
644 | SSLIOReadFunc readFunc, | |
645 | SSLIOWriteFunc writeFunc) | |
646 | { | |
647 | struct SSLRecordInternalContext *ctx = ref; | |
648 | ||
649 | ctx->read = readFunc; | |
650 | ctx->write = writeFunc; | |
651 | ||
652 | return 0; | |
653 | } | |
654 | ||
655 | int | |
656 | SSLSetInternalRecordLayerConnection( | |
657 | SSLRecordContextRef ref, | |
658 | SSLIOConnectionRef ioRef) | |
659 | { | |
660 | struct SSLRecordInternalContext *ctx = ref; | |
661 | ||
662 | ctx->ioRef = ioRef; | |
663 | ||
664 | return 0; | |
665 | } | |
666 | ||
667 | void | |
668 | SSLDestroyInternalRecordLayer(SSLRecordContextRef ref) | |
669 | { | |
670 | struct SSLRecordInternalContext *ctx = ref; | |
671 | WaitingRecord *waitRecord, *next; | |
672 | ||
673 | /* RecordContext cleanup : */ | |
674 | SSLFreeBuffer(&ctx->partialReadBuffer); | |
675 | waitRecord = ctx->recordWriteQueue; | |
676 | while (waitRecord) | |
677 | { next = waitRecord->next; | |
678 | sslFree(waitRecord); | |
679 | waitRecord = next; | |
680 | } | |
681 | ||
682 | ||
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); | |
689 | ||
690 | sslFree(ctx); | |
691 | ||
692 | } | |
693 | ||
694 | struct SSLRecordFuncs SSLRecordLayerInternal = | |
695 | { | |
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, | |
705 | }; | |
706 |