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