1c0b746e5SOllivier Robert /* 2c0b746e5SOllivier Robert * authkeys.c - routines to manage the storage of authentication keys 3c0b746e5SOllivier Robert */ 4c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H 5c0b746e5SOllivier Robert # include <config.h> 6c0b746e5SOllivier Robert #endif 7c0b746e5SOllivier Robert 82b15cb3dSCy Schubert #include <math.h> 9c0b746e5SOllivier Robert #include <stdio.h> 10c0b746e5SOllivier Robert 11c0b746e5SOllivier Robert #include "ntp.h" 122b15cb3dSCy Schubert #include "ntp_fp.h" 13c0b746e5SOllivier Robert #include "ntpd.h" 142b15cb3dSCy Schubert #include "ntp_lists.h" 15c0b746e5SOllivier Robert #include "ntp_string.h" 16c0b746e5SOllivier Robert #include "ntp_malloc.h" 17c0b746e5SOllivier Robert #include "ntp_stdlib.h" 18c0b746e5SOllivier Robert 19c0b746e5SOllivier Robert /* 20c0b746e5SOllivier Robert * Structure to store keys in in the hash table. 21c0b746e5SOllivier Robert */ 222b15cb3dSCy Schubert typedef struct savekey symkey; 232b15cb3dSCy Schubert 24c0b746e5SOllivier Robert struct savekey { 252b15cb3dSCy Schubert symkey * hlink; /* next in hash bucket */ 262b15cb3dSCy Schubert DECL_DLIST_LINK(symkey, llink); /* for overall & free lists */ 272b15cb3dSCy Schubert u_char * secret; /* shared secret */ 28c0b746e5SOllivier Robert u_long lifetime; /* remaining lifetime */ 292b15cb3dSCy Schubert keyid_t keyid; /* key identifier */ 302b15cb3dSCy Schubert u_short type; /* OpenSSL digest NID */ 312b15cb3dSCy Schubert u_short secretsize; /* secret octets */ 322b15cb3dSCy Schubert u_short flags; /* KEY_ flags that wave */ 33c0b746e5SOllivier Robert }; 34c0b746e5SOllivier Robert 352b15cb3dSCy Schubert /* define the payload region of symkey beyond the list pointers */ 362b15cb3dSCy Schubert #define symkey_payload secret 37c0b746e5SOllivier Robert 382b15cb3dSCy Schubert #define KEY_TRUSTED 0x001 /* this key is trusted */ 392b15cb3dSCy Schubert 402b15cb3dSCy Schubert #ifdef DEBUG 412b15cb3dSCy Schubert typedef struct symkey_alloc_tag symkey_alloc; 422b15cb3dSCy Schubert 432b15cb3dSCy Schubert struct symkey_alloc_tag { 442b15cb3dSCy Schubert symkey_alloc * link; 452b15cb3dSCy Schubert void * mem; /* enable free() atexit */ 462b15cb3dSCy Schubert }; 472b15cb3dSCy Schubert 482b15cb3dSCy Schubert symkey_alloc * authallocs; 492b15cb3dSCy Schubert #endif /* DEBUG */ 502b15cb3dSCy Schubert 512b15cb3dSCy Schubert static inline u_short auth_log2(double x); 522b15cb3dSCy Schubert static void auth_resize_hashtable(void); 532b15cb3dSCy Schubert static void allocsymkey(symkey **, keyid_t, u_short, 542b15cb3dSCy Schubert u_short, u_long, u_short, u_char *); 552b15cb3dSCy Schubert static void freesymkey(symkey *, symkey **); 562b15cb3dSCy Schubert #ifdef DEBUG 572b15cb3dSCy Schubert static void free_auth_mem(void); 582b15cb3dSCy Schubert #endif 592b15cb3dSCy Schubert 602b15cb3dSCy Schubert symkey key_listhead; /* list of all in-use keys */; 61c0b746e5SOllivier Robert /* 62c0b746e5SOllivier Robert * The hash table. This is indexed by the low order bits of the 63c0b746e5SOllivier Robert * keyid. We make this fairly big for potentially busy servers. 64c0b746e5SOllivier Robert */ 652b15cb3dSCy Schubert #define DEF_AUTHHASHSIZE 64 662b15cb3dSCy Schubert //#define HASHMASK ((HASHSIZE)-1) 672b15cb3dSCy Schubert #define KEYHASH(keyid) ((keyid) & authhashmask) 68c0b746e5SOllivier Robert 692b15cb3dSCy Schubert int authhashdisabled; 702b15cb3dSCy Schubert u_short authhashbuckets = DEF_AUTHHASHSIZE; 712b15cb3dSCy Schubert u_short authhashmask = DEF_AUTHHASHSIZE - 1; 722b15cb3dSCy Schubert symkey **key_hash; 73c0b746e5SOllivier Robert 74c0b746e5SOllivier Robert u_long authkeynotfound; /* keys not found */ 75c0b746e5SOllivier Robert u_long authkeylookups; /* calls to lookup keys */ 76c0b746e5SOllivier Robert u_long authnumkeys; /* number of active keys */ 77c0b746e5SOllivier Robert u_long authkeyexpired; /* key lifetime expirations */ 78c0b746e5SOllivier Robert u_long authkeyuncached; /* cache misses */ 79c0b746e5SOllivier Robert u_long authnokey; /* calls to encrypt with no key */ 80c0b746e5SOllivier Robert u_long authencryptions; /* calls to encrypt */ 81c0b746e5SOllivier Robert u_long authdecryptions; /* calls to decrypt */ 82c0b746e5SOllivier Robert 83c0b746e5SOllivier Robert /* 842b15cb3dSCy Schubert * Storage for free symkey structures. We malloc() such things but 85c0b746e5SOllivier Robert * never free them. 86c0b746e5SOllivier Robert */ 872b15cb3dSCy Schubert symkey *authfreekeys; 88c0b746e5SOllivier Robert int authnumfreekeys; 89c0b746e5SOllivier Robert 902b15cb3dSCy Schubert #define MEMINC 16 /* number of new free ones to get */ 91c0b746e5SOllivier Robert 92c0b746e5SOllivier Robert /* 93c0b746e5SOllivier Robert * The key cache. We cache the last key we looked at here. 94c0b746e5SOllivier Robert */ 95224ba2bdSOllivier Robert keyid_t cache_keyid; /* key identifier */ 962b15cb3dSCy Schubert u_char *cache_secret; /* secret */ 972b15cb3dSCy Schubert u_short cache_secretsize; /* secret length */ 982b15cb3dSCy Schubert int cache_type; /* OpenSSL digest NID */ 99c0b746e5SOllivier Robert u_short cache_flags; /* flags that wave */ 100c0b746e5SOllivier Robert 101c0b746e5SOllivier Robert 102c0b746e5SOllivier Robert /* 103c0b746e5SOllivier Robert * init_auth - initialize internal data 104c0b746e5SOllivier Robert */ 105c0b746e5SOllivier Robert void 106c0b746e5SOllivier Robert init_auth(void) 107c0b746e5SOllivier Robert { 1082b15cb3dSCy Schubert size_t newalloc; 1092b15cb3dSCy Schubert 110c0b746e5SOllivier Robert /* 111c0b746e5SOllivier Robert * Initialize hash table and free list 112c0b746e5SOllivier Robert */ 1132b15cb3dSCy Schubert newalloc = authhashbuckets * sizeof(key_hash[0]); 1142b15cb3dSCy Schubert 1152b15cb3dSCy Schubert key_hash = erealloc(key_hash, newalloc); 1162b15cb3dSCy Schubert memset(key_hash, '\0', newalloc); 1172b15cb3dSCy Schubert 1182b15cb3dSCy Schubert INIT_DLIST(key_listhead, llink); 1192b15cb3dSCy Schubert 1202b15cb3dSCy Schubert #ifdef DEBUG 1212b15cb3dSCy Schubert atexit(&free_auth_mem); 1222b15cb3dSCy Schubert #endif 1232b15cb3dSCy Schubert } 1242b15cb3dSCy Schubert 1252b15cb3dSCy Schubert 1262b15cb3dSCy Schubert /* 1272b15cb3dSCy Schubert * free_auth_mem - assist in leak detection by freeing all dynamic 1282b15cb3dSCy Schubert * allocations from this module. 1292b15cb3dSCy Schubert */ 1302b15cb3dSCy Schubert #ifdef DEBUG 1312b15cb3dSCy Schubert static void 1322b15cb3dSCy Schubert free_auth_mem(void) 1332b15cb3dSCy Schubert { 1342b15cb3dSCy Schubert symkey * sk; 1352b15cb3dSCy Schubert symkey_alloc * alloc; 1362b15cb3dSCy Schubert symkey_alloc * next_alloc; 1372b15cb3dSCy Schubert 1382b15cb3dSCy Schubert while (NULL != (sk = HEAD_DLIST(key_listhead, llink))) { 1392b15cb3dSCy Schubert freesymkey(sk, &key_hash[KEYHASH(sk->keyid)]); 1402b15cb3dSCy Schubert } 1412b15cb3dSCy Schubert free(key_hash); 1422b15cb3dSCy Schubert key_hash = NULL; 1432b15cb3dSCy Schubert cache_keyid = 0; 1442b15cb3dSCy Schubert cache_flags = 0; 1452b15cb3dSCy Schubert for (alloc = authallocs; alloc != NULL; alloc = next_alloc) { 1462b15cb3dSCy Schubert next_alloc = alloc->link; 1472b15cb3dSCy Schubert free(alloc->mem); 1482b15cb3dSCy Schubert } 1492b15cb3dSCy Schubert authfreekeys = NULL; 1502b15cb3dSCy Schubert authnumfreekeys = 0; 1512b15cb3dSCy Schubert } 1522b15cb3dSCy Schubert #endif /* DEBUG */ 1532b15cb3dSCy Schubert 1542b15cb3dSCy Schubert 1552b15cb3dSCy Schubert /* 1562b15cb3dSCy Schubert * auth_moremem - get some more free key structures 1572b15cb3dSCy Schubert */ 1582b15cb3dSCy Schubert void 1592b15cb3dSCy Schubert auth_moremem( 1602b15cb3dSCy Schubert int keycount 1612b15cb3dSCy Schubert ) 1622b15cb3dSCy Schubert { 1632b15cb3dSCy Schubert symkey * sk; 1642b15cb3dSCy Schubert int i; 1652b15cb3dSCy Schubert #ifdef DEBUG 1662b15cb3dSCy Schubert void * base; 1672b15cb3dSCy Schubert symkey_alloc * allocrec; 1682b15cb3dSCy Schubert # define MOREMEM_EXTRA_ALLOC (sizeof(*allocrec)) 1692b15cb3dSCy Schubert #else 1702b15cb3dSCy Schubert # define MOREMEM_EXTRA_ALLOC (0) 1712b15cb3dSCy Schubert #endif 1722b15cb3dSCy Schubert 1732b15cb3dSCy Schubert i = (keycount > 0) 1742b15cb3dSCy Schubert ? keycount 1752b15cb3dSCy Schubert : MEMINC; 1762b15cb3dSCy Schubert sk = emalloc_zero(i * sizeof(*sk) + MOREMEM_EXTRA_ALLOC); 1772b15cb3dSCy Schubert #ifdef DEBUG 1782b15cb3dSCy Schubert base = sk; 1792b15cb3dSCy Schubert #endif 1802b15cb3dSCy Schubert authnumfreekeys += i; 1812b15cb3dSCy Schubert 1822b15cb3dSCy Schubert for (; i > 0; i--, sk++) { 1832b15cb3dSCy Schubert LINK_SLIST(authfreekeys, sk, llink.f); 1842b15cb3dSCy Schubert } 1852b15cb3dSCy Schubert 1862b15cb3dSCy Schubert #ifdef DEBUG 1872b15cb3dSCy Schubert allocrec = (void *)sk; 1882b15cb3dSCy Schubert allocrec->mem = base; 1892b15cb3dSCy Schubert LINK_SLIST(authallocs, allocrec, link); 1902b15cb3dSCy Schubert #endif 1912b15cb3dSCy Schubert } 1922b15cb3dSCy Schubert 1932b15cb3dSCy Schubert 1942b15cb3dSCy Schubert /* 1952b15cb3dSCy Schubert * auth_prealloc_symkeys 1962b15cb3dSCy Schubert */ 1972b15cb3dSCy Schubert void 1982b15cb3dSCy Schubert auth_prealloc_symkeys( 1992b15cb3dSCy Schubert int keycount 2002b15cb3dSCy Schubert ) 2012b15cb3dSCy Schubert { 2022b15cb3dSCy Schubert int allocated; 2032b15cb3dSCy Schubert int additional; 2042b15cb3dSCy Schubert 2052b15cb3dSCy Schubert allocated = authnumkeys + authnumfreekeys; 2062b15cb3dSCy Schubert additional = keycount - allocated; 2072b15cb3dSCy Schubert if (additional > 0) 2082b15cb3dSCy Schubert auth_moremem(additional); 2092b15cb3dSCy Schubert auth_resize_hashtable(); 2102b15cb3dSCy Schubert } 2112b15cb3dSCy Schubert 2122b15cb3dSCy Schubert 2132b15cb3dSCy Schubert static inline u_short 2142b15cb3dSCy Schubert auth_log2(double x) 2152b15cb3dSCy Schubert { 2162b15cb3dSCy Schubert return (u_short)(log10(x) / log10(2)); 2172b15cb3dSCy Schubert } 2182b15cb3dSCy Schubert 2192b15cb3dSCy Schubert 2202b15cb3dSCy Schubert /* 2212b15cb3dSCy Schubert * auth_resize_hashtable 2222b15cb3dSCy Schubert * 2232b15cb3dSCy Schubert * Size hash table to average 4 or fewer entries per bucket initially, 2242b15cb3dSCy Schubert * within the bounds of at least 4 and no more than 15 bits for the hash 2252b15cb3dSCy Schubert * table index. Populate the hash table. 2262b15cb3dSCy Schubert */ 2272b15cb3dSCy Schubert static void 2282b15cb3dSCy Schubert auth_resize_hashtable(void) 2292b15cb3dSCy Schubert { 2302b15cb3dSCy Schubert u_long totalkeys; 2312b15cb3dSCy Schubert u_short hashbits; 2322b15cb3dSCy Schubert u_short hash; 2332b15cb3dSCy Schubert size_t newalloc; 2342b15cb3dSCy Schubert symkey * sk; 2352b15cb3dSCy Schubert 2362b15cb3dSCy Schubert totalkeys = authnumkeys + authnumfreekeys; 2372b15cb3dSCy Schubert hashbits = auth_log2(totalkeys / 4.0) + 1; 2382b15cb3dSCy Schubert hashbits = max(4, hashbits); 2392b15cb3dSCy Schubert hashbits = min(15, hashbits); 2402b15cb3dSCy Schubert 2412b15cb3dSCy Schubert authhashbuckets = 1 << hashbits; 2422b15cb3dSCy Schubert authhashmask = authhashbuckets - 1; 2432b15cb3dSCy Schubert newalloc = authhashbuckets * sizeof(key_hash[0]); 2442b15cb3dSCy Schubert 2452b15cb3dSCy Schubert key_hash = erealloc(key_hash, newalloc); 2462b15cb3dSCy Schubert memset(key_hash, '\0', newalloc); 2472b15cb3dSCy Schubert 2482b15cb3dSCy Schubert ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey) 2492b15cb3dSCy Schubert hash = KEYHASH(sk->keyid); 2502b15cb3dSCy Schubert LINK_SLIST(key_hash[hash], sk, hlink); 2512b15cb3dSCy Schubert ITER_DLIST_END() 2522b15cb3dSCy Schubert } 2532b15cb3dSCy Schubert 2542b15cb3dSCy Schubert 2552b15cb3dSCy Schubert /* 2562b15cb3dSCy Schubert * allocsymkey - common code to allocate and link in symkey 2572b15cb3dSCy Schubert * 2582b15cb3dSCy Schubert * secret must be allocated with a free-compatible allocator. It is 2592b15cb3dSCy Schubert * owned by the referring symkey structure, and will be free()d by 2602b15cb3dSCy Schubert * freesymkey(). 2612b15cb3dSCy Schubert */ 2622b15cb3dSCy Schubert static void 2632b15cb3dSCy Schubert allocsymkey( 2642b15cb3dSCy Schubert symkey ** bucket, 2652b15cb3dSCy Schubert keyid_t id, 2662b15cb3dSCy Schubert u_short flags, 2672b15cb3dSCy Schubert u_short type, 2682b15cb3dSCy Schubert u_long lifetime, 2692b15cb3dSCy Schubert u_short secretsize, 2702b15cb3dSCy Schubert u_char * secret 2712b15cb3dSCy Schubert ) 2722b15cb3dSCy Schubert { 2732b15cb3dSCy Schubert symkey * sk; 2742b15cb3dSCy Schubert 2752b15cb3dSCy Schubert if (authnumfreekeys < 1) 2762b15cb3dSCy Schubert auth_moremem(-1); 2772b15cb3dSCy Schubert UNLINK_HEAD_SLIST(sk, authfreekeys, llink.f); 2782b15cb3dSCy Schubert DEBUG_ENSURE(sk != NULL); 2792b15cb3dSCy Schubert sk->keyid = id; 2802b15cb3dSCy Schubert sk->flags = flags; 2812b15cb3dSCy Schubert sk->type = type; 2822b15cb3dSCy Schubert sk->secretsize = secretsize; 2832b15cb3dSCy Schubert sk->secret = secret; 2842b15cb3dSCy Schubert sk->lifetime = lifetime; 2852b15cb3dSCy Schubert LINK_SLIST(*bucket, sk, hlink); 2862b15cb3dSCy Schubert LINK_TAIL_DLIST(key_listhead, sk, llink); 2872b15cb3dSCy Schubert authnumfreekeys--; 2882b15cb3dSCy Schubert authnumkeys++; 2892b15cb3dSCy Schubert } 2902b15cb3dSCy Schubert 2912b15cb3dSCy Schubert 2922b15cb3dSCy Schubert /* 2932b15cb3dSCy Schubert * freesymkey - common code to remove a symkey and recycle its entry. 2942b15cb3dSCy Schubert */ 2952b15cb3dSCy Schubert static void 2962b15cb3dSCy Schubert freesymkey( 2972b15cb3dSCy Schubert symkey * sk, 2982b15cb3dSCy Schubert symkey ** bucket 2992b15cb3dSCy Schubert ) 3002b15cb3dSCy Schubert { 3012b15cb3dSCy Schubert symkey * unlinked; 3022b15cb3dSCy Schubert 3032b15cb3dSCy Schubert if (sk->secret != NULL) { 3042b15cb3dSCy Schubert memset(sk->secret, '\0', sk->secretsize); 3052b15cb3dSCy Schubert free(sk->secret); 3062b15cb3dSCy Schubert } 3072b15cb3dSCy Schubert UNLINK_SLIST(unlinked, *bucket, sk, hlink, symkey); 3082b15cb3dSCy Schubert DEBUG_ENSURE(sk == unlinked); 3092b15cb3dSCy Schubert UNLINK_DLIST(sk, llink); 3102b15cb3dSCy Schubert memset((char *)sk + offsetof(symkey, symkey_payload), '\0', 3112b15cb3dSCy Schubert sizeof(*sk) - offsetof(symkey, symkey_payload)); 3122b15cb3dSCy Schubert LINK_SLIST(authfreekeys, sk, llink.f); 3132b15cb3dSCy Schubert authnumkeys--; 3142b15cb3dSCy Schubert authnumfreekeys++; 315c0b746e5SOllivier Robert } 316c0b746e5SOllivier Robert 317c0b746e5SOllivier Robert 318c0b746e5SOllivier Robert /* 319c0b746e5SOllivier Robert * auth_findkey - find a key in the hash table 320c0b746e5SOllivier Robert */ 321c0b746e5SOllivier Robert struct savekey * 322c0b746e5SOllivier Robert auth_findkey( 3232b15cb3dSCy Schubert keyid_t id 324c0b746e5SOllivier Robert ) 325c0b746e5SOllivier Robert { 3262b15cb3dSCy Schubert symkey * sk; 327c0b746e5SOllivier Robert 3282b15cb3dSCy Schubert for (sk = key_hash[KEYHASH(id)]; sk != NULL; sk = sk->hlink) { 3292b15cb3dSCy Schubert if (id == sk->keyid) { 3302b15cb3dSCy Schubert return sk; 331c0b746e5SOllivier Robert } 3322b15cb3dSCy Schubert } 3332b15cb3dSCy Schubert 3342b15cb3dSCy Schubert return NULL; 335c0b746e5SOllivier Robert } 336c0b746e5SOllivier Robert 337c0b746e5SOllivier Robert 338c0b746e5SOllivier Robert /* 3392b15cb3dSCy Schubert * auth_havekey - return TRUE if the key id is zero or known 340c0b746e5SOllivier Robert */ 341c0b746e5SOllivier Robert int 342c0b746e5SOllivier Robert auth_havekey( 3432b15cb3dSCy Schubert keyid_t id 344c0b746e5SOllivier Robert ) 345c0b746e5SOllivier Robert { 3462b15cb3dSCy Schubert symkey * sk; 347c0b746e5SOllivier Robert 3482b15cb3dSCy Schubert if (0 == id || cache_keyid == id) { 3492b15cb3dSCy Schubert return TRUE; 350c0b746e5SOllivier Robert } 3512b15cb3dSCy Schubert 3522b15cb3dSCy Schubert for (sk = key_hash[KEYHASH(id)]; sk != NULL; sk = sk->hlink) { 3532b15cb3dSCy Schubert if (id == sk->keyid) { 3542b15cb3dSCy Schubert return TRUE; 3552b15cb3dSCy Schubert } 3562b15cb3dSCy Schubert } 3572b15cb3dSCy Schubert 3582b15cb3dSCy Schubert return FALSE; 359c0b746e5SOllivier Robert } 360c0b746e5SOllivier Robert 361c0b746e5SOllivier Robert 362c0b746e5SOllivier Robert /* 3632b15cb3dSCy Schubert * authhavekey - return TRUE and cache the key, if zero or both known 3642b15cb3dSCy Schubert * and trusted. 365c0b746e5SOllivier Robert */ 366c0b746e5SOllivier Robert int 367c0b746e5SOllivier Robert authhavekey( 3682b15cb3dSCy Schubert keyid_t id 369c0b746e5SOllivier Robert ) 370c0b746e5SOllivier Robert { 3712b15cb3dSCy Schubert symkey * sk; 372c0b746e5SOllivier Robert 373c0b746e5SOllivier Robert authkeylookups++; 3742b15cb3dSCy Schubert if (0 == id || cache_keyid == id) { 3752b15cb3dSCy Schubert return TRUE; 376c0b746e5SOllivier Robert } 377c0b746e5SOllivier Robert 378c0b746e5SOllivier Robert /* 3792b15cb3dSCy Schubert * Seach the bin for the key. If found and the key type 3802b15cb3dSCy Schubert * is zero, somebody marked it trusted without specifying 3812b15cb3dSCy Schubert * a key or key type. In this case consider the key missing. 382c0b746e5SOllivier Robert */ 3832b15cb3dSCy Schubert authkeyuncached++; 3842b15cb3dSCy Schubert for (sk = key_hash[KEYHASH(id)]; sk != NULL; sk = sk->hlink) { 3852b15cb3dSCy Schubert if (id == sk->keyid) { 3862b15cb3dSCy Schubert if (0 == sk->type) { 3872b15cb3dSCy Schubert authkeynotfound++; 3882b15cb3dSCy Schubert return FALSE; 389c0b746e5SOllivier Robert } 3902b15cb3dSCy Schubert break; 3912b15cb3dSCy Schubert } 3922b15cb3dSCy Schubert } 3932b15cb3dSCy Schubert 3942b15cb3dSCy Schubert /* 3952b15cb3dSCy Schubert * If the key is not found, or if it is found but not trusted, 3962b15cb3dSCy Schubert * the key is not considered found. 3972b15cb3dSCy Schubert */ 3982b15cb3dSCy Schubert if (NULL == sk) { 3992b15cb3dSCy Schubert authkeynotfound++; 4002b15cb3dSCy Schubert return FALSE; 4012b15cb3dSCy Schubert } 4022b15cb3dSCy Schubert if (!(KEY_TRUSTED & sk->flags)) { 4032b15cb3dSCy Schubert authnokey++; 4042b15cb3dSCy Schubert return FALSE; 4052b15cb3dSCy Schubert } 4062b15cb3dSCy Schubert 4072b15cb3dSCy Schubert /* 4082b15cb3dSCy Schubert * The key is found and trusted. Initialize the key cache. 4092b15cb3dSCy Schubert */ 4102b15cb3dSCy Schubert cache_keyid = sk->keyid; 4112b15cb3dSCy Schubert cache_type = sk->type; 4122b15cb3dSCy Schubert cache_flags = sk->flags; 4132b15cb3dSCy Schubert cache_secret = sk->secret; 4142b15cb3dSCy Schubert cache_secretsize = sk->secretsize; 4152b15cb3dSCy Schubert 4162b15cb3dSCy Schubert return TRUE; 417c0b746e5SOllivier Robert } 418c0b746e5SOllivier Robert 419c0b746e5SOllivier Robert 420c0b746e5SOllivier Robert /* 421c0b746e5SOllivier Robert * authtrust - declare a key to be trusted/untrusted 422c0b746e5SOllivier Robert */ 423c0b746e5SOllivier Robert void 424c0b746e5SOllivier Robert authtrust( 4252b15cb3dSCy Schubert keyid_t id, 426224ba2bdSOllivier Robert u_long trust 427c0b746e5SOllivier Robert ) 428c0b746e5SOllivier Robert { 4292b15cb3dSCy Schubert symkey ** bucket; 4302b15cb3dSCy Schubert symkey * sk; 4312b15cb3dSCy Schubert u_long lifetime; 432c0b746e5SOllivier Robert 4332b15cb3dSCy Schubert /* 4342b15cb3dSCy Schubert * Search bin for key; if it does not exist and is untrusted, 4352b15cb3dSCy Schubert * forget it. 4362b15cb3dSCy Schubert */ 4372b15cb3dSCy Schubert bucket = &key_hash[KEYHASH(id)]; 4382b15cb3dSCy Schubert for (sk = *bucket; sk != NULL; sk = sk->hlink) { 4392b15cb3dSCy Schubert if (id == sk->keyid) 440c0b746e5SOllivier Robert break; 441c0b746e5SOllivier Robert } 4422b15cb3dSCy Schubert if (!trust && NULL == sk) 443c0b746e5SOllivier Robert return; 444c0b746e5SOllivier Robert 4452b15cb3dSCy Schubert /* 4462b15cb3dSCy Schubert * There are two conditions remaining. Either it does not 4472b15cb3dSCy Schubert * exist and is to be trusted or it does exist and is or is 4482b15cb3dSCy Schubert * not to be trusted. 4492b15cb3dSCy Schubert */ 4502b15cb3dSCy Schubert if (sk != NULL) { 4512b15cb3dSCy Schubert if (cache_keyid == id) { 452c0b746e5SOllivier Robert cache_flags = 0; 453c0b746e5SOllivier Robert cache_keyid = 0; 454c0b746e5SOllivier Robert } 455c0b746e5SOllivier Robert 4562b15cb3dSCy Schubert /* 4572b15cb3dSCy Schubert * Key exists. If it is to be trusted, say so and 4582b15cb3dSCy Schubert * update its lifetime. 4592b15cb3dSCy Schubert */ 460c0b746e5SOllivier Robert if (trust > 0) { 461c0b746e5SOllivier Robert sk->flags |= KEY_TRUSTED; 462c0b746e5SOllivier Robert if (trust > 1) 463c0b746e5SOllivier Robert sk->lifetime = current_time + trust; 464c0b746e5SOllivier Robert else 465c0b746e5SOllivier Robert sk->lifetime = 0; 466c0b746e5SOllivier Robert return; 467c0b746e5SOllivier Robert } 468c0b746e5SOllivier Robert 4692b15cb3dSCy Schubert /* No longer trusted, return it to the free list. */ 4702b15cb3dSCy Schubert freesymkey(sk, bucket); 4712b15cb3dSCy Schubert return; 4722b15cb3dSCy Schubert } 473c0b746e5SOllivier Robert 4742b15cb3dSCy Schubert /* 4752b15cb3dSCy Schubert * keyid is not present, but the is to be trusted. We allocate 4762b15cb3dSCy Schubert * a new key, but do not specify a key type or secret. 4772b15cb3dSCy Schubert */ 4782b15cb3dSCy Schubert if (trust > 1) { 4792b15cb3dSCy Schubert lifetime = current_time + trust; 480c0b746e5SOllivier Robert } else { 4812b15cb3dSCy Schubert lifetime = 0; 482c0b746e5SOllivier Robert } 4832b15cb3dSCy Schubert allocsymkey(bucket, id, KEY_TRUSTED, 0, lifetime, 0, NULL); 484c0b746e5SOllivier Robert } 485c0b746e5SOllivier Robert 486c0b746e5SOllivier Robert 487c0b746e5SOllivier Robert /* 488c0b746e5SOllivier Robert * authistrusted - determine whether a key is trusted 489c0b746e5SOllivier Robert */ 490c0b746e5SOllivier Robert int 491c0b746e5SOllivier Robert authistrusted( 492224ba2bdSOllivier Robert keyid_t keyno 493c0b746e5SOllivier Robert ) 494c0b746e5SOllivier Robert { 4952b15cb3dSCy Schubert symkey * sk; 4962b15cb3dSCy Schubert symkey ** bucket; 497c0b746e5SOllivier Robert 498c0b746e5SOllivier Robert if (keyno == cache_keyid) 4992b15cb3dSCy Schubert return !!(KEY_TRUSTED & cache_flags); 500c0b746e5SOllivier Robert 501c0b746e5SOllivier Robert authkeyuncached++; 5022b15cb3dSCy Schubert bucket = &key_hash[KEYHASH(keyno)]; 5032b15cb3dSCy Schubert for (sk = *bucket; sk != NULL; sk = sk->hlink) { 504c0b746e5SOllivier Robert if (keyno == sk->keyid) 505c0b746e5SOllivier Robert break; 506c0b746e5SOllivier Robert } 5072b15cb3dSCy Schubert if (NULL == sk || !(KEY_TRUSTED & sk->flags)) { 508c0b746e5SOllivier Robert authkeynotfound++; 5092b15cb3dSCy Schubert return FALSE; 510c0b746e5SOllivier Robert } 5112b15cb3dSCy Schubert return TRUE; 512c0b746e5SOllivier Robert } 513c0b746e5SOllivier Robert 514c0b746e5SOllivier Robert 515c0b746e5SOllivier Robert void 516c0b746e5SOllivier Robert MD5auth_setkey( 517224ba2bdSOllivier Robert keyid_t keyno, 5182b15cb3dSCy Schubert int keytype, 519c0b746e5SOllivier Robert const u_char *key, 5202b15cb3dSCy Schubert size_t len 521c0b746e5SOllivier Robert ) 522c0b746e5SOllivier Robert { 5232b15cb3dSCy Schubert symkey * sk; 5242b15cb3dSCy Schubert symkey ** bucket; 5252b15cb3dSCy Schubert u_char * secret; 5262b15cb3dSCy Schubert size_t secretsize; 527c0b746e5SOllivier Robert 5282b15cb3dSCy Schubert DEBUG_ENSURE(keytype <= USHRT_MAX); 5292b15cb3dSCy Schubert DEBUG_ENSURE(len < 4 * 1024); 530c0b746e5SOllivier Robert /* 531c0b746e5SOllivier Robert * See if we already have the key. If so just stick in the 532c0b746e5SOllivier Robert * new value. 533c0b746e5SOllivier Robert */ 5342b15cb3dSCy Schubert bucket = &key_hash[KEYHASH(keyno)]; 5352b15cb3dSCy Schubert for (sk = *bucket; sk != NULL; sk = sk->hlink) { 536c0b746e5SOllivier Robert if (keyno == sk->keyid) { 537*9034852cSGleb Smirnoff /* TALOS-CAN-0054: make sure we have a new buffer! */ 538*9034852cSGleb Smirnoff if (NULL != sk->secret) { 539*9034852cSGleb Smirnoff memset(sk->secret, 0, sk->secretsize); 540*9034852cSGleb Smirnoff free(sk->secret); 541*9034852cSGleb Smirnoff } 542*9034852cSGleb Smirnoff sk->secret = emalloc(len); 5432b15cb3dSCy Schubert sk->type = (u_short)keytype; 5442b15cb3dSCy Schubert secretsize = len; 5452b15cb3dSCy Schubert sk->secretsize = (u_short)secretsize; 5462b15cb3dSCy Schubert #ifndef DISABLE_BUG1243_FIX 5472b15cb3dSCy Schubert memcpy(sk->secret, key, secretsize); 5482b15cb3dSCy Schubert #else 5492b15cb3dSCy Schubert strlcpy((char *)sk->secret, (const char *)key, 5502b15cb3dSCy Schubert secretsize); 5512b15cb3dSCy Schubert #endif 552c0b746e5SOllivier Robert if (cache_keyid == keyno) { 553c0b746e5SOllivier Robert cache_flags = 0; 554c0b746e5SOllivier Robert cache_keyid = 0; 555c0b746e5SOllivier Robert } 556c0b746e5SOllivier Robert return; 557c0b746e5SOllivier Robert } 558c0b746e5SOllivier Robert } 559c0b746e5SOllivier Robert 560c0b746e5SOllivier Robert /* 561c0b746e5SOllivier Robert * Need to allocate new structure. Do it. 562c0b746e5SOllivier Robert */ 5632b15cb3dSCy Schubert secretsize = len; 5642b15cb3dSCy Schubert secret = emalloc(secretsize); 5652b15cb3dSCy Schubert #ifndef DISABLE_BUG1243_FIX 5662b15cb3dSCy Schubert memcpy(secret, key, secretsize); 5672b15cb3dSCy Schubert #else 5682b15cb3dSCy Schubert strlcpy((char *)secret, (const char *)key, secretsize); 5692b15cb3dSCy Schubert #endif 5702b15cb3dSCy Schubert allocsymkey(bucket, keyno, 0, (u_short)keytype, 0, 5712b15cb3dSCy Schubert (u_short)secretsize, secret); 5722b15cb3dSCy Schubert #ifdef DEBUG 5732b15cb3dSCy Schubert if (debug >= 4) { 5742b15cb3dSCy Schubert size_t j; 5752b15cb3dSCy Schubert 5762b15cb3dSCy Schubert printf("auth_setkey: key %d type %d len %d ", (int)keyno, 5772b15cb3dSCy Schubert keytype, (int)secretsize); 5782b15cb3dSCy Schubert for (j = 0; j < secretsize; j++) 5792b15cb3dSCy Schubert printf("%02x", secret[j]); 5802b15cb3dSCy Schubert printf("\n"); 5812b15cb3dSCy Schubert } 5822b15cb3dSCy Schubert #endif 583c0b746e5SOllivier Robert } 584c0b746e5SOllivier Robert 585c0b746e5SOllivier Robert 586c0b746e5SOllivier Robert /* 5872b15cb3dSCy Schubert * auth_delkeys - delete non-autokey untrusted keys, and clear all info 5882b15cb3dSCy Schubert * except the trusted bit of non-autokey trusted keys, in 5892b15cb3dSCy Schubert * preparation for rereading the keys file. 590c0b746e5SOllivier Robert */ 591c0b746e5SOllivier Robert void 592c0b746e5SOllivier Robert auth_delkeys(void) 593c0b746e5SOllivier Robert { 5942b15cb3dSCy Schubert symkey * sk; 595c0b746e5SOllivier Robert 5962b15cb3dSCy Schubert ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey) 5972b15cb3dSCy Schubert if (sk->keyid > NTP_MAXKEY) { /* autokey */ 5982b15cb3dSCy Schubert continue; 5992b15cb3dSCy Schubert } 6002b15cb3dSCy Schubert 601c0b746e5SOllivier Robert /* 602*9034852cSGleb Smirnoff * Don't lose info as to which keys are trusted. Make 603*9034852cSGleb Smirnoff * sure there are no dangling pointers! 604c0b746e5SOllivier Robert */ 6052b15cb3dSCy Schubert if (KEY_TRUSTED & sk->flags) { 6062b15cb3dSCy Schubert if (sk->secret != NULL) { 607*9034852cSGleb Smirnoff memset(sk->secret, 0, sk->secretsize); 6082b15cb3dSCy Schubert free(sk->secret); 609*9034852cSGleb Smirnoff sk->secret = NULL; /* TALOS-CAN-0054 */ 6102b15cb3dSCy Schubert } 6112b15cb3dSCy Schubert sk->secretsize = 0; 612c0b746e5SOllivier Robert sk->lifetime = 0; 613c0b746e5SOllivier Robert } else { 6142b15cb3dSCy Schubert freesymkey(sk, &key_hash[KEYHASH(sk->keyid)]); 615c0b746e5SOllivier Robert } 6162b15cb3dSCy Schubert ITER_DLIST_END() 617c0b746e5SOllivier Robert } 6182b15cb3dSCy Schubert 619c0b746e5SOllivier Robert 620c0b746e5SOllivier Robert /* 621c0b746e5SOllivier Robert * auth_agekeys - delete keys whose lifetimes have expired 622c0b746e5SOllivier Robert */ 623c0b746e5SOllivier Robert void 624c0b746e5SOllivier Robert auth_agekeys(void) 625c0b746e5SOllivier Robert { 6262b15cb3dSCy Schubert symkey * sk; 627c0b746e5SOllivier Robert 6282b15cb3dSCy Schubert ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey) 6292b15cb3dSCy Schubert if (sk->lifetime > 0 && current_time > sk->lifetime) { 6302b15cb3dSCy Schubert freesymkey(sk, &key_hash[KEYHASH(sk->keyid)]); 631c0b746e5SOllivier Robert authkeyexpired++; 632c0b746e5SOllivier Robert } 6332b15cb3dSCy Schubert ITER_DLIST_END() 6342b15cb3dSCy Schubert DPRINTF(1, ("auth_agekeys: at %lu keys %lu expired %lu\n", 6352b15cb3dSCy Schubert current_time, authnumkeys, authkeyexpired)); 636c0b746e5SOllivier Robert } 6372b15cb3dSCy Schubert 638c0b746e5SOllivier Robert 639c0b746e5SOllivier Robert /* 640c0b746e5SOllivier Robert * authencrypt - generate message authenticator 641c0b746e5SOllivier Robert * 642c0b746e5SOllivier Robert * Returns length of authenticator field, zero if key not found. 643c0b746e5SOllivier Robert */ 644c0b746e5SOllivier Robert int 645c0b746e5SOllivier Robert authencrypt( 646224ba2bdSOllivier Robert keyid_t keyno, 647c0b746e5SOllivier Robert u_int32 * pkt, 648c0b746e5SOllivier Robert int length 649c0b746e5SOllivier Robert ) 6502b15cb3dSCy Schubert {\ 651c0b746e5SOllivier Robert /* 652c0b746e5SOllivier Robert * A zero key identifier means the sender has not verified 653c0b746e5SOllivier Robert * the last message was correctly authenticated. The MAC 654c0b746e5SOllivier Robert * consists of a single word with value zero. 655c0b746e5SOllivier Robert */ 656c0b746e5SOllivier Robert authencryptions++; 657224ba2bdSOllivier Robert pkt[length / 4] = htonl(keyno); 6582b15cb3dSCy Schubert if (0 == keyno) { 6592b15cb3dSCy Schubert return 4; 660c0b746e5SOllivier Robert } 6612b15cb3dSCy Schubert if (!authhavekey(keyno)) { 6622b15cb3dSCy Schubert return 0; 663c0b746e5SOllivier Robert } 664c0b746e5SOllivier Robert 6652b15cb3dSCy Schubert return MD5authencrypt(cache_type, cache_secret, pkt, length); 6662b15cb3dSCy Schubert } 6672b15cb3dSCy Schubert 6682b15cb3dSCy Schubert 669c0b746e5SOllivier Robert /* 670c0b746e5SOllivier Robert * authdecrypt - verify message authenticator 671c0b746e5SOllivier Robert * 6722b15cb3dSCy Schubert * Returns TRUE if authenticator valid, FALSE if invalid or not found. 673c0b746e5SOllivier Robert */ 674c0b746e5SOllivier Robert int 675c0b746e5SOllivier Robert authdecrypt( 676224ba2bdSOllivier Robert keyid_t keyno, 677c0b746e5SOllivier Robert u_int32 * pkt, 678c0b746e5SOllivier Robert int length, 679c0b746e5SOllivier Robert int size 680c0b746e5SOllivier Robert ) 681c0b746e5SOllivier Robert { 682c0b746e5SOllivier Robert /* 683c0b746e5SOllivier Robert * A zero key identifier means the sender has not verified 6842b15cb3dSCy Schubert * the last message was correctly authenticated. For our 6852b15cb3dSCy Schubert * purpose this is an invalid authenticator. 686c0b746e5SOllivier Robert */ 687c0b746e5SOllivier Robert authdecryptions++; 6882b15cb3dSCy Schubert if (0 == keyno || !authhavekey(keyno) || size < 4) { 6892b15cb3dSCy Schubert return FALSE; 6902b15cb3dSCy Schubert } 691c0b746e5SOllivier Robert 6922b15cb3dSCy Schubert return MD5authdecrypt(cache_type, cache_secret, pkt, length, 6932b15cb3dSCy Schubert size); 694c0b746e5SOllivier Robert } 695