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