2 * Copyright (c) 2002,2005-2007,2010-2011 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * ssl3RecordCallouts.c - SSLv3-specific routines for SslTlsCallouts.
28 /* THIS FILE CONTAINS KERNEL CODE */
30 #include <AssertMacros.h>
36 #include <sys/types.h>
42 #include "sslMemory.h"
46 #include "tls_record.h"
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
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.
61 struct SSLRecordInternalContext
*ctx
)
65 WaitingRecord
*out
= NULL
, *queue
;
66 SSLBuffer payload
, mac
;
68 uint16_t payloadSize
,blockSize
= 0;
71 switch(rec
.protocolVersion
) {
72 case DTLS_Version_1_0
:
81 return errSSLRecordInternal
;
83 check(rec
.contents
.length
<= 16384);
85 sslLogRecordIo("type = %02x, ver = %04x, len = %ld, seq = %016llx",
86 rec
.contentType
, rec
.protocolVersion
, rec
.contents
.length
,
87 ctx
->writeCipher
.sequenceNum
);
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 +
94 * padding [block ciphers only] +
95 * padding length field (1 byte) [block ciphers only]
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
;
112 case streamCipherType
:
113 payloadSize
+= ctx
->writeCipher
.macRef
->hash
->digestSize
;
116 /* AES_GCM doesn't need padding. */
117 payloadSize
+= aead
->macSize
;
121 return errSSLRecordInternal
;
124 out
= (WaitingRecord
*)sslMalloc(offsetof(WaitingRecord
, data
) +
128 out
->length
= head
+ payloadSize
;
131 *(charPtr
++) = rec
.contentType
;
132 charPtr
= SSLEncodeInt(charPtr
, rec
.protocolVersion
, 2);
134 /* DTLS sequence number */
135 if(rec
.protocolVersion
== DTLS_Version_1_0
)
136 charPtr
= SSLEncodeUInt64(charPtr
,ctx
->writeCipher
.sequenceNum
);
138 charPtr
= SSLEncodeInt(charPtr
, payloadSize
, 2);
141 if((ctx
->negProtocolVersion
>= TLS_Version_1_1
) &&
142 (cipherType
== blockCipherType
))
145 randomIV
.data
= charPtr
;
146 randomIV
.length
= blockSize
;
147 if((err
= sslRand(&randomIV
)) != 0)
149 charPtr
+= blockSize
;
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
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);
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
;
168 charPtr
+= rec
.contents
.length
;
171 if (cipherType
!= aeadCipherType
) {
172 /* MAC immediately follows data */
174 mac
.length
= ctx
->writeCipher
.macRef
->hash
->digestSize
;
175 charPtr
+= mac
.length
;
176 if (mac
.length
> 0) /* Optimize away null case */
178 check(ctx
->sslTslCalls
!= NULL
);
179 if ((err
= ctx
->sslTslCalls
->computeMac(rec
.contentType
,
183 ctx
->writeCipher
.sequenceNum
,
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
)
197 payload
.data
-= blockSize
;
200 /* Update payload to reflect encrypted data: IV, contents, mac & padding */
201 payload
.length
= payloadSize
;
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
;
212 case streamCipherType
:
213 /* Encrypt the data */
214 if ((err
= cipher
->encrypt(payload
.data
,
215 payload
.data
, payload
.length
, ctx
->writeCipher
.cipherCtx
)) != 0)
223 return errSSLRecordInternal
;
226 /* Enqueue the record to be written from the idle loop */
227 if (ctx
->recordWriteQueue
== 0)
228 ctx
->recordWriteQueue
= out
;
230 { queue
= ctx
->recordWriteQueue
;
231 while (queue
->next
!= 0)
236 /* Increment the sequence number */
237 IncrementUInt64(&ctx
->writeCipher
.sequenceNum
);
243 * Only for if we fail between when the WaitingRecord is allocated and when
250 static int ssl3DecryptRecord(
253 struct SSLRecordInternalContext
*ctx
)
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)
264 return errSSLRecordDecryptionFail
;
267 case streamCipherType
:
268 /* Decrypt in place */
269 err
= c
->decrypt(payload
->data
, payload
->data
,
270 payload
->length
, ctx
->readCipher
.cipherCtx
);
275 return errSSLRecordInternal
;
279 return errSSLRecordDecryptionFail
;
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
)
289 sslErrorLog("DecryptSSLRecord: bad padding length (%d)\n",
290 (unsigned)payload
->data
[payload
->length
- 1]);
291 return errSSLRecordDecryptionFail
;
293 content
.length
-= 1 + payload
->data
[payload
->length
- 1];
294 /* Remove block size padding */
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)
303 return errSSLRecordBadRecordMac
;
306 *payload
= content
; /* Modify payload buffer to indicate content length */
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
316 const HashReference
*hash
;
320 check(cipherCtx
->macRef
!= NULL
);
321 hash
= cipherCtx
->macRef
->hash
;
324 hashCtx
= &cipherCtx
->macCtx
.hashCtx
;
325 if(hashCtx
->data
!= NULL
) {
326 SSLFreeBuffer(hashCtx
);
328 serr
= SSLAllocBuffer(hashCtx
, hash
->contextSize
);
335 static int ssl3FreeMac (
336 CipherContext
*cipherCtx
)
340 check(cipherCtx
!= NULL
);
341 /* this can be called on a completely zeroed out CipherContext... */
342 if(cipherCtx
->macRef
== NULL
) {
345 hashCtx
= &cipherCtx
->macCtx
.hashCtx
;
346 if(hashCtx
->data
!= NULL
) {
347 sslFree(hashCtx
->data
);
348 hashCtx
->data
= NULL
;
354 static int ssl3ComputeMac (
357 SSLBuffer mac
, // caller mallocs data
358 CipherContext
*cipherCtx
, // assumes macCtx, macRef
360 struct SSLRecordInternalContext
*ctx
)
363 uint8_t innerDigestData
[SSL_MAX_DIGEST_LEN
];
364 uint8_t scratchData
[11], *charPtr
;
365 SSLBuffer digest
, digestCtx
, scratch
;
368 const HashReference
*hash
;
370 check(cipherCtx
!= NULL
);
371 check(cipherCtx
->macRef
!= NULL
);
372 hash
= cipherCtx
->macRef
->hash
;
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
;
380 /* init'd early in SSLNewContext() */
381 check(SSLMACPad1
[0] == 0x36 && SSLMACPad2
[0] == 0x5C);
384 * MAC = hash( MAC_write_secret + pad_2 +
385 * hash( MAC_write_secret + pad_1 + seq_num + type +
389 if ((err
= hash
->init(&digestCtx
)) != 0)
391 if ((err
= hash
->update(&digestCtx
, &secret
)) != 0) /* MAC secret */
393 scratch
.data
= (uint8_t *)SSLMACPad1
;
394 scratch
.length
= hash
->macPadSize
;
395 if ((err
= hash
->update(&digestCtx
, &scratch
)) != 0) /* pad1 */
397 charPtr
= scratchData
;
398 charPtr
= SSLEncodeUInt64(charPtr
, seqNo
);
400 charPtr
= SSLEncodeSize(charPtr
, data
.length
, 2);
401 scratch
.data
= scratchData
;
403 check(charPtr
= scratchData
+11);
404 if ((err
= hash
->update(&digestCtx
, &scratch
)) != 0)
405 /* sequenceNo, type & length */
407 if ((err
= hash
->update(&digestCtx
, &data
)) != 0) /* content */
409 digest
.data
= innerDigestData
;
410 digest
.length
= hash
->digestSize
;
411 if ((err
= hash
->final(&digestCtx
, &digest
)) != 0) /* figure inner digest */
414 if ((err
= hash
->init(&digestCtx
)) != 0)
416 if ((err
= hash
->update(&digestCtx
, &secret
)) != 0) /* MAC secret */
418 scratch
.data
= (uint8_t *)SSLMACPad2
;
419 scratch
.length
= hash
->macPadSize
;
420 if ((err
= hash
->update(&digestCtx
, &scratch
)) != 0) /* pad2 */
422 if ((err
= hash
->update(&digestCtx
, &digest
)) != 0) /* inner digest */
424 if ((err
= hash
->final(&digestCtx
, &mac
)) != 0) /* figure the mac */
427 err
= 0; /* redundant, I know */
434 const SslRecordCallouts Ssl3RecordCallouts
= {