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.
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.
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.10 2008/06/05 18:06:33 swildner 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.
49 #include <sys/types.h>
51 #include <rpc/key_prot.h>
52 #include <rpc/des_crypt.h>
54 #include <sys/errno.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)
74 pk_nodefaultkeys(void)
80 * Set the modulus for all our Diffie-Hellman operations
83 setmodulus(char *modx
)
86 if (BN_hex2bn(&modulus
, modx
) == 0)
87 errx(1, "could not convert modulus to BIGNUM: %s",
88 ERR_error_string(ERR_get_error(), 0));
92 * Set the secretkey key for this uid
95 pk_setkey(uid_t uid
, keybuf skey
)
97 if (!storesecretkey(uid
, skey
)) {
98 return (KEY_SYSTEMERR
);
100 return (KEY_SUCCESS
);
104 * Encrypt the key using the public key associated with remote_name and the
105 * secret key associated with uid.
108 pk_encrypt(uid_t uid
, char *remote_name
, netobj
*remote_key
, des_block
*key
)
110 return (pk_crypt(uid
, remote_name
, remote_key
, key
, DES_ENCRYPT
));
114 * Decrypt the key using the public key associated with remote_name and the
115 * secret key associated with uid.
118 pk_decrypt(uid_t uid
, char *remote_name
, netobj
*remote_key
, des_block
*key
)
120 return (pk_crypt(uid
, remote_name
, remote_key
, key
, DES_DECRYPT
));
123 static int store_netname( uid_t
, key_netstarg
* );
124 static int fetch_netname( uid_t
, key_netstarg
* );
127 pk_netput(uid_t uid
, key_netstarg
*netstore
)
129 if (!store_netname(uid
, netstore
)) {
130 return (KEY_SYSTEMERR
);
132 return (KEY_SUCCESS
);
136 pk_netget(uid_t uid
, key_netstarg
*netstore
)
138 if (!fetch_netname(uid
, netstore
)) {
139 return (KEY_SYSTEMERR
);
141 return (KEY_SUCCESS
);
146 * Do the work of pk_encrypt && pk_decrypt
149 pk_crypt(uid_t uid
, char *remote_name
, netobj
*remote_key
, des_block
*key
,
154 char xsecret_hold
[1024];
157 BIGNUM
*public, *secret
, *common
;
161 xsecret
= fetchsecretkey(uid
);
162 if (xsecret
== NULL
|| xsecret
[0] == 0) {
163 memset(zero
, 0, sizeof (zero
));
164 xsecret
= xsecret_hold
;
166 return (KEY_NOSECRET
);
168 if (!getsecretkey("nobody", xsecret
, zero
) || xsecret
[0] == 0) {
169 return (KEY_NOSECRET
);
173 memcpy(xpublic
, remote_key
->n_bytes
, remote_key
->n_len
);
175 bzero((char *)&xpublic
, sizeof(xpublic
));
176 if (!getpublickey(remote_name
, xpublic
)) {
177 if (nodefaultkeys
|| !getpublickey("nobody", xpublic
))
178 return (KEY_UNKNOWN
);
182 if (!readcache(xpublic
, xsecret
, &deskey
)) {
183 if ((ctx
= BN_CTX_new()) == NULL
)
184 return (KEY_SYSTEMERR
);
186 if (BN_hex2bn(&public, xpublic
) == 0) {
188 return (KEY_SYSTEMERR
);
191 if (BN_hex2bn(&secret
, xsecret
) == 0) {
194 return (KEY_SYSTEMERR
);
197 if ((common
= BN_new()) == NULL
) {
201 return (KEY_SYSTEMERR
);
204 BN_mod_exp(common
, public, secret
, modulus
, ctx
);
205 extractdeskey(common
, &deskey
);
206 writecache(xpublic
, xsecret
, &deskey
);
212 error
= ecb_crypt((char *)&deskey
, (char *)key
, sizeof (des_block
),
214 if (DES_FAILED(error
)) {
215 return (KEY_SYSTEMERR
);
217 return (KEY_SUCCESS
);
221 pk_get_conv_key(uid_t uid
, keybuf xpublic
, cryptkeyres
*result
)
224 char xsecret_hold
[1024];
225 BIGNUM
*public, *secret
, *common
;
230 xsecret
= fetchsecretkey(uid
);
232 if (xsecret
== NULL
|| xsecret
[0] == 0) {
233 memset(zero
, 0, sizeof (zero
));
234 xsecret
= xsecret_hold
;
236 return (KEY_NOSECRET
);
238 if (!getsecretkey("nobody", xsecret
, zero
) ||
240 return (KEY_NOSECRET
);
243 if (!readcache(xpublic
, xsecret
, &result
->cryptkeyres_u
.deskey
)) {
244 if ((ctx
= BN_CTX_new()) == NULL
)
245 return (KEY_SYSTEMERR
);
247 if (BN_hex2bn(&public, xpublic
) == 0) {
249 return (KEY_SYSTEMERR
);
252 if (BN_hex2bn(&secret
, xsecret
) == 0) {
255 return (KEY_SYSTEMERR
);
258 if ((common
= BN_new()) == NULL
) {
262 return (KEY_SYSTEMERR
);
265 BN_mod_exp(common
, public, secret
, modulus
, ctx
);
267 extractdeskey(common
, &result
->cryptkeyres_u
.deskey
);
268 writecache(xpublic
, xsecret
, &result
->cryptkeyres_u
.deskey
);
275 return (KEY_SUCCESS
);
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.
283 extractdeskey(BIGNUM
*ck
, des_block
*deskey
)
287 BN_ULONG r
, base
= (1 << 8);
290 if ((a
= BN_dup(ck
)) == NULL
)
291 errx(1, "could not copy BIGNUM");
293 for (i
= 0; i
< ((KEYSIZE
- 64) / 2) / 8; i
++) {
294 r
= BN_div_word(a
, base
);
297 for (i
= 0; i
< 8; i
++) {
298 r
= BN_div_word(a
, base
);
302 des_setparity((char *)deskey
);
306 * Key storage management
311 struct secretkey_netname_list
{
313 key_netstarg keynetdata
;
315 struct secretkey_netname_list
*next
;
320 static struct secretkey_netname_list
*g_secretkey_netname
;
323 * Store the keys and netname for this uid
326 store_netname(uid_t uid
, key_netstarg
*netstore
)
328 struct secretkey_netname_list
*new;
329 struct secretkey_netname_list
**l
;
331 for (l
= &g_secretkey_netname
; *l
!= NULL
&& (*l
)->uid
!= uid
;
335 new = (struct secretkey_netname_list
*)malloc(sizeof (*new));
344 if (new->keynetdata
.st_netname
)
345 free(new->keynetdata
.st_netname
);
347 memcpy(new->keynetdata
.st_priv_key
, netstore
->st_priv_key
,
349 memcpy(new->keynetdata
.st_pub_key
, netstore
->st_pub_key
, HEXKEYBYTES
);
351 if (netstore
->st_netname
)
352 new->keynetdata
.st_netname
= strdup(netstore
->st_netname
);
354 new->keynetdata
.st_netname
= NULL
;
355 new->sc_flag
= KEY_NAME
;
361 * Fetch the keys and netname for this uid
365 fetch_netname(uid_t uid
, struct key_netstarg
*key_netst
)
367 struct secretkey_netname_list
*l
;
369 for (l
= g_secretkey_netname
; l
!= NULL
; l
= l
->next
) {
370 if ((l
->uid
== uid
) && (l
->sc_flag
== KEY_NAME
)){
372 memcpy(key_netst
->st_priv_key
,
373 l
->keynetdata
.st_priv_key
, HEXKEYBYTES
);
375 memcpy(key_netst
->st_pub_key
,
376 l
->keynetdata
.st_pub_key
, HEXKEYBYTES
);
378 if (l
->keynetdata
.st_netname
)
379 key_netst
->st_netname
=
380 strdup(l
->keynetdata
.st_netname
);
382 key_netst
->st_netname
= NULL
;
391 fetchsecretkey(uid_t uid
)
393 struct secretkey_netname_list
*l
;
395 for (l
= g_secretkey_netname
; l
!= NULL
; l
= l
->next
) {
397 return (l
->keynetdata
.st_priv_key
);
404 * Store the secretkey for this uid
407 storesecretkey(uid_t uid
, keybuf key
)
409 struct secretkey_netname_list
*new;
410 struct secretkey_netname_list
**l
;
412 for (l
= &g_secretkey_netname
; *l
!= NULL
&& (*l
)->uid
!= uid
;
416 new = (struct secretkey_netname_list
*) malloc(sizeof (*new));
421 new->sc_flag
= KEY_ONLY
;
422 memset(new->keynetdata
.st_pub_key
, 0, HEXKEYBYTES
);
423 new->keynetdata
.st_netname
= NULL
;
430 memcpy(new->keynetdata
.st_priv_key
, key
,
438 return ("0123456789abcdef"[val
]);
442 bin2hex(unsigned char *bin
, unsigned char *hex
, int size
)
446 for (i
= 0; i
< size
; i
++) {
447 *hex
++ = hexdigit(*bin
>> 4);
448 *hex
++ = hexdigit(*bin
++ & 0xf);
455 if ('0' <= dig
&& dig
<= '9') {
457 } else if ('a' <= dig
&& dig
<= 'f') {
458 return (dig
- 'a' + 10);
459 } else if ('A' <= dig
&& dig
<= 'F') {
460 return (dig
- 'A' + 10);
467 hex2bin(unsigned char *hex
, unsigned char *bin
, int size
)
471 for (i
= 0; i
< size
; i
++) {
472 *bin
= hexval(*hex
++) << 4;
473 *bin
++ |= hexval(*hex
++);
478 * Exponential caching management
480 struct cachekey_list
{
484 struct cachekey_list
*next
;
486 static struct cachekey_list
*g_cachedkeys
;
489 * cache result of expensive multiple precision exponential operation
492 writecache(char *pub
, char *sec
, des_block
*deskey
)
494 struct cachekey_list
*new;
496 new = (struct cachekey_list
*) malloc(sizeof (struct cachekey_list
));
500 memcpy(new->public, pub
, sizeof (keybuf
));
501 memcpy(new->secret
, sec
, sizeof (keybuf
));
502 new->deskey
= *deskey
;
503 new->next
= g_cachedkeys
;
508 * Try to find the common key in the cache
511 readcache(char *pub
, char *sec
, des_block
*deskey
)
513 struct cachekey_list
*found
;
514 struct cachekey_list
**l
;
516 #define cachehit(pub, sec, list) \
517 (memcmp(pub, (list)->public, sizeof (keybuf)) == 0 && \
518 memcmp(sec, (list)->secret, sizeof (keybuf)) == 0)
520 for (l
= &g_cachedkeys
; (*l
) != NULL
&& !cachehit(pub
, sec
, *l
);
528 found
->next
= g_cachedkeys
;
529 g_cachedkeys
= found
;
530 *deskey
= found
->deskey
;