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
29 * @(#)setkey.c 1.11 94/04/25 SMI
30 * $FreeBSD: src/usr.sbin/keyserv/setkey.c,v 1.3 1999/08/28 01:16:41 peter Exp $
31 * $DragonFly: src/usr.sbin/keyserv/setkey.c,v 1.2 2003/06/17 04:29:55 dillon Exp $
35 * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
39 * Do the real work of the keyserver.
40 * Store secret keys. Compute common keys,
41 * and use them to decrypt and encrypt DES keys.
42 * Cache the common keys, so the expensive computation is avoided.
49 #include <sys/types.h>
51 #include <rpc/key_prot.h>
52 #include <rpc/des_crypt.h>
54 #include <sys/errno.h>
58 static char *fetchsecretkey __P(( uid_t ));
59 static void writecache __P(( char *, char *, des_block * ));
60 static int readcache __P(( char *, char *, des_block * ));
61 static void extractdeskey __P (( MINT *, des_block * ));
62 static int storesecretkey __P(( uid_t, keybuf ));
63 static keystatus pk_crypt __P(( uid_t, char *, netobj *, des_block *, int));
64 static int nodefaultkeys = 0;
68 * prohibit the nobody key on this machine k (the -d flag)
77 * Set the modulus for all our Diffie-Hellman operations
87 * Set the secretkey key for this uid
94 if (!storesecretkey(uid, skey)) {
95 return (KEY_SYSTEMERR);
101 * Encrypt the key using the public key associated with remote_name and the
102 * secret key associated with uid.
105 pk_encrypt(uid, remote_name, remote_key, key)
111 return (pk_crypt(uid, remote_name, remote_key, key, DES_ENCRYPT));
115 * Decrypt the key using the public key associated with remote_name and the
116 * secret key associated with uid.
119 pk_decrypt(uid, remote_name, remote_key, key)
125 return (pk_crypt(uid, remote_name, remote_key, key, DES_DECRYPT));
128 static int store_netname __P(( uid_t, key_netstarg * ));
129 static int fetch_netname __P(( uid_t, key_netstarg * ));
132 pk_netput(uid, netstore)
134 key_netstarg *netstore;
136 if (!store_netname(uid, netstore)) {
137 return (KEY_SYSTEMERR);
139 return (KEY_SUCCESS);
143 pk_netget(uid, netstore)
145 key_netstarg *netstore;
147 if (!fetch_netname(uid, netstore)) {
148 return (KEY_SYSTEMERR);
150 return (KEY_SUCCESS);
155 * Do the work of pk_encrypt && pk_decrypt
158 pk_crypt(uid, remote_name, remote_key, key, mode)
167 char xsecret_hold[1024];
175 xsecret = fetchsecretkey(uid);
176 if (xsecret == NULL || xsecret[0] == 0) {
177 memset(zero, 0, sizeof (zero));
178 xsecret = xsecret_hold;
180 return (KEY_NOSECRET);
182 if (!getsecretkey("nobody", xsecret, zero) || xsecret[0] == 0) {
183 return (KEY_NOSECRET);
187 memcpy(xpublic, remote_key->n_bytes, remote_key->n_len);
189 bzero((char *)&xpublic, sizeof(xpublic));
190 if (!getpublickey(remote_name, xpublic)) {
191 if (nodefaultkeys || !getpublickey("nobody", xpublic))
192 return (KEY_UNKNOWN);
196 if (!readcache(xpublic, xsecret, &deskey)) {
197 public = xtom(xpublic);
198 secret = xtom(xsecret);
199 /* Sanity Check on public and private keys */
200 if ((public == NULL) || (secret == NULL))
201 return (KEY_SYSTEMERR);
204 pow(public, secret, MODULUS, common);
205 extractdeskey(common, &deskey);
206 writecache(xpublic, xsecret, &deskey);
211 err = ecb_crypt((char *)&deskey, (char *)key, sizeof (des_block),
213 if (DES_FAILED(err)) {
214 return (KEY_SYSTEMERR);
216 return (KEY_SUCCESS);
220 pk_get_conv_key(uid, xpublic, result)
226 char xsecret_hold[1024];
233 xsecret = fetchsecretkey(uid);
235 if (xsecret == NULL || xsecret[0] == 0) {
236 memset(zero, 0, sizeof (zero));
237 xsecret = xsecret_hold;
239 return (KEY_NOSECRET);
241 if (!getsecretkey("nobody", xsecret, zero) ||
243 return (KEY_NOSECRET);
246 if (!readcache(xpublic, xsecret, &result->cryptkeyres_u.deskey)) {
247 public = xtom(xpublic);
248 secret = xtom(xsecret);
249 /* Sanity Check on public and private keys */
250 if ((public == NULL) || (secret == NULL))
251 return (KEY_SYSTEMERR);
254 pow(public, secret, MODULUS, common);
255 extractdeskey(common, &result->cryptkeyres_u.deskey);
256 writecache(xpublic, xsecret, &result->cryptkeyres_u.deskey);
262 return (KEY_SUCCESS);
266 * Choose middle 64 bits of the common key to use as our des key, possibly
267 * overwriting the lower order bits by setting parity.
270 extractdeskey(ck, deskey)
277 short base = (1 << 8);
286 for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) {
287 sdiv(a, base, a, &r);
290 for (i = 0; i < 8; i++) {
291 sdiv(a, base, a, &r);
295 des_setparity((char *)deskey);
299 * Key storage management
304 struct secretkey_netname_list {
306 key_netstarg keynetdata;
308 struct secretkey_netname_list *next;
313 static struct secretkey_netname_list *g_secretkey_netname;
316 * Store the keys and netname for this uid
319 store_netname(uid, netstore)
321 key_netstarg *netstore;
323 struct secretkey_netname_list *new;
324 struct secretkey_netname_list **l;
326 for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid;
330 new = (struct secretkey_netname_list *)malloc(sizeof (*new));
339 if (new->keynetdata.st_netname)
340 (void) free (new->keynetdata.st_netname);
342 memcpy(new->keynetdata.st_priv_key, netstore->st_priv_key,
344 memcpy(new->keynetdata.st_pub_key, netstore->st_pub_key, HEXKEYBYTES);
346 if (netstore->st_netname)
347 new->keynetdata.st_netname = strdup(netstore->st_netname);
349 new->keynetdata.st_netname = (char *)NULL;
350 new->sc_flag = KEY_NAME;
356 * Fetch the keys and netname for this uid
360 fetch_netname(uid, key_netst)
362 struct key_netstarg *key_netst;
364 struct secretkey_netname_list *l;
366 for (l = g_secretkey_netname; l != NULL; l = l->next) {
367 if ((l->uid == uid) && (l->sc_flag == KEY_NAME)){
369 memcpy(key_netst->st_priv_key,
370 l->keynetdata.st_priv_key, HEXKEYBYTES);
372 memcpy(key_netst->st_pub_key,
373 l->keynetdata.st_pub_key, HEXKEYBYTES);
375 if (l->keynetdata.st_netname)
376 key_netst->st_netname =
377 strdup(l->keynetdata.st_netname);
379 key_netst->st_netname = NULL;
391 struct secretkey_netname_list *l;
393 for (l = g_secretkey_netname; l != NULL; l = l->next) {
395 return (l->keynetdata.st_priv_key);
402 * Store the secretkey for this uid
405 storesecretkey(uid, key)
409 struct secretkey_netname_list *new;
410 struct secretkey_netname_list **l;
412 for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid;
416 new = (struct secretkey_netname_list *) malloc(sizeof (*new));
421 new->sc_flag = KEY_ONLY;
422 memset(new->keynetdata.st_pub_key, 0, HEXKEYBYTES);
423 new->keynetdata.st_netname = NULL;
430 memcpy(new->keynetdata.st_priv_key, key,
439 return ("0123456789abcdef"[val]);
443 bin2hex(bin, hex, size)
450 for (i = 0; i < size; i++) {
451 *hex++ = hexdigit(*bin >> 4);
452 *hex++ = hexdigit(*bin++ & 0xf);
460 if ('0' <= dig && dig <= '9') {
462 } else if ('a' <= dig && dig <= 'f') {
463 return (dig - 'a' + 10);
464 } else if ('A' <= dig && dig <= 'F') {
465 return (dig - 'A' + 10);
472 hex2bin(hex, bin, size)
479 for (i = 0; i < size; i++) {
480 *bin = hexval(*hex++) << 4;
481 *bin++ |= hexval(*hex++);
486 * Exponential caching management
488 struct cachekey_list {
492 struct cachekey_list *next;
494 static struct cachekey_list *g_cachedkeys;
497 * cache result of expensive multiple precision exponential operation
500 writecache(pub, sec, deskey)
505 struct cachekey_list *new;
507 new = (struct cachekey_list *) malloc(sizeof (struct cachekey_list));
511 memcpy(new->public, pub, sizeof (keybuf));
512 memcpy(new->secret, sec, sizeof (keybuf));
513 new->deskey = *deskey;
514 new->next = g_cachedkeys;
519 * Try to find the common key in the cache
522 readcache(pub, sec, deskey)
527 struct cachekey_list *found;
528 register struct cachekey_list **l;
530 #define cachehit(pub, sec, list) \
531 (memcmp(pub, (list)->public, sizeof (keybuf)) == 0 && \
532 memcmp(sec, (list)->secret, sizeof (keybuf)) == 0)
534 for (l = &g_cachedkeys; (*l) != NULL && !cachehit(pub, sec, *l);
542 found->next = g_cachedkeys;
543 g_cachedkeys = found;
544 *deskey = found->deskey;