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