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