xref: /dragonfly/usr.sbin/keyserv/setkey.c (revision 7d3e9a5b)
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, MERCHANTABILITY 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  */
32 
33 /*
34  * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
35  */
36 
37 /*
38  * Do the real work of the keyserver.
39  * Store secret keys. Compute common keys,
40  * and use them to decrypt and encrypt DES keys.
41  * Cache the common keys, so the expensive computation is avoided.
42  */
43 #include <err.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <sys/types.h>
49 #include <rpc/rpc.h>
50 #include <rpc/key_prot.h>
51 #include <rpc/des_crypt.h>
52 #include <rpc/des.h>
53 #include <sys/errno.h>
54 #include "keyserv.h"
55 #include <openssl/bn.h>
56 #include <openssl/crypto.h>
57 #include <openssl/err.h>
58 
59 static BIGNUM *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 ( BIGNUM *, 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 = NULL;
85 	if (BN_hex2bn(&modulus, modx) == 0)
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 		public = NULL;
185 		if (BN_hex2bn(&public, xpublic) == 0) {
186 			BN_CTX_free(ctx);
187 			return (KEY_SYSTEMERR);
188 		}
189 		secret = NULL;
190 		if (BN_hex2bn(&secret, xsecret) == 0) {
191 			BN_free(public);
192 			BN_CTX_free(ctx);
193 			return (KEY_SYSTEMERR);
194 		}
195 
196 		if ((common = BN_new()) == NULL) {
197 			BN_free(secret);
198 			BN_free(public);
199 			BN_CTX_free(ctx);
200 			return (KEY_SYSTEMERR);
201 		}
202 		BN_zero(common);
203 		BN_mod_exp(common, public, secret, modulus, ctx);
204 		extractdeskey(common, &deskey);
205 		writecache(xpublic, xsecret, &deskey);
206 		BN_free(secret);
207 		BN_free(public);
208 		BN_free(common);
209 		BN_CTX_free(ctx);
210 	}
211 	error = ecb_crypt((char *)&deskey, (char *)key, sizeof (des_block),
212 		DES_HW | mode);
213 	if (DES_FAILED(error)) {
214 		return (KEY_SYSTEMERR);
215 	}
216 	return (KEY_SUCCESS);
217 }
218 
219 keystatus
220 pk_get_conv_key(uid_t uid, keybuf xpublic, cryptkeyres *result)
221 {
222 	char *xsecret;
223 	char xsecret_hold[1024];
224 	BIGNUM *public, *secret, *common;
225 	BN_CTX *ctx;
226 	char zero[8];
227 
228 
229 	xsecret = fetchsecretkey(uid);
230 
231 	if (xsecret == NULL || xsecret[0] == 0) {
232 		memset(zero, 0, sizeof (zero));
233 		xsecret = xsecret_hold;
234 		if (nodefaultkeys)
235 			return (KEY_NOSECRET);
236 
237 		if (!getsecretkey("nobody", xsecret, zero) ||
238 			xsecret[0] == 0)
239 			return (KEY_NOSECRET);
240 	}
241 
242 	if (!readcache(xpublic, xsecret, &result->cryptkeyres_u.deskey)) {
243 		if ((ctx = BN_CTX_new()) == NULL)
244 			return (KEY_SYSTEMERR);
245 		public = NULL;
246 		if (BN_hex2bn(&public, xpublic) == 0) {
247 			BN_CTX_free(ctx);
248 			return (KEY_SYSTEMERR);
249 		}
250 		secret = NULL;
251 		if (BN_hex2bn(&secret, xsecret) == 0) {
252 			BN_free(public);
253 			BN_CTX_free(ctx);
254 			return (KEY_SYSTEMERR);
255 		}
256 
257 		if ((common = BN_new()) == NULL) {
258 			BN_free(secret);
259 			BN_free(public);
260 			BN_CTX_free(ctx);
261 			return (KEY_SYSTEMERR);
262 		}
263 		BN_zero(common);
264 		BN_mod_exp(common, public, secret, modulus, ctx);
265 
266 		extractdeskey(common, &result->cryptkeyres_u.deskey);
267 		writecache(xpublic, xsecret, &result->cryptkeyres_u.deskey);
268 		BN_free(secret);
269 		BN_free(public);
270 		BN_free(common);
271 		BN_CTX_free(ctx);
272 	}
273 
274 	return (KEY_SUCCESS);
275 }
276 
277 /*
278  * Choose middle 64 bits of the common key to use as our des key, possibly
279  * overwriting the lower order bits by setting parity.
280  */
281 static void
282 extractdeskey(BIGNUM *ck, des_block *deskey)
283 {
284 	BIGNUM *a;
285 	int i;
286 	BN_ULONG r, base = (1 << 8);
287 	char *k;
288 
289 	if ((a = BN_dup(ck)) == NULL)
290 		errx(1, "could not copy BIGNUM");
291 
292 	for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) {
293 		r = BN_div_word(a, base);
294 	}
295 	k = deskey->c;
296 	for (i = 0; i < 8; i++) {
297 		r = BN_div_word(a, base);
298 		*k++ = r;
299 	}
300 	BN_free(a);
301 	des_setparity((char *)deskey);
302 }
303 
304 /*
305  * Key storage management
306  */
307 
308 #define	KEY_ONLY 0
309 #define	KEY_NAME 1
310 struct secretkey_netname_list {
311 	uid_t uid;
312 	key_netstarg keynetdata;
313 	u_char sc_flag;
314 	struct secretkey_netname_list *next;
315 };
316 
317 
318 
319 static struct secretkey_netname_list *g_secretkey_netname;
320 
321 /*
322  * Store the keys and netname for this uid
323  */
324 static int
325 store_netname(uid_t uid, key_netstarg *netstore)
326 {
327 	struct secretkey_netname_list *new;
328 	struct secretkey_netname_list **l;
329 
330 	for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid;
331 			l = &(*l)->next) {
332 	}
333 	if (*l == NULL) {
334 		new = (struct secretkey_netname_list *)malloc(sizeof (*new));
335 		if (new == NULL) {
336 			return (0);
337 		}
338 		new->uid = uid;
339 		new->next = NULL;
340 		*l = new;
341 	} else {
342 		new = *l;
343 		if (new->keynetdata.st_netname)
344 			free(new->keynetdata.st_netname);
345 	}
346 	memcpy(new->keynetdata.st_priv_key, netstore->st_priv_key,
347 		HEXKEYBYTES);
348 	memcpy(new->keynetdata.st_pub_key, netstore->st_pub_key, HEXKEYBYTES);
349 
350 	if (netstore->st_netname)
351 		new->keynetdata.st_netname = strdup(netstore->st_netname);
352 	else
353 		new->keynetdata.st_netname = NULL;
354 	new->sc_flag = KEY_NAME;
355 	return (1);
356 
357 }
358 
359 /*
360  * Fetch the keys and netname for this uid
361  */
362 
363 static int
364 fetch_netname(uid_t uid, struct key_netstarg *key_netst)
365 {
366 	struct secretkey_netname_list *l;
367 
368 	for (l = g_secretkey_netname; l != NULL; l = l->next) {
369 		if ((l->uid == uid) && (l->sc_flag == KEY_NAME)){
370 
371 			memcpy(key_netst->st_priv_key,
372 				l->keynetdata.st_priv_key, HEXKEYBYTES);
373 
374 			memcpy(key_netst->st_pub_key,
375 				l->keynetdata.st_pub_key, HEXKEYBYTES);
376 
377 			if (l->keynetdata.st_netname)
378 				key_netst->st_netname =
379 					strdup(l->keynetdata.st_netname);
380 			else
381 				key_netst->st_netname = NULL;
382 		return (1);
383 		}
384 	}
385 
386 	return (0);
387 }
388 
389 static char *
390 fetchsecretkey(uid_t uid)
391 {
392 	struct secretkey_netname_list *l;
393 
394 	for (l = g_secretkey_netname; l != NULL; l = l->next) {
395 		if (l->uid == uid) {
396 			return (l->keynetdata.st_priv_key);
397 		}
398 	}
399 	return (NULL);
400 }
401 
402 /*
403  * Store the secretkey for this uid
404  */
405 static int
406 storesecretkey(uid_t uid, keybuf key)
407 {
408 	struct secretkey_netname_list *new;
409 	struct secretkey_netname_list **l;
410 
411 	for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid;
412 			l = &(*l)->next) {
413 	}
414 	if (*l == NULL) {
415 		new = (struct secretkey_netname_list *) malloc(sizeof (*new));
416 		if (new == NULL) {
417 			return (0);
418 		}
419 		new->uid = uid;
420 		new->sc_flag = KEY_ONLY;
421 		memset(new->keynetdata.st_pub_key, 0, HEXKEYBYTES);
422 		new->keynetdata.st_netname = NULL;
423 		new->next = NULL;
424 		*l = new;
425 	} else {
426 		new = *l;
427 	}
428 
429 	memcpy(new->keynetdata.st_priv_key, key,
430 		HEXKEYBYTES);
431 	return (1);
432 }
433 
434 static int
435 hexdigit(int val)
436 {
437 	return ("0123456789abcdef"[val]);
438 }
439 
440 void
441 bin2hex(unsigned char *bin, unsigned char *hex, int size)
442 {
443 	int i;
444 
445 	for (i = 0; i < size; i++) {
446 		*hex++ = hexdigit(*bin >> 4);
447 		*hex++ = hexdigit(*bin++ & 0xf);
448 	}
449 }
450 
451 static int
452 hexval(char dig)
453 {
454 	if ('0' <= dig && dig <= '9') {
455 		return (dig - '0');
456 	} else if ('a' <= dig && dig <= 'f') {
457 		return (dig - 'a' + 10);
458 	} else if ('A' <= dig && dig <= 'F') {
459 		return (dig - 'A' + 10);
460 	} else {
461 		return (-1);
462 	}
463 }
464 
465 void
466 hex2bin(unsigned char *hex, unsigned char *bin, int size)
467 {
468 	int i;
469 
470 	for (i = 0; i < size; i++) {
471 		*bin = hexval(*hex++) << 4;
472 		*bin++ |= hexval(*hex++);
473 	}
474 }
475 
476 /*
477  * Exponential caching management
478  */
479 struct cachekey_list {
480 	keybuf secret;
481 	keybuf public;
482 	des_block deskey;
483 	struct cachekey_list *next;
484 };
485 static struct cachekey_list *g_cachedkeys;
486 
487 /*
488  * cache result of expensive multiple precision exponential operation
489  */
490 static void
491 writecache(char *pub, char *sec, des_block *deskey)
492 {
493 	struct cachekey_list *new;
494 
495 	new = (struct cachekey_list *) malloc(sizeof (struct cachekey_list));
496 	if (new == NULL) {
497 		return;
498 	}
499 	memcpy(new->public, pub, sizeof (keybuf));
500 	memcpy(new->secret, sec, sizeof (keybuf));
501 	new->deskey = *deskey;
502 	new->next = g_cachedkeys;
503 	g_cachedkeys = new;
504 }
505 
506 /*
507  * Try to find the common key in the cache
508  */
509 static int
510 readcache(char *pub, char *sec, des_block *deskey)
511 {
512 	struct cachekey_list *found;
513 	struct cachekey_list **l;
514 
515 #define	cachehit(pub, sec, list)	\
516 		(memcmp(pub, (list)->public, sizeof (keybuf)) == 0 && \
517 		memcmp(sec, (list)->secret, sizeof (keybuf)) == 0)
518 
519 	for (l = &g_cachedkeys; (*l) != NULL && !cachehit(pub, sec, *l);
520 		l = &(*l)->next)
521 		;
522 	if ((*l) == NULL) {
523 		return (0);
524 	}
525 	found = *l;
526 	(*l) = (*l)->next;
527 	found->next = g_cachedkeys;
528 	g_cachedkeys = found;
529 	*deskey = found->deskey;
530 	return (1);
531 }
532