xref: /netbsd-src/external/bsd/ntp/dist/libntp/authkeys.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
1*eabc0478Schristos /*	$NetBSD: authkeys.c,v 1.14 2024/08/18 20:47:13 christos Exp $	*/
2abb0f93cSkardel 
3abb0f93cSkardel /*
4abb0f93cSkardel  * authkeys.c - routines to manage the storage of authentication keys
5abb0f93cSkardel  */
6abb0f93cSkardel #ifdef HAVE_CONFIG_H
7abb0f93cSkardel # include <config.h>
8abb0f93cSkardel #endif
9abb0f93cSkardel 
102950cc38Schristos #include <math.h>
11abb0f93cSkardel #include <stdio.h>
12abb0f93cSkardel 
13abb0f93cSkardel #include "ntp.h"
142950cc38Schristos #include "ntp_fp.h"
15abb0f93cSkardel #include "ntpd.h"
162950cc38Schristos #include "ntp_lists.h"
17abb0f93cSkardel #include "ntp_string.h"
18abb0f93cSkardel #include "ntp_malloc.h"
19abb0f93cSkardel #include "ntp_stdlib.h"
2068dbbb44Schristos #include "ntp_keyacc.h"
21abb0f93cSkardel 
22abb0f93cSkardel /*
23abb0f93cSkardel  * Structure to store keys in in the hash table.
24abb0f93cSkardel  */
252950cc38Schristos typedef struct savekey symkey;
262950cc38Schristos 
27abb0f93cSkardel struct savekey {
282950cc38Schristos 	symkey *	hlink;		/* next in hash bucket */
292950cc38Schristos 	DECL_DLIST_LINK(symkey, llink);	/* for overall & free lists */
302950cc38Schristos 	u_char *	secret;		/* shared secret */
3168dbbb44Schristos 	KeyAccT *	keyacclist;	/* Private key access list */
32abb0f93cSkardel 	u_long		lifetime;	/* remaining lifetime */
332950cc38Schristos 	keyid_t		keyid;		/* key identifier */
342950cc38Schristos 	u_short		type;		/* OpenSSL digest NID */
3568dbbb44Schristos 	size_t		secretsize;	/* secret octets */
362950cc38Schristos 	u_short		flags;		/* KEY_ flags that wave */
37abb0f93cSkardel };
38abb0f93cSkardel 
392950cc38Schristos /* define the payload region of symkey beyond the list pointers */
402950cc38Schristos #define symkey_payload	secret
412950cc38Schristos 
42abb0f93cSkardel #define	KEY_TRUSTED	0x001	/* this key is trusted */
43abb0f93cSkardel 
442950cc38Schristos #ifdef DEBUG
452950cc38Schristos typedef struct symkey_alloc_tag symkey_alloc;
462950cc38Schristos 
472950cc38Schristos struct symkey_alloc_tag {
482950cc38Schristos 	symkey_alloc *	link;
492950cc38Schristos 	void *		mem;		/* enable free() atexit */
502950cc38Schristos };
512950cc38Schristos 
522950cc38Schristos symkey_alloc *	authallocs;
532950cc38Schristos #endif	/* DEBUG */
542950cc38Schristos 
5568dbbb44Schristos static u_short	auth_log2(size_t);
562950cc38Schristos static void		auth_resize_hashtable(void);
5768dbbb44Schristos static void		allocsymkey(keyid_t,	u_short,
5868dbbb44Schristos 				    u_short, u_long, size_t, u_char *, KeyAccT *);
5968dbbb44Schristos static void		freesymkey(symkey *);
602950cc38Schristos #ifdef DEBUG
612950cc38Schristos static void		free_auth_mem(void);
622950cc38Schristos #endif
632950cc38Schristos 
642950cc38Schristos symkey	key_listhead;		/* list of all in-use keys */;
65abb0f93cSkardel /*
66abb0f93cSkardel  * The hash table. This is indexed by the low order bits of the
67abb0f93cSkardel  * keyid. We make this fairly big for potentially busy servers.
68abb0f93cSkardel  */
692950cc38Schristos #define	DEF_AUTHHASHSIZE	64
708b8da087Schristos /*#define	HASHMASK	((HASHSIZE)-1)*/
712950cc38Schristos #define	KEYHASH(keyid)	((keyid) & authhashmask)
72abb0f93cSkardel 
732950cc38Schristos int	authhashdisabled;
742950cc38Schristos u_short	authhashbuckets = DEF_AUTHHASHSIZE;
752950cc38Schristos u_short authhashmask = DEF_AUTHHASHSIZE - 1;
762950cc38Schristos symkey **key_hash;
77abb0f93cSkardel 
78abb0f93cSkardel u_long authkeynotfound;		/* keys not found */
79abb0f93cSkardel u_long authkeylookups;		/* calls to lookup keys */
80abb0f93cSkardel u_long authnumkeys;		/* number of active keys */
81abb0f93cSkardel u_long authkeyexpired;		/* key lifetime expirations */
82abb0f93cSkardel u_long authkeyuncached;		/* cache misses */
83abb0f93cSkardel u_long authnokey;		/* calls to encrypt with no key */
84abb0f93cSkardel u_long authencryptions;		/* calls to encrypt */
85abb0f93cSkardel u_long authdecryptions;		/* calls to decrypt */
86abb0f93cSkardel 
87abb0f93cSkardel /*
882950cc38Schristos  * Storage for free symkey structures.  We malloc() such things but
89abb0f93cSkardel  * never free them.
90abb0f93cSkardel  */
912950cc38Schristos symkey *authfreekeys;
92abb0f93cSkardel int authnumfreekeys;
93abb0f93cSkardel 
942950cc38Schristos #define	MEMINC	16		/* number of new free ones to get */
95abb0f93cSkardel 
96abb0f93cSkardel /*
97abb0f93cSkardel  * The key cache. We cache the last key we looked at here.
9868dbbb44Schristos  * Note: this should hold the last *trusted* key. Also the
9968dbbb44Schristos  * cache is only loaded when the digest type / MAC algorithm
10068dbbb44Schristos  * is valid.
101abb0f93cSkardel  */
102abb0f93cSkardel keyid_t	cache_keyid;		/* key identifier */
1032950cc38Schristos u_char *cache_secret;		/* secret */
10468dbbb44Schristos size_t	cache_secretsize;	/* secret length */
1052950cc38Schristos int	cache_type;		/* OpenSSL digest NID */
106abb0f93cSkardel u_short cache_flags;		/* flags that wave */
10768dbbb44Schristos KeyAccT *cache_keyacclist;	/* key access list */
10868dbbb44Schristos 
10968dbbb44Schristos /* --------------------------------------------------------------------
11068dbbb44Schristos  * manage key access lists
11168dbbb44Schristos  * --------------------------------------------------------------------
11268dbbb44Schristos  */
11368dbbb44Schristos /* allocate and populate new access node and pushes it on the list.
11468dbbb44Schristos  * Returns the new head.
11568dbbb44Schristos  */
11668dbbb44Schristos KeyAccT*
11768dbbb44Schristos keyacc_new_push(
11868dbbb44Schristos 	KeyAccT          * head,
1194eea345dSchristos 	const sockaddr_u * addr,
1204eea345dSchristos 	unsigned int	   subnetbits
12168dbbb44Schristos 	)
12268dbbb44Schristos {
12368dbbb44Schristos 	KeyAccT *	node = emalloc(sizeof(KeyAccT));
12468dbbb44Schristos 
12568dbbb44Schristos 	memcpy(&node->addr, addr, sizeof(sockaddr_u));
1264eea345dSchristos 	node->subnetbits = subnetbits;
12768dbbb44Schristos 	node->next = head;
1284eea345dSchristos 
12968dbbb44Schristos 	return node;
13068dbbb44Schristos }
13168dbbb44Schristos 
13268dbbb44Schristos /* ----------------------------------------------------------------- */
13368dbbb44Schristos /* pop and deallocate the first node of a list of access nodes, if
13468dbbb44Schristos  * the list is not empty. Returns the tail of the list.
13568dbbb44Schristos  */
13668dbbb44Schristos KeyAccT*
13768dbbb44Schristos keyacc_pop_free(
13868dbbb44Schristos 	KeyAccT *head
13968dbbb44Schristos 	)
14068dbbb44Schristos {
14168dbbb44Schristos 	KeyAccT *	next = NULL;
14268dbbb44Schristos 	if (head) {
14368dbbb44Schristos 		next = head->next;
14468dbbb44Schristos 		free(head);
14568dbbb44Schristos 	}
14668dbbb44Schristos 	return next;
14768dbbb44Schristos }
14868dbbb44Schristos 
14968dbbb44Schristos /* ----------------------------------------------------------------- */
15068dbbb44Schristos /* deallocate the list; returns an empty list. */
15168dbbb44Schristos KeyAccT*
15268dbbb44Schristos keyacc_all_free(
15368dbbb44Schristos 	KeyAccT * head
15468dbbb44Schristos 	)
15568dbbb44Schristos {
15668dbbb44Schristos 	while (head)
15768dbbb44Schristos 		head = keyacc_pop_free(head);
15868dbbb44Schristos 	return head;
15968dbbb44Schristos }
16068dbbb44Schristos 
16168dbbb44Schristos /* ----------------------------------------------------------------- */
16268dbbb44Schristos /* scan a list to see if it contains a given address. Return the
16368dbbb44Schristos  * default result value in case of an empty list.
16468dbbb44Schristos  */
16568dbbb44Schristos int /*BOOL*/
16668dbbb44Schristos keyacc_contains(
16768dbbb44Schristos 	const KeyAccT    *head,
16868dbbb44Schristos 	const sockaddr_u *addr,
16968dbbb44Schristos 	int               defv)
17068dbbb44Schristos {
17168dbbb44Schristos 	if (head) {
17268dbbb44Schristos 		do {
1734eea345dSchristos 			if (keyacc_amatch(&head->addr, addr,
1744eea345dSchristos 					  head->subnetbits))
17568dbbb44Schristos 				return TRUE;
17668dbbb44Schristos 		} while (NULL != (head = head->next));
17768dbbb44Schristos 		return FALSE;
17868dbbb44Schristos 	} else {
17968dbbb44Schristos 		return !!defv;
18068dbbb44Schristos 	}
18168dbbb44Schristos }
182abb0f93cSkardel 
1834eea345dSchristos #if CHAR_BIT != 8
1844eea345dSchristos # error "don't know how to handle bytes with that bit size"
1854eea345dSchristos #endif
1864eea345dSchristos 
1874eea345dSchristos /* ----------------------------------------------------------------- */
1884eea345dSchristos /* check two addresses for a match, taking a prefix length into account
1894eea345dSchristos  * when doing the compare.
1904eea345dSchristos  *
1914eea345dSchristos  * The ISC lib contains a similar function with not entirely specified
1924eea345dSchristos  * semantics, so it seemed somewhat cleaner to do this from scratch.
1934eea345dSchristos  *
1944eea345dSchristos  * Note 1: It *is* assumed that the addresses are stored in network byte
1954eea345dSchristos  * order, that is, most significant byte first!
1964eea345dSchristos  *
1974eea345dSchristos  * Note 2: "no address" compares unequal to all other addresses, even to
1984eea345dSchristos  * itself. This has the same semantics as NaNs have for floats: *any*
1994eea345dSchristos  * relational or equality operation involving a NaN returns FALSE, even
2004eea345dSchristos  * equality with itself. "no address" is either a NULL pointer argument
2014eea345dSchristos  * or an address of type AF_UNSPEC.
2024eea345dSchristos  */
2034eea345dSchristos int/*BOOL*/
2044eea345dSchristos keyacc_amatch(
2054eea345dSchristos 	const sockaddr_u *	a1,
2064eea345dSchristos 	const sockaddr_u *	a2,
2074eea345dSchristos 	unsigned int		mbits
2084eea345dSchristos 	)
2094eea345dSchristos {
2104eea345dSchristos 	const uint8_t * pm1;
2114eea345dSchristos 	const uint8_t * pm2;
2124eea345dSchristos 	uint8_t         msk;
2134eea345dSchristos 	unsigned int    len;
2144eea345dSchristos 
2154eea345dSchristos 	/* 1st check: If any address is not an address, it's inequal. */
2164eea345dSchristos 	if ( !a1 || (AF_UNSPEC == AF(a1)) ||
2174eea345dSchristos 	     !a2 || (AF_UNSPEC == AF(a2))  )
2184eea345dSchristos 		return FALSE;
2194eea345dSchristos 
2204eea345dSchristos 	/* We could check pointers for equality here and shortcut the
2214eea345dSchristos 	 * other checks if we find object identity. But that use case is
2224eea345dSchristos 	 * too rare to care for it.
2234eea345dSchristos 	 */
2244eea345dSchristos 
2254eea345dSchristos 	/* 2nd check: Address families must be the same. */
2264eea345dSchristos 	if (AF(a1) != AF(a2))
2274eea345dSchristos 		return FALSE;
2284eea345dSchristos 
2294eea345dSchristos 	/* type check: address family determines buffer & size */
2304eea345dSchristos 	switch (AF(a1)) {
2314eea345dSchristos 	case AF_INET:
2324eea345dSchristos 		/* IPv4 is easy: clamp size, get byte pointers */
2334eea345dSchristos 		if (mbits > sizeof(NSRCADR(a1)) * 8)
2344eea345dSchristos 			mbits = sizeof(NSRCADR(a1)) * 8;
2354eea345dSchristos 		pm1 = (const void*)&NSRCADR(a1);
2364eea345dSchristos 		pm2 = (const void*)&NSRCADR(a2);
2374eea345dSchristos 		break;
2384eea345dSchristos 
2394eea345dSchristos 	case AF_INET6:
2404eea345dSchristos 		/* IPv6 is slightly different: Both scopes must match,
2414eea345dSchristos 		 * too, before we even consider doing a match!
2424eea345dSchristos 		 */
2434eea345dSchristos 		if ( ! SCOPE_EQ(a1, a2))
2444eea345dSchristos 			return FALSE;
2454eea345dSchristos 		if (mbits > sizeof(NSRCADR6(a1)) * 8)
2464eea345dSchristos 			mbits = sizeof(NSRCADR6(a1)) * 8;
2474eea345dSchristos 		pm1 = (const void*)&NSRCADR6(a1);
2484eea345dSchristos 		pm2 = (const void*)&NSRCADR6(a2);
2494eea345dSchristos 		break;
2504eea345dSchristos 
2514eea345dSchristos 	default:
2524eea345dSchristos 		/* don't know how to compare that!?! */
2534eea345dSchristos 		return FALSE;
2544eea345dSchristos 	}
2554eea345dSchristos 
2564eea345dSchristos 	/* Split bit length into byte length and partial byte mask.
2574eea345dSchristos 	 * Note that the byte mask extends from the MSB of a byte down,
2584eea345dSchristos 	 * and that zero shift (--> mbits % 8 == 0) results in an
2594eea345dSchristos 	 * all-zero mask.
2604eea345dSchristos 	 */
2614eea345dSchristos 	msk = 0xFFu ^ (0xFFu >> (mbits & 7));
2624eea345dSchristos 	len = mbits >> 3;
2634eea345dSchristos 
2644eea345dSchristos 	/* 3rd check: Do memcmp() over full bytes, if any */
2654eea345dSchristos 	if (len && memcmp(pm1, pm2, len))
2664eea345dSchristos 		return FALSE;
2674eea345dSchristos 
2684eea345dSchristos 	/* 4th check: compare last incomplete byte, if any */
2694eea345dSchristos 	if (msk && ((pm1[len] ^ pm2[len]) & msk))
2704eea345dSchristos 		return FALSE;
2714eea345dSchristos 
2724eea345dSchristos 	/* If none of the above failed, we're successfully through. */
2734eea345dSchristos 	return TRUE;
2744eea345dSchristos }
275abb0f93cSkardel 
276abb0f93cSkardel /*
277abb0f93cSkardel  * init_auth - initialize internal data
278abb0f93cSkardel  */
279abb0f93cSkardel void
280abb0f93cSkardel init_auth(void)
281abb0f93cSkardel {
2822950cc38Schristos 	size_t newalloc;
2832950cc38Schristos 
284abb0f93cSkardel 	/*
285abb0f93cSkardel 	 * Initialize hash table and free list
286abb0f93cSkardel 	 */
2872950cc38Schristos 	newalloc = authhashbuckets * sizeof(key_hash[0]);
2882950cc38Schristos 
289*eabc0478Schristos 	key_hash = emalloc_zero(newalloc);
2902950cc38Schristos 
2912950cc38Schristos 	INIT_DLIST(key_listhead, llink);
2922950cc38Schristos 
2932950cc38Schristos #ifdef DEBUG
2942950cc38Schristos 	atexit(&free_auth_mem);
2952950cc38Schristos #endif
2962950cc38Schristos }
2972950cc38Schristos 
2982950cc38Schristos 
2992950cc38Schristos /*
3002950cc38Schristos  * free_auth_mem - assist in leak detection by freeing all dynamic
3012950cc38Schristos  *		   allocations from this module.
3022950cc38Schristos  */
3032950cc38Schristos #ifdef DEBUG
3042950cc38Schristos static void
3052950cc38Schristos free_auth_mem(void)
3062950cc38Schristos {
3072950cc38Schristos 	symkey *	sk;
3082950cc38Schristos 	symkey_alloc *	alloc;
3092950cc38Schristos 	symkey_alloc *	next_alloc;
3102950cc38Schristos 
3112950cc38Schristos 	while (NULL != (sk = HEAD_DLIST(key_listhead, llink))) {
31268dbbb44Schristos 		freesymkey(sk);
3132950cc38Schristos 	}
3142950cc38Schristos 	free(key_hash);
3152950cc38Schristos 	key_hash = NULL;
3162950cc38Schristos 	cache_keyid = 0;
3172950cc38Schristos 	cache_flags = 0;
31868dbbb44Schristos 	cache_keyacclist = NULL;
3192950cc38Schristos 	for (alloc = authallocs; alloc != NULL; alloc = next_alloc) {
3202950cc38Schristos 		next_alloc = alloc->link;
3212950cc38Schristos 		free(alloc->mem);
3222950cc38Schristos 	}
3232950cc38Schristos 	authfreekeys = NULL;
3242950cc38Schristos 	authnumfreekeys = 0;
3252950cc38Schristos }
3262950cc38Schristos #endif	/* DEBUG */
3272950cc38Schristos 
3282950cc38Schristos 
3292950cc38Schristos /*
3302950cc38Schristos  * auth_moremem - get some more free key structures
3312950cc38Schristos  */
3322950cc38Schristos void
3332950cc38Schristos auth_moremem(
3342950cc38Schristos 	int	keycount
3352950cc38Schristos 	)
3362950cc38Schristos {
3372950cc38Schristos 	symkey *	sk;
3382950cc38Schristos 	int		i;
3392950cc38Schristos #ifdef DEBUG
3402950cc38Schristos 	void *		base;
3412950cc38Schristos 	symkey_alloc *	allocrec;
3422950cc38Schristos # define MOREMEM_EXTRA_ALLOC	(sizeof(*allocrec))
3432950cc38Schristos #else
3442950cc38Schristos # define MOREMEM_EXTRA_ALLOC	(0)
3452950cc38Schristos #endif
3462950cc38Schristos 
3472950cc38Schristos 	i = (keycount > 0)
3482950cc38Schristos 		? keycount
3492950cc38Schristos 		: MEMINC;
350ccc794f0Schristos 	sk = eallocarrayxz(i, sizeof(*sk), MOREMEM_EXTRA_ALLOC);
3512950cc38Schristos #ifdef DEBUG
3522950cc38Schristos 	base = sk;
3532950cc38Schristos #endif
3542950cc38Schristos 	authnumfreekeys += i;
3552950cc38Schristos 
3562950cc38Schristos 	for (; i > 0; i--, sk++) {
3572950cc38Schristos 		LINK_SLIST(authfreekeys, sk, llink.f);
3582950cc38Schristos 	}
3592950cc38Schristos 
3602950cc38Schristos #ifdef DEBUG
3612950cc38Schristos 	allocrec = (void *)sk;
3622950cc38Schristos 	allocrec->mem = base;
3632950cc38Schristos 	LINK_SLIST(authallocs, allocrec, link);
3642950cc38Schristos #endif
3652950cc38Schristos }
3662950cc38Schristos 
3672950cc38Schristos 
3682950cc38Schristos /*
3692950cc38Schristos  * auth_prealloc_symkeys
3702950cc38Schristos  */
3712950cc38Schristos void
3722950cc38Schristos auth_prealloc_symkeys(
3732950cc38Schristos 	int	keycount
3742950cc38Schristos 	)
3752950cc38Schristos {
3762950cc38Schristos 	int	allocated;
3772950cc38Schristos 	int	additional;
3782950cc38Schristos 
3792950cc38Schristos 	allocated = authnumkeys + authnumfreekeys;
3802950cc38Schristos 	additional = keycount - allocated;
3812950cc38Schristos 	if (additional > 0)
3822950cc38Schristos 		auth_moremem(additional);
3832950cc38Schristos 	auth_resize_hashtable();
3842950cc38Schristos }
3852950cc38Schristos 
3862950cc38Schristos 
38768dbbb44Schristos static u_short
38868dbbb44Schristos auth_log2(size_t x)
3892950cc38Schristos {
39068dbbb44Schristos 	/*
39168dbbb44Schristos 	** bithack to calculate floor(log2(x))
39268dbbb44Schristos 	**
39368dbbb44Schristos 	** This assumes
39468dbbb44Schristos 	**   - (sizeof(size_t) is a power of two
39568dbbb44Schristos 	**   - CHAR_BITS is a power of two
39668dbbb44Schristos 	**   - returning zero for arguments <= 0 is OK.
39768dbbb44Schristos 	**
39868dbbb44Schristos 	** Does only shifts, masks and sums in integer arithmetic in
39968dbbb44Schristos 	** log2(CHAR_BIT*sizeof(size_t)) steps. (that is, 5/6 steps for
40068dbbb44Schristos 	** 32bit/64bit size_t)
40168dbbb44Schristos 	*/
40268dbbb44Schristos 	int	s;
40368dbbb44Schristos 	int	r = 0;
40468dbbb44Schristos 	size_t  m = ~(size_t)0;
40568dbbb44Schristos 
40668dbbb44Schristos 	for (s = sizeof(size_t) / 2 * CHAR_BIT; s != 0; s >>= 1) {
40768dbbb44Schristos 		m <<= s;
40868dbbb44Schristos 		if (x & m)
40968dbbb44Schristos 			r += s;
41068dbbb44Schristos 		else
41168dbbb44Schristos 			x <<= s;
41268dbbb44Schristos 	}
41368dbbb44Schristos 	return (u_short)r;
41468dbbb44Schristos }
41568dbbb44Schristos 
4164eea345dSchristos int/*BOOL*/
4174eea345dSchristos ipaddr_match_masked(const sockaddr_u *,const sockaddr_u *,
4184eea345dSchristos 		    unsigned int mbits);
4194eea345dSchristos 
42068dbbb44Schristos static void
42168dbbb44Schristos authcache_flush_id(
42268dbbb44Schristos 	keyid_t id
42368dbbb44Schristos 	)
42468dbbb44Schristos {
42568dbbb44Schristos 	if (cache_keyid == id) {
42668dbbb44Schristos 		cache_keyid = 0;
42768dbbb44Schristos 		cache_type = 0;
42868dbbb44Schristos 		cache_flags = 0;
42968dbbb44Schristos 		cache_secret = NULL;
43068dbbb44Schristos 		cache_secretsize = 0;
43168dbbb44Schristos 		cache_keyacclist = NULL;
43268dbbb44Schristos 	}
4332950cc38Schristos }
4342950cc38Schristos 
4352950cc38Schristos 
4362950cc38Schristos /*
4372950cc38Schristos  * auth_resize_hashtable
4382950cc38Schristos  *
4392950cc38Schristos  * Size hash table to average 4 or fewer entries per bucket initially,
4402950cc38Schristos  * within the bounds of at least 4 and no more than 15 bits for the hash
4412950cc38Schristos  * table index.  Populate the hash table.
4422950cc38Schristos  */
4432950cc38Schristos static void
4442950cc38Schristos auth_resize_hashtable(void)
4452950cc38Schristos {
4462950cc38Schristos 	u_long		totalkeys;
4472950cc38Schristos 	u_short		hashbits;
4482950cc38Schristos 	u_short		hash;
4492950cc38Schristos 	size_t		newalloc;
4502950cc38Schristos 	symkey *	sk;
4512950cc38Schristos 
4522950cc38Schristos 	totalkeys = authnumkeys + authnumfreekeys;
45368dbbb44Schristos 	hashbits = auth_log2(totalkeys / 4) + 1;
4542950cc38Schristos 	hashbits = max(4, hashbits);
4552950cc38Schristos 	hashbits = min(15, hashbits);
4562950cc38Schristos 
4572950cc38Schristos 	authhashbuckets = 1 << hashbits;
4582950cc38Schristos 	authhashmask = authhashbuckets - 1;
4592950cc38Schristos 	newalloc = authhashbuckets * sizeof(key_hash[0]);
4602950cc38Schristos 
4612950cc38Schristos 	key_hash = erealloc(key_hash, newalloc);
462*eabc0478Schristos 	zero_mem(key_hash, newalloc);
4632950cc38Schristos 
4642950cc38Schristos 	ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey)
4652950cc38Schristos 		hash = KEYHASH(sk->keyid);
4662950cc38Schristos 		LINK_SLIST(key_hash[hash], sk, hlink);
4672950cc38Schristos 	ITER_DLIST_END()
4682950cc38Schristos }
4692950cc38Schristos 
4702950cc38Schristos 
4712950cc38Schristos /*
4722950cc38Schristos  * allocsymkey - common code to allocate and link in symkey
4732950cc38Schristos  *
4742950cc38Schristos  * secret must be allocated with a free-compatible allocator.  It is
4752950cc38Schristos  * owned by the referring symkey structure, and will be free()d by
4762950cc38Schristos  * freesymkey().
4772950cc38Schristos  */
4782950cc38Schristos static void
4792950cc38Schristos allocsymkey(
4802950cc38Schristos 	keyid_t		id,
4812950cc38Schristos 	u_short		flags,
4822950cc38Schristos 	u_short		type,
4832950cc38Schristos 	u_long		lifetime,
48468dbbb44Schristos 	size_t		secretsize,
48568dbbb44Schristos 	u_char *	secret,
48668dbbb44Schristos 	KeyAccT *	ka
4872950cc38Schristos 	)
4882950cc38Schristos {
4892950cc38Schristos 	symkey *	sk;
49068dbbb44Schristos 	symkey **	bucket;
49168dbbb44Schristos 
49268dbbb44Schristos 	bucket = &key_hash[KEYHASH(id)];
49368dbbb44Schristos 
4942950cc38Schristos 
4952950cc38Schristos 	if (authnumfreekeys < 1)
4962950cc38Schristos 		auth_moremem(-1);
4972950cc38Schristos 	UNLINK_HEAD_SLIST(sk, authfreekeys, llink.f);
4982950cc38Schristos 	DEBUG_ENSURE(sk != NULL);
4992950cc38Schristos 	sk->keyid = id;
5002950cc38Schristos 	sk->flags = flags;
5012950cc38Schristos 	sk->type = type;
5022950cc38Schristos 	sk->secretsize = secretsize;
5032950cc38Schristos 	sk->secret = secret;
50468dbbb44Schristos 	sk->keyacclist = ka;
5052950cc38Schristos 	sk->lifetime = lifetime;
5062950cc38Schristos 	LINK_SLIST(*bucket, sk, hlink);
5072950cc38Schristos 	LINK_TAIL_DLIST(key_listhead, sk, llink);
5082950cc38Schristos 	authnumfreekeys--;
5092950cc38Schristos 	authnumkeys++;
5102950cc38Schristos }
5112950cc38Schristos 
5122950cc38Schristos 
5132950cc38Schristos /*
5142950cc38Schristos  * freesymkey - common code to remove a symkey and recycle its entry.
5152950cc38Schristos  */
5162950cc38Schristos static void
5172950cc38Schristos freesymkey(
51868dbbb44Schristos 	symkey *	sk
5192950cc38Schristos 	)
5202950cc38Schristos {
52168dbbb44Schristos 	symkey **	bucket;
5222950cc38Schristos 	symkey *	unlinked;
5232950cc38Schristos 
52468dbbb44Schristos 	if (NULL == sk)
52568dbbb44Schristos 		return;
52668dbbb44Schristos 
52768dbbb44Schristos 	authcache_flush_id(sk->keyid);
52868dbbb44Schristos 	keyacc_all_free(sk->keyacclist);
52968dbbb44Schristos 
53068dbbb44Schristos 	bucket = &key_hash[KEYHASH(sk->keyid)];
5312950cc38Schristos 	if (sk->secret != NULL) {
532*eabc0478Schristos 		zero_mem(sk->secret, sk->secretsize);
5332950cc38Schristos 		free(sk->secret);
5342950cc38Schristos 	}
5352950cc38Schristos 	UNLINK_SLIST(unlinked, *bucket, sk, hlink, symkey);
5362950cc38Schristos 	DEBUG_ENSURE(sk == unlinked);
5372950cc38Schristos 	UNLINK_DLIST(sk, llink);
538*eabc0478Schristos 	zero_mem((char *)sk + offsetof(symkey, symkey_payload),
5392950cc38Schristos 		 sizeof(*sk) - offsetof(symkey, symkey_payload));
5402950cc38Schristos 	LINK_SLIST(authfreekeys, sk, llink.f);
5412950cc38Schristos 	authnumkeys--;
5422950cc38Schristos 	authnumfreekeys++;
543abb0f93cSkardel }
544abb0f93cSkardel 
545abb0f93cSkardel 
546abb0f93cSkardel /*
547abb0f93cSkardel  * auth_findkey - find a key in the hash table
548abb0f93cSkardel  */
549abb0f93cSkardel struct savekey *
550abb0f93cSkardel auth_findkey(
5512950cc38Schristos 	keyid_t		id
552abb0f93cSkardel 	)
553abb0f93cSkardel {
5542950cc38Schristos 	symkey *	sk;
555abb0f93cSkardel 
55668dbbb44Schristos 	for (sk = key_hash[KEYHASH(id)]; sk != NULL; sk = sk->hlink)
55768dbbb44Schristos 		if (id == sk->keyid)
5582950cc38Schristos 			return sk;
5592950cc38Schristos 	return NULL;
560abb0f93cSkardel }
561abb0f93cSkardel 
562abb0f93cSkardel 
563abb0f93cSkardel /*
56468dbbb44Schristos  * auth_havekey - return TRUE if the key id is zero or known. The
56568dbbb44Schristos  * key needs not to be trusted.
566abb0f93cSkardel  */
567abb0f93cSkardel int
568abb0f93cSkardel auth_havekey(
5692950cc38Schristos 	keyid_t		id
570abb0f93cSkardel 	)
571abb0f93cSkardel {
57268dbbb44Schristos 	return
57368dbbb44Schristos 	    (0           == id) ||
57468dbbb44Schristos 	    (cache_keyid == id) ||
57568dbbb44Schristos 	    (NULL        != auth_findkey(id));
576abb0f93cSkardel }
577abb0f93cSkardel 
578abb0f93cSkardel 
579abb0f93cSkardel /*
5802950cc38Schristos  * authhavekey - return TRUE and cache the key, if zero or both known
5812950cc38Schristos  *		 and trusted.
582abb0f93cSkardel  */
583abb0f93cSkardel int
584abb0f93cSkardel authhavekey(
5852950cc38Schristos 	keyid_t		id
586abb0f93cSkardel 	)
587abb0f93cSkardel {
5882950cc38Schristos 	symkey *	sk;
589abb0f93cSkardel 
590abb0f93cSkardel 	authkeylookups++;
59168dbbb44Schristos 	if (0 == id || cache_keyid == id)
59268dbbb44Schristos 		return !!(KEY_TRUSTED & cache_flags);
593abb0f93cSkardel 
594abb0f93cSkardel 	/*
59568dbbb44Schristos 	 * Search the bin for the key. If not found, or found but the key
59668dbbb44Schristos 	 * type is zero, somebody marked it trusted without specifying a
59768dbbb44Schristos 	 * key or key type. In this case consider the key missing.
598abb0f93cSkardel 	 */
599abb0f93cSkardel 	authkeyuncached++;
60068dbbb44Schristos 	sk = auth_findkey(id);
60168dbbb44Schristos 	if ((sk == NULL) || (sk->type == 0)) {
602abb0f93cSkardel 		authkeynotfound++;
6032950cc38Schristos 		return FALSE;
604abb0f93cSkardel 	}
605abb0f93cSkardel 
606abb0f93cSkardel 	/*
60768dbbb44Schristos 	 * If the key is not trusted, the key is not considered found.
608abb0f93cSkardel 	 */
6092950cc38Schristos 	if ( ! (KEY_TRUSTED & sk->flags)) {
610abb0f93cSkardel 		authnokey++;
6112950cc38Schristos 		return FALSE;
612abb0f93cSkardel 	}
613abb0f93cSkardel 
614abb0f93cSkardel 	/*
615abb0f93cSkardel 	 * The key is found and trusted. Initialize the key cache.
616*eabc0478Schristos 	 * The cache really should be a struct savekey to streamline
617*eabc0478Schristos 	 * this code.  Using a sk pointer would be even faster but more
618*eabc0478Schristos 	 * fragile around pointing to freed memory.
619abb0f93cSkardel 	 */
620abb0f93cSkardel 	cache_keyid = sk->keyid;
621abb0f93cSkardel 	cache_type = sk->type;
622abb0f93cSkardel 	cache_flags = sk->flags;
6232950cc38Schristos 	cache_secret = sk->secret;
6242950cc38Schristos 	cache_secretsize = sk->secretsize;
62568dbbb44Schristos 	cache_keyacclist = sk->keyacclist;
626abb0f93cSkardel 
6272950cc38Schristos 	return TRUE;
628abb0f93cSkardel }
629abb0f93cSkardel 
630abb0f93cSkardel 
631abb0f93cSkardel /*
632abb0f93cSkardel  * authtrust - declare a key to be trusted/untrusted
633abb0f93cSkardel  */
634abb0f93cSkardel void
635abb0f93cSkardel authtrust(
6362950cc38Schristos 	keyid_t		id,
637abb0f93cSkardel 	u_long		trust
638abb0f93cSkardel 	)
639abb0f93cSkardel {
6402950cc38Schristos 	symkey *	sk;
6412950cc38Schristos 	u_long		lifetime;
642abb0f93cSkardel 
643abb0f93cSkardel 	/*
644abb0f93cSkardel 	 * Search bin for key; if it does not exist and is untrusted,
645abb0f93cSkardel 	 * forget it.
646abb0f93cSkardel 	 */
64768dbbb44Schristos 
64868dbbb44Schristos 	sk = auth_findkey(id);
64968dbbb44Schristos 	if (!trust && sk == NULL)
650abb0f93cSkardel 		return;
651abb0f93cSkardel 
652abb0f93cSkardel 	/*
653abb0f93cSkardel 	 * There are two conditions remaining. Either it does not
654abb0f93cSkardel 	 * exist and is to be trusted or it does exist and is or is
655abb0f93cSkardel 	 * not to be trusted.
656abb0f93cSkardel 	 */
6572950cc38Schristos 	if (sk != NULL) {
658abb0f93cSkardel 		/*
65968dbbb44Schristos 		 * Key exists. If it is to be trusted, say so and update
66068dbbb44Schristos 		 * its lifetime. If no longer trusted, return it to the
66168dbbb44Schristos 		 * free list. Flush the cache first to be sure there are
66268dbbb44Schristos 		 * no discrepancies.
663abb0f93cSkardel 		 */
66468dbbb44Schristos 		authcache_flush_id(id);
665abb0f93cSkardel 		if (trust > 0) {
666abb0f93cSkardel 			sk->flags |= KEY_TRUSTED;
667abb0f93cSkardel 			if (trust > 1)
668abb0f93cSkardel 				sk->lifetime = current_time + trust;
669abb0f93cSkardel 			else
670abb0f93cSkardel 				sk->lifetime = 0;
67168dbbb44Schristos 		} else {
67268dbbb44Schristos 			freesymkey(sk);
673abb0f93cSkardel 		}
674abb0f93cSkardel 		return;
675abb0f93cSkardel 	}
676abb0f93cSkardel 
677abb0f93cSkardel 	/*
6782950cc38Schristos 	 * keyid is not present, but the is to be trusted.  We allocate
6792950cc38Schristos 	 * a new key, but do not specify a key type or secret.
680abb0f93cSkardel 	 */
6812950cc38Schristos 	if (trust > 1) {
6822950cc38Schristos 		lifetime = current_time + trust;
6832950cc38Schristos 	} else {
6842950cc38Schristos 		lifetime = 0;
6852950cc38Schristos 	}
68668dbbb44Schristos 	allocsymkey(id, KEY_TRUSTED, 0, lifetime, 0, NULL, NULL);
687abb0f93cSkardel }
688abb0f93cSkardel 
689abb0f93cSkardel 
690abb0f93cSkardel /*
691abb0f93cSkardel  * authistrusted - determine whether a key is trusted
692abb0f93cSkardel  */
693abb0f93cSkardel int
694abb0f93cSkardel authistrusted(
69568dbbb44Schristos 	keyid_t		id
696abb0f93cSkardel 	)
697abb0f93cSkardel {
6982950cc38Schristos 	symkey *	sk;
699abb0f93cSkardel 
70068dbbb44Schristos 	if (id == cache_keyid)
7012950cc38Schristos 		return !!(KEY_TRUSTED & cache_flags);
702abb0f93cSkardel 
703abb0f93cSkardel 	authkeyuncached++;
70468dbbb44Schristos 	sk = auth_findkey(id);
70568dbbb44Schristos 	if (sk == NULL || !(KEY_TRUSTED & sk->flags)) {
706abb0f93cSkardel 		authkeynotfound++;
7072950cc38Schristos 		return FALSE;
708abb0f93cSkardel 	}
7092950cc38Schristos 	return TRUE;
710abb0f93cSkardel }
711abb0f93cSkardel 
71268dbbb44Schristos 
71368dbbb44Schristos /*
71468dbbb44Schristos  * authistrustedip - determine if the IP is OK for the keyid
71568dbbb44Schristos  */
71668dbbb44Schristos  int
71768dbbb44Schristos  authistrustedip(
71868dbbb44Schristos  	keyid_t		keyno,
71968dbbb44Schristos 	sockaddr_u *	sau
72068dbbb44Schristos 	)
72168dbbb44Schristos {
72268dbbb44Schristos 	symkey *	sk;
72368dbbb44Schristos 
72468dbbb44Schristos 	if (keyno == cache_keyid) {
72568dbbb44Schristos 		return (KEY_TRUSTED & cache_flags) &&
72668dbbb44Schristos 			keyacc_contains(cache_keyacclist, sau, TRUE);
7274eea345dSchristos 	}
7284eea345dSchristos 
7294eea345dSchristos 	if (NULL != (sk = auth_findkey(keyno))) {
73068dbbb44Schristos 		authkeyuncached++;
73168dbbb44Schristos 		return (KEY_TRUSTED & sk->flags) &&
73268dbbb44Schristos 			keyacc_contains(sk->keyacclist, sau, TRUE);
73368dbbb44Schristos 	}
7344eea345dSchristos 
7354eea345dSchristos 	authkeynotfound++;
7364eea345dSchristos 	return FALSE;
73768dbbb44Schristos }
73868dbbb44Schristos 
7398b8da087Schristos /* Note: There are two locations below where 'strncpy()' is used. While
7408b8da087Schristos  * this function is a hazard by itself, it's essential that it is used
7418b8da087Schristos  * here. Bug 1243 involved that the secret was filled with NUL bytes
7428b8da087Schristos  * after the first NUL encountered, and 'strlcpy()' simply does NOT have
7438b8da087Schristos  * this behaviour. So disabling the fix and reverting to the buggy
7448b8da087Schristos  * behaviour due to compatibility issues MUST also fill with NUL and
7458b8da087Schristos  * this needs 'strncpy'. Also, the secret is managed as a byte blob of a
7468b8da087Schristos  * given size, and eventually truncating it and replacing the last byte
7478b8da087Schristos  * with a NUL would be a bug.
7488b8da087Schristos  * perlinger@ntp.org 2015-10-10
7498b8da087Schristos  */
750abb0f93cSkardel void
751abb0f93cSkardel MD5auth_setkey(
752abb0f93cSkardel 	keyid_t keyno,
753abb0f93cSkardel 	int	keytype,
754abb0f93cSkardel 	const u_char *key,
75568dbbb44Schristos 	size_t secretsize,
75668dbbb44Schristos 	KeyAccT *ka
757abb0f93cSkardel 	)
758abb0f93cSkardel {
7592950cc38Schristos 	symkey *	sk;
7602950cc38Schristos 	u_char *	secret;
761abb0f93cSkardel 
7622950cc38Schristos 	DEBUG_ENSURE(keytype <= USHRT_MAX);
76368dbbb44Schristos 	DEBUG_ENSURE(secretsize < 4 * 1024);
764abb0f93cSkardel 	/*
765abb0f93cSkardel 	 * See if we already have the key.  If so just stick in the
766abb0f93cSkardel 	 * new value.
767abb0f93cSkardel 	 */
76868dbbb44Schristos 	sk = auth_findkey(keyno);
76968dbbb44Schristos 	if (sk != NULL && keyno == sk->keyid) {
770af12ab5eSchristos 			/* TALOS-CAN-0054: make sure we have a new buffer! */
771af12ab5eSchristos 		if (NULL != sk->secret) {
772af12ab5eSchristos 			memset(sk->secret, 0, sk->secretsize);
773af12ab5eSchristos 			free(sk->secret);
774af12ab5eSchristos 		}
77568dbbb44Schristos 		sk->secret = emalloc(secretsize + 1);
7762950cc38Schristos 		sk->type = (u_short)keytype;
77768dbbb44Schristos 		sk->secretsize = secretsize;
77868dbbb44Schristos 		/* make sure access lists don't leak here! */
77968dbbb44Schristos 		if (ka != sk->keyacclist) {
78068dbbb44Schristos 			keyacc_all_free(sk->keyacclist);
78168dbbb44Schristos 			sk->keyacclist = ka;
78268dbbb44Schristos 		}
783abb0f93cSkardel #ifndef DISABLE_BUG1243_FIX
7842950cc38Schristos 		memcpy(sk->secret, key, secretsize);
785abb0f93cSkardel #else
7868b8da087Schristos 		/* >MUST< use 'strncpy()' here! See above! */
7878b8da087Schristos 		strncpy((char *)sk->secret, (const char *)key,
7882950cc38Schristos 			secretsize);
789abb0f93cSkardel #endif
79068dbbb44Schristos 		authcache_flush_id(keyno);
791abb0f93cSkardel 		return;
792abb0f93cSkardel 	}
793abb0f93cSkardel 
794abb0f93cSkardel 	/*
795abb0f93cSkardel 	 * Need to allocate new structure.  Do it.
796abb0f93cSkardel 	 */
79768dbbb44Schristos 	secret = emalloc(secretsize + 1);
798abb0f93cSkardel #ifndef DISABLE_BUG1243_FIX
7992950cc38Schristos 	memcpy(secret, key, secretsize);
800abb0f93cSkardel #else
8018b8da087Schristos 	/* >MUST< use 'strncpy()' here! See above! */
8028b8da087Schristos 	strncpy((char *)secret, (const char *)key, secretsize);
803abb0f93cSkardel #endif
80468dbbb44Schristos 	allocsymkey(keyno, 0, (u_short)keytype, 0,
80568dbbb44Schristos 		    secretsize, secret, ka);
806abb0f93cSkardel #ifdef DEBUG
807*eabc0478Schristos 	if (debug >= 1) {
8082950cc38Schristos 		size_t	j;
809abb0f93cSkardel 
8102950cc38Schristos 		printf("auth_setkey: key %d type %d len %d ", (int)keyno,
8112950cc38Schristos 		    keytype, (int)secretsize);
81268dbbb44Schristos 		for (j = 0; j < secretsize; j++) {
8132950cc38Schristos 			printf("%02x", secret[j]);
81468dbbb44Schristos 		}
815abb0f93cSkardel 		printf("\n");
816abb0f93cSkardel 	}
817abb0f93cSkardel #endif
818abb0f93cSkardel }
819abb0f93cSkardel 
820abb0f93cSkardel 
821abb0f93cSkardel /*
8222950cc38Schristos  * auth_delkeys - delete non-autokey untrusted keys, and clear all info
8232950cc38Schristos  *		  except the trusted bit of non-autokey trusted keys, in
8242950cc38Schristos  *		  preparation for rereading the keys file.
825abb0f93cSkardel  */
826abb0f93cSkardel void
827abb0f93cSkardel auth_delkeys(void)
828abb0f93cSkardel {
8292950cc38Schristos 	symkey *	sk;
830abb0f93cSkardel 
8312950cc38Schristos 	ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey)
8322950cc38Schristos 		if (sk->keyid > NTP_MAXKEY) {	/* autokey */
8332950cc38Schristos 			continue;
8342950cc38Schristos 		}
8352950cc38Schristos 
836abb0f93cSkardel 		/*
837af12ab5eSchristos 		 * Don't lose info as to which keys are trusted. Make
838af12ab5eSchristos 		 * sure there are no dangling pointers!
839abb0f93cSkardel 		 */
8402950cc38Schristos 		if (KEY_TRUSTED & sk->flags) {
8412950cc38Schristos 			if (sk->secret != NULL) {
842*eabc0478Schristos 				zero_mem(sk->secret, sk->secretsize);
8432950cc38Schristos 				free(sk->secret);
844af12ab5eSchristos 				sk->secret = NULL; /* TALOS-CAN-0054 */
8452950cc38Schristos 			}
84668dbbb44Schristos 			sk->keyacclist = keyacc_all_free(sk->keyacclist);
8472950cc38Schristos 			sk->secretsize = 0;
848abb0f93cSkardel 			sk->lifetime = 0;
849abb0f93cSkardel 		} else {
85068dbbb44Schristos 			freesymkey(sk);
851abb0f93cSkardel 		}
8522950cc38Schristos 	ITER_DLIST_END()
853abb0f93cSkardel }
8542950cc38Schristos 
855abb0f93cSkardel 
856abb0f93cSkardel /*
857abb0f93cSkardel  * auth_agekeys - delete keys whose lifetimes have expired
858abb0f93cSkardel  */
859abb0f93cSkardel void
860abb0f93cSkardel auth_agekeys(void)
861abb0f93cSkardel {
8622950cc38Schristos 	symkey *	sk;
863abb0f93cSkardel 
8642950cc38Schristos 	ITER_DLIST_BEGIN(key_listhead, sk, llink, symkey)
8652950cc38Schristos 		if (sk->lifetime > 0 && current_time > sk->lifetime) {
86668dbbb44Schristos 			freesymkey(sk);
867abb0f93cSkardel 			authkeyexpired++;
868abb0f93cSkardel 		}
8692950cc38Schristos 	ITER_DLIST_END()
8702950cc38Schristos 	DPRINTF(1, ("auth_agekeys: at %lu keys %lu expired %lu\n",
8712950cc38Schristos 		    current_time, authnumkeys, authkeyexpired));
872abb0f93cSkardel }
8732950cc38Schristos 
874abb0f93cSkardel 
875abb0f93cSkardel /*
876abb0f93cSkardel  * authencrypt - generate message authenticator
877abb0f93cSkardel  *
878abb0f93cSkardel  * Returns length of authenticator field, zero if key not found.
879abb0f93cSkardel  */
8808b8da087Schristos size_t
881abb0f93cSkardel authencrypt(
882abb0f93cSkardel 	keyid_t		keyno,
883abb0f93cSkardel 	u_int32 *	pkt,
8848b8da087Schristos 	size_t		length
885abb0f93cSkardel 	)
8868b8da087Schristos {
887abb0f93cSkardel 	/*
888abb0f93cSkardel 	 * A zero key identifier means the sender has not verified
889abb0f93cSkardel 	 * the last message was correctly authenticated. The MAC
890abb0f93cSkardel 	 * consists of a single word with value zero.
891abb0f93cSkardel 	 */
892abb0f93cSkardel 	authencryptions++;
893*eabc0478Schristos 	pkt[length / KEY_MAC_LEN] = htonl(keyno);
8942950cc38Schristos 	if (0 == keyno) {
895*eabc0478Schristos 		return KEY_MAC_LEN;
896abb0f93cSkardel 	}
8972950cc38Schristos 	if (!authhavekey(keyno)) {
8982950cc38Schristos 		return 0;
8992950cc38Schristos 	}
900abb0f93cSkardel 
9014eea345dSchristos 	return MD5authencrypt(cache_type,
9024eea345dSchristos 			      cache_secret, cache_secretsize,
9034eea345dSchristos 			      pkt, length);
904abb0f93cSkardel }
905abb0f93cSkardel 
9062950cc38Schristos 
907abb0f93cSkardel /*
908abb0f93cSkardel  * authdecrypt - verify message authenticator
909abb0f93cSkardel  *
9102950cc38Schristos  * Returns TRUE if authenticator valid, FALSE if invalid or not found.
911abb0f93cSkardel  */
912abb0f93cSkardel int
913abb0f93cSkardel authdecrypt(
914abb0f93cSkardel 	keyid_t		keyno,
915abb0f93cSkardel 	u_int32 *	pkt,
9168b8da087Schristos 	size_t		length,
9178b8da087Schristos 	size_t		size
918abb0f93cSkardel 	)
919abb0f93cSkardel {
920abb0f93cSkardel 	/*
921abb0f93cSkardel 	 * A zero key identifier means the sender has not verified
9222950cc38Schristos 	 * the last message was correctly authenticated.  For our
9232950cc38Schristos 	 * purpose this is an invalid authenticator.
924abb0f93cSkardel 	 */
925abb0f93cSkardel 	authdecryptions++;
9262950cc38Schristos 	if (0 == keyno || !authhavekey(keyno) || size < 4) {
9272950cc38Schristos 		return FALSE;
9282950cc38Schristos 	}
929abb0f93cSkardel 
9304eea345dSchristos 	return MD5authdecrypt(cache_type,
9314eea345dSchristos 			      cache_secret, cache_secretsize,
932*eabc0478Schristos 			      pkt, length, size, keyno);
933*eabc0478Schristos }
934*eabc0478Schristos 
935*eabc0478Schristos 
936*eabc0478Schristos /* password decoding helpers */
937*eabc0478Schristos static size_t
938*eabc0478Schristos pwdecode_plain(
939*eabc0478Schristos 	u_char *	dst,
940*eabc0478Schristos 	size_t 		dstlen,
941*eabc0478Schristos 	const char *	src
942*eabc0478Schristos 	)
943*eabc0478Schristos {
944*eabc0478Schristos 	size_t		srclen = strlen(src);
945*eabc0478Schristos 	if (srclen > dstlen) {
946*eabc0478Schristos 		errno = ENOMEM;
947*eabc0478Schristos 		return (size_t)-1;
948*eabc0478Schristos 	}
949*eabc0478Schristos 	memcpy(dst, src, srclen);
950*eabc0478Schristos 	return srclen;
951*eabc0478Schristos }
952*eabc0478Schristos 
953*eabc0478Schristos static size_t
954*eabc0478Schristos pwdecode_hex(
955*eabc0478Schristos 	u_char *	dst,
956*eabc0478Schristos 	size_t 		dstlen,
957*eabc0478Schristos 	const char *	src
958*eabc0478Schristos 	)
959*eabc0478Schristos {
960*eabc0478Schristos 	static const char hex[] = "00112233445566778899AaBbCcDdEeFf";
961*eabc0478Schristos 
962*eabc0478Schristos 	size_t		srclen = strlen(src);
963*eabc0478Schristos 	size_t		reslen = (srclen >> 1) + (srclen & 1);
964*eabc0478Schristos 	u_char		tmp;
965*eabc0478Schristos 	char		*ptr;
966*eabc0478Schristos 	size_t		j;
967*eabc0478Schristos 
968*eabc0478Schristos 	if (reslen > dstlen) {
969*eabc0478Schristos 		errno = ENOMEM;
970*eabc0478Schristos 		reslen = (size_t)-1;
971*eabc0478Schristos 	} else {
972*eabc0478Schristos 		for (j = 0; j < srclen; ++j) {
973*eabc0478Schristos 			tmp = *(const unsigned char*)(src + j);
974*eabc0478Schristos 			ptr = strchr(hex, tmp);
975*eabc0478Schristos 			if (ptr == NULL) {
976*eabc0478Schristos 				errno = EINVAL;
977*eabc0478Schristos 				reslen = (size_t)-1;
978*eabc0478Schristos 				break;
979*eabc0478Schristos 			}
980*eabc0478Schristos 			tmp = (u_char)((ptr - hex) >> 1);
981*eabc0478Schristos 			if (j & 1)
982*eabc0478Schristos 				dst[j >> 1] |= tmp;
983*eabc0478Schristos 			else
984*eabc0478Schristos 				dst[j >> 1] = tmp << 4;
985*eabc0478Schristos 		}
986*eabc0478Schristos 	}
987*eabc0478Schristos 	return reslen;
988*eabc0478Schristos }
989*eabc0478Schristos /*
990*eabc0478Schristos  * authdecodepw - decode plaintext or hex-encoded password to binary
991*eabc0478Schristos  * secret.  Returns size of secret in bytes or -1 on error.
992*eabc0478Schristos  */
993*eabc0478Schristos size_t
994*eabc0478Schristos authdecodepw(
995*eabc0478Schristos 	u_char *	dst,
996*eabc0478Schristos 	size_t 		dstlen,
997*eabc0478Schristos 	const char *	src,
998*eabc0478Schristos 	enum AuthPwdEnc	enc
999*eabc0478Schristos 	)
1000*eabc0478Schristos {
1001*eabc0478Schristos 	size_t		reslen;
1002*eabc0478Schristos 
1003*eabc0478Schristos 	if ( !(dst && dstlen && src)) {
1004*eabc0478Schristos 		errno  = EINVAL;
1005*eabc0478Schristos 		reslen = (size_t)-1;
1006*eabc0478Schristos 	} else {
1007*eabc0478Schristos 		switch (enc) {
1008*eabc0478Schristos 		case AUTHPWD_UNSPEC:
1009*eabc0478Schristos 			if (strlen(src) <= 20)
1010*eabc0478Schristos 				reslen = pwdecode_plain(dst, dstlen, src);
1011*eabc0478Schristos 			else
1012*eabc0478Schristos 				reslen = pwdecode_hex(dst, dstlen, src);
1013*eabc0478Schristos 			break;
1014*eabc0478Schristos 		case AUTHPWD_PLAIN:
1015*eabc0478Schristos 			reslen = pwdecode_plain(dst, dstlen, src);
1016*eabc0478Schristos 			break;
1017*eabc0478Schristos 		case AUTHPWD_HEX:
1018*eabc0478Schristos 			reslen = pwdecode_hex(dst, dstlen, src);
1019*eabc0478Schristos 			break;
1020*eabc0478Schristos 		default:
1021*eabc0478Schristos 			errno = EINVAL;
1022*eabc0478Schristos 			reslen = (size_t)-1;
1023*eabc0478Schristos 		}
1024*eabc0478Schristos 	}
1025*eabc0478Schristos 	return reslen;
1026abb0f93cSkardel }
1027