]> git.saurik.com Git - apple/security.git/blob - SecureTransport/sslrec.c
Security-29.tar.gz
[apple/security.git] / SecureTransport / sslrec.c
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
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
8 * using this file.
9 *
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.
16 */
17
18
19 /*
20 File: sslrec.c
21
22 Contains: Encryption, decryption and MACing of data
23
24 Written by: Doug Mitchell, based on Netscape RSARef 3.0
25
26 Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved.
27
28 */
29 /* *********************************************************************
30 File: sslrec.c
31
32 SSLRef 3.0 Final -- 11/19/96
33
34 Copyright (c)1996 by Netscape Communications Corp.
35
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.
39
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/>.
43
44 *********************************************************************
45
46 File: sslrec.c Encryption, decryption and MACing of data
47
48 All the transformations which occur between plaintext and the
49 secured, authenticated data that goes out over the wire. Also,
50 detects incoming SSL 2 hello messages and hands them off to the SSL 2
51 record layer (and hands all SSL 2 reading & writing off to the SSL 2
52 layer).
53
54 ****************************************************************** */
55
56
57 #include "ssl.h"
58
59 #ifndef _SSLREC_H_
60 #include "sslrec.h"
61 #endif
62
63 #ifndef _SSLALLOC_H_
64 #include "sslalloc.h"
65 #endif
66
67 #ifndef _CRYPTTYPE_H_
68 #include "cryptType.h"
69 #endif
70
71 #ifndef _SSLCTX_H_
72 #include "sslctx.h"
73 #endif
74
75 #ifndef _SSLALERT_H_
76 #include "sslalert.h"
77 #endif
78
79 #ifndef _SSL_DEBUG_H_
80 #include "sslDebug.h"
81 #endif
82
83 #ifndef _SSL2_H_
84 #include "ssl2.h"
85 #endif
86
87 #ifndef _SSLUTIL_H_
88 #include "sslutil.h"
89 #endif
90
91 #ifdef _APPLE_CDSA_
92 #ifndef _APPLE_GLUE_H_
93 #include "appleGlue.h"
94 #endif
95 #endif
96
97 #include <string.h>
98
99 /*
100 * Lots of servers fail to provide closure alerts when they disconnect.
101 * For now we'll just accept it as long as it occurs on a clean record boundary
102 * (and the handshake is complete).
103 */
104 #define SSL_ALLOW_UNNOTICED_DISCONNECT 1
105
106 static SSLErr DecryptSSLRecord(UInt8 type, SSLBuffer *payload, SSLContext *ctx);
107 static SSLErr VerifyMAC(UInt8 type, SSLBuffer data, UInt8 *compareMAC, SSLContext *ctx);
108 static SSLErr ComputeMAC(UInt8 type, SSLBuffer data, SSLBuffer mac, sslUint64 seqNo, SSLBuffer secret, const HashReference *macHash, SSLContext *ctx);
109 static UInt8* SSLEncodeUInt64(UInt8 *p, sslUint64 value);
110
111 /* ReadSSLRecord
112 * Attempt to read & decrypt an SSL record.
113 */
114 SSLErr
115 SSLReadRecord(SSLRecord *rec, SSLContext *ctx)
116 { SSLErr err;
117 UInt32 len, contentLen;
118 UInt8 *progress;
119 SSLBuffer readData, cipherFragment;
120
121 if (!ctx->partialReadBuffer.data || ctx->partialReadBuffer.length < 5)
122 { if (ctx->partialReadBuffer.data)
123 if ((err = SSLFreeBuffer(&ctx->partialReadBuffer, &ctx->sysCtx)) != 0)
124 { SSLFatalSessionAlert(alert_close_notify, ctx);
125 return ERR(err);
126 }
127 if ((err = SSLAllocBuffer(&ctx->partialReadBuffer, DEFAULT_BUFFER_SIZE, &ctx->sysCtx)) != 0)
128 { SSLFatalSessionAlert(alert_close_notify, ctx);
129 return ERR(err);
130 }
131 }
132
133 if (ctx->negProtocolVersion == SSL_Version_Undetermined ||
134 ctx->negProtocolVersion == SSL_Version_3_0_With_2_0_Hello)
135 if (ctx->amountRead < 1)
136 { readData.length = 1 - ctx->amountRead;
137 readData.data = ctx->partialReadBuffer.data + ctx->amountRead;
138 len = readData.length;
139 #ifdef _APPLE_CDSA_
140 err = sslIoRead(readData, &len, ctx);
141 if(err != 0)
142 #else
143 if (ERR(err = ctx->ioCtx.read(readData, &len, ctx->ioCtx.ioRef)) != 0)
144 #endif
145 { if (err == SSLWouldBlockErr)
146 ctx->amountRead += len;
147 else
148 SSLFatalSessionAlert(alert_close_notify, ctx);
149 return err;
150 }
151 ctx->amountRead += len;
152 }
153
154 /* In undetermined cases, if the first byte isn't in the range of SSL 3.0
155 * record types, this is an SSL 2.0 record
156 */
157 switch (ctx->negProtocolVersion)
158 { case SSL_Version_Undetermined:
159 case SSL_Version_3_0_With_2_0_Hello:
160 if (ctx->partialReadBuffer.data[0] < SSL_smallest_3_0_type ||
161 ctx->partialReadBuffer.data[0] > SSL_largest_3_0_type)
162 return SSL2ReadRecord(rec, ctx);
163 else
164 break;
165 case SSL_Version_2_0:
166 return SSL2ReadRecord(rec, ctx);
167 default:
168 break;
169 }
170
171 if (ctx->amountRead < 5)
172 { readData.length = 5 - ctx->amountRead;
173 readData.data = ctx->partialReadBuffer.data + ctx->amountRead;
174 len = readData.length;
175 #ifdef _APPLE_CDSA_
176 err = sslIoRead(readData, &len, ctx);
177 if(err != 0)
178 #else
179 if (ERR(err = ctx->ioCtx.read(readData, &len, ctx->ioCtx.ioRef)) != 0)
180 #endif
181 {
182 switch(err) {
183 case SSLWouldBlockErr:
184 ctx->amountRead += len;
185 break;
186 #if SSL_ALLOW_UNNOTICED_DISCONNECT
187 case SSLConnectionClosedGraceful:
188 /* legal if we're on record boundary and we've gotten past
189 * the handshake */
190 if((ctx->amountRead == 0) && /* nothing pending */
191 (len == 0) && /* nothing new */
192 (ctx->state == HandshakeClientReady)) { /* handshake done */
193 /*
194 * This means that the server has discionected without
195 * sending a closure alert notice. This is technically
196 * illegal per the SSL3 spec, but about half of the
197 * servers out there do it, so we report it as a separate
198 * error which most clients - including (currently)
199 * URLAccess - ignore by treating it the same as
200 * a SSLConnectionClosedGraceful error. Paranoid
201 * clients can detect it and handle it however they
202 * want to.
203 */
204 SSLChangeHdskState(ctx, SSLNoNotifyClose);
205 err = SSLConnectionClosedNoNotify;
206 break;
207 }
208 else {
209 /* illegal disconnect */
210 err = SSLConnectionClosedError;
211 /* and drop thru to default: fatal alert */
212 }
213 #endif /* SSL_ALLOW_UNNOTICED_DISCONNECT */
214 default:
215 SSLFatalSessionAlert(alert_close_notify, ctx);
216 break;
217 }
218 return err;
219 }
220 ctx->amountRead += len;
221 }
222
223 CASSERT(ctx->amountRead >= 5);
224
225 progress = ctx->partialReadBuffer.data;
226 rec->contentType = *progress++;
227 if (rec->contentType < SSL_smallest_3_0_type ||
228 rec->contentType > SSL_largest_3_0_type)
229 return ERR(SSLProtocolErr);
230
231 rec->protocolVersion = (SSLProtocolVersion)SSLDecodeInt(progress, 2);
232 progress += 2;
233 contentLen = SSLDecodeInt(progress, 2);
234 progress += 2;
235 if (contentLen > (16384 + 2048)) /* Maximum legal length of an SSLCipherText payload */
236 { SSLFatalSessionAlert(alert_unexpected_message, ctx);
237 return ERR(SSLProtocolErr);
238 }
239
240 if (ctx->partialReadBuffer.length < 5 + contentLen)
241 { if ((err = SSLReallocBuffer(&ctx->partialReadBuffer, 5 + contentLen, &ctx->sysCtx)) != 0)
242 { SSLFatalSessionAlert(alert_close_notify, ctx);
243 return ERR(err);
244 }
245 }
246
247 if (ctx->amountRead < 5 + contentLen)
248 { readData.length = 5 + contentLen - ctx->amountRead;
249 readData.data = ctx->partialReadBuffer.data + ctx->amountRead;
250 len = readData.length;
251 #ifdef _APPLE_CDSA_
252 err = sslIoRead(readData, &len, ctx);
253 if(err != 0)
254 #else
255 if (ERR(err = ctx->ioCtx.read(readData, &len, ctx->ioCtx.ioRef)) != 0)
256 #endif
257 { if (err == SSLWouldBlockErr)
258 ctx->amountRead += len;
259 else
260 SSLFatalSessionAlert(alert_close_notify, ctx);
261 return err;
262 }
263 ctx->amountRead += len;
264 }
265
266 CASSERT(ctx->amountRead >= 5 + contentLen);
267
268 cipherFragment.data = ctx->partialReadBuffer.data + 5;
269 cipherFragment.length = contentLen;
270
271 /* Decrypt the payload & check the MAC, modifying the length of the buffer to indicate the
272 * amount of plaintext data after adjusting for the block size and removing the MAC
273 * (this function generates its own alerts)
274 */
275 if ((err = DecryptSSLRecord(rec->contentType, &cipherFragment, ctx)) != 0)
276 return err;
277
278 /* We appear to have sucessfully received a record; increment the sequence number */
279 IncrementUInt64(&ctx->readCipher.sequenceNum);
280
281 /* Allocate a buffer to return the plaintext in and return it */
282 if ((err = SSLAllocBuffer(&rec->contents, cipherFragment.length, &ctx->sysCtx)) != 0)
283 { SSLFatalSessionAlert(alert_close_notify, ctx);
284 return ERR(err);
285 }
286 memcpy(rec->contents.data, cipherFragment.data, cipherFragment.length);
287
288 ctx->amountRead = 0; /* We've used all the data in the cache */
289
290 return SSLNoErr;
291 }
292
293 /* SSLWriteRecord does not send alerts on failure, out of the assumption/fear
294 * that this might result in a loop (since sending an alert causes SSLWriteRecord
295 * to be called).
296 */
297 SSLErr
298 SSLWriteRecord(SSLRecord rec, SSLContext *ctx)
299 { SSLErr err;
300 int padding = 0, i;
301 WaitingRecord *out, *queue;
302 SSLBuffer buf, payload, secret, mac;
303 UInt8 *progress;
304 UInt16 payloadSize,blockSize;
305
306 if (rec.protocolVersion == SSL_Version_2_0)
307 return SSL2WriteRecord(rec, ctx);
308
309 CASSERT(rec.protocolVersion == SSL_Version_3_0);
310 CASSERT(rec.contents.length <= 16384);
311
312 out = 0;
313 /* Allocate a WaitingRecord to store our ready-to-send record in */
314 if ((err = SSLAllocBuffer(&buf, sizeof(WaitingRecord), &ctx->sysCtx)) != 0)
315 return ERR(err);
316 out = (WaitingRecord*)buf.data;
317 out->next = 0;
318 out->sent = 0;
319 /* Allocate enough room for the transmitted record, which will be:
320 * 5 bytes of header +
321 * encrypted contents +
322 * macLength +
323 * padding [block ciphers only] +
324 * padding length field (1 byte) [block ciphers only]
325 */
326 payloadSize = (UInt16) (rec.contents.length + ctx->writeCipher.hash->digestSize);
327 blockSize = ctx->writeCipher.symCipher->blockSize;
328 if (blockSize > 0)
329 { padding = blockSize - (payloadSize % blockSize) - 1;
330 payloadSize += padding + 1;
331 }
332 out->data.data = 0;
333 if ((err = SSLAllocBuffer(&out->data, 5 + payloadSize, &ctx->sysCtx)) != 0)
334 goto fail;
335
336 progress = out->data.data;
337 *(progress++) = rec.contentType;
338 progress = SSLEncodeInt(progress, rec.protocolVersion, 2);
339 progress = SSLEncodeInt(progress, payloadSize, 2);
340
341 /* Copy the contents into the output buffer */
342 memcpy(progress, rec.contents.data, rec.contents.length);
343 payload.data = progress;
344 payload.length = rec.contents.length;
345
346 progress += rec.contents.length;
347 /* MAC immediately follows data */
348 mac.data = progress;
349 mac.length = ctx->writeCipher.hash->digestSize;
350 progress += mac.length;
351
352 /* MAC the data */
353 if (mac.length > 0) /* Optimize away null case */
354 { secret.data = ctx->writeCipher.macSecret;
355 secret.length = ctx->writeCipher.hash->digestSize;
356 if ((err = ComputeMAC(rec.contentType, payload, mac, ctx->writeCipher.sequenceNum, secret, ctx->writeCipher.hash, ctx)) != 0)
357 goto fail;
358 }
359
360 /* Update payload to reflect encrypted data: contents, mac & padding */
361 payload.length = payloadSize;
362
363 /* Fill in the padding bytes & padding length field with the padding value; the
364 * protocol only requires the last byte,
365 * but filling them all in avoids leaking data
366 */
367 if (ctx->writeCipher.symCipher->blockSize > 0)
368 for (i = 1; i <= padding + 1; ++i)
369 payload.data[payload.length - i] = padding;
370
371 /* Encrypt the data */
372 DUMP_BUFFER_NAME("cleartext data", payload);
373 /* _APPLE_CDSA_ change */
374 if ((err = ctx->writeCipher.symCipher->encrypt(payload,
375 payload,
376 &ctx->writeCipher,
377 ctx)) != 0)
378 goto fail;
379 DUMP_BUFFER_NAME("encrypted data", payload);
380
381 /* Enqueue the record to be written from the idle loop */
382 if (ctx->recordWriteQueue == 0)
383 ctx->recordWriteQueue = out;
384 else
385 { queue = ctx->recordWriteQueue;
386 while (queue->next != 0)
387 queue = queue->next;
388 queue->next = out;
389 }
390
391 /* Increment the sequence number */
392 IncrementUInt64(&ctx->writeCipher.sequenceNum);
393
394 return SSLNoErr;
395
396 fail: /* Only for if we fail between when the WaitingRecord is allocated and when it is queued */
397 SSLFreeBuffer(&out->data, &ctx->sysCtx);
398 buf.data = (UInt8*)out;
399 buf.length = sizeof(WaitingRecord);
400 SSLFreeBuffer(&buf, &ctx->sysCtx);
401 return ERR(err);
402 }
403
404 static SSLErr
405 DecryptSSLRecord(UInt8 type, SSLBuffer *payload, SSLContext *ctx)
406 { SSLErr err;
407 SSLBuffer content;
408
409 if ((ctx->readCipher.symCipher->blockSize > 0) &&
410 ((payload->length % ctx->readCipher.symCipher->blockSize) != 0))
411 { SSLFatalSessionAlert(alert_unexpected_message, ctx);
412 return ERR(SSLProtocolErr);
413 }
414
415 /* Decrypt in place */
416 DUMP_BUFFER_NAME("encrypted data", (*payload));
417 /* _APPLE_CDSA_ change */
418 if ((err = ctx->readCipher.symCipher->decrypt(*payload,
419 *payload,
420 &ctx->readCipher,
421 ctx)) != 0)
422 { SSLFatalSessionAlert(alert_close_notify, ctx);
423 return ERR(err);
424 }
425 DUMP_BUFFER_NAME("decrypted data", (*payload));
426
427 /* Locate content within decrypted payload */
428 content.data = payload->data;
429 content.length = payload->length - ctx->readCipher.hash->digestSize;
430 if (ctx->readCipher.symCipher->blockSize > 0)
431 { /* padding can't be equal to or more than a block */
432 if (payload->data[payload->length - 1] >= ctx->readCipher.symCipher->blockSize)
433 { SSLFatalSessionAlert(alert_unexpected_message, ctx);
434 errorLog1("DecryptSSLRecord: bad padding length (%d)\n",
435 (unsigned)payload->data[payload->length - 1]);
436 return ERR(SSLProtocolErr);
437 }
438 content.length -= 1 + payload->data[payload->length - 1]; /* Remove block size padding */
439 }
440
441 /* Verify MAC on payload */
442 if (ctx->readCipher.hash->digestSize > 0) /* Optimize away MAC for null case */
443 if ((err = VerifyMAC(type, content, payload->data + content.length, ctx)) != 0)
444 { SSLFatalSessionAlert(alert_bad_record_mac, ctx);
445 return ERR(err);
446 }
447
448 *payload = content; /* Modify payload buffer to indicate content length */
449
450 return SSLNoErr;
451 }
452
453 static UInt8*
454 SSLEncodeUInt64(UInt8 *p, sslUint64 value)
455 { p = SSLEncodeInt(p, value.high, 4);
456 return SSLEncodeInt(p, value.low, 4);
457 }
458
459 static SSLErr
460 VerifyMAC(UInt8 type, SSLBuffer data, UInt8 *compareMAC, SSLContext *ctx)
461 { SSLErr err;
462 UInt8 macData[MAX_DIGEST_SIZE];
463 SSLBuffer secret, mac;
464
465 secret.data = ctx->readCipher.macSecret;
466 secret.length = ctx->readCipher.hash->digestSize;
467 mac.data = macData;
468 mac.length = ctx->readCipher.hash->digestSize;
469
470 if ((err = ComputeMAC(type, data, mac, ctx->readCipher.sequenceNum, secret, ctx->readCipher.hash, ctx)) != 0)
471 return ERR(err);
472
473 if ((memcmp(mac.data, compareMAC, mac.length)) != 0) {
474 errorLog0("VerifyMAC: Mac verify failure\n");
475 return ERR(SSLProtocolErr);
476 }
477 return SSLNoErr;
478 }
479
480 static SSLErr
481 ComputeMAC(UInt8 type, SSLBuffer data, SSLBuffer mac, sslUint64 seqNo, SSLBuffer secret,
482 const HashReference *macHash, SSLContext *ctx)
483 { SSLErr err;
484 UInt8 innerDigestData[MAX_DIGEST_SIZE];
485 UInt8 scratchData[11], *progress;
486 SSLBuffer digest,digestCtx,scratch;
487
488 CASSERT(macHash->macPadSize <= MAX_MAC_PADDING);
489 CASSERT(macHash->digestSize <= MAX_DIGEST_SIZE);
490 CASSERT(SSLMACPad1[0] == 0x36 && SSLMACPad2[0] == 0x5C);
491
492 digestCtx.data = 0;
493 if ((err = SSLAllocBuffer(&digestCtx, macHash->contextSize, &ctx->sysCtx)) != 0)
494 goto exit;
495
496 /* MAC = hash( MAC_write_secret + pad_2 + hash( MAC_write_secret + pad_1 + seq_num + type + length + content ) ) */
497 if ((err = macHash->init(digestCtx)) != 0)
498 goto exit;
499 if ((err = macHash->update(digestCtx, secret)) != 0) /* MAC secret */
500 goto exit;
501 scratch.data = SSLMACPad1;
502 scratch.length = macHash->macPadSize;
503 if ((err = macHash->update(digestCtx, scratch)) != 0) /* pad1 */
504 goto exit;
505 progress = scratchData;
506 progress = SSLEncodeUInt64(progress, seqNo);
507 *progress++ = type;
508 progress = SSLEncodeInt(progress, data.length, 2);
509 scratch.data = scratchData;
510 scratch.length = 11;
511 CASSERT(progress = scratchData+11);
512 if ((err = macHash->update(digestCtx, scratch)) != 0) /* sequenceNo, type & length */
513 goto exit;
514 if ((err = macHash->update(digestCtx, data)) != 0) /* content */
515 goto exit;
516 digest.data = innerDigestData;
517 digest.length = macHash->digestSize;
518 if ((err = macHash->final(digestCtx, digest)) != 0) /* figure inner digest */
519 goto exit;
520
521 if ((err = macHash->init(digestCtx)) != 0)
522 goto exit;
523 if ((err = macHash->update(digestCtx, secret)) != 0) /* MAC secret */
524 goto exit;
525 scratch.data = SSLMACPad2;
526 scratch.length = macHash->macPadSize;
527 if ((err = macHash->update(digestCtx, scratch)) != 0) /* pad2 */
528 goto exit;
529 if ((err = macHash->update(digestCtx, digest)) != 0) /* inner digest */
530 goto exit;
531 if ((err = macHash->final(digestCtx, mac)) != 0) /* figure the mac */
532 goto exit;
533
534 err = SSLNoErr; /* redundant, I know */
535
536 exit:
537 SSLFreeBuffer(&digestCtx, &ctx->sysCtx);
538 return ERR(err);
539 }