setkey.c revision 26234
1139749Simp/*
2113584Ssimokawa * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3103285Sikob * unrestricted use provided that this legend is included on all tape
4103285Sikob * media and as a part of the software program in whole or part.  Users
5103285Sikob * may copy or modify Sun RPC without charge, but are not authorized
6103285Sikob * to license or distribute it to anyone else except as part of a product or
7103285Sikob * program developed by the user.
8103285Sikob *
9103285Sikob * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10103285Sikob * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11103285Sikob * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
12103285Sikob *
13103285Sikob * Sun RPC is provided with no support and without any obligation on the
14103285Sikob * part of Sun Microsystems, Inc. to assist in its use, correction,
15103285Sikob * modification or enhancement.
16103285Sikob *
17103285Sikob * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18103285Sikob * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19103285Sikob * OR ANY PART THEREOF.
20103285Sikob *
21103285Sikob * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22103285Sikob * or profits or other special, indirect and consequential damages, even if
23103285Sikob * Sun has been advised of the possibility of such damages.
24103285Sikob *
25103285Sikob * Sun Microsystems, Inc.
26103285Sikob * 2550 Garcia Avenue
27103285Sikob * Mountain View, California  94043
28103285Sikob */
29103285Sikob
30103285Sikob#pragma ident	"@(#)setkey.c	1.11	94/04/25 SMI"
31103285Sikob
32103285Sikob/*
33103285Sikob * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
34103285Sikob */
35103285Sikob
36103285Sikob/*
37103285Sikob * Do the real work of the keyserver.
38127468Ssimokawa * Store secret keys. Compute common keys,
39127468Ssimokawa * and use them to decrypt and encrypt DES keys.
40127468Ssimokawa * Cache the common keys, so the expensive computation is avoided.
41127468Ssimokawa */
42103285Sikob#include <stdio.h>
43103285Sikob#include <stdlib.h>
44103285Sikob#include <unistd.h>
45103285Sikob#include <sys/types.h>
46103285Sikob#include <mp.h>
47103285Sikob#include <rpc/rpc.h>
48103285Sikob#include <rpc/key_prot.h>
49113584Ssimokawa#include <rpc/des_crypt.h>
50170374Ssimokawa#include <rpc/des.h>
51170374Ssimokawa#include <sys/errno.h>
52113584Ssimokawa#include <string.h>
53103285Sikob#include "keyserv.h"
54103285Sikob
55169130Ssimokawastatic MINT *MODULUS;
56169130Ssimokawastatic char *fetchsecretkey __P(( uid_t ));
57103285Sikobstatic void writecache __P(( char *, char *, des_block * ));
58129585Sdfrstatic int readcache __P(( char *, char *, des_block * ));
59103285Sikobstatic void extractdeskey __P (( MINT *, des_block * ));
60129585Sdfrstatic int storesecretkey __P(( uid_t, keybuf ));
61129585Sdfrstatic keystatus pk_crypt __P(( uid_t, char *, netobj *, des_block *, int));
62129585Sdfrstatic int nodefaultkeys = 0;
63129585Sdfr
64103285Sikob
65103285Sikob/*
66103285Sikob * prohibit the nobody key on this machine k (the -d flag)
67129585Sdfr */
68103285Sikobvoid
69106810Ssimokawapk_nodefaultkeys()
70129585Sdfr{
71103285Sikob	nodefaultkeys = 1;
72103285Sikob}
73103285Sikob
74110193Ssimokawa/*
75103285Sikob * Set the modulus for all our Diffie-Hellman operations
76109645Ssimokawa */
77103285Sikobvoid
78127468Ssimokawasetmodulus(modx)
79130585Sphk	char *modx;
80103285Sikob{
81103285Sikob	MODULUS = xtom(modx);
82103285Sikob}
83109645Ssimokawa
84103285Sikob/*
85103285Sikob * Set the secretkey key for this uid
86103285Sikob */
87109645Ssimokawakeystatus
88103285Sikobpk_setkey(uid, skey)
89103285Sikob	uid_t uid;
90103285Sikob	keybuf skey;
91124169Ssimokawa{
92124169Ssimokawa	if (!storesecretkey(uid, skey)) {
93103285Sikob		return (KEY_SYSTEMERR);
94103285Sikob	}
95103285Sikob	return (KEY_SUCCESS);
96103285Sikob}
97103285Sikob
98103285Sikob/*
99103285Sikob * Encrypt the key using the public key associated with remote_name and the
100103285Sikob * secret key associated with uid.
101103285Sikob */
102103285Sikobkeystatus
103170374Ssimokawapk_encrypt(uid, remote_name, remote_key, key)
104103285Sikob	uid_t uid;
105103285Sikob	char *remote_name;
106103285Sikob	netobj	*remote_key;
107103285Sikob	des_block *key;
108103285Sikob{
109129585Sdfr	return (pk_crypt(uid, remote_name, remote_key, key, DES_ENCRYPT));
110103285Sikob}
111103285Sikob
112103285Sikob/*
113103285Sikob * Decrypt the key using the public key associated with remote_name and the
114103285Sikob * secret key associated with uid.
115103285Sikob */
116103285Sikobkeystatus
117103285Sikobpk_decrypt(uid, remote_name, remote_key, key)
118103285Sikob	uid_t uid;
119129585Sdfr	char *remote_name;
120169806Ssimokawa	netobj *remote_key;
121116978Ssimokawa	des_block *key;
122103285Sikob{
123103285Sikob	return (pk_crypt(uid, remote_name, remote_key, key, DES_DECRYPT));
124103285Sikob}
125103285Sikob
126103285Sikobstatic int store_netname __P(( uid_t, key_netstarg * ));
127103285Sikobstatic int fetch_netname __P(( uid_t, key_netstarg * ));
128103285Sikob
129103285Sikobkeystatus
130103285Sikobpk_netput(uid, netstore)
131103285Sikob	uid_t uid;
132109814Ssimokawa	key_netstarg *netstore;
133103285Sikob{
134103285Sikob	if (!store_netname(uid, netstore)) {
135169130Ssimokawa		return (KEY_SYSTEMERR);
136171457Ssimokawa	}
137171513Ssimokawa	return (KEY_SUCCESS);
138103285Sikob}
139110193Ssimokawa
140103285Sikobkeystatus
141103285Sikobpk_netget(uid, netstore)
142129585Sdfr	uid_t uid;
143103285Sikob	key_netstarg *netstore;
144129585Sdfr{
145116376Ssimokawa	if (!fetch_netname(uid, netstore)) {
146116376Ssimokawa		return (KEY_SYSTEMERR);
147116376Ssimokawa	}
148103285Sikob	return (KEY_SUCCESS);
149103285Sikob}
150108853Ssimokawa
151110193Ssimokawa
152110193Ssimokawa/*
153170374Ssimokawa * Do the work of pk_encrypt && pk_decrypt
154129585Sdfr */
155124169Ssimokawastatic keystatus
156129585Sdfrpk_crypt(uid, remote_name, remote_key, key, mode)
157130585Sphk	uid_t uid;
158124169Ssimokawa	char *remote_name;
159124169Ssimokawa	netobj *remote_key;
160124169Ssimokawa	des_block *key;
161124169Ssimokawa	int mode;
162124169Ssimokawa{
163124169Ssimokawa	char *xsecret;
164124169Ssimokawa	char xpublic[1024];
165129585Sdfr	char xsecret_hold[1024];
166129585Sdfr	des_block deskey;
167103285Sikob	int err;
168113584Ssimokawa	MINT *public;
169170374Ssimokawa	MINT *secret;
170170374Ssimokawa	MINT *common;
171170374Ssimokawa	char zero[8];
172170374Ssimokawa
173103285Sikob	xsecret = fetchsecretkey(uid);
174103285Sikob	if (xsecret == NULL || xsecret[0] == 0) {
175103285Sikob		memset(zero, 0, sizeof (zero));
176170374Ssimokawa		xsecret = xsecret_hold;
177170374Ssimokawa		if (nodefaultkeys)
178170374Ssimokawa			return (KEY_NOSECRET);
179170374Ssimokawa
180170374Ssimokawa		if (!getsecretkey("nobody", xsecret, zero) || xsecret[0] == 0) {
181109645Ssimokawa			return (KEY_NOSECRET);
182109645Ssimokawa		}
183109645Ssimokawa	}
184109645Ssimokawa	if (remote_key) {
185109645Ssimokawa		memcpy(xpublic, remote_key->n_bytes, remote_key->n_len);
186109645Ssimokawa	} else {
187109645Ssimokawa		bzero((char *)&xpublic, sizeof(xpublic));
188109645Ssimokawa		if (!getpublickey(remote_name, xpublic)) {
189109645Ssimokawa			if (nodefaultkeys || !getpublickey("nobody", xpublic))
190109645Ssimokawa				return (KEY_UNKNOWN);
191109645Ssimokawa		}
192109645Ssimokawa	}
193109645Ssimokawa
194109645Ssimokawa	if (!readcache(xpublic, xsecret, &deskey)) {
195124169Ssimokawa		public = xtom(xpublic);
196118293Ssimokawa		secret = xtom(xsecret);
197169130Ssimokawa		/* Sanity Check on public and private keys */
198109645Ssimokawa		if ((public == NULL) || (secret == NULL))
199109645Ssimokawa			return (KEY_SYSTEMERR);
200109645Ssimokawa
201113584Ssimokawa		common = itom(0);
202109645Ssimokawa		pow(public, secret, MODULUS, common);
203109645Ssimokawa		extractdeskey(common, &deskey);
204109645Ssimokawa		writecache(xpublic, xsecret, &deskey);
205109645Ssimokawa		mfree(secret);
206109645Ssimokawa		mfree(public);
207109890Ssimokawa		mfree(common);
208109645Ssimokawa	}
209109645Ssimokawa	err = ecb_crypt((char *)&deskey, (char *)key, sizeof (des_block),
210109645Ssimokawa		DES_HW | mode);
211124169Ssimokawa	if (DES_FAILED(err)) {
212109645Ssimokawa		return (KEY_SYSTEMERR);
213109645Ssimokawa	}
214109645Ssimokawa	return (KEY_SUCCESS);
215113584Ssimokawa}
216111942Ssimokawa
217109645Ssimokawakeystatus
218109645Ssimokawapk_get_conv_key(uid, xpublic, result)
219109645Ssimokawa	uid_t uid;
220111942Ssimokawa	keybuf xpublic;
221109645Ssimokawa	cryptkeyres *result;
222109645Ssimokawa{
223109645Ssimokawa	char *xsecret;
224120660Ssimokawa	char xsecret_hold[1024];
225120660Ssimokawa	MINT *public;
226169130Ssimokawa	MINT *secret;
227109645Ssimokawa	MINT *common;
228109645Ssimokawa	char zero[8];
229169130Ssimokawa
230109645Ssimokawa
231109645Ssimokawa	xsecret = fetchsecretkey(uid);
232103285Sikob
233103285Sikob	if (xsecret == NULL || xsecret[0] == 0) {
234103285Sikob		memset(zero, 0, sizeof (zero));
235103285Sikob		xsecret = xsecret_hold;
236110577Ssimokawa		if (nodefaultkeys)
237113584Ssimokawa			return (KEY_NOSECRET);
238170374Ssimokawa
239170374Ssimokawa		if (!getsecretkey("nobody", xsecret, zero) ||
240170374Ssimokawa			xsecret[0] == 0)
241170374Ssimokawa			return (KEY_NOSECRET);
242170374Ssimokawa	}
243170374Ssimokawa
244170374Ssimokawa	if (!readcache(xpublic, xsecret, &result->cryptkeyres_u.deskey)) {
245170374Ssimokawa		public = xtom(xpublic);
246170374Ssimokawa		secret = xtom(xsecret);
247170374Ssimokawa		/* Sanity Check on public and private keys */
248169119Ssimokawa		if ((public == NULL) || (secret == NULL))
249167632Ssimokawa			return (KEY_SYSTEMERR);
250103285Sikob
251120660Ssimokawa		common = itom(0);
252129585Sdfr		pow(public, secret, MODULUS, common);
253129585Sdfr		extractdeskey(common, &result->cryptkeyres_u.deskey);
254129585Sdfr		writecache(xpublic, xsecret, &result->cryptkeyres_u.deskey);
255103285Sikob		mfree(secret);
256103285Sikob		mfree(public);
257103285Sikob		mfree(common);
258169119Ssimokawa	}
259110269Ssimokawa
260103285Sikob	return (KEY_SUCCESS);
261120660Ssimokawa}
262120660Ssimokawa
263120660Ssimokawa/*
264120660Ssimokawa * Choose middle 64 bits of the common key to use as our des key, possibly
265120660Ssimokawa * overwriting the lower order bits by setting parity.
266120660Ssimokawa */
267129585Sdfrstatic void
268120660Ssimokawaextractdeskey(ck, deskey)
269120660Ssimokawa	MINT *ck;
270129585Sdfr	des_block *deskey;
271124169Ssimokawa{
272124169Ssimokawa	MINT *a;
273124169Ssimokawa	short r;
274124169Ssimokawa	int i;
275124169Ssimokawa	short base = (1 << 8);
276124169Ssimokawa	char *k;
277124169Ssimokawa
278124169Ssimokawa	a = itom(0);
279124169Ssimokawa#ifdef SOLARIS_MP
280124169Ssimokawa	_mp_move(ck, a);
281124169Ssimokawa#else
282169130Ssimokawa	move(ck, a);
283169130Ssimokawa#endif
284169130Ssimokawa	for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) {
285124169Ssimokawa		sdiv(a, base, a, &r);
286169117Ssimokawa	}
287129585Sdfr	k = deskey->c;
288124169Ssimokawa	for (i = 0; i < 8; i++) {
289124169Ssimokawa		sdiv(a, base, a, &r);
290170374Ssimokawa		*k++ = r;
291170374Ssimokawa	}
292124169Ssimokawa	mfree(a);
293124169Ssimokawa	des_setparity((char *)deskey);
294124169Ssimokawa}
295129585Sdfr
296124169Ssimokawa/*
297124169Ssimokawa * Key storage management
298124169Ssimokawa */
299148868Srwatson
300170374Ssimokawa#define	KEY_ONLY 0
301103285Sikob#define	KEY_NAME 1
302103285Sikobstruct secretkey_netname_list {
303103285Sikob	uid_t uid;
304170400Ssimokawa	key_netstarg keynetdata;
305103285Sikob	u_char sc_flag;
306127468Ssimokawa	struct secretkey_netname_list *next;
307127468Ssimokawa};
308127468Ssimokawa
309103285Sikob
310127468Ssimokawa
311103285Sikobstatic struct secretkey_netname_list *g_secretkey_netname;
312127468Ssimokawa
313127468Ssimokawa/*
314127468Ssimokawa * Store the keys and netname for this uid
315170374Ssimokawa */
316111615Ssimokawastatic int
317111615Ssimokawastore_netname(uid, netstore)
318127468Ssimokawa	uid_t uid;
319120660Ssimokawa	key_netstarg *netstore;
320120660Ssimokawa{
321120660Ssimokawa	struct secretkey_netname_list *new;
322120660Ssimokawa	struct secretkey_netname_list **l;
323120660Ssimokawa
324120660Ssimokawa	for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid;
325120660Ssimokawa			l = &(*l)->next) {
326120660Ssimokawa	}
327120660Ssimokawa	if (*l == NULL) {
328120660Ssimokawa		new = (struct secretkey_netname_list *)malloc(sizeof (*new));
329120660Ssimokawa		if (new == NULL) {
330120660Ssimokawa			return (0);
331120660Ssimokawa		}
332120660Ssimokawa		new->uid = uid;
333120660Ssimokawa		new->next = NULL;
334121780Ssimokawa		*l = new;
335120660Ssimokawa	} else {
336120660Ssimokawa		new = *l;
337110195Ssimokawa		if (new->keynetdata.st_netname)
338110269Ssimokawa			(void) free (new->keynetdata.st_netname);
339	}
340	memcpy(new->keynetdata.st_priv_key, netstore->st_priv_key,
341		HEXKEYBYTES);
342	memcpy(new->keynetdata.st_pub_key, netstore->st_pub_key, HEXKEYBYTES);
343
344	if (netstore->st_netname)
345		new->keynetdata.st_netname = strdup(netstore->st_netname);
346	else
347		new->keynetdata.st_netname = (char *)NULL;
348	new->sc_flag = KEY_NAME;
349	return (1);
350
351}
352
353/*
354 * Fetch the keys and netname for this uid
355 */
356
357static int
358fetch_netname(uid, key_netst)
359	uid_t uid;
360	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
385static char *
386fetchsecretkey(uid)
387	uid_t uid;
388{
389	struct secretkey_netname_list *l;
390
391	for (l = g_secretkey_netname; l != NULL; l = l->next) {
392		if (l->uid == uid) {
393			return (l->keynetdata.st_priv_key);
394		}
395	}
396	return (NULL);
397}
398
399/*
400 * Store the secretkey for this uid
401 */
402static int
403storesecretkey(uid, key)
404	uid_t uid;
405	keybuf key;
406{
407	struct secretkey_netname_list *new;
408	struct secretkey_netname_list **l;
409
410	for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid;
411			l = &(*l)->next) {
412	}
413	if (*l == NULL) {
414		new = (struct secretkey_netname_list *) malloc(sizeof (*new));
415		if (new == NULL) {
416			return (0);
417		}
418		new->uid = uid;
419		new->sc_flag = KEY_ONLY;
420		memset(new->keynetdata.st_pub_key, 0, HEXKEYBYTES);
421		new->keynetdata.st_netname = NULL;
422		new->next = NULL;
423		*l = new;
424	} else {
425		new = *l;
426	}
427
428	memcpy(new->keynetdata.st_priv_key, key,
429		HEXKEYBYTES);
430	return (1);
431}
432
433static int
434hexdigit(val)
435	int val;
436{
437	return ("0123456789abcdef"[val]);
438}
439
440void
441bin2hex(bin, hex, size)
442	unsigned char *bin;
443	unsigned char *hex;
444	int size;
445{
446	int i;
447
448	for (i = 0; i < size; i++) {
449		*hex++ = hexdigit(*bin >> 4);
450		*hex++ = hexdigit(*bin++ & 0xf);
451	}
452}
453
454static int
455hexval(dig)
456	char dig;
457{
458	if ('0' <= dig && dig <= '9') {
459		return (dig - '0');
460	} else if ('a' <= dig && dig <= 'f') {
461		return (dig - 'a' + 10);
462	} else if ('A' <= dig && dig <= 'F') {
463		return (dig - 'A' + 10);
464	} else {
465		return (-1);
466	}
467}
468
469void
470hex2bin(hex, bin, size)
471	unsigned char *hex;
472	unsigned char *bin;
473	int size;
474{
475	int i;
476
477	for (i = 0; i < size; i++) {
478		*bin = hexval(*hex++) << 4;
479		*bin++ |= hexval(*hex++);
480	}
481}
482
483/*
484 * Exponential caching management
485 */
486struct cachekey_list {
487	keybuf secret;
488	keybuf public;
489	des_block deskey;
490	struct cachekey_list *next;
491};
492static struct cachekey_list *g_cachedkeys;
493
494/*
495 * cache result of expensive multiple precision exponential operation
496 */
497static void
498writecache(pub, sec, deskey)
499	char *pub;
500	char *sec;
501	des_block *deskey;
502{
503	struct cachekey_list *new;
504
505	new = (struct cachekey_list *) malloc(sizeof (struct cachekey_list));
506	if (new == NULL) {
507		return;
508	}
509	memcpy(new->public, pub, sizeof (keybuf));
510	memcpy(new->secret, sec, sizeof (keybuf));
511	new->deskey = *deskey;
512	new->next = g_cachedkeys;
513	g_cachedkeys = new;
514}
515
516/*
517 * Try to find the common key in the cache
518 */
519static int
520readcache(pub, sec, deskey)
521	char *pub;
522	char *sec;
523	des_block *deskey;
524{
525	struct cachekey_list *found;
526	register struct cachekey_list **l;
527
528#define	cachehit(pub, sec, list)	\
529		(memcmp(pub, (list)->public, sizeof (keybuf)) == 0 && \
530		memcmp(sec, (list)->secret, sizeof (keybuf)) == 0)
531
532	for (l = &g_cachedkeys; (*l) != NULL && !cachehit(pub, sec, *l);
533		l = &(*l)->next)
534		;
535	if ((*l) == NULL) {
536		return (0);
537	}
538	found = *l;
539	(*l) = (*l)->next;
540	found->next = g_cachedkeys;
541	g_cachedkeys = found;
542	*deskey = found->deskey;
543	return (1);
544}
545