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 8290000Sglebius#include <math.h> 954359Sroberto#include <stdio.h> 1054359Sroberto 11290000Sglebius#include "ntp.h" 1254359Sroberto#include "ntp_fp.h" 1354359Sroberto#include "ntpd.h" 14290000Sglebius#include "ntp_lists.h" 1554359Sroberto#include "ntp_string.h" 1654359Sroberto#include "ntp_malloc.h" 1754359Sroberto#include "ntp_stdlib.h" 18294904Sdelphij#include "ntp_keyacc.h" 1954359Sroberto 2054359Sroberto/* 2154359Sroberto * Structure to store keys in in the hash table. 2254359Sroberto */ 23290000Sglebiustypedef struct savekey symkey; 24290000Sglebius 2554359Srobertostruct savekey { 26290000Sglebius symkey * hlink; /* next in hash bucket */ 27290000Sglebius DECL_DLIST_LINK(symkey, llink); /* for overall & free lists */ 28290000Sglebius u_char * secret; /* shared secret */ 29294904Sdelphij KeyAccT * keyacclist; /* Private key access list */ 30290000Sglebius u_long lifetime; /* remaining lifetime */ 31290000Sglebius keyid_t keyid; /* key identifier */ 32290000Sglebius u_short type; /* OpenSSL digest NID */ 33298770Sdelphij size_t secretsize; /* secret octets */ 34290000Sglebius u_short flags; /* KEY_ flags that wave */ 3554359Sroberto}; 3654359Sroberto 37290000Sglebius/* define the payload region of symkey beyond the list pointers */ 38290000Sglebius#define symkey_payload secret 39290000Sglebius 4054359Sroberto#define KEY_TRUSTED 0x001 /* this key is trusted */ 4154359Sroberto 42290000Sglebius#ifdef DEBUG 43290000Sglebiustypedef struct symkey_alloc_tag symkey_alloc; 44290000Sglebius 45290000Sglebiusstruct symkey_alloc_tag { 46290000Sglebius symkey_alloc * link; 47290000Sglebius void * mem; /* enable free() atexit */ 48290000Sglebius}; 49290000Sglebius 50290000Sglebiussymkey_alloc * authallocs; 51290000Sglebius#endif /* DEBUG */ 52290000Sglebius 53294904Sdelphijstatic u_short auth_log2(size_t); 54298770Sdelphijstatic void auth_resize_hashtable(void); 55298770Sdelphijstatic void allocsymkey(keyid_t, u_short, 56298770Sdelphij u_short, u_long, size_t, u_char *, KeyAccT *); 57298770Sdelphijstatic void freesymkey(symkey *); 58290000Sglebius#ifdef DEBUG 59298770Sdelphijstatic void free_auth_mem(void); 60290000Sglebius#endif 61290000Sglebius 62290000Sglebiussymkey key_listhead; /* list of all in-use keys */; 6354359Sroberto/* 6454359Sroberto * The hash table. This is indexed by the low order bits of the 6554359Sroberto * keyid. We make this fairly big for potentially busy servers. 6654359Sroberto */ 67290000Sglebius#define DEF_AUTHHASHSIZE 64 68293894Sglebius/*#define HASHMASK ((HASHSIZE)-1)*/ 69290000Sglebius#define KEYHASH(keyid) ((keyid) & authhashmask) 7054359Sroberto 71290000Sglebiusint authhashdisabled; 72290000Sglebiusu_short authhashbuckets = DEF_AUTHHASHSIZE; 73290000Sglebiusu_short authhashmask = DEF_AUTHHASHSIZE - 1; 74290000Sglebiussymkey **key_hash; 7554359Sroberto 7654359Srobertou_long authkeynotfound; /* keys not found */ 7754359Srobertou_long authkeylookups; /* calls to lookup keys */ 7854359Srobertou_long authnumkeys; /* number of active keys */ 7954359Srobertou_long authkeyexpired; /* key lifetime expirations */ 8054359Srobertou_long authkeyuncached; /* cache misses */ 8154359Srobertou_long authnokey; /* calls to encrypt with no key */ 8254359Srobertou_long authencryptions; /* calls to encrypt */ 8354359Srobertou_long authdecryptions; /* calls to decrypt */ 8454359Sroberto 8554359Sroberto/* 86290000Sglebius * Storage for free symkey structures. We malloc() such things but 8754359Sroberto * never free them. 8854359Sroberto */ 89290000Sglebiussymkey *authfreekeys; 9054359Srobertoint authnumfreekeys; 9154359Sroberto 92290000Sglebius#define MEMINC 16 /* number of new free ones to get */ 9354359Sroberto 9454359Sroberto/* 9554359Sroberto * The key cache. We cache the last key we looked at here. 96298770Sdelphij * Note: this should hold the last *trusted* key. Also the 97298770Sdelphij * cache is only loaded when the digest type / MAC algorithm 98298770Sdelphij * is valid. 9954359Sroberto */ 10082498Srobertokeyid_t cache_keyid; /* key identifier */ 101290000Sglebiusu_char *cache_secret; /* secret */ 102298770Sdelphijsize_t cache_secretsize; /* secret length */ 103290000Sglebiusint cache_type; /* OpenSSL digest NID */ 10454359Srobertou_short cache_flags; /* flags that wave */ 105294904SdelphijKeyAccT *cache_keyacclist; /* key access list */ 10654359Sroberto 107298770Sdelphij/* -------------------------------------------------------------------- 108298770Sdelphij * manage key access lists 109298770Sdelphij * -------------------------------------------------------------------- 110298770Sdelphij */ 111298770Sdelphij/* allocate and populate new access node and pushes it on the list. 112298770Sdelphij * Returns the new head. 113298770Sdelphij */ 114298770SdelphijKeyAccT* 115298770Sdelphijkeyacc_new_push( 116298770Sdelphij KeyAccT * head, 117298770Sdelphij const sockaddr_u * addr 118298770Sdelphij ) 119298770Sdelphij{ 120298770Sdelphij KeyAccT * node = emalloc(sizeof(KeyAccT)); 121298770Sdelphij 122298770Sdelphij memcpy(&node->addr, addr, sizeof(sockaddr_u)); 123298770Sdelphij node->next = head; 124298770Sdelphij return node; 125298770Sdelphij} 12654359Sroberto 127298770Sdelphij/* ----------------------------------------------------------------- */ 128298770Sdelphij/* pop and deallocate the first node of a list of access nodes, if 129298770Sdelphij * the list is not empty. Returns the tail of the list. 130298770Sdelphij */ 131298770SdelphijKeyAccT* 132298770Sdelphijkeyacc_pop_free( 133298770Sdelphij KeyAccT *head 134298770Sdelphij ) 135298770Sdelphij{ 136298770Sdelphij KeyAccT * next = NULL; 137298770Sdelphij if (head) { 138298770Sdelphij next = head->next; 139298770Sdelphij free(head); 140298770Sdelphij } 141298770Sdelphij return next; 142298770Sdelphij} 143298770Sdelphij 144298770Sdelphij/* ----------------------------------------------------------------- */ 145298770Sdelphij/* deallocate the list; returns an empty list. */ 146298770SdelphijKeyAccT* 147298770Sdelphijkeyacc_all_free( 148298770Sdelphij KeyAccT * head 149298770Sdelphij ) 150298770Sdelphij{ 151298770Sdelphij while (head) 152298770Sdelphij head = keyacc_pop_free(head); 153298770Sdelphij return head; 154298770Sdelphij} 155298770Sdelphij 156298770Sdelphij/* ----------------------------------------------------------------- */ 157298770Sdelphij/* scan a list to see if it contains a given address. Return the 158298770Sdelphij * default result value in case of an empty list. 159298770Sdelphij */ 160298770Sdelphijint /*BOOL*/ 161298770Sdelphijkeyacc_contains( 162298770Sdelphij const KeyAccT *head, 163298770Sdelphij const sockaddr_u *addr, 164298770Sdelphij int defv) 165298770Sdelphij{ 166298770Sdelphij if (head) { 167298770Sdelphij do { 168298770Sdelphij if (SOCK_EQ(&head->addr, addr)) 169298770Sdelphij return TRUE; 170298770Sdelphij } while (NULL != (head = head->next)); 171298770Sdelphij return FALSE; 172298770Sdelphij } else { 173298770Sdelphij return !!defv; 174298770Sdelphij } 175298770Sdelphij} 176298770Sdelphij 177298770Sdelphij 17854359Sroberto/* 17954359Sroberto * init_auth - initialize internal data 18054359Sroberto */ 18154359Srobertovoid 18254359Srobertoinit_auth(void) 18354359Sroberto{ 184290000Sglebius size_t newalloc; 185290000Sglebius 18654359Sroberto /* 18754359Sroberto * Initialize hash table and free list 18854359Sroberto */ 189290000Sglebius newalloc = authhashbuckets * sizeof(key_hash[0]); 190290000Sglebius 191290000Sglebius key_hash = erealloc(key_hash, newalloc); 192290000Sglebius memset(key_hash, '\0', newalloc); 193290000Sglebius 194290000Sglebius INIT_DLIST(key_listhead, llink); 195290000Sglebius 196290000Sglebius#ifdef DEBUG 197290000Sglebius atexit(&free_auth_mem); 198290000Sglebius#endif 19954359Sroberto} 20054359Sroberto 20154359Sroberto 20254359Sroberto/* 203290000Sglebius * free_auth_mem - assist in leak detection by freeing all dynamic 204290000Sglebius * allocations from this module. 205290000Sglebius */ 206290000Sglebius#ifdef DEBUG 207290000Sglebiusstatic void 208290000Sglebiusfree_auth_mem(void) 209290000Sglebius{ 210290000Sglebius symkey * sk; 211290000Sglebius symkey_alloc * alloc; 212290000Sglebius symkey_alloc * next_alloc; 213290000Sglebius 214290000Sglebius while (NULL != (sk = HEAD_DLIST(key_listhead, llink))) { 215298770Sdelphij freesymkey(sk); 216290000Sglebius } 217290000Sglebius free(key_hash); 218290000Sglebius key_hash = NULL; 219290000Sglebius cache_keyid = 0; 220290000Sglebius cache_flags = 0; 221294904Sdelphij cache_keyacclist = NULL; 222290000Sglebius for (alloc = authallocs; alloc != NULL; alloc = next_alloc) { 223290000Sglebius next_alloc = alloc->link; 224290000Sglebius free(alloc->mem); 225290000Sglebius } 226290000Sglebius authfreekeys = NULL; 227290000Sglebius authnumfreekeys = 0; 228290000Sglebius} 229290000Sglebius#endif /* DEBUG */ 230290000Sglebius 231290000Sglebius 232290000Sglebius/* 233290000Sglebius * auth_moremem - get some more free key structures 234290000Sglebius */ 235290000Sglebiusvoid 236290000Sglebiusauth_moremem( 237290000Sglebius int keycount 238290000Sglebius ) 239290000Sglebius{ 240290000Sglebius symkey * sk; 241290000Sglebius int i; 242290000Sglebius#ifdef DEBUG 243290000Sglebius void * base; 244290000Sglebius symkey_alloc * allocrec; 245290000Sglebius# define MOREMEM_EXTRA_ALLOC (sizeof(*allocrec)) 246290000Sglebius#else 247290000Sglebius# define MOREMEM_EXTRA_ALLOC (0) 248290000Sglebius#endif 249290000Sglebius 250290000Sglebius i = (keycount > 0) 251290000Sglebius ? keycount 252290000Sglebius : MEMINC; 253290000Sglebius sk = emalloc_zero(i * sizeof(*sk) + MOREMEM_EXTRA_ALLOC); 254290000Sglebius#ifdef DEBUG 255290000Sglebius base = sk; 256290000Sglebius#endif 257290000Sglebius authnumfreekeys += i; 258290000Sglebius 259290000Sglebius for (; i > 0; i--, sk++) { 260290000Sglebius LINK_SLIST(authfreekeys, sk, llink.f); 261290000Sglebius } 262290000Sglebius 263290000Sglebius#ifdef DEBUG 264290000Sglebius allocrec = (void *)sk; 265290000Sglebius allocrec->mem = base; 266290000Sglebius LINK_SLIST(authallocs, allocrec, link); 267290000Sglebius#endif 268290000Sglebius} 269290000Sglebius 270290000Sglebius 271290000Sglebius/* 272290000Sglebius * auth_prealloc_symkeys 273290000Sglebius */ 274290000Sglebiusvoid 275290000Sglebiusauth_prealloc_symkeys( 276290000Sglebius int keycount 277290000Sglebius ) 278290000Sglebius{ 279290000Sglebius int allocated; 280290000Sglebius int additional; 281290000Sglebius 282290000Sglebius allocated = authnumkeys + authnumfreekeys; 283290000Sglebius additional = keycount - allocated; 284290000Sglebius if (additional > 0) 285290000Sglebius auth_moremem(additional); 286290000Sglebius auth_resize_hashtable(); 287290000Sglebius} 288290000Sglebius 289290000Sglebius 290294904Sdelphijstatic u_short 291294904Sdelphijauth_log2(size_t x) 292290000Sglebius{ 293294904Sdelphij /* 294294904Sdelphij ** bithack to calculate floor(log2(x)) 295294904Sdelphij ** 296294904Sdelphij ** This assumes 297294904Sdelphij ** - (sizeof(size_t) is a power of two 298294904Sdelphij ** - CHAR_BITS is a power of two 299294904Sdelphij ** - returning zero for arguments <= 0 is OK. 300294904Sdelphij ** 301294904Sdelphij ** Does only shifts, masks and sums in integer arithmetic in 302294904Sdelphij ** log2(CHAR_BIT*sizeof(size_t)) steps. (that is, 5/6 steps for 303294904Sdelphij ** 32bit/64bit size_t) 304294904Sdelphij */ 305294904Sdelphij int s; 306294904Sdelphij int r = 0; 307294904Sdelphij size_t m = ~(size_t)0; 308294904Sdelphij 309294904Sdelphij for (s = sizeof(size_t) / 2 * CHAR_BIT; s != 0; s >>= 1) { 310294904Sdelphij m <<= s; 311294904Sdelphij if (x & m) 312294904Sdelphij r += s; 313294904Sdelphij else 314294904Sdelphij x <<= s; 315294904Sdelphij } 316294904Sdelphij return (u_short)r; 317290000Sglebius} 318290000Sglebius 319298770Sdelphijstatic void 320298770Sdelphijauthcache_flush_id( 321298770Sdelphij keyid_t id 322298770Sdelphij ) 323298770Sdelphij{ 324298770Sdelphij if (cache_keyid == id) { 325298770Sdelphij cache_keyid = 0; 326298770Sdelphij cache_type = 0; 327298770Sdelphij cache_flags = 0; 328298770Sdelphij cache_secret = NULL; 329298770Sdelphij cache_secretsize = 0; 330298770Sdelphij cache_keyacclist = NULL; 331298770Sdelphij } 332298770Sdelphij} 333290000Sglebius 334298770Sdelphij 335290000Sglebius/* 336290000Sglebius * auth_resize_hashtable 337290000Sglebius * 338290000Sglebius * Size hash table to average 4 or fewer entries per bucket initially, 339290000Sglebius * within the bounds of at least 4 and no more than 15 bits for the hash 340290000Sglebius * table index. Populate the hash table. 341290000Sglebius */ 342290000Sglebiusstatic void 343290000Sglebiusauth_resize_hashtable(void) 344290000Sglebius{ 345290000Sglebius u_long totalkeys; 346290000Sglebius u_short hashbits; 347290000Sglebius u_short hash; 348290000Sglebius size_t newalloc; 349290000Sglebius symkey * sk; 350290000Sglebius 351290000Sglebius totalkeys = authnumkeys + authnumfreekeys; 352294904Sdelphij hashbits = auth_log2(totalkeys / 4) + 1; 353290000Sglebius hashbits = max(4, hashbits); 354290000Sglebius hashbits = min(15, hashbits); 355290000Sglebius 356290000Sglebius authhashbuckets = 1 << hashbits; 357290000Sglebius authhashmask = authhashbuckets - 1; 358290000Sglebius newalloc = authhashbuckets * sizeof(key_hash[0]); 359290000Sglebius 360290000Sglebius key_hash = erealloc(key_hash, newalloc); 361290000Sglebius memset(key_hash, '\0', newalloc); 362290000Sglebius 363290000Sglebius ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey) 364290000Sglebius hash = KEYHASH(sk->keyid); 365290000Sglebius LINK_SLIST(key_hash[hash], sk, hlink); 366290000Sglebius ITER_DLIST_END() 367290000Sglebius} 368290000Sglebius 369290000Sglebius 370290000Sglebius/* 371290000Sglebius * allocsymkey - common code to allocate and link in symkey 372290000Sglebius * 373290000Sglebius * secret must be allocated with a free-compatible allocator. It is 374290000Sglebius * owned by the referring symkey structure, and will be free()d by 375290000Sglebius * freesymkey(). 376290000Sglebius */ 377290000Sglebiusstatic void 378290000Sglebiusallocsymkey( 379290000Sglebius keyid_t id, 380290000Sglebius u_short flags, 381290000Sglebius u_short type, 382290000Sglebius u_long lifetime, 383298770Sdelphij size_t secretsize, 384294904Sdelphij u_char * secret, 385294904Sdelphij KeyAccT * ka 386290000Sglebius ) 387290000Sglebius{ 388290000Sglebius symkey * sk; 389298770Sdelphij symkey ** bucket; 390290000Sglebius 391298770Sdelphij bucket = &key_hash[KEYHASH(id)]; 392298770Sdelphij 393298770Sdelphij 394290000Sglebius if (authnumfreekeys < 1) 395290000Sglebius auth_moremem(-1); 396290000Sglebius UNLINK_HEAD_SLIST(sk, authfreekeys, llink.f); 397290000Sglebius DEBUG_ENSURE(sk != NULL); 398290000Sglebius sk->keyid = id; 399290000Sglebius sk->flags = flags; 400290000Sglebius sk->type = type; 401290000Sglebius sk->secretsize = secretsize; 402290000Sglebius sk->secret = secret; 403294904Sdelphij sk->keyacclist = ka; 404290000Sglebius sk->lifetime = lifetime; 405290000Sglebius LINK_SLIST(*bucket, sk, hlink); 406290000Sglebius LINK_TAIL_DLIST(key_listhead, sk, llink); 407290000Sglebius authnumfreekeys--; 408290000Sglebius authnumkeys++; 409290000Sglebius} 410290000Sglebius 411290000Sglebius 412290000Sglebius/* 413290000Sglebius * freesymkey - common code to remove a symkey and recycle its entry. 414290000Sglebius */ 415290000Sglebiusstatic void 416290000Sglebiusfreesymkey( 417298770Sdelphij symkey * sk 418290000Sglebius ) 419290000Sglebius{ 420298770Sdelphij symkey ** bucket; 421290000Sglebius symkey * unlinked; 422290000Sglebius 423298770Sdelphij if (NULL == sk) 424298770Sdelphij return; 425298770Sdelphij 426298770Sdelphij authcache_flush_id(sk->keyid); 427298770Sdelphij keyacc_all_free(sk->keyacclist); 428298770Sdelphij 429298770Sdelphij bucket = &key_hash[KEYHASH(sk->keyid)]; 430290000Sglebius if (sk->secret != NULL) { 431290000Sglebius memset(sk->secret, '\0', sk->secretsize); 432290000Sglebius free(sk->secret); 433290000Sglebius } 434290000Sglebius UNLINK_SLIST(unlinked, *bucket, sk, hlink, symkey); 435290000Sglebius DEBUG_ENSURE(sk == unlinked); 436290000Sglebius UNLINK_DLIST(sk, llink); 437290000Sglebius memset((char *)sk + offsetof(symkey, symkey_payload), '\0', 438290000Sglebius sizeof(*sk) - offsetof(symkey, symkey_payload)); 439290000Sglebius LINK_SLIST(authfreekeys, sk, llink.f); 440290000Sglebius authnumkeys--; 441290000Sglebius authnumfreekeys++; 442290000Sglebius} 443290000Sglebius 444290000Sglebius 445290000Sglebius/* 44654359Sroberto * auth_findkey - find a key in the hash table 44754359Sroberto */ 44854359Srobertostruct savekey * 44954359Srobertoauth_findkey( 450290000Sglebius keyid_t id 45154359Sroberto ) 45254359Sroberto{ 453290000Sglebius symkey * sk; 45454359Sroberto 455298770Sdelphij for (sk = key_hash[KEYHASH(id)]; sk != NULL; sk = sk->hlink) 456298770Sdelphij if (id == sk->keyid) 457290000Sglebius return sk; 458290000Sglebius return NULL; 45954359Sroberto} 46054359Sroberto 46154359Sroberto 46254359Sroberto/* 463298770Sdelphij * auth_havekey - return TRUE if the key id is zero or known. The 464298770Sdelphij * key needs not to be trusted. 46554359Sroberto */ 46654359Srobertoint 46754359Srobertoauth_havekey( 468290000Sglebius keyid_t id 46954359Sroberto ) 47054359Sroberto{ 471298770Sdelphij return 472298770Sdelphij (0 == id) || 473298770Sdelphij (cache_keyid == id) || 474298770Sdelphij (NULL != auth_findkey(id)); 47554359Sroberto} 47654359Sroberto 47754359Sroberto 47854359Sroberto/* 479290000Sglebius * authhavekey - return TRUE and cache the key, if zero or both known 480290000Sglebius * and trusted. 48154359Sroberto */ 48254359Srobertoint 48354359Srobertoauthhavekey( 484290000Sglebius keyid_t id 48554359Sroberto ) 48654359Sroberto{ 487290000Sglebius symkey * sk; 48854359Sroberto 48954359Sroberto authkeylookups++; 490298770Sdelphij if (0 == id || cache_keyid == id) 491298770Sdelphij return !!(KEY_TRUSTED & cache_flags); 49254359Sroberto 493290000Sglebius /* 494298770Sdelphij * Search the bin for the key. If not found, or found but the key 495298770Sdelphij * type is zero, somebody marked it trusted without specifying a 496298770Sdelphij * key or key type. In this case consider the key missing. 497290000Sglebius */ 49854359Sroberto authkeyuncached++; 499298770Sdelphij sk = auth_findkey(id); 500298770Sdelphij if ((sk == NULL) || (sk->type == 0)) { 501298770Sdelphij authkeynotfound++; 502298770Sdelphij return FALSE; 50354359Sroberto } 504290000Sglebius 505290000Sglebius /* 506298770Sdelphij * If the key is not trusted, the key is not considered found. 507290000Sglebius */ 508298770Sdelphij if ( ! (KEY_TRUSTED & sk->flags)) { 50954359Sroberto authnokey++; 510290000Sglebius return FALSE; 51154359Sroberto } 512290000Sglebius 513290000Sglebius /* 514290000Sglebius * The key is found and trusted. Initialize the key cache. 515290000Sglebius */ 51654359Sroberto cache_keyid = sk->keyid; 517290000Sglebius cache_type = sk->type; 51854359Sroberto cache_flags = sk->flags; 519290000Sglebius cache_secret = sk->secret; 520290000Sglebius cache_secretsize = sk->secretsize; 521294904Sdelphij cache_keyacclist = sk->keyacclist; 52254359Sroberto 523290000Sglebius return TRUE; 52454359Sroberto} 52554359Sroberto 52654359Sroberto 52754359Sroberto/* 52854359Sroberto * authtrust - declare a key to be trusted/untrusted 52954359Sroberto */ 53054359Srobertovoid 53154359Srobertoauthtrust( 532290000Sglebius keyid_t id, 533290000Sglebius u_long trust 53454359Sroberto ) 53554359Sroberto{ 536290000Sglebius symkey * sk; 537290000Sglebius u_long lifetime; 53854359Sroberto 539290000Sglebius /* 540290000Sglebius * Search bin for key; if it does not exist and is untrusted, 541290000Sglebius * forget it. 542290000Sglebius */ 543298770Sdelphij 544298770Sdelphij sk = auth_findkey(id); 545298770Sdelphij if (!trust && sk == NULL) 546290000Sglebius return; 54754359Sroberto 548290000Sglebius /* 549290000Sglebius * There are two conditions remaining. Either it does not 550290000Sglebius * exist and is to be trusted or it does exist and is or is 551290000Sglebius * not to be trusted. 552290000Sglebius */ 553290000Sglebius if (sk != NULL) { 554290000Sglebius /* 555298770Sdelphij * Key exists. If it is to be trusted, say so and update 556298770Sdelphij * its lifetime. If no longer trusted, return it to the 557298770Sdelphij * free list. Flush the cache first to be sure there are 558298770Sdelphij * no discrepancies. 559290000Sglebius */ 560298770Sdelphij authcache_flush_id(id); 56154359Sroberto if (trust > 0) { 56254359Sroberto sk->flags |= KEY_TRUSTED; 56354359Sroberto if (trust > 1) 56454359Sroberto sk->lifetime = current_time + trust; 56554359Sroberto else 56654359Sroberto sk->lifetime = 0; 567298770Sdelphij } else { 568298770Sdelphij freesymkey(sk); 56954359Sroberto } 57054359Sroberto return; 57154359Sroberto } 57254359Sroberto 573290000Sglebius /* 574290000Sglebius * keyid is not present, but the is to be trusted. We allocate 575290000Sglebius * a new key, but do not specify a key type or secret. 576290000Sglebius */ 577290000Sglebius if (trust > 1) { 578290000Sglebius lifetime = current_time + trust; 579290000Sglebius } else { 580290000Sglebius lifetime = 0; 581290000Sglebius } 582298770Sdelphij allocsymkey(id, KEY_TRUSTED, 0, lifetime, 0, NULL, NULL); 58354359Sroberto} 58454359Sroberto 58554359Sroberto 58654359Sroberto/* 58754359Sroberto * authistrusted - determine whether a key is trusted 58854359Sroberto */ 58954359Srobertoint 59054359Srobertoauthistrusted( 591298770Sdelphij keyid_t id 59254359Sroberto ) 59354359Sroberto{ 594290000Sglebius symkey * sk; 59554359Sroberto 596298770Sdelphij if (id == cache_keyid) 597290000Sglebius return !!(KEY_TRUSTED & cache_flags); 59854359Sroberto 59954359Sroberto authkeyuncached++; 600298770Sdelphij sk = auth_findkey(id); 601298770Sdelphij if (sk == NULL || !(KEY_TRUSTED & sk->flags)) { 60254359Sroberto authkeynotfound++; 603290000Sglebius return FALSE; 60454359Sroberto } 605290000Sglebius return TRUE; 60654359Sroberto} 60754359Sroberto 608294904Sdelphij 609294904Sdelphij/* 610294904Sdelphij * authistrustedip - determine if the IP is OK for the keyid 611294904Sdelphij */ 612294904Sdelphij int 613294904Sdelphij authistrustedip( 614294904Sdelphij keyid_t keyno, 615294904Sdelphij sockaddr_u * sau 616294904Sdelphij ) 617294904Sdelphij{ 618294904Sdelphij symkey * sk; 619294904Sdelphij 620298770Sdelphij /* That specific key was already used to authenticate the 621298770Sdelphij * packet. Therefore, the key *must* exist... There's a chance 622298770Sdelphij * that is not trusted, though. 623298770Sdelphij */ 624298770Sdelphij if (keyno == cache_keyid) { 625298770Sdelphij return (KEY_TRUSTED & cache_flags) && 626298770Sdelphij keyacc_contains(cache_keyacclist, sau, TRUE); 627298770Sdelphij } else { 628294904Sdelphij authkeyuncached++; 629298770Sdelphij sk = auth_findkey(keyno); 630298770Sdelphij INSIST(NULL != sk); 631298770Sdelphij return (KEY_TRUSTED & sk->flags) && 632298770Sdelphij keyacc_contains(sk->keyacclist, sau, TRUE); 633294904Sdelphij } 634294904Sdelphij} 635294904Sdelphij 636293894Sglebius/* Note: There are two locations below where 'strncpy()' is used. While 637293894Sglebius * this function is a hazard by itself, it's essential that it is used 638293894Sglebius * here. Bug 1243 involved that the secret was filled with NUL bytes 639293894Sglebius * after the first NUL encountered, and 'strlcpy()' simply does NOT have 640293894Sglebius * this behaviour. So disabling the fix and reverting to the buggy 641293894Sglebius * behaviour due to compatibility issues MUST also fill with NUL and 642293894Sglebius * this needs 'strncpy'. Also, the secret is managed as a byte blob of a 643293894Sglebius * given size, and eventually truncating it and replacing the last byte 644293894Sglebius * with a NUL would be a bug. 645293894Sglebius * perlinger@ntp.org 2015-10-10 646293894Sglebius */ 64754359Srobertovoid 64854359SrobertoMD5auth_setkey( 64982498Sroberto keyid_t keyno, 650290000Sglebius int keytype, 65154359Sroberto const u_char *key, 652298770Sdelphij size_t secretsize, 653294904Sdelphij KeyAccT *ka 65454359Sroberto ) 65554359Sroberto{ 656290000Sglebius symkey * sk; 657290000Sglebius u_char * secret; 65854359Sroberto 659290000Sglebius DEBUG_ENSURE(keytype <= USHRT_MAX); 660298770Sdelphij DEBUG_ENSURE(secretsize < 4 * 1024); 66154359Sroberto /* 66254359Sroberto * See if we already have the key. If so just stick in the 66354359Sroberto * new value. 66454359Sroberto */ 665298770Sdelphij sk = auth_findkey(keyno); 666298770Sdelphij if (sk != NULL && keyno == sk->keyid) { 667290000Sglebius /* TALOS-CAN-0054: make sure we have a new buffer! */ 668298770Sdelphij if (NULL != sk->secret) { 669298770Sdelphij memset(sk->secret, 0, sk->secretsize); 670298770Sdelphij free(sk->secret); 671298770Sdelphij } 672298770Sdelphij sk->secret = emalloc(secretsize + 1); 673298770Sdelphij sk->type = (u_short)keytype; 674298770Sdelphij sk->secretsize = secretsize; 675298770Sdelphij /* make sure access lists don't leak here! */ 676298770Sdelphij if (ka != sk->keyacclist) { 677298770Sdelphij keyacc_all_free(sk->keyacclist); 678294904Sdelphij sk->keyacclist = ka; 679298770Sdelphij } 680290000Sglebius#ifndef DISABLE_BUG1243_FIX 681298770Sdelphij memcpy(sk->secret, key, secretsize); 682290000Sglebius#else 683298770Sdelphij /* >MUST< use 'strncpy()' here! See above! */ 684298770Sdelphij strncpy((char *)sk->secret, (const char *)key, 685298770Sdelphij secretsize); 686290000Sglebius#endif 687298770Sdelphij authcache_flush_id(keyno); 688298770Sdelphij return; 68954359Sroberto } 69054359Sroberto 69154359Sroberto /* 69254359Sroberto * Need to allocate new structure. Do it. 69354359Sroberto */ 694298770Sdelphij secret = emalloc(secretsize + 1); 695290000Sglebius#ifndef DISABLE_BUG1243_FIX 696290000Sglebius memcpy(secret, key, secretsize); 697290000Sglebius#else 698293894Sglebius /* >MUST< use 'strncpy()' here! See above! */ 699293894Sglebius strncpy((char *)secret, (const char *)key, secretsize); 700290000Sglebius#endif 701298770Sdelphij allocsymkey(keyno, 0, (u_short)keytype, 0, 702298770Sdelphij secretsize, secret, ka); 703290000Sglebius#ifdef DEBUG 704290000Sglebius if (debug >= 4) { 705290000Sglebius size_t j; 70654359Sroberto 707290000Sglebius printf("auth_setkey: key %d type %d len %d ", (int)keyno, 708290000Sglebius keytype, (int)secretsize); 709298770Sdelphij for (j = 0; j < secretsize; j++) { 710290000Sglebius printf("%02x", secret[j]); 711298770Sdelphij } 712290000Sglebius printf("\n"); 713290000Sglebius } 714290000Sglebius#endif 715290000Sglebius} 71654359Sroberto 71754359Sroberto 71854359Sroberto/* 719290000Sglebius * auth_delkeys - delete non-autokey untrusted keys, and clear all info 720290000Sglebius * except the trusted bit of non-autokey trusted keys, in 721290000Sglebius * preparation for rereading the keys file. 72254359Sroberto */ 72354359Srobertovoid 72454359Srobertoauth_delkeys(void) 72554359Sroberto{ 726290000Sglebius symkey * sk; 72754359Sroberto 728290000Sglebius ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey) 729290000Sglebius if (sk->keyid > NTP_MAXKEY) { /* autokey */ 730290000Sglebius continue; 731290000Sglebius } 732290000Sglebius 73354359Sroberto /* 734290000Sglebius * Don't lose info as to which keys are trusted. Make 735290000Sglebius * sure there are no dangling pointers! 73654359Sroberto */ 737290000Sglebius if (KEY_TRUSTED & sk->flags) { 738290000Sglebius if (sk->secret != NULL) { 739290000Sglebius memset(sk->secret, 0, sk->secretsize); 740290000Sglebius free(sk->secret); 741290000Sglebius sk->secret = NULL; /* TALOS-CAN-0054 */ 74254359Sroberto } 743298770Sdelphij sk->keyacclist = keyacc_all_free(sk->keyacclist); 744290000Sglebius sk->secretsize = 0; 745290000Sglebius sk->lifetime = 0; 746290000Sglebius } else { 747298770Sdelphij freesymkey(sk); 74854359Sroberto } 749290000Sglebius ITER_DLIST_END() 75054359Sroberto} 75154359Sroberto 752290000Sglebius 75354359Sroberto/* 75454359Sroberto * auth_agekeys - delete keys whose lifetimes have expired 75554359Sroberto */ 75654359Srobertovoid 75754359Srobertoauth_agekeys(void) 75854359Sroberto{ 759290000Sglebius symkey * sk; 76054359Sroberto 761290000Sglebius ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey) 762290000Sglebius if (sk->lifetime > 0 && current_time > sk->lifetime) { 763298770Sdelphij freesymkey(sk); 764290000Sglebius authkeyexpired++; 76554359Sroberto } 766290000Sglebius ITER_DLIST_END() 767290000Sglebius DPRINTF(1, ("auth_agekeys: at %lu keys %lu expired %lu\n", 768290000Sglebius current_time, authnumkeys, authkeyexpired)); 76954359Sroberto} 77054359Sroberto 771290000Sglebius 77254359Sroberto/* 77354359Sroberto * authencrypt - generate message authenticator 77454359Sroberto * 77554359Sroberto * Returns length of authenticator field, zero if key not found. 77654359Sroberto */ 777293894Sglebiussize_t 77854359Srobertoauthencrypt( 779290000Sglebius keyid_t keyno, 780290000Sglebius u_int32 * pkt, 781293894Sglebius size_t length 78254359Sroberto ) 783293894Sglebius{ 78454359Sroberto /* 78554359Sroberto * A zero key identifier means the sender has not verified 78654359Sroberto * the last message was correctly authenticated. The MAC 78754359Sroberto * consists of a single word with value zero. 78854359Sroberto */ 78954359Sroberto authencryptions++; 79082498Sroberto pkt[length / 4] = htonl(keyno); 791290000Sglebius if (0 == keyno) { 792290000Sglebius return 4; 79354359Sroberto } 794290000Sglebius if (!authhavekey(keyno)) { 795290000Sglebius return 0; 796290000Sglebius } 79754359Sroberto 798290000Sglebius return MD5authencrypt(cache_type, cache_secret, pkt, length); 79954359Sroberto} 80054359Sroberto 801290000Sglebius 80254359Sroberto/* 80354359Sroberto * authdecrypt - verify message authenticator 80454359Sroberto * 805290000Sglebius * Returns TRUE if authenticator valid, FALSE if invalid or not found. 80654359Sroberto */ 80754359Srobertoint 80854359Srobertoauthdecrypt( 809290000Sglebius keyid_t keyno, 810290000Sglebius u_int32 * pkt, 811293894Sglebius size_t length, 812293894Sglebius size_t size 81354359Sroberto ) 81454359Sroberto{ 81554359Sroberto /* 81654359Sroberto * A zero key identifier means the sender has not verified 817290000Sglebius * the last message was correctly authenticated. For our 818290000Sglebius * purpose this is an invalid authenticator. 81954359Sroberto */ 82054359Sroberto authdecryptions++; 821290000Sglebius if (0 == keyno || !authhavekey(keyno) || size < 4) { 822290000Sglebius return FALSE; 823290000Sglebius } 82454359Sroberto 825290000Sglebius return MD5authdecrypt(cache_type, cache_secret, pkt, length, 826290000Sglebius size); 82754359Sroberto} 828