126234Swpaul/* 226234Swpaul * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 326234Swpaul * unrestricted use provided that this legend is included on all tape 426234Swpaul * media and as a part of the software program in whole or part. Users 526234Swpaul * may copy or modify Sun RPC without charge, but are not authorized 626234Swpaul * to license or distribute it to anyone else except as part of a product or 726234Swpaul * program developed by the user. 826234Swpaul * 926234Swpaul * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 1026234Swpaul * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 1126234Swpaul * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 1226234Swpaul * 1326234Swpaul * Sun RPC is provided with no support and without any obligation on the 1426234Swpaul * part of Sun Microsystems, Inc. to assist in its use, correction, 1526234Swpaul * modification or enhancement. 1626234Swpaul * 1726234Swpaul * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 1826234Swpaul * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 1926234Swpaul * OR ANY PART THEREOF. 2026234Swpaul * 2126234Swpaul * In no event will Sun Microsystems, Inc. be liable for any lost revenue 2226234Swpaul * or profits or other special, indirect and consequential damages, even if 2326234Swpaul * Sun has been advised of the possibility of such damages. 2426234Swpaul * 2526234Swpaul * Sun Microsystems, Inc. 2626234Swpaul * 2550 Garcia Avenue 2726234Swpaul * Mountain View, California 94043 2826234Swpaul */ 2926234Swpaul 3029735Scharnier#ifndef lint 3129735Scharnier#if 0 3229735Scharnierstatic char sccsid[] = "@(#)setkey.c 1.11 94/04/25 SMI"; 3329735Scharnier#endif 3429735Scharnierstatic const char rcsid[] = 3550479Speter "$FreeBSD$"; 3629735Scharnier#endif /* not lint */ 3726234Swpaul 3826234Swpaul/* 3926234Swpaul * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. 4026234Swpaul */ 4126234Swpaul 4226234Swpaul/* 4326234Swpaul * Do the real work of the keyserver. 4426234Swpaul * Store secret keys. Compute common keys, 4526234Swpaul * and use them to decrypt and encrypt DES keys. 4626234Swpaul * Cache the common keys, so the expensive computation is avoided. 4726234Swpaul */ 4829735Scharnier#include <mp.h> 4926234Swpaul#include <stdio.h> 5026234Swpaul#include <stdlib.h> 5129735Scharnier#include <string.h> 5226234Swpaul#include <unistd.h> 5326234Swpaul#include <sys/types.h> 5426234Swpaul#include <rpc/rpc.h> 5526234Swpaul#include <rpc/key_prot.h> 5626234Swpaul#include <rpc/des_crypt.h> 5726234Swpaul#include <rpc/des.h> 5826234Swpaul#include <sys/errno.h> 5926234Swpaul#include "keyserv.h" 6026234Swpaul 6126234Swpaulstatic MINT *MODULUS; 62173412Skevlostatic char *fetchsecretkey( uid_t ); 63173412Skevlostatic void writecache( char *, char *, des_block * ); 64173412Skevlostatic int readcache( char *, char *, des_block * ); 65173412Skevlostatic void extractdeskey( MINT *, des_block * ); 66173412Skevlostatic int storesecretkey( uid_t, keybuf ); 67173412Skevlostatic keystatus pk_crypt( uid_t, char *, netobj *, des_block *, int); 6826234Swpaulstatic int nodefaultkeys = 0; 6926234Swpaul 7026234Swpaul 7126234Swpaul/* 7226234Swpaul * prohibit the nobody key on this machine k (the -d flag) 7326234Swpaul */ 7426234Swpaulvoid 7526234Swpaulpk_nodefaultkeys() 7626234Swpaul{ 7726234Swpaul nodefaultkeys = 1; 7826234Swpaul} 7926234Swpaul 8026234Swpaul/* 8126234Swpaul * Set the modulus for all our Diffie-Hellman operations 8226234Swpaul */ 8326234Swpaulvoid 8426234Swpaulsetmodulus(modx) 8526234Swpaul char *modx; 8626234Swpaul{ 87189092Sed MODULUS = mp_xtom(modx); 8826234Swpaul} 8926234Swpaul 9026234Swpaul/* 9126234Swpaul * Set the secretkey key for this uid 9226234Swpaul */ 9326234Swpaulkeystatus 9426234Swpaulpk_setkey(uid, skey) 9526234Swpaul uid_t uid; 9626234Swpaul keybuf skey; 9726234Swpaul{ 9826234Swpaul if (!storesecretkey(uid, skey)) { 9926234Swpaul return (KEY_SYSTEMERR); 10026234Swpaul } 10126234Swpaul return (KEY_SUCCESS); 10226234Swpaul} 10326234Swpaul 10426234Swpaul/* 10526234Swpaul * Encrypt the key using the public key associated with remote_name and the 10626234Swpaul * secret key associated with uid. 10726234Swpaul */ 10826234Swpaulkeystatus 10926234Swpaulpk_encrypt(uid, remote_name, remote_key, key) 11026234Swpaul uid_t uid; 11126234Swpaul char *remote_name; 11226234Swpaul netobj *remote_key; 11326234Swpaul des_block *key; 11426234Swpaul{ 11526234Swpaul return (pk_crypt(uid, remote_name, remote_key, key, DES_ENCRYPT)); 11626234Swpaul} 11726234Swpaul 11826234Swpaul/* 11926234Swpaul * Decrypt the key using the public key associated with remote_name and the 12026234Swpaul * secret key associated with uid. 12126234Swpaul */ 12226234Swpaulkeystatus 12326234Swpaulpk_decrypt(uid, remote_name, remote_key, key) 12426234Swpaul uid_t uid; 12526234Swpaul char *remote_name; 12626234Swpaul netobj *remote_key; 12726234Swpaul des_block *key; 12826234Swpaul{ 12926234Swpaul return (pk_crypt(uid, remote_name, remote_key, key, DES_DECRYPT)); 13026234Swpaul} 13126234Swpaul 132173412Skevlostatic int store_netname( uid_t, key_netstarg * ); 133173412Skevlostatic int fetch_netname( uid_t, key_netstarg * ); 13426234Swpaul 13526234Swpaulkeystatus 13626234Swpaulpk_netput(uid, netstore) 13726234Swpaul uid_t uid; 13826234Swpaul key_netstarg *netstore; 13926234Swpaul{ 14026234Swpaul if (!store_netname(uid, netstore)) { 14126234Swpaul return (KEY_SYSTEMERR); 14226234Swpaul } 14326234Swpaul return (KEY_SUCCESS); 14426234Swpaul} 14526234Swpaul 14626234Swpaulkeystatus 14726234Swpaulpk_netget(uid, netstore) 14826234Swpaul uid_t uid; 14926234Swpaul key_netstarg *netstore; 15026234Swpaul{ 15126234Swpaul if (!fetch_netname(uid, netstore)) { 15226234Swpaul return (KEY_SYSTEMERR); 15326234Swpaul } 15426234Swpaul return (KEY_SUCCESS); 15526234Swpaul} 15626234Swpaul 15726234Swpaul 15826234Swpaul/* 15926234Swpaul * Do the work of pk_encrypt && pk_decrypt 16026234Swpaul */ 16126234Swpaulstatic keystatus 16226234Swpaulpk_crypt(uid, remote_name, remote_key, key, mode) 16326234Swpaul uid_t uid; 16426234Swpaul char *remote_name; 16526234Swpaul netobj *remote_key; 16626234Swpaul des_block *key; 16726234Swpaul int mode; 16826234Swpaul{ 16926234Swpaul char *xsecret; 17026234Swpaul char xpublic[1024]; 17126234Swpaul char xsecret_hold[1024]; 17226234Swpaul des_block deskey; 17326234Swpaul int err; 17426234Swpaul MINT *public; 17526234Swpaul MINT *secret; 17626234Swpaul MINT *common; 17726234Swpaul char zero[8]; 17826234Swpaul 17926234Swpaul xsecret = fetchsecretkey(uid); 18026234Swpaul if (xsecret == NULL || xsecret[0] == 0) { 18126234Swpaul memset(zero, 0, sizeof (zero)); 18226234Swpaul xsecret = xsecret_hold; 18326234Swpaul if (nodefaultkeys) 18426234Swpaul return (KEY_NOSECRET); 18526234Swpaul 18626234Swpaul if (!getsecretkey("nobody", xsecret, zero) || xsecret[0] == 0) { 18726234Swpaul return (KEY_NOSECRET); 18826234Swpaul } 18926234Swpaul } 19026234Swpaul if (remote_key) { 19126234Swpaul memcpy(xpublic, remote_key->n_bytes, remote_key->n_len); 19226234Swpaul } else { 19326234Swpaul bzero((char *)&xpublic, sizeof(xpublic)); 19426234Swpaul if (!getpublickey(remote_name, xpublic)) { 19526234Swpaul if (nodefaultkeys || !getpublickey("nobody", xpublic)) 19626234Swpaul return (KEY_UNKNOWN); 19726234Swpaul } 19826234Swpaul } 19926234Swpaul 20026234Swpaul if (!readcache(xpublic, xsecret, &deskey)) { 201189092Sed public = mp_xtom(xpublic); 202189092Sed secret = mp_xtom(xsecret); 20326234Swpaul /* Sanity Check on public and private keys */ 20426234Swpaul if ((public == NULL) || (secret == NULL)) 20526234Swpaul return (KEY_SYSTEMERR); 20626234Swpaul 207189092Sed common = mp_itom(0); 208189092Sed mp_pow(public, secret, MODULUS, common); 20926234Swpaul extractdeskey(common, &deskey); 21026234Swpaul writecache(xpublic, xsecret, &deskey); 211189092Sed mp_mfree(secret); 212189092Sed mp_mfree(public); 213189092Sed mp_mfree(common); 21426234Swpaul } 21526234Swpaul err = ecb_crypt((char *)&deskey, (char *)key, sizeof (des_block), 21626234Swpaul DES_HW | mode); 21726234Swpaul if (DES_FAILED(err)) { 21826234Swpaul return (KEY_SYSTEMERR); 21926234Swpaul } 22026234Swpaul return (KEY_SUCCESS); 22126234Swpaul} 22226234Swpaul 22326234Swpaulkeystatus 22426234Swpaulpk_get_conv_key(uid, xpublic, result) 22526234Swpaul uid_t uid; 22626234Swpaul keybuf xpublic; 22726234Swpaul cryptkeyres *result; 22826234Swpaul{ 22926234Swpaul char *xsecret; 23026234Swpaul char xsecret_hold[1024]; 23126234Swpaul MINT *public; 23226234Swpaul MINT *secret; 23326234Swpaul MINT *common; 23426234Swpaul char zero[8]; 23526234Swpaul 23626234Swpaul 23726234Swpaul xsecret = fetchsecretkey(uid); 23826234Swpaul 23926234Swpaul if (xsecret == NULL || xsecret[0] == 0) { 24026234Swpaul memset(zero, 0, sizeof (zero)); 24126234Swpaul xsecret = xsecret_hold; 24226234Swpaul if (nodefaultkeys) 24326234Swpaul return (KEY_NOSECRET); 24426234Swpaul 24526234Swpaul if (!getsecretkey("nobody", xsecret, zero) || 24626234Swpaul xsecret[0] == 0) 24726234Swpaul return (KEY_NOSECRET); 24826234Swpaul } 24926234Swpaul 25026234Swpaul if (!readcache(xpublic, xsecret, &result->cryptkeyres_u.deskey)) { 251189092Sed public = mp_xtom(xpublic); 252189092Sed secret = mp_xtom(xsecret); 25326234Swpaul /* Sanity Check on public and private keys */ 25426234Swpaul if ((public == NULL) || (secret == NULL)) 25526234Swpaul return (KEY_SYSTEMERR); 25626234Swpaul 257189092Sed common = mp_itom(0); 258189092Sed mp_pow(public, secret, MODULUS, common); 25926234Swpaul extractdeskey(common, &result->cryptkeyres_u.deskey); 26026234Swpaul writecache(xpublic, xsecret, &result->cryptkeyres_u.deskey); 261189092Sed mp_mfree(secret); 262189092Sed mp_mfree(public); 263189092Sed mp_mfree(common); 26426234Swpaul } 26526234Swpaul 26626234Swpaul return (KEY_SUCCESS); 26726234Swpaul} 26826234Swpaul 26926234Swpaul/* 27026234Swpaul * Choose middle 64 bits of the common key to use as our des key, possibly 27126234Swpaul * overwriting the lower order bits by setting parity. 27226234Swpaul */ 27326234Swpaulstatic void 27426234Swpaulextractdeskey(ck, deskey) 27526234Swpaul MINT *ck; 27626234Swpaul des_block *deskey; 27726234Swpaul{ 27826234Swpaul MINT *a; 27926234Swpaul short r; 28026234Swpaul int i; 28126234Swpaul short base = (1 << 8); 28226234Swpaul char *k; 28326234Swpaul 284189092Sed a = mp_itom(0); 28526234Swpaul#ifdef SOLARIS_MP 28626234Swpaul _mp_move(ck, a); 28726234Swpaul#else 288189092Sed mp_move(ck, a); 28926234Swpaul#endif 29026234Swpaul for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) { 291189092Sed mp_sdiv(a, base, a, &r); 29226234Swpaul } 29326234Swpaul k = deskey->c; 29426234Swpaul for (i = 0; i < 8; i++) { 295189092Sed mp_sdiv(a, base, a, &r); 29626234Swpaul *k++ = r; 29726234Swpaul } 298189092Sed mp_mfree(a); 29926234Swpaul des_setparity((char *)deskey); 30026234Swpaul} 30126234Swpaul 30226234Swpaul/* 30326234Swpaul * Key storage management 30426234Swpaul */ 30526234Swpaul 30626234Swpaul#define KEY_ONLY 0 30726234Swpaul#define KEY_NAME 1 30826234Swpaulstruct secretkey_netname_list { 30926234Swpaul uid_t uid; 31026234Swpaul key_netstarg keynetdata; 31126234Swpaul u_char sc_flag; 31226234Swpaul struct secretkey_netname_list *next; 31326234Swpaul}; 31426234Swpaul 31526234Swpaul 31626234Swpaul 31726234Swpaulstatic struct secretkey_netname_list *g_secretkey_netname; 31826234Swpaul 31926234Swpaul/* 32026234Swpaul * Store the keys and netname for this uid 32126234Swpaul */ 32226234Swpaulstatic int 32326234Swpaulstore_netname(uid, netstore) 32426234Swpaul uid_t uid; 32526234Swpaul key_netstarg *netstore; 32626234Swpaul{ 32726234Swpaul struct secretkey_netname_list *new; 32826234Swpaul struct secretkey_netname_list **l; 32926234Swpaul 33026234Swpaul for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid; 33126234Swpaul l = &(*l)->next) { 33226234Swpaul } 33326234Swpaul if (*l == NULL) { 33426234Swpaul new = (struct secretkey_netname_list *)malloc(sizeof (*new)); 33526234Swpaul if (new == NULL) { 33626234Swpaul return (0); 33726234Swpaul } 33826234Swpaul new->uid = uid; 33926234Swpaul new->next = NULL; 34026234Swpaul *l = new; 34126234Swpaul } else { 34226234Swpaul new = *l; 34326234Swpaul if (new->keynetdata.st_netname) 34426234Swpaul (void) free (new->keynetdata.st_netname); 34526234Swpaul } 34626234Swpaul memcpy(new->keynetdata.st_priv_key, netstore->st_priv_key, 34726234Swpaul HEXKEYBYTES); 34826234Swpaul memcpy(new->keynetdata.st_pub_key, netstore->st_pub_key, HEXKEYBYTES); 34926234Swpaul 35026234Swpaul if (netstore->st_netname) 35126234Swpaul new->keynetdata.st_netname = strdup(netstore->st_netname); 35226234Swpaul else 35326234Swpaul new->keynetdata.st_netname = (char *)NULL; 35426234Swpaul new->sc_flag = KEY_NAME; 35526234Swpaul return (1); 35626234Swpaul 35726234Swpaul} 35826234Swpaul 35926234Swpaul/* 36026234Swpaul * Fetch the keys and netname for this uid 36126234Swpaul */ 36226234Swpaul 36326234Swpaulstatic int 36426234Swpaulfetch_netname(uid, key_netst) 36526234Swpaul uid_t uid; 36626234Swpaul struct key_netstarg *key_netst; 36726234Swpaul{ 36826234Swpaul struct secretkey_netname_list *l; 36926234Swpaul 37026234Swpaul for (l = g_secretkey_netname; l != NULL; l = l->next) { 37126234Swpaul if ((l->uid == uid) && (l->sc_flag == KEY_NAME)){ 37226234Swpaul 37326234Swpaul memcpy(key_netst->st_priv_key, 37426234Swpaul l->keynetdata.st_priv_key, HEXKEYBYTES); 37526234Swpaul 37626234Swpaul memcpy(key_netst->st_pub_key, 37726234Swpaul l->keynetdata.st_pub_key, HEXKEYBYTES); 37826234Swpaul 37926234Swpaul if (l->keynetdata.st_netname) 38026234Swpaul key_netst->st_netname = 38126234Swpaul strdup(l->keynetdata.st_netname); 38226234Swpaul else 38326234Swpaul key_netst->st_netname = NULL; 38426234Swpaul return (1); 38526234Swpaul } 38626234Swpaul } 38726234Swpaul 38826234Swpaul return (0); 38926234Swpaul} 39026234Swpaul 39126234Swpaulstatic char * 39226234Swpaulfetchsecretkey(uid) 39326234Swpaul uid_t uid; 39426234Swpaul{ 39526234Swpaul struct secretkey_netname_list *l; 39626234Swpaul 39726234Swpaul for (l = g_secretkey_netname; l != NULL; l = l->next) { 39826234Swpaul if (l->uid == uid) { 39926234Swpaul return (l->keynetdata.st_priv_key); 40026234Swpaul } 40126234Swpaul } 40226234Swpaul return (NULL); 40326234Swpaul} 40426234Swpaul 40526234Swpaul/* 40626234Swpaul * Store the secretkey for this uid 40726234Swpaul */ 40826234Swpaulstatic int 40926234Swpaulstoresecretkey(uid, key) 41026234Swpaul uid_t uid; 41126234Swpaul keybuf key; 41226234Swpaul{ 41326234Swpaul struct secretkey_netname_list *new; 41426234Swpaul struct secretkey_netname_list **l; 41526234Swpaul 41626234Swpaul for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid; 41726234Swpaul l = &(*l)->next) { 41826234Swpaul } 41926234Swpaul if (*l == NULL) { 42026234Swpaul new = (struct secretkey_netname_list *) malloc(sizeof (*new)); 42126234Swpaul if (new == NULL) { 42226234Swpaul return (0); 42326234Swpaul } 42426234Swpaul new->uid = uid; 42526234Swpaul new->sc_flag = KEY_ONLY; 42626234Swpaul memset(new->keynetdata.st_pub_key, 0, HEXKEYBYTES); 42726234Swpaul new->keynetdata.st_netname = NULL; 42826234Swpaul new->next = NULL; 42926234Swpaul *l = new; 43026234Swpaul } else { 43126234Swpaul new = *l; 43226234Swpaul } 43326234Swpaul 43426234Swpaul memcpy(new->keynetdata.st_priv_key, key, 43526234Swpaul HEXKEYBYTES); 43626234Swpaul return (1); 43726234Swpaul} 43826234Swpaul 43926234Swpaulstatic int 44026234Swpaulhexdigit(val) 44126234Swpaul int val; 44226234Swpaul{ 44326234Swpaul return ("0123456789abcdef"[val]); 44426234Swpaul} 44526234Swpaul 44626234Swpaulvoid 44726234Swpaulbin2hex(bin, hex, size) 44826234Swpaul unsigned char *bin; 44926234Swpaul unsigned char *hex; 45026234Swpaul int size; 45126234Swpaul{ 45226234Swpaul int i; 45326234Swpaul 45426234Swpaul for (i = 0; i < size; i++) { 45526234Swpaul *hex++ = hexdigit(*bin >> 4); 45626234Swpaul *hex++ = hexdigit(*bin++ & 0xf); 45726234Swpaul } 45826234Swpaul} 45926234Swpaul 46026234Swpaulstatic int 46126234Swpaulhexval(dig) 46226234Swpaul char dig; 46326234Swpaul{ 46426234Swpaul if ('0' <= dig && dig <= '9') { 46526234Swpaul return (dig - '0'); 46626234Swpaul } else if ('a' <= dig && dig <= 'f') { 46726234Swpaul return (dig - 'a' + 10); 46826234Swpaul } else if ('A' <= dig && dig <= 'F') { 46926234Swpaul return (dig - 'A' + 10); 47026234Swpaul } else { 47126234Swpaul return (-1); 47226234Swpaul } 47326234Swpaul} 47426234Swpaul 47526234Swpaulvoid 47626234Swpaulhex2bin(hex, bin, size) 47726234Swpaul unsigned char *hex; 47826234Swpaul unsigned char *bin; 47926234Swpaul int size; 48026234Swpaul{ 48126234Swpaul int i; 48226234Swpaul 48326234Swpaul for (i = 0; i < size; i++) { 48426234Swpaul *bin = hexval(*hex++) << 4; 48526234Swpaul *bin++ |= hexval(*hex++); 48626234Swpaul } 48726234Swpaul} 48826234Swpaul 48926234Swpaul/* 49026234Swpaul * Exponential caching management 49126234Swpaul */ 49226234Swpaulstruct cachekey_list { 49326234Swpaul keybuf secret; 49426234Swpaul keybuf public; 49526234Swpaul des_block deskey; 49626234Swpaul struct cachekey_list *next; 49726234Swpaul}; 49826234Swpaulstatic struct cachekey_list *g_cachedkeys; 49926234Swpaul 50026234Swpaul/* 50126234Swpaul * cache result of expensive multiple precision exponential operation 50226234Swpaul */ 50326234Swpaulstatic void 50426234Swpaulwritecache(pub, sec, deskey) 50526234Swpaul char *pub; 50626234Swpaul char *sec; 50726234Swpaul des_block *deskey; 50826234Swpaul{ 50926234Swpaul struct cachekey_list *new; 51026234Swpaul 51126234Swpaul new = (struct cachekey_list *) malloc(sizeof (struct cachekey_list)); 51226234Swpaul if (new == NULL) { 51326234Swpaul return; 51426234Swpaul } 51526234Swpaul memcpy(new->public, pub, sizeof (keybuf)); 51626234Swpaul memcpy(new->secret, sec, sizeof (keybuf)); 51726234Swpaul new->deskey = *deskey; 51826234Swpaul new->next = g_cachedkeys; 51926234Swpaul g_cachedkeys = new; 52026234Swpaul} 52126234Swpaul 52226234Swpaul/* 52326234Swpaul * Try to find the common key in the cache 52426234Swpaul */ 52526234Swpaulstatic int 52626234Swpaulreadcache(pub, sec, deskey) 52726234Swpaul char *pub; 52826234Swpaul char *sec; 52926234Swpaul des_block *deskey; 53026234Swpaul{ 53126234Swpaul struct cachekey_list *found; 53226234Swpaul register struct cachekey_list **l; 53326234Swpaul 53426234Swpaul#define cachehit(pub, sec, list) \ 53526234Swpaul (memcmp(pub, (list)->public, sizeof (keybuf)) == 0 && \ 53626234Swpaul memcmp(sec, (list)->secret, sizeof (keybuf)) == 0) 53726234Swpaul 53826234Swpaul for (l = &g_cachedkeys; (*l) != NULL && !cachehit(pub, sec, *l); 53926234Swpaul l = &(*l)->next) 54026234Swpaul ; 54126234Swpaul if ((*l) == NULL) { 54226234Swpaul return (0); 54326234Swpaul } 54426234Swpaul found = *l; 54526234Swpaul (*l) = (*l)->next; 54626234Swpaul found->next = g_cachedkeys; 54726234Swpaul g_cachedkeys = found; 54826234Swpaul *deskey = found->deskey; 54926234Swpaul return (1); 55026234Swpaul} 551