154359Sroberto/*
254359Sroberto * authkeys.c - routines to manage the storage of authentication keys
354359Sroberto */
454359Sroberto#ifdef HAVE_CONFIG_H
554359Sroberto# include <config.h>
654359Sroberto#endif
754359Sroberto
8285612Sdelphij#include <math.h>
954359Sroberto#include <stdio.h>
1054359Sroberto
11285612Sdelphij#include "ntp.h"
1254359Sroberto#include "ntp_fp.h"
1354359Sroberto#include "ntpd.h"
14285612Sdelphij#include "ntp_lists.h"
1554359Sroberto#include "ntp_string.h"
1654359Sroberto#include "ntp_malloc.h"
1754359Sroberto#include "ntp_stdlib.h"
18294904Sdelphij#include "ntp_keyacc.h"
1954359Sroberto
2054359Sroberto/*
2154359Sroberto * Structure to store keys in in the hash table.
2254359Sroberto */
23285612Sdelphijtypedef struct savekey symkey;
24285612Sdelphij
2554359Srobertostruct savekey {
26285612Sdelphij	symkey *	hlink;		/* next in hash bucket */
27285612Sdelphij	DECL_DLIST_LINK(symkey, llink);	/* for overall & free lists */
28285612Sdelphij	u_char *	secret;		/* shared secret */
29294904Sdelphij	KeyAccT *	keyacclist;	/* Private key access list */
30285612Sdelphij	u_long		lifetime;	/* remaining lifetime */
31285612Sdelphij	keyid_t		keyid;		/* key identifier */
32285612Sdelphij	u_short		type;		/* OpenSSL digest NID */
33298770Sdelphij	size_t		secretsize;	/* secret octets */
34285612Sdelphij	u_short		flags;		/* KEY_ flags that wave */
3554359Sroberto};
3654359Sroberto
37285612Sdelphij/* define the payload region of symkey beyond the list pointers */
38285612Sdelphij#define symkey_payload	secret
39285612Sdelphij
4054359Sroberto#define	KEY_TRUSTED	0x001	/* this key is trusted */
4154359Sroberto
42285612Sdelphij#ifdef DEBUG
43285612Sdelphijtypedef struct symkey_alloc_tag symkey_alloc;
44285612Sdelphij
45285612Sdelphijstruct symkey_alloc_tag {
46285612Sdelphij	symkey_alloc *	link;
47285612Sdelphij	void *		mem;		/* enable free() atexit */
48285612Sdelphij};
49285612Sdelphij
50285612Sdelphijsymkey_alloc *	authallocs;
51285612Sdelphij#endif	/* DEBUG */
52285612Sdelphij
53294904Sdelphijstatic u_short	auth_log2(size_t);
54298770Sdelphijstatic void		auth_resize_hashtable(void);
55298770Sdelphijstatic void		allocsymkey(keyid_t,	u_short,
56298770Sdelphij				    u_short, u_long, size_t, u_char *, KeyAccT *);
57298770Sdelphijstatic void		freesymkey(symkey *);
58285612Sdelphij#ifdef DEBUG
59298770Sdelphijstatic void		free_auth_mem(void);
60285612Sdelphij#endif
61285612Sdelphij
62285612Sdelphijsymkey	key_listhead;		/* list of all in-use keys */;
6354359Sroberto/*
6454359Sroberto * The hash table. This is indexed by the low order bits of the
6554359Sroberto * keyid. We make this fairly big for potentially busy servers.
6654359Sroberto */
67285612Sdelphij#define	DEF_AUTHHASHSIZE	64
68293893Sglebius/*#define	HASHMASK	((HASHSIZE)-1)*/
69285612Sdelphij#define	KEYHASH(keyid)	((keyid) & authhashmask)
7054359Sroberto
71285612Sdelphijint	authhashdisabled;
72285612Sdelphiju_short	authhashbuckets = DEF_AUTHHASHSIZE;
73285612Sdelphiju_short authhashmask = DEF_AUTHHASHSIZE - 1;
74285612Sdelphijsymkey **key_hash;
7554359Sroberto
7654359Srobertou_long authkeynotfound;		/* keys not found */
7754359Srobertou_long authkeylookups;		/* calls to lookup keys */
7854359Srobertou_long authnumkeys;		/* number of active keys */
7954359Srobertou_long authkeyexpired;		/* key lifetime expirations */
8054359Srobertou_long authkeyuncached;		/* cache misses */
8154359Srobertou_long authnokey;		/* calls to encrypt with no key */
8254359Srobertou_long authencryptions;		/* calls to encrypt */
8354359Srobertou_long authdecryptions;		/* calls to decrypt */
8454359Sroberto
8554359Sroberto/*
86285612Sdelphij * Storage for free symkey structures.  We malloc() such things but
8754359Sroberto * never free them.
8854359Sroberto */
89285612Sdelphijsymkey *authfreekeys;
9054359Srobertoint authnumfreekeys;
9154359Sroberto
92285612Sdelphij#define	MEMINC	16		/* number of new free ones to get */
9354359Sroberto
9454359Sroberto/*
9554359Sroberto * The key cache. We cache the last key we looked at here.
96298770Sdelphij * Note: this should hold the last *trusted* key. Also the
97298770Sdelphij * cache is only loaded when the digest type / MAC algorithm
98298770Sdelphij * is valid.
9954359Sroberto */
10082498Srobertokeyid_t	cache_keyid;		/* key identifier */
101285612Sdelphiju_char *cache_secret;		/* secret */
102298770Sdelphijsize_t	cache_secretsize;	/* secret length */
103285612Sdelphijint	cache_type;		/* OpenSSL digest NID */
10454359Srobertou_short cache_flags;		/* flags that wave */
105294904SdelphijKeyAccT *cache_keyacclist;	/* key access list */
10654359Sroberto
107298770Sdelphij/* --------------------------------------------------------------------
108298770Sdelphij * manage key access lists
109298770Sdelphij * --------------------------------------------------------------------
110298770Sdelphij */
111298770Sdelphij/* allocate and populate new access node and pushes it on the list.
112298770Sdelphij * Returns the new head.
113298770Sdelphij */
114298770SdelphijKeyAccT*
115298770Sdelphijkeyacc_new_push(
116298770Sdelphij	KeyAccT          * head,
117298770Sdelphij	const sockaddr_u * addr
118298770Sdelphij	)
119298770Sdelphij{
120298770Sdelphij	KeyAccT *	node = emalloc(sizeof(KeyAccT));
121298770Sdelphij
122298770Sdelphij	memcpy(&node->addr, addr, sizeof(sockaddr_u));
123298770Sdelphij	node->next = head;
124298770Sdelphij	return node;
125298770Sdelphij}
12654359Sroberto
127298770Sdelphij/* ----------------------------------------------------------------- */
128298770Sdelphij/* pop and deallocate the first node of a list of access nodes, if
129298770Sdelphij * the list is not empty. Returns the tail of the list.
130298770Sdelphij */
131298770SdelphijKeyAccT*
132298770Sdelphijkeyacc_pop_free(
133298770Sdelphij	KeyAccT *head
134298770Sdelphij	)
135298770Sdelphij{
136298770Sdelphij	KeyAccT *	next = NULL;
137298770Sdelphij	if (head) {
138298770Sdelphij		next = head->next;
139298770Sdelphij		free(head);
140298770Sdelphij	}
141298770Sdelphij	return next;
142298770Sdelphij}
143298770Sdelphij
144298770Sdelphij/* ----------------------------------------------------------------- */
145298770Sdelphij/* deallocate the list; returns an empty list. */
146298770SdelphijKeyAccT*
147298770Sdelphijkeyacc_all_free(
148298770Sdelphij	KeyAccT * head
149298770Sdelphij	)
150298770Sdelphij{
151298770Sdelphij	while (head)
152298770Sdelphij		head = keyacc_pop_free(head);
153298770Sdelphij	return head;
154298770Sdelphij}
155298770Sdelphij
156298770Sdelphij/* ----------------------------------------------------------------- */
157298770Sdelphij/* scan a list to see if it contains a given address. Return the
158298770Sdelphij * default result value in case of an empty list.
159298770Sdelphij */
160298770Sdelphijint /*BOOL*/
161298770Sdelphijkeyacc_contains(
162298770Sdelphij	const KeyAccT    *head,
163298770Sdelphij	const sockaddr_u *addr,
164298770Sdelphij	int               defv)
165298770Sdelphij{
166298770Sdelphij	if (head) {
167298770Sdelphij		do {
168298770Sdelphij			if (SOCK_EQ(&head->addr, addr))
169298770Sdelphij				return TRUE;
170298770Sdelphij		} while (NULL != (head = head->next));
171298770Sdelphij		return FALSE;
172298770Sdelphij	} else {
173298770Sdelphij		return !!defv;
174298770Sdelphij	}
175298770Sdelphij}
176298770Sdelphij
177298770Sdelphij
17854359Sroberto/*
17954359Sroberto * init_auth - initialize internal data
18054359Sroberto */
18154359Srobertovoid
18254359Srobertoinit_auth(void)
18354359Sroberto{
184285612Sdelphij	size_t newalloc;
185285612Sdelphij
18654359Sroberto	/*
18754359Sroberto	 * Initialize hash table and free list
18854359Sroberto	 */
189285612Sdelphij	newalloc = authhashbuckets * sizeof(key_hash[0]);
190285612Sdelphij
191285612Sdelphij	key_hash = erealloc(key_hash, newalloc);
192285612Sdelphij	memset(key_hash, '\0', newalloc);
193285612Sdelphij
194285612Sdelphij	INIT_DLIST(key_listhead, llink);
195285612Sdelphij
196285612Sdelphij#ifdef DEBUG
197285612Sdelphij	atexit(&free_auth_mem);
198285612Sdelphij#endif
19954359Sroberto}
20054359Sroberto
20154359Sroberto
20254359Sroberto/*
203285612Sdelphij * free_auth_mem - assist in leak detection by freeing all dynamic
204285612Sdelphij *		   allocations from this module.
205285612Sdelphij */
206285612Sdelphij#ifdef DEBUG
207285612Sdelphijstatic void
208285612Sdelphijfree_auth_mem(void)
209285612Sdelphij{
210285612Sdelphij	symkey *	sk;
211285612Sdelphij	symkey_alloc *	alloc;
212285612Sdelphij	symkey_alloc *	next_alloc;
213285612Sdelphij
214285612Sdelphij	while (NULL != (sk = HEAD_DLIST(key_listhead, llink))) {
215298770Sdelphij		freesymkey(sk);
216285612Sdelphij	}
217285612Sdelphij	free(key_hash);
218285612Sdelphij	key_hash = NULL;
219285612Sdelphij	cache_keyid = 0;
220285612Sdelphij	cache_flags = 0;
221294904Sdelphij	cache_keyacclist = NULL;
222285612Sdelphij	for (alloc = authallocs; alloc != NULL; alloc = next_alloc) {
223285612Sdelphij		next_alloc = alloc->link;
224285612Sdelphij		free(alloc->mem);
225285612Sdelphij	}
226285612Sdelphij	authfreekeys = NULL;
227285612Sdelphij	authnumfreekeys = 0;
228285612Sdelphij}
229285612Sdelphij#endif	/* DEBUG */
230285612Sdelphij
231285612Sdelphij
232285612Sdelphij/*
233285612Sdelphij * auth_moremem - get some more free key structures
234285612Sdelphij */
235285612Sdelphijvoid
236285612Sdelphijauth_moremem(
237285612Sdelphij	int	keycount
238285612Sdelphij	)
239285612Sdelphij{
240285612Sdelphij	symkey *	sk;
241285612Sdelphij	int		i;
242285612Sdelphij#ifdef DEBUG
243285612Sdelphij	void *		base;
244285612Sdelphij	symkey_alloc *	allocrec;
245285612Sdelphij# define MOREMEM_EXTRA_ALLOC	(sizeof(*allocrec))
246285612Sdelphij#else
247285612Sdelphij# define MOREMEM_EXTRA_ALLOC	(0)
248285612Sdelphij#endif
249285612Sdelphij
250285612Sdelphij	i = (keycount > 0)
251285612Sdelphij		? keycount
252285612Sdelphij		: MEMINC;
253285612Sdelphij	sk = emalloc_zero(i * sizeof(*sk) + MOREMEM_EXTRA_ALLOC);
254285612Sdelphij#ifdef DEBUG
255285612Sdelphij	base = sk;
256285612Sdelphij#endif
257285612Sdelphij	authnumfreekeys += i;
258285612Sdelphij
259285612Sdelphij	for (; i > 0; i--, sk++) {
260285612Sdelphij		LINK_SLIST(authfreekeys, sk, llink.f);
261285612Sdelphij	}
262285612Sdelphij
263285612Sdelphij#ifdef DEBUG
264285612Sdelphij	allocrec = (void *)sk;
265285612Sdelphij	allocrec->mem = base;
266285612Sdelphij	LINK_SLIST(authallocs, allocrec, link);
267285612Sdelphij#endif
268285612Sdelphij}
269285612Sdelphij
270285612Sdelphij
271285612Sdelphij/*
272285612Sdelphij * auth_prealloc_symkeys
273285612Sdelphij */
274285612Sdelphijvoid
275285612Sdelphijauth_prealloc_symkeys(
276285612Sdelphij	int	keycount
277285612Sdelphij	)
278285612Sdelphij{
279285612Sdelphij	int	allocated;
280285612Sdelphij	int	additional;
281285612Sdelphij
282285612Sdelphij	allocated = authnumkeys + authnumfreekeys;
283285612Sdelphij	additional = keycount - allocated;
284285612Sdelphij	if (additional > 0)
285285612Sdelphij		auth_moremem(additional);
286285612Sdelphij	auth_resize_hashtable();
287285612Sdelphij}
288285612Sdelphij
289285612Sdelphij
290294904Sdelphijstatic u_short
291294904Sdelphijauth_log2(size_t x)
292285612Sdelphij{
293294904Sdelphij	/*
294294904Sdelphij	** bithack to calculate floor(log2(x))
295294904Sdelphij	**
296294904Sdelphij	** This assumes
297294904Sdelphij	**   - (sizeof(size_t) is a power of two
298294904Sdelphij	**   - CHAR_BITS is a power of two
299294904Sdelphij	**   - returning zero for arguments <= 0 is OK.
300294904Sdelphij	**
301294904Sdelphij	** Does only shifts, masks and sums in integer arithmetic in
302294904Sdelphij	** log2(CHAR_BIT*sizeof(size_t)) steps. (that is, 5/6 steps for
303294904Sdelphij	** 32bit/64bit size_t)
304294904Sdelphij	*/
305294904Sdelphij	int	s;
306294904Sdelphij	int	r = 0;
307294904Sdelphij	size_t  m = ~(size_t)0;
308294904Sdelphij
309294904Sdelphij	for (s = sizeof(size_t) / 2 * CHAR_BIT; s != 0; s >>= 1) {
310294904Sdelphij		m <<= s;
311294904Sdelphij		if (x & m)
312294904Sdelphij			r += s;
313294904Sdelphij		else
314294904Sdelphij			x <<= s;
315294904Sdelphij	}
316294904Sdelphij	return (u_short)r;
317285612Sdelphij}
318285612Sdelphij
319298770Sdelphijstatic void
320298770Sdelphijauthcache_flush_id(
321298770Sdelphij	keyid_t id
322298770Sdelphij	)
323298770Sdelphij{
324298770Sdelphij	if (cache_keyid == id) {
325298770Sdelphij		cache_keyid = 0;
326298770Sdelphij		cache_type = 0;
327298770Sdelphij		cache_flags = 0;
328298770Sdelphij		cache_secret = NULL;
329298770Sdelphij		cache_secretsize = 0;
330298770Sdelphij		cache_keyacclist = NULL;
331298770Sdelphij	}
332298770Sdelphij}
333285612Sdelphij
334298770Sdelphij
335285612Sdelphij/*
336285612Sdelphij * auth_resize_hashtable
337285612Sdelphij *
338285612Sdelphij * Size hash table to average 4 or fewer entries per bucket initially,
339285612Sdelphij * within the bounds of at least 4 and no more than 15 bits for the hash
340285612Sdelphij * table index.  Populate the hash table.
341285612Sdelphij */
342285612Sdelphijstatic void
343285612Sdelphijauth_resize_hashtable(void)
344285612Sdelphij{
345285612Sdelphij	u_long		totalkeys;
346285612Sdelphij	u_short		hashbits;
347285612Sdelphij	u_short		hash;
348285612Sdelphij	size_t		newalloc;
349285612Sdelphij	symkey *	sk;
350285612Sdelphij
351285612Sdelphij	totalkeys = authnumkeys + authnumfreekeys;
352294904Sdelphij	hashbits = auth_log2(totalkeys / 4) + 1;
353285612Sdelphij	hashbits = max(4, hashbits);
354285612Sdelphij	hashbits = min(15, hashbits);
355285612Sdelphij
356285612Sdelphij	authhashbuckets = 1 << hashbits;
357285612Sdelphij	authhashmask = authhashbuckets - 1;
358285612Sdelphij	newalloc = authhashbuckets * sizeof(key_hash[0]);
359285612Sdelphij
360285612Sdelphij	key_hash = erealloc(key_hash, newalloc);
361285612Sdelphij	memset(key_hash, '\0', newalloc);
362285612Sdelphij
363285612Sdelphij	ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey)
364285612Sdelphij		hash = KEYHASH(sk->keyid);
365285612Sdelphij		LINK_SLIST(key_hash[hash], sk, hlink);
366285612Sdelphij	ITER_DLIST_END()
367285612Sdelphij}
368285612Sdelphij
369285612Sdelphij
370285612Sdelphij/*
371285612Sdelphij * allocsymkey - common code to allocate and link in symkey
372285612Sdelphij *
373285612Sdelphij * secret must be allocated with a free-compatible allocator.  It is
374285612Sdelphij * owned by the referring symkey structure, and will be free()d by
375285612Sdelphij * freesymkey().
376285612Sdelphij */
377285612Sdelphijstatic void
378285612Sdelphijallocsymkey(
379285612Sdelphij	keyid_t		id,
380285612Sdelphij	u_short		flags,
381285612Sdelphij	u_short		type,
382285612Sdelphij	u_long		lifetime,
383298770Sdelphij	size_t		secretsize,
384294904Sdelphij	u_char *	secret,
385294904Sdelphij	KeyAccT *	ka
386285612Sdelphij	)
387285612Sdelphij{
388285612Sdelphij	symkey *	sk;
389298770Sdelphij	symkey **	bucket;
390285612Sdelphij
391298770Sdelphij	bucket = &key_hash[KEYHASH(id)];
392298770Sdelphij
393298770Sdelphij
394285612Sdelphij	if (authnumfreekeys < 1)
395285612Sdelphij		auth_moremem(-1);
396285612Sdelphij	UNLINK_HEAD_SLIST(sk, authfreekeys, llink.f);
397285612Sdelphij	DEBUG_ENSURE(sk != NULL);
398285612Sdelphij	sk->keyid = id;
399285612Sdelphij	sk->flags = flags;
400285612Sdelphij	sk->type = type;
401285612Sdelphij	sk->secretsize = secretsize;
402285612Sdelphij	sk->secret = secret;
403294904Sdelphij	sk->keyacclist = ka;
404285612Sdelphij	sk->lifetime = lifetime;
405285612Sdelphij	LINK_SLIST(*bucket, sk, hlink);
406285612Sdelphij	LINK_TAIL_DLIST(key_listhead, sk, llink);
407285612Sdelphij	authnumfreekeys--;
408285612Sdelphij	authnumkeys++;
409285612Sdelphij}
410285612Sdelphij
411285612Sdelphij
412285612Sdelphij/*
413285612Sdelphij * freesymkey - common code to remove a symkey and recycle its entry.
414285612Sdelphij */
415285612Sdelphijstatic void
416285612Sdelphijfreesymkey(
417298770Sdelphij	symkey *	sk
418285612Sdelphij	)
419285612Sdelphij{
420298770Sdelphij	symkey **	bucket;
421285612Sdelphij	symkey *	unlinked;
422285612Sdelphij
423298770Sdelphij	if (NULL == sk)
424298770Sdelphij		return;
425298770Sdelphij
426298770Sdelphij	authcache_flush_id(sk->keyid);
427298770Sdelphij	keyacc_all_free(sk->keyacclist);
428298770Sdelphij
429298770Sdelphij	bucket = &key_hash[KEYHASH(sk->keyid)];
430285612Sdelphij	if (sk->secret != NULL) {
431285612Sdelphij		memset(sk->secret, '\0', sk->secretsize);
432285612Sdelphij		free(sk->secret);
433285612Sdelphij	}
434285612Sdelphij	UNLINK_SLIST(unlinked, *bucket, sk, hlink, symkey);
435285612Sdelphij	DEBUG_ENSURE(sk == unlinked);
436285612Sdelphij	UNLINK_DLIST(sk, llink);
437285612Sdelphij	memset((char *)sk + offsetof(symkey, symkey_payload), '\0',
438285612Sdelphij	       sizeof(*sk) - offsetof(symkey, symkey_payload));
439285612Sdelphij	LINK_SLIST(authfreekeys, sk, llink.f);
440285612Sdelphij	authnumkeys--;
441285612Sdelphij	authnumfreekeys++;
442285612Sdelphij}
443285612Sdelphij
444285612Sdelphij
445285612Sdelphij/*
44654359Sroberto * auth_findkey - find a key in the hash table
44754359Sroberto */
44854359Srobertostruct savekey *
44954359Srobertoauth_findkey(
450285612Sdelphij	keyid_t		id
45154359Sroberto	)
45254359Sroberto{
453285612Sdelphij	symkey *	sk;
45454359Sroberto
455298770Sdelphij	for (sk = key_hash[KEYHASH(id)]; sk != NULL; sk = sk->hlink)
456298770Sdelphij		if (id == sk->keyid)
457285612Sdelphij			return sk;
458285612Sdelphij	return NULL;
45954359Sroberto}
46054359Sroberto
46154359Sroberto
46254359Sroberto/*
463298770Sdelphij * auth_havekey - return TRUE if the key id is zero or known. The
464298770Sdelphij * key needs not to be trusted.
46554359Sroberto */
46654359Srobertoint
46754359Srobertoauth_havekey(
468285612Sdelphij	keyid_t		id
46954359Sroberto	)
47054359Sroberto{
471298770Sdelphij	return
472298770Sdelphij	    (0           == id) ||
473298770Sdelphij	    (cache_keyid == id) ||
474298770Sdelphij	    (NULL        != auth_findkey(id));
47554359Sroberto}
47654359Sroberto
47754359Sroberto
47854359Sroberto/*
479285612Sdelphij * authhavekey - return TRUE and cache the key, if zero or both known
480285612Sdelphij *		 and trusted.
48154359Sroberto */
48254359Srobertoint
48354359Srobertoauthhavekey(
484285612Sdelphij	keyid_t		id
48554359Sroberto	)
48654359Sroberto{
487285612Sdelphij	symkey *	sk;
48854359Sroberto
48954359Sroberto	authkeylookups++;
490298770Sdelphij	if (0 == id || cache_keyid == id)
491298770Sdelphij		return !!(KEY_TRUSTED & cache_flags);
49254359Sroberto
493285612Sdelphij	/*
494298770Sdelphij	 * Search the bin for the key. If not found, or found but the key
495298770Sdelphij	 * type is zero, somebody marked it trusted without specifying a
496298770Sdelphij	 * key or key type. In this case consider the key missing.
497285612Sdelphij	 */
49854359Sroberto	authkeyuncached++;
499298770Sdelphij	sk = auth_findkey(id);
500298770Sdelphij	if ((sk == NULL) || (sk->type == 0)) {
501298770Sdelphij		authkeynotfound++;
502298770Sdelphij		return FALSE;
50354359Sroberto	}
504285612Sdelphij
505285612Sdelphij	/*
506298770Sdelphij	 * If the key is not trusted, the key is not considered found.
507285612Sdelphij	 */
508298770Sdelphij	if ( ! (KEY_TRUSTED & sk->flags)) {
50954359Sroberto		authnokey++;
510285612Sdelphij		return FALSE;
51154359Sroberto	}
512285612Sdelphij
513285612Sdelphij	/*
514285612Sdelphij	 * The key is found and trusted. Initialize the key cache.
515285612Sdelphij	 */
51654359Sroberto	cache_keyid = sk->keyid;
517285612Sdelphij	cache_type = sk->type;
51854359Sroberto	cache_flags = sk->flags;
519285612Sdelphij	cache_secret = sk->secret;
520285612Sdelphij	cache_secretsize = sk->secretsize;
521294904Sdelphij	cache_keyacclist = sk->keyacclist;
52254359Sroberto
523285612Sdelphij	return TRUE;
52454359Sroberto}
52554359Sroberto
52654359Sroberto
52754359Sroberto/*
52854359Sroberto * authtrust - declare a key to be trusted/untrusted
52954359Sroberto */
53054359Srobertovoid
53154359Srobertoauthtrust(
532285612Sdelphij	keyid_t		id,
533285612Sdelphij	u_long		trust
53454359Sroberto	)
53554359Sroberto{
536285612Sdelphij	symkey *	sk;
537285612Sdelphij	u_long		lifetime;
53854359Sroberto
539285612Sdelphij	/*
540285612Sdelphij	 * Search bin for key; if it does not exist and is untrusted,
541285612Sdelphij	 * forget it.
542285612Sdelphij	 */
543298770Sdelphij
544298770Sdelphij	sk = auth_findkey(id);
545298770Sdelphij	if (!trust && sk == NULL)
546285612Sdelphij		return;
54754359Sroberto
548285612Sdelphij	/*
549285612Sdelphij	 * There are two conditions remaining. Either it does not
550285612Sdelphij	 * exist and is to be trusted or it does exist and is or is
551285612Sdelphij	 * not to be trusted.
552285612Sdelphij	 */
553285612Sdelphij	if (sk != NULL) {
554285612Sdelphij		/*
555298770Sdelphij		 * Key exists. If it is to be trusted, say so and update
556298770Sdelphij		 * its lifetime. If no longer trusted, return it to the
557298770Sdelphij		 * free list. Flush the cache first to be sure there are
558298770Sdelphij		 * no discrepancies.
559285612Sdelphij		 */
560298770Sdelphij		authcache_flush_id(id);
56154359Sroberto		if (trust > 0) {
56254359Sroberto			sk->flags |= KEY_TRUSTED;
56354359Sroberto			if (trust > 1)
56454359Sroberto				sk->lifetime = current_time + trust;
56554359Sroberto			else
56654359Sroberto				sk->lifetime = 0;
567298770Sdelphij		} else {
568298770Sdelphij			freesymkey(sk);
56954359Sroberto		}
57054359Sroberto		return;
57154359Sroberto	}
57254359Sroberto
573285612Sdelphij	/*
574285612Sdelphij	 * keyid is not present, but the is to be trusted.  We allocate
575285612Sdelphij	 * a new key, but do not specify a key type or secret.
576285612Sdelphij	 */
577285612Sdelphij	if (trust > 1) {
578285612Sdelphij		lifetime = current_time + trust;
579285612Sdelphij	} else {
580285612Sdelphij		lifetime = 0;
581285612Sdelphij	}
582298770Sdelphij	allocsymkey(id, KEY_TRUSTED, 0, lifetime, 0, NULL, NULL);
58354359Sroberto}
58454359Sroberto
58554359Sroberto
58654359Sroberto/*
58754359Sroberto * authistrusted - determine whether a key is trusted
58854359Sroberto */
58954359Srobertoint
59054359Srobertoauthistrusted(
591298770Sdelphij	keyid_t		id
59254359Sroberto	)
59354359Sroberto{
594285612Sdelphij	symkey *	sk;
59554359Sroberto
596298770Sdelphij	if (id == cache_keyid)
597285612Sdelphij		return !!(KEY_TRUSTED & cache_flags);
59854359Sroberto
59954359Sroberto	authkeyuncached++;
600298770Sdelphij	sk = auth_findkey(id);
601298770Sdelphij	if (sk == NULL || !(KEY_TRUSTED & sk->flags)) {
60254359Sroberto		authkeynotfound++;
603285612Sdelphij		return FALSE;
60454359Sroberto	}
605285612Sdelphij	return TRUE;
60654359Sroberto}
60754359Sroberto
608294904Sdelphij
609294904Sdelphij/*
610294904Sdelphij * authistrustedip - determine if the IP is OK for the keyid
611294904Sdelphij */
612294904Sdelphij int
613294904Sdelphij authistrustedip(
614294904Sdelphij 	keyid_t		keyno,
615294904Sdelphij	sockaddr_u *	sau
616294904Sdelphij	)
617294904Sdelphij{
618294904Sdelphij	symkey *	sk;
619294904Sdelphij
620298770Sdelphij	/* That specific key was already used to authenticate the
621298770Sdelphij	 * packet. Therefore, the key *must* exist...  There's a chance
622298770Sdelphij	 * that is not trusted, though.
623298770Sdelphij	 */
624298770Sdelphij	if (keyno == cache_keyid) {
625298770Sdelphij		return (KEY_TRUSTED & cache_flags) &&
626298770Sdelphij		    keyacc_contains(cache_keyacclist, sau, TRUE);
627298770Sdelphij	} else {
628294904Sdelphij		authkeyuncached++;
629298770Sdelphij		sk = auth_findkey(keyno);
630298770Sdelphij		INSIST(NULL != sk);
631298770Sdelphij		return (KEY_TRUSTED & sk->flags) &&
632298770Sdelphij		    keyacc_contains(sk->keyacclist, sau, TRUE);
633294904Sdelphij	}
634294904Sdelphij}
635294904Sdelphij
636293893Sglebius/* Note: There are two locations below where 'strncpy()' is used. While
637293893Sglebius * this function is a hazard by itself, it's essential that it is used
638293893Sglebius * here. Bug 1243 involved that the secret was filled with NUL bytes
639293893Sglebius * after the first NUL encountered, and 'strlcpy()' simply does NOT have
640293893Sglebius * this behaviour. So disabling the fix and reverting to the buggy
641293893Sglebius * behaviour due to compatibility issues MUST also fill with NUL and
642293893Sglebius * this needs 'strncpy'. Also, the secret is managed as a byte blob of a
643293893Sglebius * given size, and eventually truncating it and replacing the last byte
644293893Sglebius * with a NUL would be a bug.
645293893Sglebius * perlinger@ntp.org 2015-10-10
646293893Sglebius */
64754359Srobertovoid
64854359SrobertoMD5auth_setkey(
64982498Sroberto	keyid_t keyno,
650285612Sdelphij	int	keytype,
65154359Sroberto	const u_char *key,
652298770Sdelphij	size_t secretsize,
653294904Sdelphij	KeyAccT *ka
65454359Sroberto	)
65554359Sroberto{
656285612Sdelphij	symkey *	sk;
657285612Sdelphij	u_char *	secret;
65854359Sroberto
659285612Sdelphij	DEBUG_ENSURE(keytype <= USHRT_MAX);
660298770Sdelphij	DEBUG_ENSURE(secretsize < 4 * 1024);
66154359Sroberto	/*
66254359Sroberto	 * See if we already have the key.  If so just stick in the
66354359Sroberto	 * new value.
66454359Sroberto	 */
665298770Sdelphij	sk = auth_findkey(keyno);
666298770Sdelphij	if (sk != NULL && keyno == sk->keyid) {
667289999Sglebius			/* TALOS-CAN-0054: make sure we have a new buffer! */
668298770Sdelphij		if (NULL != sk->secret) {
669298770Sdelphij			memset(sk->secret, 0, sk->secretsize);
670298770Sdelphij			free(sk->secret);
671298770Sdelphij		}
672298770Sdelphij		sk->secret = emalloc(secretsize + 1);
673298770Sdelphij		sk->type = (u_short)keytype;
674298770Sdelphij		sk->secretsize = secretsize;
675298770Sdelphij		/* make sure access lists don't leak here! */
676298770Sdelphij		if (ka != sk->keyacclist) {
677298770Sdelphij			keyacc_all_free(sk->keyacclist);
678294904Sdelphij			sk->keyacclist = ka;
679298770Sdelphij		}
680285612Sdelphij#ifndef DISABLE_BUG1243_FIX
681298770Sdelphij		memcpy(sk->secret, key, secretsize);
682285612Sdelphij#else
683298770Sdelphij		/* >MUST< use 'strncpy()' here! See above! */
684298770Sdelphij		strncpy((char *)sk->secret, (const char *)key,
685298770Sdelphij			secretsize);
686285612Sdelphij#endif
687298770Sdelphij		authcache_flush_id(keyno);
688298770Sdelphij		return;
68954359Sroberto	}
69054359Sroberto
69154359Sroberto	/*
69254359Sroberto	 * Need to allocate new structure.  Do it.
69354359Sroberto	 */
694298770Sdelphij	secret = emalloc(secretsize + 1);
695285612Sdelphij#ifndef DISABLE_BUG1243_FIX
696285612Sdelphij	memcpy(secret, key, secretsize);
697285612Sdelphij#else
698293893Sglebius	/* >MUST< use 'strncpy()' here! See above! */
699293893Sglebius	strncpy((char *)secret, (const char *)key, secretsize);
700285612Sdelphij#endif
701298770Sdelphij	allocsymkey(keyno, 0, (u_short)keytype, 0,
702298770Sdelphij		    secretsize, secret, ka);
703285612Sdelphij#ifdef DEBUG
704285612Sdelphij	if (debug >= 4) {
705285612Sdelphij		size_t	j;
70654359Sroberto
707285612Sdelphij		printf("auth_setkey: key %d type %d len %d ", (int)keyno,
708285612Sdelphij		    keytype, (int)secretsize);
709298770Sdelphij		for (j = 0; j < secretsize; j++) {
710285612Sdelphij			printf("%02x", secret[j]);
711298770Sdelphij		}
712285612Sdelphij		printf("\n");
713285612Sdelphij	}
714285612Sdelphij#endif
715285612Sdelphij}
71654359Sroberto
71754359Sroberto
71854359Sroberto/*
719285612Sdelphij * auth_delkeys - delete non-autokey untrusted keys, and clear all info
720285612Sdelphij *                except the trusted bit of non-autokey trusted keys, in
721285612Sdelphij *		  preparation for rereading the keys file.
72254359Sroberto */
72354359Srobertovoid
72454359Srobertoauth_delkeys(void)
72554359Sroberto{
726285612Sdelphij	symkey *	sk;
72754359Sroberto
728285612Sdelphij	ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey)
729285612Sdelphij		if (sk->keyid > NTP_MAXKEY) {	/* autokey */
730285612Sdelphij			continue;
731285612Sdelphij		}
732285612Sdelphij
73354359Sroberto		/*
734289999Sglebius		 * Don't lose info as to which keys are trusted. Make
735289999Sglebius		 * sure there are no dangling pointers!
73654359Sroberto		 */
737285612Sdelphij		if (KEY_TRUSTED & sk->flags) {
738285612Sdelphij			if (sk->secret != NULL) {
739289999Sglebius				memset(sk->secret, 0, sk->secretsize);
740285612Sdelphij				free(sk->secret);
741289999Sglebius				sk->secret = NULL; /* TALOS-CAN-0054 */
74254359Sroberto			}
743298770Sdelphij			sk->keyacclist = keyacc_all_free(sk->keyacclist);
744285612Sdelphij			sk->secretsize = 0;
745285612Sdelphij			sk->lifetime = 0;
746285612Sdelphij		} else {
747298770Sdelphij			freesymkey(sk);
74854359Sroberto		}
749285612Sdelphij	ITER_DLIST_END()
75054359Sroberto}
75154359Sroberto
752285612Sdelphij
75354359Sroberto/*
75454359Sroberto * auth_agekeys - delete keys whose lifetimes have expired
75554359Sroberto */
75654359Srobertovoid
75754359Srobertoauth_agekeys(void)
75854359Sroberto{
759285612Sdelphij	symkey *	sk;
76054359Sroberto
761285612Sdelphij	ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey)
762285612Sdelphij		if (sk->lifetime > 0 && current_time > sk->lifetime) {
763298770Sdelphij			freesymkey(sk);
764285612Sdelphij			authkeyexpired++;
76554359Sroberto		}
766285612Sdelphij	ITER_DLIST_END()
767285612Sdelphij	DPRINTF(1, ("auth_agekeys: at %lu keys %lu expired %lu\n",
768285612Sdelphij		    current_time, authnumkeys, authkeyexpired));
76954359Sroberto}
77054359Sroberto
771285612Sdelphij
77254359Sroberto/*
77354359Sroberto * authencrypt - generate message authenticator
77454359Sroberto *
77554359Sroberto * Returns length of authenticator field, zero if key not found.
77654359Sroberto */
777293893Sglebiussize_t
77854359Srobertoauthencrypt(
779285612Sdelphij	keyid_t		keyno,
780285612Sdelphij	u_int32 *	pkt,
781293893Sglebius	size_t		length
78254359Sroberto	)
783293893Sglebius{
78454359Sroberto	/*
78554359Sroberto	 * A zero key identifier means the sender has not verified
78654359Sroberto	 * the last message was correctly authenticated. The MAC
78754359Sroberto	 * consists of a single word with value zero.
78854359Sroberto	 */
78954359Sroberto	authencryptions++;
79082498Sroberto	pkt[length / 4] = htonl(keyno);
791285612Sdelphij	if (0 == keyno) {
792285612Sdelphij		return 4;
79354359Sroberto	}
794285612Sdelphij	if (!authhavekey(keyno)) {
795285612Sdelphij		return 0;
796285612Sdelphij	}
79754359Sroberto
798285612Sdelphij	return MD5authencrypt(cache_type, cache_secret, pkt, length);
79954359Sroberto}
80054359Sroberto
801285612Sdelphij
80254359Sroberto/*
80354359Sroberto * authdecrypt - verify message authenticator
80454359Sroberto *
805285612Sdelphij * Returns TRUE if authenticator valid, FALSE if invalid or not found.
80654359Sroberto */
80754359Srobertoint
80854359Srobertoauthdecrypt(
809285612Sdelphij	keyid_t		keyno,
810285612Sdelphij	u_int32 *	pkt,
811293893Sglebius	size_t		length,
812293893Sglebius	size_t		size
81354359Sroberto	)
81454359Sroberto{
81554359Sroberto	/*
81654359Sroberto	 * A zero key identifier means the sender has not verified
817285612Sdelphij	 * the last message was correctly authenticated.  For our
818285612Sdelphij	 * purpose this is an invalid authenticator.
81954359Sroberto	 */
82054359Sroberto	authdecryptions++;
821285612Sdelphij	if (0 == keyno || !authhavekey(keyno) || size < 4) {
822285612Sdelphij		return FALSE;
823285612Sdelphij	}
82454359Sroberto
825285612Sdelphij	return MD5authdecrypt(cache_type, cache_secret, pkt, length,
826285612Sdelphij			      size);
82754359Sroberto}
828