xref: /freebsd/contrib/ntp/libntp/authkeys.c (revision 9034852c84a13f0e3b5527e1c886ca94b2863b2b)
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