2 * Copyright (c) 2002,2005-2008,2010-2012 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 * tls_hmac.c - HMAC routines used by TLS
31 #include "sslMemory.h"
32 #include "cryptType.h"
33 #include "sslDigests.h"
38 #ifdef USE_CDSA_CRYPTO
39 #include "sslCrypto.h"
40 #include <CommonCrypto/CommonHMAC.h>
42 /* Per-session state, opaque to callers; all fields set at alloc time */
46 /* this one is set once with the key, and it then cloned
48 CCHmacContext ccHmacTemplate
;
50 /* the one we actually feed data to */
54 /* FIXME not sure if we need this */
55 const struct HMACReference
*hmac
;
59 #pragma mark CommonCryptor HMAC routines
61 /* Create an HMAC session */
62 static OSStatus
HMAC_Alloc(
63 const struct HMACReference
*hmac
,
67 HMACContextRef
*hmacCtxOut
) // RETURNED
69 CCHmacAlgorithm ccAlg
;
71 HMACContextRef hmacCtx
= (HMACContextRef
)sslMalloc(sizeof(struct HMACContext
));
81 ccAlg
= kCCHmacAlgSHA384
;
82 hmacCtx
->macSize
= CC_SHA384_DIGEST_LENGTH
;
85 ccAlg
= kCCHmacAlgSHA256
;
86 hmacCtx
->macSize
= CC_SHA256_DIGEST_LENGTH
;
89 ccAlg
= kCCHmacAlgSHA1
;
90 hmacCtx
->macSize
= CC_SHA1_DIGEST_LENGTH
;
93 ccAlg
= kCCHmacAlgMD5
;
94 hmacCtx
->macSize
= CC_MD5_DIGEST_LENGTH
;
98 return errSSLInternal
;
101 /* create the template from which individual record MAC-ers are cloned */
102 CCHmacInit(&hmacCtx
->ccHmacTemplate
, ccAlg
, keyPtr
, keyLen
);
103 *hmacCtxOut
= hmacCtx
;
108 static OSStatus
HMAC_Free(
109 HMACContextRef hmacCtx
)
111 if(hmacCtx
!= NULL
) {
112 memset(hmacCtx
, 0, sizeof(*hmacCtx
));
118 /* Reusable init - clone from template */
119 static OSStatus
HMAC_Init(
120 HMACContextRef hmacCtx
)
122 if(hmacCtx
== NULL
) {
123 return errSSLInternal
;
125 hmacCtx
->ccHmac
= hmacCtx
->ccHmacTemplate
;
129 /* normal crypt ops */
130 static OSStatus
HMAC_Update(
131 HMACContextRef hmacCtx
,
135 CCHmacUpdate(&hmacCtx
->ccHmac
, data
, dataLen
);
139 static OSStatus
HMAC_Final(
140 HMACContextRef hmacCtx
,
141 void *hmac
, // mallocd by caller
142 unsigned *hmacLen
) // IN/OUT
144 if(*hmacLen
< hmacCtx
->macSize
) {
145 return errSSLInternal
;
147 CCHmacFinal(&hmacCtx
->ccHmac
, hmac
);
148 *hmacLen
= hmacCtx
->macSize
;
153 static OSStatus
HMAC_Hmac (
154 HMACContextRef hmacCtx
,
157 void *hmac
, // mallocd by caller
158 unsigned *hmacLen
) // IN/OUT
161 const HMACReference
*hmacRef
;
163 if(hmacCtx
== NULL
) {
164 return errSSLInternal
;
166 hmacRef
= hmacCtx
->hmac
;
167 assert(hmacRef
!= NULL
);
168 serr
= hmacRef
->init(hmacCtx
);
172 serr
= hmacRef
->update(hmacCtx
, data
, dataLen
);
176 return hmacRef
->final(hmacCtx
, hmac
, hmacLen
);
181 /* Per-session state, opaque to callers; all fields set at alloc time */
184 const HashReference
*digest
;
185 SSLBuffer outerHashCtx
;
186 SSLBuffer innerHashCtx
;
187 SSLBuffer currentHashCtx
;
191 #pragma mark Common HMAC routines
193 /* Create an HMAC session */
194 static OSStatus
HMAC_Alloc(
195 const struct HMACReference
*hmac
,
199 HMACContextRef
*hmacCtx
) // RETURNED
201 const HashReference
*digest
;
206 size_t digest_block_size
;
210 digest
= &SSLHashSHA384
;
211 digest_block_size
= 128;
214 digest
= &SSLHashSHA256
;
215 digest_block_size
= 64;
218 digest
= &SSLHashSHA1
;
219 digest_block_size
= 64;
222 digest
= &SSLHashMD5
;
223 digest_block_size
= 64;
227 return errSSLInternal
;
230 context
= (uint8_t *)sslMalloc(sizeof(struct HMACContext
) +
231 3 * digest
->contextSize
);
234 href
= (HMACContextRef
)context
;
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
;
244 digest
->init(&href
->outerHashCtx
, ctx
);
245 digest
->init(&href
->innerHashCtx
, ctx
);
247 uint8_t tmpkey
[digest
->digestSize
];
248 uint8_t pad
[digest_block_size
];
249 SSLBuffer kpad
= { digest_block_size
, pad
};
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
;
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
);
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
);
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
);
277 /* Clear out the key bits in pad. */
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
);
290 static OSStatus
HMAC_Free(
291 HMACContextRef hmacCtx
)
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
);
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
);
309 static OSStatus
HMAC_Init(
310 HMACContextRef hmacCtx
)
313 return errSSLInternal
;
315 assert(hmacCtx
->digest
!= NULL
);
317 hmacCtx
->digest
->close(&hmacCtx
->currentHashCtx
, hmacCtx
->ctx
);
318 hmacCtx
->digest
->clone(&hmacCtx
->innerHashCtx
, &hmacCtx
->currentHashCtx
);
323 /* normal crypt ops */
324 static OSStatus
HMAC_Update(
325 HMACContextRef hmacCtx
,
329 SSLBuffer cdata
= { dataLen
, (uint8_t *)data
};
331 return errSSLInternal
;
333 assert(hmacCtx
->digest
!= NULL
);
335 hmacCtx
->digest
->update(&hmacCtx
->currentHashCtx
, &cdata
);
340 static OSStatus
HMAC_Final(
341 HMACContextRef hmacCtx
,
342 void *hmac
, // mallocd by caller
343 size_t *hmacLen
) // IN/OUT
345 uint8_t bytes
[TLS_HMAC_MAX_SIZE
];
346 SSLBuffer digest
= { TLS_HMAC_MAX_SIZE
, bytes
};
349 if(hmacCtx
== NULL
) {
350 return errSSLInternal
;
352 if((hmac
== NULL
) || (hmacLen
== NULL
)) {
353 return errSSLInternal
;
355 assert(hmacCtx
->digest
!= NULL
);
356 assert(*hmacLen
>= hmacCtx
->digest
->digestSize
);
358 cdata
.length
= *hmacLen
;
359 cdata
.data
= (uint8_t *)hmac
;
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
;
372 static OSStatus
HMAC_Hmac (
373 HMACContextRef hmacCtx
,
376 void *hmac
, // mallocd by caller
377 size_t *hmacLen
) // IN/OUT
381 if(hmacCtx
== NULL
) {
382 return errSSLInternal
;
384 serr
= HMAC_Init(hmacCtx
);
388 serr
= HMAC_Update(hmacCtx
, data
, dataLen
);
392 return HMAC_Final(hmacCtx
, hmac
, hmacLen
);
395 #endif /* !USE_CDSA_CRYPTO */
398 #pragma mark Null HMAC
400 static OSStatus
HMAC_AllocNull(
401 const struct HMACReference
*hmac
,
405 HMACContextRef
*hmacCtx
) // RETURNED
411 static OSStatus
HMAC_FreeNull(
412 HMACContextRef hmacCtx
)
417 static OSStatus
HMAC_InitNull(
418 HMACContextRef hmacCtx
)
423 static OSStatus
HMAC_UpdateNull(
424 HMACContextRef hmacCtx
,
431 static OSStatus
HMAC_FinalNull(
432 HMACContextRef hmacCtx
,
433 void *hmac
, // mallocd by caller
434 size_t *hmacLen
) // IN/OUT
439 static OSStatus
HMAC_HmacNull (
440 HMACContextRef hmacCtx
,
443 void *hmac
, // mallocd by caller
449 const HMACReference TlsHmacNull
= {
460 const HMACReference TlsHmacMD5
= {
471 const HMACReference TlsHmacSHA1
= {
482 const HMACReference TlsHmacSHA256
= {
493 const HMACReference TlsHmacSHA384
= {
504 const HashHmacReference HashHmacNull
= {
509 const HashHmacReference HashHmacMD5
= {
514 const HashHmacReference HashHmacSHA1
= {
519 const HashHmacReference HashHmacSHA256
= {
524 const HashHmacReference HashHmacSHA384
= {