setkey.c revision 26234
1139749Simp/* 2113584Ssimokawa * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 3103285Sikob * unrestricted use provided that this legend is included on all tape 4103285Sikob * media and as a part of the software program in whole or part. Users 5103285Sikob * may copy or modify Sun RPC without charge, but are not authorized 6103285Sikob * to license or distribute it to anyone else except as part of a product or 7103285Sikob * program developed by the user. 8103285Sikob * 9103285Sikob * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 10103285Sikob * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 11103285Sikob * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 12103285Sikob * 13103285Sikob * Sun RPC is provided with no support and without any obligation on the 14103285Sikob * part of Sun Microsystems, Inc. to assist in its use, correction, 15103285Sikob * modification or enhancement. 16103285Sikob * 17103285Sikob * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 18103285Sikob * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 19103285Sikob * OR ANY PART THEREOF. 20103285Sikob * 21103285Sikob * In no event will Sun Microsystems, Inc. be liable for any lost revenue 22103285Sikob * or profits or other special, indirect and consequential damages, even if 23103285Sikob * Sun has been advised of the possibility of such damages. 24103285Sikob * 25103285Sikob * Sun Microsystems, Inc. 26103285Sikob * 2550 Garcia Avenue 27103285Sikob * Mountain View, California 94043 28103285Sikob */ 29103285Sikob 30103285Sikob#pragma ident "@(#)setkey.c 1.11 94/04/25 SMI" 31103285Sikob 32103285Sikob/* 33103285Sikob * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. 34103285Sikob */ 35103285Sikob 36103285Sikob/* 37103285Sikob * Do the real work of the keyserver. 38127468Ssimokawa * Store secret keys. Compute common keys, 39127468Ssimokawa * and use them to decrypt and encrypt DES keys. 40127468Ssimokawa * Cache the common keys, so the expensive computation is avoided. 41127468Ssimokawa */ 42103285Sikob#include <stdio.h> 43103285Sikob#include <stdlib.h> 44103285Sikob#include <unistd.h> 45103285Sikob#include <sys/types.h> 46103285Sikob#include <mp.h> 47103285Sikob#include <rpc/rpc.h> 48103285Sikob#include <rpc/key_prot.h> 49113584Ssimokawa#include <rpc/des_crypt.h> 50170374Ssimokawa#include <rpc/des.h> 51170374Ssimokawa#include <sys/errno.h> 52113584Ssimokawa#include <string.h> 53103285Sikob#include "keyserv.h" 54103285Sikob 55169130Ssimokawastatic MINT *MODULUS; 56169130Ssimokawastatic char *fetchsecretkey __P(( uid_t )); 57103285Sikobstatic void writecache __P(( char *, char *, des_block * )); 58129585Sdfrstatic int readcache __P(( char *, char *, des_block * )); 59103285Sikobstatic void extractdeskey __P (( MINT *, des_block * )); 60129585Sdfrstatic int storesecretkey __P(( uid_t, keybuf )); 61129585Sdfrstatic keystatus pk_crypt __P(( uid_t, char *, netobj *, des_block *, int)); 62129585Sdfrstatic int nodefaultkeys = 0; 63129585Sdfr 64103285Sikob 65103285Sikob/* 66103285Sikob * prohibit the nobody key on this machine k (the -d flag) 67129585Sdfr */ 68103285Sikobvoid 69106810Ssimokawapk_nodefaultkeys() 70129585Sdfr{ 71103285Sikob nodefaultkeys = 1; 72103285Sikob} 73103285Sikob 74110193Ssimokawa/* 75103285Sikob * Set the modulus for all our Diffie-Hellman operations 76109645Ssimokawa */ 77103285Sikobvoid 78127468Ssimokawasetmodulus(modx) 79130585Sphk char *modx; 80103285Sikob{ 81103285Sikob MODULUS = xtom(modx); 82103285Sikob} 83109645Ssimokawa 84103285Sikob/* 85103285Sikob * Set the secretkey key for this uid 86103285Sikob */ 87109645Ssimokawakeystatus 88103285Sikobpk_setkey(uid, skey) 89103285Sikob uid_t uid; 90103285Sikob keybuf skey; 91124169Ssimokawa{ 92124169Ssimokawa if (!storesecretkey(uid, skey)) { 93103285Sikob return (KEY_SYSTEMERR); 94103285Sikob } 95103285Sikob return (KEY_SUCCESS); 96103285Sikob} 97103285Sikob 98103285Sikob/* 99103285Sikob * Encrypt the key using the public key associated with remote_name and the 100103285Sikob * secret key associated with uid. 101103285Sikob */ 102103285Sikobkeystatus 103170374Ssimokawapk_encrypt(uid, remote_name, remote_key, key) 104103285Sikob uid_t uid; 105103285Sikob char *remote_name; 106103285Sikob netobj *remote_key; 107103285Sikob des_block *key; 108103285Sikob{ 109129585Sdfr return (pk_crypt(uid, remote_name, remote_key, key, DES_ENCRYPT)); 110103285Sikob} 111103285Sikob 112103285Sikob/* 113103285Sikob * Decrypt the key using the public key associated with remote_name and the 114103285Sikob * secret key associated with uid. 115103285Sikob */ 116103285Sikobkeystatus 117103285Sikobpk_decrypt(uid, remote_name, remote_key, key) 118103285Sikob uid_t uid; 119129585Sdfr char *remote_name; 120169806Ssimokawa netobj *remote_key; 121116978Ssimokawa des_block *key; 122103285Sikob{ 123103285Sikob return (pk_crypt(uid, remote_name, remote_key, key, DES_DECRYPT)); 124103285Sikob} 125103285Sikob 126103285Sikobstatic int store_netname __P(( uid_t, key_netstarg * )); 127103285Sikobstatic int fetch_netname __P(( uid_t, key_netstarg * )); 128103285Sikob 129103285Sikobkeystatus 130103285Sikobpk_netput(uid, netstore) 131103285Sikob uid_t uid; 132109814Ssimokawa key_netstarg *netstore; 133103285Sikob{ 134103285Sikob if (!store_netname(uid, netstore)) { 135169130Ssimokawa return (KEY_SYSTEMERR); 136171457Ssimokawa } 137171513Ssimokawa return (KEY_SUCCESS); 138103285Sikob} 139110193Ssimokawa 140103285Sikobkeystatus 141103285Sikobpk_netget(uid, netstore) 142129585Sdfr uid_t uid; 143103285Sikob key_netstarg *netstore; 144129585Sdfr{ 145116376Ssimokawa if (!fetch_netname(uid, netstore)) { 146116376Ssimokawa return (KEY_SYSTEMERR); 147116376Ssimokawa } 148103285Sikob return (KEY_SUCCESS); 149103285Sikob} 150108853Ssimokawa 151110193Ssimokawa 152110193Ssimokawa/* 153170374Ssimokawa * Do the work of pk_encrypt && pk_decrypt 154129585Sdfr */ 155124169Ssimokawastatic keystatus 156129585Sdfrpk_crypt(uid, remote_name, remote_key, key, mode) 157130585Sphk uid_t uid; 158124169Ssimokawa char *remote_name; 159124169Ssimokawa netobj *remote_key; 160124169Ssimokawa des_block *key; 161124169Ssimokawa int mode; 162124169Ssimokawa{ 163124169Ssimokawa char *xsecret; 164124169Ssimokawa char xpublic[1024]; 165129585Sdfr char xsecret_hold[1024]; 166129585Sdfr des_block deskey; 167103285Sikob int err; 168113584Ssimokawa MINT *public; 169170374Ssimokawa MINT *secret; 170170374Ssimokawa MINT *common; 171170374Ssimokawa char zero[8]; 172170374Ssimokawa 173103285Sikob xsecret = fetchsecretkey(uid); 174103285Sikob if (xsecret == NULL || xsecret[0] == 0) { 175103285Sikob memset(zero, 0, sizeof (zero)); 176170374Ssimokawa xsecret = xsecret_hold; 177170374Ssimokawa if (nodefaultkeys) 178170374Ssimokawa return (KEY_NOSECRET); 179170374Ssimokawa 180170374Ssimokawa if (!getsecretkey("nobody", xsecret, zero) || xsecret[0] == 0) { 181109645Ssimokawa return (KEY_NOSECRET); 182109645Ssimokawa } 183109645Ssimokawa } 184109645Ssimokawa if (remote_key) { 185109645Ssimokawa memcpy(xpublic, remote_key->n_bytes, remote_key->n_len); 186109645Ssimokawa } else { 187109645Ssimokawa bzero((char *)&xpublic, sizeof(xpublic)); 188109645Ssimokawa if (!getpublickey(remote_name, xpublic)) { 189109645Ssimokawa if (nodefaultkeys || !getpublickey("nobody", xpublic)) 190109645Ssimokawa return (KEY_UNKNOWN); 191109645Ssimokawa } 192109645Ssimokawa } 193109645Ssimokawa 194109645Ssimokawa if (!readcache(xpublic, xsecret, &deskey)) { 195124169Ssimokawa public = xtom(xpublic); 196118293Ssimokawa secret = xtom(xsecret); 197169130Ssimokawa /* Sanity Check on public and private keys */ 198109645Ssimokawa if ((public == NULL) || (secret == NULL)) 199109645Ssimokawa return (KEY_SYSTEMERR); 200109645Ssimokawa 201113584Ssimokawa common = itom(0); 202109645Ssimokawa pow(public, secret, MODULUS, common); 203109645Ssimokawa extractdeskey(common, &deskey); 204109645Ssimokawa writecache(xpublic, xsecret, &deskey); 205109645Ssimokawa mfree(secret); 206109645Ssimokawa mfree(public); 207109890Ssimokawa mfree(common); 208109645Ssimokawa } 209109645Ssimokawa err = ecb_crypt((char *)&deskey, (char *)key, sizeof (des_block), 210109645Ssimokawa DES_HW | mode); 211124169Ssimokawa if (DES_FAILED(err)) { 212109645Ssimokawa return (KEY_SYSTEMERR); 213109645Ssimokawa } 214109645Ssimokawa return (KEY_SUCCESS); 215113584Ssimokawa} 216111942Ssimokawa 217109645Ssimokawakeystatus 218109645Ssimokawapk_get_conv_key(uid, xpublic, result) 219109645Ssimokawa uid_t uid; 220111942Ssimokawa keybuf xpublic; 221109645Ssimokawa cryptkeyres *result; 222109645Ssimokawa{ 223109645Ssimokawa char *xsecret; 224120660Ssimokawa char xsecret_hold[1024]; 225120660Ssimokawa MINT *public; 226169130Ssimokawa MINT *secret; 227109645Ssimokawa MINT *common; 228109645Ssimokawa char zero[8]; 229169130Ssimokawa 230109645Ssimokawa 231109645Ssimokawa xsecret = fetchsecretkey(uid); 232103285Sikob 233103285Sikob if (xsecret == NULL || xsecret[0] == 0) { 234103285Sikob memset(zero, 0, sizeof (zero)); 235103285Sikob xsecret = xsecret_hold; 236110577Ssimokawa if (nodefaultkeys) 237113584Ssimokawa return (KEY_NOSECRET); 238170374Ssimokawa 239170374Ssimokawa if (!getsecretkey("nobody", xsecret, zero) || 240170374Ssimokawa xsecret[0] == 0) 241170374Ssimokawa return (KEY_NOSECRET); 242170374Ssimokawa } 243170374Ssimokawa 244170374Ssimokawa if (!readcache(xpublic, xsecret, &result->cryptkeyres_u.deskey)) { 245170374Ssimokawa public = xtom(xpublic); 246170374Ssimokawa secret = xtom(xsecret); 247170374Ssimokawa /* Sanity Check on public and private keys */ 248169119Ssimokawa if ((public == NULL) || (secret == NULL)) 249167632Ssimokawa return (KEY_SYSTEMERR); 250103285Sikob 251120660Ssimokawa common = itom(0); 252129585Sdfr pow(public, secret, MODULUS, common); 253129585Sdfr extractdeskey(common, &result->cryptkeyres_u.deskey); 254129585Sdfr writecache(xpublic, xsecret, &result->cryptkeyres_u.deskey); 255103285Sikob mfree(secret); 256103285Sikob mfree(public); 257103285Sikob mfree(common); 258169119Ssimokawa } 259110269Ssimokawa 260103285Sikob return (KEY_SUCCESS); 261120660Ssimokawa} 262120660Ssimokawa 263120660Ssimokawa/* 264120660Ssimokawa * Choose middle 64 bits of the common key to use as our des key, possibly 265120660Ssimokawa * overwriting the lower order bits by setting parity. 266120660Ssimokawa */ 267129585Sdfrstatic void 268120660Ssimokawaextractdeskey(ck, deskey) 269120660Ssimokawa MINT *ck; 270129585Sdfr des_block *deskey; 271124169Ssimokawa{ 272124169Ssimokawa MINT *a; 273124169Ssimokawa short r; 274124169Ssimokawa int i; 275124169Ssimokawa short base = (1 << 8); 276124169Ssimokawa char *k; 277124169Ssimokawa 278124169Ssimokawa a = itom(0); 279124169Ssimokawa#ifdef SOLARIS_MP 280124169Ssimokawa _mp_move(ck, a); 281124169Ssimokawa#else 282169130Ssimokawa move(ck, a); 283169130Ssimokawa#endif 284169130Ssimokawa for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) { 285124169Ssimokawa sdiv(a, base, a, &r); 286169117Ssimokawa } 287129585Sdfr k = deskey->c; 288124169Ssimokawa for (i = 0; i < 8; i++) { 289124169Ssimokawa sdiv(a, base, a, &r); 290170374Ssimokawa *k++ = r; 291170374Ssimokawa } 292124169Ssimokawa mfree(a); 293124169Ssimokawa des_setparity((char *)deskey); 294124169Ssimokawa} 295129585Sdfr 296124169Ssimokawa/* 297124169Ssimokawa * Key storage management 298124169Ssimokawa */ 299148868Srwatson 300170374Ssimokawa#define KEY_ONLY 0 301103285Sikob#define KEY_NAME 1 302103285Sikobstruct secretkey_netname_list { 303103285Sikob uid_t uid; 304170400Ssimokawa key_netstarg keynetdata; 305103285Sikob u_char sc_flag; 306127468Ssimokawa struct secretkey_netname_list *next; 307127468Ssimokawa}; 308127468Ssimokawa 309103285Sikob 310127468Ssimokawa 311103285Sikobstatic struct secretkey_netname_list *g_secretkey_netname; 312127468Ssimokawa 313127468Ssimokawa/* 314127468Ssimokawa * Store the keys and netname for this uid 315170374Ssimokawa */ 316111615Ssimokawastatic int 317111615Ssimokawastore_netname(uid, netstore) 318127468Ssimokawa uid_t uid; 319120660Ssimokawa key_netstarg *netstore; 320120660Ssimokawa{ 321120660Ssimokawa struct secretkey_netname_list *new; 322120660Ssimokawa struct secretkey_netname_list **l; 323120660Ssimokawa 324120660Ssimokawa for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid; 325120660Ssimokawa l = &(*l)->next) { 326120660Ssimokawa } 327120660Ssimokawa if (*l == NULL) { 328120660Ssimokawa new = (struct secretkey_netname_list *)malloc(sizeof (*new)); 329120660Ssimokawa if (new == NULL) { 330120660Ssimokawa return (0); 331120660Ssimokawa } 332120660Ssimokawa new->uid = uid; 333120660Ssimokawa new->next = NULL; 334121780Ssimokawa *l = new; 335120660Ssimokawa } else { 336120660Ssimokawa new = *l; 337110195Ssimokawa if (new->keynetdata.st_netname) 338110269Ssimokawa (void) free (new->keynetdata.st_netname); 339 } 340 memcpy(new->keynetdata.st_priv_key, netstore->st_priv_key, 341 HEXKEYBYTES); 342 memcpy(new->keynetdata.st_pub_key, netstore->st_pub_key, HEXKEYBYTES); 343 344 if (netstore->st_netname) 345 new->keynetdata.st_netname = strdup(netstore->st_netname); 346 else 347 new->keynetdata.st_netname = (char *)NULL; 348 new->sc_flag = KEY_NAME; 349 return (1); 350 351} 352 353/* 354 * Fetch the keys and netname for this uid 355 */ 356 357static int 358fetch_netname(uid, key_netst) 359 uid_t uid; 360 struct key_netstarg *key_netst; 361{ 362 struct secretkey_netname_list *l; 363 364 for (l = g_secretkey_netname; l != NULL; l = l->next) { 365 if ((l->uid == uid) && (l->sc_flag == KEY_NAME)){ 366 367 memcpy(key_netst->st_priv_key, 368 l->keynetdata.st_priv_key, HEXKEYBYTES); 369 370 memcpy(key_netst->st_pub_key, 371 l->keynetdata.st_pub_key, HEXKEYBYTES); 372 373 if (l->keynetdata.st_netname) 374 key_netst->st_netname = 375 strdup(l->keynetdata.st_netname); 376 else 377 key_netst->st_netname = NULL; 378 return (1); 379 } 380 } 381 382 return (0); 383} 384 385static char * 386fetchsecretkey(uid) 387 uid_t uid; 388{ 389 struct secretkey_netname_list *l; 390 391 for (l = g_secretkey_netname; l != NULL; l = l->next) { 392 if (l->uid == uid) { 393 return (l->keynetdata.st_priv_key); 394 } 395 } 396 return (NULL); 397} 398 399/* 400 * Store the secretkey for this uid 401 */ 402static int 403storesecretkey(uid, key) 404 uid_t uid; 405 keybuf key; 406{ 407 struct secretkey_netname_list *new; 408 struct secretkey_netname_list **l; 409 410 for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid; 411 l = &(*l)->next) { 412 } 413 if (*l == NULL) { 414 new = (struct secretkey_netname_list *) malloc(sizeof (*new)); 415 if (new == NULL) { 416 return (0); 417 } 418 new->uid = uid; 419 new->sc_flag = KEY_ONLY; 420 memset(new->keynetdata.st_pub_key, 0, HEXKEYBYTES); 421 new->keynetdata.st_netname = NULL; 422 new->next = NULL; 423 *l = new; 424 } else { 425 new = *l; 426 } 427 428 memcpy(new->keynetdata.st_priv_key, key, 429 HEXKEYBYTES); 430 return (1); 431} 432 433static int 434hexdigit(val) 435 int val; 436{ 437 return ("0123456789abcdef"[val]); 438} 439 440void 441bin2hex(bin, hex, size) 442 unsigned char *bin; 443 unsigned char *hex; 444 int size; 445{ 446 int i; 447 448 for (i = 0; i < size; i++) { 449 *hex++ = hexdigit(*bin >> 4); 450 *hex++ = hexdigit(*bin++ & 0xf); 451 } 452} 453 454static int 455hexval(dig) 456 char dig; 457{ 458 if ('0' <= dig && dig <= '9') { 459 return (dig - '0'); 460 } else if ('a' <= dig && dig <= 'f') { 461 return (dig - 'a' + 10); 462 } else if ('A' <= dig && dig <= 'F') { 463 return (dig - 'A' + 10); 464 } else { 465 return (-1); 466 } 467} 468 469void 470hex2bin(hex, bin, size) 471 unsigned char *hex; 472 unsigned char *bin; 473 int size; 474{ 475 int i; 476 477 for (i = 0; i < size; i++) { 478 *bin = hexval(*hex++) << 4; 479 *bin++ |= hexval(*hex++); 480 } 481} 482 483/* 484 * Exponential caching management 485 */ 486struct cachekey_list { 487 keybuf secret; 488 keybuf public; 489 des_block deskey; 490 struct cachekey_list *next; 491}; 492static struct cachekey_list *g_cachedkeys; 493 494/* 495 * cache result of expensive multiple precision exponential operation 496 */ 497static void 498writecache(pub, sec, deskey) 499 char *pub; 500 char *sec; 501 des_block *deskey; 502{ 503 struct cachekey_list *new; 504 505 new = (struct cachekey_list *) malloc(sizeof (struct cachekey_list)); 506 if (new == NULL) { 507 return; 508 } 509 memcpy(new->public, pub, sizeof (keybuf)); 510 memcpy(new->secret, sec, sizeof (keybuf)); 511 new->deskey = *deskey; 512 new->next = g_cachedkeys; 513 g_cachedkeys = new; 514} 515 516/* 517 * Try to find the common key in the cache 518 */ 519static int 520readcache(pub, sec, deskey) 521 char *pub; 522 char *sec; 523 des_block *deskey; 524{ 525 struct cachekey_list *found; 526 register struct cachekey_list **l; 527 528#define cachehit(pub, sec, list) \ 529 (memcmp(pub, (list)->public, sizeof (keybuf)) == 0 && \ 530 memcmp(sec, (list)->secret, sizeof (keybuf)) == 0) 531 532 for (l = &g_cachedkeys; (*l) != NULL && !cachehit(pub, sec, *l); 533 l = &(*l)->next) 534 ; 535 if ((*l) == NULL) { 536 return (0); 537 } 538 found = *l; 539 (*l) = (*l)->next; 540 found->next = g_cachedkeys; 541 g_cachedkeys = found; 542 *deskey = found->deskey; 543 return (1); 544} 545