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