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