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