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