1/*
2 * Copyright (c) 2002,2005-2008,2010-2012,2014 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 */
39struct 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 */
50static 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 */
146static 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 */
165static 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 */
182static 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
200static 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 */
234static 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
262static 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
272static int HMAC_FreeNull(
273	HMACContextRef	hmacCtx)
274{
275	return 0;
276}
277
278static int HMAC_InitNull(
279	HMACContextRef	hmacCtx)
280	{
281	return 0;
282}
283
284static int HMAC_UpdateNull(
285	HMACContextRef	hmacCtx,
286	const void		*data,
287	size_t          dataLen)
288{
289	return 0;
290}
291
292static int HMAC_FinalNull(
293	HMACContextRef	hmacCtx,
294	void			*hmac,			// mallocd by caller
295	size_t          *hmacLen)		// IN/OUT
296{
297	return 0;
298}
299
300static 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
310const 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
321const 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
332const 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
343const 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
354const 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};
364