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