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