Merge from vendor branch NCURSES:
[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.8 2005/01/11 13:22:40 joerg 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 <err.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 #include <openssl/bn.h>
57 #include <openssl/crypto.h>
58 #include <openssl/err.h>
59
60 static BIGNUM *modulus;
61 static char *fetchsecretkey( uid_t );
62 static void writecache( char *, char *, des_block * );
63 static int readcache( char *, char *, des_block * );
64 static void extractdeskey ( BIGNUM *, des_block * );
65 static int storesecretkey( uid_t, keybuf );
66 static keystatus pk_crypt( uid_t, char *, netobj *, des_block *, int);
67 static int nodefaultkeys = 0;
68
69
70 /*
71  * prohibit the nobody key on this machine k (the -d flag)
72  */
73 void
74 pk_nodefaultkeys(void)
75 {
76         nodefaultkeys = 1;
77 }
78
79 /*
80  * Set the modulus for all our Diffie-Hellman operations
81  */
82 void
83 setmodulus(char *modx)
84 {
85         if (BN_hex2bn(&modulus, modx) == NULL)
86                 errx(1, "could not convert modulus to BIGNUM: %s",
87                      ERR_error_string(ERR_get_error(), 0));
88 }
89
90 /*
91  * Set the secretkey key for this uid
92  */
93 keystatus
94 pk_setkey(uid_t uid, keybuf skey)
95 {
96         if (!storesecretkey(uid, skey)) {
97                 return (KEY_SYSTEMERR);
98         }
99         return (KEY_SUCCESS);
100 }
101
102 /*
103  * Encrypt the key using the public key associated with remote_name and the
104  * secret key associated with uid.
105  */
106 keystatus
107 pk_encrypt(uid_t uid, char *remote_name, netobj *remote_key, des_block *key)
108 {
109         return (pk_crypt(uid, remote_name, remote_key, key, DES_ENCRYPT));
110 }
111
112 /*
113  * Decrypt the key using the public key associated with remote_name and the
114  * secret key associated with uid.
115  */
116 keystatus
117 pk_decrypt(uid_t uid, char *remote_name, netobj *remote_key, des_block *key)
118 {
119         return (pk_crypt(uid, remote_name, remote_key, key, DES_DECRYPT));
120 }
121
122 static int store_netname( uid_t, key_netstarg * );
123 static int fetch_netname( uid_t, key_netstarg * );
124
125 keystatus
126 pk_netput(uid_t uid, key_netstarg *netstore)
127 {
128         if (!store_netname(uid, netstore)) {
129                 return (KEY_SYSTEMERR);
130         }
131         return (KEY_SUCCESS);
132 }
133
134 keystatus
135 pk_netget(uid_t uid, key_netstarg *netstore)
136 {
137         if (!fetch_netname(uid, netstore)) {
138                 return (KEY_SYSTEMERR);
139         }
140         return (KEY_SUCCESS);
141 }
142
143
144 /*
145  * Do the work of pk_encrypt && pk_decrypt
146  */
147 static keystatus
148 pk_crypt(uid_t uid, char *remote_name, netobj *remote_key, des_block *key,
149          int mode)
150 {
151         char *xsecret;
152         char xpublic[1024];
153         char xsecret_hold[1024];
154         des_block deskey;
155         int error;
156         BIGNUM *public, *secret, *common;
157         BN_CTX *ctx;
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                 if ((ctx = BN_CTX_new()) == NULL)
183                         return (KEY_SYSTEMERR);
184                 if (BN_hex2bn(&public, xpublic) == NULL) {
185                         BN_CTX_free(ctx);
186                         return (KEY_SYSTEMERR);
187                 }
188                 if (BN_hex2bn(&secret, xsecret) == NULL) {
189                         BN_free(public);
190                         BN_CTX_free(ctx);
191                         return (KEY_SYSTEMERR);
192                 }
193
194                 if ((common = BN_new()) == NULL) {
195                         BN_free(secret);
196                         BN_free(public);
197                         BN_CTX_free(ctx);
198                         return (KEY_SYSTEMERR);
199                 }
200                 BN_zero(common);
201                 BN_mod_exp(common, public, secret, modulus, ctx);
202                 extractdeskey(common, &deskey);
203                 writecache(xpublic, xsecret, &deskey);
204                 BN_free(secret);
205                 BN_free(public);
206                 BN_free(common);
207                 BN_CTX_free(ctx);
208         }
209         error = ecb_crypt((char *)&deskey, (char *)key, sizeof (des_block),
210                 DES_HW | mode);
211         if (DES_FAILED(error)) {
212                 return (KEY_SYSTEMERR);
213         }
214         return (KEY_SUCCESS);
215 }
216
217 keystatus
218 pk_get_conv_key(uid_t uid, keybuf xpublic, cryptkeyres *result)
219 {
220         char *xsecret;
221         char xsecret_hold[1024];
222         BIGNUM *public, *secret, *common;
223         BN_CTX *ctx;
224         char zero[8];
225
226
227         xsecret = fetchsecretkey(uid);
228
229         if (xsecret == NULL || xsecret[0] == 0) {
230                 memset(zero, 0, sizeof (zero));
231                 xsecret = xsecret_hold;
232                 if (nodefaultkeys)
233                         return (KEY_NOSECRET);
234
235                 if (!getsecretkey("nobody", xsecret, zero) ||
236                         xsecret[0] == 0)
237                         return (KEY_NOSECRET);
238         }
239
240         if (!readcache(xpublic, xsecret, &result->cryptkeyres_u.deskey)) {
241                 if ((ctx = BN_CTX_new()) == NULL)
242                         return (KEY_SYSTEMERR);
243                 if (BN_hex2bn(&public, xpublic) == NULL) {
244                         BN_CTX_free(ctx);
245                         return (KEY_SYSTEMERR);
246                 }
247                 if (BN_hex2bn(&secret, xsecret) == NULL) {
248                         BN_free(public);
249                         BN_CTX_free(ctx);
250                         return (KEY_SYSTEMERR);
251                 }
252
253                 if ((common = BN_new()) == NULL) {
254                         BN_free(secret);
255                         BN_free(public);
256                         BN_CTX_free(ctx);
257                         return (KEY_SYSTEMERR);
258                 }
259                 BN_zero(common);
260                 BN_mod_exp(common, public, secret, modulus, ctx);
261
262                 extractdeskey(common, &result->cryptkeyres_u.deskey);
263                 writecache(xpublic, xsecret, &result->cryptkeyres_u.deskey);
264                 BN_free(secret);
265                 BN_free(public);
266                 BN_free(common);
267                 BN_CTX_free(ctx);
268         }
269
270         return (KEY_SUCCESS);
271 }
272
273 /*
274  * Choose middle 64 bits of the common key to use as our des key, possibly
275  * overwriting the lower order bits by setting parity.
276  */
277 static void
278 extractdeskey(BIGNUM *ck, des_block *deskey)
279 {
280         BIGNUM *a;
281         int i;
282         BN_ULONG r, base = (1 << 8);
283         char *k;
284
285         if ((a = BN_dup(ck)) == NULL)
286                 errx(1, "could not copy BIGNUM");
287
288         for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) {
289                 r = BN_div_word(a, base);
290         }
291         k = deskey->c;
292         for (i = 0; i < 8; i++) {
293                 r = BN_div_word(a, base);
294                 *k++ = r;
295         }
296         BN_free(a);
297         des_setparity((char *)deskey);
298 }
299
300 /*
301  * Key storage management
302  */
303
304 #define KEY_ONLY 0
305 #define KEY_NAME 1
306 struct secretkey_netname_list {
307         uid_t uid;
308         key_netstarg keynetdata;
309         u_char sc_flag;
310         struct secretkey_netname_list *next;
311 };
312
313
314
315 static struct secretkey_netname_list *g_secretkey_netname;
316
317 /*
318  * Store the keys and netname for this uid
319  */
320 static int
321 store_netname(uid_t uid, 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                         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_t uid, struct key_netstarg *key_netst)
361 {
362         struct secretkey_netname_list *l;
363
364         for (l = g_secretkey_netname; l != NULL; l = l->next) {
365                 if ((l->uid == uid) && (l->sc_flag == KEY_NAME)){
366
367                         memcpy(key_netst->st_priv_key,
368                                 l->keynetdata.st_priv_key, HEXKEYBYTES);
369
370                         memcpy(key_netst->st_pub_key,
371                                 l->keynetdata.st_pub_key, HEXKEYBYTES);
372
373                         if (l->keynetdata.st_netname)
374                                 key_netst->st_netname =
375                                         strdup(l->keynetdata.st_netname);
376                         else
377                                 key_netst->st_netname = NULL;
378                 return (1);
379                 }
380         }
381
382         return (0);
383 }
384
385 static char *
386 fetchsecretkey(uid_t uid)
387 {
388         struct secretkey_netname_list *l;
389
390         for (l = g_secretkey_netname; l != NULL; l = l->next) {
391                 if (l->uid == uid) {
392                         return (l->keynetdata.st_priv_key);
393                 }
394         }
395         return (NULL);
396 }
397
398 /*
399  * Store the secretkey for this uid
400  */
401 static int
402 storesecretkey(uid_t uid, keybuf key)
403 {
404         struct secretkey_netname_list *new;
405         struct secretkey_netname_list **l;
406
407         for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid;
408                         l = &(*l)->next) {
409         }
410         if (*l == NULL) {
411                 new = (struct secretkey_netname_list *) malloc(sizeof (*new));
412                 if (new == NULL) {
413                         return (0);
414                 }
415                 new->uid = uid;
416                 new->sc_flag = KEY_ONLY;
417                 memset(new->keynetdata.st_pub_key, 0, HEXKEYBYTES);
418                 new->keynetdata.st_netname = NULL;
419                 new->next = NULL;
420                 *l = new;
421         } else {
422                 new = *l;
423         }
424
425         memcpy(new->keynetdata.st_priv_key, key,
426                 HEXKEYBYTES);
427         return (1);
428 }
429
430 static int
431 hexdigit(int val)
432 {
433         return ("0123456789abcdef"[val]);
434 }
435
436 void
437 bin2hex(unsigned char *bin, unsigned char *hex, int size)
438 {
439         int i;
440
441         for (i = 0; i < size; i++) {
442                 *hex++ = hexdigit(*bin >> 4);
443                 *hex++ = hexdigit(*bin++ & 0xf);
444         }
445 }
446
447 static int
448 hexval(char dig)
449 {
450         if ('0' <= dig && dig <= '9') {
451                 return (dig - '0');
452         } else if ('a' <= dig && dig <= 'f') {
453                 return (dig - 'a' + 10);
454         } else if ('A' <= dig && dig <= 'F') {
455                 return (dig - 'A' + 10);
456         } else {
457                 return (-1);
458         }
459 }
460
461 void
462 hex2bin(unsigned char *hex, unsigned char *bin, int size)
463 {
464         int i;
465
466         for (i = 0; i < size; i++) {
467                 *bin = hexval(*hex++) << 4;
468                 *bin++ |= hexval(*hex++);
469         }
470 }
471
472 /*
473  * Exponential caching management
474  */
475 struct cachekey_list {
476         keybuf secret;
477         keybuf public;
478         des_block deskey;
479         struct cachekey_list *next;
480 };
481 static struct cachekey_list *g_cachedkeys;
482
483 /*
484  * cache result of expensive multiple precision exponential operation
485  */
486 static void
487 writecache(char *pub, char *sec, des_block *deskey)
488 {
489         struct cachekey_list *new;
490
491         new = (struct cachekey_list *) malloc(sizeof (struct cachekey_list));
492         if (new == NULL) {
493                 return;
494         }
495         memcpy(new->public, pub, sizeof (keybuf));
496         memcpy(new->secret, sec, sizeof (keybuf));
497         new->deskey = *deskey;
498         new->next = g_cachedkeys;
499         g_cachedkeys = new;
500 }
501
502 /*
503  * Try to find the common key in the cache
504  */
505 static int
506 readcache(char *pub, char *sec, des_block *deskey)
507 {
508         struct cachekey_list *found;
509         struct cachekey_list **l;
510
511 #define cachehit(pub, sec, list)        \
512                 (memcmp(pub, (list)->public, sizeof (keybuf)) == 0 && \
513                 memcmp(sec, (list)->secret, sizeof (keybuf)) == 0)
514
515         for (l = &g_cachedkeys; (*l) != NULL && !cachehit(pub, sec, *l);
516                 l = &(*l)->next)
517                 ;
518         if ((*l) == NULL) {
519                 return (0);
520         }
521         found = *l;
522         (*l) = (*l)->next;
523         found->next = g_cachedkeys;
524         g_cachedkeys = found;
525         *deskey = found->deskey;
526         return (1);
527 }