Use ether_crc32_be / ether_crc32_le.
[dragonfly/netmp.git] / usr.sbin / keyserv / setkey.c
blobd27a0ca3efaa484f8b3b70aaa714167aea0822a4
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.
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.
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.
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.
25 * Sun Microsystems, Inc.
26 * 2550 Garcia Avenue
27 * Mountain View, California 94043
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.8 2005/01/11 13:22:40 joerg Exp $
35 * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
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.
44 #include <err.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 #include <openssl/bn.h>
57 #include <openssl/crypto.h>
58 #include <openssl/err.h>
60 static BIGNUM *modulus;
61 static char *fetchsecretkey( uid_t );
62 static void writecache( char *, char *, des_block * );
63 static int readcache( char *, char *, des_block * );
64 static void extractdeskey ( BIGNUM *, des_block * );
65 static int storesecretkey( uid_t, keybuf );
66 static keystatus pk_crypt( uid_t, char *, netobj *, des_block *, int);
67 static int nodefaultkeys = 0;
71 * prohibit the nobody key on this machine k (the -d flag)
73 void
74 pk_nodefaultkeys(void)
76 nodefaultkeys = 1;
80 * Set the modulus for all our Diffie-Hellman operations
82 void
83 setmodulus(char *modx)
85 if (BN_hex2bn(&modulus, modx) == NULL)
86 errx(1, "could not convert modulus to BIGNUM: %s",
87 ERR_error_string(ERR_get_error(), 0));
91 * Set the secretkey key for this uid
93 keystatus
94 pk_setkey(uid_t uid, keybuf skey)
96 if (!storesecretkey(uid, skey)) {
97 return (KEY_SYSTEMERR);
99 return (KEY_SUCCESS);
103 * Encrypt the key using the public key associated with remote_name and the
104 * secret key associated with uid.
106 keystatus
107 pk_encrypt(uid_t uid, char *remote_name, netobj *remote_key, des_block *key)
109 return (pk_crypt(uid, remote_name, remote_key, key, DES_ENCRYPT));
113 * Decrypt the key using the public key associated with remote_name and the
114 * secret key associated with uid.
116 keystatus
117 pk_decrypt(uid_t uid, char *remote_name, netobj *remote_key, des_block *key)
119 return (pk_crypt(uid, remote_name, remote_key, key, DES_DECRYPT));
122 static int store_netname( uid_t, key_netstarg * );
123 static int fetch_netname( uid_t, key_netstarg * );
125 keystatus
126 pk_netput(uid_t uid, key_netstarg *netstore)
128 if (!store_netname(uid, netstore)) {
129 return (KEY_SYSTEMERR);
131 return (KEY_SUCCESS);
134 keystatus
135 pk_netget(uid_t uid, key_netstarg *netstore)
137 if (!fetch_netname(uid, netstore)) {
138 return (KEY_SYSTEMERR);
140 return (KEY_SUCCESS);
145 * Do the work of pk_encrypt && pk_decrypt
147 static keystatus
148 pk_crypt(uid_t uid, char *remote_name, netobj *remote_key, des_block *key,
149 int mode)
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];
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);
167 if (!getsecretkey("nobody", xsecret, zero) || xsecret[0] == 0) {
168 return (KEY_NOSECRET);
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);
181 if (!readcache(xpublic, xsecret, &deskey)) {
182 if ((ctx = BN_CTX_new()) == NULL)
183 return (KEY_SYSTEMERR);
184 if (BN_hex2bn(&public, xpublic) == NULL) {
185 BN_CTX_free(ctx);
186 return (KEY_SYSTEMERR);
188 if (BN_hex2bn(&secret, xsecret) == NULL) {
189 BN_free(public);
190 BN_CTX_free(ctx);
191 return (KEY_SYSTEMERR);
194 if ((common = BN_new()) == NULL) {
195 BN_free(secret);
196 BN_free(public);
197 BN_CTX_free(ctx);
198 return (KEY_SYSTEMERR);
200 BN_zero(common);
201 BN_mod_exp(common, public, secret, modulus, ctx);
202 extractdeskey(common, &deskey);
203 writecache(xpublic, xsecret, &deskey);
204 BN_free(secret);
205 BN_free(public);
206 BN_free(common);
207 BN_CTX_free(ctx);
209 error = ecb_crypt((char *)&deskey, (char *)key, sizeof (des_block),
210 DES_HW | mode);
211 if (DES_FAILED(error)) {
212 return (KEY_SYSTEMERR);
214 return (KEY_SUCCESS);
217 keystatus
218 pk_get_conv_key(uid_t uid, keybuf xpublic, cryptkeyres *result)
220 char *xsecret;
221 char xsecret_hold[1024];
222 BIGNUM *public, *secret, *common;
223 BN_CTX *ctx;
224 char zero[8];
227 xsecret = fetchsecretkey(uid);
229 if (xsecret == NULL || xsecret[0] == 0) {
230 memset(zero, 0, sizeof (zero));
231 xsecret = xsecret_hold;
232 if (nodefaultkeys)
233 return (KEY_NOSECRET);
235 if (!getsecretkey("nobody", xsecret, zero) ||
236 xsecret[0] == 0)
237 return (KEY_NOSECRET);
240 if (!readcache(xpublic, xsecret, &result->cryptkeyres_u.deskey)) {
241 if ((ctx = BN_CTX_new()) == NULL)
242 return (KEY_SYSTEMERR);
243 if (BN_hex2bn(&public, xpublic) == NULL) {
244 BN_CTX_free(ctx);
245 return (KEY_SYSTEMERR);
247 if (BN_hex2bn(&secret, xsecret) == NULL) {
248 BN_free(public);
249 BN_CTX_free(ctx);
250 return (KEY_SYSTEMERR);
253 if ((common = BN_new()) == NULL) {
254 BN_free(secret);
255 BN_free(public);
256 BN_CTX_free(ctx);
257 return (KEY_SYSTEMERR);
259 BN_zero(common);
260 BN_mod_exp(common, public, secret, modulus, ctx);
262 extractdeskey(common, &result->cryptkeyres_u.deskey);
263 writecache(xpublic, xsecret, &result->cryptkeyres_u.deskey);
264 BN_free(secret);
265 BN_free(public);
266 BN_free(common);
267 BN_CTX_free(ctx);
270 return (KEY_SUCCESS);
274 * Choose middle 64 bits of the common key to use as our des key, possibly
275 * overwriting the lower order bits by setting parity.
277 static void
278 extractdeskey(BIGNUM *ck, des_block *deskey)
280 BIGNUM *a;
281 int i;
282 BN_ULONG r, base = (1 << 8);
283 char *k;
285 if ((a = BN_dup(ck)) == NULL)
286 errx(1, "could not copy BIGNUM");
288 for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) {
289 r = BN_div_word(a, base);
291 k = deskey->c;
292 for (i = 0; i < 8; i++) {
293 r = BN_div_word(a, base);
294 *k++ = r;
296 BN_free(a);
297 des_setparity((char *)deskey);
301 * Key storage management
304 #define KEY_ONLY 0
305 #define KEY_NAME 1
306 struct secretkey_netname_list {
307 uid_t uid;
308 key_netstarg keynetdata;
309 u_char sc_flag;
310 struct secretkey_netname_list *next;
315 static struct secretkey_netname_list *g_secretkey_netname;
318 * Store the keys and netname for this uid
320 static int
321 store_netname(uid_t uid, key_netstarg *netstore)
323 struct secretkey_netname_list *new;
324 struct secretkey_netname_list **l;
326 for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid;
327 l = &(*l)->next) {
329 if (*l == NULL) {
330 new = (struct secretkey_netname_list *)malloc(sizeof (*new));
331 if (new == NULL) {
332 return (0);
334 new->uid = uid;
335 new->next = NULL;
336 *l = new;
337 } else {
338 new = *l;
339 if (new->keynetdata.st_netname)
340 free(new->keynetdata.st_netname);
342 memcpy(new->keynetdata.st_priv_key, netstore->st_priv_key,
343 HEXKEYBYTES);
344 memcpy(new->keynetdata.st_pub_key, netstore->st_pub_key, HEXKEYBYTES);
346 if (netstore->st_netname)
347 new->keynetdata.st_netname = strdup(netstore->st_netname);
348 else
349 new->keynetdata.st_netname = (char *)NULL;
350 new->sc_flag = KEY_NAME;
351 return (1);
356 * Fetch the keys and netname for this uid
359 static int
360 fetch_netname(uid_t uid, struct key_netstarg *key_netst)
362 struct secretkey_netname_list *l;
364 for (l = g_secretkey_netname; l != NULL; l = l->next) {
365 if ((l->uid == uid) && (l->sc_flag == KEY_NAME)){
367 memcpy(key_netst->st_priv_key,
368 l->keynetdata.st_priv_key, HEXKEYBYTES);
370 memcpy(key_netst->st_pub_key,
371 l->keynetdata.st_pub_key, HEXKEYBYTES);
373 if (l->keynetdata.st_netname)
374 key_netst->st_netname =
375 strdup(l->keynetdata.st_netname);
376 else
377 key_netst->st_netname = NULL;
378 return (1);
382 return (0);
385 static char *
386 fetchsecretkey(uid_t uid)
388 struct secretkey_netname_list *l;
390 for (l = g_secretkey_netname; l != NULL; l = l->next) {
391 if (l->uid == uid) {
392 return (l->keynetdata.st_priv_key);
395 return (NULL);
399 * Store the secretkey for this uid
401 static int
402 storesecretkey(uid_t uid, keybuf key)
404 struct secretkey_netname_list *new;
405 struct secretkey_netname_list **l;
407 for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid;
408 l = &(*l)->next) {
410 if (*l == NULL) {
411 new = (struct secretkey_netname_list *) malloc(sizeof (*new));
412 if (new == NULL) {
413 return (0);
415 new->uid = uid;
416 new->sc_flag = KEY_ONLY;
417 memset(new->keynetdata.st_pub_key, 0, HEXKEYBYTES);
418 new->keynetdata.st_netname = NULL;
419 new->next = NULL;
420 *l = new;
421 } else {
422 new = *l;
425 memcpy(new->keynetdata.st_priv_key, key,
426 HEXKEYBYTES);
427 return (1);
430 static int
431 hexdigit(int val)
433 return ("0123456789abcdef"[val]);
436 void
437 bin2hex(unsigned char *bin, unsigned char *hex, int size)
439 int i;
441 for (i = 0; i < size; i++) {
442 *hex++ = hexdigit(*bin >> 4);
443 *hex++ = hexdigit(*bin++ & 0xf);
447 static int
448 hexval(char dig)
450 if ('0' <= dig && dig <= '9') {
451 return (dig - '0');
452 } else if ('a' <= dig && dig <= 'f') {
453 return (dig - 'a' + 10);
454 } else if ('A' <= dig && dig <= 'F') {
455 return (dig - 'A' + 10);
456 } else {
457 return (-1);
461 void
462 hex2bin(unsigned char *hex, unsigned char *bin, int size)
464 int i;
466 for (i = 0; i < size; i++) {
467 *bin = hexval(*hex++) << 4;
468 *bin++ |= hexval(*hex++);
473 * Exponential caching management
475 struct cachekey_list {
476 keybuf secret;
477 keybuf public;
478 des_block deskey;
479 struct cachekey_list *next;
481 static struct cachekey_list *g_cachedkeys;
484 * cache result of expensive multiple precision exponential operation
486 static void
487 writecache(char *pub, char *sec, des_block *deskey)
489 struct cachekey_list *new;
491 new = (struct cachekey_list *) malloc(sizeof (struct cachekey_list));
492 if (new == NULL) {
493 return;
495 memcpy(new->public, pub, sizeof (keybuf));
496 memcpy(new->secret, sec, sizeof (keybuf));
497 new->deskey = *deskey;
498 new->next = g_cachedkeys;
499 g_cachedkeys = new;
503 * Try to find the common key in the cache
505 static int
506 readcache(char *pub, char *sec, des_block *deskey)
508 struct cachekey_list *found;
509 struct cachekey_list **l;
511 #define cachehit(pub, sec, list) \
512 (memcmp(pub, (list)->public, sizeof (keybuf)) == 0 && \
513 memcmp(sec, (list)->secret, sizeof (keybuf)) == 0)
515 for (l = &g_cachedkeys; (*l) != NULL && !cachehit(pub, sec, *l);
516 l = &(*l)->next)
518 if ((*l) == NULL) {
519 return (0);
521 found = *l;
522 (*l) = (*l)->next;
523 found->next = g_cachedkeys;
524 g_cachedkeys = found;
525 *deskey = found->deskey;
526 return (1);