1 /*
   2  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
   3  * Use is subject to license terms.
   4  */
   5 
   6 #pragma ident   "%Z%%M% %I%     %E% SMI"
   7 
   8 #ifdef HMAC_MD5
   9 #ifndef LINT
  10 static const char rcsid[] = "$Header: /proj/cvs/isc/bind8/src/lib/dst/hmac_link.c,v 1.9 2001/05/29 05:48:10 marka Exp $";
  11 #endif
  12 /*
  13  * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
  14  *
  15  * Permission to use, copy modify, and distribute this software for any
  16  * purpose with or without fee is hereby granted, provided that the above
  17  * copyright notice and this permission notice appear in all copies.
  18  *
  19  * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
  20  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
  21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL
  22  * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
  23  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
  24  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  25  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  26  * WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
  27  */
  28 
  29 /* 
  30  * This file contains an implementation of the HMAC-MD5 algorithm.
  31  */
  32 #include "port_before.h"
  33 
  34 #include <stdio.h>
  35 #include <unistd.h>
  36 #include <stdlib.h>
  37 #include <string.h>
  38 #include <memory.h>
  39 #include <sys/param.h>
  40 #include <sys/time.h>
  41 #include <netinet/in.h>
  42 #include <arpa/nameser.h>
  43 #include <resolv.h>
  44 
  45 #include "dst_internal.h"
  46 #ifdef USE_MD5
  47 #ifndef SUNW_LIBMD5
  48 # include "md5.h"
  49 #else
  50 #include <sys/md5.h>
  51 #endif
  52 # ifndef _MD5_H_
  53 #  define _MD5_H_ 1     /* make sure we do not include rsaref md5.h file */
  54 # endif
  55 #endif
  56 
  57 #include "port_after.h"
  58 
  59 
  60 #define HMAC_LEN        64
  61 #define HMAC_IPAD       0x36
  62 #define HMAC_OPAD       0x5c
  63 #define MD5_LEN         16
  64 
  65 
  66 typedef struct hmackey {
  67         u_char hk_ipad[64], hk_opad[64];
  68 } HMAC_Key;
  69 
  70 
  71 /************************************************************************** 
  72  * dst_hmac_md5_sign
  73  *     Call HMAC signing functions to sign a block of data.
  74  *     There are three steps to signing, INIT (initialize structures), 
  75  *     UPDATE (hash (more) data), FINAL (generate a signature).  This
  76  *     routine performs one or more of these steps.
  77  * Parameters
  78  *     mode     SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
  79  *     priv_key    key to use for signing.
  80  *     context   the context to be used in this digest
  81  *     data     data to be signed.
  82  *     len       length in bytes of data.
  83  *     signature   location to store signature.
  84  *     sig_len     size of the signature location
  85  * returns 
  86  *      N  Success on SIG_MODE_FINAL = returns signature length in bytes
  87  *      0  Success on SIG_MODE_INIT  and UPDATE
  88  *       <0  Failure
  89  */
  90 
  91 static int
  92 dst_hmac_md5_sign(const int mode, DST_KEY *d_key, void **context, 
  93                   const u_char *data, const int len, 
  94                   u_char *signature, const int sig_len)
  95 {
  96         HMAC_Key *key;
  97         int sign_len = 0;
  98         MD5_CTX *ctx = NULL;
  99 
 100         if (mode & SIG_MODE_INIT) 
 101                 ctx = (MD5_CTX *) malloc(sizeof(*ctx));
 102         else if (context)
 103                 ctx = (MD5_CTX *) *context;
 104         if (ctx == NULL) 
 105                 return (-1);
 106 
 107         if (d_key == NULL || d_key->dk_KEY_struct == NULL)
 108                 return (-1);
 109         key = (HMAC_Key *) d_key->dk_KEY_struct;
 110 
 111         if (mode & SIG_MODE_INIT) {
 112                 MD5Init(ctx);
 113                 MD5Update(ctx, key->hk_ipad, HMAC_LEN);
 114         }
 115 
 116         if ((mode & SIG_MODE_UPDATE) && (data && len > 0))
 117                 MD5Update(ctx, data, len);
 118 
 119         if (mode & SIG_MODE_FINAL) {
 120                 if (signature == NULL || sig_len < MD5_LEN)
 121                         return (SIGN_FINAL_FAILURE);
 122                 MD5Final(signature, ctx);
 123 
 124                 /* perform outer MD5 */
 125                 MD5Init(ctx);
 126                 MD5Update(ctx, key->hk_opad, HMAC_LEN);
 127                 MD5Update(ctx, signature, MD5_LEN);
 128                 MD5Final(signature, ctx);
 129                 sign_len = MD5_LEN;
 130                 SAFE_FREE(ctx);
 131         }
 132         else { 
 133                 if (context == NULL) 
 134                         return (-1);
 135                 *context = (void *) ctx;
 136         }               
 137         return (sign_len);
 138 }
 139 
 140 
 141 /************************************************************************** 
 142  * dst_hmac_md5_verify() 
 143  *     Calls HMAC verification routines.  There are three steps to 
 144  *     verification, INIT (initialize structures), UPDATE (hash (more) data), 
 145  *     FINAL (generate a signature).  This routine performs one or more of 
 146  *     these steps.
 147  * Parameters
 148  *     mode     SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
 149  *     dkey     key to use for verify.
 150  *     data     data signed.
 151  *     len       length in bytes of data.
 152  *     signature   signature.
 153  *     sig_len     length in bytes of signature.
 154  * returns 
 155  *     0  Success 
 156  *    <0  Failure
 157  */
 158 
 159 static int
 160 dst_hmac_md5_verify(const int mode, DST_KEY *d_key, void **context,
 161                 const u_char *data, const int len,
 162                 const u_char *signature, const int sig_len)
 163 {
 164         HMAC_Key *key;
 165         MD5_CTX *ctx = NULL;
 166 
 167         if (mode & SIG_MODE_INIT) 
 168                 ctx = (MD5_CTX *) malloc(sizeof(*ctx));
 169         else if (context)
 170                 ctx = (MD5_CTX *) *context;
 171         if (ctx == NULL) 
 172                 return (-1);
 173 
 174         if (d_key == NULL || d_key->dk_KEY_struct == NULL)
 175                 return (-1);
 176 
 177         key = (HMAC_Key *) d_key->dk_KEY_struct;
 178         if (mode & SIG_MODE_INIT) {
 179                 MD5Init(ctx);
 180                 MD5Update(ctx, key->hk_ipad, HMAC_LEN);
 181         }
 182         if ((mode & SIG_MODE_UPDATE) && (data && len > 0))
 183                 MD5Update(ctx, data, len);
 184 
 185         if (mode & SIG_MODE_FINAL) {
 186                 u_char digest[MD5_LEN];
 187                 if (signature == NULL || key == NULL || sig_len != MD5_LEN)
 188                         return (VERIFY_FINAL_FAILURE);
 189                 MD5Final(digest, ctx);
 190 
 191                 /* perform outer MD5 */
 192                 MD5Init(ctx);
 193                 MD5Update(ctx, key->hk_opad, HMAC_LEN);
 194                 MD5Update(ctx, digest, MD5_LEN);
 195                 MD5Final(digest, ctx);
 196 
 197                 SAFE_FREE(ctx);
 198                 if (memcmp(digest, signature, MD5_LEN) != 0)
 199                         return (VERIFY_FINAL_FAILURE);
 200         }
 201         else { 
 202                 if (context == NULL) 
 203                         return (-1);
 204                 *context = (void *) ctx;
 205         }               
 206         return (0);
 207 }
 208 
 209 
 210 /************************************************************************** 
 211  * dst_buffer_to_hmac_md5
 212  *     Converts key from raw data to an HMAC Key
 213  *     This function gets in a pointer to the data
 214  * Parameters
 215  *     hkey     the HMAC key to be filled in
 216  *     key      the key in raw format
 217  *     keylen   the length of the key
 218  * Return
 219  *      0       Success
 220  *      <0   Failure
 221  */
 222 static int
 223 dst_buffer_to_hmac_md5(DST_KEY *dkey, const u_char *key, const int keylen)
 224 {
 225         int i;
 226         HMAC_Key *hkey = NULL;
 227         MD5_CTX ctx;
 228         int local_keylen = keylen;
 229 
 230         if (dkey == NULL || key == NULL || keylen < 0)
 231                 return (-1);
 232 
 233         if ((hkey = (HMAC_Key *) malloc(sizeof(HMAC_Key))) == NULL)
 234                   return (-2);
 235 
 236         memset(hkey->hk_ipad, 0, sizeof(hkey->hk_ipad));
 237         memset(hkey->hk_opad, 0, sizeof(hkey->hk_opad));
 238 
 239         /* if key is longer than HMAC_LEN bytes reset it to key=MD5(key) */
 240         if (keylen > HMAC_LEN) {
 241                 u_char tk[MD5_LEN];
 242                 MD5Init(&ctx);
 243                 MD5Update(&ctx, key, keylen);
 244                 MD5Final(tk, &ctx);
 245                 memset((void *) &ctx, 0, sizeof(ctx));
 246                 key = tk;
 247                 local_keylen = MD5_LEN;
 248         }
 249         /* start out by storing key in pads */
 250         memcpy(hkey->hk_ipad, key, local_keylen);
 251         memcpy(hkey->hk_opad, key, local_keylen);
 252 
 253         /* XOR key with hk_ipad and opad values */
 254         for (i = 0; i < HMAC_LEN; i++) {
 255                 hkey->hk_ipad[i] ^= HMAC_IPAD;
 256                 hkey->hk_opad[i] ^= HMAC_OPAD;
 257         }
 258         dkey->dk_key_size = local_keylen;
 259         dkey->dk_KEY_struct = (void *) hkey;
 260         return (1);
 261 }
 262 
 263 
 264 /************************************************************************** 
 265  *  dst_hmac_md5_key_to_file_format
 266  *      Encodes an HMAC Key into the portable file format.
 267  *  Parameters 
 268  *      hkey      HMAC KEY structure 
 269  *      buff      output buffer
 270  *      buff_len  size of output buffer 
 271  *  Return
 272  *      0  Failure - null input hkey
 273  *     -1  Failure - not enough space in output area
 274  *      N  Success - Length of data returned in buff
 275  */
 276 
 277 static int
 278 dst_hmac_md5_key_to_file_format(const DST_KEY *dkey, char *buff,
 279                             const int buff_len)
 280 {
 281         char *bp;
 282         int len, b_len, i, key_len;
 283         u_char key[HMAC_LEN];
 284         HMAC_Key *hkey;
 285 
 286         if (dkey == NULL || dkey->dk_KEY_struct == NULL) 
 287                 return (0);
 288         if (buff == NULL || buff_len <= (int) strlen(key_file_fmt_str))
 289                 return (-1);    /* no OR not enough space in output area */
 290 
 291         hkey = (HMAC_Key *) dkey->dk_KEY_struct;
 292         memset(buff, 0, buff_len);      /* just in case */
 293         /* write file header */
 294         sprintf(buff, key_file_fmt_str, KEY_FILE_FORMAT, KEY_HMAC_MD5, "HMAC");
 295 
 296         bp = (char *) strchr(buff, '\0');
 297         b_len = buff_len - (bp - buff);
 298 
 299         memset(key, 0, HMAC_LEN);
 300         for (i = 0; i < HMAC_LEN; i++)
 301                 key[i] = hkey->hk_ipad[i] ^ HMAC_IPAD;
 302         for (i = HMAC_LEN - 1; i >= 0; i--)
 303                 if (key[i] != 0)
 304                         break;
 305         key_len = i + 1;
 306 
 307         strcat(bp, "Key: ");
 308         bp += strlen("Key: ");
 309         b_len = buff_len - (bp - buff);
 310 
 311         len = b64_ntop(key, key_len, bp, b_len);
 312         if (len < 0) 
 313                 return (-1);
 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 int 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         int key_len, len;
 346 
 347         if (dkey == NULL)
 348                 return (-2);
 349         if (buff == NULL || buff_len < 0)
 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  * intput: 
 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 int 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 i, n, size;
 444 
 445         i = nothing;
 446 
 447         if (key == NULL || key->dk_alg != KEY_HMAC_MD5)
 448                 return (0);
 449         size = (key->dk_key_size + 7) / 8; /* convert to bytes */
 450         if (size <= 0)
 451                 return(0);
 452         
 453         i = size > 64 ? 64 : size;
 454         buff = malloc(i+8);
 455 
 456         n = dst_random(DST_RAND_SEMI, i, buff);
 457         n += dst_random(DST_RAND_KEY, i, buff);
 458         if (n <= i) {        /* failed getting anything */
 459                 SAFE_FREE2(buff, i);
 460                 return (-1);
 461         }
 462         n = dst_buffer_to_hmac_md5(key, buff, i);
 463         SAFE_FREE2(buff, i);
 464         if (n <= 0)
 465                 return (n);
 466         return (1);
 467 }
 468 
 469 /*
 470  * dst_hmac_md5_init()  Function to answer set up function pointers for HMAC
 471  *         related functions 
 472  */
 473 int
 474 #ifdef  ORIGINAL_ISC_CODE
 475 dst_hmac_md5_init()
 476 #else
 477 dst_md5_hmac_init()
 478 #endif
 479 {
 480         if (dst_t_func[KEY_HMAC_MD5] != NULL)
 481                 return (1);
 482         dst_t_func[KEY_HMAC_MD5] = malloc(sizeof(struct dst_func));
 483         if (dst_t_func[KEY_HMAC_MD5] == NULL)
 484                 return (0);
 485         memset(dst_t_func[KEY_HMAC_MD5], 0, sizeof(struct dst_func));
 486         dst_t_func[KEY_HMAC_MD5]->sign = dst_hmac_md5_sign;
 487         dst_t_func[KEY_HMAC_MD5]->verify = dst_hmac_md5_verify;
 488         dst_t_func[KEY_HMAC_MD5]->compare = dst_hmac_md5_compare_keys;
 489         dst_t_func[KEY_HMAC_MD5]->generate = dst_hmac_md5_generate_key;
 490         dst_t_func[KEY_HMAC_MD5]->destroy = dst_hmac_md5_free_key_structure;
 491         dst_t_func[KEY_HMAC_MD5]->to_dns_key = dst_hmac_md5_to_dns_key;
 492         dst_t_func[KEY_HMAC_MD5]->from_dns_key = dst_buffer_to_hmac_md5;
 493         dst_t_func[KEY_HMAC_MD5]->to_file_fmt = dst_hmac_md5_key_to_file_format;
 494         dst_t_func[KEY_HMAC_MD5]->from_file_fmt = dst_hmac_md5_key_from_file_format;
 495         return (1);
 496 }
 497 
 498 #else 
 499 int
 500 dst_hmac_md5_init(){
 501         return (0);
 502 }
 503 #endif
 504 
 505 
 506 
 507 
 508 
 509 
 510