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.
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.
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.
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.
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.
25 * Sun Microsystems, Inc.
27 * Mountain View, California 94043
32 static char sccsid[] = "@(#)setkey.c 1.11 94/04/25 SMI";
34 static const char rcsid[] =
39 * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
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.
53 #include <sys/types.h>
55 #include <rpc/key_prot.h>
56 #include <rpc/des_crypt.h>
58 #include <sys/errno.h>
62 static char *fetchsecretkey( uid_t );
63 static void writecache( char *, char *, des_block * );
64 static int readcache( char *, char *, des_block * );
65 static void extractdeskey( MINT *, des_block * );
66 static int storesecretkey( uid_t, keybuf );
67 static keystatus pk_crypt( uid_t, char *, netobj *, des_block *, int);
68 static int nodefaultkeys = 0;
72 * prohibit the nobody key on this machine k (the -d flag)
81 * Set the modulus for all our Diffie-Hellman operations
87 MODULUS = mp_xtom(modx);
91 * Set the secretkey key for this uid
98 if (!storesecretkey(uid, skey)) {
99 return (KEY_SYSTEMERR);
101 return (KEY_SUCCESS);
105 * Encrypt the key using the public key associated with remote_name and the
106 * secret key associated with uid.
109 pk_encrypt(uid, remote_name, remote_key, key)
115 return (pk_crypt(uid, remote_name, remote_key, key, DES_ENCRYPT));
119 * Decrypt the key using the public key associated with remote_name and the
120 * secret key associated with uid.
123 pk_decrypt(uid, remote_name, remote_key, key)
129 return (pk_crypt(uid, remote_name, remote_key, key, DES_DECRYPT));
132 static int store_netname( uid_t, key_netstarg * );
133 static int fetch_netname( uid_t, key_netstarg * );
136 pk_netput(uid, netstore)
138 key_netstarg *netstore;
140 if (!store_netname(uid, netstore)) {
141 return (KEY_SYSTEMERR);
143 return (KEY_SUCCESS);
147 pk_netget(uid, netstore)
149 key_netstarg *netstore;
151 if (!fetch_netname(uid, netstore)) {
152 return (KEY_SYSTEMERR);
154 return (KEY_SUCCESS);
159 * Do the work of pk_encrypt && pk_decrypt
162 pk_crypt(uid, remote_name, remote_key, key, mode)
171 char xsecret_hold[1024];
179 xsecret = fetchsecretkey(uid);
180 if (xsecret == NULL || xsecret[0] == 0) {
181 memset(zero, 0, sizeof (zero));
182 xsecret = xsecret_hold;
184 return (KEY_NOSECRET);
186 if (!getsecretkey("nobody", xsecret, zero) || xsecret[0] == 0) {
187 return (KEY_NOSECRET);
191 memcpy(xpublic, remote_key->n_bytes, remote_key->n_len);
193 bzero((char *)&xpublic, sizeof(xpublic));
194 if (!getpublickey(remote_name, xpublic)) {
195 if (nodefaultkeys || !getpublickey("nobody", xpublic))
196 return (KEY_UNKNOWN);
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);
208 mp_pow(public, secret, MODULUS, common);
209 extractdeskey(common, &deskey);
210 writecache(xpublic, xsecret, &deskey);
215 err = ecb_crypt((char *)&deskey, (char *)key, sizeof (des_block),
217 if (DES_FAILED(err)) {
218 return (KEY_SYSTEMERR);
220 return (KEY_SUCCESS);
224 pk_get_conv_key(uid, xpublic, result)
230 char xsecret_hold[1024];
237 xsecret = fetchsecretkey(uid);
239 if (xsecret == NULL || xsecret[0] == 0) {
240 memset(zero, 0, sizeof (zero));
241 xsecret = xsecret_hold;
243 return (KEY_NOSECRET);
245 if (!getsecretkey("nobody", xsecret, zero) ||
247 return (KEY_NOSECRET);
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);
258 mp_pow(public, secret, MODULUS, common);
259 extractdeskey(common, &result->cryptkeyres_u.deskey);
260 writecache(xpublic, xsecret, &result->cryptkeyres_u.deskey);
266 return (KEY_SUCCESS);
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.
274 extractdeskey(ck, deskey)
281 short base = (1 << 8);
290 for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) {
291 mp_sdiv(a, base, a, &r);
294 for (i = 0; i < 8; i++) {
295 mp_sdiv(a, base, a, &r);
299 des_setparity((char *)deskey);
303 * Key storage management
308 struct secretkey_netname_list {
310 key_netstarg keynetdata;
312 struct secretkey_netname_list *next;
317 static struct secretkey_netname_list *g_secretkey_netname;
320 * Store the keys and netname for this uid
323 store_netname(uid, netstore)
325 key_netstarg *netstore;
327 struct secretkey_netname_list *new;
328 struct secretkey_netname_list **l;
330 for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid;
334 new = (struct secretkey_netname_list *)malloc(sizeof (*new));
343 if (new->keynetdata.st_netname)
344 (void) free (new->keynetdata.st_netname);
346 memcpy(new->keynetdata.st_priv_key, netstore->st_priv_key,
348 memcpy(new->keynetdata.st_pub_key, netstore->st_pub_key, HEXKEYBYTES);
350 if (netstore->st_netname)
351 new->keynetdata.st_netname = strdup(netstore->st_netname);
353 new->keynetdata.st_netname = (char *)NULL;
354 new->sc_flag = KEY_NAME;
360 * Fetch the keys and netname for this uid
364 fetch_netname(uid, key_netst)
366 struct key_netstarg *key_netst;
368 struct secretkey_netname_list *l;
370 for (l = g_secretkey_netname; l != NULL; l = l->next) {
371 if ((l->uid == uid) && (l->sc_flag == KEY_NAME)){
373 memcpy(key_netst->st_priv_key,
374 l->keynetdata.st_priv_key, HEXKEYBYTES);
376 memcpy(key_netst->st_pub_key,
377 l->keynetdata.st_pub_key, HEXKEYBYTES);
379 if (l->keynetdata.st_netname)
380 key_netst->st_netname =
381 strdup(l->keynetdata.st_netname);
383 key_netst->st_netname = NULL;
395 struct secretkey_netname_list *l;
397 for (l = g_secretkey_netname; l != NULL; l = l->next) {
399 return (l->keynetdata.st_priv_key);
406 * Store the secretkey for this uid
409 storesecretkey(uid, key)
413 struct secretkey_netname_list *new;
414 struct secretkey_netname_list **l;
416 for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid;
420 new = (struct secretkey_netname_list *) malloc(sizeof (*new));
425 new->sc_flag = KEY_ONLY;
426 memset(new->keynetdata.st_pub_key, 0, HEXKEYBYTES);
427 new->keynetdata.st_netname = NULL;
434 memcpy(new->keynetdata.st_priv_key, key,
443 return ("0123456789abcdef"[val]);
447 bin2hex(bin, hex, size)
454 for (i = 0; i < size; i++) {
455 *hex++ = hexdigit(*bin >> 4);
456 *hex++ = hexdigit(*bin++ & 0xf);
464 if ('0' <= dig && dig <= '9') {
466 } else if ('a' <= dig && dig <= 'f') {
467 return (dig - 'a' + 10);
468 } else if ('A' <= dig && dig <= 'F') {
469 return (dig - 'A' + 10);
476 hex2bin(hex, bin, size)
483 for (i = 0; i < size; i++) {
484 *bin = hexval(*hex++) << 4;
485 *bin++ |= hexval(*hex++);
490 * Exponential caching management
492 struct cachekey_list {
496 struct cachekey_list *next;
498 static struct cachekey_list *g_cachedkeys;
501 * cache result of expensive multiple precision exponential operation
504 writecache(pub, sec, deskey)
509 struct cachekey_list *new;
511 new = (struct cachekey_list *) malloc(sizeof (struct cachekey_list));
515 memcpy(new->public, pub, sizeof (keybuf));
516 memcpy(new->secret, sec, sizeof (keybuf));
517 new->deskey = *deskey;
518 new->next = g_cachedkeys;
523 * Try to find the common key in the cache
526 readcache(pub, sec, deskey)
531 struct cachekey_list *found;
532 register struct cachekey_list **l;
534 #define cachehit(pub, sec, list) \
535 (memcmp(pub, (list)->public, sizeof (keybuf)) == 0 && \
536 memcmp(sec, (list)->secret, sizeof (keybuf)) == 0)
538 for (l = &g_cachedkeys; (*l) != NULL && !cachehit(pub, sec, *l);
546 found->next = g_cachedkeys;
547 g_cachedkeys = found;
548 *deskey = found->deskey;