xref: /dragonfly/usr.sbin/keyserv/setkey.c (revision 2d8a3be7)
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 }
547