]> git.saurik.com Git - apple/security.git/blob - SecureTransport/ssl2rec.c
f73acfb8765f9fea52a9440865b9ad556c2c0254
[apple/security.git] / SecureTransport / ssl2rec.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: ssl2rec.c
21
22 Contains: Record encrypting/decrypting/MACing for SSL 2
23
24 Written by: Doug Mitchell, based on Netscape SSLRef 3.0
25
26 Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved.
27
28 */
29 /* *********************************************************************
30 File: ssl2rec.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: ssl2rec.c Record encrypting/decrypting/MACing for SSL 2
47
48
49 ****************************************************************** */
50
51 #ifndef _SSL2_H_
52 #include "ssl2.h"
53 #endif
54
55 #ifndef _SSLREC_H_
56 #include "sslrec.h"
57 #endif
58
59 #ifndef _SSLALLOC_H_
60 #include "sslalloc.h"
61 #endif
62
63 #ifndef _SSLCTX_H_
64 #include "sslctx.h"
65 #endif
66
67 #ifndef _SSLALERT_H_
68 #include "sslalert.h"
69 #endif
70
71 #ifndef _SSL_DEBUG_H_
72 #include "sslDebug.h"
73 #endif
74
75 #ifndef _SSLUTIL_H_
76 #include "sslutil.h"
77 #endif
78
79 #ifndef _DIGESTS_H_
80 #include "digests.h"
81 #endif
82
83 #ifndef _APPLE_GLUE_H_
84 #include "appleGlue.h"
85 #endif
86
87 #include <string.h>
88
89 static SSLErr SSL2DecryptRecord(SSLBuffer *payload, SSLContext *ctx);
90 static SSLErr SSL2VerifyMAC(SSLBuffer content, UInt8 *compareMAC, SSLContext *ctx);
91 static SSLErr SSL2CalculateMAC(SSLBuffer secret, SSLBuffer content, UInt32 seqNo, const HashReference *hash, SSLBuffer mac, SSLContext *ctx);
92
93
94 SSLErr
95 SSL2ReadRecord(SSLRecord *rec, SSLContext *ctx)
96 { SSLErr err;
97 UInt32 len, contentLen;
98 int padding, headerSize;
99 UInt8 *progress;
100 SSLBuffer readData, cipherFragment;
101
102 switch (ctx->negProtocolVersion)
103 { case SSL_Version_Undetermined:
104 case SSL_Version_3_0_With_2_0_Hello:
105 case SSL_Version_2_0:
106 break;
107 case SSL_Version_3_0: /* We've negotiated a 3.0 session; we can send an alert */
108 case TLS_Version_1_0:
109 SSLFatalSessionAlert(alert_unexpected_message, ctx);
110 return SSLProtocolErr;
111 case SSL_Version_3_0_Only: /* We haven't yet negotiated, but we don't want to support 2.0; just die without an alert */
112 return SSLProtocolErr;
113 default:
114 sslPanic("bad protocolVersion in ctx->protocolVersion");
115 }
116
117 if (!ctx->partialReadBuffer.data || ctx->partialReadBuffer.length < 3)
118 { if (ctx->partialReadBuffer.data)
119 if (ERR(err = SSLFreeBuffer(&ctx->partialReadBuffer, &ctx->sysCtx)) != 0)
120 { SSLFatalSessionAlert(alert_close_notify, ctx);
121 return err;
122 }
123 if (ERR(err = SSLAllocBuffer(&ctx->partialReadBuffer, DEFAULT_BUFFER_SIZE, &ctx->sysCtx)) != 0)
124 { SSLFatalSessionAlert(alert_close_notify, ctx);
125 return err;
126 }
127 }
128
129 if (ctx->amountRead < 3)
130 { readData.length = 3 - ctx->amountRead;
131 readData.data = ctx->partialReadBuffer.data + ctx->amountRead;
132 len = readData.length;
133 err = sslIoRead(readData, &len, ctx);
134 if(err != 0)
135 { if (err == SSLWouldBlockErr)
136 ctx->amountRead += len;
137 if (err == SSLIOErr && ctx->amountRead == 0) /* If the session closes on a record boundary, it's graceful */
138 err = SSLConnectionClosedGraceful;
139 return err;
140 }
141 ctx->amountRead += len;
142 }
143
144 rec->contentType = SSL_version_2_0_record;
145 rec->protocolVersion = SSL_Version_2_0;
146 progress = ctx->partialReadBuffer.data;
147
148 if (((*progress) & 0x80) != 0) /* High bit on -> specifies 2-byte header */
149 { headerSize = 2;
150 contentLen = ((progress[0] & 0x7F) << 8) | progress[1];
151 padding = 0;
152 }
153 else if (((*progress) & 0x40) != 0) /* Bit 6 on -> specifies security escape */
154 { return ERR(SSLProtocolErr); /* No security escapes are defined */
155 }
156 else /* 3-byte header */
157 { headerSize = 3;
158 contentLen = ((progress[0] & 0x3F) << 8) | progress[1];
159 padding = progress[2];
160 }
161
162 /*
163 * FIXME - what's the max record size?
164 * and why doesn't SSLReadRecord parse the 2 or 3 byte header?
165 * Note: I see contentLen of 0 coming back from www.cduniverse.com when
166 * it's only been given SSL_RSA_EXPORT_WITH_DES40_CBC_SHA.
167 */
168 if((contentLen == 0) || (contentLen > 0xffff)) {
169 return SSLProtocolErr;
170 }
171
172 progress += headerSize;
173
174 if (ctx->partialReadBuffer.length < headerSize + contentLen)
175 { if (ERR(err = SSLReallocBuffer(&ctx->partialReadBuffer, 5 + contentLen, &ctx->sysCtx)) != 0)
176 return err;
177 }
178
179 if (ctx->amountRead < headerSize + contentLen)
180 { readData.length = headerSize + contentLen - ctx->amountRead;
181 readData.data = ctx->partialReadBuffer.data + ctx->amountRead;
182 len = readData.length;
183 err = sslIoRead(readData, &len, ctx);
184 if(err != 0)
185 { if (err == SSLWouldBlockErr)
186 ctx->amountRead += len;
187 return err;
188 }
189 ctx->amountRead += len;
190 }
191
192 cipherFragment.data = ctx->partialReadBuffer.data + headerSize;
193 cipherFragment.length = contentLen;
194 if (ERR(err = SSL2DecryptRecord(&cipherFragment, ctx)) != 0)
195 return err;
196
197 cipherFragment.length -= padding; /* Remove padding; MAC was removed by SSL2DecryptRecord */
198
199 IncrementUInt64(&ctx->readCipher.sequenceNum);
200
201 /* Allocate a buffer to return the plaintext in and return it */
202 if (ERR(err = SSLAllocBuffer(&rec->contents, cipherFragment.length, &ctx->sysCtx)) != 0)
203 return err;
204 memcpy(rec->contents.data, cipherFragment.data, cipherFragment.length);
205
206 ctx->amountRead = 0; /* We've used all the data in the cache */
207
208 return SSLNoErr;
209 }
210
211 SSLErr
212 SSL2WriteRecord(SSLRecord rec, SSLContext *ctx)
213 { SSLErr err;
214 int padding = 0, i, headerSize;
215 WaitingRecord *out, *queue;
216 SSLBuffer buf, content, payload, secret, mac;
217 UInt8 *progress;
218 UInt16 payloadSize, blockSize;
219
220 CASSERT(rec.contents.length < 16384);
221
222 out = 0;
223 /* Allocate a WaitingRecord to store our ready-to-send record in */
224 if (ERR(err = SSLAllocBuffer(&buf, sizeof(WaitingRecord), &ctx->sysCtx)) != 0)
225 return err;
226 out = (WaitingRecord*)buf.data;
227 out->next = 0;
228 out->sent = 0;
229
230 payloadSize = (UInt16)
231 (rec.contents.length + ctx->writeCipher.macRef->hash->digestSize);
232 blockSize = ctx->writeCipher.symCipher->blockSize;
233 if (blockSize > 0)
234 {
235 padding = blockSize - (payloadSize % blockSize);
236 if (padding == blockSize)
237 padding = 0;
238 payloadSize += padding;
239 headerSize = 3;
240 }
241 else
242 { padding = 0;
243 headerSize = 2;
244 }
245 out->data.data = 0;
246 if (ERR(err = SSLAllocBuffer(&out->data, headerSize + payloadSize, &ctx->sysCtx)) != 0)
247 goto fail;
248 progress = out->data.data;
249
250 if (headerSize == 2)
251 progress = SSLEncodeInt(progress, payloadSize | 0x8000, 2);
252 else
253 { progress = SSLEncodeInt(progress, payloadSize, 2);
254 *progress++ = padding;
255 }
256
257 payload.data = progress;
258 payload.length = payloadSize;
259
260 mac.data = progress;
261 mac.length = ctx->writeCipher.macRef->hash->digestSize;
262 progress += mac.length;
263
264 content.data = progress;
265 content.length = rec.contents.length + padding;
266 memcpy(progress, rec.contents.data, rec.contents.length);
267 progress += rec.contents.length;
268 i = padding;
269 while (i--)
270 *progress++ = padding;
271
272 CASSERT(progress == out->data.data + out->data.length);
273
274 secret.data = ctx->writeCipher.macSecret;
275 secret.length = ctx->writeCipher.symCipher->keySize;
276 if (mac.length > 0)
277 if (ERR(err = SSL2CalculateMAC(secret, content,
278 ctx->writeCipher.sequenceNum.low,
279 ctx->writeCipher.macRef->hash, mac, ctx)) != 0)
280 goto fail;
281
282 /* APPLE_CDSA change...*/
283 if (ERR(err = ctx->writeCipher.symCipher->encrypt(payload,
284 payload,
285 &ctx->writeCipher,
286 ctx)) != 0)
287 goto fail;
288
289 /* Enqueue the record to be written from the idle loop */
290 if (ctx->recordWriteQueue == 0)
291 ctx->recordWriteQueue = out;
292 else
293 { queue = ctx->recordWriteQueue;
294 while (queue->next != 0)
295 queue = queue->next;
296 queue->next = out;
297 }
298
299 /* Increment the sequence number */
300 IncrementUInt64(&ctx->writeCipher.sequenceNum);
301
302 return SSLNoErr;
303
304 fail: /* Only for if we fail between when the WaitingRecord is allocated and when it is queued */
305 SSLFreeBuffer(&out->data, 0);
306 buf.data = (UInt8*)out;
307 buf.length = sizeof(WaitingRecord);
308 SSLFreeBuffer(&buf, &ctx->sysCtx);
309 return err;
310 }
311
312 static SSLErr
313 SSL2DecryptRecord(SSLBuffer *payload, SSLContext *ctx)
314 { SSLErr err;
315 SSLBuffer content;
316
317 if (ctx->readCipher.symCipher->blockSize > 0)
318 if (payload->length % ctx->readCipher.symCipher->blockSize != 0)
319 return ERR(SSLProtocolErr);
320
321 /* Decrypt in place */
322 /* APPLE_CDSA change...*/
323 if (ERR(err = ctx->readCipher.symCipher->decrypt(*payload,
324 *payload,
325 &ctx->readCipher,
326 ctx)) != 0)
327 return err;
328
329 if (ctx->readCipher.macRef->hash->digestSize > 0) /* Optimize away MAC for null case */
330 { content.data = payload->data + ctx->readCipher.macRef->hash->digestSize; /* Data is after MAC */
331 content.length = payload->length - ctx->readCipher.macRef->hash->digestSize;
332 if (ERR(err = SSL2VerifyMAC(content, payload->data, ctx)) != 0)
333 return err;
334 /* Adjust payload to remove MAC; caller is still responsible for removing padding [if any] */
335 *payload = content;
336 }
337
338 return SSLNoErr;
339 }
340
341 #define IGNORE_MAC_FAILURE 0
342
343 static SSLErr
344 SSL2VerifyMAC(SSLBuffer content, UInt8 *compareMAC, SSLContext *ctx)
345 { SSLErr err;
346 UInt8 calculatedMAC[MAX_DIGEST_SIZE];
347 SSLBuffer secret, mac;
348
349 secret.data = ctx->readCipher.macSecret;
350 secret.length = ctx->readCipher.symCipher->keySize;
351 mac.data = calculatedMAC;
352 mac.length = ctx->readCipher.macRef->hash->digestSize;
353 if (ERR(err = SSL2CalculateMAC(secret, content, ctx->readCipher.sequenceNum.low,
354 ctx->readCipher.macRef->hash, mac, ctx)) != 0)
355 return err;
356 if (memcmp(mac.data, compareMAC, mac.length) != 0) {
357 #if IGNORE_MAC_FAILURE
358 dprintf0("SSL2VerifyMAC: Mac verify failure\n");
359 return SSLNoErr;
360 #else
361 errorLog0("SSL2VerifyMAC: Mac verify failure\n");
362 return ERR(SSLProtocolErr);
363 #endif
364 }
365 return SSLNoErr;
366 }
367
368 #define LOG_MAC_DATA 0
369 #if LOG_MAC_DATA
370 static void logMacData(
371 char *field,
372 SSLBuffer *data)
373 {
374 int i;
375
376 printf("%s: ", field);
377 for(i=0; i<data->length; i++) {
378 printf("%02X", data->data[i]);
379 if((i % 4) == 3) {
380 printf(" ");
381 }
382 }
383 printf("\n");
384 }
385 #else /* LOG_MAC_DATA */
386 #define logMacData(f, d)
387 #endif /* LOG_MAC_DATA */
388
389 /* For SSL 2, the MAC is hash ( secret || content || sequence# )
390 * where secret is the decryption key for the message, content is
391 * the record data plus any padding used to round out the record
392 * size to an even multiple of the block size and sequence# is
393 * a monotonically increasing 32-bit unsigned integer.
394 */
395 static SSLErr
396 SSL2CalculateMAC(SSLBuffer secret, SSLBuffer content, UInt32 seqNo, const HashReference *hash, SSLBuffer mac, SSLContext *ctx)
397 { SSLErr err;
398 UInt8 sequenceNum[4];
399 SSLBuffer seqData, hashContext;
400
401 SSLEncodeInt(sequenceNum, seqNo, 4);
402 seqData.data = sequenceNum;
403 seqData.length = 4;
404
405 hashContext.data = 0;
406 if (ERR(err = ReadyHash(hash, &hashContext, ctx)) != 0)
407 return err;
408 if (ERR(err = hash->update(hashContext, secret)) != 0)
409 goto fail;
410 if (ERR(err = hash->update(hashContext, content)) != 0)
411 goto fail;
412 if (ERR(err = hash->update(hashContext, seqData)) != 0)
413 goto fail;
414 if (ERR(err = hash->final(hashContext, mac)) != 0)
415 goto fail;
416
417 logMacData("secret ", &secret);
418 logMacData("seqData", &seqData);
419 logMacData("mac ", &mac);
420
421 err = SSLNoErr;
422 fail:
423 ERR(SSLFreeBuffer(&hashContext, &ctx->sysCtx));
424 return err;
425 }
426
427 SSLErr
428 SSL2SendError(SSL2ErrorCode error, SSLContext *ctx)
429 { SSLErr err;
430 SSLRecord rec;
431 UInt8 errorData[3];
432
433 rec.contentType = SSL_version_2_0_record;
434 rec.protocolVersion = SSL_Version_2_0;
435 rec.contents.data = errorData;
436 rec.contents.length = 3;
437 errorData[0] = ssl2_mt_error;
438 SSLEncodeInt(errorData + 1, error, 2);
439
440 ERR(err = SSL2WriteRecord(rec, ctx));
441 return err;
442 }