]> git.saurik.com Git - apple/security.git/blob - libsecurity_ssl/lib/tls_hmac.c
Security-55178.0.1.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 #include "tls_hmac.h"
29
30
31 #include "sslMemory.h"
32 #include "cryptType.h"
33 #include "sslDigests.h"
34 #include "sslDebug.h"
35 #include <strings.h>
36 #include <assert.h>
37
38 #ifdef USE_CDSA_CRYPTO
39 #include "sslCrypto.h"
40 #include <CommonCrypto/CommonHMAC.h>
41
42 /* Per-session state, opaque to callers; all fields set at alloc time */
43 struct HMACContext {
44 SSLContext *ctx;
45
46 /* this one is set once with the key, and it then cloned
47 * for each init() */
48 CCHmacContext ccHmacTemplate;
49
50 /* the one we actually feed data to */
51 CCHmacContext ccHmac;
52 size_t macSize;
53
54 /* FIXME not sure if we need this */
55 const struct HMACReference *hmac;
56 };
57
58 #pragma mark -
59 #pragma mark CommonCryptor HMAC routines
60
61 /* Create an HMAC session */
62 static OSStatus HMAC_Alloc(
63 const struct HMACReference *hmac,
64 SSLContext *ctx,
65 const void *keyPtr,
66 unsigned keyLen,
67 HMACContextRef *hmacCtxOut) // RETURNED
68 {
69 CCHmacAlgorithm ccAlg;
70
71 HMACContextRef hmacCtx = (HMACContextRef)sslMalloc(sizeof(struct HMACContext));
72
73 if(hmacCtx == NULL) {
74 return memFullErr;
75 }
76 hmacCtx->ctx = ctx;
77 hmacCtx->hmac = hmac;
78
79 switch(hmac->alg) {
80 case HA_SHA384:
81 ccAlg = kCCHmacAlgSHA384;
82 hmacCtx->macSize = CC_SHA384_DIGEST_LENGTH;
83 break;
84 case HA_SHA256:
85 ccAlg = kCCHmacAlgSHA256;
86 hmacCtx->macSize = CC_SHA256_DIGEST_LENGTH;
87 break;
88 case HA_SHA1:
89 ccAlg = kCCHmacAlgSHA1;
90 hmacCtx->macSize = CC_SHA1_DIGEST_LENGTH;
91 break;
92 case HA_MD5:
93 ccAlg = kCCHmacAlgMD5;
94 hmacCtx->macSize = CC_MD5_DIGEST_LENGTH;
95 break;
96 default:
97 ASSERT(0);
98 return errSSLInternal;
99 }
100
101 /* create the template from which individual record MAC-ers are cloned */
102 CCHmacInit(&hmacCtx->ccHmacTemplate, ccAlg, keyPtr, keyLen);
103 *hmacCtxOut = hmacCtx;
104 return noErr;
105 }
106
107 /* free a session */
108 static OSStatus HMAC_Free(
109 HMACContextRef hmacCtx)
110 {
111 if(hmacCtx != NULL) {
112 memset(hmacCtx, 0, sizeof(*hmacCtx));
113 sslFree(hmacCtx);
114 }
115 return noErr;
116 }
117
118 /* Reusable init - clone from template */
119 static OSStatus HMAC_Init(
120 HMACContextRef hmacCtx)
121 {
122 if(hmacCtx == NULL) {
123 return errSSLInternal;
124 }
125 hmacCtx->ccHmac = hmacCtx->ccHmacTemplate;
126 return noErr;
127 }
128
129 /* normal crypt ops */
130 static OSStatus HMAC_Update(
131 HMACContextRef hmacCtx,
132 const void *data,
133 unsigned dataLen)
134 {
135 CCHmacUpdate(&hmacCtx->ccHmac, data, dataLen);
136 return noErr;
137 }
138
139 static OSStatus HMAC_Final(
140 HMACContextRef hmacCtx,
141 void *hmac, // mallocd by caller
142 unsigned *hmacLen) // IN/OUT
143 {
144 if(*hmacLen < hmacCtx->macSize) {
145 return errSSLInternal;
146 }
147 CCHmacFinal(&hmacCtx->ccHmac, hmac);
148 *hmacLen = hmacCtx->macSize;
149 return noErr;
150 }
151
152 /* one-shot */
153 static OSStatus HMAC_Hmac (
154 HMACContextRef hmacCtx,
155 const void *data,
156 unsigned dataLen,
157 void *hmac, // mallocd by caller
158 unsigned *hmacLen) // IN/OUT
159 {
160 OSStatus serr;
161 const HMACReference *hmacRef;
162
163 if(hmacCtx == NULL) {
164 return errSSLInternal;
165 }
166 hmacRef = hmacCtx->hmac;
167 assert(hmacRef != NULL);
168 serr = hmacRef->init(hmacCtx);
169 if(serr) {
170 return serr;
171 }
172 serr = hmacRef->update(hmacCtx, data, dataLen);
173 if(serr) {
174 return serr;
175 }
176 return hmacRef->final(hmacCtx, hmac, hmacLen);
177 }
178
179 #else
180
181 /* Per-session state, opaque to callers; all fields set at alloc time */
182 struct HMACContext {
183 SSLContext *ctx;
184 const HashReference *digest;
185 SSLBuffer outerHashCtx;
186 SSLBuffer innerHashCtx;
187 SSLBuffer currentHashCtx;
188 };
189
190 #pragma mark -
191 #pragma mark Common HMAC routines
192
193 /* Create an HMAC session */
194 static OSStatus HMAC_Alloc(
195 const struct HMACReference *hmac,
196 SSLContext *ctx,
197 const void *keyPtr,
198 size_t keyLen,
199 HMACContextRef *hmacCtx) // RETURNED
200 {
201 const HashReference *digest;
202 HMACContextRef href;
203 size_t ix;
204 uint8_t *context;
205 const uint8_t *key;
206 size_t digest_block_size;
207
208 switch(hmac->alg) {
209 case HA_SHA384:
210 digest = &SSLHashSHA384;
211 digest_block_size = 128;
212 break;
213 case HA_SHA256:
214 digest = &SSLHashSHA256;
215 digest_block_size = 64;
216 break;
217 case HA_SHA1:
218 digest = &SSLHashSHA1;
219 digest_block_size = 64;
220 break;
221 case HA_MD5:
222 digest = &SSLHashMD5;
223 digest_block_size = 64;
224 break;
225 default:
226 assert(0);
227 return errSSLInternal;
228 }
229
230 context = (uint8_t *)sslMalloc(sizeof(struct HMACContext) +
231 3 * digest->contextSize);
232 if(context == NULL)
233 return memFullErr;
234 href = (HMACContextRef)context;
235 href->ctx = ctx;
236 href->digest = digest;
237 href->outerHashCtx.data = context + sizeof(*href);
238 href->outerHashCtx.length = digest->contextSize;
239 href->innerHashCtx.data = href->outerHashCtx.data + digest->contextSize;
240 href->innerHashCtx.length = digest->contextSize;
241 href->currentHashCtx.data = href->innerHashCtx.data + digest->contextSize;
242 href->currentHashCtx.length = digest->contextSize;
243
244 digest->init(&href->outerHashCtx, ctx);
245 digest->init(&href->innerHashCtx, ctx);
246
247 uint8_t tmpkey[digest->digestSize];
248 uint8_t pad[digest_block_size];
249 SSLBuffer kpad = { digest_block_size, pad };
250
251 /* If the key is longer than digest_block_size, reset it to key=digest(key) */
252 if (keyLen <= digest_block_size) {
253 key = (const uint8_t *)keyPtr;
254 } else {
255 SSLBuffer keyBuffer = { keyLen, (uint8_t *)keyPtr };
256 SSLBuffer outBuffer = { digest->digestSize, tmpkey };
257 digest->update(&href->innerHashCtx, &keyBuffer);
258 digest->final(&href->innerHashCtx, &outBuffer);
259 key = outBuffer.data;
260 keyLen = outBuffer.length;
261 /* Re-initialize the inner context. */
262 digest->init(&href->innerHashCtx, ctx);
263 }
264
265 /* Copy the key into k_opad while doing the XOR. */
266 for (ix = 0; ix < keyLen; ++ix)
267 pad[ix] = key[ix] ^ 0x5c;
268 memset(pad + keyLen, 0x5c, digest_block_size - keyLen);
269 digest->update(&href->outerHashCtx, &kpad);
270
271 /* Copy the key into k_ipad while doing the XOR. */
272 for (ix = 0; ix < keyLen; ++ix)
273 pad[ix] = key[ix] ^ 0x36;
274 memset(pad + keyLen, 0x36, digest_block_size - keyLen);
275 digest->update(&href->innerHashCtx, &kpad);
276
277 /* Clear out the key bits in pad. */
278 bzero(pad, keyLen);
279
280 /* Now clone the inner digest so we are ready to receive an update. */
281 /* @@@ If init is always called before update we could skip this step. */
282 digest->clone(&href->innerHashCtx, &href->currentHashCtx);
283
284 /* success */
285 *hmacCtx = href;
286 return noErr;
287 }
288
289 /* free a session */
290 static OSStatus HMAC_Free(
291 HMACContextRef hmacCtx)
292 {
293 if(hmacCtx != NULL) {
294 hmacCtx->digest->close(&hmacCtx->outerHashCtx, hmacCtx->ctx);
295 hmacCtx->digest->close(&hmacCtx->innerHashCtx, hmacCtx->ctx);
296 hmacCtx->digest->close(&hmacCtx->currentHashCtx, hmacCtx->ctx);
297
298 /* Clear out any key material left in the digest contexts. */
299 bzero(hmacCtx->outerHashCtx.data, hmacCtx->outerHashCtx.length);
300 bzero(hmacCtx->innerHashCtx.data, hmacCtx->innerHashCtx.length);
301 bzero(hmacCtx->currentHashCtx.data, hmacCtx->currentHashCtx.length);
302
303 sslFree(hmacCtx);
304 }
305 return noErr;
306 }
307
308 /* Reusable init */
309 static OSStatus HMAC_Init(
310 HMACContextRef hmacCtx)
311 {
312 if(hmacCtx == NULL)
313 return errSSLInternal;
314
315 assert(hmacCtx->digest != NULL);
316
317 hmacCtx->digest->close(&hmacCtx->currentHashCtx, hmacCtx->ctx);
318 hmacCtx->digest->clone(&hmacCtx->innerHashCtx, &hmacCtx->currentHashCtx);
319
320 return noErr;
321 }
322
323 /* normal crypt ops */
324 static OSStatus HMAC_Update(
325 HMACContextRef hmacCtx,
326 const void *data,
327 size_t dataLen)
328 {
329 SSLBuffer cdata = { dataLen, (uint8_t *)data };
330 if(hmacCtx == NULL)
331 return errSSLInternal;
332
333 assert(hmacCtx->digest != NULL);
334
335 hmacCtx->digest->update(&hmacCtx->currentHashCtx, &cdata);
336
337 return noErr;
338 }
339
340 static OSStatus HMAC_Final(
341 HMACContextRef hmacCtx,
342 void *hmac, // mallocd by caller
343 size_t *hmacLen) // IN/OUT
344 {
345 uint8_t bytes[TLS_HMAC_MAX_SIZE];
346 SSLBuffer digest = { TLS_HMAC_MAX_SIZE, bytes };
347 SSLBuffer cdata;
348
349 if(hmacCtx == NULL) {
350 return errSSLInternal;
351 }
352 if((hmac == NULL) || (hmacLen == NULL)) {
353 return errSSLInternal;
354 }
355 assert(hmacCtx->digest != NULL);
356 assert(*hmacLen >= hmacCtx->digest->digestSize);
357
358 cdata.length = *hmacLen;
359 cdata.data = (uint8_t *)hmac;
360
361 hmacCtx->digest->final(&hmacCtx->currentHashCtx, &digest);
362 hmacCtx->digest->clone(&hmacCtx->outerHashCtx, &hmacCtx->currentHashCtx);
363 hmacCtx->digest->update(&hmacCtx->currentHashCtx, &digest);
364 bzero(bytes, hmacCtx->digest->digestSize);
365 hmacCtx->digest->final(&hmacCtx->currentHashCtx, &cdata);
366 *hmacLen = hmacCtx->digest->digestSize;
367
368 return noErr;
369 }
370
371 /* one-shot */
372 static OSStatus HMAC_Hmac (
373 HMACContextRef hmacCtx,
374 const void *data,
375 size_t dataLen,
376 void *hmac, // mallocd by caller
377 size_t *hmacLen) // IN/OUT
378 {
379 OSStatus serr;
380
381 if(hmacCtx == NULL) {
382 return errSSLInternal;
383 }
384 serr = HMAC_Init(hmacCtx);
385 if(serr) {
386 return serr;
387 }
388 serr = HMAC_Update(hmacCtx, data, dataLen);
389 if(serr) {
390 return serr;
391 }
392 return HMAC_Final(hmacCtx, hmac, hmacLen);
393 }
394
395 #endif /* !USE_CDSA_CRYPTO */
396
397 #pragma mark -
398 #pragma mark Null HMAC
399
400 static OSStatus HMAC_AllocNull(
401 const struct HMACReference *hmac,
402 SSLContext *ctx,
403 const void *keyPtr,
404 size_t keyLen,
405 HMACContextRef *hmacCtx) // RETURNED
406 {
407 *hmacCtx = NULL;
408 return noErr;
409 }
410
411 static OSStatus HMAC_FreeNull(
412 HMACContextRef hmacCtx)
413 {
414 return noErr;
415 }
416
417 static OSStatus HMAC_InitNull(
418 HMACContextRef hmacCtx)
419 {
420 return noErr;
421 }
422
423 static OSStatus HMAC_UpdateNull(
424 HMACContextRef hmacCtx,
425 const void *data,
426 size_t dataLen)
427 {
428 return noErr;
429 }
430
431 static OSStatus HMAC_FinalNull(
432 HMACContextRef hmacCtx,
433 void *hmac, // mallocd by caller
434 size_t *hmacLen) // IN/OUT
435 {
436 return noErr;
437 }
438
439 static OSStatus HMAC_HmacNull (
440 HMACContextRef hmacCtx,
441 const void *data,
442 size_t dataLen,
443 void *hmac, // mallocd by caller
444 size_t *hmacLen)
445 {
446 return noErr;
447 }
448
449 const HMACReference TlsHmacNull = {
450 0,
451 HA_Null,
452 HMAC_AllocNull,
453 HMAC_FreeNull,
454 HMAC_InitNull,
455 HMAC_UpdateNull,
456 HMAC_FinalNull,
457 HMAC_HmacNull
458 };
459
460 const HMACReference TlsHmacMD5 = {
461 16,
462 HA_MD5,
463 HMAC_Alloc,
464 HMAC_Free,
465 HMAC_Init,
466 HMAC_Update,
467 HMAC_Final,
468 HMAC_Hmac
469 };
470
471 const HMACReference TlsHmacSHA1 = {
472 20,
473 HA_SHA1,
474 HMAC_Alloc,
475 HMAC_Free,
476 HMAC_Init,
477 HMAC_Update,
478 HMAC_Final,
479 HMAC_Hmac
480 };
481
482 const HMACReference TlsHmacSHA256 = {
483 32,
484 HA_SHA256,
485 HMAC_Alloc,
486 HMAC_Free,
487 HMAC_Init,
488 HMAC_Update,
489 HMAC_Final,
490 HMAC_Hmac
491 };
492
493 const HMACReference TlsHmacSHA384 = {
494 48,
495 HA_SHA384,
496 HMAC_Alloc,
497 HMAC_Free,
498 HMAC_Init,
499 HMAC_Update,
500 HMAC_Final,
501 HMAC_Hmac
502 };
503
504 const HashHmacReference HashHmacNull = {
505 &SSLHashNull,
506 &TlsHmacNull
507 };
508
509 const HashHmacReference HashHmacMD5 = {
510 &SSLHashMD5,
511 &TlsHmacMD5
512 };
513
514 const HashHmacReference HashHmacSHA1 = {
515 &SSLHashSHA1,
516 &TlsHmacSHA1
517 };
518
519 const HashHmacReference HashHmacSHA256 = {
520 &SSLHashSHA256,
521 &TlsHmacSHA256
522 };
523
524 const HashHmacReference HashHmacSHA384 = {
525 &SSLHashSHA384,
526 &TlsHmacSHA384
527 };