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