]> git.saurik.com Git - apple/security.git/blob - libsecurity_ssl/lib/ssl3RecordCallouts.c
Security-55471.14.tar.gz
[apple/security.git] / libsecurity_ssl / lib / ssl3RecordCallouts.c
1 /*
2 * Copyright (c) 2002,2005-2007,2010-2011 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * ssl3RecordCallouts.c - SSLv3-specific routines for SslTlsCallouts.
26 */
27
28 /* THIS FILE CONTAINS KERNEL CODE */
29
30 #include <AssertMacros.h>
31 #include <string.h>
32 #include <stdint.h>
33 #include <inttypes.h>
34
35 #ifdef KERNEL
36 #include <sys/types.h>
37 #else
38 #include <stddef.h>
39 #endif
40
41 #include "sslDebug.h"
42 #include "sslMemory.h"
43 #include "sslUtils.h"
44 #include "sslRand.h"
45
46 #include "tls_record.h"
47
48
49 /*
50 * ssl3WriteRecord does not send alerts on failure, out of the assumption/fear
51 * that this might result in a loop (since sending an alert causes ssl3WriteRecord
52 * to be called).
53 *
54 * As far as I can tell, we can use this same routine for SSLv3 and TLSv1, as long
55 * as we're not trying to use the "variable length padding" feature of TLSv1.
56 * OpenSSL doesn't use that feature; for now, neither will we. Thus this routine
57 * is used for the SslTlsCallouts.writeRecord function for both protocols.
58 */
59 int ssl3WriteRecord(
60 SSLRecord rec,
61 struct SSLRecordInternalContext *ctx)
62 {
63 int err;
64 int padding = 0, i;
65 WaitingRecord *out = NULL, *queue;
66 SSLBuffer payload, mac;
67 uint8_t *charPtr;
68 uint16_t payloadSize,blockSize = 0;
69 int head = 5;
70
71 switch(rec.protocolVersion) {
72 case DTLS_Version_1_0:
73 head += 8;
74 case SSL_Version_3_0:
75 case TLS_Version_1_0:
76 case TLS_Version_1_1:
77 case TLS_Version_1_2:
78 break;
79 default:
80 check(0);
81 return errSSLRecordInternal;
82 }
83 check(rec.contents.length <= 16384);
84
85 sslLogRecordIo("type = %02x, ver = %04x, len = %ld, seq = %016llx",
86 rec.contentType, rec.protocolVersion, rec.contents.length,
87 ctx->writeCipher.sequenceNum);
88
89 /* Allocate enough room for the transmitted record, which will be:
90 * 5 bytes of header (13 for DTLS) +
91 * IV [block cipher and TLS1.1 or DTLS 1.0 only]
92 * encrypted contents +
93 * macLength +
94 * padding [block ciphers only] +
95 * padding length field (1 byte) [block ciphers only]
96 */
97 payloadSize = (uint16_t) rec.contents.length;
98 CipherType cipherType = ctx->writeCipher.symCipher->params->cipherType;
99 const Cipher *cipher = &ctx->writeCipher.symCipher->c.cipher;
100 const AEADCipher *aead = &ctx->writeCipher.symCipher->c.aead;
101 blockSize = ctx->writeCipher.symCipher->params->blockSize;
102 switch (cipherType) {
103 case blockCipherType:
104 payloadSize += ctx->writeCipher.macRef->hash->digestSize;
105 padding = blockSize - (payloadSize % blockSize) - 1;
106 payloadSize += padding + 1;
107 /* TLS 1.1, TLS1.2 and DTLS 1.0 have an extra block for IV */
108 if(ctx->negProtocolVersion >= TLS_Version_1_1) {
109 payloadSize += blockSize;
110 }
111 break;
112 case streamCipherType:
113 payloadSize += ctx->writeCipher.macRef->hash->digestSize;
114 break;
115 case aeadCipherType:
116 /* AES_GCM doesn't need padding. */
117 payloadSize += aead->macSize;
118 break;
119 default:
120 check(0);
121 return errSSLRecordInternal;
122 }
123
124 out = (WaitingRecord *)sslMalloc(offsetof(WaitingRecord, data) +
125 head + payloadSize);
126 out->next = NULL;
127 out->sent = 0;
128 out->length = head + payloadSize;
129
130 charPtr = out->data;
131 *(charPtr++) = rec.contentType;
132 charPtr = SSLEncodeInt(charPtr, rec.protocolVersion, 2);
133
134 /* DTLS sequence number */
135 if(rec.protocolVersion == DTLS_Version_1_0)
136 charPtr = SSLEncodeUInt64(charPtr,ctx->writeCipher.sequenceNum);
137
138 charPtr = SSLEncodeInt(charPtr, payloadSize, 2);
139
140 /* Also for DTLS */
141 if((ctx->negProtocolVersion >= TLS_Version_1_1) &&
142 (cipherType == blockCipherType))
143 {
144 SSLBuffer randomIV;
145 randomIV.data = charPtr;
146 randomIV.length = blockSize;
147 if((err = sslRand(&randomIV)) != 0)
148 return err;
149 charPtr += blockSize;
150 }
151 if (cipherType == aeadCipherType) {
152 /* Encode the explicit iv, for AES_GCM we just use the 8 byte
153 sequenceNum as the explicitIV.
154 Ideally this needs to be done in the algorithm itself, by an
155 extra function pointer in AEADCipher. */
156 charPtr = SSLEncodeUInt64(charPtr,ctx->writeCipher.sequenceNum);
157 /* TODO: If we ever add any mode other than GCM this code might have
158 to be different. */
159 /* TODO: Pass 4 byte implicit and 8 byte explicit IV to cipher */
160 //err = ctx->writeCipher.symCipher->c.aead.setIV(charPtr, &ctx->writeCipher, ctx);
161 }
162
163 /* Copy the contents into the output buffer */
164 memcpy(charPtr, rec.contents.data, rec.contents.length);
165 payload.data = charPtr;
166 payload.length = rec.contents.length;
167
168 charPtr += rec.contents.length;
169
170 /* MAC the data */
171 if (cipherType != aeadCipherType) {
172 /* MAC immediately follows data */
173 mac.data = charPtr;
174 mac.length = ctx->writeCipher.macRef->hash->digestSize;
175 charPtr += mac.length;
176 if (mac.length > 0) /* Optimize away null case */
177 {
178 check(ctx->sslTslCalls != NULL);
179 if ((err = ctx->sslTslCalls->computeMac(rec.contentType,
180 payload,
181 mac,
182 &ctx->writeCipher,
183 ctx->writeCipher.sequenceNum,
184 ctx)) != 0)
185 goto fail;
186 }
187 }
188
189 /* For TLS 1.1 and DTLS, we would need to specifiy the IV, but instead
190 we are clever like this: since the IV is just one block in front,
191 we encrypt it with the rest of the data. The actual transmitted IV
192 is the result of the encryption, with whatever internal IV is used.
193 This method is explained in the TLS 1.1 RFC */
194 if(ctx->negProtocolVersion >= TLS_Version_1_1 &&
195 cipherType == blockCipherType)
196 {
197 payload.data -= blockSize;
198 }
199
200 /* Update payload to reflect encrypted data: IV, contents, mac & padding */
201 payload.length = payloadSize;
202
203
204 switch (cipherType) {
205 case blockCipherType:
206 /* Fill in the padding bytes & padding length field with the
207 * padding value; the protocol only requires the last byte,
208 * but filling them all in avoids leaking data */
209 for (i = 1; i <= padding + 1; ++i)
210 payload.data[payload.length - i] = padding;
211 /* DROPTRHOUGH */
212 case streamCipherType:
213 /* Encrypt the data */
214 if ((err = cipher->encrypt(payload.data,
215 payload.data, payload.length, ctx->writeCipher.cipherCtx)) != 0)
216 goto fail;
217 break;
218 case aeadCipherType:
219 check(0);
220 break;
221 default:
222 check(0);
223 return errSSLRecordInternal;
224 }
225
226 /* Enqueue the record to be written from the idle loop */
227 if (ctx->recordWriteQueue == 0)
228 ctx->recordWriteQueue = out;
229 else
230 { queue = ctx->recordWriteQueue;
231 while (queue->next != 0)
232 queue = queue->next;
233 queue->next = out;
234 }
235
236 /* Increment the sequence number */
237 IncrementUInt64(&ctx->writeCipher.sequenceNum);
238
239 return 0;
240
241 fail:
242 /*
243 * Only for if we fail between when the WaitingRecord is allocated and when
244 * it is queued
245 */
246 sslFree(out);
247 return err;
248 }
249
250 static int ssl3DecryptRecord(
251 uint8_t type,
252 SSLBuffer *payload,
253 struct SSLRecordInternalContext *ctx)
254 {
255 int err;
256 SSLBuffer content;
257
258 CipherType cipherType = ctx->readCipher.symCipher->params->cipherType;
259 const Cipher *c = &ctx->readCipher.symCipher->c.cipher;
260 switch (cipherType) {
261 case blockCipherType:
262 if ((payload->length % ctx->readCipher.symCipher->params->blockSize) != 0)
263 {
264 return errSSLRecordDecryptionFail;
265 }
266 /* DROPTHROUGH */
267 case streamCipherType:
268 /* Decrypt in place */
269 err = c->decrypt(payload->data, payload->data,
270 payload->length, ctx->readCipher.cipherCtx);
271 break;
272 case aeadCipherType:
273 default:
274 check(0);
275 return errSSLRecordInternal;
276 }
277 if (err != 0)
278 {
279 return errSSLRecordDecryptionFail;
280 }
281
282 /* Locate content within decrypted payload */
283 content.data = payload->data;
284 content.length = payload->length - ctx->readCipher.macRef->hash->digestSize;
285 if (cipherType == blockCipherType)
286 { /* padding can't be equal to or more than a block */
287 if (payload->data[payload->length - 1] >= ctx->readCipher.symCipher->params->blockSize)
288 {
289 sslErrorLog("DecryptSSLRecord: bad padding length (%d)\n",
290 (unsigned)payload->data[payload->length - 1]);
291 return errSSLRecordDecryptionFail;
292 }
293 content.length -= 1 + payload->data[payload->length - 1];
294 /* Remove block size padding */
295 }
296
297 /* Verify MAC on payload */
298 if (ctx->readCipher.macRef->hash->digestSize > 0)
299 /* Optimize away MAC for null case */
300 if ((err = SSLVerifyMac(type, &content,
301 payload->data + content.length, ctx)) != 0)
302 {
303 return errSSLRecordBadRecordMac;
304 }
305
306 *payload = content; /* Modify payload buffer to indicate content length */
307
308 return 0;
309 }
310
311 /* initialize a per-CipherContext HashHmacContext for use in MACing each record */
312 static int ssl3InitMac (
313 CipherContext *cipherCtx) // macRef, macSecret valid on entry
314 // macCtx valid on return
315 {
316 const HashReference *hash;
317 SSLBuffer *hashCtx;
318 int serr;
319
320 check(cipherCtx->macRef != NULL);
321 hash = cipherCtx->macRef->hash;
322 check(hash != NULL);
323
324 hashCtx = &cipherCtx->macCtx.hashCtx;
325 if(hashCtx->data != NULL) {
326 SSLFreeBuffer(hashCtx);
327 }
328 serr = SSLAllocBuffer(hashCtx, hash->contextSize);
329 if(serr) {
330 return serr;
331 }
332 return 0;
333 }
334
335 static int ssl3FreeMac (
336 CipherContext *cipherCtx)
337 {
338 SSLBuffer *hashCtx;
339
340 check(cipherCtx != NULL);
341 /* this can be called on a completely zeroed out CipherContext... */
342 if(cipherCtx->macRef == NULL) {
343 return 0;
344 }
345 hashCtx = &cipherCtx->macCtx.hashCtx;
346 if(hashCtx->data != NULL) {
347 sslFree(hashCtx->data);
348 hashCtx->data = NULL;
349 }
350 hashCtx->length = 0;
351 return 0;
352 }
353
354 static int ssl3ComputeMac (
355 uint8_t type,
356 SSLBuffer data,
357 SSLBuffer mac, // caller mallocs data
358 CipherContext *cipherCtx, // assumes macCtx, macRef
359 sslUint64 seqNo,
360 struct SSLRecordInternalContext *ctx)
361 {
362 int err;
363 uint8_t innerDigestData[SSL_MAX_DIGEST_LEN];
364 uint8_t scratchData[11], *charPtr;
365 SSLBuffer digest, digestCtx, scratch;
366 SSLBuffer secret;
367
368 const HashReference *hash;
369
370 check(cipherCtx != NULL);
371 check(cipherCtx->macRef != NULL);
372 hash = cipherCtx->macRef->hash;
373 check(hash != NULL);
374 check(hash->macPadSize <= MAX_MAC_PADDING);
375 check(hash->digestSize <= SSL_MAX_DIGEST_LEN);
376 digestCtx = cipherCtx->macCtx.hashCtx; // may be NULL, for null cipher
377 secret.data = cipherCtx->macSecret;
378 secret.length = hash->digestSize;
379
380 /* init'd early in SSLNewContext() */
381 check(SSLMACPad1[0] == 0x36 && SSLMACPad2[0] == 0x5C);
382
383 /*
384 * MAC = hash( MAC_write_secret + pad_2 +
385 * hash( MAC_write_secret + pad_1 + seq_num + type +
386 * length + content )
387 * )
388 */
389 if ((err = hash->init(&digestCtx)) != 0)
390 goto exit;
391 if ((err = hash->update(&digestCtx, &secret)) != 0) /* MAC secret */
392 goto exit;
393 scratch.data = (uint8_t *)SSLMACPad1;
394 scratch.length = hash->macPadSize;
395 if ((err = hash->update(&digestCtx, &scratch)) != 0) /* pad1 */
396 goto exit;
397 charPtr = scratchData;
398 charPtr = SSLEncodeUInt64(charPtr, seqNo);
399 *charPtr++ = type;
400 charPtr = SSLEncodeSize(charPtr, data.length, 2);
401 scratch.data = scratchData;
402 scratch.length = 11;
403 check(charPtr = scratchData+11);
404 if ((err = hash->update(&digestCtx, &scratch)) != 0)
405 /* sequenceNo, type & length */
406 goto exit;
407 if ((err = hash->update(&digestCtx, &data)) != 0) /* content */
408 goto exit;
409 digest.data = innerDigestData;
410 digest.length = hash->digestSize;
411 if ((err = hash->final(&digestCtx, &digest)) != 0) /* figure inner digest */
412 goto exit;
413
414 if ((err = hash->init(&digestCtx)) != 0)
415 goto exit;
416 if ((err = hash->update(&digestCtx, &secret)) != 0) /* MAC secret */
417 goto exit;
418 scratch.data = (uint8_t *)SSLMACPad2;
419 scratch.length = hash->macPadSize;
420 if ((err = hash->update(&digestCtx, &scratch)) != 0) /* pad2 */
421 goto exit;
422 if ((err = hash->update(&digestCtx, &digest)) != 0) /* inner digest */
423 goto exit;
424 if ((err = hash->final(&digestCtx, &mac)) != 0) /* figure the mac */
425 goto exit;
426
427 err = 0; /* redundant, I know */
428
429 exit:
430 return err;
431 }
432
433
434 const SslRecordCallouts Ssl3RecordCallouts = {
435 ssl3DecryptRecord,
436 ssl3WriteRecord,
437 ssl3InitMac,
438 ssl3FreeMac,
439 ssl3ComputeMac,
440 };