summaryrefslogtreecommitdiffstats
path: root/lib/librpc/secure_rpc/keyserv/setkey.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/librpc/secure_rpc/keyserv/setkey.c')
-rw-r--r--lib/librpc/secure_rpc/keyserv/setkey.c514
1 files changed, 514 insertions, 0 deletions
diff --git a/lib/librpc/secure_rpc/keyserv/setkey.c b/lib/librpc/secure_rpc/keyserv/setkey.c
new file mode 100644
index 0000000..d62dc9c
--- /dev/null
+++ b/lib/librpc/secure_rpc/keyserv/setkey.c
@@ -0,0 +1,514 @@
+#ifndef lint
+static char sccsid[] = "@(#)setkey.c 2.2 88/08/10 4.0 RPCSRC; from Copyr 1988 Sun Micro";
+#endif
+/*
+ * 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
+ */
+
+/*
+ * Copyright (C) 1986, 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 <sys/file.h>
+#include <mp.h>
+#include <rpc/rpc.h>
+#include <rpc/key_prot.h>
+#include <des_crypt.h>
+#include <sys/errno.h>
+
+extern char *malloc();
+extern char ROOTKEY[];
+
+static MINT *MODULUS;
+static char *fetchsecretkey();
+static keystatus pk_crypt();
+
+
+/*
+ * Set the modulus for all our Diffie-Hellman operations
+ */
+setmodulus(modx)
+ char *modx;
+{
+ MODULUS = xtom(modx);
+}
+
+
+/*
+ * Set the secretkey key for this uid
+ */
+keystatus
+pk_setkey(uid, skey)
+ short 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, key)
+ short uid;
+ char *remote_name;
+ des_block *key;
+{
+ return (pk_crypt(uid, remote_name, 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, key)
+ short uid;
+ char *remote_name;
+ des_block *key;
+{
+ return (pk_crypt(uid, remote_name, key, DES_DECRYPT));
+}
+
+
+/*
+ * Do the work of pk_encrypt && pk_decrypt
+ */
+static keystatus
+pk_crypt(uid, remote_name, key, mode)
+ short uid;
+ char *remote_name;
+ des_block *key;
+ int mode;
+{
+ char *xsecret;
+ char xpublic[HEXKEYBYTES + 1];
+ char xsecret_hold[HEXKEYBYTES + 1];
+ des_block deskey;
+ int err;
+ MINT *public;
+ MINT *secret;
+ MINT *common;
+ char zero[8];
+
+ xsecret = fetchsecretkey(uid);
+ if (xsecret == NULL) {
+ bzero(zero, sizeof(zero));
+ xsecret = xsecret_hold;
+ if (!getsecretkey("nobody", xsecret, zero) ||
+ xsecret[0] == 0) {
+ return (KEY_NOSECRET);
+ }
+ }
+ if (!getpublickey(remote_name, xpublic) &&
+ !getpublickey("nobody", xpublic)) {
+ return (KEY_UNKNOWN);
+ }
+ if (!readcache(xpublic, xsecret, &deskey)) {
+ public = xtom(xpublic);
+ secret = xtom(xsecret);
+ common = itom(0);
+ pow(public, secret, MODULUS, common);
+ extractdeskey(common, &deskey);
+ writecache(xpublic, xsecret, &deskey);
+ mfree(secret);
+ mfree(public);
+ mfree(common);
+ }
+ err = ecb_crypt(&deskey, key, sizeof(des_block), DES_HW | mode);
+ if (DES_FAILED(err)) {
+ return (KEY_SYSTEMERR);
+ }
+ 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
+extractdeskey(ck, deskey)
+ MINT *ck;
+ des_block *deskey;
+{
+ MINT *a;
+ short r;
+ int i;
+ short base = (1 << 8);
+ char *k;
+
+
+ a = itom(0);
+ move(ck, a);
+ 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(deskey);
+}
+
+
+/*
+ * Key storage management
+ */
+
+struct secretkey_list {
+ short uid;
+ char secretkey[HEXKEYBYTES+1];
+ struct secretkey_list *next;
+};
+
+static struct secretkey_list *g_secretkeys;
+
+/*
+ * Fetch the secret key for this uid
+ */
+static char *
+fetchsecretkey(uid)
+ short uid;
+{
+ struct secretkey_list *l;
+
+ for (l = g_secretkeys; l != NULL; l = l->next) {
+ if (l->uid == uid) {
+ return (l->secretkey);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * Store the secretkey for this uid
+ */
+storesecretkey(uid, key)
+ short uid;
+ keybuf key;
+{
+ struct secretkey_list *new;
+ struct secretkey_list **l;
+ int nitems;
+
+
+ nitems = 0;
+ for (l = &g_secretkeys; *l != NULL && (*l)->uid != uid;
+ l = &(*l)->next) {
+ nitems++;
+ }
+ if (*l == NULL) {
+ new = (struct secretkey_list *)malloc(sizeof(*new));
+ if (new == NULL) {
+ return (0);
+ }
+ new->uid = uid;
+ new->next = NULL;
+ *l = new;
+ } else {
+ new = *l;
+ }
+ bcopy(key, new->secretkey, HEXKEYBYTES);
+ new->secretkey[HEXKEYBYTES] = 0;
+ seekitem(nitems);
+ writeitem(uid, new->secretkey);
+ return (1);
+}
+
+
+hexdigit(val)
+ int val;
+{
+ return ("0123456789abcdef"[val]);
+
+}
+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);
+ }
+}
+
+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);
+ }
+}
+
+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++);
+ }
+}
+
+static char KEYSTORE[] = "/etc/keystore";
+FILE *kf;
+
+openstore()
+{
+ kf = fopen(KEYSTORE, "r+");
+ if (kf == NULL) {
+ kf = fopen(KEYSTORE, "w+");
+ if (kf == NULL) {
+ return (0);
+ }
+ }
+ setbuf(kf, NULL);
+ return (1);
+}
+
+static char rootkey[KEYBYTES];
+static int haverootkey;
+struct storedkey {
+ short uid;
+ char crypt[KEYBYTES];
+};
+
+readkeys()
+{
+ struct secretkey_list *node;
+ struct secretkey_list **l;
+ int uid;
+ char secretkey[HEXKEYBYTES+1];
+
+ if (kf == NULL) {
+ return;
+ }
+ l = &g_secretkeys;
+ seekitem(0);
+ while (readitem(&uid, secretkey)) {
+ node = (struct secretkey_list *)malloc(sizeof(*node));
+ if (node == NULL) {
+ return;
+ }
+ node->uid = uid;
+ bcopy(secretkey, node->secretkey, HEXKEYBYTES + 1);
+ node->next = NULL;
+ *l = node;
+ l = &node->next;
+ }
+}
+
+writekeys()
+{
+ struct secretkey_list *k;
+
+ seekitem(0);
+ for (k = g_secretkeys; k != NULL; k = k->next) {
+ writeitem(k->uid, k->secretkey);
+ }
+}
+
+seekitem(item)
+ int item;
+{
+ if (kf != NULL) {
+ fseek(kf, item * sizeof(struct storedkey), 0);
+ }
+}
+
+writeitem(uid, key)
+ int uid;
+ char *key;
+{
+ struct storedkey item;
+ char rootkey_tmp[KEYBYTES];
+ int reencrypt;
+
+ if (kf == NULL) {
+ return (1);
+ }
+ if (uid == 0) {
+ writerootkey(key);
+ hex2bin(key, rootkey_tmp, KEYBYTES);
+ reencrypt = (haverootkey &&
+ bcmp(rootkey, rootkey_tmp, KEYBYTES) != 0);
+ bcopy(rootkey_tmp, rootkey, KEYBYTES);
+ haverootkey = 1;
+ if (reencrypt) {
+ writekeys();
+ return (1);
+ }
+ }
+ if (!haverootkey) {
+ return (1);
+ }
+ item.uid = uid;
+ hex2bin(key, item.crypt, KEYBYTES);
+ ecb_crypt(rootkey, item.crypt, KEYBYTES, DES_ENCRYPT|DES_HW);
+ return (fwrite(&item, sizeof(item), 1, kf) >= 0);
+}
+
+
+readitem(uidp, key)
+ int *uidp;
+ char *key;
+{
+ struct storedkey item;
+
+ if (!haverootkey || kf == NULL) {
+ return (0);
+ }
+ if (fread(&item, sizeof(item), 1, kf) != 1) {
+ return (0);
+ }
+ *uidp = item.uid;
+ ecb_crypt(rootkey, item.crypt, KEYBYTES, DES_DECRYPT|DES_HW);
+ bin2hex(item.crypt, key, KEYBYTES);
+ key[HEXKEYBYTES] = 0;
+ return (1);
+}
+
+/*
+ * Root users store their key in /etc/$ROOTKEY so
+ * that they can auto reboot without having to be
+ * around to type a password. Storing this in a file
+ * is rather dubious: it should really be in the EEPROM
+ * so it does not go over the net for diskless machines.
+ */
+writerootkey(secret)
+ char *secret;
+{
+ char newline = '\n';
+ int fd;
+
+ fd = open(ROOTKEY, O_WRONLY|O_TRUNC|O_CREAT, 0);
+ if (fd < 0) {
+ perror(ROOTKEY);
+ } else {
+ if (write(fd, secret, strlen(secret)) < 0 ||
+ write(fd, &newline, sizeof(newline)) < 0) {
+ (void)fprintf(stderr, "%s: ", ROOTKEY);
+ perror("write");
+ }
+ close(fd);
+ }
+}
+
+
+/*
+ * 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
+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;
+ }
+ bcopy(pub, new->public, sizeof(keybuf));
+ bcopy(sec, new->secret, sizeof(keybuf));
+ new->deskey = *deskey;
+ new->next = g_cachedkeys;
+ g_cachedkeys = new;
+}
+
+/*
+ * Try to find the common key in the cache
+ */
+static
+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) \
+ (bcmp(pub, (list)->public, sizeof(keybuf)) == 0 && \
+ bcmp(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);
+}
OpenPOWER on IntegriCloud