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