]> git.saurik.com Git - apple/security.git/blob - libsecurity_ssl/lib/tls1RecordCallouts.c
Security-55471.14.tar.gz
[apple/security.git] / libsecurity_ssl / lib / tls1RecordCallouts.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 * tls1RecordCallouts.c - TLSv1-specific routines for SslTlsCallouts.
26 */
27
28 /* THIS FILE CONTAINS KERNEL CODE */
29
30 #include "tls_record.h"
31 #include "sslMemory.h"
32 #include "sslDebug.h"
33 #include "sslUtils.h"
34
35 #include <AssertMacros.h>
36 #include <string.h>
37
38 /* not needed; encrypt/encode is the same for both protocols as long as
39 * we don't use the "variable length padding" feature. */
40 #if 0
41 static int tls1WriteRecord(
42 SSLRecord rec,
43 SSLContext *ctx)
44 {
45 check(0);
46 return errSecUnimplemented;
47 }
48 #endif
49
50 static int tls1DecryptRecord(
51 uint8_t type,
52 SSLBuffer *payload,
53 struct SSLRecordInternalContext *ctx)
54 {
55 int err;
56 SSLBuffer content;
57
58 if ((ctx->readCipher.symCipher->params->blockSize > 0) &&
59 ((payload->length % ctx->readCipher.symCipher->params->blockSize) != 0)) {
60 return errSSLRecordRecordOverflow;
61 }
62
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)
67 {
68 return errSSLRecordDecryptionFail;
69 }
70
71 /* Locate content within decrypted payload */
72
73 /* TLS 1.1 and DTLS 1.0 block ciphers */
74 if((ctx->negProtocolVersion>=TLS_Version_1_1) && (ctx->readCipher.symCipher->params->blockSize>0))
75 {
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);
78 } else {
79 content.data = payload->data;
80 content.length = payload->length - ctx->readCipher.macRef->hash->digestSize;
81 }
82
83 /* Test for underflow - if the record size is smaller than required */
84 if(content.length > payload->length) {
85 return errSSLRecordClosedAbort;
86 }
87
88 err = 0;
89
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];
93
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.
100 */
101 if(padSize+1<=content.length) {
102 uint8_t *padChars;
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;
108 }
109 }
110 } else {
111 err = errSSLRecordBadRecordMac;
112 }
113 }
114
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)
120 {
121 err = errSSLRecordBadRecordMac;
122 }
123
124 *payload = content; /* Modify payload buffer to indicate content length */
125
126 return err;
127 }
128
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
133 {
134 const HMACReference *hmac;
135 int serr;
136
137 check(cipherCtx);
138 check(cipherCtx->macRef != NULL);
139 hmac = cipherCtx->macRef->hmac;
140 check(hmac != NULL);
141
142 if(cipherCtx->macCtx.hmacCtx != NULL) {
143 hmac->free(cipherCtx->macCtx.hmacCtx);
144 cipherCtx->macCtx.hmacCtx = NULL;
145 }
146 serr = hmac->alloc(hmac, cipherCtx->macSecret,
147 cipherCtx->macRef->hmac->macSize, &cipherCtx->macCtx.hmacCtx);
148
149 /* mac secret now stored in macCtx.hmacCtx, delete it from cipherCtx */
150 memset(cipherCtx->macSecret, 0, sizeof(cipherCtx->macSecret));
151 return serr;
152 }
153
154 static int tls1FreeMac (
155 CipherContext *cipherCtx)
156 {
157 /* this can be called on a completely zeroed out CipherContext... */
158 if(cipherCtx->macRef == NULL) {
159 return 0;
160 }
161 check(cipherCtx->macRef->hmac != NULL);
162
163 if(cipherCtx->macCtx.hmacCtx != NULL) {
164 cipherCtx->macRef->hmac->free(cipherCtx->macCtx.hmacCtx);
165 cipherCtx->macCtx.hmacCtx = NULL;
166 }
167 return 0;
168 }
169
170 /*
171 * mac = HMAC_hash(MAC_write_secret, seq_num + TLSCompressed.type +
172 * TLSCompressed.version + TLSCompressed.length +
173 * TLSCompressed.fragment));
174 */
175
176 /* sequence, type, version, length */
177 #define HDR_LENGTH (8 + 1 + 2 + 2)
178 static int tls1ComputeMac (
179 uint8_t type,
180 SSLBuffer data,
181 SSLBuffer mac, // caller mallocs data
182 CipherContext *cipherCtx, // assumes macCtx, macRef
183 sslUint64 seqNo,
184 struct SSLRecordInternalContext *ctx)
185 {
186 uint8_t hdr[HDR_LENGTH];
187 uint8_t *p;
188 HMACContextRef hmacCtx;
189 int serr;
190 const HMACReference *hmac;
191 size_t macLength;
192
193 check(cipherCtx != NULL);
194 check(cipherCtx->macRef != NULL);
195 hmac = cipherCtx->macRef->hmac;
196 check(hmac != NULL);
197 hmacCtx = cipherCtx->macCtx.hmacCtx; // may be NULL, for null cipher
198
199 serr = hmac->init(hmacCtx);
200 if(serr) {
201 goto fail;
202 }
203 p = SSLEncodeUInt64(hdr, seqNo);
204 *p++ = type;
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);
210 if(serr) {
211 goto fail;
212 }
213 serr = hmac->update(hmacCtx, data.data, data.length);
214 if(serr) {
215 goto fail;
216 }
217 macLength = mac.length;
218 serr = hmac->final(hmacCtx, mac.data, &macLength);
219 if(serr) {
220 goto fail;
221 }
222 mac.length = macLength;
223 fail:
224 return serr;
225 }
226
227 const SslRecordCallouts Tls1RecordCallouts = {
228 tls1DecryptRecord,
229 ssl3WriteRecord,
230 tls1InitMac,
231 tls1FreeMac,
232 tls1ComputeMac,
233 };
234