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