diff options
author | wpaul <wpaul@FreeBSD.org> | 1997-05-28 15:44:22 +0000 |
---|---|---|
committer | wpaul <wpaul@FreeBSD.org> | 1997-05-28 15:44:22 +0000 |
commit | 7467e74fd1ffc0466987fdf1610da369c4f873e3 (patch) | |
tree | 36aad08a01e1181706bbcf72ab1542ea997bf0bd /usr.sbin | |
parent | 19f636016113354fc26680afe2669faef603f393 (diff) | |
parent | e3331e295ebb65cb3b0f4cb69cdcfd2e2991f737 (diff) | |
download | FreeBSD-src-7467e74fd1ffc0466987fdf1610da369c4f873e3.zip FreeBSD-src-7467e74fd1ffc0466987fdf1610da369c4f873e3.tar.gz |
This commit was generated by cvs2svn to compensate for changes in r26234,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/keyserv/Makefile | 24 | ||||
-rw-r--r-- | usr.sbin/keyserv/crypt_server.c | 264 | ||||
-rw-r--r-- | usr.sbin/keyserv/keyserv.8 | 77 | ||||
-rw-r--r-- | usr.sbin/keyserv/keyserv.c | 828 | ||||
-rw-r--r-- | usr.sbin/keyserv/keyserv.h | 19 | ||||
-rw-r--r-- | usr.sbin/keyserv/keyserv_uid.c | 77 | ||||
-rw-r--r-- | usr.sbin/keyserv/setkey.c | 544 |
7 files changed, 1833 insertions, 0 deletions
diff --git a/usr.sbin/keyserv/Makefile b/usr.sbin/keyserv/Makefile new file mode 100644 index 0000000..564e8ac --- /dev/null +++ b/usr.sbin/keyserv/Makefile @@ -0,0 +1,24 @@ +# $Id: Makefile,v 1.2 1996/11/22 03:00:17 wpaul Exp wpaul $ + +PROG= keyserv +SRCS= keyserv.c setkey.c keyserv_uid.c crypt_svc.c crypt_server.c + +MAN8= keyserv.8 + +CFLAGS+= -DKEYSERV_RANDOM -DBROKEN_DES -I. + +LDADD+= -lmp -lrpcsvc + +RPCDIR= ${DESTDIR}/usr/include/rpcsvc + +CLEANFILES= crypt_svc.c crypt.h + +RPCGEN= rpcgen -C + +crypt_svc.c: ${RPCDIR}/crypt.x crypt.h + ${RPCGEN} -m -o ${.TARGET} ${RPCDIR}/crypt.x + +crypt.h: ${RPCDIR}/crypt.x + ${RPCGEN} -h -o ${.TARGET} ${RPCDIR}/crypt.x + +.include <bsd.prog.mk> diff --git a/usr.sbin/keyserv/crypt_server.c b/usr.sbin/keyserv/crypt_server.c new file mode 100644 index 0000000..aa4f4c9 --- /dev/null +++ b/usr.sbin/keyserv/crypt_server.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 1996 + * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: crypt_server.c,v 1.15 1996/12/25 19:21:10 wpaul Exp $ + */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/param.h> +#include <stdlib.h> +#include <dirent.h> +#include <err.h> +#include <rpc/des_crypt.h> +#include <rpc/des.h> +#include <string.h> +#include <dlfcn.h> +#include "crypt.h" + +#ifndef lint +static const char rcsid[] = "$Id: crypt_server.c,v 1.15 1996/12/25 19:21:10 wpaul Exp $"; +#endif + +/* + * The U.S. government stupidly believes that a) it can keep strong + * crypto code a secret and b) that doing so somehow protects national + * interests. It's wrong on both counts, but until it listens to reason + * we have to make certain compromises so it doesn't have an excuse to + * throw us in federal prison. + * + * Consequently, the core OS ships without DES support, and keyserv + * defaults to using RC4 with only a 40 bit key, just like nutscrape. + * This breaks compatibility with Secure RPC on other systems, but it + * allows Secure RPC to work between FreeBSD systems that don't have the + * DES package installed without throwing security totally out the window. + * + * In order to avoid having to supply two versions of keyserv (one with + * DES and one without), we use dlopen() and friends to load libdes.so + * into our address space at runtime. We check for the presence of + * /usr/lib/libdes.so.3.0 at startup and load it if we find it. If we + * can't find it, or the __des_crypt symbol doesn't exist, we fall back + * to the RC4 encryption code. The user can specify another path using + * the -p flag. + */ + + /* rc4.h */ +typedef struct rc4_key +{ + unsigned char state[256]; + unsigned char x; + unsigned char y; +} rc4_key; + +static void prepare_key(unsigned char *key_data_ptr,int key_data_len, + rc4_key *key); +static void rc4(unsigned char *buffer_ptr,int buffer_len,rc4_key * key); +static void swap_byte(unsigned char *a, unsigned char *b); + +static void prepare_key(unsigned char *key_data_ptr, int key_data_len, + rc4_key *key) +{ + unsigned char index1; + unsigned char index2; + unsigned char* state; + short counter; + + state = &key->state[0]; + for(counter = 0; counter < 256; counter++) + state[counter] = counter; + key->x = 0; + key->y = 0; + index1 = 0; + index2 = 0; + for(counter = 0; counter < 256; counter++) + { + index2 = (key_data_ptr[index1] + state[counter] + + index2) % 256; + swap_byte(&state[counter], &state[index2]); + + index1 = (index1 + 1) % key_data_len; + } +} + +static void rc4(unsigned char *buffer_ptr, int buffer_len, rc4_key *key) +{ + unsigned char x; + unsigned char y; + unsigned char* state; + unsigned char xorIndex; + short counter; + + x = key->x; + y = key->y; + + state = &key->state[0]; + for(counter = 0; counter < buffer_len; counter ++) + { + x = (x + 1) % 256; + y = (state[x] + y) % 256; + swap_byte(&state[x], &state[y]); + + xorIndex = (state[x] + state[y]) % 256; + + buffer_ptr[counter] ^= state[xorIndex]; + } + key->x = x; + key->y = y; +} + +static void swap_byte(unsigned char *a, unsigned char *b) +{ + unsigned char swapByte; + + swapByte = *a; + *a = *b; + *b = swapByte; +} + +/* Dummy _des_crypt function that uses RC4 with a 40 bit key */ +int _rc4_crypt(buf, len, desp) + char *buf; + int len; + struct desparams *desp; +{ + struct rc4_key rc4k; + + /* + * U.S. government anti-crypto weasels take + * note: although we are supplied with a 64 bit + * key, we're only passing 40 bits to the RC4 + * encryption code. So there. + */ + prepare_key(desp->des_key, 5, &rc4k); + rc4(buf, len, &rc4k); + + return(DESERR_NOHWDEVICE); +} + +int (*_my_crypt)__P((char *, int, struct desparams *)) = NULL; + +static void *dlhandle; + +#ifndef _PATH_USRLIB +#define _PATH_USRLIB "/usr/lib" +#endif + +#ifndef LIBDES +#define LIBDES "libdes.so.3." +#endif + +void load_des(warn, libpath) + int warn; + char *libpath; +{ + DIR *dird; + struct dirent *dirp; + char dlpath[MAXPATHLEN]; + int minor = -1; + int len; + + if (libpath == NULL) { + len = strlen(LIBDES); + if ((dird = opendir(_PATH_USRLIB)) == NULL) + err(1, "opendir(/usr/lib) failed"); + + while ((dirp = readdir(dird)) != NULL) { + /* must have a minor number */ + if (strlen(dirp->d_name) <= len) + continue; + if (!strncmp(dirp->d_name, LIBDES, len)) { + if (atoi((dirp->d_name + len + 1)) > minor) { + minor = atoi((dirp->d_name + len + 1)); + snprintf(dlpath,sizeof(dlpath),"%s/%s", + _PATH_USRLIB, dirp->d_name); + } + } + } + + closedir(dird); + } else + snprintf(dlpath, sizeof(dlpath), "%s", libpath); + + if (dlpath != NULL && (dlhandle = dlopen(dlpath, 0444)) != NULL) + _my_crypt = (int (*)())dlsym(dlhandle, "__des_crypt"); + + if (_my_crypt == NULL) { + if (dlhandle != NULL) + dlclose(dlhandle); + _my_crypt = &_rc4_crypt; + if (warn) { + printf ("DES support disabled -- using RC4 instead.\n"); + printf ("Warning: RC4 cipher is not compatible with "); + printf ("other Secure RPC implementations.\nInstall "); + printf ("the FreeBSD 'des' distribution to enable"); + printf (" DES encryption.\n"); + } + } else { + if (warn) { + printf ("DES support enabled\n"); + printf ("Using %s shared object.\n", dlpath); + } + } + + return; +} + +desresp * +des_crypt_1_svc(desargs *argp, struct svc_req *rqstp) +{ + static desresp result; + struct desparams dparm; + + if (argp->desbuf.desbuf_len > DES_MAXDATA) { + result.stat = DESERR_BADPARAM; + return(&result); + } + + bcopy(argp->des_key, dparm.des_key, 8); + bcopy(argp->des_ivec, dparm.des_ivec, 8); + dparm.des_mode = argp->des_mode; + dparm.des_dir = argp->des_dir; + +#ifdef BROKEN_DES + dparm.UDES.UDES_buf = argp->desbuf.desbuf_val; +#endif + result.stat = _my_crypt(argp->desbuf.desbuf_val, + argp->desbuf.desbuf_len, + &dparm); + + if (result.stat == DESERR_NONE || result.stat == DESERR_NOHWDEVICE) { + bcopy(dparm.des_ivec, result.des_ivec, 8); + result.desbuf.desbuf_len = argp->desbuf.desbuf_len; + result.desbuf.desbuf_val = argp->desbuf.desbuf_val; + } + + return (&result); +} diff --git a/usr.sbin/keyserv/keyserv.8 b/usr.sbin/keyserv/keyserv.8 new file mode 100644 index 0000000..b1c31d3 --- /dev/null +++ b/usr.sbin/keyserv/keyserv.8 @@ -0,0 +1,77 @@ +.\" @(#)keyserv.1m 1.21 93/07/14 SMI; from SVr4 +'\"macro stdmacro +.\" Copyright 1989 AT&T +.\" @(#)keyserv.8c 1.8 89/03/29 SMI; +.\".TH KEYSERV 8C "9 September 1987" +.nr X +.TH keyserv 1M "14 Sep 1992" +.SH NAME +keyserv \- server for storing private encryption keys +.SH SYNOPSIS +.B keyserv +[ +.B \-d +] [ +.B \-D +] [ +.B \-n +] +.SH AVAILABILITY +.LP +SUNWcsu +.SH DESCRIPTION +.IX "keyserv" "" "\fLkeyserv\fP \(em server for storing private encryption keys" +.IX "NFS security" "server for storing private encryption keys" "" "server for storing private encryption keys \(em \fLkeyserv\fP" +.IX "encryption keys" "server for storing private keys" "" "server for storing private keys \(em \fLkeyserv\fP" +.LP +.B keyserv +is a daemon that is used for storing the +private encryption keys of each +user logged into the system. +These encryption keys are used for accessing +secure network services such as secure NFS. +.P +Normally, root's key is read from the file +.B /etc/.rootkey +when the daemon is started. +This is useful during power-fail reboots +when no one is around to type a password. +.P +If a client with no secret key calls +.BR keyserv , +then the key of user +.B nobody +is used instead as the default key. +.SH OPTIONS +.TP 10 +.B \-d +Disable the use of default keys for +.BR nobody . +.TP +.B \-D +Run in debugging mode and log all requests to +.BR keyserv . +.TP +.B \-n +Root's secret key is not read from +.BR /etc/.rootkey . +Instead, +.B keyserv +prompts the user for the password to decrypt +root's key stored in the +.B /etc/publickey +database and then stores the decrypted key in +.B /etc/.rootkey +for future use. +This option is useful if the +.B /etc/.rootkey +file ever gets out of date or corrupted. +.SH FILES +.PD 0 +.TP 20 +.B /etc/.rootkey +.PD +.SH "SEE ALSO" +.BR keylogin (1), +.BR keylogout (1), +.BR publickey (4) diff --git a/usr.sbin/keyserv/keyserv.c b/usr.sbin/keyserv/keyserv.c new file mode 100644 index 0000000..fcf7090 --- /dev/null +++ b/usr.sbin/keyserv/keyserv.c @@ -0,0 +1,828 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +#pragma ident "@(#)keyserv.c 1.15 94/04/25 SMI" + +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* + * Keyserver + * Store secret keys per uid. Do public key encryption and decryption + * operations. Generate "random" keys. + * Do not talk to anything but a local root + * process on the local transport only + */ + +#include <stdio.h> +#include <stdlib.h> +#include <pwd.h> +#include <unistd.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <rpc/rpc.h> +#include <rpc/pmap_clnt.h> +#include <sys/param.h> +#include <sys/file.h> +#include <pwd.h> +#include <rpc/des_crypt.h> +#include <rpc/des.h> +#include <rpc/key_prot.h> +#include <rpcsvc/crypt.h> +#include "keyserv.h" + +#ifndef NGROUPS +#define NGROUPS 16 +#endif + +#ifndef KEYSERVSOCK +#define KEYSERVSOCK "/var/run/keyservsock" +#endif + +static void randomize __P(( des_block * )); +static void usage __P(( void )); +static int getrootkey __P(( des_block *, int )); +static int root_auth __P(( SVCXPRT *, struct svc_req * )); + +#ifdef DEBUG +static int debugging = 1; +#else +static int debugging = 0; +#endif + +static void keyprogram(); +static des_block masterkey; +char *getenv(); +static char ROOTKEY[] = "/etc/.rootkey"; + +/* + * Hack to allow the keyserver to use AUTH_DES (for authenticated + * NIS+ calls, for example). The only functions that get called + * are key_encryptsession_pk, key_decryptsession_pk, and key_gendes. + * + * The approach is to have the keyserver fill in pointers to local + * implementations of these functions, and to call those in key_call(). + */ + +extern cryptkeyres *(*__key_encryptsession_pk_LOCAL)(); +extern cryptkeyres *(*__key_decryptsession_pk_LOCAL)(); +extern des_block *(*__key_gendes_LOCAL)(); +extern int (*__des_crypt_LOCAL)(); + +cryptkeyres *key_encrypt_pk_2_svc_prog __P(( uid_t, cryptkeyarg2 * )); +cryptkeyres *key_decrypt_pk_2_svc_prog __P(( uid_t, cryptkeyarg2 * )); +des_block *key_gen_1_svc_prog __P(( void *, struct svc_req * )); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int nflag = 0; + extern char *optarg; + extern int optind; + int c; + register SVCXPRT *transp; + int sock = RPC_ANYSOCK; + int warn = 0; + char *path = NULL; + + __key_encryptsession_pk_LOCAL = &key_encrypt_pk_2_svc_prog; + __key_decryptsession_pk_LOCAL = &key_decrypt_pk_2_svc_prog; + __key_gendes_LOCAL = &key_gen_1_svc_prog; + + while ((c = getopt(argc, argv, "ndDvp:")) != -1) + switch (c) { + case 'n': + nflag++; + break; + case 'd': + pk_nodefaultkeys(); + break; + case 'D': + debugging = 1; + break; + case 'v': + warn = 1; + break; + case 'p': + path = optarg; + break; + default: + usage(); + } + + load_des(warn, path); + __des_crypt_LOCAL = _my_crypt; + if (svc_auth_reg(AUTH_DES, _svcauth_des) == -1) { + fprintf(stderr, "failed to register AUTH_DES authenticator\n"); + exit(1); + } + + if (optind != argc) { + usage(); + } + + /* + * Initialize + */ + (void) umask(066); /* paranoia */ + if (geteuid() != 0) { + (void) fprintf(stderr, "%s must be run as root\n", argv[0]); + exit(1); + } + setmodulus(HEXMODULUS); + getrootkey(&masterkey, nflag); + + + /* Create services. */ + + (void) pmap_unset(KEY_PROG, KEY_VERS); + (void) pmap_unset(KEY_PROG, KEY_VERS2); + unlink(KEYSERVSOCK); + + transp = svcudp_create(RPC_ANYSOCK); + if (transp == NULL) { + fprintf(stderr, "cannot create udp service."); + exit(1); + } + if (!svc_register(transp, KEY_PROG, KEY_VERS, keyprogram, IPPROTO_UDP)) { + fprintf(stderr, "unable to register (KEY_PROG, KEY_VERS, udp)."); + exit(1); + } + if (!svc_register(transp, KEY_PROG, KEY_VERS2, keyprogram, IPPROTO_UDP)) { + fprintf(stderr, "unable to register (KEY_PROG, KEY_VERS2, udp)."); + exit(1); + } + + transp = svctcp_create(RPC_ANYSOCK, 0, 0); + if (transp == NULL) { + fprintf(stderr, "cannot create tcp service."); + exit(1); + } + if (!svc_register(transp, KEY_PROG, KEY_VERS, keyprogram, IPPROTO_TCP)) { + fprintf(stderr, "unable to register (KEY_PROG, KEY_VERS, tcp)."); + exit(1); + } + if (!svc_register(transp, KEY_PROG, KEY_VERS2, keyprogram, IPPROTO_TCP)) { + fprintf(stderr, "unable to register (KEY_PROG, KEY_VERS2, tcp)."); + exit(1); + } + + transp = svcunix_create(sock, 0, 0, KEYSERVSOCK); + chmod(KEYSERVSOCK, 0666); + if (transp == NULL) { + fprintf(stderr, "cannot create AF_UNIX service."); + exit(1); + } + if (!svc_register(transp, KEY_PROG, KEY_VERS, keyprogram, 0)) { + fprintf(stderr, "unable to register (KEY_PROG, KEY_VERS, unix)."); + exit(1); + } + if (!svc_register(transp, KEY_PROG, KEY_VERS2, keyprogram, 0)) { + fprintf(stderr, "unable to register (KEY_PROG, KEY_VERS2, unix)."); + exit(1); + } + if (!svc_register(transp, CRYPT_PROG, CRYPT_VERS, crypt_prog_1, 0)) { + fprintf(stderr, "unable to register (CRYPT_PROG, CRYPT_VERS, unix)."); + exit(1); + } + + if (!debugging) { + daemon(0,0); + } + + signal(SIGPIPE, SIG_IGN); + + svc_run(); + abort(); + /* NOTREACHED */ +} + +/* + * In the event that we don't get a root password, we try to + * randomize the master key the best we can + */ +static void +randomize(master) + des_block *master; +{ + int i; + int seed; + struct timeval tv; + int shift; + + seed = 0; + for (i = 0; i < 1024; i++) { + (void) gettimeofday(&tv, (struct timezone *) NULL); + shift = i % 8 * sizeof (int); + seed ^= (tv.tv_usec << shift) | (tv.tv_usec >> (32 - shift)); + } +#ifdef KEYSERV_RANDOM + srandom(seed); + master->key.low = random(); + master->key.high = random(); + srandom(seed); +#else + /* use stupid dangerous bad rand() */ + srand(seed); + master->key.low = rand(); + master->key.high = rand(); + srand(seed); +#endif +} + +/* + * Try to get root's secret key, by prompting if terminal is a tty, else trying + * from standard input. + * Returns 1 on success. + */ +static int +getrootkey(master, prompt) + des_block *master; + int prompt; +{ + char *passwd; + char name[MAXNETNAMELEN + 1]; + char secret[HEXKEYBYTES]; + key_netstarg netstore; + int fd; + + if (!prompt) { + /* + * Read secret key out of ROOTKEY + */ + fd = open(ROOTKEY, O_RDONLY, 0); + if (fd < 0) { + randomize(master); + return (0); + } + if (read(fd, secret, HEXKEYBYTES) < HEXKEYBYTES) { + (void) fprintf(stderr, + "keyserv: the key read from %s was too short.\n", + ROOTKEY); + (void) close(fd); + return (0); + } + (void) close(fd); + if (!getnetname(name)) { + (void) fprintf(stderr, "keyserv: \ +failed to generate host's netname when establishing root's key.\n"); + return (0); + } + memcpy(netstore.st_priv_key, secret, HEXKEYBYTES); + memset(netstore.st_pub_key, 0, HEXKEYBYTES); + netstore.st_netname = name; + if (pk_netput(0, &netstore) != KEY_SUCCESS) { + (void) fprintf(stderr, + "keyserv: could not set root's key and netname.\n"); + return (0); + } + return (1); + } + /* + * Decrypt yellow pages publickey entry to get secret key + */ + passwd = getpass("root password:"); + passwd2des(passwd, (char *)master); + getnetname(name); + if (!getsecretkey(name, secret, passwd)) { + (void) fprintf(stderr, + "Can't find %s's secret key\n", name); + return (0); + } + if (secret[0] == 0) { + (void) fprintf(stderr, + "Password does not decrypt secret key for %s\n", name); + return (0); + } + (void) pk_setkey(0, secret); + /* + * Store it for future use in $ROOTKEY, if possible + */ + fd = open(ROOTKEY, O_WRONLY|O_TRUNC|O_CREAT, 0); + if (fd > 0) { + char newline = '\n'; + + write(fd, secret, strlen(secret)); + write(fd, &newline, sizeof (newline)); + close(fd); + } + return (1); +} + +/* + * Procedures to implement RPC service + */ +char * +strstatus(status) + keystatus status; +{ + switch (status) { + case KEY_SUCCESS: + return ("KEY_SUCCESS"); + case KEY_NOSECRET: + return ("KEY_NOSECRET"); + case KEY_UNKNOWN: + return ("KEY_UNKNOWN"); + case KEY_SYSTEMERR: + return ("KEY_SYSTEMERR"); + default: + return ("(bad result code)"); + } +} + +keystatus * +key_set_1_svc_prog(uid, key) + uid_t uid; + keybuf key; +{ + static keystatus status; + + if (debugging) { + (void) fprintf(stderr, "set(%ld, %.*s) = ", uid, + (int) sizeof (keybuf), key); + } + status = pk_setkey(uid, key); + if (debugging) { + (void) fprintf(stderr, "%s\n", strstatus(status)); + (void) fflush(stderr); + } + return (&status); +} + +cryptkeyres * +key_encrypt_pk_2_svc_prog(uid, arg) + uid_t uid; + cryptkeyarg2 *arg; +{ + static cryptkeyres res; + + if (debugging) { + (void) fprintf(stderr, "encrypt(%ld, %s, %08x%08x) = ", uid, + arg->remotename, arg->deskey.key.high, + arg->deskey.key.low); + } + res.cryptkeyres_u.deskey = arg->deskey; + res.status = pk_encrypt(uid, arg->remotename, &(arg->remotekey), + &res.cryptkeyres_u.deskey); + if (debugging) { + if (res.status == KEY_SUCCESS) { + (void) fprintf(stderr, "%08x%08x\n", + res.cryptkeyres_u.deskey.key.high, + res.cryptkeyres_u.deskey.key.low); + } else { + (void) fprintf(stderr, "%s\n", strstatus(res.status)); + } + (void) fflush(stderr); + } + return (&res); +} + +cryptkeyres * +key_decrypt_pk_2_svc_prog(uid, arg) + uid_t uid; + cryptkeyarg2 *arg; +{ + static cryptkeyres res; + + if (debugging) { + (void) fprintf(stderr, "decrypt(%ld, %s, %08x%08x) = ", uid, + arg->remotename, arg->deskey.key.high, + arg->deskey.key.low); + } + res.cryptkeyres_u.deskey = arg->deskey; + res.status = pk_decrypt(uid, arg->remotename, &(arg->remotekey), + &res.cryptkeyres_u.deskey); + if (debugging) { + if (res.status == KEY_SUCCESS) { + (void) fprintf(stderr, "%08x%08x\n", + res.cryptkeyres_u.deskey.key.high, + res.cryptkeyres_u.deskey.key.low); + } else { + (void) fprintf(stderr, "%s\n", strstatus(res.status)); + } + (void) fflush(stderr); + } + return (&res); +} + +keystatus * +key_net_put_2_svc_prog(uid, arg) + uid_t uid; + key_netstarg *arg; +{ + static keystatus status; + + if (debugging) { + (void) fprintf(stderr, "net_put(%s, %.*s, %.*s) = ", + arg->st_netname, (int)sizeof (arg->st_pub_key), + arg->st_pub_key, (int)sizeof (arg->st_priv_key), + arg->st_priv_key); + }; + + status = pk_netput(uid, arg); + + if (debugging) { + (void) fprintf(stderr, "%s\n", strstatus(status)); + (void) fflush(stderr); + } + + return (&status); +} + +key_netstres * +key_net_get_2_svc_prog(uid, arg) + uid_t uid; + void *arg; +{ + static key_netstres keynetname; + + if (debugging) + (void) fprintf(stderr, "net_get(%ld) = ", uid); + + keynetname.status = pk_netget(uid, &keynetname.key_netstres_u.knet); + if (debugging) { + if (keynetname.status == KEY_SUCCESS) { + fprintf(stderr, "<%s, %.*s, %.*s>\n", + keynetname.key_netstres_u.knet.st_netname, + (int)sizeof (keynetname.key_netstres_u.knet.st_pub_key), + keynetname.key_netstres_u.knet.st_pub_key, + (int)sizeof (keynetname.key_netstres_u.knet.st_priv_key), + keynetname.key_netstres_u.knet.st_priv_key); + } else { + (void) fprintf(stderr, "NOT FOUND\n"); + } + (void) fflush(stderr); + } + + return (&keynetname); + +} + +cryptkeyres * +key_get_conv_2_svc_prog(uid, arg) + uid_t uid; + keybuf arg; +{ + static cryptkeyres res; + + if (debugging) + (void) fprintf(stderr, "get_conv(%ld, %.*s) = ", uid, + (int)sizeof (arg), arg); + + + res.status = pk_get_conv_key(uid, arg, &res); + + if (debugging) { + if (res.status == KEY_SUCCESS) { + (void) fprintf(stderr, "%08x%08x\n", + res.cryptkeyres_u.deskey.key.high, + res.cryptkeyres_u.deskey.key.low); + } else { + (void) fprintf(stderr, "%s\n", strstatus(res.status)); + } + (void) fflush(stderr); + } + return (&res); +} + + +cryptkeyres * +key_encrypt_1_svc_prog(uid, arg) + uid_t uid; + cryptkeyarg *arg; +{ + static cryptkeyres res; + + if (debugging) { + (void) fprintf(stderr, "encrypt(%ld, %s, %08x%08x) = ", uid, + arg->remotename, arg->deskey.key.high, + arg->deskey.key.low); + } + res.cryptkeyres_u.deskey = arg->deskey; + res.status = pk_encrypt(uid, arg->remotename, NULL, + &res.cryptkeyres_u.deskey); + if (debugging) { + if (res.status == KEY_SUCCESS) { + (void) fprintf(stderr, "%08x%08x\n", + res.cryptkeyres_u.deskey.key.high, + res.cryptkeyres_u.deskey.key.low); + } else { + (void) fprintf(stderr, "%s\n", strstatus(res.status)); + } + (void) fflush(stderr); + } + return (&res); +} + +cryptkeyres * +key_decrypt_1_svc_prog(uid, arg) + uid_t uid; + cryptkeyarg *arg; +{ + static cryptkeyres res; + + if (debugging) { + (void) fprintf(stderr, "decrypt(%ld, %s, %08x%08x) = ", uid, + arg->remotename, arg->deskey.key.high, + arg->deskey.key.low); + } + res.cryptkeyres_u.deskey = arg->deskey; + res.status = pk_decrypt(uid, arg->remotename, NULL, + &res.cryptkeyres_u.deskey); + if (debugging) { + if (res.status == KEY_SUCCESS) { + (void) fprintf(stderr, "%08x%08x\n", + res.cryptkeyres_u.deskey.key.high, + res.cryptkeyres_u.deskey.key.low); + } else { + (void) fprintf(stderr, "%s\n", strstatus(res.status)); + } + (void) fflush(stderr); + } + return (&res); +} + +/* ARGSUSED */ +des_block * +key_gen_1_svc_prog(v, s) + void *v; + struct svc_req *s; +{ + struct timeval time; + static des_block keygen; + static des_block key; + + (void) gettimeofday(&time, (struct timezone *) NULL); + keygen.key.high += (time.tv_sec ^ time.tv_usec); + keygen.key.low += (time.tv_sec ^ time.tv_usec); + ecb_crypt((char *)&masterkey, (char *)&keygen, sizeof (keygen), + DES_ENCRYPT | DES_HW); + key = keygen; + des_setparity((char *)&key); + if (debugging) { + (void) fprintf(stderr, "gen() = %08x%08x\n", key.key.high, + key.key.low); + (void) fflush(stderr); + } + return (&key); +} + +getcredres * +key_getcred_1_svc_prog(uid, name) + uid_t uid; + netnamestr *name; +{ + static getcredres res; + static u_int gids[NGROUPS]; + struct unixcred *cred; + + cred = &res.getcredres_u.cred; + cred->gids.gids_val = gids; + if (!netname2user(*name, (uid_t *) &cred->uid, (gid_t *) &cred->gid, + (int *)&cred->gids.gids_len, (gid_t *)gids)) { + res.status = KEY_UNKNOWN; + } else { + res.status = KEY_SUCCESS; + } + if (debugging) { + (void) fprintf(stderr, "getcred(%s) = ", *name); + if (res.status == KEY_SUCCESS) { + (void) fprintf(stderr, "uid=%d, gid=%d, grouplen=%d\n", + cred->uid, cred->gid, cred->gids.gids_len); + } else { + (void) fprintf(stderr, "%s\n", strstatus(res.status)); + } + (void) fflush(stderr); + } + return (&res); +} + +/* + * RPC boilerplate + */ +static void +keyprogram(rqstp, transp) + struct svc_req *rqstp; + SVCXPRT *transp; +{ + union { + keybuf key_set_1_arg; + cryptkeyarg key_encrypt_1_arg; + cryptkeyarg key_decrypt_1_arg; + netnamestr key_getcred_1_arg; + cryptkeyarg key_encrypt_2_arg; + cryptkeyarg key_decrypt_2_arg; + netnamestr key_getcred_2_arg; + cryptkeyarg2 key_encrypt_pk_2_arg; + cryptkeyarg2 key_decrypt_pk_2_arg; + key_netstarg key_net_put_2_arg; + netobj key_get_conv_2_arg; + } argument; + char *result; + bool_t(*xdr_argument)(), (*xdr_result)(); + char *(*local) (); + uid_t uid = -1; + int check_auth; + + switch (rqstp->rq_proc) { + case NULLPROC: + svc_sendreply(transp, xdr_void, (char *)NULL); + return; + + case KEY_SET: + xdr_argument = xdr_keybuf; + xdr_result = xdr_int; + local = (char *(*)()) key_set_1_svc_prog; + check_auth = 1; + break; + + case KEY_ENCRYPT: + xdr_argument = xdr_cryptkeyarg; + xdr_result = xdr_cryptkeyres; + local = (char *(*)()) key_encrypt_1_svc_prog; + check_auth = 1; + break; + + case KEY_DECRYPT: + xdr_argument = xdr_cryptkeyarg; + xdr_result = xdr_cryptkeyres; + local = (char *(*)()) key_decrypt_1_svc_prog; + check_auth = 1; + break; + + case KEY_GEN: + xdr_argument = xdr_void; + xdr_result = xdr_des_block; + local = (char *(*)()) key_gen_1_svc_prog; + check_auth = 0; + break; + + case KEY_GETCRED: + xdr_argument = xdr_netnamestr; + xdr_result = xdr_getcredres; + local = (char *(*)()) key_getcred_1_svc_prog; + check_auth = 0; + break; + + case KEY_ENCRYPT_PK: + xdr_argument = xdr_cryptkeyarg2; + xdr_result = xdr_cryptkeyres; + local = (char *(*)()) key_encrypt_pk_2_svc_prog; + check_auth = 1; + break; + + case KEY_DECRYPT_PK: + xdr_argument = xdr_cryptkeyarg2; + xdr_result = xdr_cryptkeyres; + local = (char *(*)()) key_decrypt_pk_2_svc_prog; + check_auth = 1; + break; + + + case KEY_NET_PUT: + xdr_argument = xdr_key_netstarg; + xdr_result = xdr_keystatus; + local = (char *(*)()) key_net_put_2_svc_prog; + check_auth = 1; + break; + + case KEY_NET_GET: + xdr_argument = (xdrproc_t) xdr_void; + xdr_result = xdr_key_netstres; + local = (char *(*)()) key_net_get_2_svc_prog; + check_auth = 1; + break; + + case KEY_GET_CONV: + xdr_argument = (xdrproc_t) xdr_keybuf; + xdr_result = xdr_cryptkeyres; + local = (char *(*)()) key_get_conv_2_svc_prog; + check_auth = 1; + break; + + default: + svcerr_noproc(transp); + return; + } + if (check_auth) { + if (root_auth(transp, rqstp) == 0) { + if (debugging) { + (void) fprintf(stderr, + "not local privileged process\n"); + } + svcerr_weakauth(transp); + return; + } + if (rqstp->rq_cred.oa_flavor != AUTH_SYS) { + if (debugging) { + (void) fprintf(stderr, + "not unix authentication\n"); + } + svcerr_weakauth(transp); + return; + } + uid = ((struct authsys_parms *)rqstp->rq_clntcred)->aup_uid; + } + + memset((char *) &argument, 0, sizeof (argument)); + if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) { + svcerr_decode(transp); + return; + } + result = (*local) (uid, &argument); + if (!svc_sendreply(transp, xdr_result, (char *) result)) { + if (debugging) + (void) fprintf(stderr, "unable to reply\n"); + svcerr_systemerr(transp); + } + if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) { + if (debugging) + (void) fprintf(stderr, + "unable to free arguments\n"); + exit(1); + } + return; +} + +static int +root_auth(trans, rqstp) + SVCXPRT *trans; + struct svc_req *rqstp; +{ + uid_t uid; + struct sockaddr_in *remote; + + remote = svc_getcaller(trans); + if (remote->sin_family == AF_INET) { + if (debugging) + fprintf(stderr, "client didn't use AF_UNIX\n"); + return (0); + } + + if (__rpc_get_local_uid(&uid, trans) < 0) { + if (debugging) + fprintf(stderr, "__rpc_get_local_uid failed\n"); + return (0); + } + + if (debugging) + fprintf(stderr, "local_uid %ld\n", uid); + if (uid == 0) + return (1); + if (rqstp->rq_cred.oa_flavor == AUTH_SYS) { + if (((uid_t) ((struct authunix_parms *) + rqstp->rq_clntcred)->aup_uid) + == uid) { + return (1); + } else { + if (debugging) + fprintf(stderr, + "local_uid %ld mismatches auth %ld\n", uid, +((uid_t) ((struct authunix_parms *)rqstp->rq_clntcred)->aup_uid)); + return (0); + } + } else { + if (debugging) + fprintf(stderr, "Not auth sys\n"); + return (0); + } +} + +static void +usage() +{ + (void) fprintf(stderr, + "usage: keyserv [-n] [-D] [-d] [-v] [-p path]\n"); + (void) fprintf(stderr, "-d disables the use of default keys\n"); + exit(1); +} diff --git a/usr.sbin/keyserv/keyserv.h b/usr.sbin/keyserv/keyserv.h new file mode 100644 index 0000000..6e2402d --- /dev/null +++ b/usr.sbin/keyserv/keyserv.h @@ -0,0 +1,19 @@ + +extern void setmodulus __P((char *modx)); + +extern keystatus pk_setkey __P(( uid_t, keybuf ));; +extern keystatus pk_encrypt __P(( uid_t, char *, netobj *, des_block * )); +extern keystatus pk_decrypt __P(( uid_t, char *, netobj *, des_block * )); +extern keystatus pk_netput __P(( uid_t, key_netstarg * )); +extern keystatus pk_netget __P(( uid_t, key_netstarg * )); +extern keystatus pk_get_conv_key __P(( uid_t, keybuf, cryptkeyres * )); +extern void pk_nodefaultkeys __P(( void )); + +extern int __rpc_get_local_uid __P(( uid_t * , SVCXPRT * )); +extern void crypt_prog_1 __P(( struct svc_req *, register SVCXPRT * )); +extern void load_des __P(( int, char * )); + +extern int (*_my_crypt)__P(( char *, int, struct desparams * )); + +extern char ROOTKEY[]; + diff --git a/usr.sbin/keyserv/keyserv_uid.c b/usr.sbin/keyserv/keyserv_uid.c new file mode 100644 index 0000000..f38e3b0 --- /dev/null +++ b/usr.sbin/keyserv/keyserv_uid.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1996 + * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: keyserv_uid.c,v 1.13 1997/01/19 20:23:05 wpaul Exp $ + */ + +#include <stdio.h> +#include <sys/types.h> +#include <string.h> +#include <rpc/key_prot.h> +#include <rpc/des.h> +#include <signal.h> +#include <sys/socket.h> +#include <sys/param.h> +#include <unistd.h> + +#include "keyserv.h" + +#ifndef lint +static const char rcsid[] = "$Id: keyserv_uid.c,v 1.13 1997/01/19 20:23:05 wpaul Exp $"; +#endif + +/* + * XXX should be declared somewhere + */ +struct cmessage { + struct cmsghdr cmsg; + struct cmsgcred cmcred; +}; + +int +__rpc_get_local_uid(uid, transp) + uid_t *uid; + SVCXPRT *transp; +{ + struct cmessage *cm; + + if (transp->xp_verf.oa_length < sizeof(struct cmessage) || + transp->xp_verf.oa_base == NULL || + transp->xp_verf.oa_flavor != AUTH_UNIX) + return(-1); + + cm = (struct cmessage *)transp->xp_verf.oa_base; + if (cm->cmsg.cmsg_type != SCM_CREDS) + return(-1); + + *uid = cm->cmcred.cmcred_euid; + return(0); +} diff --git a/usr.sbin/keyserv/setkey.c b/usr.sbin/keyserv/setkey.c new file mode 100644 index 0000000..bdafae9 --- /dev/null +++ b/usr.sbin/keyserv/setkey.c @@ -0,0 +1,544 @@ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +#pragma ident "@(#)setkey.c 1.11 94/04/25 SMI" + +/* + * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + */ + +/* + * Do the real work of the keyserver. + * Store secret keys. Compute common keys, + * and use them to decrypt and encrypt DES keys. + * Cache the common keys, so the expensive computation is avoided. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <mp.h> +#include <rpc/rpc.h> +#include <rpc/key_prot.h> +#include <rpc/des_crypt.h> +#include <rpc/des.h> +#include <sys/errno.h> +#include <string.h> +#include "keyserv.h" + +static MINT *MODULUS; +static char *fetchsecretkey __P(( uid_t )); +static void writecache __P(( char *, char *, des_block * )); +static int readcache __P(( char *, char *, des_block * )); +static void extractdeskey __P (( MINT *, des_block * )); +static int storesecretkey __P(( uid_t, keybuf )); +static keystatus pk_crypt __P(( uid_t, char *, netobj *, des_block *, int)); +static int nodefaultkeys = 0; + + +/* + * prohibit the nobody key on this machine k (the -d flag) + */ +void +pk_nodefaultkeys() +{ + nodefaultkeys = 1; +} + +/* + * Set the modulus for all our Diffie-Hellman operations + */ +void +setmodulus(modx) + char *modx; +{ + MODULUS = xtom(modx); +} + +/* + * Set the secretkey key for this uid + */ +keystatus +pk_setkey(uid, skey) + uid_t uid; + keybuf skey; +{ + if (!storesecretkey(uid, skey)) { + return (KEY_SYSTEMERR); + } + return (KEY_SUCCESS); +} + +/* + * Encrypt the key using the public key associated with remote_name and the + * secret key associated with uid. + */ +keystatus +pk_encrypt(uid, remote_name, remote_key, key) + uid_t uid; + char *remote_name; + netobj *remote_key; + des_block *key; +{ + return (pk_crypt(uid, remote_name, remote_key, key, DES_ENCRYPT)); +} + +/* + * Decrypt the key using the public key associated with remote_name and the + * secret key associated with uid. + */ +keystatus +pk_decrypt(uid, remote_name, remote_key, key) + uid_t uid; + char *remote_name; + netobj *remote_key; + des_block *key; +{ + return (pk_crypt(uid, remote_name, remote_key, key, DES_DECRYPT)); +} + +static int store_netname __P(( uid_t, key_netstarg * )); +static int fetch_netname __P(( uid_t, key_netstarg * )); + +keystatus +pk_netput(uid, netstore) + uid_t uid; + key_netstarg *netstore; +{ + if (!store_netname(uid, netstore)) { + return (KEY_SYSTEMERR); + } + return (KEY_SUCCESS); +} + +keystatus +pk_netget(uid, netstore) + uid_t uid; + key_netstarg *netstore; +{ + if (!fetch_netname(uid, netstore)) { + return (KEY_SYSTEMERR); + } + return (KEY_SUCCESS); +} + + +/* + * Do the work of pk_encrypt && pk_decrypt + */ +static keystatus +pk_crypt(uid, remote_name, remote_key, key, mode) + uid_t uid; + char *remote_name; + netobj *remote_key; + des_block *key; + int mode; +{ + char *xsecret; + char xpublic[1024]; + char xsecret_hold[1024]; + des_block deskey; + int err; + MINT *public; + MINT *secret; + MINT *common; + char zero[8]; + + xsecret = fetchsecretkey(uid); + if (xsecret == NULL || xsecret[0] == 0) { + memset(zero, 0, sizeof (zero)); + xsecret = xsecret_hold; + if (nodefaultkeys) + return (KEY_NOSECRET); + + if (!getsecretkey("nobody", xsecret, zero) || xsecret[0] == 0) { + return (KEY_NOSECRET); + } + } + if (remote_key) { + memcpy(xpublic, remote_key->n_bytes, remote_key->n_len); + } else { + bzero((char *)&xpublic, sizeof(xpublic)); + if (!getpublickey(remote_name, xpublic)) { + if (nodefaultkeys || !getpublickey("nobody", xpublic)) + return (KEY_UNKNOWN); + } + } + + if (!readcache(xpublic, xsecret, &deskey)) { + public = xtom(xpublic); + secret = xtom(xsecret); + /* Sanity Check on public and private keys */ + if ((public == NULL) || (secret == NULL)) + return (KEY_SYSTEMERR); + + common = itom(0); + pow(public, secret, MODULUS, common); + extractdeskey(common, &deskey); + writecache(xpublic, xsecret, &deskey); + mfree(secret); + mfree(public); + mfree(common); + } + err = ecb_crypt((char *)&deskey, (char *)key, sizeof (des_block), + DES_HW | mode); + if (DES_FAILED(err)) { + return (KEY_SYSTEMERR); + } + return (KEY_SUCCESS); +} + +keystatus +pk_get_conv_key(uid, xpublic, result) + uid_t uid; + keybuf xpublic; + cryptkeyres *result; +{ + char *xsecret; + char xsecret_hold[1024]; + MINT *public; + MINT *secret; + MINT *common; + char zero[8]; + + + xsecret = fetchsecretkey(uid); + + if (xsecret == NULL || xsecret[0] == 0) { + memset(zero, 0, sizeof (zero)); + xsecret = xsecret_hold; + if (nodefaultkeys) + return (KEY_NOSECRET); + + if (!getsecretkey("nobody", xsecret, zero) || + xsecret[0] == 0) + return (KEY_NOSECRET); + } + + if (!readcache(xpublic, xsecret, &result->cryptkeyres_u.deskey)) { + public = xtom(xpublic); + secret = xtom(xsecret); + /* Sanity Check on public and private keys */ + if ((public == NULL) || (secret == NULL)) + return (KEY_SYSTEMERR); + + common = itom(0); + pow(public, secret, MODULUS, common); + extractdeskey(common, &result->cryptkeyres_u.deskey); + writecache(xpublic, xsecret, &result->cryptkeyres_u.deskey); + mfree(secret); + mfree(public); + mfree(common); + } + + return (KEY_SUCCESS); +} + +/* + * Choose middle 64 bits of the common key to use as our des key, possibly + * overwriting the lower order bits by setting parity. + */ +static void +extractdeskey(ck, deskey) + MINT *ck; + des_block *deskey; +{ + MINT *a; + short r; + int i; + short base = (1 << 8); + char *k; + + a = itom(0); +#ifdef SOLARIS_MP + _mp_move(ck, a); +#else + move(ck, a); +#endif + for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) { + sdiv(a, base, a, &r); + } + k = deskey->c; + for (i = 0; i < 8; i++) { + sdiv(a, base, a, &r); + *k++ = r; + } + mfree(a); + des_setparity((char *)deskey); +} + +/* + * Key storage management + */ + +#define KEY_ONLY 0 +#define KEY_NAME 1 +struct secretkey_netname_list { + uid_t uid; + key_netstarg keynetdata; + u_char sc_flag; + struct secretkey_netname_list *next; +}; + + + +static struct secretkey_netname_list *g_secretkey_netname; + +/* + * Store the keys and netname for this uid + */ +static int +store_netname(uid, netstore) + uid_t uid; + key_netstarg *netstore; +{ + struct secretkey_netname_list *new; + struct secretkey_netname_list **l; + + for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid; + l = &(*l)->next) { + } + if (*l == NULL) { + new = (struct secretkey_netname_list *)malloc(sizeof (*new)); + if (new == NULL) { + return (0); + } + new->uid = uid; + new->next = NULL; + *l = new; + } else { + new = *l; + if (new->keynetdata.st_netname) + (void) free (new->keynetdata.st_netname); + } + memcpy(new->keynetdata.st_priv_key, netstore->st_priv_key, + HEXKEYBYTES); + memcpy(new->keynetdata.st_pub_key, netstore->st_pub_key, HEXKEYBYTES); + + if (netstore->st_netname) + new->keynetdata.st_netname = strdup(netstore->st_netname); + else + new->keynetdata.st_netname = (char *)NULL; + new->sc_flag = KEY_NAME; + return (1); + +} + +/* + * Fetch the keys and netname for this uid + */ + +static int +fetch_netname(uid, key_netst) + uid_t uid; + struct key_netstarg *key_netst; +{ + struct secretkey_netname_list *l; + + for (l = g_secretkey_netname; l != NULL; l = l->next) { + if ((l->uid == uid) && (l->sc_flag == KEY_NAME)){ + + memcpy(key_netst->st_priv_key, + l->keynetdata.st_priv_key, HEXKEYBYTES); + + memcpy(key_netst->st_pub_key, + l->keynetdata.st_pub_key, HEXKEYBYTES); + + if (l->keynetdata.st_netname) + key_netst->st_netname = + strdup(l->keynetdata.st_netname); + else + key_netst->st_netname = NULL; + return (1); + } + } + + return (0); +} + +static char * +fetchsecretkey(uid) + uid_t uid; +{ + struct secretkey_netname_list *l; + + for (l = g_secretkey_netname; l != NULL; l = l->next) { + if (l->uid == uid) { + return (l->keynetdata.st_priv_key); + } + } + return (NULL); +} + +/* + * Store the secretkey for this uid + */ +static int +storesecretkey(uid, key) + uid_t uid; + keybuf key; +{ + struct secretkey_netname_list *new; + struct secretkey_netname_list **l; + + for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid; + l = &(*l)->next) { + } + if (*l == NULL) { + new = (struct secretkey_netname_list *) malloc(sizeof (*new)); + if (new == NULL) { + return (0); + } + new->uid = uid; + new->sc_flag = KEY_ONLY; + memset(new->keynetdata.st_pub_key, 0, HEXKEYBYTES); + new->keynetdata.st_netname = NULL; + new->next = NULL; + *l = new; + } else { + new = *l; + } + + memcpy(new->keynetdata.st_priv_key, key, + HEXKEYBYTES); + return (1); +} + +static int +hexdigit(val) + int val; +{ + return ("0123456789abcdef"[val]); +} + +void +bin2hex(bin, hex, size) + unsigned char *bin; + unsigned char *hex; + int size; +{ + int i; + + for (i = 0; i < size; i++) { + *hex++ = hexdigit(*bin >> 4); + *hex++ = hexdigit(*bin++ & 0xf); + } +} + +static int +hexval(dig) + char dig; +{ + if ('0' <= dig && dig <= '9') { + return (dig - '0'); + } else if ('a' <= dig && dig <= 'f') { + return (dig - 'a' + 10); + } else if ('A' <= dig && dig <= 'F') { + return (dig - 'A' + 10); + } else { + return (-1); + } +} + +void +hex2bin(hex, bin, size) + unsigned char *hex; + unsigned char *bin; + int size; +{ + int i; + + for (i = 0; i < size; i++) { + *bin = hexval(*hex++) << 4; + *bin++ |= hexval(*hex++); + } +} + +/* + * Exponential caching management + */ +struct cachekey_list { + keybuf secret; + keybuf public; + des_block deskey; + struct cachekey_list *next; +}; +static struct cachekey_list *g_cachedkeys; + +/* + * cache result of expensive multiple precision exponential operation + */ +static void +writecache(pub, sec, deskey) + char *pub; + char *sec; + des_block *deskey; +{ + struct cachekey_list *new; + + new = (struct cachekey_list *) malloc(sizeof (struct cachekey_list)); + if (new == NULL) { + return; + } + memcpy(new->public, pub, sizeof (keybuf)); + memcpy(new->secret, sec, sizeof (keybuf)); + new->deskey = *deskey; + new->next = g_cachedkeys; + g_cachedkeys = new; +} + +/* + * Try to find the common key in the cache + */ +static int +readcache(pub, sec, deskey) + char *pub; + char *sec; + des_block *deskey; +{ + struct cachekey_list *found; + register struct cachekey_list **l; + +#define cachehit(pub, sec, list) \ + (memcmp(pub, (list)->public, sizeof (keybuf)) == 0 && \ + memcmp(sec, (list)->secret, sizeof (keybuf)) == 0) + + for (l = &g_cachedkeys; (*l) != NULL && !cachehit(pub, sec, *l); + l = &(*l)->next) + ; + if ((*l) == NULL) { + return (0); + } + found = *l; + (*l) = (*l)->next; + found->next = g_cachedkeys; + g_cachedkeys = found; + *deskey = found->deskey; + return (1); +} |