]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ntp/libntp/authkeys.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / ntp / libntp / authkeys.c
1 /*
2  * authkeys.c - routines to manage the storage of authentication keys
3  */
4
5 #ifdef HAVE_CONFIG_H
6 # include <config.h>
7 #endif
8
9 #include <stdio.h>
10
11 #include "ntp_types.h"
12 #include "ntp_fp.h"
13 #include "ntp.h"
14 #include "ntpd.h"
15 #include "ntp_string.h"
16 #include "ntp_malloc.h"
17 #include "ntp_stdlib.h"
18
19 /*
20  * Structure to store keys in in the hash table.
21  */
22 struct savekey {
23         struct savekey *next;
24         union {
25                 long bogon;             /* Make sure nonempty */
26                 u_char MD5_key[32];     /* MD5 key */
27         } k;
28         keyid_t keyid;          /* key identifier */
29         u_short flags;          /* flags that wave */
30         u_long lifetime;        /* remaining lifetime */
31         int keylen;             /* key length */
32 };
33
34 #define KEY_TRUSTED     0x001   /* this key is trusted */
35 #define KEY_MD5         0x200   /* this is a MD5 type key */
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
45 struct savekey *key_hash[HASHSIZE];
46
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 */
55
56 /*
57  * Storage for free key structures.  We malloc() such things but
58  * never free them.
59  */
60 struct savekey *authfreekeys;
61 int 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  */
68 keyid_t cache_keyid;            /* key identifier */
69 u_char  *cache_key;             /* key pointer */
70 u_int   cache_keylen;           /* key length */
71 u_short cache_flags;            /* flags that wave */
72
73
74 /*
75  * init_auth - initialize internal data
76  */
77 void
78 init_auth(void)
79 {
80         /*
81          * Initialize hash table and free list
82          */
83         memset((char *)key_hash, 0, sizeof key_hash);
84 }
85
86
87 /*
88  * auth_findkey - find a key in the hash table
89  */
90 struct savekey *
91 auth_findkey(
92         keyid_t keyno
93         )
94 {
95         struct savekey *sk;
96
97         sk = key_hash[KEYHASH(keyno)];
98         while (sk != 0) {
99                 if (keyno == sk->keyid)
100                         return (sk);
101
102                 sk = sk->next;
103         }
104         return (0);
105 }
106
107
108 /*
109  * auth_havekey - return one if the key is known
110  */
111 int
112 auth_havekey(
113         keyid_t keyno
114         )
115 {
116         struct savekey *sk;
117
118         if (keyno == 0 || (keyno == cache_keyid))
119                 return (1);
120
121         sk = key_hash[KEYHASH(keyno)];
122         while (sk != 0) {
123                 if (keyno == sk->keyid)
124                         return (1);
125
126                 sk = sk->next;
127         }
128         return (0);
129 }
130
131
132 /*
133  * authhavekey - return one and cache the key, if known and trusted.
134  */
135 int
136 authhavekey(
137         keyid_t keyno
138         )
139 {
140         struct savekey *sk;
141
142         authkeylookups++;
143         if (keyno == 0 || keyno == cache_keyid)
144                 return (1);
145
146         authkeyuncached++;
147         sk = key_hash[KEYHASH(keyno)];
148         while (sk != 0) {
149                 if (keyno == sk->keyid)
150                     break;
151                 sk = sk->next;
152         }
153         if (sk == 0) {
154                 authkeynotfound++;
155                 return (0);
156         } else if (!(sk->flags & KEY_TRUSTED)) {
157                 authnokey++;
158                 return (0);
159         }
160         cache_keyid = sk->keyid;
161         cache_flags = sk->flags;
162         if (sk->flags & KEY_MD5) {
163                 cache_key = sk->k.MD5_key;
164                 cache_keylen = sk->keylen;
165                 return (1);
166         }
167         return (0);
168 }
169
170
171 /*
172  * auth_moremem - get some more free key structures
173  */
174 int
175 auth_moremem(void)
176 {
177         struct savekey *sk;
178         int i;
179
180         sk = (struct savekey *)calloc(MEMINC, sizeof(struct savekey));
181         if (sk == 0)
182                 return (0);
183         
184         for (i = MEMINC; i > 0; i--) {
185                 sk->next = authfreekeys;
186                 authfreekeys = sk++;
187         }
188         authnumfreekeys += MEMINC;
189         return (authnumfreekeys);
190 }
191
192
193 /*
194  * authtrust - declare a key to be trusted/untrusted
195  */
196 void
197 authtrust(
198         keyid_t keyno,
199         u_long trust
200         )
201 {
202         struct savekey *sk;
203
204 #ifdef DEBUG
205         if (debug > 2)
206                 printf("authtrust: keyid %08x life %lu\n", keyno, trust);
207 #endif
208         sk = key_hash[KEYHASH(keyno)];
209         while (sk != 0) {
210                 if (keyno == sk->keyid)
211                     break;
212                 sk = sk->next;
213         }
214
215         if (sk == 0 && !trust)
216                 return;
217         
218         if (sk != 0) {
219                 if (cache_keyid == keyno) {
220                         cache_flags = 0;
221                         cache_keyid = 0;
222                 }
223
224                 if (trust > 0) {
225                         sk->flags |= KEY_TRUSTED;
226                         if (trust > 1)
227                                 sk->lifetime = current_time + trust;
228                         else
229                                 sk->lifetime = 0;
230                         return;
231                 }
232
233                 sk->flags &= ~KEY_TRUSTED; {
234                         struct savekey *skp;
235
236                         skp = key_hash[KEYHASH(keyno)];
237                         if (skp == sk) {
238                                 key_hash[KEYHASH(keyno)] = sk->next;
239                         } else {
240                                 while (skp->next != sk)
241                                     skp = skp->next;
242                                 skp->next = sk->next;
243                         }
244                         authnumkeys--;
245
246                         sk->next = authfreekeys;
247                         authfreekeys = sk;
248                         authnumfreekeys++;
249                 }
250                 return;
251         }
252
253         if (authnumfreekeys == 0)
254             if (auth_moremem() == 0)
255                 return;
256
257         sk = authfreekeys;
258         authfreekeys = sk->next;
259         authnumfreekeys--;
260
261         sk->keyid = keyno;
262         sk->flags = KEY_TRUSTED;
263         sk->next = key_hash[KEYHASH(keyno)];
264         key_hash[KEYHASH(keyno)] = sk;
265         authnumkeys++;
266         return;
267 }
268
269
270 /*
271  * authistrusted - determine whether a key is trusted
272  */
273 int
274 authistrusted(
275         keyid_t keyno
276         )
277 {
278         struct savekey *sk;
279
280         if (keyno == cache_keyid)
281             return ((cache_flags & KEY_TRUSTED) != 0);
282
283         authkeyuncached++;
284         sk = key_hash[KEYHASH(keyno)];
285         while (sk != 0) {
286                 if (keyno == sk->keyid)
287                     break;
288                 sk = sk->next;
289         }
290         if (sk == 0) {
291                 authkeynotfound++;
292                 return (0);
293         } else if (!(sk->flags & KEY_TRUSTED)) {
294                 authkeynotfound++;
295                 return (0);
296         }
297         return (1);
298 }
299
300
301 void
302 MD5auth_setkey(
303         keyid_t keyno,
304         const u_char *key,
305         const int len
306         )
307 {
308         struct savekey *sk;
309         
310         /*
311          * See if we already have the key.  If so just stick in the
312          * new value.
313          */
314         sk = key_hash[KEYHASH(keyno)];
315         while (sk != 0) {
316                 if (keyno == sk->keyid) {
317                         strncpy((char *)sk->k.MD5_key, (const char *)key,
318                             sizeof(sk->k.MD5_key));
319                         if ((sk->keylen = len) > sizeof(sk->k.MD5_key))
320                             sk->keylen = sizeof(sk->k.MD5_key);
321
322                         sk->flags |= KEY_MD5;
323                         if (cache_keyid == keyno) {
324                                 cache_flags = 0;
325                                 cache_keyid = 0;
326                         }
327                         return;
328                 }
329                 sk = sk->next;
330         }
331
332         /*
333          * Need to allocate new structure.  Do it.
334          */
335         if (authnumfreekeys == 0) {
336                 if (auth_moremem() == 0)
337                     return;
338         }
339
340         sk = authfreekeys;
341         authfreekeys = sk->next;
342         authnumfreekeys--;
343
344         strncpy((char *)sk->k.MD5_key, (const char *)key,
345                 sizeof(sk->k.MD5_key));
346         if ((sk->keylen = len) > sizeof(sk->k.MD5_key))
347             sk->keylen = sizeof(sk->k.MD5_key);
348
349         sk->keyid = keyno;
350         sk->flags = KEY_MD5;
351         sk->lifetime = 0;
352         sk->next = key_hash[KEYHASH(keyno)];
353         key_hash[KEYHASH(keyno)] = sk;
354         authnumkeys++;
355         return;
356 }
357     
358 /*
359  * auth_delkeys - delete all known keys, in preparation for rereading
360  *                the keys file (presumably)
361  */
362 void
363 auth_delkeys(void)
364 {
365         struct savekey *sk;
366         struct savekey **skp;
367         int i;
368
369         for (i = 0; i < HASHSIZE; i++) {
370                 skp = &(key_hash[i]);
371                 sk = key_hash[i];
372                 /*
373                  * Leave autokey keys alone.
374                  */
375                 while (sk != 0 && sk->keyid <= NTP_MAXKEY) {
376                         /*
377                          * Don't lose info as to which keys are trusted.
378                          */
379                         if (sk->flags & KEY_TRUSTED) {
380                                 skp = &(sk->next);
381                                 memset(&sk->k, 0, sizeof(sk->k));
382                                 sk->lifetime = 0;
383                                 sk->keylen = 0;
384                                 sk = sk->next;
385                         } else {
386                                 *skp = sk->next;
387                                 authnumkeys--;
388                                 sk->next = authfreekeys;
389                                 authfreekeys = sk;
390                                 authnumfreekeys++;
391                                 sk = *skp;
392                         }
393                 }
394         }
395 }
396
397 /*
398  * auth_agekeys - delete keys whose lifetimes have expired
399  */
400 void
401 auth_agekeys(void)
402 {
403         struct savekey *sk;
404         struct savekey *skp;
405         int i;
406
407         for (i = 0; i < HASHSIZE; i++) {
408                 sk = skp = key_hash[i];
409                 while (sk != 0) {
410                         skp = sk->next;
411                         if (sk->lifetime > 0 && current_time >
412                             sk->lifetime) {
413                                 authtrust(sk->keyid, 0);
414                                 authkeyexpired++;
415                         }
416                         sk = skp;
417                 }
418         }
419 #ifdef DEBUG
420         if (debug)
421                 printf("auth_agekeys: at %lu keys %lu expired %lu\n",
422                     current_time, authnumkeys, authkeyexpired);
423 #endif
424 }
425
426 /*
427  * authencrypt - generate message authenticator
428  *
429  * Returns length of authenticator field, zero if key not found.
430  */
431 int
432 authencrypt(
433         keyid_t keyno,
434         u_int32 *pkt,
435         int length
436         )
437 {
438
439         /*
440          * A zero key identifier means the sender has not verified
441          * the last message was correctly authenticated. The MAC
442          * consists of a single word with value zero.
443          */
444         authencryptions++;
445         pkt[length / 4] = htonl(keyno);
446         if (keyno == 0) {
447                 return (4);
448         }
449         if (!authhavekey(keyno))
450                 return (0);
451
452         if (cache_flags & KEY_MD5)
453                 return (MD5authencrypt(cache_key, pkt, length));
454
455         return (0);
456 }
457
458 /*
459  * authdecrypt - verify message authenticator
460  *
461  * Returns one if authenticator valid, zero if invalid or key not found.
462  */
463 int
464 authdecrypt(
465         keyid_t keyno,
466         u_int32 *pkt,
467         int length,
468         int size
469         )
470 {
471
472         /*
473          * A zero key identifier means the sender has not verified
474          * the last message was correctly authenticated. Nevertheless,
475          * the authenticator itself is considered valid.
476          */
477         authdecryptions++;
478         if (keyno == 0)
479                 return (0);
480
481         if (!authhavekey(keyno) || size < 4)
482                 return (0);
483
484         if (cache_flags & KEY_MD5)
485                 return (MD5authdecrypt(cache_key, pkt, length, size));
486
487         return (0);
488 }