1 /* 2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 3 * unrestricted use provided that this legend is included on all tape 4 * media and as a part of the software program in whole or part. Users 5 * may copy or modify Sun RPC without charge, but are not authorized 6 * to license or distribute it to anyone else except as part of a product or 7 * program developed by the user. 8 * 9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 12 * 13 * Sun RPC is provided with no support and without any obligation on the 14 * part of Sun Microsystems, Inc. to assist in its use, correction, 15 * modification or enhancement. 16 * 17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 19 * OR ANY PART THEREOF. 20 * 21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 22 * or profits or other special, indirect and consequential damages, even if 23 * Sun has been advised of the possibility of such damages. 24 * 25 * Sun Microsystems, Inc. 26 * 2550 Garcia Avenue 27 * Mountain View, California 94043 28 */ 29 30 #ifndef lint 31 #if 0 32 static char sccsid[] = "@(#)setkey.c 1.11 94/04/25 SMI"; 33 #endif 34 #endif /* not lint */ 35 36 /* 37 * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. 38 */ 39 40 /* 41 * Do the real work of the keyserver. 42 * Store secret keys. Compute common keys, 43 * and use them to decrypt and encrypt DES keys. 44 * Cache the common keys, so the expensive computation is avoided. 45 */ 46 #include <mp.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <unistd.h> 51 #include <sys/types.h> 52 #include <rpc/rpc.h> 53 #include <rpc/key_prot.h> 54 #include <rpc/des_crypt.h> 55 #include <rpc/des.h> 56 #include <sys/errno.h> 57 #include "keyserv.h" 58 59 static MINT *MODULUS; 60 static char *fetchsecretkey( uid_t ); 61 static void writecache( char *, char *, des_block * ); 62 static int readcache( char *, char *, des_block * ); 63 static void extractdeskey( MINT *, des_block * ); 64 static int storesecretkey( uid_t, keybuf ); 65 static keystatus pk_crypt( uid_t, char *, netobj *, des_block *, int); 66 static int nodefaultkeys = 0; 67 68 69 /* 70 * prohibit the nobody key on this machine k (the -d flag) 71 */ 72 void 73 pk_nodefaultkeys(void) 74 { 75 nodefaultkeys = 1; 76 } 77 78 /* 79 * Set the modulus for all our Diffie-Hellman operations 80 */ 81 void 82 setmodulus(char *modx) 83 { 84 MODULUS = mp_xtom(modx); 85 } 86 87 /* 88 * Set the secretkey key for this uid 89 */ 90 keystatus 91 pk_setkey(uid_t uid, keybuf skey) 92 { 93 if (!storesecretkey(uid, skey)) { 94 return (KEY_SYSTEMERR); 95 } 96 return (KEY_SUCCESS); 97 } 98 99 /* 100 * Encrypt the key using the public key associated with remote_name and the 101 * secret key associated with uid. 102 */ 103 keystatus 104 pk_encrypt(uid_t uid, char *remote_name, netobj *remote_key, des_block *key) 105 { 106 return (pk_crypt(uid, remote_name, remote_key, key, DES_ENCRYPT)); 107 } 108 109 /* 110 * Decrypt the key using the public key associated with remote_name and the 111 * secret key associated with uid. 112 */ 113 keystatus 114 pk_decrypt(uid_t uid, char *remote_name, netobj *remote_key, des_block *key) 115 { 116 return (pk_crypt(uid, remote_name, remote_key, key, DES_DECRYPT)); 117 } 118 119 static int store_netname( uid_t, key_netstarg * ); 120 static int fetch_netname( uid_t, key_netstarg * ); 121 122 keystatus 123 pk_netput(uid_t uid, key_netstarg *netstore) 124 { 125 if (!store_netname(uid, netstore)) { 126 return (KEY_SYSTEMERR); 127 } 128 return (KEY_SUCCESS); 129 } 130 131 keystatus 132 pk_netget(uid_t uid, key_netstarg *netstore) 133 { 134 if (!fetch_netname(uid, netstore)) { 135 return (KEY_SYSTEMERR); 136 } 137 return (KEY_SUCCESS); 138 } 139 140 141 /* 142 * Do the work of pk_encrypt && pk_decrypt 143 */ 144 static keystatus 145 pk_crypt(uid_t uid, char *remote_name, netobj *remote_key, des_block *key, 146 int mode) 147 { 148 char *xsecret; 149 char xpublic[1024]; 150 char xsecret_hold[1024]; 151 des_block deskey; 152 int err; 153 MINT *public; 154 MINT *secret; 155 MINT *common; 156 char zero[8]; 157 158 xsecret = fetchsecretkey(uid); 159 if (xsecret == NULL || xsecret[0] == 0) { 160 memset(zero, 0, sizeof (zero)); 161 xsecret = xsecret_hold; 162 if (nodefaultkeys) 163 return (KEY_NOSECRET); 164 165 if (!getsecretkey("nobody", xsecret, zero) || xsecret[0] == 0) { 166 return (KEY_NOSECRET); 167 } 168 } 169 if (remote_key) { 170 memcpy(xpublic, remote_key->n_bytes, remote_key->n_len); 171 } else { 172 bzero((char *)&xpublic, sizeof(xpublic)); 173 if (!getpublickey(remote_name, xpublic)) { 174 if (nodefaultkeys || !getpublickey("nobody", xpublic)) 175 return (KEY_UNKNOWN); 176 } 177 } 178 179 if (!readcache(xpublic, xsecret, &deskey)) { 180 public = mp_xtom(xpublic); 181 secret = mp_xtom(xsecret); 182 /* Sanity Check on public and private keys */ 183 if ((public == NULL) || (secret == NULL)) 184 return (KEY_SYSTEMERR); 185 186 common = mp_itom(0); 187 mp_pow(public, secret, MODULUS, common); 188 extractdeskey(common, &deskey); 189 writecache(xpublic, xsecret, &deskey); 190 mp_mfree(secret); 191 mp_mfree(public); 192 mp_mfree(common); 193 } 194 err = ecb_crypt((char *)&deskey, (char *)key, sizeof (des_block), 195 DES_HW | mode); 196 if (DES_FAILED(err)) { 197 return (KEY_SYSTEMERR); 198 } 199 return (KEY_SUCCESS); 200 } 201 202 keystatus 203 pk_get_conv_key(uid_t uid, keybuf xpublic, cryptkeyres *result) 204 { 205 char *xsecret; 206 char xsecret_hold[1024]; 207 MINT *public; 208 MINT *secret; 209 MINT *common; 210 char zero[8]; 211 212 213 xsecret = fetchsecretkey(uid); 214 215 if (xsecret == NULL || xsecret[0] == 0) { 216 memset(zero, 0, sizeof (zero)); 217 xsecret = xsecret_hold; 218 if (nodefaultkeys) 219 return (KEY_NOSECRET); 220 221 if (!getsecretkey("nobody", xsecret, zero) || 222 xsecret[0] == 0) 223 return (KEY_NOSECRET); 224 } 225 226 if (!readcache(xpublic, xsecret, &result->cryptkeyres_u.deskey)) { 227 public = mp_xtom(xpublic); 228 secret = mp_xtom(xsecret); 229 /* Sanity Check on public and private keys */ 230 if ((public == NULL) || (secret == NULL)) 231 return (KEY_SYSTEMERR); 232 233 common = mp_itom(0); 234 mp_pow(public, secret, MODULUS, common); 235 extractdeskey(common, &result->cryptkeyres_u.deskey); 236 writecache(xpublic, xsecret, &result->cryptkeyres_u.deskey); 237 mp_mfree(secret); 238 mp_mfree(public); 239 mp_mfree(common); 240 } 241 242 return (KEY_SUCCESS); 243 } 244 245 /* 246 * Choose middle 64 bits of the common key to use as our des key, possibly 247 * overwriting the lower order bits by setting parity. 248 */ 249 static void 250 extractdeskey(MINT *ck, des_block *deskey) 251 { 252 MINT *a; 253 short r; 254 int i; 255 short base = (1 << 8); 256 char *k; 257 258 a = mp_itom(0); 259 #ifdef SOLARIS_MP 260 _mp_move(ck, a); 261 #else 262 mp_move(ck, a); 263 #endif 264 for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) { 265 mp_sdiv(a, base, a, &r); 266 } 267 k = deskey->c; 268 for (i = 0; i < 8; i++) { 269 mp_sdiv(a, base, a, &r); 270 *k++ = r; 271 } 272 mp_mfree(a); 273 des_setparity((char *)deskey); 274 } 275 276 /* 277 * Key storage management 278 */ 279 280 #define KEY_ONLY 0 281 #define KEY_NAME 1 282 struct secretkey_netname_list { 283 uid_t uid; 284 key_netstarg keynetdata; 285 u_char sc_flag; 286 struct secretkey_netname_list *next; 287 }; 288 289 290 291 static struct secretkey_netname_list *g_secretkey_netname; 292 293 /* 294 * Store the keys and netname for this uid 295 */ 296 static int 297 store_netname(uid_t uid, key_netstarg *netstore) 298 { 299 struct secretkey_netname_list *new; 300 struct secretkey_netname_list **l; 301 302 for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid; 303 l = &(*l)->next) { 304 } 305 if (*l == NULL) { 306 new = (struct secretkey_netname_list *)malloc(sizeof (*new)); 307 if (new == NULL) { 308 return (0); 309 } 310 new->uid = uid; 311 new->next = NULL; 312 *l = new; 313 } else { 314 new = *l; 315 if (new->keynetdata.st_netname) 316 (void) free (new->keynetdata.st_netname); 317 } 318 memcpy(new->keynetdata.st_priv_key, netstore->st_priv_key, 319 HEXKEYBYTES); 320 memcpy(new->keynetdata.st_pub_key, netstore->st_pub_key, HEXKEYBYTES); 321 322 if (netstore->st_netname) 323 new->keynetdata.st_netname = strdup(netstore->st_netname); 324 else 325 new->keynetdata.st_netname = (char *)NULL; 326 new->sc_flag = KEY_NAME; 327 return (1); 328 329 } 330 331 /* 332 * Fetch the keys and netname for this uid 333 */ 334 335 static int 336 fetch_netname(uid_t uid, struct key_netstarg *key_netst) 337 { 338 struct secretkey_netname_list *l; 339 340 for (l = g_secretkey_netname; l != NULL; l = l->next) { 341 if ((l->uid == uid) && (l->sc_flag == KEY_NAME)){ 342 343 memcpy(key_netst->st_priv_key, 344 l->keynetdata.st_priv_key, HEXKEYBYTES); 345 346 memcpy(key_netst->st_pub_key, 347 l->keynetdata.st_pub_key, HEXKEYBYTES); 348 349 if (l->keynetdata.st_netname) 350 key_netst->st_netname = 351 strdup(l->keynetdata.st_netname); 352 else 353 key_netst->st_netname = NULL; 354 return (1); 355 } 356 } 357 358 return (0); 359 } 360 361 static char * 362 fetchsecretkey(uid_t uid) 363 { 364 struct secretkey_netname_list *l; 365 366 for (l = g_secretkey_netname; l != NULL; l = l->next) { 367 if (l->uid == uid) { 368 return (l->keynetdata.st_priv_key); 369 } 370 } 371 return (NULL); 372 } 373 374 /* 375 * Store the secretkey for this uid 376 */ 377 static int 378 storesecretkey(uid_t uid, keybuf key) 379 { 380 struct secretkey_netname_list *new; 381 struct secretkey_netname_list **l; 382 383 for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid; 384 l = &(*l)->next) { 385 } 386 if (*l == NULL) { 387 new = (struct secretkey_netname_list *) malloc(sizeof (*new)); 388 if (new == NULL) { 389 return (0); 390 } 391 new->uid = uid; 392 new->sc_flag = KEY_ONLY; 393 memset(new->keynetdata.st_pub_key, 0, HEXKEYBYTES); 394 new->keynetdata.st_netname = NULL; 395 new->next = NULL; 396 *l = new; 397 } else { 398 new = *l; 399 } 400 401 memcpy(new->keynetdata.st_priv_key, key, 402 HEXKEYBYTES); 403 return (1); 404 } 405 406 static int 407 hexdigit(int val) 408 { 409 return ("0123456789abcdef"[val]); 410 } 411 412 void 413 bin2hex(unsigned char *bin, unsigned char *hex, int size) 414 { 415 int i; 416 417 for (i = 0; i < size; i++) { 418 *hex++ = hexdigit(*bin >> 4); 419 *hex++ = hexdigit(*bin++ & 0xf); 420 } 421 } 422 423 static int 424 hexval(char dig) 425 { 426 if ('0' <= dig && dig <= '9') { 427 return (dig - '0'); 428 } else if ('a' <= dig && dig <= 'f') { 429 return (dig - 'a' + 10); 430 } else if ('A' <= dig && dig <= 'F') { 431 return (dig - 'A' + 10); 432 } else { 433 return (-1); 434 } 435 } 436 437 void 438 hex2bin(unsigned char *hex, unsigned char *bin, int size) 439 { 440 int i; 441 442 for (i = 0; i < size; i++) { 443 *bin = hexval(*hex++) << 4; 444 *bin++ |= hexval(*hex++); 445 } 446 } 447 448 /* 449 * Exponential caching management 450 */ 451 struct cachekey_list { 452 keybuf secret; 453 keybuf public; 454 des_block deskey; 455 struct cachekey_list *next; 456 }; 457 static struct cachekey_list *g_cachedkeys; 458 459 /* 460 * cache result of expensive multiple precision exponential operation 461 */ 462 static void 463 writecache(char *pub, char *sec, des_block *deskey) 464 { 465 struct cachekey_list *new; 466 467 new = (struct cachekey_list *) malloc(sizeof (struct cachekey_list)); 468 if (new == NULL) { 469 return; 470 } 471 memcpy(new->public, pub, sizeof (keybuf)); 472 memcpy(new->secret, sec, sizeof (keybuf)); 473 new->deskey = *deskey; 474 new->next = g_cachedkeys; 475 g_cachedkeys = new; 476 } 477 478 /* 479 * Try to find the common key in the cache 480 */ 481 static int 482 readcache(char *pub, char *sec, des_block *deskey) 483 { 484 struct cachekey_list *found; 485 register struct cachekey_list **l; 486 487 #define cachehit(pub, sec, list) \ 488 (memcmp(pub, (list)->public, sizeof (keybuf)) == 0 && \ 489 memcmp(sec, (list)->secret, sizeof (keybuf)) == 0) 490 491 for (l = &g_cachedkeys; (*l) != NULL && !cachehit(pub, sec, *l); 492 l = &(*l)->next) 493 ; 494 if ((*l) == NULL) { 495 return (0); 496 } 497 found = *l; 498 (*l) = (*l)->next; 499 found->next = g_cachedkeys; 500 g_cachedkeys = found; 501 *deskey = found->deskey; 502 return (1); 503 } 504