1/*
2 * authkeys.c - routines to manage the storage of authentication keys
3 */
4#ifdef HAVE_CONFIG_H
5# include <config.h>
6#endif
7
8#include <math.h>
9#include <stdio.h>
10
11#include "ntp.h"
12#include "ntp_fp.h"
13#include "ntpd.h"
14#include "ntp_lists.h"
15#include "ntp_string.h"
16#include "ntp_malloc.h"
17#include "ntp_stdlib.h"
18#include "ntp_keyacc.h"
19
20/*
21 * Structure to store keys in in the hash table.
22 */
23typedef struct savekey symkey;
24
25struct savekey {
26	symkey *	hlink;		/* next in hash bucket */
27	DECL_DLIST_LINK(symkey, llink);	/* for overall & free lists */
28	u_char *	secret;		/* shared secret */
29	KeyAccT *	keyacclist;	/* Private key access list */
30	u_long		lifetime;	/* remaining lifetime */
31	keyid_t		keyid;		/* key identifier */
32	u_short		type;		/* OpenSSL digest NID */
33	size_t		secretsize;	/* secret octets */
34	u_short		flags;		/* KEY_ flags that wave */
35};
36
37/* define the payload region of symkey beyond the list pointers */
38#define symkey_payload	secret
39
40#define	KEY_TRUSTED	0x001	/* this key is trusted */
41
42#ifdef DEBUG
43typedef struct symkey_alloc_tag symkey_alloc;
44
45struct symkey_alloc_tag {
46	symkey_alloc *	link;
47	void *		mem;		/* enable free() atexit */
48};
49
50symkey_alloc *	authallocs;
51#endif	/* DEBUG */
52
53static u_short	auth_log2(size_t);
54static void		auth_resize_hashtable(void);
55static void		allocsymkey(keyid_t,	u_short,
56				    u_short, u_long, size_t, u_char *, KeyAccT *);
57static void		freesymkey(symkey *);
58#ifdef DEBUG
59static void		free_auth_mem(void);
60#endif
61
62symkey	key_listhead;		/* list of all in-use keys */;
63/*
64 * The hash table. This is indexed by the low order bits of the
65 * keyid. We make this fairly big for potentially busy servers.
66 */
67#define	DEF_AUTHHASHSIZE	64
68/*#define	HASHMASK	((HASHSIZE)-1)*/
69#define	KEYHASH(keyid)	((keyid) & authhashmask)
70
71int	authhashdisabled;
72u_short	authhashbuckets = DEF_AUTHHASHSIZE;
73u_short authhashmask = DEF_AUTHHASHSIZE - 1;
74symkey **key_hash;
75
76u_long authkeynotfound;		/* keys not found */
77u_long authkeylookups;		/* calls to lookup keys */
78u_long authnumkeys;		/* number of active keys */
79u_long authkeyexpired;		/* key lifetime expirations */
80u_long authkeyuncached;		/* cache misses */
81u_long authnokey;		/* calls to encrypt with no key */
82u_long authencryptions;		/* calls to encrypt */
83u_long authdecryptions;		/* calls to decrypt */
84
85/*
86 * Storage for free symkey structures.  We malloc() such things but
87 * never free them.
88 */
89symkey *authfreekeys;
90int authnumfreekeys;
91
92#define	MEMINC	16		/* number of new free ones to get */
93
94/*
95 * The key cache. We cache the last key we looked at here.
96 * Note: this should hold the last *trusted* key. Also the
97 * cache is only loaded when the digest type / MAC algorithm
98 * is valid.
99 */
100keyid_t	cache_keyid;		/* key identifier */
101u_char *cache_secret;		/* secret */
102size_t	cache_secretsize;	/* secret length */
103int	cache_type;		/* OpenSSL digest NID */
104u_short cache_flags;		/* flags that wave */
105KeyAccT *cache_keyacclist;	/* key access list */
106
107/* --------------------------------------------------------------------
108 * manage key access lists
109 * --------------------------------------------------------------------
110 */
111/* allocate and populate new access node and pushes it on the list.
112 * Returns the new head.
113 */
114KeyAccT*
115keyacc_new_push(
116	KeyAccT          * head,
117	const sockaddr_u * addr,
118	unsigned int	   subnetbits
119	)
120{
121	KeyAccT *	node = emalloc(sizeof(KeyAccT));
122
123	memcpy(&node->addr, addr, sizeof(sockaddr_u));
124	node->subnetbits = subnetbits;
125	node->next = head;
126
127	return node;
128}
129
130/* ----------------------------------------------------------------- */
131/* pop and deallocate the first node of a list of access nodes, if
132 * the list is not empty. Returns the tail of the list.
133 */
134KeyAccT*
135keyacc_pop_free(
136	KeyAccT *head
137	)
138{
139	KeyAccT *	next = NULL;
140	if (head) {
141		next = head->next;
142		free(head);
143	}
144	return next;
145}
146
147/* ----------------------------------------------------------------- */
148/* deallocate the list; returns an empty list. */
149KeyAccT*
150keyacc_all_free(
151	KeyAccT * head
152	)
153{
154	while (head)
155		head = keyacc_pop_free(head);
156	return head;
157}
158
159/* ----------------------------------------------------------------- */
160/* scan a list to see if it contains a given address. Return the
161 * default result value in case of an empty list.
162 */
163int /*BOOL*/
164keyacc_contains(
165	const KeyAccT    *head,
166	const sockaddr_u *addr,
167	int               defv)
168{
169	if (head) {
170		do {
171			if (keyacc_amatch(&head->addr, addr,
172					  head->subnetbits))
173				return TRUE;
174		} while (NULL != (head = head->next));
175		return FALSE;
176	} else {
177		return !!defv;
178	}
179}
180
181#if CHAR_BIT != 8
182# error "don't know how to handle bytes with that bit size"
183#endif
184
185/* ----------------------------------------------------------------- */
186/* check two addresses for a match, taking a prefix length into account
187 * when doing the compare.
188 *
189 * The ISC lib contains a similar function with not entirely specified
190 * semantics, so it seemed somewhat cleaner to do this from scratch.
191 *
192 * Note 1: It *is* assumed that the addresses are stored in network byte
193 * order, that is, most significant byte first!
194 *
195 * Note 2: "no address" compares unequal to all other addresses, even to
196 * itself. This has the same semantics as NaNs have for floats: *any*
197 * relational or equality operation involving a NaN returns FALSE, even
198 * equality with itself. "no address" is either a NULL pointer argument
199 * or an address of type AF_UNSPEC.
200 */
201int/*BOOL*/
202keyacc_amatch(
203	const sockaddr_u *	a1,
204	const sockaddr_u *	a2,
205	unsigned int		mbits
206	)
207{
208	const uint8_t * pm1;
209	const uint8_t * pm2;
210	uint8_t         msk;
211	unsigned int    len;
212
213	/* 1st check: If any address is not an address, it's inequal. */
214	if ( !a1 || (AF_UNSPEC == AF(a1)) ||
215	     !a2 || (AF_UNSPEC == AF(a2))  )
216		return FALSE;
217
218	/* We could check pointers for equality here and shortcut the
219	 * other checks if we find object identity. But that use case is
220	 * too rare to care for it.
221	 */
222
223	/* 2nd check: Address families must be the same. */
224	if (AF(a1) != AF(a2))
225		return FALSE;
226
227	/* type check: address family determines buffer & size */
228	switch (AF(a1)) {
229	case AF_INET:
230		/* IPv4 is easy: clamp size, get byte pointers */
231		if (mbits > sizeof(NSRCADR(a1)) * 8)
232			mbits = sizeof(NSRCADR(a1)) * 8;
233		pm1 = (const void*)&NSRCADR(a1);
234		pm2 = (const void*)&NSRCADR(a2);
235		break;
236
237	case AF_INET6:
238		/* IPv6 is slightly different: Both scopes must match,
239		 * too, before we even consider doing a match!
240		 */
241		if ( ! SCOPE_EQ(a1, a2))
242			return FALSE;
243		if (mbits > sizeof(NSRCADR6(a1)) * 8)
244			mbits = sizeof(NSRCADR6(a1)) * 8;
245		pm1 = (const void*)&NSRCADR6(a1);
246		pm2 = (const void*)&NSRCADR6(a2);
247		break;
248
249	default:
250		/* don't know how to compare that!?! */
251		return FALSE;
252	}
253
254	/* Split bit length into byte length and partial byte mask.
255	 * Note that the byte mask extends from the MSB of a byte down,
256	 * and that zero shift (--> mbits % 8 == 0) results in an
257	 * all-zero mask.
258	 */
259	msk = 0xFFu ^ (0xFFu >> (mbits & 7));
260	len = mbits >> 3;
261
262	/* 3rd check: Do memcmp() over full bytes, if any */
263	if (len && memcmp(pm1, pm2, len))
264		return FALSE;
265
266	/* 4th check: compare last incomplete byte, if any */
267	if (msk && ((pm1[len] ^ pm2[len]) & msk))
268		return FALSE;
269
270	/* If none of the above failed, we're successfully through. */
271	return TRUE;
272}
273
274/*
275 * init_auth - initialize internal data
276 */
277void
278init_auth(void)
279{
280	size_t newalloc;
281
282	/*
283	 * Initialize hash table and free list
284	 */
285	newalloc = authhashbuckets * sizeof(key_hash[0]);
286
287	key_hash = erealloc(key_hash, newalloc);
288	memset(key_hash, '\0', newalloc);
289
290	INIT_DLIST(key_listhead, llink);
291
292#ifdef DEBUG
293	atexit(&free_auth_mem);
294#endif
295}
296
297
298/*
299 * free_auth_mem - assist in leak detection by freeing all dynamic
300 *		   allocations from this module.
301 */
302#ifdef DEBUG
303static void
304free_auth_mem(void)
305{
306	symkey *	sk;
307	symkey_alloc *	alloc;
308	symkey_alloc *	next_alloc;
309
310	while (NULL != (sk = HEAD_DLIST(key_listhead, llink))) {
311		freesymkey(sk);
312	}
313	free(key_hash);
314	key_hash = NULL;
315	cache_keyid = 0;
316	cache_flags = 0;
317	cache_keyacclist = NULL;
318	for (alloc = authallocs; alloc != NULL; alloc = next_alloc) {
319		next_alloc = alloc->link;
320		free(alloc->mem);
321	}
322	authfreekeys = NULL;
323	authnumfreekeys = 0;
324}
325#endif	/* DEBUG */
326
327
328/*
329 * auth_moremem - get some more free key structures
330 */
331void
332auth_moremem(
333	int	keycount
334	)
335{
336	symkey *	sk;
337	int		i;
338#ifdef DEBUG
339	void *		base;
340	symkey_alloc *	allocrec;
341# define MOREMEM_EXTRA_ALLOC	(sizeof(*allocrec))
342#else
343# define MOREMEM_EXTRA_ALLOC	(0)
344#endif
345
346	i = (keycount > 0)
347		? keycount
348		: MEMINC;
349	sk = eallocarrayxz(i, sizeof(*sk), MOREMEM_EXTRA_ALLOC);
350#ifdef DEBUG
351	base = sk;
352#endif
353	authnumfreekeys += i;
354
355	for (; i > 0; i--, sk++) {
356		LINK_SLIST(authfreekeys, sk, llink.f);
357	}
358
359#ifdef DEBUG
360	allocrec = (void *)sk;
361	allocrec->mem = base;
362	LINK_SLIST(authallocs, allocrec, link);
363#endif
364}
365
366
367/*
368 * auth_prealloc_symkeys
369 */
370void
371auth_prealloc_symkeys(
372	int	keycount
373	)
374{
375	int	allocated;
376	int	additional;
377
378	allocated = authnumkeys + authnumfreekeys;
379	additional = keycount - allocated;
380	if (additional > 0)
381		auth_moremem(additional);
382	auth_resize_hashtable();
383}
384
385
386static u_short
387auth_log2(size_t x)
388{
389	/*
390	** bithack to calculate floor(log2(x))
391	**
392	** This assumes
393	**   - (sizeof(size_t) is a power of two
394	**   - CHAR_BITS is a power of two
395	**   - returning zero for arguments <= 0 is OK.
396	**
397	** Does only shifts, masks and sums in integer arithmetic in
398	** log2(CHAR_BIT*sizeof(size_t)) steps. (that is, 5/6 steps for
399	** 32bit/64bit size_t)
400	*/
401	int	s;
402	int	r = 0;
403	size_t  m = ~(size_t)0;
404
405	for (s = sizeof(size_t) / 2 * CHAR_BIT; s != 0; s >>= 1) {
406		m <<= s;
407		if (x & m)
408			r += s;
409		else
410			x <<= s;
411	}
412	return (u_short)r;
413}
414
415int/*BOOL*/
416ipaddr_match_masked(const sockaddr_u *,const sockaddr_u *,
417		    unsigned int mbits);
418
419static void
420authcache_flush_id(
421	keyid_t id
422	)
423{
424	if (cache_keyid == id) {
425		cache_keyid = 0;
426		cache_type = 0;
427		cache_flags = 0;
428		cache_secret = NULL;
429		cache_secretsize = 0;
430		cache_keyacclist = NULL;
431	}
432}
433
434
435/*
436 * auth_resize_hashtable
437 *
438 * Size hash table to average 4 or fewer entries per bucket initially,
439 * within the bounds of at least 4 and no more than 15 bits for the hash
440 * table index.  Populate the hash table.
441 */
442static void
443auth_resize_hashtable(void)
444{
445	u_long		totalkeys;
446	u_short		hashbits;
447	u_short		hash;
448	size_t		newalloc;
449	symkey *	sk;
450
451	totalkeys = authnumkeys + authnumfreekeys;
452	hashbits = auth_log2(totalkeys / 4) + 1;
453	hashbits = max(4, hashbits);
454	hashbits = min(15, hashbits);
455
456	authhashbuckets = 1 << hashbits;
457	authhashmask = authhashbuckets - 1;
458	newalloc = authhashbuckets * sizeof(key_hash[0]);
459
460	key_hash = erealloc(key_hash, newalloc);
461	memset(key_hash, '\0', newalloc);
462
463	ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey)
464		hash = KEYHASH(sk->keyid);
465		LINK_SLIST(key_hash[hash], sk, hlink);
466	ITER_DLIST_END()
467}
468
469
470/*
471 * allocsymkey - common code to allocate and link in symkey
472 *
473 * secret must be allocated with a free-compatible allocator.  It is
474 * owned by the referring symkey structure, and will be free()d by
475 * freesymkey().
476 */
477static void
478allocsymkey(
479	keyid_t		id,
480	u_short		flags,
481	u_short		type,
482	u_long		lifetime,
483	size_t		secretsize,
484	u_char *	secret,
485	KeyAccT *	ka
486	)
487{
488	symkey *	sk;
489	symkey **	bucket;
490
491	bucket = &key_hash[KEYHASH(id)];
492
493
494	if (authnumfreekeys < 1)
495		auth_moremem(-1);
496	UNLINK_HEAD_SLIST(sk, authfreekeys, llink.f);
497	DEBUG_ENSURE(sk != NULL);
498	sk->keyid = id;
499	sk->flags = flags;
500	sk->type = type;
501	sk->secretsize = secretsize;
502	sk->secret = secret;
503	sk->keyacclist = ka;
504	sk->lifetime = lifetime;
505	LINK_SLIST(*bucket, sk, hlink);
506	LINK_TAIL_DLIST(key_listhead, sk, llink);
507	authnumfreekeys--;
508	authnumkeys++;
509}
510
511
512/*
513 * freesymkey - common code to remove a symkey and recycle its entry.
514 */
515static void
516freesymkey(
517	symkey *	sk
518	)
519{
520	symkey **	bucket;
521	symkey *	unlinked;
522
523	if (NULL == sk)
524		return;
525
526	authcache_flush_id(sk->keyid);
527	keyacc_all_free(sk->keyacclist);
528
529	bucket = &key_hash[KEYHASH(sk->keyid)];
530	if (sk->secret != NULL) {
531		memset(sk->secret, '\0', sk->secretsize);
532		free(sk->secret);
533	}
534	UNLINK_SLIST(unlinked, *bucket, sk, hlink, symkey);
535	DEBUG_ENSURE(sk == unlinked);
536	UNLINK_DLIST(sk, llink);
537	memset((char *)sk + offsetof(symkey, symkey_payload), '\0',
538	       sizeof(*sk) - offsetof(symkey, symkey_payload));
539	LINK_SLIST(authfreekeys, sk, llink.f);
540	authnumkeys--;
541	authnumfreekeys++;
542}
543
544
545/*
546 * auth_findkey - find a key in the hash table
547 */
548struct savekey *
549auth_findkey(
550	keyid_t		id
551	)
552{
553	symkey *	sk;
554
555	for (sk = key_hash[KEYHASH(id)]; sk != NULL; sk = sk->hlink)
556		if (id == sk->keyid)
557			return sk;
558	return NULL;
559}
560
561
562/*
563 * auth_havekey - return TRUE if the key id is zero or known. The
564 * key needs not to be trusted.
565 */
566int
567auth_havekey(
568	keyid_t		id
569	)
570{
571	return
572	    (0           == id) ||
573	    (cache_keyid == id) ||
574	    (NULL        != auth_findkey(id));
575}
576
577
578/*
579 * authhavekey - return TRUE and cache the key, if zero or both known
580 *		 and trusted.
581 */
582int
583authhavekey(
584	keyid_t		id
585	)
586{
587	symkey *	sk;
588
589	authkeylookups++;
590	if (0 == id || cache_keyid == id)
591		return !!(KEY_TRUSTED & cache_flags);
592
593	/*
594	 * Search the bin for the key. If not found, or found but the key
595	 * type is zero, somebody marked it trusted without specifying a
596	 * key or key type. In this case consider the key missing.
597	 */
598	authkeyuncached++;
599	sk = auth_findkey(id);
600	if ((sk == NULL) || (sk->type == 0)) {
601		authkeynotfound++;
602		return FALSE;
603	}
604
605	/*
606	 * If the key is not trusted, the key is not considered found.
607	 */
608	if ( ! (KEY_TRUSTED & sk->flags)) {
609		authnokey++;
610		return FALSE;
611	}
612
613	/*
614	 * The key is found and trusted. Initialize the key cache.
615	 */
616	cache_keyid = sk->keyid;
617	cache_type = sk->type;
618	cache_flags = sk->flags;
619	cache_secret = sk->secret;
620	cache_secretsize = sk->secretsize;
621	cache_keyacclist = sk->keyacclist;
622
623	return TRUE;
624}
625
626
627/*
628 * authtrust - declare a key to be trusted/untrusted
629 */
630void
631authtrust(
632	keyid_t		id,
633	u_long		trust
634	)
635{
636	symkey *	sk;
637	u_long		lifetime;
638
639	/*
640	 * Search bin for key; if it does not exist and is untrusted,
641	 * forget it.
642	 */
643
644	sk = auth_findkey(id);
645	if (!trust && sk == NULL)
646		return;
647
648	/*
649	 * There are two conditions remaining. Either it does not
650	 * exist and is to be trusted or it does exist and is or is
651	 * not to be trusted.
652	 */
653	if (sk != NULL) {
654		/*
655		 * Key exists. If it is to be trusted, say so and update
656		 * its lifetime. If no longer trusted, return it to the
657		 * free list. Flush the cache first to be sure there are
658		 * no discrepancies.
659		 */
660		authcache_flush_id(id);
661		if (trust > 0) {
662			sk->flags |= KEY_TRUSTED;
663			if (trust > 1)
664				sk->lifetime = current_time + trust;
665			else
666				sk->lifetime = 0;
667		} else {
668			freesymkey(sk);
669		}
670		return;
671	}
672
673	/*
674	 * keyid is not present, but the is to be trusted.  We allocate
675	 * a new key, but do not specify a key type or secret.
676	 */
677	if (trust > 1) {
678		lifetime = current_time + trust;
679	} else {
680		lifetime = 0;
681	}
682	allocsymkey(id, KEY_TRUSTED, 0, lifetime, 0, NULL, NULL);
683}
684
685
686/*
687 * authistrusted - determine whether a key is trusted
688 */
689int
690authistrusted(
691	keyid_t		id
692	)
693{
694	symkey *	sk;
695
696	if (id == cache_keyid)
697		return !!(KEY_TRUSTED & cache_flags);
698
699	authkeyuncached++;
700	sk = auth_findkey(id);
701	if (sk == NULL || !(KEY_TRUSTED & sk->flags)) {
702		authkeynotfound++;
703		return FALSE;
704	}
705	return TRUE;
706}
707
708
709/*
710 * authistrustedip - determine if the IP is OK for the keyid
711 */
712 int
713 authistrustedip(
714 	keyid_t		keyno,
715	sockaddr_u *	sau
716	)
717{
718	symkey *	sk;
719
720	if (keyno == cache_keyid) {
721		return (KEY_TRUSTED & cache_flags) &&
722		    keyacc_contains(cache_keyacclist, sau, TRUE);
723	}
724
725	if (NULL != (sk = auth_findkey(keyno))) {
726		authkeyuncached++;
727		return (KEY_TRUSTED & sk->flags) &&
728		    keyacc_contains(sk->keyacclist, sau, TRUE);
729	}
730
731	authkeynotfound++;
732	return FALSE;
733}
734
735/* Note: There are two locations below where 'strncpy()' is used. While
736 * this function is a hazard by itself, it's essential that it is used
737 * here. Bug 1243 involved that the secret was filled with NUL bytes
738 * after the first NUL encountered, and 'strlcpy()' simply does NOT have
739 * this behaviour. So disabling the fix and reverting to the buggy
740 * behaviour due to compatibility issues MUST also fill with NUL and
741 * this needs 'strncpy'. Also, the secret is managed as a byte blob of a
742 * given size, and eventually truncating it and replacing the last byte
743 * with a NUL would be a bug.
744 * perlinger@ntp.org 2015-10-10
745 */
746void
747MD5auth_setkey(
748	keyid_t keyno,
749	int	keytype,
750	const u_char *key,
751	size_t secretsize,
752	KeyAccT *ka
753	)
754{
755	symkey *	sk;
756	u_char *	secret;
757
758	DEBUG_ENSURE(keytype <= USHRT_MAX);
759	DEBUG_ENSURE(secretsize < 4 * 1024);
760	/*
761	 * See if we already have the key.  If so just stick in the
762	 * new value.
763	 */
764	sk = auth_findkey(keyno);
765	if (sk != NULL && keyno == sk->keyid) {
766			/* TALOS-CAN-0054: make sure we have a new buffer! */
767		if (NULL != sk->secret) {
768			memset(sk->secret, 0, sk->secretsize);
769			free(sk->secret);
770		}
771		sk->secret = emalloc(secretsize + 1);
772		sk->type = (u_short)keytype;
773		sk->secretsize = secretsize;
774		/* make sure access lists don't leak here! */
775		if (ka != sk->keyacclist) {
776			keyacc_all_free(sk->keyacclist);
777			sk->keyacclist = ka;
778		}
779#ifndef DISABLE_BUG1243_FIX
780		memcpy(sk->secret, key, secretsize);
781#else
782		/* >MUST< use 'strncpy()' here! See above! */
783		strncpy((char *)sk->secret, (const char *)key,
784			secretsize);
785#endif
786		authcache_flush_id(keyno);
787		return;
788	}
789
790	/*
791	 * Need to allocate new structure.  Do it.
792	 */
793	secret = emalloc(secretsize + 1);
794#ifndef DISABLE_BUG1243_FIX
795	memcpy(secret, key, secretsize);
796#else
797	/* >MUST< use 'strncpy()' here! See above! */
798	strncpy((char *)secret, (const char *)key, secretsize);
799#endif
800	allocsymkey(keyno, 0, (u_short)keytype, 0,
801		    secretsize, secret, ka);
802#ifdef DEBUG
803	if (debug >= 4) {
804		size_t	j;
805
806		printf("auth_setkey: key %d type %d len %d ", (int)keyno,
807		    keytype, (int)secretsize);
808		for (j = 0; j < secretsize; j++) {
809			printf("%02x", secret[j]);
810		}
811		printf("\n");
812	}
813#endif
814}
815
816
817/*
818 * auth_delkeys - delete non-autokey untrusted keys, and clear all info
819 *                except the trusted bit of non-autokey trusted keys, in
820 *		  preparation for rereading the keys file.
821 */
822void
823auth_delkeys(void)
824{
825	symkey *	sk;
826
827	ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey)
828		if (sk->keyid > NTP_MAXKEY) {	/* autokey */
829			continue;
830		}
831
832		/*
833		 * Don't lose info as to which keys are trusted. Make
834		 * sure there are no dangling pointers!
835		 */
836		if (KEY_TRUSTED & sk->flags) {
837			if (sk->secret != NULL) {
838				memset(sk->secret, 0, sk->secretsize);
839				free(sk->secret);
840				sk->secret = NULL; /* TALOS-CAN-0054 */
841			}
842			sk->keyacclist = keyacc_all_free(sk->keyacclist);
843			sk->secretsize = 0;
844			sk->lifetime = 0;
845		} else {
846			freesymkey(sk);
847		}
848	ITER_DLIST_END()
849}
850
851
852/*
853 * auth_agekeys - delete keys whose lifetimes have expired
854 */
855void
856auth_agekeys(void)
857{
858	symkey *	sk;
859
860	ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey)
861		if (sk->lifetime > 0 && current_time > sk->lifetime) {
862			freesymkey(sk);
863			authkeyexpired++;
864		}
865	ITER_DLIST_END()
866	DPRINTF(1, ("auth_agekeys: at %lu keys %lu expired %lu\n",
867		    current_time, authnumkeys, authkeyexpired));
868}
869
870
871/*
872 * authencrypt - generate message authenticator
873 *
874 * Returns length of authenticator field, zero if key not found.
875 */
876size_t
877authencrypt(
878	keyid_t		keyno,
879	u_int32 *	pkt,
880	size_t		length
881	)
882{
883	/*
884	 * A zero key identifier means the sender has not verified
885	 * the last message was correctly authenticated. The MAC
886	 * consists of a single word with value zero.
887	 */
888	authencryptions++;
889	pkt[length / 4] = htonl(keyno);
890	if (0 == keyno) {
891		return 4;
892	}
893	if (!authhavekey(keyno)) {
894		return 0;
895	}
896
897	return MD5authencrypt(cache_type,
898			      cache_secret, cache_secretsize,
899			      pkt, length);
900}
901
902
903/*
904 * authdecrypt - verify message authenticator
905 *
906 * Returns TRUE if authenticator valid, FALSE if invalid or not found.
907 */
908int
909authdecrypt(
910	keyid_t		keyno,
911	u_int32 *	pkt,
912	size_t		length,
913	size_t		size
914	)
915{
916	/*
917	 * A zero key identifier means the sender has not verified
918	 * the last message was correctly authenticated.  For our
919	 * purpose this is an invalid authenticator.
920	 */
921	authdecryptions++;
922	if (0 == keyno || !authhavekey(keyno) || size < 4) {
923		return FALSE;
924	}
925
926	return MD5authdecrypt(cache_type,
927			      cache_secret, cache_secretsize,
928			      pkt, length, size);
929}
930