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)
75 pk_nodefaultkeys(void)
81 * Set the modulus for all our Diffie-Hellman operations
84 setmodulus(char *modx)
86 MODULUS = mp_xtom(modx);
90 * Set the secretkey key for this uid
93 pk_setkey(uid_t uid, keybuf skey)
95 if (!storesecretkey(uid, skey)) {
96 return (KEY_SYSTEMERR);
102 * Encrypt the key using the public key associated with remote_name and the
103 * secret key associated with uid.
106 pk_encrypt(uid_t uid, char *remote_name, netobj *remote_key, des_block *key)
108 return (pk_crypt(uid, remote_name, remote_key, key, DES_ENCRYPT));
112 * Decrypt the key using the public key associated with remote_name and the
113 * secret key associated with uid.
116 pk_decrypt(uid_t uid, char *remote_name, netobj *remote_key, des_block *key)
118 return (pk_crypt(uid, remote_name, remote_key, key, DES_DECRYPT));
121 static int store_netname( uid_t, key_netstarg * );
122 static int fetch_netname( uid_t, key_netstarg * );
125 pk_netput(uid_t uid, key_netstarg *netstore)
127 if (!store_netname(uid, netstore)) {
128 return (KEY_SYSTEMERR);
130 return (KEY_SUCCESS);
134 pk_netget(uid_t uid, key_netstarg *netstore)
136 if (!fetch_netname(uid, netstore)) {
137 return (KEY_SYSTEMERR);
139 return (KEY_SUCCESS);
144 * Do the work of pk_encrypt && pk_decrypt
147 pk_crypt(uid_t uid, char *remote_name, netobj *remote_key, des_block *key,
152 char xsecret_hold[1024];
160 xsecret = fetchsecretkey(uid);
161 if (xsecret == NULL || xsecret[0] == 0) {
162 memset(zero, 0, sizeof (zero));
163 xsecret = xsecret_hold;
165 return (KEY_NOSECRET);
167 if (!getsecretkey("nobody", xsecret, zero) || xsecret[0] == 0) {
168 return (KEY_NOSECRET);
172 memcpy(xpublic, remote_key->n_bytes, remote_key->n_len);
174 bzero((char *)&xpublic, sizeof(xpublic));
175 if (!getpublickey(remote_name, xpublic)) {
176 if (nodefaultkeys || !getpublickey("nobody", xpublic))
177 return (KEY_UNKNOWN);
181 if (!readcache(xpublic, xsecret, &deskey)) {
182 public = mp_xtom(xpublic);
183 secret = mp_xtom(xsecret);
184 /* Sanity Check on public and private keys */
185 if ((public == NULL) || (secret == NULL))
186 return (KEY_SYSTEMERR);
189 mp_pow(public, secret, MODULUS, common);
190 extractdeskey(common, &deskey);
191 writecache(xpublic, xsecret, &deskey);
196 err = ecb_crypt((char *)&deskey, (char *)key, sizeof (des_block),
198 if (DES_FAILED(err)) {
199 return (KEY_SYSTEMERR);
201 return (KEY_SUCCESS);
205 pk_get_conv_key(uid_t uid, keybuf xpublic, cryptkeyres *result)
208 char xsecret_hold[1024];
215 xsecret = fetchsecretkey(uid);
217 if (xsecret == NULL || xsecret[0] == 0) {
218 memset(zero, 0, sizeof (zero));
219 xsecret = xsecret_hold;
221 return (KEY_NOSECRET);
223 if (!getsecretkey("nobody", xsecret, zero) ||
225 return (KEY_NOSECRET);
228 if (!readcache(xpublic, xsecret, &result->cryptkeyres_u.deskey)) {
229 public = mp_xtom(xpublic);
230 secret = mp_xtom(xsecret);
231 /* Sanity Check on public and private keys */
232 if ((public == NULL) || (secret == NULL))
233 return (KEY_SYSTEMERR);
236 mp_pow(public, secret, MODULUS, common);
237 extractdeskey(common, &result->cryptkeyres_u.deskey);
238 writecache(xpublic, xsecret, &result->cryptkeyres_u.deskey);
244 return (KEY_SUCCESS);
248 * Choose middle 64 bits of the common key to use as our des key, possibly
249 * overwriting the lower order bits by setting parity.
252 extractdeskey(MINT *ck, des_block *deskey)
257 short base = (1 << 8);
266 for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) {
267 mp_sdiv(a, base, a, &r);
270 for (i = 0; i < 8; i++) {
271 mp_sdiv(a, base, a, &r);
275 des_setparity((char *)deskey);
279 * Key storage management
284 struct secretkey_netname_list {
286 key_netstarg keynetdata;
288 struct secretkey_netname_list *next;
293 static struct secretkey_netname_list *g_secretkey_netname;
296 * Store the keys and netname for this uid
299 store_netname(uid_t uid, key_netstarg *netstore)
301 struct secretkey_netname_list *new;
302 struct secretkey_netname_list **l;
304 for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid;
308 new = (struct secretkey_netname_list *)malloc(sizeof (*new));
317 if (new->keynetdata.st_netname)
318 (void) free (new->keynetdata.st_netname);
320 memcpy(new->keynetdata.st_priv_key, netstore->st_priv_key,
322 memcpy(new->keynetdata.st_pub_key, netstore->st_pub_key, HEXKEYBYTES);
324 if (netstore->st_netname)
325 new->keynetdata.st_netname = strdup(netstore->st_netname);
327 new->keynetdata.st_netname = (char *)NULL;
328 new->sc_flag = KEY_NAME;
334 * Fetch the keys and netname for this uid
338 fetch_netname(uid_t uid, struct key_netstarg *key_netst)
340 struct secretkey_netname_list *l;
342 for (l = g_secretkey_netname; l != NULL; l = l->next) {
343 if ((l->uid == uid) && (l->sc_flag == KEY_NAME)){
345 memcpy(key_netst->st_priv_key,
346 l->keynetdata.st_priv_key, HEXKEYBYTES);
348 memcpy(key_netst->st_pub_key,
349 l->keynetdata.st_pub_key, HEXKEYBYTES);
351 if (l->keynetdata.st_netname)
352 key_netst->st_netname =
353 strdup(l->keynetdata.st_netname);
355 key_netst->st_netname = NULL;
364 fetchsecretkey(uid_t uid)
366 struct secretkey_netname_list *l;
368 for (l = g_secretkey_netname; l != NULL; l = l->next) {
370 return (l->keynetdata.st_priv_key);
377 * Store the secretkey for this uid
380 storesecretkey(uid_t uid, keybuf key)
382 struct secretkey_netname_list *new;
383 struct secretkey_netname_list **l;
385 for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid;
389 new = (struct secretkey_netname_list *) malloc(sizeof (*new));
394 new->sc_flag = KEY_ONLY;
395 memset(new->keynetdata.st_pub_key, 0, HEXKEYBYTES);
396 new->keynetdata.st_netname = NULL;
403 memcpy(new->keynetdata.st_priv_key, key,
411 return ("0123456789abcdef"[val]);
415 bin2hex(unsigned char *bin, unsigned char *hex, int size)
419 for (i = 0; i < size; i++) {
420 *hex++ = hexdigit(*bin >> 4);
421 *hex++ = hexdigit(*bin++ & 0xf);
428 if ('0' <= dig && dig <= '9') {
430 } else if ('a' <= dig && dig <= 'f') {
431 return (dig - 'a' + 10);
432 } else if ('A' <= dig && dig <= 'F') {
433 return (dig - 'A' + 10);
440 hex2bin(unsigned char *hex, unsigned char *bin, int size)
444 for (i = 0; i < size; i++) {
445 *bin = hexval(*hex++) << 4;
446 *bin++ |= hexval(*hex++);
451 * Exponential caching management
453 struct cachekey_list {
457 struct cachekey_list *next;
459 static struct cachekey_list *g_cachedkeys;
462 * cache result of expensive multiple precision exponential operation
465 writecache(char *pub, char *sec, des_block *deskey)
467 struct cachekey_list *new;
469 new = (struct cachekey_list *) malloc(sizeof (struct cachekey_list));
473 memcpy(new->public, pub, sizeof (keybuf));
474 memcpy(new->secret, sec, sizeof (keybuf));
475 new->deskey = *deskey;
476 new->next = g_cachedkeys;
481 * Try to find the common key in the cache
484 readcache(char *pub, char *sec, des_block *deskey)
486 struct cachekey_list *found;
487 register struct cachekey_list **l;
489 #define cachehit(pub, sec, list) \
490 (memcmp(pub, (list)->public, sizeof (keybuf)) == 0 && \
491 memcmp(sec, (list)->secret, sizeof (keybuf)) == 0)
493 for (l = &g_cachedkeys; (*l) != NULL && !cachehit(pub, sec, *l);
501 found->next = g_cachedkeys;
502 g_cachedkeys = found;
503 *deskey = found->deskey;