authkeys.c revision 293650
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"
1854359Sroberto
1954359Sroberto/*
2054359Sroberto * Structure to store keys in in the hash table.
2154359Sroberto */
22285612Sdelphijtypedef struct savekey symkey;
23285612Sdelphij
2454359Srobertostruct savekey {
25285612Sdelphij	symkey *	hlink;		/* next in hash bucket */
26285612Sdelphij	DECL_DLIST_LINK(symkey, llink);	/* for overall & free lists */
27285612Sdelphij	u_char *	secret;		/* shared secret */
28285612Sdelphij	u_long		lifetime;	/* remaining lifetime */
29285612Sdelphij	keyid_t		keyid;		/* key identifier */
30285612Sdelphij	u_short		type;		/* OpenSSL digest NID */
31285612Sdelphij	u_short		secretsize;	/* secret octets */
32285612Sdelphij	u_short		flags;		/* KEY_ flags that wave */
3354359Sroberto};
3454359Sroberto
35285612Sdelphij/* define the payload region of symkey beyond the list pointers */
36285612Sdelphij#define symkey_payload	secret
37285612Sdelphij
3854359Sroberto#define	KEY_TRUSTED	0x001	/* this key is trusted */
3954359Sroberto
40285612Sdelphij#ifdef DEBUG
41285612Sdelphijtypedef struct symkey_alloc_tag symkey_alloc;
42285612Sdelphij
43285612Sdelphijstruct symkey_alloc_tag {
44285612Sdelphij	symkey_alloc *	link;
45285612Sdelphij	void *		mem;		/* enable free() atexit */
46285612Sdelphij};
47285612Sdelphij
48285612Sdelphijsymkey_alloc *	authallocs;
49285612Sdelphij#endif	/* DEBUG */
50285612Sdelphij
51285612Sdelphijstatic inline u_short	auth_log2(double x);
52285612Sdelphijstatic void		auth_resize_hashtable(void);
53285612Sdelphijstatic void		allocsymkey(symkey **, keyid_t,	u_short,
54285612Sdelphij				    u_short, u_long, u_short, u_char *);
55285612Sdelphijstatic void		freesymkey(symkey *, symkey **);
56285612Sdelphij#ifdef DEBUG
57285612Sdelphijstatic void		free_auth_mem(void);
58285612Sdelphij#endif
59285612Sdelphij
60285612Sdelphijsymkey	key_listhead;		/* list of all in-use keys */;
6154359Sroberto/*
6254359Sroberto * The hash table. This is indexed by the low order bits of the
6354359Sroberto * keyid. We make this fairly big for potentially busy servers.
6454359Sroberto */
65285612Sdelphij#define	DEF_AUTHHASHSIZE	64
66293650Sglebius/*#define	HASHMASK	((HASHSIZE)-1)*/
67285612Sdelphij#define	KEYHASH(keyid)	((keyid) & authhashmask)
6854359Sroberto
69285612Sdelphijint	authhashdisabled;
70285612Sdelphiju_short	authhashbuckets = DEF_AUTHHASHSIZE;
71285612Sdelphiju_short authhashmask = DEF_AUTHHASHSIZE - 1;
72285612Sdelphijsymkey **key_hash;
7354359Sroberto
7454359Srobertou_long authkeynotfound;		/* keys not found */
7554359Srobertou_long authkeylookups;		/* calls to lookup keys */
7654359Srobertou_long authnumkeys;		/* number of active keys */
7754359Srobertou_long authkeyexpired;		/* key lifetime expirations */
7854359Srobertou_long authkeyuncached;		/* cache misses */
7954359Srobertou_long authnokey;		/* calls to encrypt with no key */
8054359Srobertou_long authencryptions;		/* calls to encrypt */
8154359Srobertou_long authdecryptions;		/* calls to decrypt */
8254359Sroberto
8354359Sroberto/*
84285612Sdelphij * Storage for free symkey structures.  We malloc() such things but
8554359Sroberto * never free them.
8654359Sroberto */
87285612Sdelphijsymkey *authfreekeys;
8854359Srobertoint authnumfreekeys;
8954359Sroberto
90285612Sdelphij#define	MEMINC	16		/* number of new free ones to get */
9154359Sroberto
9254359Sroberto/*
9354359Sroberto * The key cache. We cache the last key we looked at here.
9454359Sroberto */
9582498Srobertokeyid_t	cache_keyid;		/* key identifier */
96285612Sdelphiju_char *cache_secret;		/* secret */
97285612Sdelphiju_short	cache_secretsize;	/* secret length */
98285612Sdelphijint	cache_type;		/* OpenSSL digest NID */
9954359Srobertou_short cache_flags;		/* flags that wave */
10054359Sroberto
10154359Sroberto
10254359Sroberto/*
10354359Sroberto * init_auth - initialize internal data
10454359Sroberto */
10554359Srobertovoid
10654359Srobertoinit_auth(void)
10754359Sroberto{
108285612Sdelphij	size_t newalloc;
109285612Sdelphij
11054359Sroberto	/*
11154359Sroberto	 * Initialize hash table and free list
11254359Sroberto	 */
113285612Sdelphij	newalloc = authhashbuckets * sizeof(key_hash[0]);
114285612Sdelphij
115285612Sdelphij	key_hash = erealloc(key_hash, newalloc);
116285612Sdelphij	memset(key_hash, '\0', newalloc);
117285612Sdelphij
118285612Sdelphij	INIT_DLIST(key_listhead, llink);
119285612Sdelphij
120285612Sdelphij#ifdef DEBUG
121285612Sdelphij	atexit(&free_auth_mem);
122285612Sdelphij#endif
12354359Sroberto}
12454359Sroberto
12554359Sroberto
12654359Sroberto/*
127285612Sdelphij * free_auth_mem - assist in leak detection by freeing all dynamic
128285612Sdelphij *		   allocations from this module.
129285612Sdelphij */
130285612Sdelphij#ifdef DEBUG
131285612Sdelphijstatic void
132285612Sdelphijfree_auth_mem(void)
133285612Sdelphij{
134285612Sdelphij	symkey *	sk;
135285612Sdelphij	symkey_alloc *	alloc;
136285612Sdelphij	symkey_alloc *	next_alloc;
137285612Sdelphij
138285612Sdelphij	while (NULL != (sk = HEAD_DLIST(key_listhead, llink))) {
139285612Sdelphij		freesymkey(sk, &key_hash[KEYHASH(sk->keyid)]);
140285612Sdelphij	}
141285612Sdelphij	free(key_hash);
142285612Sdelphij	key_hash = NULL;
143285612Sdelphij	cache_keyid = 0;
144285612Sdelphij	cache_flags = 0;
145285612Sdelphij	for (alloc = authallocs; alloc != NULL; alloc = next_alloc) {
146285612Sdelphij		next_alloc = alloc->link;
147285612Sdelphij		free(alloc->mem);
148285612Sdelphij	}
149285612Sdelphij	authfreekeys = NULL;
150285612Sdelphij	authnumfreekeys = 0;
151285612Sdelphij}
152285612Sdelphij#endif	/* DEBUG */
153285612Sdelphij
154285612Sdelphij
155285612Sdelphij/*
156285612Sdelphij * auth_moremem - get some more free key structures
157285612Sdelphij */
158285612Sdelphijvoid
159285612Sdelphijauth_moremem(
160285612Sdelphij	int	keycount
161285612Sdelphij	)
162285612Sdelphij{
163285612Sdelphij	symkey *	sk;
164285612Sdelphij	int		i;
165285612Sdelphij#ifdef DEBUG
166285612Sdelphij	void *		base;
167285612Sdelphij	symkey_alloc *	allocrec;
168285612Sdelphij# define MOREMEM_EXTRA_ALLOC	(sizeof(*allocrec))
169285612Sdelphij#else
170285612Sdelphij# define MOREMEM_EXTRA_ALLOC	(0)
171285612Sdelphij#endif
172285612Sdelphij
173285612Sdelphij	i = (keycount > 0)
174285612Sdelphij		? keycount
175285612Sdelphij		: MEMINC;
176285612Sdelphij	sk = emalloc_zero(i * sizeof(*sk) + MOREMEM_EXTRA_ALLOC);
177285612Sdelphij#ifdef DEBUG
178285612Sdelphij	base = sk;
179285612Sdelphij#endif
180285612Sdelphij	authnumfreekeys += i;
181285612Sdelphij
182285612Sdelphij	for (; i > 0; i--, sk++) {
183285612Sdelphij		LINK_SLIST(authfreekeys, sk, llink.f);
184285612Sdelphij	}
185285612Sdelphij
186285612Sdelphij#ifdef DEBUG
187285612Sdelphij	allocrec = (void *)sk;
188285612Sdelphij	allocrec->mem = base;
189285612Sdelphij	LINK_SLIST(authallocs, allocrec, link);
190285612Sdelphij#endif
191285612Sdelphij}
192285612Sdelphij
193285612Sdelphij
194285612Sdelphij/*
195285612Sdelphij * auth_prealloc_symkeys
196285612Sdelphij */
197285612Sdelphijvoid
198285612Sdelphijauth_prealloc_symkeys(
199285612Sdelphij	int	keycount
200285612Sdelphij	)
201285612Sdelphij{
202285612Sdelphij	int	allocated;
203285612Sdelphij	int	additional;
204285612Sdelphij
205285612Sdelphij	allocated = authnumkeys + authnumfreekeys;
206285612Sdelphij	additional = keycount - allocated;
207285612Sdelphij	if (additional > 0)
208285612Sdelphij		auth_moremem(additional);
209285612Sdelphij	auth_resize_hashtable();
210285612Sdelphij}
211285612Sdelphij
212285612Sdelphij
213285612Sdelphijstatic inline u_short
214285612Sdelphijauth_log2(double x)
215285612Sdelphij{
216285612Sdelphij	return (u_short)(log10(x) / log10(2));
217285612Sdelphij}
218285612Sdelphij
219285612Sdelphij
220285612Sdelphij/*
221285612Sdelphij * auth_resize_hashtable
222285612Sdelphij *
223285612Sdelphij * Size hash table to average 4 or fewer entries per bucket initially,
224285612Sdelphij * within the bounds of at least 4 and no more than 15 bits for the hash
225285612Sdelphij * table index.  Populate the hash table.
226285612Sdelphij */
227285612Sdelphijstatic void
228285612Sdelphijauth_resize_hashtable(void)
229285612Sdelphij{
230285612Sdelphij	u_long		totalkeys;
231285612Sdelphij	u_short		hashbits;
232285612Sdelphij	u_short		hash;
233285612Sdelphij	size_t		newalloc;
234285612Sdelphij	symkey *	sk;
235285612Sdelphij
236285612Sdelphij	totalkeys = authnumkeys + authnumfreekeys;
237285612Sdelphij	hashbits = auth_log2(totalkeys / 4.0) + 1;
238285612Sdelphij	hashbits = max(4, hashbits);
239285612Sdelphij	hashbits = min(15, hashbits);
240285612Sdelphij
241285612Sdelphij	authhashbuckets = 1 << hashbits;
242285612Sdelphij	authhashmask = authhashbuckets - 1;
243285612Sdelphij	newalloc = authhashbuckets * sizeof(key_hash[0]);
244285612Sdelphij
245285612Sdelphij	key_hash = erealloc(key_hash, newalloc);
246285612Sdelphij	memset(key_hash, '\0', newalloc);
247285612Sdelphij
248285612Sdelphij	ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey)
249285612Sdelphij		hash = KEYHASH(sk->keyid);
250285612Sdelphij		LINK_SLIST(key_hash[hash], sk, hlink);
251285612Sdelphij	ITER_DLIST_END()
252285612Sdelphij}
253285612Sdelphij
254285612Sdelphij
255285612Sdelphij/*
256285612Sdelphij * allocsymkey - common code to allocate and link in symkey
257285612Sdelphij *
258285612Sdelphij * secret must be allocated with a free-compatible allocator.  It is
259285612Sdelphij * owned by the referring symkey structure, and will be free()d by
260285612Sdelphij * freesymkey().
261285612Sdelphij */
262285612Sdelphijstatic void
263285612Sdelphijallocsymkey(
264285612Sdelphij	symkey **	bucket,
265285612Sdelphij	keyid_t		id,
266285612Sdelphij	u_short		flags,
267285612Sdelphij	u_short		type,
268285612Sdelphij	u_long		lifetime,
269285612Sdelphij	u_short		secretsize,
270285612Sdelphij	u_char *	secret
271285612Sdelphij	)
272285612Sdelphij{
273285612Sdelphij	symkey *	sk;
274285612Sdelphij
275285612Sdelphij	if (authnumfreekeys < 1)
276285612Sdelphij		auth_moremem(-1);
277285612Sdelphij	UNLINK_HEAD_SLIST(sk, authfreekeys, llink.f);
278285612Sdelphij	DEBUG_ENSURE(sk != NULL);
279285612Sdelphij	sk->keyid = id;
280285612Sdelphij	sk->flags = flags;
281285612Sdelphij	sk->type = type;
282285612Sdelphij	sk->secretsize = secretsize;
283285612Sdelphij	sk->secret = secret;
284285612Sdelphij	sk->lifetime = lifetime;
285285612Sdelphij	LINK_SLIST(*bucket, sk, hlink);
286285612Sdelphij	LINK_TAIL_DLIST(key_listhead, sk, llink);
287285612Sdelphij	authnumfreekeys--;
288285612Sdelphij	authnumkeys++;
289285612Sdelphij}
290285612Sdelphij
291285612Sdelphij
292285612Sdelphij/*
293285612Sdelphij * freesymkey - common code to remove a symkey and recycle its entry.
294285612Sdelphij */
295285612Sdelphijstatic void
296285612Sdelphijfreesymkey(
297285612Sdelphij	symkey *	sk,
298285612Sdelphij	symkey **	bucket
299285612Sdelphij	)
300285612Sdelphij{
301285612Sdelphij	symkey *	unlinked;
302285612Sdelphij
303285612Sdelphij	if (sk->secret != NULL) {
304285612Sdelphij		memset(sk->secret, '\0', sk->secretsize);
305285612Sdelphij		free(sk->secret);
306285612Sdelphij	}
307285612Sdelphij	UNLINK_SLIST(unlinked, *bucket, sk, hlink, symkey);
308285612Sdelphij	DEBUG_ENSURE(sk == unlinked);
309285612Sdelphij	UNLINK_DLIST(sk, llink);
310285612Sdelphij	memset((char *)sk + offsetof(symkey, symkey_payload), '\0',
311285612Sdelphij	       sizeof(*sk) - offsetof(symkey, symkey_payload));
312285612Sdelphij	LINK_SLIST(authfreekeys, sk, llink.f);
313285612Sdelphij	authnumkeys--;
314285612Sdelphij	authnumfreekeys++;
315285612Sdelphij}
316285612Sdelphij
317285612Sdelphij
318285612Sdelphij/*
31954359Sroberto * auth_findkey - find a key in the hash table
32054359Sroberto */
32154359Srobertostruct savekey *
32254359Srobertoauth_findkey(
323285612Sdelphij	keyid_t		id
32454359Sroberto	)
32554359Sroberto{
326285612Sdelphij	symkey *	sk;
32754359Sroberto
328285612Sdelphij	for (sk = key_hash[KEYHASH(id)]; sk != NULL; sk = sk->hlink) {
329285612Sdelphij		if (id == sk->keyid) {
330285612Sdelphij			return sk;
331285612Sdelphij		}
332285612Sdelphij	}
33354359Sroberto
334285612Sdelphij	return NULL;
33554359Sroberto}
33654359Sroberto
33754359Sroberto
33854359Sroberto/*
339285612Sdelphij * auth_havekey - return TRUE if the key id is zero or known
34054359Sroberto */
34154359Srobertoint
34254359Srobertoauth_havekey(
343285612Sdelphij	keyid_t		id
34454359Sroberto	)
34554359Sroberto{
346285612Sdelphij	symkey *	sk;
34754359Sroberto
348285612Sdelphij	if (0 == id || cache_keyid == id) {
349285612Sdelphij		return TRUE;
350285612Sdelphij	}
35154359Sroberto
352285612Sdelphij	for (sk = key_hash[KEYHASH(id)]; sk != NULL; sk = sk->hlink) {
353285612Sdelphij		if (id == sk->keyid) {
354285612Sdelphij			return TRUE;
355285612Sdelphij		}
356285612Sdelphij	}
35754359Sroberto
358285612Sdelphij	return FALSE;
35954359Sroberto}
36054359Sroberto
36154359Sroberto
36254359Sroberto/*
363285612Sdelphij * authhavekey - return TRUE and cache the key, if zero or both known
364285612Sdelphij *		 and trusted.
36554359Sroberto */
36654359Srobertoint
36754359Srobertoauthhavekey(
368285612Sdelphij	keyid_t		id
36954359Sroberto	)
37054359Sroberto{
371285612Sdelphij	symkey *	sk;
37254359Sroberto
37354359Sroberto	authkeylookups++;
374285612Sdelphij	if (0 == id || cache_keyid == id) {
375285612Sdelphij		return TRUE;
376285612Sdelphij	}
37754359Sroberto
378285612Sdelphij	/*
379285612Sdelphij	 * Seach the bin for the key. If found and the key type
380285612Sdelphij	 * is zero, somebody marked it trusted without specifying
381285612Sdelphij	 * a key or key type. In this case consider the key missing.
382285612Sdelphij	 */
38354359Sroberto	authkeyuncached++;
384285612Sdelphij	for (sk = key_hash[KEYHASH(id)]; sk != NULL; sk = sk->hlink) {
385285612Sdelphij		if (id == sk->keyid) {
386285612Sdelphij			if (0 == sk->type) {
387285612Sdelphij				authkeynotfound++;
388285612Sdelphij				return FALSE;
389285612Sdelphij			}
390285612Sdelphij			break;
391285612Sdelphij		}
39254359Sroberto	}
393285612Sdelphij
394285612Sdelphij	/*
395285612Sdelphij	 * If the key is not found, or if it is found but not trusted,
396285612Sdelphij	 * the key is not considered found.
397285612Sdelphij	 */
398285612Sdelphij	if (NULL == sk) {
39954359Sroberto		authkeynotfound++;
400285612Sdelphij		return FALSE;
401285612Sdelphij	}
402285612Sdelphij	if (!(KEY_TRUSTED & sk->flags)) {
40354359Sroberto		authnokey++;
404285612Sdelphij		return FALSE;
40554359Sroberto	}
406285612Sdelphij
407285612Sdelphij	/*
408285612Sdelphij	 * The key is found and trusted. Initialize the key cache.
409285612Sdelphij	 */
41054359Sroberto	cache_keyid = sk->keyid;
411285612Sdelphij	cache_type = sk->type;
41254359Sroberto	cache_flags = sk->flags;
413285612Sdelphij	cache_secret = sk->secret;
414285612Sdelphij	cache_secretsize = sk->secretsize;
41554359Sroberto
416285612Sdelphij	return TRUE;
41754359Sroberto}
41854359Sroberto
41954359Sroberto
42054359Sroberto/*
42154359Sroberto * authtrust - declare a key to be trusted/untrusted
42254359Sroberto */
42354359Srobertovoid
42454359Srobertoauthtrust(
425285612Sdelphij	keyid_t		id,
426285612Sdelphij	u_long		trust
42754359Sroberto	)
42854359Sroberto{
429285612Sdelphij	symkey **	bucket;
430285612Sdelphij	symkey *	sk;
431285612Sdelphij	u_long		lifetime;
43254359Sroberto
433285612Sdelphij	/*
434285612Sdelphij	 * Search bin for key; if it does not exist and is untrusted,
435285612Sdelphij	 * forget it.
436285612Sdelphij	 */
437285612Sdelphij	bucket = &key_hash[KEYHASH(id)];
438285612Sdelphij	for (sk = *bucket; sk != NULL; sk = sk->hlink) {
439285612Sdelphij		if (id == sk->keyid)
440285612Sdelphij			break;
44154359Sroberto	}
442285612Sdelphij	if (!trust && NULL == sk)
443285612Sdelphij		return;
44454359Sroberto
445285612Sdelphij	/*
446285612Sdelphij	 * There are two conditions remaining. Either it does not
447285612Sdelphij	 * exist and is to be trusted or it does exist and is or is
448285612Sdelphij	 * not to be trusted.
449285612Sdelphij	 */
450285612Sdelphij	if (sk != NULL) {
451285612Sdelphij		if (cache_keyid == id) {
45254359Sroberto			cache_flags = 0;
45354359Sroberto			cache_keyid = 0;
45454359Sroberto		}
45554359Sroberto
456285612Sdelphij		/*
457285612Sdelphij		 * Key exists. If it is to be trusted, say so and
458285612Sdelphij		 * update its lifetime.
459285612Sdelphij		 */
46054359Sroberto		if (trust > 0) {
46154359Sroberto			sk->flags |= KEY_TRUSTED;
46254359Sroberto			if (trust > 1)
46354359Sroberto				sk->lifetime = current_time + trust;
46454359Sroberto			else
46554359Sroberto				sk->lifetime = 0;
46654359Sroberto			return;
46754359Sroberto		}
46854359Sroberto
469285612Sdelphij		/* No longer trusted, return it to the free list. */
470285612Sdelphij		freesymkey(sk, bucket);
47154359Sroberto		return;
47254359Sroberto	}
47354359Sroberto
474285612Sdelphij	/*
475285612Sdelphij	 * keyid is not present, but the is to be trusted.  We allocate
476285612Sdelphij	 * a new key, but do not specify a key type or secret.
477285612Sdelphij	 */
478285612Sdelphij	if (trust > 1) {
479285612Sdelphij		lifetime = current_time + trust;
480285612Sdelphij	} else {
481285612Sdelphij		lifetime = 0;
482285612Sdelphij	}
483285612Sdelphij	allocsymkey(bucket, id, KEY_TRUSTED, 0, lifetime, 0, NULL);
48454359Sroberto}
48554359Sroberto
48654359Sroberto
48754359Sroberto/*
48854359Sroberto * authistrusted - determine whether a key is trusted
48954359Sroberto */
49054359Srobertoint
49154359Srobertoauthistrusted(
492285612Sdelphij	keyid_t		keyno
49354359Sroberto	)
49454359Sroberto{
495285612Sdelphij	symkey *	sk;
496285612Sdelphij	symkey **	bucket;
49754359Sroberto
49854359Sroberto	if (keyno == cache_keyid)
499285612Sdelphij		return !!(KEY_TRUSTED & cache_flags);
50054359Sroberto
50154359Sroberto	authkeyuncached++;
502285612Sdelphij	bucket = &key_hash[KEYHASH(keyno)];
503285612Sdelphij	for (sk = *bucket; sk != NULL; sk = sk->hlink) {
50454359Sroberto		if (keyno == sk->keyid)
505285612Sdelphij			break;
50654359Sroberto	}
507285612Sdelphij	if (NULL == sk || !(KEY_TRUSTED & sk->flags)) {
50854359Sroberto		authkeynotfound++;
509285612Sdelphij		return FALSE;
51054359Sroberto	}
511285612Sdelphij	return TRUE;
51254359Sroberto}
51354359Sroberto
514293650Sglebius/* Note: There are two locations below where 'strncpy()' is used. While
515293650Sglebius * this function is a hazard by itself, it's essential that it is used
516293650Sglebius * here. Bug 1243 involved that the secret was filled with NUL bytes
517293650Sglebius * after the first NUL encountered, and 'strlcpy()' simply does NOT have
518293650Sglebius * this behaviour. So disabling the fix and reverting to the buggy
519293650Sglebius * behaviour due to compatibility issues MUST also fill with NUL and
520293650Sglebius * this needs 'strncpy'. Also, the secret is managed as a byte blob of a
521293650Sglebius * given size, and eventually truncating it and replacing the last byte
522293650Sglebius * with a NUL would be a bug.
523293650Sglebius * perlinger@ntp.org 2015-10-10
524293650Sglebius */
52554359Srobertovoid
52654359SrobertoMD5auth_setkey(
52782498Sroberto	keyid_t keyno,
528285612Sdelphij	int	keytype,
52954359Sroberto	const u_char *key,
530285612Sdelphij	size_t len
53154359Sroberto	)
53254359Sroberto{
533285612Sdelphij	symkey *	sk;
534285612Sdelphij	symkey **	bucket;
535285612Sdelphij	u_char *	secret;
536285612Sdelphij	size_t		secretsize;
53754359Sroberto
538285612Sdelphij	DEBUG_ENSURE(keytype <= USHRT_MAX);
539285612Sdelphij	DEBUG_ENSURE(len < 4 * 1024);
54054359Sroberto	/*
54154359Sroberto	 * See if we already have the key.  If so just stick in the
54254359Sroberto	 * new value.
54354359Sroberto	 */
544285612Sdelphij	bucket = &key_hash[KEYHASH(keyno)];
545285612Sdelphij	for (sk = *bucket; sk != NULL; sk = sk->hlink) {
54654359Sroberto		if (keyno == sk->keyid) {
547289997Sglebius			/* TALOS-CAN-0054: make sure we have a new buffer! */
548289997Sglebius			if (NULL != sk->secret) {
549289997Sglebius				memset(sk->secret, 0, sk->secretsize);
550289997Sglebius				free(sk->secret);
551289997Sglebius			}
552289997Sglebius			sk->secret = emalloc(len);
553285612Sdelphij			sk->type = (u_short)keytype;
554285612Sdelphij			secretsize = len;
555285612Sdelphij			sk->secretsize = (u_short)secretsize;
556285612Sdelphij#ifndef DISABLE_BUG1243_FIX
557285612Sdelphij			memcpy(sk->secret, key, secretsize);
558285612Sdelphij#else
559293650Sglebius			/* >MUST< use 'strncpy()' here! See above! */
560293650Sglebius			strncpy((char *)sk->secret, (const char *)key,
561285612Sdelphij				secretsize);
562285612Sdelphij#endif
56354359Sroberto			if (cache_keyid == keyno) {
56454359Sroberto				cache_flags = 0;
56554359Sroberto				cache_keyid = 0;
56654359Sroberto			}
56754359Sroberto			return;
56854359Sroberto		}
56954359Sroberto	}
57054359Sroberto
57154359Sroberto	/*
57254359Sroberto	 * Need to allocate new structure.  Do it.
57354359Sroberto	 */
574285612Sdelphij	secretsize = len;
575285612Sdelphij	secret = emalloc(secretsize);
576285612Sdelphij#ifndef DISABLE_BUG1243_FIX
577285612Sdelphij	memcpy(secret, key, secretsize);
578285612Sdelphij#else
579293650Sglebius	/* >MUST< use 'strncpy()' here! See above! */
580293650Sglebius	strncpy((char *)secret, (const char *)key, secretsize);
581285612Sdelphij#endif
582285612Sdelphij	allocsymkey(bucket, keyno, 0, (u_short)keytype, 0,
583285612Sdelphij		    (u_short)secretsize, secret);
584285612Sdelphij#ifdef DEBUG
585285612Sdelphij	if (debug >= 4) {
586285612Sdelphij		size_t	j;
58754359Sroberto
588285612Sdelphij		printf("auth_setkey: key %d type %d len %d ", (int)keyno,
589285612Sdelphij		    keytype, (int)secretsize);
590285612Sdelphij		for (j = 0; j < secretsize; j++)
591285612Sdelphij			printf("%02x", secret[j]);
592285612Sdelphij		printf("\n");
593285612Sdelphij	}
594285612Sdelphij#endif
595285612Sdelphij}
59654359Sroberto
59754359Sroberto
59854359Sroberto/*
599285612Sdelphij * auth_delkeys - delete non-autokey untrusted keys, and clear all info
600285612Sdelphij *                except the trusted bit of non-autokey trusted keys, in
601285612Sdelphij *		  preparation for rereading the keys file.
60254359Sroberto */
60354359Srobertovoid
60454359Srobertoauth_delkeys(void)
60554359Sroberto{
606285612Sdelphij	symkey *	sk;
60754359Sroberto
608285612Sdelphij	ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey)
609285612Sdelphij		if (sk->keyid > NTP_MAXKEY) {	/* autokey */
610285612Sdelphij			continue;
611285612Sdelphij		}
612285612Sdelphij
61354359Sroberto		/*
614289997Sglebius		 * Don't lose info as to which keys are trusted. Make
615289997Sglebius		 * sure there are no dangling pointers!
61654359Sroberto		 */
617285612Sdelphij		if (KEY_TRUSTED & sk->flags) {
618285612Sdelphij			if (sk->secret != NULL) {
619289997Sglebius				memset(sk->secret, 0, sk->secretsize);
620285612Sdelphij				free(sk->secret);
621289997Sglebius				sk->secret = NULL; /* TALOS-CAN-0054 */
62254359Sroberto			}
623285612Sdelphij			sk->secretsize = 0;
624285612Sdelphij			sk->lifetime = 0;
625285612Sdelphij		} else {
626285612Sdelphij			freesymkey(sk, &key_hash[KEYHASH(sk->keyid)]);
62754359Sroberto		}
628285612Sdelphij	ITER_DLIST_END()
62954359Sroberto}
63054359Sroberto
631285612Sdelphij
63254359Sroberto/*
63354359Sroberto * auth_agekeys - delete keys whose lifetimes have expired
63454359Sroberto */
63554359Srobertovoid
63654359Srobertoauth_agekeys(void)
63754359Sroberto{
638285612Sdelphij	symkey *	sk;
63954359Sroberto
640285612Sdelphij	ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey)
641285612Sdelphij		if (sk->lifetime > 0 && current_time > sk->lifetime) {
642285612Sdelphij			freesymkey(sk, &key_hash[KEYHASH(sk->keyid)]);
643285612Sdelphij			authkeyexpired++;
64454359Sroberto		}
645285612Sdelphij	ITER_DLIST_END()
646285612Sdelphij	DPRINTF(1, ("auth_agekeys: at %lu keys %lu expired %lu\n",
647285612Sdelphij		    current_time, authnumkeys, authkeyexpired));
64854359Sroberto}
64954359Sroberto
650285612Sdelphij
65154359Sroberto/*
65254359Sroberto * authencrypt - generate message authenticator
65354359Sroberto *
65454359Sroberto * Returns length of authenticator field, zero if key not found.
65554359Sroberto */
656293650Sglebiussize_t
65754359Srobertoauthencrypt(
658285612Sdelphij	keyid_t		keyno,
659285612Sdelphij	u_int32 *	pkt,
660293650Sglebius	size_t		length
66154359Sroberto	)
662293650Sglebius{
66354359Sroberto	/*
66454359Sroberto	 * A zero key identifier means the sender has not verified
66554359Sroberto	 * the last message was correctly authenticated. The MAC
66654359Sroberto	 * consists of a single word with value zero.
66754359Sroberto	 */
66854359Sroberto	authencryptions++;
66982498Sroberto	pkt[length / 4] = htonl(keyno);
670285612Sdelphij	if (0 == keyno) {
671285612Sdelphij		return 4;
67254359Sroberto	}
673285612Sdelphij	if (!authhavekey(keyno)) {
674285612Sdelphij		return 0;
675285612Sdelphij	}
67654359Sroberto
677285612Sdelphij	return MD5authencrypt(cache_type, cache_secret, pkt, length);
67854359Sroberto}
67954359Sroberto
680285612Sdelphij
68154359Sroberto/*
68254359Sroberto * authdecrypt - verify message authenticator
68354359Sroberto *
684285612Sdelphij * Returns TRUE if authenticator valid, FALSE if invalid or not found.
68554359Sroberto */
68654359Srobertoint
68754359Srobertoauthdecrypt(
688285612Sdelphij	keyid_t		keyno,
689285612Sdelphij	u_int32 *	pkt,
690293650Sglebius	size_t		length,
691293650Sglebius	size_t		size
69254359Sroberto	)
69354359Sroberto{
69454359Sroberto	/*
69554359Sroberto	 * A zero key identifier means the sender has not verified
696285612Sdelphij	 * the last message was correctly authenticated.  For our
697285612Sdelphij	 * purpose this is an invalid authenticator.
69854359Sroberto	 */
69954359Sroberto	authdecryptions++;
700285612Sdelphij	if (0 == keyno || !authhavekey(keyno) || size < 4) {
701285612Sdelphij		return FALSE;
702285612Sdelphij	}
70354359Sroberto
704285612Sdelphij	return MD5authdecrypt(cache_type, cache_secret, pkt, length,
705285612Sdelphij			      size);
70654359Sroberto}
707