diff options
Diffstat (limited to 'usr.sbin/keyserv/setkey.c')
-rw-r--r-- | usr.sbin/keyserv/setkey.c | 544 |
1 files changed, 544 insertions, 0 deletions
diff --git a/usr.sbin/keyserv/setkey.c b/usr.sbin/keyserv/setkey.c new file mode 100644 index 0000000..bdafae9 --- /dev/null +++ b/usr.sbin/keyserv/setkey.c @@ -0,0 +1,544 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +#pragma ident "@(#)setkey.c 1.11 94/04/25 SMI" + +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* + * Do the real work of the keyserver. + * Store secret keys. Compute common keys, + * and use them to decrypt and encrypt DES keys. + * Cache the common keys, so the expensive computation is avoided. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <mp.h> +#include <rpc/rpc.h> +#include <rpc/key_prot.h> +#include <rpc/des_crypt.h> +#include <rpc/des.h> +#include <sys/errno.h> +#include <string.h> +#include "keyserv.h" + +static MINT *MODULUS; +static char *fetchsecretkey __P(( uid_t )); +static void writecache __P(( char *, char *, des_block * )); +static int readcache __P(( char *, char *, des_block * )); +static void extractdeskey __P (( MINT *, des_block * )); +static int storesecretkey __P(( uid_t, keybuf )); +static keystatus pk_crypt __P(( uid_t, char *, netobj *, des_block *, int)); +static int nodefaultkeys = 0; + + +/* + * prohibit the nobody key on this machine k (the -d flag) + */ +void +pk_nodefaultkeys() +{ + nodefaultkeys = 1; +} + +/* + * Set the modulus for all our Diffie-Hellman operations + */ +void +setmodulus(modx) + char *modx; +{ + MODULUS = xtom(modx); +} + +/* + * Set the secretkey key for this uid + */ +keystatus +pk_setkey(uid, skey) + uid_t uid; + keybuf skey; +{ + if (!storesecretkey(uid, skey)) { + return (KEY_SYSTEMERR); + } + return (KEY_SUCCESS); +} + +/* + * Encrypt the key using the public key associated with remote_name and the + * secret key associated with uid. + */ +keystatus +pk_encrypt(uid, remote_name, remote_key, key) + uid_t uid; + char *remote_name; + netobj *remote_key; + des_block *key; +{ + return (pk_crypt(uid, remote_name, remote_key, key, DES_ENCRYPT)); +} + +/* + * Decrypt the key using the public key associated with remote_name and the + * secret key associated with uid. + */ +keystatus +pk_decrypt(uid, remote_name, remote_key, key) + uid_t uid; + char *remote_name; + netobj *remote_key; + des_block *key; +{ + return (pk_crypt(uid, remote_name, remote_key, key, DES_DECRYPT)); +} + +static int store_netname __P(( uid_t, key_netstarg * )); +static int fetch_netname __P(( uid_t, key_netstarg * )); + +keystatus +pk_netput(uid, netstore) + uid_t uid; + key_netstarg *netstore; +{ + if (!store_netname(uid, netstore)) { + return (KEY_SYSTEMERR); + } + return (KEY_SUCCESS); +} + +keystatus +pk_netget(uid, netstore) + uid_t uid; + key_netstarg *netstore; +{ + if (!fetch_netname(uid, netstore)) { + return (KEY_SYSTEMERR); + } + return (KEY_SUCCESS); +} + + +/* + * Do the work of pk_encrypt && pk_decrypt + */ +static keystatus +pk_crypt(uid, remote_name, remote_key, key, mode) + uid_t uid; + char *remote_name; + netobj *remote_key; + des_block *key; + int mode; +{ + char *xsecret; + char xpublic[1024]; + char xsecret_hold[1024]; + des_block deskey; + int err; + MINT *public; + MINT *secret; + MINT *common; + char zero[8]; + + xsecret = fetchsecretkey(uid); + if (xsecret == NULL || xsecret[0] == 0) { + memset(zero, 0, sizeof (zero)); + xsecret = xsecret_hold; + if (nodefaultkeys) + return (KEY_NOSECRET); + + if (!getsecretkey("nobody", xsecret, zero) || xsecret[0] == 0) { + return (KEY_NOSECRET); + } + } + if (remote_key) { + memcpy(xpublic, remote_key->n_bytes, remote_key->n_len); + } else { + bzero((char *)&xpublic, sizeof(xpublic)); + if (!getpublickey(remote_name, xpublic)) { + if (nodefaultkeys || !getpublickey("nobody", xpublic)) + return (KEY_UNKNOWN); + } + } + + if (!readcache(xpublic, xsecret, &deskey)) { + public = xtom(xpublic); + secret = xtom(xsecret); + /* Sanity Check on public and private keys */ + if ((public == NULL) || (secret == NULL)) + return (KEY_SYSTEMERR); + + common = itom(0); + pow(public, secret, MODULUS, common); + extractdeskey(common, &deskey); + writecache(xpublic, xsecret, &deskey); + mfree(secret); + mfree(public); + mfree(common); + } + err = ecb_crypt((char *)&deskey, (char *)key, sizeof (des_block), + DES_HW | mode); + if (DES_FAILED(err)) { + return (KEY_SYSTEMERR); + } + return (KEY_SUCCESS); +} + +keystatus +pk_get_conv_key(uid, xpublic, result) + uid_t uid; + keybuf xpublic; + cryptkeyres *result; +{ + char *xsecret; + char xsecret_hold[1024]; + MINT *public; + MINT *secret; + MINT *common; + char zero[8]; + + + xsecret = fetchsecretkey(uid); + + if (xsecret == NULL || xsecret[0] == 0) { + memset(zero, 0, sizeof (zero)); + xsecret = xsecret_hold; + if (nodefaultkeys) + return (KEY_NOSECRET); + + if (!getsecretkey("nobody", xsecret, zero) || + xsecret[0] == 0) + return (KEY_NOSECRET); + } + + if (!readcache(xpublic, xsecret, &result->cryptkeyres_u.deskey)) { + public = xtom(xpublic); + secret = xtom(xsecret); + /* Sanity Check on public and private keys */ + if ((public == NULL) || (secret == NULL)) + return (KEY_SYSTEMERR); + + common = itom(0); + pow(public, secret, MODULUS, common); + extractdeskey(common, &result->cryptkeyres_u.deskey); + writecache(xpublic, xsecret, &result->cryptkeyres_u.deskey); + mfree(secret); + mfree(public); + mfree(common); + } + + return (KEY_SUCCESS); +} + +/* + * Choose middle 64 bits of the common key to use as our des key, possibly + * overwriting the lower order bits by setting parity. + */ +static void +extractdeskey(ck, deskey) + MINT *ck; + des_block *deskey; +{ + MINT *a; + short r; + int i; + short base = (1 << 8); + char *k; + + a = itom(0); +#ifdef SOLARIS_MP + _mp_move(ck, a); +#else + move(ck, a); +#endif + for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) { + sdiv(a, base, a, &r); + } + k = deskey->c; + for (i = 0; i < 8; i++) { + sdiv(a, base, a, &r); + *k++ = r; + } + mfree(a); + des_setparity((char *)deskey); +} + +/* + * Key storage management + */ + +#define KEY_ONLY 0 +#define KEY_NAME 1 +struct secretkey_netname_list { + uid_t uid; + key_netstarg keynetdata; + u_char sc_flag; + struct secretkey_netname_list *next; +}; + + + +static struct secretkey_netname_list *g_secretkey_netname; + +/* + * Store the keys and netname for this uid + */ +static int +store_netname(uid, netstore) + uid_t uid; + key_netstarg *netstore; +{ + struct secretkey_netname_list *new; + struct secretkey_netname_list **l; + + for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid; + l = &(*l)->next) { + } + if (*l == NULL) { + new = (struct secretkey_netname_list *)malloc(sizeof (*new)); + if (new == NULL) { + return (0); + } + new->uid = uid; + new->next = NULL; + *l = new; + } else { + new = *l; + if (new->keynetdata.st_netname) + (void) free (new->keynetdata.st_netname); + } + memcpy(new->keynetdata.st_priv_key, netstore->st_priv_key, + HEXKEYBYTES); + memcpy(new->keynetdata.st_pub_key, netstore->st_pub_key, HEXKEYBYTES); + + if (netstore->st_netname) + new->keynetdata.st_netname = strdup(netstore->st_netname); + else + new->keynetdata.st_netname = (char *)NULL; + new->sc_flag = KEY_NAME; + return (1); + +} + +/* + * Fetch the keys and netname for this uid + */ + +static int +fetch_netname(uid, key_netst) + uid_t uid; + struct key_netstarg *key_netst; +{ + struct secretkey_netname_list *l; + + for (l = g_secretkey_netname; l != NULL; l = l->next) { + if ((l->uid == uid) && (l->sc_flag == KEY_NAME)){ + + memcpy(key_netst->st_priv_key, + l->keynetdata.st_priv_key, HEXKEYBYTES); + + memcpy(key_netst->st_pub_key, + l->keynetdata.st_pub_key, HEXKEYBYTES); + + if (l->keynetdata.st_netname) + key_netst->st_netname = + strdup(l->keynetdata.st_netname); + else + key_netst->st_netname = NULL; + return (1); + } + } + + return (0); +} + +static char * +fetchsecretkey(uid) + uid_t uid; +{ + struct secretkey_netname_list *l; + + for (l = g_secretkey_netname; l != NULL; l = l->next) { + if (l->uid == uid) { + return (l->keynetdata.st_priv_key); + } + } + return (NULL); +} + +/* + * Store the secretkey for this uid + */ +static int +storesecretkey(uid, key) + uid_t uid; + keybuf key; +{ + struct secretkey_netname_list *new; + struct secretkey_netname_list **l; + + for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid; + l = &(*l)->next) { + } + if (*l == NULL) { + new = (struct secretkey_netname_list *) malloc(sizeof (*new)); + if (new == NULL) { + return (0); + } + new->uid = uid; + new->sc_flag = KEY_ONLY; + memset(new->keynetdata.st_pub_key, 0, HEXKEYBYTES); + new->keynetdata.st_netname = NULL; + new->next = NULL; + *l = new; + } else { + new = *l; + } + + memcpy(new->keynetdata.st_priv_key, key, + HEXKEYBYTES); + return (1); +} + +static int +hexdigit(val) + int val; +{ + return ("0123456789abcdef"[val]); +} + +void +bin2hex(bin, hex, size) + unsigned char *bin; + unsigned char *hex; + int size; +{ + int i; + + for (i = 0; i < size; i++) { + *hex++ = hexdigit(*bin >> 4); + *hex++ = hexdigit(*bin++ & 0xf); + } +} + +static int +hexval(dig) + char dig; +{ + if ('0' <= dig && dig <= '9') { + return (dig - '0'); + } else if ('a' <= dig && dig <= 'f') { + return (dig - 'a' + 10); + } else if ('A' <= dig && dig <= 'F') { + return (dig - 'A' + 10); + } else { + return (-1); + } +} + +void +hex2bin(hex, bin, size) + unsigned char *hex; + unsigned char *bin; + int size; +{ + int i; + + for (i = 0; i < size; i++) { + *bin = hexval(*hex++) << 4; + *bin++ |= hexval(*hex++); + } +} + +/* + * Exponential caching management + */ +struct cachekey_list { + keybuf secret; + keybuf public; + des_block deskey; + struct cachekey_list *next; +}; +static struct cachekey_list *g_cachedkeys; + +/* + * cache result of expensive multiple precision exponential operation + */ +static void +writecache(pub, sec, deskey) + char *pub; + char *sec; + des_block *deskey; +{ + struct cachekey_list *new; + + new = (struct cachekey_list *) malloc(sizeof (struct cachekey_list)); + if (new == NULL) { + return; + } + memcpy(new->public, pub, sizeof (keybuf)); + memcpy(new->secret, sec, sizeof (keybuf)); + new->deskey = *deskey; + new->next = g_cachedkeys; + g_cachedkeys = new; +} + +/* + * Try to find the common key in the cache + */ +static int +readcache(pub, sec, deskey) + char *pub; + char *sec; + des_block *deskey; +{ + struct cachekey_list *found; + register struct cachekey_list **l; + +#define cachehit(pub, sec, list) \ + (memcmp(pub, (list)->public, sizeof (keybuf)) == 0 && \ + memcmp(sec, (list)->secret, sizeof (keybuf)) == 0) + + for (l = &g_cachedkeys; (*l) != NULL && !cachehit(pub, sec, *l); + l = &(*l)->next) + ; + if ((*l) == NULL) { + return (0); + } + found = *l; + (*l) = (*l)->next; + found->next = g_cachedkeys; + g_cachedkeys = found; + *deskey = found->deskey; + return (1); +} |