Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / ntp / dist / libntp / authkeys.c
blob5fc43ee09b6c7389dcf68fc33a1d5387dcafa346
1 /* $NetBSD$ */
3 /*
4 * authkeys.c - routines to manage the storage of authentication keys
5 */
6 #ifdef HAVE_CONFIG_H
7 # include <config.h>
8 #endif
10 #include <stdio.h>
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"
21 * Structure to store keys in in the hash table.
23 struct 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 */
35 #define KEY_TRUSTED 0x001 /* this key is trusted */
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.
41 #define HASHSIZE 64
42 #define HASHMASK ((HASHSIZE)-1)
43 #define KEYHASH(keyid) ((keyid) & HASHMASK)
45 struct savekey *key_hash[HASHSIZE];
47 u_long authkeynotfound; /* keys not found */
48 u_long authkeylookups; /* calls to lookup keys */
49 u_long authnumkeys; /* number of active keys */
50 u_long authkeyexpired; /* key lifetime expirations */
51 u_long authkeyuncached; /* cache misses */
52 u_long authnokey; /* calls to encrypt with no key */
53 u_long authencryptions; /* calls to encrypt */
54 u_long authdecryptions; /* calls to decrypt */
57 * Storage for free key structures. We malloc() such things but
58 * never free them.
60 struct savekey *authfreekeys;
61 int authnumfreekeys;
63 #define MEMINC 12 /* number of new free ones to get */
66 * The key cache. We cache the last key we looked at here.
68 keyid_t cache_keyid; /* key identifier */
69 u_char *cache_key; /* key pointer */
70 u_int cache_keylen; /* key length */
71 int cache_type; /* key type */
72 u_short cache_flags; /* flags that wave */
76 * init_auth - initialize internal data
78 void
79 init_auth(void)
82 * Initialize hash table and free list
84 memset((char *)key_hash, 0, sizeof key_hash);
89 * auth_findkey - find a key in the hash table
91 struct savekey *
92 auth_findkey(
93 keyid_t keyno
96 struct savekey *sk;
98 sk = key_hash[KEYHASH(keyno)];
99 while (sk != 0) {
100 if (keyno == sk->keyid)
101 return (sk);
103 sk = sk->next;
105 return (0);
110 * auth_havekey - return one if the key is known
113 auth_havekey(
114 keyid_t keyno
117 struct savekey *sk;
119 if (keyno == 0 || (keyno == cache_keyid))
120 return (1);
122 sk = key_hash[KEYHASH(keyno)];
123 while (sk != 0) {
124 if (keyno == sk->keyid)
125 return (1);
127 sk = sk->next;
129 return (0);
134 * authhavekey - return one and cache the key, if known and trusted.
137 authhavekey(
138 keyid_t keyno
141 struct savekey *sk;
143 authkeylookups++;
144 if (keyno == 0 || keyno == cache_keyid)
145 return (1);
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.
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);
160 break;
162 sk = sk->next;
166 * If the key is not found, or if it is found but not trusted,
167 * the key is not considered found.
169 if (sk == NULL) {
170 authkeynotfound++;
171 return (0);
174 if (!(sk->flags & KEY_TRUSTED)) {
175 authnokey++;
176 return (0);
180 * The key is found and trusted. Initialize the key cache.
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);
192 * auth_moremem - get some more free key structures
195 auth_moremem(void)
197 struct savekey *sk;
198 int i;
200 sk = (struct savekey *)calloc(MEMINC, sizeof(struct savekey));
201 if (sk == 0)
202 return (0);
204 for (i = MEMINC; i > 0; i--) {
205 sk->next = authfreekeys;
206 authfreekeys = sk++;
208 authnumfreekeys += MEMINC;
209 return (authnumfreekeys);
214 * authtrust - declare a key to be trusted/untrusted
216 void
217 authtrust(
218 keyid_t keyno,
219 u_long trust
222 struct savekey *sk;
225 * Search bin for key; if it does not exist and is untrusted,
226 * forget it.
228 sk = key_hash[KEYHASH(keyno)];
229 while (sk != 0) {
230 if (keyno == sk->keyid)
231 break;
233 sk = sk->next;
235 if (sk == 0 && !trust)
236 return;
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.
243 if (sk != 0) {
244 if (cache_keyid == keyno) {
245 cache_flags = 0;
246 cache_keyid = 0;
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.
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;
262 sk->flags &= ~KEY_TRUSTED; {
263 struct savekey *skp;
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;
273 authnumkeys--;
275 sk->next = authfreekeys;
276 authfreekeys = sk;
277 authnumfreekeys++;
279 return;
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.
287 if (authnumfreekeys == 0)
288 if (auth_moremem() == 0)
289 return;
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;
306 * authistrusted - determine whether a key is trusted
309 authistrusted(
310 keyid_t keyno
313 struct savekey *sk;
315 if (keyno == cache_keyid)
316 return ((cache_flags & KEY_TRUSTED) != 0);
318 authkeyuncached++;
319 sk = key_hash[KEYHASH(keyno)];
320 while (sk != 0) {
321 if (keyno == sk->keyid)
322 break;
323 sk = sk->next;
325 if (sk == 0) {
326 authkeynotfound++;
327 return (0);
329 } else if (!(sk->flags & KEY_TRUSTED)) {
330 authkeynotfound++;
331 return (0);
333 return (1);
337 void
338 MD5auth_setkey(
339 keyid_t keyno,
340 int keytype,
341 const u_char *key,
342 const int len
345 struct savekey *sk;
348 * See if we already have the key. If so just stick in the
349 * new value.
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;
366 return;
368 sk = sk->next;
372 * Need to allocate new structure. Do it.
374 if (0 == authnumfreekeys && !auth_moremem())
375 return;
377 sk = authfreekeys;
378 authfreekeys = sk->next;
379 authnumfreekeys--;
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;
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");
406 #endif
407 authnumkeys++;
412 * auth_delkeys - delete all known keys, in preparation for rereading
413 * the keys file (presumably)
415 void
416 auth_delkeys(void)
418 struct savekey *sk;
419 struct savekey **skp;
420 int i;
422 for (i = 0; i < HASHSIZE; i++) {
423 skp = &(key_hash[i]);
424 sk = key_hash[i];
426 * Leave autokey keys alone.
428 while (sk != 0 && sk->keyid <= NTP_MAXKEY) {
430 * Don't lose info as to which keys are trusted.
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;
451 * auth_agekeys - delete keys whose lifetimes have expired
453 void
454 auth_agekeys(void)
456 struct savekey *sk;
457 struct savekey *skp;
458 int i;
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++;
469 sk = skp;
472 #ifdef DEBUG
473 if (debug)
474 printf("auth_agekeys: at %lu keys %lu expired %lu\n",
475 current_time, authnumkeys, authkeyexpired);
476 #endif
480 * authencrypt - generate message authenticator
482 * Returns length of authenticator field, zero if key not found.
485 authencrypt(
486 keyid_t keyno,
487 u_int32 *pkt,
488 int length
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.
497 authencryptions++;
498 pkt[length / 4] = htonl(keyno);
499 if (keyno == 0) {
500 return (4);
502 if (!authhavekey(keyno))
503 return (0);
505 return (MD5authencrypt(cache_type, cache_key, pkt, length));
509 * authdecrypt - verify message authenticator
511 * Returns one if authenticator valid, zero if invalid or key not found.
514 authdecrypt(
515 keyid_t keyno,
516 u_int32 *pkt,
517 int length,
518 int size
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.
527 authdecryptions++;
528 if (keyno == 0)
529 return (0);
531 if (!authhavekey(keyno) || size < 4)
532 return (0);
534 return (MD5authdecrypt(cache_type, cache_key, pkt, length,
535 size));