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