1#ifdef HMAC_MD5
2#ifndef __APPLE__
3#ifndef LINT
4static const char rcsid[] = "$Header: /Users/Shared/libresolv_2/libresolv/dst_hmac_link.c,v 1.1 2006/03/01 19:01:36 majka Exp $";
5#endif
6#endif
7
8/*
9 * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
10 *
11 * Permission to use, copy modify, and distribute this software for any
12 * purpose with or without fee is hereby granted, provided that the above
13 * copyright notice and this permission notice appear in all copies.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
16 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL
18 * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
19 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
20 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
21 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
22 * WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
23 */
24
25/*
26 * This file contains an implementation of the HMAC-MD5 algorithm.
27 */
28#ifndef __APPLE__
29#include "port_before.h"
30#endif
31
32#include <stdio.h>
33#include <unistd.h>
34#include <stdlib.h>
35#include <string.h>
36#include <memory.h>
37#include <sys/param.h>
38#include <sys/time.h>
39#include <netinet/in.h>
40#include <arpa/nameser.h>
41#include <resolv.h>
42
43#include "dst_internal.h"
44#ifdef USE_MD5
45# include "md5.h"
46# ifndef _MD5_H_
47#  define _MD5_H_ 1	/* make sure we do not include rsaref md5.h file */
48# endif
49#endif
50
51#ifndef __APPLE__
52#include "port_after.h"
53#endif
54
55
56#define HMAC_LEN	64
57#define HMAC_IPAD	0x36
58#define HMAC_OPAD	0x5c
59#define MD5_LEN		16
60
61
62typedef struct hmackey {
63	u_char hk_ipad[64], hk_opad[64];
64} HMAC_Key;
65
66
67/**************************************************************************
68 * dst_hmac_md5_sign
69 *     Call HMAC signing functions to sign a block of data.
70 *     There are three steps to signing, INIT (initialize structures),
71 *     UPDATE (hash (more) data), FINAL (generate a signature).  This
72 *     routine performs one or more of these steps.
73 * Parameters
74 *     mode	SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
75 *     priv_key    key to use for signing.
76 *     context   the context to be used in this digest
77 *     data	data to be signed.
78 *     len	 length in bytes of data.
79 *     signature   location to store signature.
80 *     sig_len     size of the signature location
81 * returns
82 *	N  Success on SIG_MODE_FINAL = returns signature length in bytes
83 *	0  Success on SIG_MODE_INIT  and UPDATE
84 *	 <0  Failure
85 */
86
87static int
88dst_hmac_md5_sign(const int mode, DST_KEY *d_key, void **context,
89		  const u_char *data, const int len,
90		  u_char *signature, const int sig_len)
91{
92	HMAC_Key *key;
93	int sign_len = 0;
94	MD5_CTX *ctx = NULL;
95
96	if (mode & SIG_MODE_INIT)
97		ctx = (MD5_CTX *) malloc(sizeof(*ctx));
98	else if (context)
99		ctx = (MD5_CTX *) *context;
100	if (ctx == NULL)
101		return (-1);
102
103	if (d_key == NULL || d_key->dk_KEY_struct == NULL)
104		return (-1);
105	key = (HMAC_Key *) d_key->dk_KEY_struct;
106
107	if (mode & SIG_MODE_INIT) {
108		MD5Init(ctx);
109		MD5Update(ctx, key->hk_ipad, HMAC_LEN);
110	}
111
112	if ((mode & SIG_MODE_UPDATE) && (data && len > 0))
113		MD5Update(ctx, data, len);
114
115	if (mode & SIG_MODE_FINAL) {
116		if (signature == NULL || sig_len < MD5_LEN)
117			return (SIGN_FINAL_FAILURE);
118		MD5Final(signature, ctx);
119
120		/* perform outer MD5 */
121		MD5Init(ctx);
122		MD5Update(ctx, key->hk_opad, HMAC_LEN);
123		MD5Update(ctx, signature, MD5_LEN);
124		MD5Final(signature, ctx);
125		sign_len = MD5_LEN;
126		SAFE_FREE(ctx);
127	}
128	else {
129		if (context == NULL)
130			return (-1);
131		*context = (void *) ctx;
132	}
133	return (sign_len);
134}
135
136
137/**************************************************************************
138 * dst_hmac_md5_verify()
139 *     Calls HMAC verification routines.  There are three steps to
140 *     verification, INIT (initialize structures), UPDATE (hash (more) data),
141 *     FINAL (generate a signature).  This routine performs one or more of
142 *     these steps.
143 * Parameters
144 *     mode	SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
145 *     dkey	key to use for verify.
146 *     data	data signed.
147 *     len	 length in bytes of data.
148 *     signature   signature.
149 *     sig_len     length in bytes of signature.
150 * returns
151 *     0  Success
152 *    <0  Failure
153 */
154
155static int
156dst_hmac_md5_verify(const int mode, DST_KEY *d_key, void **context,
157		const u_char *data, const int len,
158		const u_char *signature, const int sig_len)
159{
160	HMAC_Key *key;
161	MD5_CTX *ctx = NULL;
162
163	if (mode & SIG_MODE_INIT)
164		ctx = (MD5_CTX *) malloc(sizeof(*ctx));
165	else if (context)
166		ctx = (MD5_CTX *) *context;
167	if (ctx == NULL)
168		return (-1);
169
170	if (d_key == NULL || d_key->dk_KEY_struct == NULL)
171		return (-1);
172
173	key = (HMAC_Key *) d_key->dk_KEY_struct;
174	if (mode & SIG_MODE_INIT) {
175		MD5Init(ctx);
176		MD5Update(ctx, key->hk_ipad, HMAC_LEN);
177	}
178	if ((mode & SIG_MODE_UPDATE) && (data && len > 0))
179		MD5Update(ctx, data, len);
180
181	if (mode & SIG_MODE_FINAL) {
182		u_char digest[MD5_LEN];
183		if (signature == NULL || key == NULL || sig_len != MD5_LEN)
184			return (VERIFY_FINAL_FAILURE);
185		MD5Final(digest, ctx);
186
187		/* perform outer MD5 */
188		MD5Init(ctx);
189		MD5Update(ctx, key->hk_opad, HMAC_LEN);
190		MD5Update(ctx, digest, MD5_LEN);
191		MD5Final(digest, ctx);
192
193		SAFE_FREE(ctx);
194		if (memcmp(digest, signature, MD5_LEN) != 0)
195			return (VERIFY_FINAL_FAILURE);
196	}
197	else {
198		if (context == NULL)
199			return (-1);
200		*context = (void *) ctx;
201	}
202	return (0);
203}
204
205
206/**************************************************************************
207 * dst_buffer_to_hmac_md5
208 *     Converts key from raw data to an HMAC Key
209 *     This function gets in a pointer to the data
210 * Parameters
211 *     hkey	the HMAC key to be filled in
212 *     key	the key in raw format
213 *     keylen	the length of the key
214 * Return
215 *	0	Success
216 *	<0	Failure
217 */
218static int
219dst_buffer_to_hmac_md5(DST_KEY *dkey, const u_char *key, const int keylen)
220{
221	int i;
222	HMAC_Key *hkey = NULL;
223	MD5_CTX ctx;
224	int local_keylen = keylen;
225
226	if (dkey == NULL || key == NULL || keylen < 0)
227		return (-1);
228
229	if ((hkey = (HMAC_Key *) malloc(sizeof(HMAC_Key))) == NULL)
230		  return (-2);
231
232	memset(hkey->hk_ipad, 0, sizeof(hkey->hk_ipad));
233	memset(hkey->hk_opad, 0, sizeof(hkey->hk_opad));
234
235	/* if key is longer than HMAC_LEN bytes reset it to key=MD5(key) */
236	if (keylen > HMAC_LEN) {
237		u_char tk[MD5_LEN];
238		MD5Init(&ctx);
239		MD5Update(&ctx, key, keylen);
240		MD5Final(tk, &ctx);
241		memset((void *) &ctx, 0, sizeof(ctx));
242		key = tk;
243		local_keylen = MD5_LEN;
244	}
245	/* start out by storing key in pads */
246	memcpy(hkey->hk_ipad, key, local_keylen);
247	memcpy(hkey->hk_opad, key, local_keylen);
248
249	/* XOR key with hk_ipad and opad values */
250	for (i = 0; i < HMAC_LEN; i++) {
251		hkey->hk_ipad[i] ^= HMAC_IPAD;
252		hkey->hk_opad[i] ^= HMAC_OPAD;
253	}
254	dkey->dk_key_size = local_keylen;
255	dkey->dk_KEY_struct = (void *) hkey;
256	return (1);
257}
258
259
260/**************************************************************************
261 *  dst_hmac_md5_key_to_file_format
262 *	Encodes an HMAC Key into the portable file format.
263 *  Parameters
264 *	hkey      HMAC KEY structure
265 *	buff      output buffer
266 *	buff_len  size of output buffer
267 *  Return
268 *	0  Failure - null input hkey
269 *     -1  Failure - not enough space in output area
270 *	N  Success - Length of data returned in buff
271 */
272
273static int
274dst_hmac_md5_key_to_file_format(const DST_KEY *dkey, char *buff,
275			    const int buff_len)
276{
277	char *bp;
278	int len, b_len, i, key_len;
279	u_char key[HMAC_LEN];
280	HMAC_Key *hkey;
281
282	if (dkey == NULL || dkey->dk_KEY_struct == NULL)
283		return (0);
284	if (buff == NULL || buff_len <= (int) strlen(key_file_fmt_str))
285		return (-1);	/* no OR not enough space in output area */
286
287	hkey = (HMAC_Key *) dkey->dk_KEY_struct;
288	memset(buff, 0, buff_len);	/* just in case */
289	/* write file header */
290	sprintf(buff, key_file_fmt_str, KEY_FILE_FORMAT, KEY_HMAC_MD5, "HMAC");
291
292	bp = (char *) strchr(buff, '\0');
293	b_len = buff_len - (bp - buff);
294
295	memset(key, 0, HMAC_LEN);
296	for (i = 0; i < HMAC_LEN; i++)
297		key[i] = hkey->hk_ipad[i] ^ HMAC_IPAD;
298	for (i = HMAC_LEN - 1; i >= 0; i--)
299		if (key[i] != 0)
300			break;
301	key_len = i + 1;
302
303	strcat(bp, "Key: ");
304	bp += strlen("Key: ");
305	b_len = buff_len - (bp - buff);
306
307	len = b64_ntop(key, key_len, bp, b_len);
308	if (len < 0)
309		return (-1);
310	bp += len;
311	*(bp++) = '\n';
312	*bp = '\0';
313	b_len = buff_len - (bp - buff);
314
315	return (buff_len - b_len);
316}
317
318
319/**************************************************************************
320 * dst_hmac_md5_key_from_file_format
321 *     Converts contents of a key file into an HMAC key.
322 * Parameters
323 *     hkey    structure to put key into
324 *     buff       buffer containing the encoded key
325 *     buff_len   the length of the buffer
326 * Return
327 *     n >= 0 Foot print of the key converted
328 *     n <  0 Error in conversion
329 */
330
331static int
332dst_hmac_md5_key_from_file_format(DST_KEY *dkey, const char *buff,
333			      const int buff_len)
334{
335	const char *p = buff, *eol;
336	u_char key[HMAC_LEN+1];	/* b64_pton needs more than 64 bytes do decode
337							 * it should probably be fixed rather than doing
338							 * this
339							 */
340	u_char *tmp;
341	int key_len, len;
342
343	if (dkey == NULL)
344		return (-2);
345	if (buff == NULL || buff_len < 0)
346		return (-1);
347
348	memset(key, 0, sizeof(key));
349
350	if (!dst_s_verify_str(&p, "Key: "))
351		return (-3);
352
353	eol = strchr(p, '\n');
354	if (eol == NULL)
355		return (-4);
356	len = eol - p;
357	tmp = malloc(len + 2);
358	memcpy(tmp, p, len);
359	*(tmp + len) = 0x0;
360	key_len = b64_pton((char *)tmp, key, HMAC_LEN+1);	/* see above */
361	SAFE_FREE2(tmp, len + 2);
362
363	if (dst_buffer_to_hmac_md5(dkey, key, key_len) < 0) {
364		return (-6);
365	}
366	return (0);
367}
368
369/*
370 * dst_hmac_md5_to_dns_key()
371 *         function to extract hmac key from DST_KEY structure
372 * intput:
373 *      in_key:  HMAC-MD5 key
374 * output:
375 *	out_str: buffer to write ot
376 *      out_len: size of output buffer
377 * returns:
378 *      number of bytes written to output buffer
379 */
380static int
381dst_hmac_md5_to_dns_key(const DST_KEY *in_key, u_char *out_str,
382			const int out_len)
383{
384
385	HMAC_Key *hkey;
386	int i;
387
388	if (in_key == NULL || in_key->dk_KEY_struct == NULL ||
389	    out_len <= in_key->dk_key_size || out_str == NULL)
390		return (-1);
391
392	hkey = (HMAC_Key *) in_key->dk_KEY_struct;
393	for (i = 0; i < in_key->dk_key_size; i++)
394		out_str[i] = hkey->hk_ipad[i] ^ HMAC_IPAD;
395	return (i);
396}
397
398/**************************************************************************
399 *  dst_hmac_md5_compare_keys
400 *	Compare two keys for equality.
401 *  Return
402 *	0	  The keys are equal
403 *	NON-ZERO   The keys are not equal
404 */
405
406static int
407dst_hmac_md5_compare_keys(const DST_KEY *key1, const DST_KEY *key2)
408{
409	HMAC_Key *hkey1 = (HMAC_Key *) key1->dk_KEY_struct;
410	HMAC_Key *hkey2 = (HMAC_Key *) key2->dk_KEY_struct;
411	return memcmp(hkey1->hk_ipad, hkey2->hk_ipad, HMAC_LEN);
412}
413
414/**************************************************************************
415 * dst_hmac_md5_free_key_structure
416 *     Frees all (none) dynamically allocated structures in hkey
417 */
418
419static void *
420dst_hmac_md5_free_key_structure(void *key)
421{
422	HMAC_Key *hkey = key;
423	SAFE_FREE(hkey);
424	return (NULL);
425}
426
427
428/***************************************************************************
429 * dst_hmac_md5_generate_key
430 *     Creates a HMAC key of size size with a maximum size of 63 bytes
431 *     generating a HMAC key larger than 63 bytes makes no sense as that key
432 *     is digested before use.
433 */
434
435static int
436dst_hmac_md5_generate_key(DST_KEY *key, const int nothing)
437{
438	(void)key;
439	(void)nothing;
440	return (-1);
441}
442
443/*
444 * dst_hmac_md5_init()  Function to answer set up function pointers for HMAC
445 *	   related functions
446 */
447int
448dst_hmac_md5_init()
449{
450	if (dst_t_func[KEY_HMAC_MD5] != NULL)
451		return (1);
452	dst_t_func[KEY_HMAC_MD5] = malloc(sizeof(struct dst_func));
453	if (dst_t_func[KEY_HMAC_MD5] == NULL)
454		return (0);
455	memset(dst_t_func[KEY_HMAC_MD5], 0, sizeof(struct dst_func));
456	dst_t_func[KEY_HMAC_MD5]->sign = dst_hmac_md5_sign;
457	dst_t_func[KEY_HMAC_MD5]->verify = dst_hmac_md5_verify;
458	dst_t_func[KEY_HMAC_MD5]->compare = dst_hmac_md5_compare_keys;
459	dst_t_func[KEY_HMAC_MD5]->generate = dst_hmac_md5_generate_key;
460	dst_t_func[KEY_HMAC_MD5]->destroy = dst_hmac_md5_free_key_structure;
461	dst_t_func[KEY_HMAC_MD5]->to_dns_key = dst_hmac_md5_to_dns_key;
462	dst_t_func[KEY_HMAC_MD5]->from_dns_key = dst_buffer_to_hmac_md5;
463	dst_t_func[KEY_HMAC_MD5]->to_file_fmt = dst_hmac_md5_key_to_file_format;
464	dst_t_func[KEY_HMAC_MD5]->from_file_fmt = dst_hmac_md5_key_from_file_format;
465	return (1);
466}
467
468#else
469#define dst_hmac_md5_init res_9_dst_hmac_md5_init
470int
471dst_hmac_md5_init(){
472	return (0);
473}
474#endif
475
476
477
478
479
480
481
482