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