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