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" 1868ba7e87SXin LI #include "ntp_keyacc.h" 19c0b746e5SOllivier Robert 20c0b746e5SOllivier Robert /* 21c0b746e5SOllivier Robert * Structure to store keys in in the hash table. 22c0b746e5SOllivier Robert */ 232b15cb3dSCy Schubert typedef struct savekey symkey; 242b15cb3dSCy Schubert 25c0b746e5SOllivier Robert struct savekey { 262b15cb3dSCy Schubert symkey * hlink; /* next in hash bucket */ 272b15cb3dSCy Schubert DECL_DLIST_LINK(symkey, llink); /* for overall & free lists */ 282b15cb3dSCy Schubert u_char * secret; /* shared secret */ 2968ba7e87SXin LI KeyAccT * keyacclist; /* Private key access list */ 30c0b746e5SOllivier Robert u_long lifetime; /* remaining lifetime */ 312b15cb3dSCy Schubert keyid_t keyid; /* key identifier */ 322b15cb3dSCy Schubert u_short type; /* OpenSSL digest NID */ 334990d495SXin LI size_t secretsize; /* secret octets */ 342b15cb3dSCy Schubert u_short flags; /* KEY_ flags that wave */ 35c0b746e5SOllivier Robert }; 36c0b746e5SOllivier Robert 372b15cb3dSCy Schubert /* define the payload region of symkey beyond the list pointers */ 382b15cb3dSCy Schubert #define symkey_payload secret 39c0b746e5SOllivier Robert 402b15cb3dSCy Schubert #define KEY_TRUSTED 0x001 /* this key is trusted */ 412b15cb3dSCy Schubert 422b15cb3dSCy Schubert #ifdef DEBUG 432b15cb3dSCy Schubert typedef struct symkey_alloc_tag symkey_alloc; 442b15cb3dSCy Schubert 452b15cb3dSCy Schubert struct symkey_alloc_tag { 462b15cb3dSCy Schubert symkey_alloc * link; 472b15cb3dSCy Schubert void * mem; /* enable free() atexit */ 482b15cb3dSCy Schubert }; 492b15cb3dSCy Schubert 502b15cb3dSCy Schubert symkey_alloc * authallocs; 512b15cb3dSCy Schubert #endif /* DEBUG */ 522b15cb3dSCy Schubert 5368ba7e87SXin LI static u_short auth_log2(size_t); 542b15cb3dSCy Schubert static void auth_resize_hashtable(void); 554990d495SXin LI static void allocsymkey(keyid_t, u_short, 564990d495SXin LI u_short, u_long, size_t, u_char *, KeyAccT *); 574990d495SXin LI static void freesymkey(symkey *); 582b15cb3dSCy Schubert #ifdef DEBUG 592b15cb3dSCy Schubert static void free_auth_mem(void); 602b15cb3dSCy Schubert #endif 612b15cb3dSCy Schubert 622b15cb3dSCy Schubert symkey key_listhead; /* list of all in-use keys */; 63c0b746e5SOllivier Robert /* 64c0b746e5SOllivier Robert * The hash table. This is indexed by the low order bits of the 65c0b746e5SOllivier Robert * keyid. We make this fairly big for potentially busy servers. 66c0b746e5SOllivier Robert */ 672b15cb3dSCy Schubert #define DEF_AUTHHASHSIZE 64 683311ff84SXin LI /*#define HASHMASK ((HASHSIZE)-1)*/ 692b15cb3dSCy Schubert #define KEYHASH(keyid) ((keyid) & authhashmask) 70c0b746e5SOllivier Robert 712b15cb3dSCy Schubert int authhashdisabled; 722b15cb3dSCy Schubert u_short authhashbuckets = DEF_AUTHHASHSIZE; 732b15cb3dSCy Schubert u_short authhashmask = DEF_AUTHHASHSIZE - 1; 742b15cb3dSCy Schubert symkey **key_hash; 75c0b746e5SOllivier Robert 76c0b746e5SOllivier Robert u_long authkeynotfound; /* keys not found */ 77c0b746e5SOllivier Robert u_long authkeylookups; /* calls to lookup keys */ 78c0b746e5SOllivier Robert u_long authnumkeys; /* number of active keys */ 79c0b746e5SOllivier Robert u_long authkeyexpired; /* key lifetime expirations */ 80c0b746e5SOllivier Robert u_long authkeyuncached; /* cache misses */ 81c0b746e5SOllivier Robert u_long authnokey; /* calls to encrypt with no key */ 82c0b746e5SOllivier Robert u_long authencryptions; /* calls to encrypt */ 83c0b746e5SOllivier Robert u_long authdecryptions; /* calls to decrypt */ 84c0b746e5SOllivier Robert 85c0b746e5SOllivier Robert /* 862b15cb3dSCy Schubert * Storage for free symkey structures. We malloc() such things but 87c0b746e5SOllivier Robert * never free them. 88c0b746e5SOllivier Robert */ 892b15cb3dSCy Schubert symkey *authfreekeys; 90c0b746e5SOllivier Robert int authnumfreekeys; 91c0b746e5SOllivier Robert 922b15cb3dSCy Schubert #define MEMINC 16 /* number of new free ones to get */ 93c0b746e5SOllivier Robert 94c0b746e5SOllivier Robert /* 95c0b746e5SOllivier Robert * The key cache. We cache the last key we looked at here. 964990d495SXin LI * Note: this should hold the last *trusted* key. Also the 974990d495SXin LI * cache is only loaded when the digest type / MAC algorithm 984990d495SXin LI * is valid. 99c0b746e5SOllivier Robert */ 100224ba2bdSOllivier Robert keyid_t cache_keyid; /* key identifier */ 1012b15cb3dSCy Schubert u_char *cache_secret; /* secret */ 1024990d495SXin LI size_t cache_secretsize; /* secret length */ 1032b15cb3dSCy Schubert int cache_type; /* OpenSSL digest NID */ 104c0b746e5SOllivier Robert u_short cache_flags; /* flags that wave */ 10568ba7e87SXin LI KeyAccT *cache_keyacclist; /* key access list */ 106c0b746e5SOllivier Robert 1074990d495SXin LI /* -------------------------------------------------------------------- 1084990d495SXin LI * manage key access lists 1094990d495SXin LI * -------------------------------------------------------------------- 1104990d495SXin LI */ 1114990d495SXin LI /* allocate and populate new access node and pushes it on the list. 1124990d495SXin LI * Returns the new head. 1134990d495SXin LI */ 1144990d495SXin LI KeyAccT* 1154990d495SXin LI keyacc_new_push( 1164990d495SXin LI KeyAccT * head, 11709100258SXin LI const sockaddr_u * addr, 11809100258SXin LI unsigned int subnetbits 1194990d495SXin LI ) 1204990d495SXin LI { 1214990d495SXin LI KeyAccT * node = emalloc(sizeof(KeyAccT)); 1224990d495SXin LI 1234990d495SXin LI memcpy(&node->addr, addr, sizeof(sockaddr_u)); 12409100258SXin LI node->subnetbits = subnetbits; 1254990d495SXin LI node->next = head; 12609100258SXin LI 1274990d495SXin LI return node; 1284990d495SXin LI } 1294990d495SXin LI 1304990d495SXin LI /* ----------------------------------------------------------------- */ 1314990d495SXin LI /* pop and deallocate the first node of a list of access nodes, if 1324990d495SXin LI * the list is not empty. Returns the tail of the list. 1334990d495SXin LI */ 1344990d495SXin LI KeyAccT* 1354990d495SXin LI keyacc_pop_free( 1364990d495SXin LI KeyAccT *head 1374990d495SXin LI ) 1384990d495SXin LI { 1394990d495SXin LI KeyAccT * next = NULL; 1404990d495SXin LI if (head) { 1414990d495SXin LI next = head->next; 1424990d495SXin LI free(head); 1434990d495SXin LI } 1444990d495SXin LI return next; 1454990d495SXin LI } 1464990d495SXin LI 1474990d495SXin LI /* ----------------------------------------------------------------- */ 1484990d495SXin LI /* deallocate the list; returns an empty list. */ 1494990d495SXin LI KeyAccT* 1504990d495SXin LI keyacc_all_free( 1514990d495SXin LI KeyAccT * head 1524990d495SXin LI ) 1534990d495SXin LI { 1544990d495SXin LI while (head) 1554990d495SXin LI head = keyacc_pop_free(head); 1564990d495SXin LI return head; 1574990d495SXin LI } 1584990d495SXin LI 1594990d495SXin LI /* ----------------------------------------------------------------- */ 1604990d495SXin LI /* scan a list to see if it contains a given address. Return the 1614990d495SXin LI * default result value in case of an empty list. 1624990d495SXin LI */ 1634990d495SXin LI int /*BOOL*/ 1644990d495SXin LI keyacc_contains( 1654990d495SXin LI const KeyAccT *head, 1664990d495SXin LI const sockaddr_u *addr, 1674990d495SXin LI int defv) 1684990d495SXin LI { 1694990d495SXin LI if (head) { 1704990d495SXin LI do { 17109100258SXin LI if (keyacc_amatch(&head->addr, addr, 17209100258SXin LI head->subnetbits)) 1734990d495SXin LI return TRUE; 1744990d495SXin LI } while (NULL != (head = head->next)); 1754990d495SXin LI return FALSE; 1764990d495SXin LI } else { 1774990d495SXin LI return !!defv; 1784990d495SXin LI } 1794990d495SXin LI } 1804990d495SXin LI 18109100258SXin LI #if CHAR_BIT != 8 18209100258SXin LI # error "don't know how to handle bytes with that bit size" 18309100258SXin LI #endif 18409100258SXin LI 18509100258SXin LI /* ----------------------------------------------------------------- */ 18609100258SXin LI /* check two addresses for a match, taking a prefix length into account 18709100258SXin LI * when doing the compare. 18809100258SXin LI * 18909100258SXin LI * The ISC lib contains a similar function with not entirely specified 19009100258SXin LI * semantics, so it seemed somewhat cleaner to do this from scratch. 19109100258SXin LI * 19209100258SXin LI * Note 1: It *is* assumed that the addresses are stored in network byte 19309100258SXin LI * order, that is, most significant byte first! 19409100258SXin LI * 19509100258SXin LI * Note 2: "no address" compares unequal to all other addresses, even to 19609100258SXin LI * itself. This has the same semantics as NaNs have for floats: *any* 19709100258SXin LI * relational or equality operation involving a NaN returns FALSE, even 19809100258SXin LI * equality with itself. "no address" is either a NULL pointer argument 19909100258SXin LI * or an address of type AF_UNSPEC. 20009100258SXin LI */ 20109100258SXin LI int/*BOOL*/ 20209100258SXin LI keyacc_amatch( 20309100258SXin LI const sockaddr_u * a1, 20409100258SXin LI const sockaddr_u * a2, 20509100258SXin LI unsigned int mbits 20609100258SXin LI ) 20709100258SXin LI { 20809100258SXin LI const uint8_t * pm1; 20909100258SXin LI const uint8_t * pm2; 21009100258SXin LI uint8_t msk; 21109100258SXin LI unsigned int len; 21209100258SXin LI 21309100258SXin LI /* 1st check: If any address is not an address, it's inequal. */ 21409100258SXin LI if ( !a1 || (AF_UNSPEC == AF(a1)) || 21509100258SXin LI !a2 || (AF_UNSPEC == AF(a2)) ) 21609100258SXin LI return FALSE; 21709100258SXin LI 21809100258SXin LI /* We could check pointers for equality here and shortcut the 21909100258SXin LI * other checks if we find object identity. But that use case is 22009100258SXin LI * too rare to care for it. 22109100258SXin LI */ 22209100258SXin LI 22309100258SXin LI /* 2nd check: Address families must be the same. */ 22409100258SXin LI if (AF(a1) != AF(a2)) 22509100258SXin LI return FALSE; 22609100258SXin LI 22709100258SXin LI /* type check: address family determines buffer & size */ 22809100258SXin LI switch (AF(a1)) { 22909100258SXin LI case AF_INET: 23009100258SXin LI /* IPv4 is easy: clamp size, get byte pointers */ 23109100258SXin LI if (mbits > sizeof(NSRCADR(a1)) * 8) 23209100258SXin LI mbits = sizeof(NSRCADR(a1)) * 8; 23309100258SXin LI pm1 = (const void*)&NSRCADR(a1); 23409100258SXin LI pm2 = (const void*)&NSRCADR(a2); 23509100258SXin LI break; 23609100258SXin LI 23709100258SXin LI case AF_INET6: 23809100258SXin LI /* IPv6 is slightly different: Both scopes must match, 23909100258SXin LI * too, before we even consider doing a match! 24009100258SXin LI */ 24109100258SXin LI if ( ! SCOPE_EQ(a1, a2)) 24209100258SXin LI return FALSE; 24309100258SXin LI if (mbits > sizeof(NSRCADR6(a1)) * 8) 24409100258SXin LI mbits = sizeof(NSRCADR6(a1)) * 8; 24509100258SXin LI pm1 = (const void*)&NSRCADR6(a1); 24609100258SXin LI pm2 = (const void*)&NSRCADR6(a2); 24709100258SXin LI break; 24809100258SXin LI 24909100258SXin LI default: 25009100258SXin LI /* don't know how to compare that!?! */ 25109100258SXin LI return FALSE; 25209100258SXin LI } 25309100258SXin LI 25409100258SXin LI /* Split bit length into byte length and partial byte mask. 25509100258SXin LI * Note that the byte mask extends from the MSB of a byte down, 25609100258SXin LI * and that zero shift (--> mbits % 8 == 0) results in an 25709100258SXin LI * all-zero mask. 25809100258SXin LI */ 25909100258SXin LI msk = 0xFFu ^ (0xFFu >> (mbits & 7)); 26009100258SXin LI len = mbits >> 3; 26109100258SXin LI 26209100258SXin LI /* 3rd check: Do memcmp() over full bytes, if any */ 26309100258SXin LI if (len && memcmp(pm1, pm2, len)) 26409100258SXin LI return FALSE; 26509100258SXin LI 26609100258SXin LI /* 4th check: compare last incomplete byte, if any */ 26709100258SXin LI if (msk && ((pm1[len] ^ pm2[len]) & msk)) 26809100258SXin LI return FALSE; 26909100258SXin LI 27009100258SXin LI /* If none of the above failed, we're successfully through. */ 27109100258SXin LI return TRUE; 27209100258SXin LI } 273c0b746e5SOllivier Robert 274c0b746e5SOllivier Robert /* 275c0b746e5SOllivier Robert * init_auth - initialize internal data 276c0b746e5SOllivier Robert */ 277c0b746e5SOllivier Robert void 278c0b746e5SOllivier Robert init_auth(void) 279c0b746e5SOllivier Robert { 2802b15cb3dSCy Schubert size_t newalloc; 2812b15cb3dSCy Schubert 282c0b746e5SOllivier Robert /* 283c0b746e5SOllivier Robert * Initialize hash table and free list 284c0b746e5SOllivier Robert */ 2852b15cb3dSCy Schubert newalloc = authhashbuckets * sizeof(key_hash[0]); 2862b15cb3dSCy Schubert 2872b15cb3dSCy Schubert key_hash = erealloc(key_hash, newalloc); 2882b15cb3dSCy Schubert memset(key_hash, '\0', newalloc); 2892b15cb3dSCy Schubert 2902b15cb3dSCy Schubert INIT_DLIST(key_listhead, llink); 2912b15cb3dSCy Schubert 2922b15cb3dSCy Schubert #ifdef DEBUG 2932b15cb3dSCy Schubert atexit(&free_auth_mem); 2942b15cb3dSCy Schubert #endif 2952b15cb3dSCy Schubert } 2962b15cb3dSCy Schubert 2972b15cb3dSCy Schubert 2982b15cb3dSCy Schubert /* 2992b15cb3dSCy Schubert * free_auth_mem - assist in leak detection by freeing all dynamic 3002b15cb3dSCy Schubert * allocations from this module. 3012b15cb3dSCy Schubert */ 3022b15cb3dSCy Schubert #ifdef DEBUG 3032b15cb3dSCy Schubert static void 3042b15cb3dSCy Schubert free_auth_mem(void) 3052b15cb3dSCy Schubert { 3062b15cb3dSCy Schubert symkey * sk; 3072b15cb3dSCy Schubert symkey_alloc * alloc; 3082b15cb3dSCy Schubert symkey_alloc * next_alloc; 3092b15cb3dSCy Schubert 3102b15cb3dSCy Schubert while (NULL != (sk = HEAD_DLIST(key_listhead, llink))) { 3114990d495SXin LI freesymkey(sk); 3122b15cb3dSCy Schubert } 3132b15cb3dSCy Schubert free(key_hash); 3142b15cb3dSCy Schubert key_hash = NULL; 3152b15cb3dSCy Schubert cache_keyid = 0; 3162b15cb3dSCy Schubert cache_flags = 0; 31768ba7e87SXin LI cache_keyacclist = NULL; 3182b15cb3dSCy Schubert for (alloc = authallocs; alloc != NULL; alloc = next_alloc) { 3192b15cb3dSCy Schubert next_alloc = alloc->link; 3202b15cb3dSCy Schubert free(alloc->mem); 3212b15cb3dSCy Schubert } 3222b15cb3dSCy Schubert authfreekeys = NULL; 3232b15cb3dSCy Schubert authnumfreekeys = 0; 3242b15cb3dSCy Schubert } 3252b15cb3dSCy Schubert #endif /* DEBUG */ 3262b15cb3dSCy Schubert 3272b15cb3dSCy Schubert 3282b15cb3dSCy Schubert /* 3292b15cb3dSCy Schubert * auth_moremem - get some more free key structures 3302b15cb3dSCy Schubert */ 3312b15cb3dSCy Schubert void 3322b15cb3dSCy Schubert auth_moremem( 3332b15cb3dSCy Schubert int keycount 3342b15cb3dSCy Schubert ) 3352b15cb3dSCy Schubert { 3362b15cb3dSCy Schubert symkey * sk; 3372b15cb3dSCy Schubert int i; 3382b15cb3dSCy Schubert #ifdef DEBUG 3392b15cb3dSCy Schubert void * base; 3402b15cb3dSCy Schubert symkey_alloc * allocrec; 3412b15cb3dSCy Schubert # define MOREMEM_EXTRA_ALLOC (sizeof(*allocrec)) 3422b15cb3dSCy Schubert #else 3432b15cb3dSCy Schubert # define MOREMEM_EXTRA_ALLOC (0) 3442b15cb3dSCy Schubert #endif 3452b15cb3dSCy Schubert 3462b15cb3dSCy Schubert i = (keycount > 0) 3472b15cb3dSCy Schubert ? keycount 3482b15cb3dSCy Schubert : MEMINC; 349f0574f5cSXin LI sk = eallocarrayxz(i, sizeof(*sk), MOREMEM_EXTRA_ALLOC); 3502b15cb3dSCy Schubert #ifdef DEBUG 3512b15cb3dSCy Schubert base = sk; 3522b15cb3dSCy Schubert #endif 3532b15cb3dSCy Schubert authnumfreekeys += i; 3542b15cb3dSCy Schubert 3552b15cb3dSCy Schubert for (; i > 0; i--, sk++) { 3562b15cb3dSCy Schubert LINK_SLIST(authfreekeys, sk, llink.f); 3572b15cb3dSCy Schubert } 3582b15cb3dSCy Schubert 3592b15cb3dSCy Schubert #ifdef DEBUG 3602b15cb3dSCy Schubert allocrec = (void *)sk; 3612b15cb3dSCy Schubert allocrec->mem = base; 3622b15cb3dSCy Schubert LINK_SLIST(authallocs, allocrec, link); 3632b15cb3dSCy Schubert #endif 3642b15cb3dSCy Schubert } 3652b15cb3dSCy Schubert 3662b15cb3dSCy Schubert 3672b15cb3dSCy Schubert /* 3682b15cb3dSCy Schubert * auth_prealloc_symkeys 3692b15cb3dSCy Schubert */ 3702b15cb3dSCy Schubert void 3712b15cb3dSCy Schubert auth_prealloc_symkeys( 3722b15cb3dSCy Schubert int keycount 3732b15cb3dSCy Schubert ) 3742b15cb3dSCy Schubert { 3752b15cb3dSCy Schubert int allocated; 3762b15cb3dSCy Schubert int additional; 3772b15cb3dSCy Schubert 3782b15cb3dSCy Schubert allocated = authnumkeys + authnumfreekeys; 3792b15cb3dSCy Schubert additional = keycount - allocated; 3802b15cb3dSCy Schubert if (additional > 0) 3812b15cb3dSCy Schubert auth_moremem(additional); 3822b15cb3dSCy Schubert auth_resize_hashtable(); 3832b15cb3dSCy Schubert } 3842b15cb3dSCy Schubert 3852b15cb3dSCy Schubert 38668ba7e87SXin LI static u_short 38768ba7e87SXin LI auth_log2(size_t x) 3882b15cb3dSCy Schubert { 38968ba7e87SXin LI /* 39068ba7e87SXin LI ** bithack to calculate floor(log2(x)) 39168ba7e87SXin LI ** 39268ba7e87SXin LI ** This assumes 39368ba7e87SXin LI ** - (sizeof(size_t) is a power of two 39468ba7e87SXin LI ** - CHAR_BITS is a power of two 39568ba7e87SXin LI ** - returning zero for arguments <= 0 is OK. 39668ba7e87SXin LI ** 39768ba7e87SXin LI ** Does only shifts, masks and sums in integer arithmetic in 39868ba7e87SXin LI ** log2(CHAR_BIT*sizeof(size_t)) steps. (that is, 5/6 steps for 39968ba7e87SXin LI ** 32bit/64bit size_t) 40068ba7e87SXin LI */ 40168ba7e87SXin LI int s; 40268ba7e87SXin LI int r = 0; 40368ba7e87SXin LI size_t m = ~(size_t)0; 40468ba7e87SXin LI 40568ba7e87SXin LI for (s = sizeof(size_t) / 2 * CHAR_BIT; s != 0; s >>= 1) { 40668ba7e87SXin LI m <<= s; 40768ba7e87SXin LI if (x & m) 40868ba7e87SXin LI r += s; 40968ba7e87SXin LI else 41068ba7e87SXin LI x <<= s; 41168ba7e87SXin LI } 41268ba7e87SXin LI return (u_short)r; 4132b15cb3dSCy Schubert } 4142b15cb3dSCy Schubert 41509100258SXin LI int/*BOOL*/ 41609100258SXin LI ipaddr_match_masked(const sockaddr_u *,const sockaddr_u *, 41709100258SXin LI unsigned int mbits); 41809100258SXin LI 4194990d495SXin LI static void 4204990d495SXin LI authcache_flush_id( 4214990d495SXin LI keyid_t id 4224990d495SXin LI ) 4234990d495SXin LI { 4244990d495SXin LI if (cache_keyid == id) { 4254990d495SXin LI cache_keyid = 0; 4264990d495SXin LI cache_type = 0; 4274990d495SXin LI cache_flags = 0; 4284990d495SXin LI cache_secret = NULL; 4294990d495SXin LI cache_secretsize = 0; 4304990d495SXin LI cache_keyacclist = NULL; 4314990d495SXin LI } 4324990d495SXin LI } 4334990d495SXin LI 4342b15cb3dSCy Schubert 4352b15cb3dSCy Schubert /* 4362b15cb3dSCy Schubert * auth_resize_hashtable 4372b15cb3dSCy Schubert * 4382b15cb3dSCy Schubert * Size hash table to average 4 or fewer entries per bucket initially, 4392b15cb3dSCy Schubert * within the bounds of at least 4 and no more than 15 bits for the hash 4402b15cb3dSCy Schubert * table index. Populate the hash table. 4412b15cb3dSCy Schubert */ 4422b15cb3dSCy Schubert static void 4432b15cb3dSCy Schubert auth_resize_hashtable(void) 4442b15cb3dSCy Schubert { 4452b15cb3dSCy Schubert u_long totalkeys; 4462b15cb3dSCy Schubert u_short hashbits; 4472b15cb3dSCy Schubert u_short hash; 4482b15cb3dSCy Schubert size_t newalloc; 4492b15cb3dSCy Schubert symkey * sk; 4502b15cb3dSCy Schubert 4512b15cb3dSCy Schubert totalkeys = authnumkeys + authnumfreekeys; 45268ba7e87SXin LI hashbits = auth_log2(totalkeys / 4) + 1; 4532b15cb3dSCy Schubert hashbits = max(4, hashbits); 4542b15cb3dSCy Schubert hashbits = min(15, hashbits); 4552b15cb3dSCy Schubert 4562b15cb3dSCy Schubert authhashbuckets = 1 << hashbits; 4572b15cb3dSCy Schubert authhashmask = authhashbuckets - 1; 4582b15cb3dSCy Schubert newalloc = authhashbuckets * sizeof(key_hash[0]); 4592b15cb3dSCy Schubert 4602b15cb3dSCy Schubert key_hash = erealloc(key_hash, newalloc); 4612b15cb3dSCy Schubert memset(key_hash, '\0', newalloc); 4622b15cb3dSCy Schubert 4632b15cb3dSCy Schubert ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey) 4642b15cb3dSCy Schubert hash = KEYHASH(sk->keyid); 4652b15cb3dSCy Schubert LINK_SLIST(key_hash[hash], sk, hlink); 4662b15cb3dSCy Schubert ITER_DLIST_END() 4672b15cb3dSCy Schubert } 4682b15cb3dSCy Schubert 4692b15cb3dSCy Schubert 4702b15cb3dSCy Schubert /* 4712b15cb3dSCy Schubert * allocsymkey - common code to allocate and link in symkey 4722b15cb3dSCy Schubert * 4732b15cb3dSCy Schubert * secret must be allocated with a free-compatible allocator. It is 4742b15cb3dSCy Schubert * owned by the referring symkey structure, and will be free()d by 4752b15cb3dSCy Schubert * freesymkey(). 4762b15cb3dSCy Schubert */ 4772b15cb3dSCy Schubert static void 4782b15cb3dSCy Schubert allocsymkey( 4792b15cb3dSCy Schubert keyid_t id, 4802b15cb3dSCy Schubert u_short flags, 4812b15cb3dSCy Schubert u_short type, 4822b15cb3dSCy Schubert u_long lifetime, 4834990d495SXin LI size_t secretsize, 48468ba7e87SXin LI u_char * secret, 48568ba7e87SXin LI KeyAccT * ka 4862b15cb3dSCy Schubert ) 4872b15cb3dSCy Schubert { 4882b15cb3dSCy Schubert symkey * sk; 4894990d495SXin LI symkey ** bucket; 4904990d495SXin LI 4914990d495SXin LI bucket = &key_hash[KEYHASH(id)]; 4924990d495SXin LI 4932b15cb3dSCy Schubert 4942b15cb3dSCy Schubert if (authnumfreekeys < 1) 4952b15cb3dSCy Schubert auth_moremem(-1); 4962b15cb3dSCy Schubert UNLINK_HEAD_SLIST(sk, authfreekeys, llink.f); 4972b15cb3dSCy Schubert DEBUG_ENSURE(sk != NULL); 4982b15cb3dSCy Schubert sk->keyid = id; 4992b15cb3dSCy Schubert sk->flags = flags; 5002b15cb3dSCy Schubert sk->type = type; 5012b15cb3dSCy Schubert sk->secretsize = secretsize; 5022b15cb3dSCy Schubert sk->secret = secret; 50368ba7e87SXin LI sk->keyacclist = ka; 5042b15cb3dSCy Schubert sk->lifetime = lifetime; 5052b15cb3dSCy Schubert LINK_SLIST(*bucket, sk, hlink); 5062b15cb3dSCy Schubert LINK_TAIL_DLIST(key_listhead, sk, llink); 5072b15cb3dSCy Schubert authnumfreekeys--; 5082b15cb3dSCy Schubert authnumkeys++; 5092b15cb3dSCy Schubert } 5102b15cb3dSCy Schubert 5112b15cb3dSCy Schubert 5122b15cb3dSCy Schubert /* 5132b15cb3dSCy Schubert * freesymkey - common code to remove a symkey and recycle its entry. 5142b15cb3dSCy Schubert */ 5152b15cb3dSCy Schubert static void 5162b15cb3dSCy Schubert freesymkey( 5174990d495SXin LI symkey * sk 5182b15cb3dSCy Schubert ) 5192b15cb3dSCy Schubert { 5204990d495SXin LI symkey ** bucket; 5212b15cb3dSCy Schubert symkey * unlinked; 5222b15cb3dSCy Schubert 5234990d495SXin LI if (NULL == sk) 5244990d495SXin LI return; 5254990d495SXin LI 5264990d495SXin LI authcache_flush_id(sk->keyid); 5274990d495SXin LI keyacc_all_free(sk->keyacclist); 5284990d495SXin LI 5294990d495SXin LI bucket = &key_hash[KEYHASH(sk->keyid)]; 5302b15cb3dSCy Schubert if (sk->secret != NULL) { 5312b15cb3dSCy Schubert memset(sk->secret, '\0', sk->secretsize); 5322b15cb3dSCy Schubert free(sk->secret); 5332b15cb3dSCy Schubert } 5342b15cb3dSCy Schubert UNLINK_SLIST(unlinked, *bucket, sk, hlink, symkey); 5352b15cb3dSCy Schubert DEBUG_ENSURE(sk == unlinked); 5362b15cb3dSCy Schubert UNLINK_DLIST(sk, llink); 5372b15cb3dSCy Schubert memset((char *)sk + offsetof(symkey, symkey_payload), '\0', 5382b15cb3dSCy Schubert sizeof(*sk) - offsetof(symkey, symkey_payload)); 5392b15cb3dSCy Schubert LINK_SLIST(authfreekeys, sk, llink.f); 5402b15cb3dSCy Schubert authnumkeys--; 5412b15cb3dSCy Schubert authnumfreekeys++; 542c0b746e5SOllivier Robert } 543c0b746e5SOllivier Robert 544c0b746e5SOllivier Robert 545c0b746e5SOllivier Robert /* 546c0b746e5SOllivier Robert * auth_findkey - find a key in the hash table 547c0b746e5SOllivier Robert */ 548c0b746e5SOllivier Robert struct savekey * 549c0b746e5SOllivier Robert auth_findkey( 5502b15cb3dSCy Schubert keyid_t id 551c0b746e5SOllivier Robert ) 552c0b746e5SOllivier Robert { 5532b15cb3dSCy Schubert symkey * sk; 554c0b746e5SOllivier Robert 5554990d495SXin LI for (sk = key_hash[KEYHASH(id)]; sk != NULL; sk = sk->hlink) 5564990d495SXin LI if (id == sk->keyid) 5572b15cb3dSCy Schubert return sk; 5582b15cb3dSCy Schubert return NULL; 559c0b746e5SOllivier Robert } 560c0b746e5SOllivier Robert 561c0b746e5SOllivier Robert 562c0b746e5SOllivier Robert /* 5634990d495SXin LI * auth_havekey - return TRUE if the key id is zero or known. The 5644990d495SXin LI * key needs not to be trusted. 565c0b746e5SOllivier Robert */ 566c0b746e5SOllivier Robert int 567c0b746e5SOllivier Robert auth_havekey( 5682b15cb3dSCy Schubert keyid_t id 569c0b746e5SOllivier Robert ) 570c0b746e5SOllivier Robert { 5714990d495SXin LI return 5724990d495SXin LI (0 == id) || 5734990d495SXin LI (cache_keyid == id) || 5744990d495SXin LI (NULL != auth_findkey(id)); 575c0b746e5SOllivier Robert } 576c0b746e5SOllivier Robert 577c0b746e5SOllivier Robert 578c0b746e5SOllivier Robert /* 5792b15cb3dSCy Schubert * authhavekey - return TRUE and cache the key, if zero or both known 5802b15cb3dSCy Schubert * and trusted. 581c0b746e5SOllivier Robert */ 582c0b746e5SOllivier Robert int 583c0b746e5SOllivier Robert authhavekey( 5842b15cb3dSCy Schubert keyid_t id 585c0b746e5SOllivier Robert ) 586c0b746e5SOllivier Robert { 5872b15cb3dSCy Schubert symkey * sk; 588c0b746e5SOllivier Robert 589c0b746e5SOllivier Robert authkeylookups++; 5904990d495SXin LI if (0 == id || cache_keyid == id) 5914990d495SXin LI return !!(KEY_TRUSTED & cache_flags); 592c0b746e5SOllivier Robert 593c0b746e5SOllivier Robert /* 5944990d495SXin LI * Search the bin for the key. If not found, or found but the key 5954990d495SXin LI * type is zero, somebody marked it trusted without specifying a 5964990d495SXin LI * key or key type. In this case consider the key missing. 597c0b746e5SOllivier Robert */ 5982b15cb3dSCy Schubert authkeyuncached++; 5994990d495SXin LI sk = auth_findkey(id); 6004990d495SXin LI if ((sk == NULL) || (sk->type == 0)) { 6012b15cb3dSCy Schubert authkeynotfound++; 6022b15cb3dSCy Schubert return FALSE; 603c0b746e5SOllivier Robert } 6042b15cb3dSCy Schubert 6052b15cb3dSCy Schubert /* 6064990d495SXin LI * If the key is not trusted, the key is not considered found. 6072b15cb3dSCy Schubert */ 6082b15cb3dSCy Schubert if ( ! (KEY_TRUSTED & sk->flags)) { 6092b15cb3dSCy Schubert authnokey++; 6102b15cb3dSCy Schubert return FALSE; 6112b15cb3dSCy Schubert } 6122b15cb3dSCy Schubert 6132b15cb3dSCy Schubert /* 6142b15cb3dSCy Schubert * The key is found and trusted. Initialize the key cache. 6152b15cb3dSCy Schubert */ 6162b15cb3dSCy Schubert cache_keyid = sk->keyid; 6172b15cb3dSCy Schubert cache_type = sk->type; 6182b15cb3dSCy Schubert cache_flags = sk->flags; 6192b15cb3dSCy Schubert cache_secret = sk->secret; 6202b15cb3dSCy Schubert cache_secretsize = sk->secretsize; 62168ba7e87SXin LI cache_keyacclist = sk->keyacclist; 6222b15cb3dSCy Schubert 6232b15cb3dSCy Schubert return TRUE; 624c0b746e5SOllivier Robert } 625c0b746e5SOllivier Robert 626c0b746e5SOllivier Robert 627c0b746e5SOllivier Robert /* 628c0b746e5SOllivier Robert * authtrust - declare a key to be trusted/untrusted 629c0b746e5SOllivier Robert */ 630c0b746e5SOllivier Robert void 631c0b746e5SOllivier Robert authtrust( 6322b15cb3dSCy Schubert keyid_t id, 633224ba2bdSOllivier Robert u_long trust 634c0b746e5SOllivier Robert ) 635c0b746e5SOllivier Robert { 6362b15cb3dSCy Schubert symkey * sk; 6372b15cb3dSCy Schubert u_long lifetime; 638c0b746e5SOllivier Robert 6392b15cb3dSCy Schubert /* 6402b15cb3dSCy Schubert * Search bin for key; if it does not exist and is untrusted, 6412b15cb3dSCy Schubert * forget it. 6422b15cb3dSCy Schubert */ 6434990d495SXin LI 6444990d495SXin LI sk = auth_findkey(id); 6454990d495SXin LI if (!trust && sk == NULL) 646c0b746e5SOllivier Robert return; 647c0b746e5SOllivier Robert 6482b15cb3dSCy Schubert /* 6492b15cb3dSCy Schubert * There are two conditions remaining. Either it does not 6502b15cb3dSCy Schubert * exist and is to be trusted or it does exist and is or is 6512b15cb3dSCy Schubert * not to be trusted. 6522b15cb3dSCy Schubert */ 6532b15cb3dSCy Schubert if (sk != NULL) { 6542b15cb3dSCy Schubert /* 6554990d495SXin LI * Key exists. If it is to be trusted, say so and update 6564990d495SXin LI * its lifetime. If no longer trusted, return it to the 6574990d495SXin LI * free list. Flush the cache first to be sure there are 6584990d495SXin LI * no discrepancies. 6592b15cb3dSCy Schubert */ 6604990d495SXin LI authcache_flush_id(id); 661c0b746e5SOllivier Robert if (trust > 0) { 662c0b746e5SOllivier Robert sk->flags |= KEY_TRUSTED; 663c0b746e5SOllivier Robert if (trust > 1) 664c0b746e5SOllivier Robert sk->lifetime = current_time + trust; 665c0b746e5SOllivier Robert else 666c0b746e5SOllivier Robert sk->lifetime = 0; 6674990d495SXin LI } else { 6684990d495SXin LI freesymkey(sk); 669c0b746e5SOllivier Robert } 6702b15cb3dSCy Schubert return; 6712b15cb3dSCy Schubert } 672c0b746e5SOllivier Robert 6732b15cb3dSCy Schubert /* 6742b15cb3dSCy Schubert * keyid is not present, but the is to be trusted. We allocate 6752b15cb3dSCy Schubert * a new key, but do not specify a key type or secret. 6762b15cb3dSCy Schubert */ 6772b15cb3dSCy Schubert if (trust > 1) { 6782b15cb3dSCy Schubert lifetime = current_time + trust; 679c0b746e5SOllivier Robert } else { 6802b15cb3dSCy Schubert lifetime = 0; 681c0b746e5SOllivier Robert } 6824990d495SXin LI allocsymkey(id, KEY_TRUSTED, 0, lifetime, 0, NULL, NULL); 683c0b746e5SOllivier Robert } 684c0b746e5SOllivier Robert 685c0b746e5SOllivier Robert 686c0b746e5SOllivier Robert /* 687c0b746e5SOllivier Robert * authistrusted - determine whether a key is trusted 688c0b746e5SOllivier Robert */ 689c0b746e5SOllivier Robert int 690c0b746e5SOllivier Robert authistrusted( 6914990d495SXin LI keyid_t id 692c0b746e5SOllivier Robert ) 693c0b746e5SOllivier Robert { 6942b15cb3dSCy Schubert symkey * sk; 695c0b746e5SOllivier Robert 6964990d495SXin LI if (id == cache_keyid) 6972b15cb3dSCy Schubert return !!(KEY_TRUSTED & cache_flags); 698c0b746e5SOllivier Robert 699c0b746e5SOllivier Robert authkeyuncached++; 7004990d495SXin LI sk = auth_findkey(id); 7014990d495SXin LI if (sk == NULL || !(KEY_TRUSTED & sk->flags)) { 702c0b746e5SOllivier Robert authkeynotfound++; 7032b15cb3dSCy Schubert return FALSE; 704c0b746e5SOllivier Robert } 7052b15cb3dSCy Schubert return TRUE; 706c0b746e5SOllivier Robert } 707c0b746e5SOllivier Robert 70868ba7e87SXin LI 70968ba7e87SXin LI /* 71068ba7e87SXin LI * authistrustedip - determine if the IP is OK for the keyid 71168ba7e87SXin LI */ 71268ba7e87SXin LI int 71368ba7e87SXin LI authistrustedip( 71468ba7e87SXin LI keyid_t keyno, 71568ba7e87SXin LI sockaddr_u * sau 71668ba7e87SXin LI ) 71768ba7e87SXin LI { 71868ba7e87SXin LI symkey * sk; 71968ba7e87SXin LI 7204990d495SXin LI if (keyno == cache_keyid) { 7214990d495SXin LI return (KEY_TRUSTED & cache_flags) && 7224990d495SXin LI keyacc_contains(cache_keyacclist, sau, TRUE); 72309100258SXin LI } 72409100258SXin LI 72509100258SXin LI if (NULL != (sk = auth_findkey(keyno))) { 72668ba7e87SXin LI authkeyuncached++; 7274990d495SXin LI return (KEY_TRUSTED & sk->flags) && 7284990d495SXin LI keyacc_contains(sk->keyacclist, sau, TRUE); 72968ba7e87SXin LI } 73009100258SXin LI 73109100258SXin LI authkeynotfound++; 73209100258SXin LI return FALSE; 73368ba7e87SXin LI } 73468ba7e87SXin LI 7353311ff84SXin LI /* Note: There are two locations below where 'strncpy()' is used. While 7363311ff84SXin LI * this function is a hazard by itself, it's essential that it is used 7373311ff84SXin LI * here. Bug 1243 involved that the secret was filled with NUL bytes 7383311ff84SXin LI * after the first NUL encountered, and 'strlcpy()' simply does NOT have 7393311ff84SXin LI * this behaviour. So disabling the fix and reverting to the buggy 7403311ff84SXin LI * behaviour due to compatibility issues MUST also fill with NUL and 7413311ff84SXin LI * this needs 'strncpy'. Also, the secret is managed as a byte blob of a 7423311ff84SXin LI * given size, and eventually truncating it and replacing the last byte 7433311ff84SXin LI * with a NUL would be a bug. 7443311ff84SXin LI * perlinger@ntp.org 2015-10-10 7453311ff84SXin LI */ 746c0b746e5SOllivier Robert void 747c0b746e5SOllivier Robert MD5auth_setkey( 748224ba2bdSOllivier Robert keyid_t keyno, 7492b15cb3dSCy Schubert int keytype, 750c0b746e5SOllivier Robert const u_char *key, 7514990d495SXin LI size_t secretsize, 75268ba7e87SXin LI KeyAccT *ka 753c0b746e5SOllivier Robert ) 754c0b746e5SOllivier Robert { 7552b15cb3dSCy Schubert symkey * sk; 7562b15cb3dSCy Schubert u_char * secret; 757c0b746e5SOllivier Robert 7582b15cb3dSCy Schubert DEBUG_ENSURE(keytype <= USHRT_MAX); 7594990d495SXin LI DEBUG_ENSURE(secretsize < 4 * 1024); 760c0b746e5SOllivier Robert /* 761c0b746e5SOllivier Robert * See if we already have the key. If so just stick in the 762c0b746e5SOllivier Robert * new value. 763c0b746e5SOllivier Robert */ 7644990d495SXin LI sk = auth_findkey(keyno); 7654990d495SXin LI if (sk != NULL && keyno == sk->keyid) { 7669034852cSGleb Smirnoff /* TALOS-CAN-0054: make sure we have a new buffer! */ 7679034852cSGleb Smirnoff if (NULL != sk->secret) { 7689034852cSGleb Smirnoff memset(sk->secret, 0, sk->secretsize); 7699034852cSGleb Smirnoff free(sk->secret); 7709034852cSGleb Smirnoff } 7714990d495SXin LI sk->secret = emalloc(secretsize + 1); 7722b15cb3dSCy Schubert sk->type = (u_short)keytype; 7734990d495SXin LI sk->secretsize = secretsize; 7744990d495SXin LI /* make sure access lists don't leak here! */ 7754990d495SXin LI if (ka != sk->keyacclist) { 7764990d495SXin LI keyacc_all_free(sk->keyacclist); 77768ba7e87SXin LI sk->keyacclist = ka; 7784990d495SXin LI } 7792b15cb3dSCy Schubert #ifndef DISABLE_BUG1243_FIX 7802b15cb3dSCy Schubert memcpy(sk->secret, key, secretsize); 7812b15cb3dSCy Schubert #else 7823311ff84SXin LI /* >MUST< use 'strncpy()' here! See above! */ 7833311ff84SXin LI strncpy((char *)sk->secret, (const char *)key, 7842b15cb3dSCy Schubert secretsize); 7852b15cb3dSCy Schubert #endif 7864990d495SXin LI authcache_flush_id(keyno); 787c0b746e5SOllivier Robert return; 788c0b746e5SOllivier Robert } 789c0b746e5SOllivier Robert 790c0b746e5SOllivier Robert /* 791c0b746e5SOllivier Robert * Need to allocate new structure. Do it. 792c0b746e5SOllivier Robert */ 7934990d495SXin LI secret = emalloc(secretsize + 1); 7942b15cb3dSCy Schubert #ifndef DISABLE_BUG1243_FIX 7952b15cb3dSCy Schubert memcpy(secret, key, secretsize); 7962b15cb3dSCy Schubert #else 7973311ff84SXin LI /* >MUST< use 'strncpy()' here! See above! */ 7983311ff84SXin LI strncpy((char *)secret, (const char *)key, secretsize); 7992b15cb3dSCy Schubert #endif 8004990d495SXin LI allocsymkey(keyno, 0, (u_short)keytype, 0, 8014990d495SXin LI secretsize, secret, ka); 8022b15cb3dSCy Schubert #ifdef DEBUG 8032b15cb3dSCy Schubert if (debug >= 4) { 8042b15cb3dSCy Schubert size_t j; 8052b15cb3dSCy Schubert 8062b15cb3dSCy Schubert printf("auth_setkey: key %d type %d len %d ", (int)keyno, 8072b15cb3dSCy Schubert keytype, (int)secretsize); 8084990d495SXin LI for (j = 0; j < secretsize; j++) { 8092b15cb3dSCy Schubert printf("%02x", secret[j]); 8104990d495SXin LI } 8112b15cb3dSCy Schubert printf("\n"); 8122b15cb3dSCy Schubert } 8132b15cb3dSCy Schubert #endif 814c0b746e5SOllivier Robert } 815c0b746e5SOllivier Robert 816c0b746e5SOllivier Robert 817c0b746e5SOllivier Robert /* 8182b15cb3dSCy Schubert * auth_delkeys - delete non-autokey untrusted keys, and clear all info 8192b15cb3dSCy Schubert * except the trusted bit of non-autokey trusted keys, in 8202b15cb3dSCy Schubert * preparation for rereading the keys file. 821c0b746e5SOllivier Robert */ 822c0b746e5SOllivier Robert void 823c0b746e5SOllivier Robert auth_delkeys(void) 824c0b746e5SOllivier Robert { 8252b15cb3dSCy Schubert symkey * sk; 826c0b746e5SOllivier Robert 8272b15cb3dSCy Schubert ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey) 8282b15cb3dSCy Schubert if (sk->keyid > NTP_MAXKEY) { /* autokey */ 8292b15cb3dSCy Schubert continue; 8302b15cb3dSCy Schubert } 8312b15cb3dSCy Schubert 832c0b746e5SOllivier Robert /* 8339034852cSGleb Smirnoff * Don't lose info as to which keys are trusted. Make 8349034852cSGleb Smirnoff * sure there are no dangling pointers! 835c0b746e5SOllivier Robert */ 8362b15cb3dSCy Schubert if (KEY_TRUSTED & sk->flags) { 8372b15cb3dSCy Schubert if (sk->secret != NULL) { 8389034852cSGleb Smirnoff memset(sk->secret, 0, sk->secretsize); 8392b15cb3dSCy Schubert free(sk->secret); 8409034852cSGleb Smirnoff sk->secret = NULL; /* TALOS-CAN-0054 */ 8412b15cb3dSCy Schubert } 8424990d495SXin LI sk->keyacclist = keyacc_all_free(sk->keyacclist); 8432b15cb3dSCy Schubert sk->secretsize = 0; 844c0b746e5SOllivier Robert sk->lifetime = 0; 845c0b746e5SOllivier Robert } else { 8464990d495SXin LI freesymkey(sk); 847c0b746e5SOllivier Robert } 8482b15cb3dSCy Schubert ITER_DLIST_END() 849c0b746e5SOllivier Robert } 8502b15cb3dSCy Schubert 851c0b746e5SOllivier Robert 852c0b746e5SOllivier Robert /* 853c0b746e5SOllivier Robert * auth_agekeys - delete keys whose lifetimes have expired 854c0b746e5SOllivier Robert */ 855c0b746e5SOllivier Robert void 856c0b746e5SOllivier Robert auth_agekeys(void) 857c0b746e5SOllivier Robert { 8582b15cb3dSCy Schubert symkey * sk; 859c0b746e5SOllivier Robert 8602b15cb3dSCy Schubert ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey) 8612b15cb3dSCy Schubert if (sk->lifetime > 0 && current_time > sk->lifetime) { 8624990d495SXin LI freesymkey(sk); 863c0b746e5SOllivier Robert authkeyexpired++; 864c0b746e5SOllivier Robert } 8652b15cb3dSCy Schubert ITER_DLIST_END() 8662b15cb3dSCy Schubert DPRINTF(1, ("auth_agekeys: at %lu keys %lu expired %lu\n", 8672b15cb3dSCy Schubert current_time, authnumkeys, authkeyexpired)); 868c0b746e5SOllivier Robert } 8692b15cb3dSCy Schubert 870c0b746e5SOllivier Robert 871c0b746e5SOllivier Robert /* 872c0b746e5SOllivier Robert * authencrypt - generate message authenticator 873c0b746e5SOllivier Robert * 874c0b746e5SOllivier Robert * Returns length of authenticator field, zero if key not found. 875c0b746e5SOllivier Robert */ 8763311ff84SXin LI size_t 877c0b746e5SOllivier Robert authencrypt( 878224ba2bdSOllivier Robert keyid_t keyno, 879c0b746e5SOllivier Robert u_int32 * pkt, 8803311ff84SXin LI size_t length 881c0b746e5SOllivier Robert ) 8823311ff84SXin LI { 883c0b746e5SOllivier Robert /* 884c0b746e5SOllivier Robert * A zero key identifier means the sender has not verified 885c0b746e5SOllivier Robert * the last message was correctly authenticated. The MAC 886c0b746e5SOllivier Robert * consists of a single word with value zero. 887c0b746e5SOllivier Robert */ 888c0b746e5SOllivier Robert authencryptions++; 889224ba2bdSOllivier Robert pkt[length / 4] = htonl(keyno); 8902b15cb3dSCy Schubert if (0 == keyno) { 8912b15cb3dSCy Schubert return 4; 892c0b746e5SOllivier Robert } 8932b15cb3dSCy Schubert if (!authhavekey(keyno)) { 8942b15cb3dSCy Schubert return 0; 895c0b746e5SOllivier Robert } 896c0b746e5SOllivier Robert 89709100258SXin LI return MD5authencrypt(cache_type, 89809100258SXin LI cache_secret, cache_secretsize, 89909100258SXin LI pkt, length); 9002b15cb3dSCy Schubert } 9012b15cb3dSCy Schubert 9022b15cb3dSCy Schubert 903c0b746e5SOllivier Robert /* 904c0b746e5SOllivier Robert * authdecrypt - verify message authenticator 905c0b746e5SOllivier Robert * 9062b15cb3dSCy Schubert * Returns TRUE if authenticator valid, FALSE if invalid or not found. 907c0b746e5SOllivier Robert */ 908c0b746e5SOllivier Robert int 909c0b746e5SOllivier Robert authdecrypt( 910224ba2bdSOllivier Robert keyid_t keyno, 911c0b746e5SOllivier Robert u_int32 * pkt, 9123311ff84SXin LI size_t length, 9133311ff84SXin LI size_t size 914c0b746e5SOllivier Robert ) 915c0b746e5SOllivier Robert { 916c0b746e5SOllivier Robert /* 917c0b746e5SOllivier Robert * A zero key identifier means the sender has not verified 9182b15cb3dSCy Schubert * the last message was correctly authenticated. For our 9192b15cb3dSCy Schubert * purpose this is an invalid authenticator. 920c0b746e5SOllivier Robert */ 921c0b746e5SOllivier Robert authdecryptions++; 9222b15cb3dSCy Schubert if (0 == keyno || !authhavekey(keyno) || size < 4) { 9232b15cb3dSCy Schubert return FALSE; 9242b15cb3dSCy Schubert } 925c0b746e5SOllivier Robert 92609100258SXin LI return MD5authdecrypt(cache_type, 92709100258SXin LI cache_secret, cache_secretsize, 928*a466cc55SCy Schubert pkt, length, size, keyno); 929*a466cc55SCy Schubert } 930*a466cc55SCy Schubert 931*a466cc55SCy Schubert /* password decoding helpers */ 932*a466cc55SCy Schubert static size_t 933*a466cc55SCy Schubert pwdecode_plain( 934*a466cc55SCy Schubert u_char * dst, 935*a466cc55SCy Schubert size_t dstlen, 936*a466cc55SCy Schubert const char * src 937*a466cc55SCy Schubert ) 938*a466cc55SCy Schubert { 939*a466cc55SCy Schubert size_t srclen = strlen(src); 940*a466cc55SCy Schubert if (srclen > dstlen) { 941*a466cc55SCy Schubert errno = ENOMEM; 942*a466cc55SCy Schubert return (size_t)-1; 943*a466cc55SCy Schubert } 944*a466cc55SCy Schubert memcpy(dst, src, srclen); 945*a466cc55SCy Schubert return srclen; 946*a466cc55SCy Schubert } 947*a466cc55SCy Schubert 948*a466cc55SCy Schubert static size_t 949*a466cc55SCy Schubert pwdecode_hex( 950*a466cc55SCy Schubert u_char * dst, 951*a466cc55SCy Schubert size_t dstlen, 952*a466cc55SCy Schubert const char * src 953*a466cc55SCy Schubert ) 954*a466cc55SCy Schubert { 955*a466cc55SCy Schubert static const char hex[] = "00112233445566778899AaBbCcDdEeFf"; 956*a466cc55SCy Schubert 957*a466cc55SCy Schubert size_t srclen = strlen(src); 958*a466cc55SCy Schubert size_t reslen = (srclen >> 1) + (srclen & 1); 959*a466cc55SCy Schubert u_char tmp; 960*a466cc55SCy Schubert char *ptr; 961*a466cc55SCy Schubert size_t j; 962*a466cc55SCy Schubert 963*a466cc55SCy Schubert if (reslen > dstlen) { 964*a466cc55SCy Schubert errno = ENOMEM; 965*a466cc55SCy Schubert reslen = (size_t)-1; 966*a466cc55SCy Schubert } else { 967*a466cc55SCy Schubert for (j = 0; j < srclen; ++j) { 968*a466cc55SCy Schubert tmp = *(const unsigned char*)(src + j); 969*a466cc55SCy Schubert ptr = strchr(hex, tmp); 970*a466cc55SCy Schubert if (ptr == NULL) { 971*a466cc55SCy Schubert errno = EINVAL; 972*a466cc55SCy Schubert reslen = (size_t)-1; 973*a466cc55SCy Schubert break; 974*a466cc55SCy Schubert } 975*a466cc55SCy Schubert tmp = (u_char)((ptr - hex) > 1); 976*a466cc55SCy Schubert if (j & 1) 977*a466cc55SCy Schubert dst[j >> 1] |= tmp; 978*a466cc55SCy Schubert else 979*a466cc55SCy Schubert dst[j >> 1] = tmp << 4; 980*a466cc55SCy Schubert } 981*a466cc55SCy Schubert } 982*a466cc55SCy Schubert return reslen; 983*a466cc55SCy Schubert } 984*a466cc55SCy Schubert /* 985*a466cc55SCy Schubert * authdecodepw - decode plaintext or hex-encoded password to binary 986*a466cc55SCy Schubert * secret. Returns size of secret in bytes or -1 on error. 987*a466cc55SCy Schubert */ 988*a466cc55SCy Schubert size_t 989*a466cc55SCy Schubert authdecodepw( 990*a466cc55SCy Schubert u_char * dst, 991*a466cc55SCy Schubert size_t dstlen, 992*a466cc55SCy Schubert const char * src, 993*a466cc55SCy Schubert enum AuthPwdEnc enc 994*a466cc55SCy Schubert ) 995*a466cc55SCy Schubert { 996*a466cc55SCy Schubert size_t reslen; 997*a466cc55SCy Schubert 998*a466cc55SCy Schubert if ( !(dst && dstlen && src)) { 999*a466cc55SCy Schubert errno = EINVAL; 1000*a466cc55SCy Schubert reslen = (size_t)-1; 1001*a466cc55SCy Schubert } else { 1002*a466cc55SCy Schubert switch (enc) { 1003*a466cc55SCy Schubert case AUTHPWD_UNSPEC: 1004*a466cc55SCy Schubert if (strlen(src) <= 20) 1005*a466cc55SCy Schubert reslen = pwdecode_plain(dst, dstlen, src); 1006*a466cc55SCy Schubert else 1007*a466cc55SCy Schubert reslen = pwdecode_hex(dst, dstlen, src); 1008*a466cc55SCy Schubert break; 1009*a466cc55SCy Schubert case AUTHPWD_PLAIN: 1010*a466cc55SCy Schubert reslen = pwdecode_plain(dst, dstlen, src); 1011*a466cc55SCy Schubert break; 1012*a466cc55SCy Schubert case AUTHPWD_HEX: 1013*a466cc55SCy Schubert reslen = pwdecode_hex(dst, dstlen, src); 1014*a466cc55SCy Schubert break; 1015*a466cc55SCy Schubert default: 1016*a466cc55SCy Schubert errno = EINVAL; 1017*a466cc55SCy Schubert reslen = (size_t)-1; 1018*a466cc55SCy Schubert } 1019*a466cc55SCy Schubert } 1020*a466cc55SCy Schubert return reslen; 1021c0b746e5SOllivier Robert } 1022