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