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