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