Home | History | Annotate | Line # | Download | only in libresolv
      1 /*	$NetBSD: hmac_link.c,v 1.4 2025/06/27 21:36:22 andvar Exp $	*/
      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
     23 __RCSID("$NetBSD: hmac_link.c,v 1.4 2025/06/27 21:36:22 andvar Exp $");
     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))
    106 		MD5Update(ctx, data, (unsigned int)len);
    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 #define BUF_LEFT (size_t)(buff_len - (bp - buff))
    272 	int len, key_len;
    273 	u_char key[HMAC_LEN];
    274 	HMAC_Key *hkey;
    275 	static const char keystr[] = "Key: ";
    276 
    277 	if (buff == NULL)
    278 		return -1;	/*%< no output area */
    279 
    280 	if (dkey == NULL || dkey->dk_KEY_struct == NULL)
    281 		return 0;
    282 
    283 	/* write file header */
    284 	hkey = (HMAC_Key *) dkey->dk_KEY_struct;
    285 	len = snprintf(buff, buff_len, KEY_FILE_FMT_STR, KEY_FILE_FORMAT,
    286 	    KEY_HMAC_MD5, "HMAC");
    287 	if (len < 0 || len >= buff_len)
    288 		return -1; 	/*%< not enough space in output area */
    289 	bp = buff + len;
    290 	if (BUF_LEFT < sizeof(keystr))
    291 		return -1;
    292 
    293 	memcpy(bp, keystr, sizeof(keystr) - 1);
    294 	bp += sizeof(keystr) - 1;
    295 
    296 	for (key_len = 0; key_len < HMAC_LEN; key_len++)
    297 		key[key_len] = hkey->hk_ipad[key_len] ^ HMAC_IPAD;
    298 	for (key_len = HMAC_LEN - 1; key_len >= 0; key_len--)
    299 		if (key[key_len] != 0)
    300 			break;
    301 	key_len++;
    302 
    303 	len = b64_ntop(key, key_len, bp, BUF_LEFT);
    304 	if (len < 0)
    305 		return -1;
    306 	bp += len;
    307 
    308 	if (BUF_LEFT < 2)
    309 		return -1;
    310 	*(bp++) = '\n';
    311 
    312 	memset(bp, 0, BUF_LEFT);
    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 to
    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 */
    473