authkeys.c revision 293650
154359Sroberto/* 254359Sroberto * authkeys.c - routines to manage the storage of authentication keys 354359Sroberto */ 454359Sroberto#ifdef HAVE_CONFIG_H 554359Sroberto# include <config.h> 654359Sroberto#endif 754359Sroberto 8285612Sdelphij#include <math.h> 954359Sroberto#include <stdio.h> 1054359Sroberto 11285612Sdelphij#include "ntp.h" 1254359Sroberto#include "ntp_fp.h" 1354359Sroberto#include "ntpd.h" 14285612Sdelphij#include "ntp_lists.h" 1554359Sroberto#include "ntp_string.h" 1654359Sroberto#include "ntp_malloc.h" 1754359Sroberto#include "ntp_stdlib.h" 1854359Sroberto 1954359Sroberto/* 2054359Sroberto * Structure to store keys in in the hash table. 2154359Sroberto */ 22285612Sdelphijtypedef struct savekey symkey; 23285612Sdelphij 2454359Srobertostruct savekey { 25285612Sdelphij symkey * hlink; /* next in hash bucket */ 26285612Sdelphij DECL_DLIST_LINK(symkey, llink); /* for overall & free lists */ 27285612Sdelphij u_char * secret; /* shared secret */ 28285612Sdelphij u_long lifetime; /* remaining lifetime */ 29285612Sdelphij keyid_t keyid; /* key identifier */ 30285612Sdelphij u_short type; /* OpenSSL digest NID */ 31285612Sdelphij u_short secretsize; /* secret octets */ 32285612Sdelphij u_short flags; /* KEY_ flags that wave */ 3354359Sroberto}; 3454359Sroberto 35285612Sdelphij/* define the payload region of symkey beyond the list pointers */ 36285612Sdelphij#define symkey_payload secret 37285612Sdelphij 3854359Sroberto#define KEY_TRUSTED 0x001 /* this key is trusted */ 3954359Sroberto 40285612Sdelphij#ifdef DEBUG 41285612Sdelphijtypedef struct symkey_alloc_tag symkey_alloc; 42285612Sdelphij 43285612Sdelphijstruct symkey_alloc_tag { 44285612Sdelphij symkey_alloc * link; 45285612Sdelphij void * mem; /* enable free() atexit */ 46285612Sdelphij}; 47285612Sdelphij 48285612Sdelphijsymkey_alloc * authallocs; 49285612Sdelphij#endif /* DEBUG */ 50285612Sdelphij 51285612Sdelphijstatic inline u_short auth_log2(double x); 52285612Sdelphijstatic void auth_resize_hashtable(void); 53285612Sdelphijstatic void allocsymkey(symkey **, keyid_t, u_short, 54285612Sdelphij u_short, u_long, u_short, u_char *); 55285612Sdelphijstatic void freesymkey(symkey *, symkey **); 56285612Sdelphij#ifdef DEBUG 57285612Sdelphijstatic void free_auth_mem(void); 58285612Sdelphij#endif 59285612Sdelphij 60285612Sdelphijsymkey key_listhead; /* list of all in-use keys */; 6154359Sroberto/* 6254359Sroberto * The hash table. This is indexed by the low order bits of the 6354359Sroberto * keyid. We make this fairly big for potentially busy servers. 6454359Sroberto */ 65285612Sdelphij#define DEF_AUTHHASHSIZE 64 66293650Sglebius/*#define HASHMASK ((HASHSIZE)-1)*/ 67285612Sdelphij#define KEYHASH(keyid) ((keyid) & authhashmask) 6854359Sroberto 69285612Sdelphijint authhashdisabled; 70285612Sdelphiju_short authhashbuckets = DEF_AUTHHASHSIZE; 71285612Sdelphiju_short authhashmask = DEF_AUTHHASHSIZE - 1; 72285612Sdelphijsymkey **key_hash; 7354359Sroberto 7454359Srobertou_long authkeynotfound; /* keys not found */ 7554359Srobertou_long authkeylookups; /* calls to lookup keys */ 7654359Srobertou_long authnumkeys; /* number of active keys */ 7754359Srobertou_long authkeyexpired; /* key lifetime expirations */ 7854359Srobertou_long authkeyuncached; /* cache misses */ 7954359Srobertou_long authnokey; /* calls to encrypt with no key */ 8054359Srobertou_long authencryptions; /* calls to encrypt */ 8154359Srobertou_long authdecryptions; /* calls to decrypt */ 8254359Sroberto 8354359Sroberto/* 84285612Sdelphij * Storage for free symkey structures. We malloc() such things but 8554359Sroberto * never free them. 8654359Sroberto */ 87285612Sdelphijsymkey *authfreekeys; 8854359Srobertoint authnumfreekeys; 8954359Sroberto 90285612Sdelphij#define MEMINC 16 /* number of new free ones to get */ 9154359Sroberto 9254359Sroberto/* 9354359Sroberto * The key cache. We cache the last key we looked at here. 9454359Sroberto */ 9582498Srobertokeyid_t cache_keyid; /* key identifier */ 96285612Sdelphiju_char *cache_secret; /* secret */ 97285612Sdelphiju_short cache_secretsize; /* secret length */ 98285612Sdelphijint cache_type; /* OpenSSL digest NID */ 9954359Srobertou_short cache_flags; /* flags that wave */ 10054359Sroberto 10154359Sroberto 10254359Sroberto/* 10354359Sroberto * init_auth - initialize internal data 10454359Sroberto */ 10554359Srobertovoid 10654359Srobertoinit_auth(void) 10754359Sroberto{ 108285612Sdelphij size_t newalloc; 109285612Sdelphij 11054359Sroberto /* 11154359Sroberto * Initialize hash table and free list 11254359Sroberto */ 113285612Sdelphij newalloc = authhashbuckets * sizeof(key_hash[0]); 114285612Sdelphij 115285612Sdelphij key_hash = erealloc(key_hash, newalloc); 116285612Sdelphij memset(key_hash, '\0', newalloc); 117285612Sdelphij 118285612Sdelphij INIT_DLIST(key_listhead, llink); 119285612Sdelphij 120285612Sdelphij#ifdef DEBUG 121285612Sdelphij atexit(&free_auth_mem); 122285612Sdelphij#endif 12354359Sroberto} 12454359Sroberto 12554359Sroberto 12654359Sroberto/* 127285612Sdelphij * free_auth_mem - assist in leak detection by freeing all dynamic 128285612Sdelphij * allocations from this module. 129285612Sdelphij */ 130285612Sdelphij#ifdef DEBUG 131285612Sdelphijstatic void 132285612Sdelphijfree_auth_mem(void) 133285612Sdelphij{ 134285612Sdelphij symkey * sk; 135285612Sdelphij symkey_alloc * alloc; 136285612Sdelphij symkey_alloc * next_alloc; 137285612Sdelphij 138285612Sdelphij while (NULL != (sk = HEAD_DLIST(key_listhead, llink))) { 139285612Sdelphij freesymkey(sk, &key_hash[KEYHASH(sk->keyid)]); 140285612Sdelphij } 141285612Sdelphij free(key_hash); 142285612Sdelphij key_hash = NULL; 143285612Sdelphij cache_keyid = 0; 144285612Sdelphij cache_flags = 0; 145285612Sdelphij for (alloc = authallocs; alloc != NULL; alloc = next_alloc) { 146285612Sdelphij next_alloc = alloc->link; 147285612Sdelphij free(alloc->mem); 148285612Sdelphij } 149285612Sdelphij authfreekeys = NULL; 150285612Sdelphij authnumfreekeys = 0; 151285612Sdelphij} 152285612Sdelphij#endif /* DEBUG */ 153285612Sdelphij 154285612Sdelphij 155285612Sdelphij/* 156285612Sdelphij * auth_moremem - get some more free key structures 157285612Sdelphij */ 158285612Sdelphijvoid 159285612Sdelphijauth_moremem( 160285612Sdelphij int keycount 161285612Sdelphij ) 162285612Sdelphij{ 163285612Sdelphij symkey * sk; 164285612Sdelphij int i; 165285612Sdelphij#ifdef DEBUG 166285612Sdelphij void * base; 167285612Sdelphij symkey_alloc * allocrec; 168285612Sdelphij# define MOREMEM_EXTRA_ALLOC (sizeof(*allocrec)) 169285612Sdelphij#else 170285612Sdelphij# define MOREMEM_EXTRA_ALLOC (0) 171285612Sdelphij#endif 172285612Sdelphij 173285612Sdelphij i = (keycount > 0) 174285612Sdelphij ? keycount 175285612Sdelphij : MEMINC; 176285612Sdelphij sk = emalloc_zero(i * sizeof(*sk) + MOREMEM_EXTRA_ALLOC); 177285612Sdelphij#ifdef DEBUG 178285612Sdelphij base = sk; 179285612Sdelphij#endif 180285612Sdelphij authnumfreekeys += i; 181285612Sdelphij 182285612Sdelphij for (; i > 0; i--, sk++) { 183285612Sdelphij LINK_SLIST(authfreekeys, sk, llink.f); 184285612Sdelphij } 185285612Sdelphij 186285612Sdelphij#ifdef DEBUG 187285612Sdelphij allocrec = (void *)sk; 188285612Sdelphij allocrec->mem = base; 189285612Sdelphij LINK_SLIST(authallocs, allocrec, link); 190285612Sdelphij#endif 191285612Sdelphij} 192285612Sdelphij 193285612Sdelphij 194285612Sdelphij/* 195285612Sdelphij * auth_prealloc_symkeys 196285612Sdelphij */ 197285612Sdelphijvoid 198285612Sdelphijauth_prealloc_symkeys( 199285612Sdelphij int keycount 200285612Sdelphij ) 201285612Sdelphij{ 202285612Sdelphij int allocated; 203285612Sdelphij int additional; 204285612Sdelphij 205285612Sdelphij allocated = authnumkeys + authnumfreekeys; 206285612Sdelphij additional = keycount - allocated; 207285612Sdelphij if (additional > 0) 208285612Sdelphij auth_moremem(additional); 209285612Sdelphij auth_resize_hashtable(); 210285612Sdelphij} 211285612Sdelphij 212285612Sdelphij 213285612Sdelphijstatic inline u_short 214285612Sdelphijauth_log2(double x) 215285612Sdelphij{ 216285612Sdelphij return (u_short)(log10(x) / log10(2)); 217285612Sdelphij} 218285612Sdelphij 219285612Sdelphij 220285612Sdelphij/* 221285612Sdelphij * auth_resize_hashtable 222285612Sdelphij * 223285612Sdelphij * Size hash table to average 4 or fewer entries per bucket initially, 224285612Sdelphij * within the bounds of at least 4 and no more than 15 bits for the hash 225285612Sdelphij * table index. Populate the hash table. 226285612Sdelphij */ 227285612Sdelphijstatic void 228285612Sdelphijauth_resize_hashtable(void) 229285612Sdelphij{ 230285612Sdelphij u_long totalkeys; 231285612Sdelphij u_short hashbits; 232285612Sdelphij u_short hash; 233285612Sdelphij size_t newalloc; 234285612Sdelphij symkey * sk; 235285612Sdelphij 236285612Sdelphij totalkeys = authnumkeys + authnumfreekeys; 237285612Sdelphij hashbits = auth_log2(totalkeys / 4.0) + 1; 238285612Sdelphij hashbits = max(4, hashbits); 239285612Sdelphij hashbits = min(15, hashbits); 240285612Sdelphij 241285612Sdelphij authhashbuckets = 1 << hashbits; 242285612Sdelphij authhashmask = authhashbuckets - 1; 243285612Sdelphij newalloc = authhashbuckets * sizeof(key_hash[0]); 244285612Sdelphij 245285612Sdelphij key_hash = erealloc(key_hash, newalloc); 246285612Sdelphij memset(key_hash, '\0', newalloc); 247285612Sdelphij 248285612Sdelphij ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey) 249285612Sdelphij hash = KEYHASH(sk->keyid); 250285612Sdelphij LINK_SLIST(key_hash[hash], sk, hlink); 251285612Sdelphij ITER_DLIST_END() 252285612Sdelphij} 253285612Sdelphij 254285612Sdelphij 255285612Sdelphij/* 256285612Sdelphij * allocsymkey - common code to allocate and link in symkey 257285612Sdelphij * 258285612Sdelphij * secret must be allocated with a free-compatible allocator. It is 259285612Sdelphij * owned by the referring symkey structure, and will be free()d by 260285612Sdelphij * freesymkey(). 261285612Sdelphij */ 262285612Sdelphijstatic void 263285612Sdelphijallocsymkey( 264285612Sdelphij symkey ** bucket, 265285612Sdelphij keyid_t id, 266285612Sdelphij u_short flags, 267285612Sdelphij u_short type, 268285612Sdelphij u_long lifetime, 269285612Sdelphij u_short secretsize, 270285612Sdelphij u_char * secret 271285612Sdelphij ) 272285612Sdelphij{ 273285612Sdelphij symkey * sk; 274285612Sdelphij 275285612Sdelphij if (authnumfreekeys < 1) 276285612Sdelphij auth_moremem(-1); 277285612Sdelphij UNLINK_HEAD_SLIST(sk, authfreekeys, llink.f); 278285612Sdelphij DEBUG_ENSURE(sk != NULL); 279285612Sdelphij sk->keyid = id; 280285612Sdelphij sk->flags = flags; 281285612Sdelphij sk->type = type; 282285612Sdelphij sk->secretsize = secretsize; 283285612Sdelphij sk->secret = secret; 284285612Sdelphij sk->lifetime = lifetime; 285285612Sdelphij LINK_SLIST(*bucket, sk, hlink); 286285612Sdelphij LINK_TAIL_DLIST(key_listhead, sk, llink); 287285612Sdelphij authnumfreekeys--; 288285612Sdelphij authnumkeys++; 289285612Sdelphij} 290285612Sdelphij 291285612Sdelphij 292285612Sdelphij/* 293285612Sdelphij * freesymkey - common code to remove a symkey and recycle its entry. 294285612Sdelphij */ 295285612Sdelphijstatic void 296285612Sdelphijfreesymkey( 297285612Sdelphij symkey * sk, 298285612Sdelphij symkey ** bucket 299285612Sdelphij ) 300285612Sdelphij{ 301285612Sdelphij symkey * unlinked; 302285612Sdelphij 303285612Sdelphij if (sk->secret != NULL) { 304285612Sdelphij memset(sk->secret, '\0', sk->secretsize); 305285612Sdelphij free(sk->secret); 306285612Sdelphij } 307285612Sdelphij UNLINK_SLIST(unlinked, *bucket, sk, hlink, symkey); 308285612Sdelphij DEBUG_ENSURE(sk == unlinked); 309285612Sdelphij UNLINK_DLIST(sk, llink); 310285612Sdelphij memset((char *)sk + offsetof(symkey, symkey_payload), '\0', 311285612Sdelphij sizeof(*sk) - offsetof(symkey, symkey_payload)); 312285612Sdelphij LINK_SLIST(authfreekeys, sk, llink.f); 313285612Sdelphij authnumkeys--; 314285612Sdelphij authnumfreekeys++; 315285612Sdelphij} 316285612Sdelphij 317285612Sdelphij 318285612Sdelphij/* 31954359Sroberto * auth_findkey - find a key in the hash table 32054359Sroberto */ 32154359Srobertostruct savekey * 32254359Srobertoauth_findkey( 323285612Sdelphij keyid_t id 32454359Sroberto ) 32554359Sroberto{ 326285612Sdelphij symkey * sk; 32754359Sroberto 328285612Sdelphij for (sk = key_hash[KEYHASH(id)]; sk != NULL; sk = sk->hlink) { 329285612Sdelphij if (id == sk->keyid) { 330285612Sdelphij return sk; 331285612Sdelphij } 332285612Sdelphij } 33354359Sroberto 334285612Sdelphij return NULL; 33554359Sroberto} 33654359Sroberto 33754359Sroberto 33854359Sroberto/* 339285612Sdelphij * auth_havekey - return TRUE if the key id is zero or known 34054359Sroberto */ 34154359Srobertoint 34254359Srobertoauth_havekey( 343285612Sdelphij keyid_t id 34454359Sroberto ) 34554359Sroberto{ 346285612Sdelphij symkey * sk; 34754359Sroberto 348285612Sdelphij if (0 == id || cache_keyid == id) { 349285612Sdelphij return TRUE; 350285612Sdelphij } 35154359Sroberto 352285612Sdelphij for (sk = key_hash[KEYHASH(id)]; sk != NULL; sk = sk->hlink) { 353285612Sdelphij if (id == sk->keyid) { 354285612Sdelphij return TRUE; 355285612Sdelphij } 356285612Sdelphij } 35754359Sroberto 358285612Sdelphij return FALSE; 35954359Sroberto} 36054359Sroberto 36154359Sroberto 36254359Sroberto/* 363285612Sdelphij * authhavekey - return TRUE and cache the key, if zero or both known 364285612Sdelphij * and trusted. 36554359Sroberto */ 36654359Srobertoint 36754359Srobertoauthhavekey( 368285612Sdelphij keyid_t id 36954359Sroberto ) 37054359Sroberto{ 371285612Sdelphij symkey * sk; 37254359Sroberto 37354359Sroberto authkeylookups++; 374285612Sdelphij if (0 == id || cache_keyid == id) { 375285612Sdelphij return TRUE; 376285612Sdelphij } 37754359Sroberto 378285612Sdelphij /* 379285612Sdelphij * Seach the bin for the key. If found and the key type 380285612Sdelphij * is zero, somebody marked it trusted without specifying 381285612Sdelphij * a key or key type. In this case consider the key missing. 382285612Sdelphij */ 38354359Sroberto authkeyuncached++; 384285612Sdelphij for (sk = key_hash[KEYHASH(id)]; sk != NULL; sk = sk->hlink) { 385285612Sdelphij if (id == sk->keyid) { 386285612Sdelphij if (0 == sk->type) { 387285612Sdelphij authkeynotfound++; 388285612Sdelphij return FALSE; 389285612Sdelphij } 390285612Sdelphij break; 391285612Sdelphij } 39254359Sroberto } 393285612Sdelphij 394285612Sdelphij /* 395285612Sdelphij * If the key is not found, or if it is found but not trusted, 396285612Sdelphij * the key is not considered found. 397285612Sdelphij */ 398285612Sdelphij if (NULL == sk) { 39954359Sroberto authkeynotfound++; 400285612Sdelphij return FALSE; 401285612Sdelphij } 402285612Sdelphij if (!(KEY_TRUSTED & sk->flags)) { 40354359Sroberto authnokey++; 404285612Sdelphij return FALSE; 40554359Sroberto } 406285612Sdelphij 407285612Sdelphij /* 408285612Sdelphij * The key is found and trusted. Initialize the key cache. 409285612Sdelphij */ 41054359Sroberto cache_keyid = sk->keyid; 411285612Sdelphij cache_type = sk->type; 41254359Sroberto cache_flags = sk->flags; 413285612Sdelphij cache_secret = sk->secret; 414285612Sdelphij cache_secretsize = sk->secretsize; 41554359Sroberto 416285612Sdelphij return TRUE; 41754359Sroberto} 41854359Sroberto 41954359Sroberto 42054359Sroberto/* 42154359Sroberto * authtrust - declare a key to be trusted/untrusted 42254359Sroberto */ 42354359Srobertovoid 42454359Srobertoauthtrust( 425285612Sdelphij keyid_t id, 426285612Sdelphij u_long trust 42754359Sroberto ) 42854359Sroberto{ 429285612Sdelphij symkey ** bucket; 430285612Sdelphij symkey * sk; 431285612Sdelphij u_long lifetime; 43254359Sroberto 433285612Sdelphij /* 434285612Sdelphij * Search bin for key; if it does not exist and is untrusted, 435285612Sdelphij * forget it. 436285612Sdelphij */ 437285612Sdelphij bucket = &key_hash[KEYHASH(id)]; 438285612Sdelphij for (sk = *bucket; sk != NULL; sk = sk->hlink) { 439285612Sdelphij if (id == sk->keyid) 440285612Sdelphij break; 44154359Sroberto } 442285612Sdelphij if (!trust && NULL == sk) 443285612Sdelphij return; 44454359Sroberto 445285612Sdelphij /* 446285612Sdelphij * There are two conditions remaining. Either it does not 447285612Sdelphij * exist and is to be trusted or it does exist and is or is 448285612Sdelphij * not to be trusted. 449285612Sdelphij */ 450285612Sdelphij if (sk != NULL) { 451285612Sdelphij if (cache_keyid == id) { 45254359Sroberto cache_flags = 0; 45354359Sroberto cache_keyid = 0; 45454359Sroberto } 45554359Sroberto 456285612Sdelphij /* 457285612Sdelphij * Key exists. If it is to be trusted, say so and 458285612Sdelphij * update its lifetime. 459285612Sdelphij */ 46054359Sroberto if (trust > 0) { 46154359Sroberto sk->flags |= KEY_TRUSTED; 46254359Sroberto if (trust > 1) 46354359Sroberto sk->lifetime = current_time + trust; 46454359Sroberto else 46554359Sroberto sk->lifetime = 0; 46654359Sroberto return; 46754359Sroberto } 46854359Sroberto 469285612Sdelphij /* No longer trusted, return it to the free list. */ 470285612Sdelphij freesymkey(sk, bucket); 47154359Sroberto return; 47254359Sroberto } 47354359Sroberto 474285612Sdelphij /* 475285612Sdelphij * keyid is not present, but the is to be trusted. We allocate 476285612Sdelphij * a new key, but do not specify a key type or secret. 477285612Sdelphij */ 478285612Sdelphij if (trust > 1) { 479285612Sdelphij lifetime = current_time + trust; 480285612Sdelphij } else { 481285612Sdelphij lifetime = 0; 482285612Sdelphij } 483285612Sdelphij allocsymkey(bucket, id, KEY_TRUSTED, 0, lifetime, 0, NULL); 48454359Sroberto} 48554359Sroberto 48654359Sroberto 48754359Sroberto/* 48854359Sroberto * authistrusted - determine whether a key is trusted 48954359Sroberto */ 49054359Srobertoint 49154359Srobertoauthistrusted( 492285612Sdelphij keyid_t keyno 49354359Sroberto ) 49454359Sroberto{ 495285612Sdelphij symkey * sk; 496285612Sdelphij symkey ** bucket; 49754359Sroberto 49854359Sroberto if (keyno == cache_keyid) 499285612Sdelphij return !!(KEY_TRUSTED & cache_flags); 50054359Sroberto 50154359Sroberto authkeyuncached++; 502285612Sdelphij bucket = &key_hash[KEYHASH(keyno)]; 503285612Sdelphij for (sk = *bucket; sk != NULL; sk = sk->hlink) { 50454359Sroberto if (keyno == sk->keyid) 505285612Sdelphij break; 50654359Sroberto } 507285612Sdelphij if (NULL == sk || !(KEY_TRUSTED & sk->flags)) { 50854359Sroberto authkeynotfound++; 509285612Sdelphij return FALSE; 51054359Sroberto } 511285612Sdelphij return TRUE; 51254359Sroberto} 51354359Sroberto 514293650Sglebius/* Note: There are two locations below where 'strncpy()' is used. While 515293650Sglebius * this function is a hazard by itself, it's essential that it is used 516293650Sglebius * here. Bug 1243 involved that the secret was filled with NUL bytes 517293650Sglebius * after the first NUL encountered, and 'strlcpy()' simply does NOT have 518293650Sglebius * this behaviour. So disabling the fix and reverting to the buggy 519293650Sglebius * behaviour due to compatibility issues MUST also fill with NUL and 520293650Sglebius * this needs 'strncpy'. Also, the secret is managed as a byte blob of a 521293650Sglebius * given size, and eventually truncating it and replacing the last byte 522293650Sglebius * with a NUL would be a bug. 523293650Sglebius * perlinger@ntp.org 2015-10-10 524293650Sglebius */ 52554359Srobertovoid 52654359SrobertoMD5auth_setkey( 52782498Sroberto keyid_t keyno, 528285612Sdelphij int keytype, 52954359Sroberto const u_char *key, 530285612Sdelphij size_t len 53154359Sroberto ) 53254359Sroberto{ 533285612Sdelphij symkey * sk; 534285612Sdelphij symkey ** bucket; 535285612Sdelphij u_char * secret; 536285612Sdelphij size_t secretsize; 53754359Sroberto 538285612Sdelphij DEBUG_ENSURE(keytype <= USHRT_MAX); 539285612Sdelphij DEBUG_ENSURE(len < 4 * 1024); 54054359Sroberto /* 54154359Sroberto * See if we already have the key. If so just stick in the 54254359Sroberto * new value. 54354359Sroberto */ 544285612Sdelphij bucket = &key_hash[KEYHASH(keyno)]; 545285612Sdelphij for (sk = *bucket; sk != NULL; sk = sk->hlink) { 54654359Sroberto if (keyno == sk->keyid) { 547289997Sglebius /* TALOS-CAN-0054: make sure we have a new buffer! */ 548289997Sglebius if (NULL != sk->secret) { 549289997Sglebius memset(sk->secret, 0, sk->secretsize); 550289997Sglebius free(sk->secret); 551289997Sglebius } 552289997Sglebius sk->secret = emalloc(len); 553285612Sdelphij sk->type = (u_short)keytype; 554285612Sdelphij secretsize = len; 555285612Sdelphij sk->secretsize = (u_short)secretsize; 556285612Sdelphij#ifndef DISABLE_BUG1243_FIX 557285612Sdelphij memcpy(sk->secret, key, secretsize); 558285612Sdelphij#else 559293650Sglebius /* >MUST< use 'strncpy()' here! See above! */ 560293650Sglebius strncpy((char *)sk->secret, (const char *)key, 561285612Sdelphij secretsize); 562285612Sdelphij#endif 56354359Sroberto if (cache_keyid == keyno) { 56454359Sroberto cache_flags = 0; 56554359Sroberto cache_keyid = 0; 56654359Sroberto } 56754359Sroberto return; 56854359Sroberto } 56954359Sroberto } 57054359Sroberto 57154359Sroberto /* 57254359Sroberto * Need to allocate new structure. Do it. 57354359Sroberto */ 574285612Sdelphij secretsize = len; 575285612Sdelphij secret = emalloc(secretsize); 576285612Sdelphij#ifndef DISABLE_BUG1243_FIX 577285612Sdelphij memcpy(secret, key, secretsize); 578285612Sdelphij#else 579293650Sglebius /* >MUST< use 'strncpy()' here! See above! */ 580293650Sglebius strncpy((char *)secret, (const char *)key, secretsize); 581285612Sdelphij#endif 582285612Sdelphij allocsymkey(bucket, keyno, 0, (u_short)keytype, 0, 583285612Sdelphij (u_short)secretsize, secret); 584285612Sdelphij#ifdef DEBUG 585285612Sdelphij if (debug >= 4) { 586285612Sdelphij size_t j; 58754359Sroberto 588285612Sdelphij printf("auth_setkey: key %d type %d len %d ", (int)keyno, 589285612Sdelphij keytype, (int)secretsize); 590285612Sdelphij for (j = 0; j < secretsize; j++) 591285612Sdelphij printf("%02x", secret[j]); 592285612Sdelphij printf("\n"); 593285612Sdelphij } 594285612Sdelphij#endif 595285612Sdelphij} 59654359Sroberto 59754359Sroberto 59854359Sroberto/* 599285612Sdelphij * auth_delkeys - delete non-autokey untrusted keys, and clear all info 600285612Sdelphij * except the trusted bit of non-autokey trusted keys, in 601285612Sdelphij * preparation for rereading the keys file. 60254359Sroberto */ 60354359Srobertovoid 60454359Srobertoauth_delkeys(void) 60554359Sroberto{ 606285612Sdelphij symkey * sk; 60754359Sroberto 608285612Sdelphij ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey) 609285612Sdelphij if (sk->keyid > NTP_MAXKEY) { /* autokey */ 610285612Sdelphij continue; 611285612Sdelphij } 612285612Sdelphij 61354359Sroberto /* 614289997Sglebius * Don't lose info as to which keys are trusted. Make 615289997Sglebius * sure there are no dangling pointers! 61654359Sroberto */ 617285612Sdelphij if (KEY_TRUSTED & sk->flags) { 618285612Sdelphij if (sk->secret != NULL) { 619289997Sglebius memset(sk->secret, 0, sk->secretsize); 620285612Sdelphij free(sk->secret); 621289997Sglebius sk->secret = NULL; /* TALOS-CAN-0054 */ 62254359Sroberto } 623285612Sdelphij sk->secretsize = 0; 624285612Sdelphij sk->lifetime = 0; 625285612Sdelphij } else { 626285612Sdelphij freesymkey(sk, &key_hash[KEYHASH(sk->keyid)]); 62754359Sroberto } 628285612Sdelphij ITER_DLIST_END() 62954359Sroberto} 63054359Sroberto 631285612Sdelphij 63254359Sroberto/* 63354359Sroberto * auth_agekeys - delete keys whose lifetimes have expired 63454359Sroberto */ 63554359Srobertovoid 63654359Srobertoauth_agekeys(void) 63754359Sroberto{ 638285612Sdelphij symkey * sk; 63954359Sroberto 640285612Sdelphij ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey) 641285612Sdelphij if (sk->lifetime > 0 && current_time > sk->lifetime) { 642285612Sdelphij freesymkey(sk, &key_hash[KEYHASH(sk->keyid)]); 643285612Sdelphij authkeyexpired++; 64454359Sroberto } 645285612Sdelphij ITER_DLIST_END() 646285612Sdelphij DPRINTF(1, ("auth_agekeys: at %lu keys %lu expired %lu\n", 647285612Sdelphij current_time, authnumkeys, authkeyexpired)); 64854359Sroberto} 64954359Sroberto 650285612Sdelphij 65154359Sroberto/* 65254359Sroberto * authencrypt - generate message authenticator 65354359Sroberto * 65454359Sroberto * Returns length of authenticator field, zero if key not found. 65554359Sroberto */ 656293650Sglebiussize_t 65754359Srobertoauthencrypt( 658285612Sdelphij keyid_t keyno, 659285612Sdelphij u_int32 * pkt, 660293650Sglebius size_t length 66154359Sroberto ) 662293650Sglebius{ 66354359Sroberto /* 66454359Sroberto * A zero key identifier means the sender has not verified 66554359Sroberto * the last message was correctly authenticated. The MAC 66654359Sroberto * consists of a single word with value zero. 66754359Sroberto */ 66854359Sroberto authencryptions++; 66982498Sroberto pkt[length / 4] = htonl(keyno); 670285612Sdelphij if (0 == keyno) { 671285612Sdelphij return 4; 67254359Sroberto } 673285612Sdelphij if (!authhavekey(keyno)) { 674285612Sdelphij return 0; 675285612Sdelphij } 67654359Sroberto 677285612Sdelphij return MD5authencrypt(cache_type, cache_secret, pkt, length); 67854359Sroberto} 67954359Sroberto 680285612Sdelphij 68154359Sroberto/* 68254359Sroberto * authdecrypt - verify message authenticator 68354359Sroberto * 684285612Sdelphij * Returns TRUE if authenticator valid, FALSE if invalid or not found. 68554359Sroberto */ 68654359Srobertoint 68754359Srobertoauthdecrypt( 688285612Sdelphij keyid_t keyno, 689285612Sdelphij u_int32 * pkt, 690293650Sglebius size_t length, 691293650Sglebius size_t size 69254359Sroberto ) 69354359Sroberto{ 69454359Sroberto /* 69554359Sroberto * A zero key identifier means the sender has not verified 696285612Sdelphij * the last message was correctly authenticated. For our 697285612Sdelphij * purpose this is an invalid authenticator. 69854359Sroberto */ 69954359Sroberto authdecryptions++; 700285612Sdelphij if (0 == keyno || !authhavekey(keyno) || size < 4) { 701285612Sdelphij return FALSE; 702285612Sdelphij } 70354359Sroberto 704285612Sdelphij return MD5authdecrypt(cache_type, cache_secret, pkt, length, 705285612Sdelphij size); 70654359Sroberto} 707