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 #else 23 __RCSID("$NetBSD: hmac_link.c,v 1.3 2016/03/07 14:35:39 christos 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 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 */ 473