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 * tls1RecordCallouts.c - TLSv1-specific routines for SslTlsCallouts.
28 /* THIS FILE CONTAINS KERNEL CODE */
30 #include "tls_record.h"
31 #include "sslMemory.h"
35 #include <AssertMacros.h>
38 /* not needed; encrypt/encode is the same for both protocols as long as
39 * we don't use the "variable length padding" feature. */
41 static int tls1WriteRecord(
46 return errSecUnimplemented
;
50 static int tls1DecryptRecord(
53 struct SSLRecordInternalContext
*ctx
)
58 if ((ctx
->readCipher
.symCipher
->params
->blockSize
> 0) &&
59 ((payload
->length
% ctx
->readCipher
.symCipher
->params
->blockSize
) != 0)) {
60 return errSSLRecordRecordOverflow
;
63 /* Decrypt in place */
64 if ((err
= ctx
->readCipher
.symCipher
->c
.cipher
.decrypt(payload
->data
,
65 payload
->data
, payload
->length
,
66 ctx
->readCipher
.cipherCtx
)) != 0)
68 return errSSLRecordDecryptionFail
;
71 /* Locate content within decrypted payload */
73 /* TLS 1.1 and DTLS 1.0 block ciphers */
74 if((ctx
->negProtocolVersion
>=TLS_Version_1_1
) && (ctx
->readCipher
.symCipher
->params
->blockSize
>0))
76 content
.data
= payload
->data
+ ctx
->readCipher
.symCipher
->params
->blockSize
;
77 content
.length
= payload
->length
- (ctx
->readCipher
.macRef
->hash
->digestSize
+ ctx
->readCipher
.symCipher
->params
->blockSize
);
79 content
.data
= payload
->data
;
80 content
.length
= payload
->length
- ctx
->readCipher
.macRef
->hash
->digestSize
;
83 /* Test for underflow - if the record size is smaller than required */
84 if(content
.length
> payload
->length
) {
85 return errSSLRecordClosedAbort
;
90 if (ctx
->readCipher
.symCipher
->params
->blockSize
> 0) {
91 /* for TLSv1, padding can be anywhere from 0 to 255 bytes */
92 uint8_t padSize
= payload
->data
[payload
->length
- 1];
94 /* Padding check sequence:
95 1. Check that the padding size (last byte in padding) is within bound
96 2. Adjust content.length accordingly
97 3. Check every padding byte (except last, already checked)
98 Do not return, just set the error value on failure,
99 to avoid creating a padding oracle with timing.
101 if(padSize
+1<=content
.length
) {
103 content
.length
-= (1 + padSize
);
104 padChars
= payload
->data
+ payload
->length
- (padSize
+1);
105 while(padChars
< (payload
->data
+ payload
->length
- 1)) {
106 if(*padChars
++ != padSize
) {
107 err
= errSSLRecordBadRecordMac
;
111 err
= errSSLRecordBadRecordMac
;
115 /* Verify MAC on payload */
116 if (ctx
->readCipher
.macRef
->hash
->digestSize
> 0)
117 /* Optimize away MAC for null case */
118 if (SSLVerifyMac(type
, &content
,
119 content
.data
+ content
.length
, ctx
) != 0)
121 err
= errSSLRecordBadRecordMac
;
124 *payload
= content
; /* Modify payload buffer to indicate content length */
129 /* initialize a per-CipherContext HashHmacContext for use in MACing each record */
130 static int tls1InitMac (
131 CipherContext
*cipherCtx
) // macRef, macSecret valid on entry
132 // macCtx valid on return
134 const HMACReference
*hmac
;
138 check(cipherCtx
->macRef
!= NULL
);
139 hmac
= cipherCtx
->macRef
->hmac
;
142 if(cipherCtx
->macCtx
.hmacCtx
!= NULL
) {
143 hmac
->free(cipherCtx
->macCtx
.hmacCtx
);
144 cipherCtx
->macCtx
.hmacCtx
= NULL
;
146 serr
= hmac
->alloc(hmac
, cipherCtx
->macSecret
,
147 cipherCtx
->macRef
->hmac
->macSize
, &cipherCtx
->macCtx
.hmacCtx
);
149 /* mac secret now stored in macCtx.hmacCtx, delete it from cipherCtx */
150 memset(cipherCtx
->macSecret
, 0, sizeof(cipherCtx
->macSecret
));
154 static int tls1FreeMac (
155 CipherContext
*cipherCtx
)
157 /* this can be called on a completely zeroed out CipherContext... */
158 if(cipherCtx
->macRef
== NULL
) {
161 check(cipherCtx
->macRef
->hmac
!= NULL
);
163 if(cipherCtx
->macCtx
.hmacCtx
!= NULL
) {
164 cipherCtx
->macRef
->hmac
->free(cipherCtx
->macCtx
.hmacCtx
);
165 cipherCtx
->macCtx
.hmacCtx
= NULL
;
171 * mac = HMAC_hash(MAC_write_secret, seq_num + TLSCompressed.type +
172 * TLSCompressed.version + TLSCompressed.length +
173 * TLSCompressed.fragment));
176 /* sequence, type, version, length */
177 #define HDR_LENGTH (8 + 1 + 2 + 2)
178 static int tls1ComputeMac (
181 SSLBuffer mac
, // caller mallocs data
182 CipherContext
*cipherCtx
, // assumes macCtx, macRef
184 struct SSLRecordInternalContext
*ctx
)
186 uint8_t hdr
[HDR_LENGTH
];
188 HMACContextRef hmacCtx
;
190 const HMACReference
*hmac
;
193 check(cipherCtx
!= NULL
);
194 check(cipherCtx
->macRef
!= NULL
);
195 hmac
= cipherCtx
->macRef
->hmac
;
197 hmacCtx
= cipherCtx
->macCtx
.hmacCtx
; // may be NULL, for null cipher
199 serr
= hmac
->init(hmacCtx
);
203 p
= SSLEncodeUInt64(hdr
, seqNo
);
205 *p
++ = ctx
->negProtocolVersion
>> 8;
206 *p
++ = ctx
->negProtocolVersion
& 0xff;
207 *p
++ = data
.length
>> 8;
208 *p
= data
.length
& 0xff;
209 serr
= hmac
->update(hmacCtx
, hdr
, HDR_LENGTH
);
213 serr
= hmac
->update(hmacCtx
, data
.data
, data
.length
);
217 macLength
= mac
.length
;
218 serr
= hmac
->final(hmacCtx
, mac
.data
, &macLength
);
222 mac
.length
= macLength
;
227 const SslRecordCallouts Tls1RecordCallouts
= {