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