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