1/*	$NetBSD: authkeys.c,v 1.2 2010/12/04 23:08:34 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 <stdio.h>
11
12#include "ntp_types.h"
13#include "ntp_fp.h"
14#include "ntp.h"
15#include "ntpd.h"
16#include "ntp_string.h"
17#include "ntp_malloc.h"
18#include "ntp_stdlib.h"
19
20/*
21 * Structure to store keys in in the hash table.
22 */
23struct savekey {
24	struct savekey *next;
25	union {
26		u_char MD5_key[64];	/* for keys up to to 512 bits */
27	} k;
28	keyid_t keyid;		/* key identifier */
29	int	type;		/* key type */
30	u_short flags;		/* flags that wave */
31	u_long lifetime;	/* remaining lifetime */
32	int keylen;		/* key length */
33};
34
35#define	KEY_TRUSTED	0x001	/* this key is trusted */
36
37/*
38 * The hash table. This is indexed by the low order bits of the
39 * keyid. We make this fairly big for potentially busy servers.
40 */
41#define	HASHSIZE	64
42#define	HASHMASK	((HASHSIZE)-1)
43#define	KEYHASH(keyid)	((keyid) & HASHMASK)
44
45struct savekey *key_hash[HASHSIZE];
46
47u_long authkeynotfound;		/* keys not found */
48u_long authkeylookups;		/* calls to lookup keys */
49u_long authnumkeys;		/* number of active keys */
50u_long authkeyexpired;		/* key lifetime expirations */
51u_long authkeyuncached;		/* cache misses */
52u_long authnokey;		/* calls to encrypt with no key */
53u_long authencryptions;		/* calls to encrypt */
54u_long authdecryptions;		/* calls to decrypt */
55
56/*
57 * Storage for free key structures.  We malloc() such things but
58 * never free them.
59 */
60struct savekey *authfreekeys;
61int authnumfreekeys;
62
63#define	MEMINC	12		/* number of new free ones to get */
64
65/*
66 * The key cache. We cache the last key we looked at here.
67 */
68keyid_t	cache_keyid;		/* key identifier */
69u_char	*cache_key;		/* key pointer */
70u_int	cache_keylen;		/* key length */
71int	cache_type;		/* key type */
72u_short cache_flags;		/* flags that wave */
73
74
75/*
76 * init_auth - initialize internal data
77 */
78void
79init_auth(void)
80{
81	/*
82	 * Initialize hash table and free list
83	 */
84	memset((char *)key_hash, 0, sizeof key_hash);
85}
86
87
88/*
89 * auth_findkey - find a key in the hash table
90 */
91struct savekey *
92auth_findkey(
93	keyid_t keyno
94	)
95{
96	struct savekey *sk;
97
98	sk = key_hash[KEYHASH(keyno)];
99	while (sk != 0) {
100		if (keyno == sk->keyid)
101			return (sk);
102
103		sk = sk->next;
104	}
105	return (0);
106}
107
108
109/*
110 * auth_havekey - return one if the key is known
111 */
112int
113auth_havekey(
114	keyid_t keyno
115	)
116{
117	struct savekey *sk;
118
119	if (keyno == 0 || (keyno == cache_keyid))
120		return (1);
121
122	sk = key_hash[KEYHASH(keyno)];
123	while (sk != 0) {
124		if (keyno == sk->keyid)
125			return (1);
126
127		sk = sk->next;
128	}
129	return (0);
130}
131
132
133/*
134 * authhavekey - return one and cache the key, if known and trusted.
135 */
136int
137authhavekey(
138	keyid_t keyno
139	)
140{
141	struct savekey *sk;
142
143	authkeylookups++;
144	if (keyno == 0 || keyno == cache_keyid)
145		return (1);
146
147	/*
148	 * Seach the bin for the key. If found and the key type
149	 * is zero, somebody marked it trusted without specifying
150	 * a key or key type. In this case consider the key missing.
151	 */
152	authkeyuncached++;
153	sk = key_hash[KEYHASH(keyno)];
154	while (sk != NULL) {
155		if (keyno == sk->keyid) {
156			if (sk->type == 0) {
157				authkeynotfound++;
158				return (0);
159			}
160			break;
161		}
162		sk = sk->next;
163	}
164
165	/*
166	 * If the key is not found, or if it is found but not trusted,
167	 * the key is not considered found.
168	 */
169	if (sk == NULL) {
170		authkeynotfound++;
171		return (0);
172
173	}
174	if (!(sk->flags & KEY_TRUSTED)) {
175		authnokey++;
176		return (0);
177	}
178
179	/*
180	 * The key is found and trusted. Initialize the key cache.
181	 */
182	cache_keyid = sk->keyid;
183	cache_type = sk->type;
184	cache_flags = sk->flags;
185	cache_key = sk->k.MD5_key;
186	cache_keylen = sk->keylen;
187	return (1);
188}
189
190
191/*
192 * auth_moremem - get some more free key structures
193 */
194int
195auth_moremem(void)
196{
197	struct savekey *sk;
198	int i;
199
200	sk = (struct savekey *)calloc(MEMINC, sizeof(struct savekey));
201	if (sk == 0)
202		return (0);
203
204	for (i = MEMINC; i > 0; i--) {
205		sk->next = authfreekeys;
206		authfreekeys = sk++;
207	}
208	authnumfreekeys += MEMINC;
209	return (authnumfreekeys);
210}
211
212
213/*
214 * authtrust - declare a key to be trusted/untrusted
215 */
216void
217authtrust(
218	keyid_t keyno,
219	u_long trust
220	)
221{
222	struct savekey *sk;
223
224	/*
225	 * Search bin for key; if it does not exist and is untrusted,
226	 * forget it.
227	 */
228	sk = key_hash[KEYHASH(keyno)];
229	while (sk != 0) {
230		if (keyno == sk->keyid)
231		    break;
232
233		sk = sk->next;
234	}
235	if (sk == 0 && !trust)
236		return;
237
238	/*
239	 * There are two conditions remaining. Either it does not
240	 * exist and is to be trusted or it does exist and is or is
241	 * not to be trusted.
242	 */
243	if (sk != 0) {
244		if (cache_keyid == keyno) {
245			cache_flags = 0;
246			cache_keyid = 0;
247		}
248
249		/*
250		 * Key exists. If it is to be trusted, say so and
251		 * update its lifetime. If not, return it to the
252		 * free list.
253		 */
254		if (trust > 0) {
255			sk->flags |= KEY_TRUSTED;
256			if (trust > 1)
257				sk->lifetime = current_time + trust;
258			else
259				sk->lifetime = 0;
260			return;
261		}
262		sk->flags &= ~KEY_TRUSTED; {
263			struct savekey *skp;
264
265			skp = key_hash[KEYHASH(keyno)];
266			if (skp == sk) {
267				key_hash[KEYHASH(keyno)] = sk->next;
268			} else {
269				while (skp->next != sk)
270				    skp = skp->next;
271				skp->next = sk->next;
272			}
273			authnumkeys--;
274
275			sk->next = authfreekeys;
276			authfreekeys = sk;
277			authnumfreekeys++;
278		}
279		return;
280	}
281
282	/*
283	 * Here there is not key, but the key is to be trusted. There
284	 * seems to be a disconnect here. Here we allocate a new key,
285	 * but do not specify a key type, key or key length.
286	 */
287	if (authnumfreekeys == 0)
288	    if (auth_moremem() == 0)
289		return;
290
291	sk = authfreekeys;
292	authfreekeys = sk->next;
293	authnumfreekeys--;
294	sk->keyid = keyno;
295	sk->type = 0;
296	sk->keylen = 0;
297	sk->flags = KEY_TRUSTED;
298	sk->next = key_hash[KEYHASH(keyno)];
299	key_hash[KEYHASH(keyno)] = sk;
300	authnumkeys++;
301	return;
302}
303
304
305/*
306 * authistrusted - determine whether a key is trusted
307 */
308int
309authistrusted(
310	keyid_t keyno
311	)
312{
313	struct savekey *sk;
314
315	if (keyno == cache_keyid)
316	    return ((cache_flags & KEY_TRUSTED) != 0);
317
318	authkeyuncached++;
319	sk = key_hash[KEYHASH(keyno)];
320	while (sk != 0) {
321		if (keyno == sk->keyid)
322		    break;
323		sk = sk->next;
324	}
325	if (sk == 0) {
326		authkeynotfound++;
327		return (0);
328
329	} else if (!(sk->flags & KEY_TRUSTED)) {
330		authkeynotfound++;
331		return (0);
332	}
333	return (1);
334}
335
336
337void
338MD5auth_setkey(
339	keyid_t keyno,
340	int	keytype,
341	const u_char *key,
342	size_t len
343	)
344{
345	struct savekey *sk;
346
347	/*
348	 * See if we already have the key.  If so just stick in the
349	 * new value.
350	 */
351	sk = key_hash[KEYHASH(keyno)];
352	while (sk != NULL) {
353		if (keyno == sk->keyid) {
354			sk->type = keytype;
355			sk->keylen = min(len, sizeof(sk->k.MD5_key));
356#ifndef DISABLE_BUG1243_FIX
357			memcpy(sk->k.MD5_key, key, sk->keylen);
358#else
359			strncpy((char *)sk->k.MD5_key, (const char *)key,
360			    sizeof(sk->k.MD5_key));
361#endif
362			if (cache_keyid == keyno) {
363				cache_flags = 0;
364				cache_keyid = 0;
365			}
366			return;
367		}
368		sk = sk->next;
369	}
370
371	/*
372	 * Need to allocate new structure.  Do it.
373	 */
374	if (0 == authnumfreekeys && !auth_moremem())
375		return;
376
377	sk = authfreekeys;
378	authfreekeys = sk->next;
379	authnumfreekeys--;
380
381	sk->keyid = keyno;
382	sk->type = keytype;
383	sk->flags = 0;
384	sk->lifetime = 0;
385	sk->keylen = min(len, sizeof(sk->k.MD5_key));
386#ifndef DISABLE_BUG1243_FIX
387	memcpy(sk->k.MD5_key, key, sk->keylen);
388#else
389	strncpy((char *)sk->k.MD5_key, (const char *)key,
390	    sizeof(sk->k.MD5_key));
391#endif
392	sk->next = key_hash[KEYHASH(keyno)];
393	key_hash[KEYHASH(keyno)] = sk;
394#ifdef DEBUG
395	if (debug > 1) {
396		char	hex[] = "0123456789abcdef";
397		int	j;
398
399		printf("auth_setkey: key %d type %d len %d ", sk->keyid,
400		    sk->type, sk->keylen);
401		for (j = 0; j < sk->keylen; j++)
402				printf("%c%c", hex[key[j] >> 4],
403				    hex[key[j] & 0xf]);
404		printf("\n");
405	}
406#endif
407	authnumkeys++;
408}
409
410
411/*
412 * auth_delkeys - delete all known keys, in preparation for rereading
413 *		  the keys file (presumably)
414 */
415void
416auth_delkeys(void)
417{
418	struct savekey *sk;
419	struct savekey **skp;
420	int i;
421
422	for (i = 0; i < HASHSIZE; i++) {
423		skp = &(key_hash[i]);
424		sk = key_hash[i];
425		/*
426		 * Leave autokey keys alone.
427		 */
428		while (sk != 0 && sk->keyid <= NTP_MAXKEY) {
429			/*
430			 * Don't lose info as to which keys are trusted.
431			 */
432			if (sk->flags & KEY_TRUSTED) {
433				skp = &(sk->next);
434				memset(&sk->k, 0, sizeof(sk->k));
435				sk->lifetime = 0;
436				sk->keylen = 0;
437				sk = sk->next;
438			} else {
439				*skp = sk->next;
440				authnumkeys--;
441				sk->next = authfreekeys;
442				authfreekeys = sk;
443				authnumfreekeys++;
444				sk = *skp;
445			}
446		}
447	}
448}
449
450/*
451 * auth_agekeys - delete keys whose lifetimes have expired
452 */
453void
454auth_agekeys(void)
455{
456	struct savekey *sk;
457	struct savekey *skp;
458	int i;
459
460	for (i = 0; i < HASHSIZE; i++) {
461		sk = skp = key_hash[i];
462		while (sk != 0) {
463			skp = sk->next;
464			if (sk->lifetime > 0 && current_time >
465			    sk->lifetime) {
466				authtrust(sk->keyid, 0);
467				authkeyexpired++;
468			}
469			sk = skp;
470		}
471	}
472#ifdef DEBUG
473	if (debug)
474		printf("auth_agekeys: at %lu keys %lu expired %lu\n",
475		    current_time, authnumkeys, authkeyexpired);
476#endif
477}
478
479/*
480 * authencrypt - generate message authenticator
481 *
482 * Returns length of authenticator field, zero if key not found.
483 */
484int
485authencrypt(
486	keyid_t keyno,
487	u_int32 *pkt,
488	int length
489	)
490{
491
492	/*
493	 * A zero key identifier means the sender has not verified
494	 * the last message was correctly authenticated. The MAC
495	 * consists of a single word with value zero.
496	 */
497	authencryptions++;
498	pkt[length / 4] = htonl(keyno);
499	if (keyno == 0) {
500		return (4);
501	}
502	if (!authhavekey(keyno))
503		return (0);
504
505	return (MD5authencrypt(cache_type, cache_key, pkt, length));
506}
507
508/*
509 * authdecrypt - verify message authenticator
510 *
511 * Returns one if authenticator valid, zero if invalid or key not found.
512 */
513int
514authdecrypt(
515	keyid_t keyno,
516	u_int32 *pkt,
517	int length,
518	int size
519	)
520{
521
522	/*
523	 * A zero key identifier means the sender has not verified
524	 * the last message was correctly authenticated. Nevertheless,
525	 * the authenticator itself is considered valid.
526	 */
527	authdecryptions++;
528	if (keyno == 0)
529		return (0);
530
531	if (!authhavekey(keyno) || size < 4)
532		return (0);
533
534	return (MD5authdecrypt(cache_type, cache_key, pkt, length,
535	   size));
536}
537