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