setkey.c revision 26235
1146773Ssam/*
2146773Ssam * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3146773Ssam * unrestricted use provided that this legend is included on all tape
4146773Ssam * media and as a part of the software program in whole or part.  Users
5146773Ssam * may copy or modify Sun RPC without charge, but are not authorized
6146773Ssam * to license or distribute it to anyone else except as part of a product or
7146773Ssam * program developed by the user.
8146773Ssam *
9146773Ssam * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10146773Ssam * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11146773Ssam * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
12146773Ssam *
13146773Ssam * Sun RPC is provided with no support and without any obligation on the
14146773Ssam * part of Sun Microsystems, Inc. to assist in its use, correction,
15146773Ssam * modification or enhancement.
16146773Ssam *
17146773Ssam * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18146773Ssam * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19146773Ssam * OR ANY PART THEREOF.
20190207Srpaulo *
21190207Srpaulo * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22146773Ssam * or profits or other special, indirect and consequential damages, even if
23146773Ssam * Sun has been advised of the possibility of such damages.
24146773Ssam *
25146773Ssam * Sun Microsystems, Inc.
26190207Srpaulo * 2550 Garcia Avenue
27146773Ssam * Mountain View, California  94043
28146773Ssam */
29146773Ssam
30146773Ssam#pragma ident	"@(#)setkey.c	1.11	94/04/25 SMI"
31146773Ssam
32146773Ssam/*
33146773Ssam * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
34146773Ssam */
35146773Ssam
36146773Ssam/*
37146773Ssam * Do the real work of the keyserver.
38146773Ssam * Store secret keys. Compute common keys,
39190207Srpaulo * and use them to decrypt and encrypt DES keys.
40146773Ssam * Cache the common keys, so the expensive computation is avoided.
41146773Ssam */
42146773Ssam#include <stdio.h>
43146773Ssam#include <stdlib.h>
44190207Srpaulo#include <unistd.h>
45190207Srpaulo#include <sys/types.h>
46190207Srpaulo#include <mp.h>
47190207Srpaulo#include <rpc/rpc.h>
48190207Srpaulo#include <rpc/key_prot.h>
49190207Srpaulo#include <rpc/des_crypt.h>
50190207Srpaulo#include <rpc/des.h>
51190207Srpaulo#include <sys/errno.h>
52190207Srpaulo#include <string.h>
53190207Srpaulo#include "keyserv.h"
54190207Srpaulo
55190207Srpaulostatic MINT *MODULUS;
56190207Srpaulostatic char *fetchsecretkey __P(( uid_t ));
57190207Srpaulostatic void writecache __P(( char *, char *, des_block * ));
58190207Srpaulostatic int readcache __P(( char *, char *, des_block * ));
59190207Srpaulostatic void extractdeskey __P (( MINT *, des_block * ));
60190207Srpaulostatic int storesecretkey __P(( uid_t, keybuf ));
61190207Srpaulostatic keystatus pk_crypt __P(( uid_t, char *, netobj *, des_block *, int));
62190207Srpaulostatic int nodefaultkeys = 0;
63190207Srpaulo
64190207Srpaulo
65190207Srpaulo/*
66146773Ssam * prohibit the nobody key on this machine k (the -d flag)
67190207Srpaulo */
68190207Srpaulovoid
69190207Srpaulopk_nodefaultkeys()
70146773Ssam{
71146773Ssam	nodefaultkeys = 1;
72190207Srpaulo}
73190207Srpaulo
74190207Srpaulo/*
75190207Srpaulo * Set the modulus for all our Diffie-Hellman operations
76190207Srpaulo */
77190207Srpaulovoid
78190207Srpaulosetmodulus(modx)
79190207Srpaulo	char *modx;
80190207Srpaulo{
81190207Srpaulo	MODULUS = xtom(modx);
82190207Srpaulo}
83190207Srpaulo
84190207Srpaulo/*
85190207Srpaulo * Set the secretkey key for this uid
86190207Srpaulo */
87190207Srpaulokeystatus
88190207Srpaulopk_setkey(uid, skey)
89190207Srpaulo	uid_t uid;
90190207Srpaulo	keybuf skey;
91190207Srpaulo{
92190207Srpaulo	if (!storesecretkey(uid, skey)) {
93190207Srpaulo		return (KEY_SYSTEMERR);
94190207Srpaulo	}
95190207Srpaulo	return (KEY_SUCCESS);
96190207Srpaulo}
97190207Srpaulo
98190207Srpaulo/*
99190207Srpaulo * Encrypt the key using the public key associated with remote_name and the
100190207Srpaulo * secret key associated with uid.
101190207Srpaulo */
102190207Srpaulokeystatus
103190207Srpaulopk_encrypt(uid, remote_name, remote_key, key)
104190207Srpaulo	uid_t uid;
105190207Srpaulo	char *remote_name;
106190207Srpaulo	netobj	*remote_key;
107190207Srpaulo	des_block *key;
108190207Srpaulo{
109190207Srpaulo	return (pk_crypt(uid, remote_name, remote_key, key, DES_ENCRYPT));
110190207Srpaulo}
111190207Srpaulo
112190207Srpaulo/*
113190207Srpaulo * Decrypt the key using the public key associated with remote_name and the
114190207Srpaulo * secret key associated with uid.
115190207Srpaulo */
116190207Srpaulokeystatus
117190207Srpaulopk_decrypt(uid, remote_name, remote_key, key)
118190207Srpaulo	uid_t uid;
119190207Srpaulo	char *remote_name;
120190207Srpaulo	netobj *remote_key;
121190207Srpaulo	des_block *key;
122190207Srpaulo{
123190207Srpaulo	return (pk_crypt(uid, remote_name, remote_key, key, DES_DECRYPT));
124190207Srpaulo}
125190207Srpaulo
126190207Srpaulostatic int store_netname __P(( uid_t, key_netstarg * ));
127190207Srpaulostatic int fetch_netname __P(( uid_t, key_netstarg * ));
128190207Srpaulo
129190207Srpaulokeystatus
130190207Srpaulopk_netput(uid, netstore)
131190207Srpaulo	uid_t uid;
132190207Srpaulo	key_netstarg *netstore;
133190207Srpaulo{
134190207Srpaulo	if (!store_netname(uid, netstore)) {
135190207Srpaulo		return (KEY_SYSTEMERR);
136190207Srpaulo	}
137190207Srpaulo	return (KEY_SUCCESS);
138190207Srpaulo}
139190207Srpaulo
140190207Srpaulokeystatus
141190207Srpaulopk_netget(uid, netstore)
142190207Srpaulo	uid_t uid;
143190207Srpaulo	key_netstarg *netstore;
144190207Srpaulo{
145190207Srpaulo	if (!fetch_netname(uid, netstore)) {
146190207Srpaulo		return (KEY_SYSTEMERR);
147190207Srpaulo	}
148190207Srpaulo	return (KEY_SUCCESS);
149190207Srpaulo}
150190207Srpaulo
151190207Srpaulo
152190207Srpaulo/*
153190207Srpaulo * Do the work of pk_encrypt && pk_decrypt
154190207Srpaulo */
155190207Srpaulostatic keystatus
156190207Srpaulopk_crypt(uid, remote_name, remote_key, key, mode)
157190207Srpaulo	uid_t uid;
158146773Ssam	char *remote_name;
159190207Srpaulo	netobj *remote_key;
160146773Ssam	des_block *key;
161146773Ssam	int mode;
162190207Srpaulo{
163190207Srpaulo	char *xsecret;
164190207Srpaulo	char xpublic[1024];
165146773Ssam	char xsecret_hold[1024];
166190207Srpaulo	des_block deskey;
167190207Srpaulo	int err;
168190207Srpaulo	MINT *public;
169190207Srpaulo	MINT *secret;
170190207Srpaulo	MINT *common;
171190207Srpaulo	char zero[8];
172190207Srpaulo
173190207Srpaulo	xsecret = fetchsecretkey(uid);
174190207Srpaulo	if (xsecret == NULL || xsecret[0] == 0) {
175146773Ssam		memset(zero, 0, sizeof (zero));
176190207Srpaulo		xsecret = xsecret_hold;
177190207Srpaulo		if (nodefaultkeys)
178190207Srpaulo			return (KEY_NOSECRET);
179190207Srpaulo
180190207Srpaulo		if (!getsecretkey("nobody", xsecret, zero) || xsecret[0] == 0) {
181190207Srpaulo			return (KEY_NOSECRET);
182190207Srpaulo		}
183190207Srpaulo	}
184190207Srpaulo	if (remote_key) {
185190207Srpaulo		memcpy(xpublic, remote_key->n_bytes, remote_key->n_len);
186190207Srpaulo	} else {
187190207Srpaulo		bzero((char *)&xpublic, sizeof(xpublic));
188190207Srpaulo		if (!getpublickey(remote_name, xpublic)) {
189190207Srpaulo			if (nodefaultkeys || !getpublickey("nobody", xpublic))
190190207Srpaulo				return (KEY_UNKNOWN);
191146773Ssam		}
192190207Srpaulo	}
193190207Srpaulo
194146773Ssam	if (!readcache(xpublic, xsecret, &deskey)) {
195190207Srpaulo		public = xtom(xpublic);
196190207Srpaulo		secret = xtom(xsecret);
197190207Srpaulo		/* Sanity Check on public and private keys */
198190207Srpaulo		if ((public == NULL) || (secret == NULL))
199190207Srpaulo			return (KEY_SYSTEMERR);
200190207Srpaulo
201190207Srpaulo		common = itom(0);
202190207Srpaulo		pow(public, secret, MODULUS, common);
203190207Srpaulo		extractdeskey(common, &deskey);
204146773Ssam		writecache(xpublic, xsecret, &deskey);
205190207Srpaulo		mfree(secret);
206190207Srpaulo		mfree(public);
207190207Srpaulo		mfree(common);
208190207Srpaulo	}
209190207Srpaulo	err = ecb_crypt((char *)&deskey, (char *)key, sizeof (des_block),
210190207Srpaulo		DES_HW | mode);
211190207Srpaulo	if (DES_FAILED(err)) {
212190207Srpaulo		return (KEY_SYSTEMERR);
213190207Srpaulo	}
214190207Srpaulo	return (KEY_SUCCESS);
215190207Srpaulo}
216190207Srpaulo
217190207Srpaulokeystatus
218190207Srpaulopk_get_conv_key(uid, xpublic, result)
219190207Srpaulo	uid_t uid;
220190207Srpaulo	keybuf xpublic;
221190207Srpaulo	cryptkeyres *result;
222190207Srpaulo{
223190207Srpaulo	char *xsecret;
224190207Srpaulo	char xsecret_hold[1024];
225190207Srpaulo	MINT *public;
226190207Srpaulo	MINT *secret;
227190207Srpaulo	MINT *common;
228190207Srpaulo	char zero[8];
229190207Srpaulo
230190207Srpaulo
231190207Srpaulo	xsecret = fetchsecretkey(uid);
232190207Srpaulo
233190207Srpaulo	if (xsecret == NULL || xsecret[0] == 0) {
234190207Srpaulo		memset(zero, 0, sizeof (zero));
235190207Srpaulo		xsecret = xsecret_hold;
236190207Srpaulo		if (nodefaultkeys)
237190207Srpaulo			return (KEY_NOSECRET);
238190207Srpaulo
239190207Srpaulo		if (!getsecretkey("nobody", xsecret, zero) ||
240190207Srpaulo			xsecret[0] == 0)
241190207Srpaulo			return (KEY_NOSECRET);
242190207Srpaulo	}
243190207Srpaulo
244190207Srpaulo	if (!readcache(xpublic, xsecret, &result->cryptkeyres_u.deskey)) {
245190207Srpaulo		public = xtom(xpublic);
246190207Srpaulo		secret = xtom(xsecret);
247190207Srpaulo		/* Sanity Check on public and private keys */
248190207Srpaulo		if ((public == NULL) || (secret == NULL))
249190207Srpaulo			return (KEY_SYSTEMERR);
250190207Srpaulo
251190207Srpaulo		common = itom(0);
252190207Srpaulo		pow(public, secret, MODULUS, common);
253190207Srpaulo		extractdeskey(common, &result->cryptkeyres_u.deskey);
254190207Srpaulo		writecache(xpublic, xsecret, &result->cryptkeyres_u.deskey);
255190207Srpaulo		mfree(secret);
256190207Srpaulo		mfree(public);
257190207Srpaulo		mfree(common);
258190207Srpaulo	}
259190207Srpaulo
260190207Srpaulo	return (KEY_SUCCESS);
261190207Srpaulo}
262190207Srpaulo
263190207Srpaulo/*
264190207Srpaulo * Choose middle 64 bits of the common key to use as our des key, possibly
265190207Srpaulo * overwriting the lower order bits by setting parity.
266190207Srpaulo */
267190207Srpaulostatic void
268190207Srpauloextractdeskey(ck, deskey)
269190207Srpaulo	MINT *ck;
270190207Srpaulo	des_block *deskey;
271190207Srpaulo{
272190207Srpaulo	MINT *a;
273190207Srpaulo	short r;
274190207Srpaulo	int i;
275190207Srpaulo	short base = (1 << 8);
276190207Srpaulo	char *k;
277190207Srpaulo
278190207Srpaulo	a = itom(0);
279190207Srpaulo#ifdef SOLARIS_MP
280190207Srpaulo	_mp_move(ck, a);
281190207Srpaulo#else
282190207Srpaulo	move(ck, a);
283190207Srpaulo#endif
284190207Srpaulo	for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) {
285190207Srpaulo		sdiv(a, base, a, &r);
286190207Srpaulo	}
287190207Srpaulo	k = deskey->c;
288190207Srpaulo	for (i = 0; i < 8; i++) {
289190207Srpaulo		sdiv(a, base, a, &r);
290190207Srpaulo		*k++ = r;
291190207Srpaulo	}
292190207Srpaulo	mfree(a);
293190207Srpaulo	des_setparity((char *)deskey);
294190207Srpaulo}
295190207Srpaulo
296190207Srpaulo/*
297190207Srpaulo * Key storage management
298190207Srpaulo */
299190207Srpaulo
300190207Srpaulo#define	KEY_ONLY 0
301146773Ssam#define	KEY_NAME 1
302146773Ssamstruct secretkey_netname_list {
303190207Srpaulo	uid_t uid;
304190207Srpaulo	key_netstarg keynetdata;
305190207Srpaulo	u_char sc_flag;
306190207Srpaulo	struct secretkey_netname_list *next;
307190207Srpaulo};
308
309
310
311static struct secretkey_netname_list *g_secretkey_netname;
312
313/*
314 * Store the keys and netname for this uid
315 */
316static int
317store_netname(uid, netstore)
318	uid_t uid;
319	key_netstarg *netstore;
320{
321	struct secretkey_netname_list *new;
322	struct secretkey_netname_list **l;
323
324	for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid;
325			l = &(*l)->next) {
326	}
327	if (*l == NULL) {
328		new = (struct secretkey_netname_list *)malloc(sizeof (*new));
329		if (new == NULL) {
330			return (0);
331		}
332		new->uid = uid;
333		new->next = NULL;
334		*l = new;
335	} else {
336		new = *l;
337		if (new->keynetdata.st_netname)
338			(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