setkey.c revision 26235
1146773Ssam/* 2146773Ssam * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 3146773Ssam * unrestricted use provided that this legend is included on all tape 4146773Ssam * media and as a part of the software program in whole or part. Users 5146773Ssam * may copy or modify Sun RPC without charge, but are not authorized 6146773Ssam * to license or distribute it to anyone else except as part of a product or 7146773Ssam * program developed by the user. 8146773Ssam * 9146773Ssam * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 10146773Ssam * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 11146773Ssam * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 12146773Ssam * 13146773Ssam * Sun RPC is provided with no support and without any obligation on the 14146773Ssam * part of Sun Microsystems, Inc. to assist in its use, correction, 15146773Ssam * modification or enhancement. 16146773Ssam * 17146773Ssam * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 18146773Ssam * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 19146773Ssam * OR ANY PART THEREOF. 20190207Srpaulo * 21190207Srpaulo * In no event will Sun Microsystems, Inc. be liable for any lost revenue 22146773Ssam * or profits or other special, indirect and consequential damages, even if 23146773Ssam * Sun has been advised of the possibility of such damages. 24146773Ssam * 25146773Ssam * Sun Microsystems, Inc. 26190207Srpaulo * 2550 Garcia Avenue 27146773Ssam * Mountain View, California 94043 28146773Ssam */ 29146773Ssam 30146773Ssam#pragma ident "@(#)setkey.c 1.11 94/04/25 SMI" 31146773Ssam 32146773Ssam/* 33146773Ssam * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. 34146773Ssam */ 35146773Ssam 36146773Ssam/* 37146773Ssam * Do the real work of the keyserver. 38146773Ssam * Store secret keys. Compute common keys, 39190207Srpaulo * and use them to decrypt and encrypt DES keys. 40146773Ssam * Cache the common keys, so the expensive computation is avoided. 41146773Ssam */ 42146773Ssam#include <stdio.h> 43146773Ssam#include <stdlib.h> 44190207Srpaulo#include <unistd.h> 45190207Srpaulo#include <sys/types.h> 46190207Srpaulo#include <mp.h> 47190207Srpaulo#include <rpc/rpc.h> 48190207Srpaulo#include <rpc/key_prot.h> 49190207Srpaulo#include <rpc/des_crypt.h> 50190207Srpaulo#include <rpc/des.h> 51190207Srpaulo#include <sys/errno.h> 52190207Srpaulo#include <string.h> 53190207Srpaulo#include "keyserv.h" 54190207Srpaulo 55190207Srpaulostatic MINT *MODULUS; 56190207Srpaulostatic char *fetchsecretkey __P(( uid_t )); 57190207Srpaulostatic void writecache __P(( char *, char *, des_block * )); 58190207Srpaulostatic int readcache __P(( char *, char *, des_block * )); 59190207Srpaulostatic void extractdeskey __P (( MINT *, des_block * )); 60190207Srpaulostatic int storesecretkey __P(( uid_t, keybuf )); 61190207Srpaulostatic keystatus pk_crypt __P(( uid_t, char *, netobj *, des_block *, int)); 62190207Srpaulostatic int nodefaultkeys = 0; 63190207Srpaulo 64190207Srpaulo 65190207Srpaulo/* 66146773Ssam * prohibit the nobody key on this machine k (the -d flag) 67190207Srpaulo */ 68190207Srpaulovoid 69190207Srpaulopk_nodefaultkeys() 70146773Ssam{ 71146773Ssam nodefaultkeys = 1; 72190207Srpaulo} 73190207Srpaulo 74190207Srpaulo/* 75190207Srpaulo * Set the modulus for all our Diffie-Hellman operations 76190207Srpaulo */ 77190207Srpaulovoid 78190207Srpaulosetmodulus(modx) 79190207Srpaulo char *modx; 80190207Srpaulo{ 81190207Srpaulo MODULUS = xtom(modx); 82190207Srpaulo} 83190207Srpaulo 84190207Srpaulo/* 85190207Srpaulo * Set the secretkey key for this uid 86190207Srpaulo */ 87190207Srpaulokeystatus 88190207Srpaulopk_setkey(uid, skey) 89190207Srpaulo uid_t uid; 90190207Srpaulo keybuf skey; 91190207Srpaulo{ 92190207Srpaulo if (!storesecretkey(uid, skey)) { 93190207Srpaulo return (KEY_SYSTEMERR); 94190207Srpaulo } 95190207Srpaulo return (KEY_SUCCESS); 96190207Srpaulo} 97190207Srpaulo 98190207Srpaulo/* 99190207Srpaulo * Encrypt the key using the public key associated with remote_name and the 100190207Srpaulo * secret key associated with uid. 101190207Srpaulo */ 102190207Srpaulokeystatus 103190207Srpaulopk_encrypt(uid, remote_name, remote_key, key) 104190207Srpaulo uid_t uid; 105190207Srpaulo char *remote_name; 106190207Srpaulo netobj *remote_key; 107190207Srpaulo des_block *key; 108190207Srpaulo{ 109190207Srpaulo return (pk_crypt(uid, remote_name, remote_key, key, DES_ENCRYPT)); 110190207Srpaulo} 111190207Srpaulo 112190207Srpaulo/* 113190207Srpaulo * Decrypt the key using the public key associated with remote_name and the 114190207Srpaulo * secret key associated with uid. 115190207Srpaulo */ 116190207Srpaulokeystatus 117190207Srpaulopk_decrypt(uid, remote_name, remote_key, key) 118190207Srpaulo uid_t uid; 119190207Srpaulo char *remote_name; 120190207Srpaulo netobj *remote_key; 121190207Srpaulo des_block *key; 122190207Srpaulo{ 123190207Srpaulo return (pk_crypt(uid, remote_name, remote_key, key, DES_DECRYPT)); 124190207Srpaulo} 125190207Srpaulo 126190207Srpaulostatic int store_netname __P(( uid_t, key_netstarg * )); 127190207Srpaulostatic int fetch_netname __P(( uid_t, key_netstarg * )); 128190207Srpaulo 129190207Srpaulokeystatus 130190207Srpaulopk_netput(uid, netstore) 131190207Srpaulo uid_t uid; 132190207Srpaulo key_netstarg *netstore; 133190207Srpaulo{ 134190207Srpaulo if (!store_netname(uid, netstore)) { 135190207Srpaulo return (KEY_SYSTEMERR); 136190207Srpaulo } 137190207Srpaulo return (KEY_SUCCESS); 138190207Srpaulo} 139190207Srpaulo 140190207Srpaulokeystatus 141190207Srpaulopk_netget(uid, netstore) 142190207Srpaulo uid_t uid; 143190207Srpaulo key_netstarg *netstore; 144190207Srpaulo{ 145190207Srpaulo if (!fetch_netname(uid, netstore)) { 146190207Srpaulo return (KEY_SYSTEMERR); 147190207Srpaulo } 148190207Srpaulo return (KEY_SUCCESS); 149190207Srpaulo} 150190207Srpaulo 151190207Srpaulo 152190207Srpaulo/* 153190207Srpaulo * Do the work of pk_encrypt && pk_decrypt 154190207Srpaulo */ 155190207Srpaulostatic keystatus 156190207Srpaulopk_crypt(uid, remote_name, remote_key, key, mode) 157190207Srpaulo uid_t uid; 158146773Ssam char *remote_name; 159190207Srpaulo netobj *remote_key; 160146773Ssam des_block *key; 161146773Ssam int mode; 162190207Srpaulo{ 163190207Srpaulo char *xsecret; 164190207Srpaulo char xpublic[1024]; 165146773Ssam char xsecret_hold[1024]; 166190207Srpaulo des_block deskey; 167190207Srpaulo int err; 168190207Srpaulo MINT *public; 169190207Srpaulo MINT *secret; 170190207Srpaulo MINT *common; 171190207Srpaulo char zero[8]; 172190207Srpaulo 173190207Srpaulo xsecret = fetchsecretkey(uid); 174190207Srpaulo if (xsecret == NULL || xsecret[0] == 0) { 175146773Ssam memset(zero, 0, sizeof (zero)); 176190207Srpaulo xsecret = xsecret_hold; 177190207Srpaulo if (nodefaultkeys) 178190207Srpaulo return (KEY_NOSECRET); 179190207Srpaulo 180190207Srpaulo if (!getsecretkey("nobody", xsecret, zero) || xsecret[0] == 0) { 181190207Srpaulo return (KEY_NOSECRET); 182190207Srpaulo } 183190207Srpaulo } 184190207Srpaulo if (remote_key) { 185190207Srpaulo memcpy(xpublic, remote_key->n_bytes, remote_key->n_len); 186190207Srpaulo } else { 187190207Srpaulo bzero((char *)&xpublic, sizeof(xpublic)); 188190207Srpaulo if (!getpublickey(remote_name, xpublic)) { 189190207Srpaulo if (nodefaultkeys || !getpublickey("nobody", xpublic)) 190190207Srpaulo return (KEY_UNKNOWN); 191146773Ssam } 192190207Srpaulo } 193190207Srpaulo 194146773Ssam if (!readcache(xpublic, xsecret, &deskey)) { 195190207Srpaulo public = xtom(xpublic); 196190207Srpaulo secret = xtom(xsecret); 197190207Srpaulo /* Sanity Check on public and private keys */ 198190207Srpaulo if ((public == NULL) || (secret == NULL)) 199190207Srpaulo return (KEY_SYSTEMERR); 200190207Srpaulo 201190207Srpaulo common = itom(0); 202190207Srpaulo pow(public, secret, MODULUS, common); 203190207Srpaulo extractdeskey(common, &deskey); 204146773Ssam writecache(xpublic, xsecret, &deskey); 205190207Srpaulo mfree(secret); 206190207Srpaulo mfree(public); 207190207Srpaulo mfree(common); 208190207Srpaulo } 209190207Srpaulo err = ecb_crypt((char *)&deskey, (char *)key, sizeof (des_block), 210190207Srpaulo DES_HW | mode); 211190207Srpaulo if (DES_FAILED(err)) { 212190207Srpaulo return (KEY_SYSTEMERR); 213190207Srpaulo } 214190207Srpaulo return (KEY_SUCCESS); 215190207Srpaulo} 216190207Srpaulo 217190207Srpaulokeystatus 218190207Srpaulopk_get_conv_key(uid, xpublic, result) 219190207Srpaulo uid_t uid; 220190207Srpaulo keybuf xpublic; 221190207Srpaulo cryptkeyres *result; 222190207Srpaulo{ 223190207Srpaulo char *xsecret; 224190207Srpaulo char xsecret_hold[1024]; 225190207Srpaulo MINT *public; 226190207Srpaulo MINT *secret; 227190207Srpaulo MINT *common; 228190207Srpaulo char zero[8]; 229190207Srpaulo 230190207Srpaulo 231190207Srpaulo xsecret = fetchsecretkey(uid); 232190207Srpaulo 233190207Srpaulo if (xsecret == NULL || xsecret[0] == 0) { 234190207Srpaulo memset(zero, 0, sizeof (zero)); 235190207Srpaulo xsecret = xsecret_hold; 236190207Srpaulo if (nodefaultkeys) 237190207Srpaulo return (KEY_NOSECRET); 238190207Srpaulo 239190207Srpaulo if (!getsecretkey("nobody", xsecret, zero) || 240190207Srpaulo xsecret[0] == 0) 241190207Srpaulo return (KEY_NOSECRET); 242190207Srpaulo } 243190207Srpaulo 244190207Srpaulo if (!readcache(xpublic, xsecret, &result->cryptkeyres_u.deskey)) { 245190207Srpaulo public = xtom(xpublic); 246190207Srpaulo secret = xtom(xsecret); 247190207Srpaulo /* Sanity Check on public and private keys */ 248190207Srpaulo if ((public == NULL) || (secret == NULL)) 249190207Srpaulo return (KEY_SYSTEMERR); 250190207Srpaulo 251190207Srpaulo common = itom(0); 252190207Srpaulo pow(public, secret, MODULUS, common); 253190207Srpaulo extractdeskey(common, &result->cryptkeyres_u.deskey); 254190207Srpaulo writecache(xpublic, xsecret, &result->cryptkeyres_u.deskey); 255190207Srpaulo mfree(secret); 256190207Srpaulo mfree(public); 257190207Srpaulo mfree(common); 258190207Srpaulo } 259190207Srpaulo 260190207Srpaulo return (KEY_SUCCESS); 261190207Srpaulo} 262190207Srpaulo 263190207Srpaulo/* 264190207Srpaulo * Choose middle 64 bits of the common key to use as our des key, possibly 265190207Srpaulo * overwriting the lower order bits by setting parity. 266190207Srpaulo */ 267190207Srpaulostatic void 268190207Srpauloextractdeskey(ck, deskey) 269190207Srpaulo MINT *ck; 270190207Srpaulo des_block *deskey; 271190207Srpaulo{ 272190207Srpaulo MINT *a; 273190207Srpaulo short r; 274190207Srpaulo int i; 275190207Srpaulo short base = (1 << 8); 276190207Srpaulo char *k; 277190207Srpaulo 278190207Srpaulo a = itom(0); 279190207Srpaulo#ifdef SOLARIS_MP 280190207Srpaulo _mp_move(ck, a); 281190207Srpaulo#else 282190207Srpaulo move(ck, a); 283190207Srpaulo#endif 284190207Srpaulo for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) { 285190207Srpaulo sdiv(a, base, a, &r); 286190207Srpaulo } 287190207Srpaulo k = deskey->c; 288190207Srpaulo for (i = 0; i < 8; i++) { 289190207Srpaulo sdiv(a, base, a, &r); 290190207Srpaulo *k++ = r; 291190207Srpaulo } 292190207Srpaulo mfree(a); 293190207Srpaulo des_setparity((char *)deskey); 294190207Srpaulo} 295190207Srpaulo 296190207Srpaulo/* 297190207Srpaulo * Key storage management 298190207Srpaulo */ 299190207Srpaulo 300190207Srpaulo#define KEY_ONLY 0 301146773Ssam#define KEY_NAME 1 302146773Ssamstruct secretkey_netname_list { 303190207Srpaulo uid_t uid; 304190207Srpaulo key_netstarg keynetdata; 305190207Srpaulo u_char sc_flag; 306190207Srpaulo struct secretkey_netname_list *next; 307190207Srpaulo}; 308 309 310 311static struct secretkey_netname_list *g_secretkey_netname; 312 313/* 314 * Store the keys and netname for this uid 315 */ 316static int 317store_netname(uid, netstore) 318 uid_t uid; 319 key_netstarg *netstore; 320{ 321 struct secretkey_netname_list *new; 322 struct secretkey_netname_list **l; 323 324 for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid; 325 l = &(*l)->next) { 326 } 327 if (*l == NULL) { 328 new = (struct secretkey_netname_list *)malloc(sizeof (*new)); 329 if (new == NULL) { 330 return (0); 331 } 332 new->uid = uid; 333 new->next = NULL; 334 *l = new; 335 } else { 336 new = *l; 337 if (new->keynetdata.st_netname) 338 (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