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
28 /* THIS FILE CONTAINS KERNEL CODE */
31 #include "tls_digest.h"
32 #include "sslMemory.h"
35 #include <AssertMacros.h>
38 /* Per-session state, opaque to callers; all fields set at alloc time */
40 const HashReference
*digest
;
41 SSLBuffer outerHashCtx
;
42 SSLBuffer innerHashCtx
;
43 SSLBuffer currentHashCtx
;
47 // MARK: Common HMAC routines
49 /* Create an HMAC session */
50 static int HMAC_Alloc(
51 const struct HMACReference
*hmac
,
54 HMACContextRef
*hmacCtx
) // RETURNED
56 const HashReference
*digest
;
61 size_t digest_block_size
;
65 digest
= &SSLHashSHA384
;
66 digest_block_size
= 128;
69 digest
= &SSLHashSHA256
;
70 digest_block_size
= 64;
73 digest
= &SSLHashSHA1
;
74 digest_block_size
= 64;
78 digest_block_size
= 64;
85 context
= (uint8_t *)sslMalloc(sizeof(struct HMACContext
) +
86 3 * digest
->contextSize
);
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
;
100 digest
->init(&href
->outerHashCtx
);
101 digest
->init(&href
->innerHashCtx
);
103 uint8_t tmpkey
[digest
->digestSize
];
104 uint8_t pad
[digest_block_size
];
105 SSLBuffer kpad
= { digest_block_size
, pad
};
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
;
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
);
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
);
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
);
133 /* Clear out the key bits in pad. */
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
);
146 static int HMAC_Free(
147 HMACContextRef hmacCtx
)
149 if(hmacCtx
!= NULL
) {
150 hmacCtx
->digest
->close(&hmacCtx
->outerHashCtx
);
151 hmacCtx
->digest
->close(&hmacCtx
->innerHashCtx
);
152 hmacCtx
->digest
->close(&hmacCtx
->currentHashCtx
);
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
);
165 static int HMAC_Init(
166 HMACContextRef hmacCtx
)
168 if(hmacCtx
== NULL
) {
173 check(hmacCtx
->digest
!= NULL
);
175 hmacCtx
->digest
->close(&hmacCtx
->currentHashCtx
);
176 hmacCtx
->digest
->clone(&hmacCtx
->innerHashCtx
, &hmacCtx
->currentHashCtx
);
181 /* normal crypt ops */
182 static int HMAC_Update(
183 HMACContextRef hmacCtx
,
187 SSLBuffer cdata
= { dataLen
, (uint8_t *)data
};
188 if(hmacCtx
== NULL
) {
193 check(hmacCtx
->digest
!= NULL
);
195 hmacCtx
->digest
->update(&hmacCtx
->currentHashCtx
, &cdata
);
200 static int HMAC_Final(
201 HMACContextRef hmacCtx
,
202 void *hmac
, // mallocd by caller
203 size_t *hmacLen
) // IN/OUT
205 uint8_t bytes
[TLS_HMAC_MAX_SIZE
];
206 SSLBuffer digest
= { TLS_HMAC_MAX_SIZE
, bytes
};
209 if(hmacCtx
== NULL
) {
213 if((hmac
== NULL
) || (hmacLen
== NULL
)) {
217 check(hmacCtx
->digest
!= NULL
);
218 check(*hmacLen
>= hmacCtx
->digest
->digestSize
);
220 cdata
.length
= *hmacLen
;
221 cdata
.data
= (uint8_t *)hmac
;
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
;
234 static int HMAC_Hmac (
235 HMACContextRef hmacCtx
,
238 void *hmac
, // mallocd by caller
239 size_t *hmacLen
) // IN/OUT
243 if(hmacCtx
== NULL
) {
247 serr
= HMAC_Init(hmacCtx
);
251 serr
= HMAC_Update(hmacCtx
, data
, dataLen
);
255 return HMAC_Final(hmacCtx
, hmac
, hmacLen
);
262 static int HMAC_AllocNull(
263 const struct HMACReference
*hmac
,
266 HMACContextRef
*hmacCtx
) // RETURNED
272 static int HMAC_FreeNull(
273 HMACContextRef hmacCtx
)
278 static int HMAC_InitNull(
279 HMACContextRef hmacCtx
)
284 static int HMAC_UpdateNull(
285 HMACContextRef hmacCtx
,
292 static int HMAC_FinalNull(
293 HMACContextRef hmacCtx
,
294 void *hmac
, // mallocd by caller
295 size_t *hmacLen
) // IN/OUT
300 static int HMAC_HmacNull (
301 HMACContextRef hmacCtx
,
304 void *hmac
, // mallocd by caller
310 const HMACReference TlsHmacNull
= {
321 const HMACReference TlsHmacMD5
= {
332 const HMACReference TlsHmacSHA1
= {
343 const HMACReference TlsHmacSHA256
= {
354 const HMACReference TlsHmacSHA384
= {