Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.sbin / keyserv / setkey.c
1 /*
2  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3  * unrestricted use provided that this legend is included on all tape
4  * media and as a part of the software program in whole or part.  Users
5  * may copy or modify Sun RPC without charge, but are not authorized
6  * to license or distribute it to anyone else except as part of a product or
7  * program developed by the user.
8  * 
9  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
12  * 
13  * Sun RPC is provided with no support and without any obligation on the
14  * part of Sun Microsystems, Inc. to assist in its use, correction,
15  * modification or enhancement.
16  * 
17  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19  * OR ANY PART THEREOF.
20  * 
21  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22  * or profits or other special, indirect and consequential damages, even if
23  * Sun has been advised of the possibility of such damages.
24  * 
25  * Sun Microsystems, Inc.
26  * 2550 Garcia Avenue
27  * Mountain View, California  94043
28  */
29
30 #ifndef lint
31 #if 0
32 static char sccsid[] = "@(#)setkey.c    1.11    94/04/25 SMI";
33 #endif
34 static const char rcsid[] =
35   "$FreeBSD: src/usr.sbin/keyserv/setkey.c,v 1.3 1999/08/28 01:16:41 peter Exp $";
36 #endif /* not lint */
37
38 /*
39  * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
40  */
41
42 /*
43  * Do the real work of the keyserver.
44  * Store secret keys. Compute common keys,
45  * and use them to decrypt and encrypt DES keys.
46  * Cache the common keys, so the expensive computation is avoided.
47  */
48 #include <mp.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <unistd.h>
53 #include <sys/types.h>
54 #include <rpc/rpc.h>
55 #include <rpc/key_prot.h>
56 #include <rpc/des_crypt.h>
57 #include <rpc/des.h>
58 #include <sys/errno.h>
59 #include "keyserv.h"
60
61 static MINT *MODULUS;
62 static char *fetchsecretkey __P(( uid_t ));
63 static void writecache __P(( char *, char *, des_block * ));
64 static int readcache __P(( char *, char *, des_block * ));
65 static void extractdeskey __P (( MINT *, des_block * ));
66 static int storesecretkey __P(( uid_t, keybuf ));
67 static keystatus pk_crypt __P(( uid_t, char *, netobj *, des_block *, int));
68 static int nodefaultkeys = 0;
69
70
71 /*
72  * prohibit the nobody key on this machine k (the -d flag)
73  */
74 void
75 pk_nodefaultkeys()
76 {
77         nodefaultkeys = 1;
78 }
79
80 /*
81  * Set the modulus for all our Diffie-Hellman operations
82  */
83 void
84 setmodulus(modx)
85         char *modx;
86 {
87         MODULUS = xtom(modx);
88 }
89
90 /*
91  * Set the secretkey key for this uid
92  */
93 keystatus
94 pk_setkey(uid, skey)
95         uid_t uid;
96         keybuf skey;
97 {
98         if (!storesecretkey(uid, skey)) {
99                 return (KEY_SYSTEMERR);
100         }
101         return (KEY_SUCCESS);
102 }
103
104 /*
105  * Encrypt the key using the public key associated with remote_name and the
106  * secret key associated with uid.
107  */
108 keystatus
109 pk_encrypt(uid, remote_name, remote_key, key)
110         uid_t uid;
111         char *remote_name;
112         netobj  *remote_key;
113         des_block *key;
114 {
115         return (pk_crypt(uid, remote_name, remote_key, key, DES_ENCRYPT));
116 }
117
118 /*
119  * Decrypt the key using the public key associated with remote_name and the
120  * secret key associated with uid.
121  */
122 keystatus
123 pk_decrypt(uid, remote_name, remote_key, key)
124         uid_t uid;
125         char *remote_name;
126         netobj *remote_key;
127         des_block *key;
128 {
129         return (pk_crypt(uid, remote_name, remote_key, key, DES_DECRYPT));
130 }
131
132 static int store_netname __P(( uid_t, key_netstarg * ));
133 static int fetch_netname __P(( uid_t, key_netstarg * ));
134
135 keystatus
136 pk_netput(uid, netstore)
137         uid_t uid;
138         key_netstarg *netstore;
139 {
140         if (!store_netname(uid, netstore)) {
141                 return (KEY_SYSTEMERR);
142         }
143         return (KEY_SUCCESS);
144 }
145
146 keystatus
147 pk_netget(uid, netstore)
148         uid_t uid;
149         key_netstarg *netstore;
150 {
151         if (!fetch_netname(uid, netstore)) {
152                 return (KEY_SYSTEMERR);
153         }
154         return (KEY_SUCCESS);
155 }
156
157
158 /*
159  * Do the work of pk_encrypt && pk_decrypt
160  */
161 static keystatus
162 pk_crypt(uid, remote_name, remote_key, key, mode)
163         uid_t uid;
164         char *remote_name;
165         netobj *remote_key;
166         des_block *key;
167         int mode;
168 {
169         char *xsecret;
170         char xpublic[1024];
171         char xsecret_hold[1024];
172         des_block deskey;
173         int err;
174         MINT *public;
175         MINT *secret;
176         MINT *common;
177         char zero[8];
178
179         xsecret = fetchsecretkey(uid);
180         if (xsecret == NULL || xsecret[0] == 0) {
181                 memset(zero, 0, sizeof (zero));
182                 xsecret = xsecret_hold;
183                 if (nodefaultkeys)
184                         return (KEY_NOSECRET);
185
186                 if (!getsecretkey("nobody", xsecret, zero) || xsecret[0] == 0) {
187                         return (KEY_NOSECRET);
188                 }
189         }
190         if (remote_key) {
191                 memcpy(xpublic, remote_key->n_bytes, remote_key->n_len);
192         } else {
193                 bzero((char *)&xpublic, sizeof(xpublic));
194                 if (!getpublickey(remote_name, xpublic)) {
195                         if (nodefaultkeys || !getpublickey("nobody", xpublic))
196                                 return (KEY_UNKNOWN);
197                 }
198         }
199
200         if (!readcache(xpublic, xsecret, &deskey)) {
201                 public = xtom(xpublic);
202                 secret = xtom(xsecret);
203                 /* Sanity Check on public and private keys */
204                 if ((public == NULL) || (secret == NULL))
205                         return (KEY_SYSTEMERR);
206
207                 common = itom(0);
208                 pow(public, secret, MODULUS, common);
209                 extractdeskey(common, &deskey);
210                 writecache(xpublic, xsecret, &deskey);
211                 mfree(secret);
212                 mfree(public);
213                 mfree(common);
214         }
215         err = ecb_crypt((char *)&deskey, (char *)key, sizeof (des_block),
216                 DES_HW | mode);
217         if (DES_FAILED(err)) {
218                 return (KEY_SYSTEMERR);
219         }
220         return (KEY_SUCCESS);
221 }
222
223 keystatus
224 pk_get_conv_key(uid, xpublic, result)
225         uid_t uid;
226         keybuf xpublic;
227         cryptkeyres *result;
228 {
229         char *xsecret;
230         char xsecret_hold[1024];
231         MINT *public;
232         MINT *secret;
233         MINT *common;
234         char zero[8];
235
236
237         xsecret = fetchsecretkey(uid);
238
239         if (xsecret == NULL || xsecret[0] == 0) {
240                 memset(zero, 0, sizeof (zero));
241                 xsecret = xsecret_hold;
242                 if (nodefaultkeys)
243                         return (KEY_NOSECRET);
244
245                 if (!getsecretkey("nobody", xsecret, zero) ||
246                         xsecret[0] == 0)
247                         return (KEY_NOSECRET);
248         }
249
250         if (!readcache(xpublic, xsecret, &result->cryptkeyres_u.deskey)) {
251                 public = xtom(xpublic);
252                 secret = xtom(xsecret);
253                 /* Sanity Check on public and private keys */
254                 if ((public == NULL) || (secret == NULL))
255                         return (KEY_SYSTEMERR);
256
257                 common = itom(0);
258                 pow(public, secret, MODULUS, common);
259                 extractdeskey(common, &result->cryptkeyres_u.deskey);
260                 writecache(xpublic, xsecret, &result->cryptkeyres_u.deskey);
261                 mfree(secret);
262                 mfree(public);
263                 mfree(common);
264         }
265
266         return (KEY_SUCCESS);
267 }
268
269 /*
270  * Choose middle 64 bits of the common key to use as our des key, possibly
271  * overwriting the lower order bits by setting parity.
272  */
273 static void
274 extractdeskey(ck, deskey)
275         MINT *ck;
276         des_block *deskey;
277 {
278         MINT *a;
279         short r;
280         int i;
281         short base = (1 << 8);
282         char *k;
283
284         a = itom(0);
285 #ifdef SOLARIS_MP
286         _mp_move(ck, a);
287 #else
288         move(ck, a);
289 #endif
290         for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) {
291                 sdiv(a, base, a, &r);
292         }
293         k = deskey->c;
294         for (i = 0; i < 8; i++) {
295                 sdiv(a, base, a, &r);
296                 *k++ = r;
297         }
298         mfree(a);
299         des_setparity((char *)deskey);
300 }
301
302 /*
303  * Key storage management
304  */
305
306 #define KEY_ONLY 0
307 #define KEY_NAME 1
308 struct secretkey_netname_list {
309         uid_t uid;
310         key_netstarg keynetdata;
311         u_char sc_flag;
312         struct secretkey_netname_list *next;
313 };
314
315
316
317 static struct secretkey_netname_list *g_secretkey_netname;
318
319 /*
320  * Store the keys and netname for this uid
321  */
322 static int
323 store_netname(uid, netstore)
324         uid_t uid;
325         key_netstarg *netstore;
326 {
327         struct secretkey_netname_list *new;
328         struct secretkey_netname_list **l;
329
330         for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid;
331                         l = &(*l)->next) {
332         }
333         if (*l == NULL) {
334                 new = (struct secretkey_netname_list *)malloc(sizeof (*new));
335                 if (new == NULL) {
336                         return (0);
337                 }
338                 new->uid = uid;
339                 new->next = NULL;
340                 *l = new;
341         } else {
342                 new = *l;
343                 if (new->keynetdata.st_netname)
344                         (void) free (new->keynetdata.st_netname);
345         }
346         memcpy(new->keynetdata.st_priv_key, netstore->st_priv_key,
347                 HEXKEYBYTES);
348         memcpy(new->keynetdata.st_pub_key, netstore->st_pub_key, HEXKEYBYTES);
349
350         if (netstore->st_netname)
351                 new->keynetdata.st_netname = strdup(netstore->st_netname);
352         else
353                 new->keynetdata.st_netname = (char *)NULL;
354         new->sc_flag = KEY_NAME;
355         return (1);
356
357 }
358
359 /*
360  * Fetch the keys and netname for this uid
361  */
362
363 static int
364 fetch_netname(uid, key_netst)
365         uid_t uid;
366         struct key_netstarg *key_netst;
367 {
368         struct secretkey_netname_list *l;
369
370         for (l = g_secretkey_netname; l != NULL; l = l->next) {
371                 if ((l->uid == uid) && (l->sc_flag == KEY_NAME)){
372
373                         memcpy(key_netst->st_priv_key,
374                                 l->keynetdata.st_priv_key, HEXKEYBYTES);
375
376                         memcpy(key_netst->st_pub_key,
377                                 l->keynetdata.st_pub_key, HEXKEYBYTES);
378
379                         if (l->keynetdata.st_netname)
380                                 key_netst->st_netname =
381                                         strdup(l->keynetdata.st_netname);
382                         else
383                                 key_netst->st_netname = NULL;
384                 return (1);
385                 }
386         }
387
388         return (0);
389 }
390
391 static char *
392 fetchsecretkey(uid)
393         uid_t uid;
394 {
395         struct secretkey_netname_list *l;
396
397         for (l = g_secretkey_netname; l != NULL; l = l->next) {
398                 if (l->uid == uid) {
399                         return (l->keynetdata.st_priv_key);
400                 }
401         }
402         return (NULL);
403 }
404
405 /*
406  * Store the secretkey for this uid
407  */
408 static int
409 storesecretkey(uid, key)
410         uid_t uid;
411         keybuf key;
412 {
413         struct secretkey_netname_list *new;
414         struct secretkey_netname_list **l;
415
416         for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid;
417                         l = &(*l)->next) {
418         }
419         if (*l == NULL) {
420                 new = (struct secretkey_netname_list *) malloc(sizeof (*new));
421                 if (new == NULL) {
422                         return (0);
423                 }
424                 new->uid = uid;
425                 new->sc_flag = KEY_ONLY;
426                 memset(new->keynetdata.st_pub_key, 0, HEXKEYBYTES);
427                 new->keynetdata.st_netname = NULL;
428                 new->next = NULL;
429                 *l = new;
430         } else {
431                 new = *l;
432         }
433
434         memcpy(new->keynetdata.st_priv_key, key,
435                 HEXKEYBYTES);
436         return (1);
437 }
438
439 static int
440 hexdigit(val)
441         int val;
442 {
443         return ("0123456789abcdef"[val]);
444 }
445
446 void
447 bin2hex(bin, hex, size)
448         unsigned char *bin;
449         unsigned char *hex;
450         int size;
451 {
452         int i;
453
454         for (i = 0; i < size; i++) {
455                 *hex++ = hexdigit(*bin >> 4);
456                 *hex++ = hexdigit(*bin++ & 0xf);
457         }
458 }
459
460 static int
461 hexval(dig)
462         char dig;
463 {
464         if ('0' <= dig && dig <= '9') {
465                 return (dig - '0');
466         } else if ('a' <= dig && dig <= 'f') {
467                 return (dig - 'a' + 10);
468         } else if ('A' <= dig && dig <= 'F') {
469                 return (dig - 'A' + 10);
470         } else {
471                 return (-1);
472         }
473 }
474
475 void
476 hex2bin(hex, bin, size)
477         unsigned char *hex;
478         unsigned char *bin;
479         int size;
480 {
481         int i;
482
483         for (i = 0; i < size; i++) {
484                 *bin = hexval(*hex++) << 4;
485                 *bin++ |= hexval(*hex++);
486         }
487 }
488
489 /*
490  * Exponential caching management
491  */
492 struct cachekey_list {
493         keybuf secret;
494         keybuf public;
495         des_block deskey;
496         struct cachekey_list *next;
497 };
498 static struct cachekey_list *g_cachedkeys;
499
500 /*
501  * cache result of expensive multiple precision exponential operation
502  */
503 static void
504 writecache(pub, sec, deskey)
505         char *pub;
506         char *sec;
507         des_block *deskey;
508 {
509         struct cachekey_list *new;
510
511         new = (struct cachekey_list *) malloc(sizeof (struct cachekey_list));
512         if (new == NULL) {
513                 return;
514         }
515         memcpy(new->public, pub, sizeof (keybuf));
516         memcpy(new->secret, sec, sizeof (keybuf));
517         new->deskey = *deskey;
518         new->next = g_cachedkeys;
519         g_cachedkeys = new;
520 }
521
522 /*
523  * Try to find the common key in the cache
524  */
525 static int
526 readcache(pub, sec, deskey)
527         char *pub;
528         char *sec;
529         des_block *deskey;
530 {
531         struct cachekey_list *found;
532         register struct cachekey_list **l;
533
534 #define cachehit(pub, sec, list)        \
535                 (memcmp(pub, (list)->public, sizeof (keybuf)) == 0 && \
536                 memcmp(sec, (list)->secret, sizeof (keybuf)) == 0)
537
538         for (l = &g_cachedkeys; (*l) != NULL && !cachehit(pub, sec, *l);
539                 l = &(*l)->next)
540                 ;
541         if ((*l) == NULL) {
542                 return (0);
543         }
544         found = *l;
545         (*l) = (*l)->next;
546         found->next = g_cachedkeys;
547         g_cachedkeys = found;
548         *deskey = found->deskey;
549         return (1);
550 }