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