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