Annotation of embedaddon/ntp/libntp/authkeys.c, revision 1.1
1.1 ! misho 1: /*
! 2: * authkeys.c - routines to manage the storage of authentication keys
! 3: */
! 4: #ifdef HAVE_CONFIG_H
! 5: # include <config.h>
! 6: #endif
! 7:
! 8: #include <stdio.h>
! 9:
! 10: #include "ntp_types.h"
! 11: #include "ntp_fp.h"
! 12: #include "ntp.h"
! 13: #include "ntpd.h"
! 14: #include "ntp_string.h"
! 15: #include "ntp_malloc.h"
! 16: #include "ntp_stdlib.h"
! 17:
! 18: /*
! 19: * Structure to store keys in in the hash table.
! 20: */
! 21: struct savekey {
! 22: struct savekey *next;
! 23: union {
! 24: u_char MD5_key[64]; /* for keys up to to 512 bits */
! 25: } k;
! 26: keyid_t keyid; /* key identifier */
! 27: int type; /* key type */
! 28: u_short flags; /* flags that wave */
! 29: u_long lifetime; /* remaining lifetime */
! 30: int keylen; /* key length */
! 31: };
! 32:
! 33: #define KEY_TRUSTED 0x001 /* this key is trusted */
! 34:
! 35: /*
! 36: * The hash table. This is indexed by the low order bits of the
! 37: * keyid. We make this fairly big for potentially busy servers.
! 38: */
! 39: #define HASHSIZE 64
! 40: #define HASHMASK ((HASHSIZE)-1)
! 41: #define KEYHASH(keyid) ((keyid) & HASHMASK)
! 42:
! 43: struct savekey *key_hash[HASHSIZE];
! 44:
! 45: u_long authkeynotfound; /* keys not found */
! 46: u_long authkeylookups; /* calls to lookup keys */
! 47: u_long authnumkeys; /* number of active keys */
! 48: u_long authkeyexpired; /* key lifetime expirations */
! 49: u_long authkeyuncached; /* cache misses */
! 50: u_long authnokey; /* calls to encrypt with no key */
! 51: u_long authencryptions; /* calls to encrypt */
! 52: u_long authdecryptions; /* calls to decrypt */
! 53:
! 54: /*
! 55: * Storage for free key structures. We malloc() such things but
! 56: * never free them.
! 57: */
! 58: struct savekey *authfreekeys;
! 59: int authnumfreekeys;
! 60:
! 61: #define MEMINC 12 /* number of new free ones to get */
! 62:
! 63: /*
! 64: * The key cache. We cache the last key we looked at here.
! 65: */
! 66: keyid_t cache_keyid; /* key identifier */
! 67: u_char *cache_key; /* key pointer */
! 68: u_int cache_keylen; /* key length */
! 69: int cache_type; /* key type */
! 70: u_short cache_flags; /* flags that wave */
! 71:
! 72:
! 73: /*
! 74: * init_auth - initialize internal data
! 75: */
! 76: void
! 77: init_auth(void)
! 78: {
! 79: /*
! 80: * Initialize hash table and free list
! 81: */
! 82: memset((char *)key_hash, 0, sizeof key_hash);
! 83: }
! 84:
! 85:
! 86: /*
! 87: * auth_findkey - find a key in the hash table
! 88: */
! 89: struct savekey *
! 90: auth_findkey(
! 91: keyid_t keyno
! 92: )
! 93: {
! 94: struct savekey *sk;
! 95:
! 96: sk = key_hash[KEYHASH(keyno)];
! 97: while (sk != 0) {
! 98: if (keyno == sk->keyid)
! 99: return (sk);
! 100:
! 101: sk = sk->next;
! 102: }
! 103: return (0);
! 104: }
! 105:
! 106:
! 107: /*
! 108: * auth_havekey - return one if the key is known
! 109: */
! 110: int
! 111: auth_havekey(
! 112: keyid_t keyno
! 113: )
! 114: {
! 115: struct savekey *sk;
! 116:
! 117: if (keyno == 0 || (keyno == cache_keyid))
! 118: return (1);
! 119:
! 120: sk = key_hash[KEYHASH(keyno)];
! 121: while (sk != 0) {
! 122: if (keyno == sk->keyid)
! 123: return (1);
! 124:
! 125: sk = sk->next;
! 126: }
! 127: return (0);
! 128: }
! 129:
! 130:
! 131: /*
! 132: * authhavekey - return one and cache the key, if known and trusted.
! 133: */
! 134: int
! 135: authhavekey(
! 136: keyid_t keyno
! 137: )
! 138: {
! 139: struct savekey *sk;
! 140:
! 141: authkeylookups++;
! 142: if (keyno == 0 || keyno == cache_keyid)
! 143: return (1);
! 144:
! 145: /*
! 146: * Seach the bin for the key. If found and the key type
! 147: * is zero, somebody marked it trusted without specifying
! 148: * a key or key type. In this case consider the key missing.
! 149: */
! 150: authkeyuncached++;
! 151: sk = key_hash[KEYHASH(keyno)];
! 152: while (sk != NULL) {
! 153: if (keyno == sk->keyid) {
! 154: if (sk->type == 0) {
! 155: authkeynotfound++;
! 156: return (0);
! 157: }
! 158: break;
! 159: }
! 160: sk = sk->next;
! 161: }
! 162:
! 163: /*
! 164: * If the key is not found, or if it is found but not trusted,
! 165: * the key is not considered found.
! 166: */
! 167: if (sk == NULL) {
! 168: authkeynotfound++;
! 169: return (0);
! 170:
! 171: }
! 172: if (!(sk->flags & KEY_TRUSTED)) {
! 173: authnokey++;
! 174: return (0);
! 175: }
! 176:
! 177: /*
! 178: * The key is found and trusted. Initialize the key cache.
! 179: */
! 180: cache_keyid = sk->keyid;
! 181: cache_type = sk->type;
! 182: cache_flags = sk->flags;
! 183: cache_key = sk->k.MD5_key;
! 184: cache_keylen = sk->keylen;
! 185: return (1);
! 186: }
! 187:
! 188:
! 189: /*
! 190: * auth_moremem - get some more free key structures
! 191: */
! 192: int
! 193: auth_moremem(void)
! 194: {
! 195: struct savekey *sk;
! 196: int i;
! 197:
! 198: sk = (struct savekey *)calloc(MEMINC, sizeof(struct savekey));
! 199: if (sk == 0)
! 200: return (0);
! 201:
! 202: for (i = MEMINC; i > 0; i--) {
! 203: sk->next = authfreekeys;
! 204: authfreekeys = sk++;
! 205: }
! 206: authnumfreekeys += MEMINC;
! 207: return (authnumfreekeys);
! 208: }
! 209:
! 210:
! 211: /*
! 212: * authtrust - declare a key to be trusted/untrusted
! 213: */
! 214: void
! 215: authtrust(
! 216: keyid_t keyno,
! 217: u_long trust
! 218: )
! 219: {
! 220: struct savekey *sk;
! 221:
! 222: /*
! 223: * Search bin for key; if it does not exist and is untrusted,
! 224: * forget it.
! 225: */
! 226: sk = key_hash[KEYHASH(keyno)];
! 227: while (sk != 0) {
! 228: if (keyno == sk->keyid)
! 229: break;
! 230:
! 231: sk = sk->next;
! 232: }
! 233: if (sk == 0 && !trust)
! 234: return;
! 235:
! 236: /*
! 237: * There are two conditions remaining. Either it does not
! 238: * exist and is to be trusted or it does exist and is or is
! 239: * not to be trusted.
! 240: */
! 241: if (sk != 0) {
! 242: if (cache_keyid == keyno) {
! 243: cache_flags = 0;
! 244: cache_keyid = 0;
! 245: }
! 246:
! 247: /*
! 248: * Key exists. If it is to be trusted, say so and
! 249: * update its lifetime. If not, return it to the
! 250: * free list.
! 251: */
! 252: if (trust > 0) {
! 253: sk->flags |= KEY_TRUSTED;
! 254: if (trust > 1)
! 255: sk->lifetime = current_time + trust;
! 256: else
! 257: sk->lifetime = 0;
! 258: return;
! 259: }
! 260: sk->flags &= ~KEY_TRUSTED; {
! 261: struct savekey *skp;
! 262:
! 263: skp = key_hash[KEYHASH(keyno)];
! 264: if (skp == sk) {
! 265: key_hash[KEYHASH(keyno)] = sk->next;
! 266: } else {
! 267: while (skp->next != sk)
! 268: skp = skp->next;
! 269: skp->next = sk->next;
! 270: }
! 271: authnumkeys--;
! 272:
! 273: sk->next = authfreekeys;
! 274: authfreekeys = sk;
! 275: authnumfreekeys++;
! 276: }
! 277: return;
! 278: }
! 279:
! 280: /*
! 281: * Here there is not key, but the key is to be trusted. There
! 282: * seems to be a disconnect here. Here we allocate a new key,
! 283: * but do not specify a key type, key or key length.
! 284: */
! 285: if (authnumfreekeys == 0)
! 286: if (auth_moremem() == 0)
! 287: return;
! 288:
! 289: sk = authfreekeys;
! 290: authfreekeys = sk->next;
! 291: authnumfreekeys--;
! 292: sk->keyid = keyno;
! 293: sk->type = 0;
! 294: sk->keylen = 0;
! 295: sk->flags = KEY_TRUSTED;
! 296: sk->next = key_hash[KEYHASH(keyno)];
! 297: key_hash[KEYHASH(keyno)] = sk;
! 298: authnumkeys++;
! 299: return;
! 300: }
! 301:
! 302:
! 303: /*
! 304: * authistrusted - determine whether a key is trusted
! 305: */
! 306: int
! 307: authistrusted(
! 308: keyid_t keyno
! 309: )
! 310: {
! 311: struct savekey *sk;
! 312:
! 313: if (keyno == cache_keyid)
! 314: return ((cache_flags & KEY_TRUSTED) != 0);
! 315:
! 316: authkeyuncached++;
! 317: sk = key_hash[KEYHASH(keyno)];
! 318: while (sk != 0) {
! 319: if (keyno == sk->keyid)
! 320: break;
! 321: sk = sk->next;
! 322: }
! 323: if (sk == 0) {
! 324: authkeynotfound++;
! 325: return (0);
! 326:
! 327: } else if (!(sk->flags & KEY_TRUSTED)) {
! 328: authkeynotfound++;
! 329: return (0);
! 330: }
! 331: return (1);
! 332: }
! 333:
! 334:
! 335: void
! 336: MD5auth_setkey(
! 337: keyid_t keyno,
! 338: int keytype,
! 339: const u_char *key,
! 340: const int len
! 341: )
! 342: {
! 343: struct savekey *sk;
! 344:
! 345: /*
! 346: * See if we already have the key. If so just stick in the
! 347: * new value.
! 348: */
! 349: sk = key_hash[KEYHASH(keyno)];
! 350: while (sk != NULL) {
! 351: if (keyno == sk->keyid) {
! 352: sk->type = keytype;
! 353: sk->keylen = min(len, sizeof(sk->k.MD5_key));
! 354: #ifndef DISABLE_BUG1243_FIX
! 355: memcpy(sk->k.MD5_key, key, sk->keylen);
! 356: #else
! 357: strncpy((char *)sk->k.MD5_key, (const char *)key,
! 358: sizeof(sk->k.MD5_key));
! 359: #endif
! 360: if (cache_keyid == keyno) {
! 361: cache_flags = 0;
! 362: cache_keyid = 0;
! 363: }
! 364: return;
! 365: }
! 366: sk = sk->next;
! 367: }
! 368:
! 369: /*
! 370: * Need to allocate new structure. Do it.
! 371: */
! 372: if (0 == authnumfreekeys && !auth_moremem())
! 373: return;
! 374:
! 375: sk = authfreekeys;
! 376: authfreekeys = sk->next;
! 377: authnumfreekeys--;
! 378:
! 379: sk->keyid = keyno;
! 380: sk->type = keytype;
! 381: sk->flags = 0;
! 382: sk->lifetime = 0;
! 383: sk->keylen = min(len, sizeof(sk->k.MD5_key));
! 384: #ifndef DISABLE_BUG1243_FIX
! 385: memcpy(sk->k.MD5_key, key, sk->keylen);
! 386: #else
! 387: strncpy((char *)sk->k.MD5_key, (const char *)key,
! 388: sizeof(sk->k.MD5_key));
! 389: #endif
! 390: sk->next = key_hash[KEYHASH(keyno)];
! 391: key_hash[KEYHASH(keyno)] = sk;
! 392: #ifdef DEBUG
! 393: if (debug > 1) {
! 394: char hex[] = "0123456789abcdef";
! 395: int j;
! 396:
! 397: printf("auth_setkey: key %d type %d len %d ", sk->keyid,
! 398: sk->type, sk->keylen);
! 399: for (j = 0; j < sk->keylen; j++)
! 400: printf("%c%c", hex[key[j] >> 4],
! 401: hex[key[j] & 0xf]);
! 402: printf("\n");
! 403: }
! 404: #endif
! 405: authnumkeys++;
! 406: }
! 407:
! 408:
! 409: /*
! 410: * auth_delkeys - delete all known keys, in preparation for rereading
! 411: * the keys file (presumably)
! 412: */
! 413: void
! 414: auth_delkeys(void)
! 415: {
! 416: struct savekey *sk;
! 417: struct savekey **skp;
! 418: int i;
! 419:
! 420: for (i = 0; i < HASHSIZE; i++) {
! 421: skp = &(key_hash[i]);
! 422: sk = key_hash[i];
! 423: /*
! 424: * Leave autokey keys alone.
! 425: */
! 426: while (sk != 0 && sk->keyid <= NTP_MAXKEY) {
! 427: /*
! 428: * Don't lose info as to which keys are trusted.
! 429: */
! 430: if (sk->flags & KEY_TRUSTED) {
! 431: skp = &(sk->next);
! 432: memset(&sk->k, 0, sizeof(sk->k));
! 433: sk->lifetime = 0;
! 434: sk->keylen = 0;
! 435: sk = sk->next;
! 436: } else {
! 437: *skp = sk->next;
! 438: authnumkeys--;
! 439: sk->next = authfreekeys;
! 440: authfreekeys = sk;
! 441: authnumfreekeys++;
! 442: sk = *skp;
! 443: }
! 444: }
! 445: }
! 446: }
! 447:
! 448: /*
! 449: * auth_agekeys - delete keys whose lifetimes have expired
! 450: */
! 451: void
! 452: auth_agekeys(void)
! 453: {
! 454: struct savekey *sk;
! 455: struct savekey *skp;
! 456: int i;
! 457:
! 458: for (i = 0; i < HASHSIZE; i++) {
! 459: sk = skp = key_hash[i];
! 460: while (sk != 0) {
! 461: skp = sk->next;
! 462: if (sk->lifetime > 0 && current_time >
! 463: sk->lifetime) {
! 464: authtrust(sk->keyid, 0);
! 465: authkeyexpired++;
! 466: }
! 467: sk = skp;
! 468: }
! 469: }
! 470: #ifdef DEBUG
! 471: if (debug)
! 472: printf("auth_agekeys: at %lu keys %lu expired %lu\n",
! 473: current_time, authnumkeys, authkeyexpired);
! 474: #endif
! 475: }
! 476:
! 477: /*
! 478: * authencrypt - generate message authenticator
! 479: *
! 480: * Returns length of authenticator field, zero if key not found.
! 481: */
! 482: int
! 483: authencrypt(
! 484: keyid_t keyno,
! 485: u_int32 *pkt,
! 486: int length
! 487: )
! 488: {
! 489:
! 490: /*
! 491: * A zero key identifier means the sender has not verified
! 492: * the last message was correctly authenticated. The MAC
! 493: * consists of a single word with value zero.
! 494: */
! 495: authencryptions++;
! 496: pkt[length / 4] = htonl(keyno);
! 497: if (keyno == 0) {
! 498: return (4);
! 499: }
! 500: if (!authhavekey(keyno))
! 501: return (0);
! 502:
! 503: return (MD5authencrypt(cache_type, cache_key, pkt, length));
! 504: }
! 505:
! 506: /*
! 507: * authdecrypt - verify message authenticator
! 508: *
! 509: * Returns one if authenticator valid, zero if invalid or key not found.
! 510: */
! 511: int
! 512: authdecrypt(
! 513: keyid_t keyno,
! 514: u_int32 *pkt,
! 515: int length,
! 516: int size
! 517: )
! 518: {
! 519:
! 520: /*
! 521: * A zero key identifier means the sender has not verified
! 522: * the last message was correctly authenticated. Nevertheless,
! 523: * the authenticator itself is considered valid.
! 524: */
! 525: authdecryptions++;
! 526: if (keyno == 0)
! 527: return (0);
! 528:
! 529: if (!authhavekey(keyno) || size < 4)
! 530: return (0);
! 531:
! 532: return (MD5authdecrypt(cache_type, cache_key, pkt, length,
! 533: size));
! 534: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>