]> git.saurik.com Git - apple/security.git/blob - libsecurity_ssl/lib/tls_hmac.c
Security-55471.tar.gz
[apple/security.git] / libsecurity_ssl / lib / tls_hmac.c
1 /*
2 * Copyright (c) 2002,2005-2008,2010-2012 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 * tls_hmac.c - HMAC routines used by TLS
26 */
27
28 /* THIS FILE CONTAINS KERNEL CODE */
29
30 #include "tls_hmac.h"
31 #include "tls_digest.h"
32 #include "sslMemory.h"
33 #include "sslDebug.h"
34 #include <string.h>
35 #include <AssertMacros.h>
36
37
38 /* Per-session state, opaque to callers; all fields set at alloc time */
39 struct HMACContext {
40 const HashReference *digest;
41 SSLBuffer outerHashCtx;
42 SSLBuffer innerHashCtx;
43 SSLBuffer currentHashCtx;
44 };
45
46 // MARK: -
47 // MARK: Common HMAC routines
48
49 /* Create an HMAC session */
50 static int HMAC_Alloc(
51 const struct HMACReference *hmac,
52 const void *keyPtr,
53 size_t keyLen,
54 HMACContextRef *hmacCtx) // RETURNED
55 {
56 const HashReference *digest;
57 HMACContextRef href;
58 size_t ix;
59 uint8_t *context;
60 const uint8_t *key;
61 size_t digest_block_size;
62
63 switch(hmac->alg) {
64 case HA_SHA384:
65 digest = &SSLHashSHA384;
66 digest_block_size = 128;
67 break;
68 case HA_SHA256:
69 digest = &SSLHashSHA256;
70 digest_block_size = 64;
71 break;
72 case HA_SHA1:
73 digest = &SSLHashSHA1;
74 digest_block_size = 64;
75 break;
76 case HA_MD5:
77 digest = &SSLHashMD5;
78 digest_block_size = 64;
79 break;
80 default:
81 check(0);
82 return -1;
83 }
84
85 context = (uint8_t *)sslMalloc(sizeof(struct HMACContext) +
86 3 * digest->contextSize);
87 if(context == NULL) {
88 check(0);
89 return -1;
90 }
91 href = (HMACContextRef)context;
92 href->digest = digest;
93 href->outerHashCtx.data = context + sizeof(*href);
94 href->outerHashCtx.length = digest->contextSize;
95 href->innerHashCtx.data = href->outerHashCtx.data + digest->contextSize;
96 href->innerHashCtx.length = digest->contextSize;
97 href->currentHashCtx.data = href->innerHashCtx.data + digest->contextSize;
98 href->currentHashCtx.length = digest->contextSize;
99
100 digest->init(&href->outerHashCtx);
101 digest->init(&href->innerHashCtx);
102
103 uint8_t tmpkey[digest->digestSize];
104 uint8_t pad[digest_block_size];
105 SSLBuffer kpad = { digest_block_size, pad };
106
107 /* If the key is longer than digest_block_size, reset it to key=digest(key) */
108 if (keyLen <= digest_block_size) {
109 key = (const uint8_t *)keyPtr;
110 } else {
111 SSLBuffer keyBuffer = { keyLen, (uint8_t *)keyPtr };
112 SSLBuffer outBuffer = { digest->digestSize, tmpkey };
113 digest->update(&href->innerHashCtx, &keyBuffer);
114 digest->final(&href->innerHashCtx, &outBuffer);
115 key = outBuffer.data;
116 keyLen = outBuffer.length;
117 /* Re-initialize the inner context. */
118 digest->init(&href->innerHashCtx);
119 }
120
121 /* Copy the key into k_opad while doing the XOR. */
122 for (ix = 0; ix < keyLen; ++ix)
123 pad[ix] = key[ix] ^ 0x5c;
124 memset(pad + keyLen, 0x5c, digest_block_size - keyLen);
125 digest->update(&href->outerHashCtx, &kpad);
126
127 /* Copy the key into k_ipad while doing the XOR. */
128 for (ix = 0; ix < keyLen; ++ix)
129 pad[ix] = key[ix] ^ 0x36;
130 memset(pad + keyLen, 0x36, digest_block_size - keyLen);
131 digest->update(&href->innerHashCtx, &kpad);
132
133 /* Clear out the key bits in pad. */
134 bzero(pad, keyLen);
135
136 /* Now clone the inner digest so we are ready to receive an update. */
137 /* @@@ If init is always called before update we could skip this step. */
138 digest->clone(&href->innerHashCtx, &href->currentHashCtx);
139
140 /* success */
141 *hmacCtx = href;
142 return 0;
143 }
144
145 /* free a session */
146 static int HMAC_Free(
147 HMACContextRef hmacCtx)
148 {
149 if(hmacCtx != NULL) {
150 hmacCtx->digest->close(&hmacCtx->outerHashCtx);
151 hmacCtx->digest->close(&hmacCtx->innerHashCtx);
152 hmacCtx->digest->close(&hmacCtx->currentHashCtx);
153
154 /* Clear out any key material left in the digest contexts. */
155 bzero(hmacCtx->outerHashCtx.data, hmacCtx->outerHashCtx.length);
156 bzero(hmacCtx->innerHashCtx.data, hmacCtx->innerHashCtx.length);
157 bzero(hmacCtx->currentHashCtx.data, hmacCtx->currentHashCtx.length);
158
159 sslFree(hmacCtx);
160 }
161 return 0;
162 }
163
164 /* Reusable init */
165 static int HMAC_Init(
166 HMACContextRef hmacCtx)
167 {
168 if(hmacCtx == NULL) {
169 check(0);
170 return -1;
171 }
172
173 check(hmacCtx->digest != NULL);
174
175 hmacCtx->digest->close(&hmacCtx->currentHashCtx);
176 hmacCtx->digest->clone(&hmacCtx->innerHashCtx, &hmacCtx->currentHashCtx);
177
178 return 0;
179 }
180
181 /* normal crypt ops */
182 static int HMAC_Update(
183 HMACContextRef hmacCtx,
184 const void *data,
185 size_t dataLen)
186 {
187 SSLBuffer cdata = { dataLen, (uint8_t *)data };
188 if(hmacCtx == NULL) {
189 check(0);
190 return -1;
191 }
192
193 check(hmacCtx->digest != NULL);
194
195 hmacCtx->digest->update(&hmacCtx->currentHashCtx, &cdata);
196
197 return 0;
198 }
199
200 static int HMAC_Final(
201 HMACContextRef hmacCtx,
202 void *hmac, // mallocd by caller
203 size_t *hmacLen) // IN/OUT
204 {
205 uint8_t bytes[TLS_HMAC_MAX_SIZE];
206 SSLBuffer digest = { TLS_HMAC_MAX_SIZE, bytes };
207 SSLBuffer cdata;
208
209 if(hmacCtx == NULL) {
210 check(0);
211 return -1;
212 }
213 if((hmac == NULL) || (hmacLen == NULL)) {
214 check(0);
215 return -1;
216 }
217 check(hmacCtx->digest != NULL);
218 check(*hmacLen >= hmacCtx->digest->digestSize);
219
220 cdata.length = *hmacLen;
221 cdata.data = (uint8_t *)hmac;
222
223 hmacCtx->digest->final(&hmacCtx->currentHashCtx, &digest);
224 hmacCtx->digest->clone(&hmacCtx->outerHashCtx, &hmacCtx->currentHashCtx);
225 hmacCtx->digest->update(&hmacCtx->currentHashCtx, &digest);
226 bzero(bytes, hmacCtx->digest->digestSize);
227 hmacCtx->digest->final(&hmacCtx->currentHashCtx, &cdata);
228 *hmacLen = hmacCtx->digest->digestSize;
229
230 return 0;
231 }
232
233 /* one-shot */
234 static int HMAC_Hmac (
235 HMACContextRef hmacCtx,
236 const void *data,
237 size_t dataLen,
238 void *hmac, // mallocd by caller
239 size_t *hmacLen) // IN/OUT
240 {
241 int serr;
242
243 if(hmacCtx == NULL) {
244 check(0);
245 return -1;
246 }
247 serr = HMAC_Init(hmacCtx);
248 if(serr) {
249 return serr;
250 }
251 serr = HMAC_Update(hmacCtx, data, dataLen);
252 if(serr) {
253 return serr;
254 }
255 return HMAC_Final(hmacCtx, hmac, hmacLen);
256 }
257
258
259 // MARK: -
260 // MARK: Null HMAC
261
262 static int HMAC_AllocNull(
263 const struct HMACReference *hmac,
264 const void *keyPtr,
265 size_t keyLen,
266 HMACContextRef *hmacCtx) // RETURNED
267 {
268 *hmacCtx = NULL;
269 return 0;
270 }
271
272 static int HMAC_FreeNull(
273 HMACContextRef hmacCtx)
274 {
275 return 0;
276 }
277
278 static int HMAC_InitNull(
279 HMACContextRef hmacCtx)
280 {
281 return 0;
282 }
283
284 static int HMAC_UpdateNull(
285 HMACContextRef hmacCtx,
286 const void *data,
287 size_t dataLen)
288 {
289 return 0;
290 }
291
292 static int HMAC_FinalNull(
293 HMACContextRef hmacCtx,
294 void *hmac, // mallocd by caller
295 size_t *hmacLen) // IN/OUT
296 {
297 return 0;
298 }
299
300 static int HMAC_HmacNull (
301 HMACContextRef hmacCtx,
302 const void *data,
303 size_t dataLen,
304 void *hmac, // mallocd by caller
305 size_t *hmacLen)
306 {
307 return 0;
308 }
309
310 const HMACReference TlsHmacNull = {
311 0,
312 HA_Null,
313 HMAC_AllocNull,
314 HMAC_FreeNull,
315 HMAC_InitNull,
316 HMAC_UpdateNull,
317 HMAC_FinalNull,
318 HMAC_HmacNull
319 };
320
321 const HMACReference TlsHmacMD5 = {
322 16,
323 HA_MD5,
324 HMAC_Alloc,
325 HMAC_Free,
326 HMAC_Init,
327 HMAC_Update,
328 HMAC_Final,
329 HMAC_Hmac
330 };
331
332 const HMACReference TlsHmacSHA1 = {
333 20,
334 HA_SHA1,
335 HMAC_Alloc,
336 HMAC_Free,
337 HMAC_Init,
338 HMAC_Update,
339 HMAC_Final,
340 HMAC_Hmac
341 };
342
343 const HMACReference TlsHmacSHA256 = {
344 32,
345 HA_SHA256,
346 HMAC_Alloc,
347 HMAC_Free,
348 HMAC_Init,
349 HMAC_Update,
350 HMAC_Final,
351 HMAC_Hmac
352 };
353
354 const HMACReference TlsHmacSHA384 = {
355 48,
356 HA_SHA384,
357 HMAC_Alloc,
358 HMAC_Free,
359 HMAC_Init,
360 HMAC_Update,
361 HMAC_Final,
362 HMAC_Hmac
363 };