/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */ /* All Rights Reserved */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */ /* UNIX System Laboratories, Inc. */ /* The copyright notice above does not evidence any */ /* actual or intended publication of such source code. */ #ident "@(#)keyserv:setkey.c 1.8.3.2" /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * PROPRIETARY NOTICE (Combined) * * This source code is unpublished proprietary information * constituting, or derived under license from AT&T's UNIX(r) System V. * In addition, portions of such source code were derived from Berkeley * 4.3 BSD under license from the Regents of the University of * California. * * * * Copyright Notice * * Notice of copyright on this source code product does not indicate * publication. * * (c) 1986,1987,1988,1989,1990 Sun Microsystems, Inc * (c) 1983,1984,1985,1986,1987,1988,1989,1990 AT&T. * (c) 1990,1991 UNIX System Laboratories, Inc. * All rights reserved. */ /* * 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 #include "mp.h" #include #include #include #include extern char ROOTKEY[]; static MINT *MODULUS; static int nodefaultkeys = 0; static char *fetchsecretkey( uid_t ); static keystatus pk_crypt(uid_t, char *, des_block *, int); static void extractdeskey( MINT *ck, des_block *deskey); static int hexdigit( int val); static int hexval( char dig); static void writecache( char *pub, char *sec, des_block *deskey); static int readcache( char *pub, char *sec, des_block *deskey); /* * prohibit the nobody key on this machine k (the -d flag) */ pk_nodefaultkeys() { nodefaultkeys = 1; } /* * Set the modulus for all our Diffie-Hellman operations */ 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, key) uid_t uid; char *remote_name; des_block *key; { return (pk_crypt(uid, remote_name, 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, key) uid_t uid; char *remote_name; des_block *key; { return (pk_crypt(uid, remote_name, key, DES_DECRYPT)); } /* * Do the work of pk_encrypt && pk_decrypt */ static keystatus pk_crypt( uid_t uid, char *remote_name, des_block *key, int mode) { char *xsecret; char xpublic[HEXKEYBYTES + 1]; char xsecret_hold[HEXKEYBYTES + 1]; 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 (!getpublickey(remote_name, xpublic)) { if (nodefaultkeys) return (KEY_UNKNOWN); if (!getpublickey("nobody", xpublic)) { return (KEY_UNKNOWN); } } if (!readcache(xpublic, xsecret, &deskey)) { public = xtom(xpublic); secret = xtom(xsecret); common = itom(0); pow(public, secret, MODULUS, common); extractdeskey(common, &deskey); writecache(xpublic, xsecret, &deskey); mfree(secret); mfree(public); mfree(common); } err = ecb_crypt(deskey.c, key->c, sizeof (des_block), DES_HW | mode); if (DES_FAILED(err)) { return (KEY_SYSTEMERR); } 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( MINT *ck, des_block *deskey) { MINT *a; short r; int i; short base = (1 << 8); char *k; a = itom(0); _mp_move(ck, a); 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(deskey->c); } /* * Key storage management */ struct secretkey_list { uid_t uid; char secretkey[HEXKEYBYTES+1]; struct secretkey_list *next; }; static struct secretkey_list *g_secretkeys; /* * Fetch the secret key for this uid */ static char * fetchsecretkey( uid_t uid) { struct secretkey_list *l; for (l = g_secretkeys; l != NULL; l = l->next) { if (l->uid == uid) { return (l->secretkey); } } return (NULL); } /* * Store the secretkey for this uid */ storesecretkey(uid, key) uid_t uid; keybuf key; { struct secretkey_list *new; struct secretkey_list **l; int nitems; nitems = 0; for (l = &g_secretkeys; *l != NULL && (*l)->uid != uid; l = &(*l)->next) { nitems++; } if (*l == NULL) { new = (struct secretkey_list *)malloc(sizeof (*new)); if (new == NULL) { return (0); } new->uid = uid; new->next = NULL; *l = new; } else { new = *l; } memcpy(new->secretkey, key, HEXKEYBYTES); new->secretkey[HEXKEYBYTES] = 0; return (1); } static int hexdigit( int val) { return ("0123456789abcdef"[val]); } 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( 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); } } 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( 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( 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); }