Index: apps/Makefile
===================================================================
RCS file: /home/nickolai/eproc/cvsroot/openssl/apps/Makefile,v
retrieving revision 1.24
diff -u -r1.24 Makefile
--- apps/Makefile	24 Oct 2006 22:14:18 -0000	1.24
+++ apps/Makefile	23 Mar 2007 06:09:11 -0000
@@ -39,7 +39,8 @@
 	ca crl rsa rsautl dsa dsaparam ec ecparam \
 	x509 genrsa gendsa genpkey s_server s_client speed \
 	s_time version pkcs7 crl2pkcs7 sess_id ciphers nseq pkcs12 \
-	pkcs8 pkey pkeyparam pkeyutl spkac smime rand engine ocsp prime ts
+	pkcs8 pkey pkeyparam pkeyutl spkac smime rand engine ocsp prime ts \
+	rsaprocd
 
 PROGS= $(PROGRAM).c
 
@@ -56,7 +57,7 @@
 	x509.o genrsa.o gendsa.o genpkey.o s_server.o s_client.o speed.o \
 	s_time.o $(A_OBJ) $(S_OBJ) $(RAND_OBJ) version.o sess_id.o \
 	ciphers.o nseq.o pkcs12.o pkcs8.o pkey.o pkeyparam.o pkeyutl.o \
-	spkac.o smime.o rand.o engine.o ocsp.o prime.o ts.o
+	spkac.o smime.o rand.o engine.o ocsp.o prime.o ts.o rsaprocd.o
 
 E_SRC=	verify.c asn1pars.c req.c dgst.c dh.c enc.c passwd.c gendh.c errstr.c ca.c \
 	pkcs7.c crl2p7.c crl.c \
@@ -64,7 +65,7 @@
 	x509.c genrsa.c gendsa.c genpkey.c s_server.c s_client.c speed.c \
 	s_time.c $(A_SRC) $(S_SRC) $(RAND_SRC) version.c sess_id.c \
 	ciphers.c nseq.c pkcs12.c pkcs8.c pkey.c pkeyparam.c pkeyutl.c \
-	spkac.c smime.c rand.c engine.c ocsp.c prime.c ts.c
+	spkac.c smime.c rand.c engine.c ocsp.c prime.c ts.c rsaprocd.c
 
 SRC=$(E_SRC)
 
Index: apps/progs.h
===================================================================
RCS file: /home/nickolai/eproc/cvsroot/openssl/apps/progs.h,v
retrieving revision 1.42
diff -u -r1.42 progs.h
--- apps/progs.h	9 Jul 2006 00:53:44 -0000	1.42
+++ apps/progs.h	23 Mar 2007 06:05:59 -0000
@@ -45,6 +45,7 @@
 extern int ocsp_main(int argc,char *argv[]);
 extern int prime_main(int argc,char *argv[]);
 extern int ts_main(int argc,char *argv[]);
+extern int rsaprocd_main(int argc,char *argv[]);
 
 #define FUNC_TYPE_GENERAL	1
 #define FUNC_TYPE_MD		2
@@ -140,6 +141,7 @@
 	{FUNC_TYPE_GENERAL,"ocsp",ocsp_main},
 	{FUNC_TYPE_GENERAL,"prime",prime_main},
 	{FUNC_TYPE_GENERAL,"ts",ts_main},
+	{FUNC_TYPE_GENERAL,"rsaprocd",rsaprocd_main},
 #ifndef OPENSSL_NO_MD2
 	{FUNC_TYPE_MD,"md2",dgst_main},
 #endif
Index: apps/rsaprocd.c
===================================================================
RCS file: apps/rsaprocd.c
diff -N apps/rsaprocd.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ apps/rsaprocd.c	23 Mar 2007 06:20:01 -0000
@@ -0,0 +1,134 @@
+/*
+ * Daemon that holds onto an RSA private key and performs
+ * encryption/decryption requests with it.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <openssl/evp.h>
+#include <openssl/rsa.h>
+#include <openssl/pem.h>
+#include "engines/e_rsaproc.h"
+
+#undef PROG
+#define PROG rsaprocd_main
+#include "apps.h"
+
+static RSA *the_key;
+
+static void
+handle_client(int s)
+{
+    unsigned char pub_e[256], pub_n[256];
+    int pub_e_len, pub_n_len;
+
+    pub_e_len = BN_bn2bin(the_key->e, pub_e);
+    pub_n_len = BN_bn2bin(the_key->n, pub_n);
+
+    write(s, &pub_e_len, sizeof(pub_e_len));
+    write(s, pub_e, pub_e_len);
+    write(s, &pub_n_len, sizeof(pub_n_len));
+    write(s, pub_n, pub_n_len);
+
+    int buflen = 8 * 1024 + 1;	/* How do we pass the buffer size later? */
+    unsigned char *fbuf = malloc(buflen);
+    unsigned char *tbuf = malloc(buflen);
+
+    for (;;) {
+	int op, padding, rval;
+	unsigned int flen, tlen = 0;
+
+	int cc = read(s, &op, sizeof(op));
+	if (cc != sizeof(op))
+	    break;
+
+	cc = read(s, &flen, sizeof(flen));
+	if (cc != sizeof(flen) || flen > buflen)
+	    break;
+
+	cc = read(s, fbuf, flen);
+	if (cc != flen)
+	    break;
+
+	cc = read(s, &padding, sizeof(padding));
+	if (cc != sizeof(padding))
+	    break;
+
+	if (op == rsaproc_encrypt) {
+	    rval = RSA_private_encrypt(flen, fbuf, tbuf, the_key, padding);
+	    if (rval > 0)
+		tlen = rval;
+	} else if (op == rsaproc_decrypt) {
+	    rval = RSA_private_decrypt(flen, fbuf, tbuf, the_key, padding);
+	    if (rval > 0)
+		tlen = BN_num_bytes(the_key->n);
+	} else {
+	    BIO_printf(bio_err, "Unknown op %d\n", op);
+	    break;
+	}
+
+	write(s, &tlen, sizeof(tlen));
+	write(s, tbuf, tlen);
+	write(s, &rval, sizeof(rval));
+    }
+
+    free(fbuf);
+    free(tbuf);
+    close(s);
+}
+
+int
+MAIN(int ac, char **av)
+{
+    if (ac != 3) {
+	BIO_printf(bio_err, "Usage: %s pem-key-file socket-name\n", av[0]);
+	exit(-1);
+    }
+
+    char *pemfile = av[1];
+    BIO *in = BIO_new(BIO_s_file_internal());
+    assert(in);
+
+    BIO_read_filename(in, pemfile);
+    EVP_PKEY *pkey = PEM_read_bio_PrivateKey(in, 0, 0, 0);
+    assert(pkey);
+    assert(pkey->type == EVP_PKEY_RSA || pkey->type == EVP_PKEY_RSA2);
+    the_key = pkey->pkey.rsa;
+
+    int fd = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (fd < 0) {
+	perror("socket");
+	return -1;
+    }
+
+    umask(077);		/* make the socket private by default */
+
+    char *sockpath = av[2];
+    struct sockaddr_un sa;
+    sa.sun_family = AF_UNIX;
+    strncpy(sa.sun_path, sockpath, sizeof(sa.sun_path));
+    if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+	perror("bind");
+	return -1;
+    }
+
+    if (listen(fd, 5) < 0) {
+	perror("listen");
+	return -1;
+    }
+
+    for (;;) {
+	int len = sizeof(sa);
+	int s = accept(fd, (struct sockaddr *) &sa, &len);
+	if (s < 0) {
+	    perror("accept");
+	    continue;
+	}
+
+	handle_client(s);
+    }
+}
Index: crypto/engine/eng_all.c
===================================================================
RCS file: /home/nickolai/eproc/cvsroot/openssl/crypto/engine/eng_all.c,v
retrieving revision 1.15
diff -u -r1.15 eng_all.c
--- crypto/engine/eng_all.c	29 Dec 2006 10:55:43 -0000	1.15
+++ crypto/engine/eng_all.c	23 Mar 2007 06:02:16 -0000
@@ -108,6 +108,7 @@
 #ifndef OPENSSL_NO_GMP
 	ENGINE_load_gmp();
 #endif
+	ENGINE_load_rsaproc();
 #endif
 	}
 
Index: crypto/engine/engine.h
===================================================================
RCS file: /home/nickolai/eproc/cvsroot/openssl/crypto/engine/engine.h,v
retrieving revision 1.71
diff -u -r1.71 engine.h
--- crypto/engine/engine.h	29 Dec 2006 10:55:43 -0000	1.71
+++ crypto/engine/engine.h	23 Mar 2007 06:02:08 -0000
@@ -338,6 +338,7 @@
 void ENGINE_load_gost(void);
 #endif
 #endif
+void ENGINE_load_rsaproc(void);
 void ENGINE_load_cryptodev(void);
 void ENGINE_load_builtin_engines(void);
 
Index: engines/Makefile
===================================================================
RCS file: /home/nickolai/eproc/cvsroot/openssl/engines/Makefile,v
retrieving revision 1.17
diff -u -r1.17 Makefile
--- engines/Makefile	29 Dec 2006 10:42:24 -0000	1.17
+++ engines/Makefile	23 Mar 2007 06:02:26 -0000
@@ -26,7 +26,7 @@
 APPS=
 
 LIB=$(TOP)/libcrypto.a
-LIBNAMES= 4758cca aep atalla cswift gmp chil nuron sureware ubsec padlock
+LIBNAMES= 4758cca aep atalla cswift gmp chil nuron sureware ubsec padlock rsaproc
 
 LIBSRC=	e_4758cca.c \
 	e_aep.c \
@@ -37,7 +37,8 @@
 	e_nuron.c \
 	e_sureware.c \
 	e_ubsec.c \
-	e_padlock.c
+	e_padlock.c \
+	e_rsaproc.c
 LIBOBJ= e_4758cca.o \
 	e_aep.o \
 	e_atalla.o \
@@ -47,7 +48,8 @@
 	e_nuron.o \
 	e_sureware.o \
 	e_ubsec.o \
-	e_padlock.o
+	e_padlock.o \
+	e_rsaproc.o
 
 SRC= $(LIBSRC)
 
Index: engines/e_rsaproc.c
===================================================================
RCS file: engines/e_rsaproc.c
diff -N engines/e_rsaproc.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ engines/e_rsaproc.c	23 Mar 2007 06:14:57 -0000
@@ -0,0 +1,158 @@
+/*
+ * Software RSA engine, using IPC into another process
+ * that keeps the RSA private key.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <openssl/evp.h>
+#include <openssl/rsa.h>
+#include <openssl/engine.h>
+#include "e_rsaproc.h"
+
+static int rsa_key_handle;
+
+static EVP_PKEY *
+rsaproc_load_privkey(ENGINE *e, const char *key_id,
+		     UI_METHOD *ui_method, void *callback_data)
+{
+    const char *sockpath = key_id;
+
+    int fd = socket(AF_UNIX, SOCK_STREAM, 0);
+    if (fd < 0) {
+	perror("rsaproc_load_privkey::socket");
+	return 0;
+    }
+
+    struct sockaddr_un sa;
+    sa.sun_family = AF_UNIX;
+    strncpy(sa.sun_path, sockpath, sizeof(sa.sun_path));
+    if (connect(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+	perror("rsaproc_load_privkey::connect");
+	close(fd);
+	return 0;
+    }
+
+    unsigned int pub_len[2];
+    unsigned char pub_val[2][256];
+    int i;
+    for (i = 0; i < 2; i++) {
+	int cc = read(fd, &pub_len[i], sizeof(pub_len[i]));
+	if (cc != sizeof(pub_len[i]) || pub_len[i] > sizeof(pub_val[i])) {
+	    fprintf(stderr, "rsaproc_load_privkey: size mismatch %d %d %d\n",
+			    cc, sizeof(pub_len[i]), pub_len[i]);
+	    close(fd);
+	    return 0;
+	}
+
+	int done = 0;
+	while (done != pub_len[i]) {
+	    cc = read(fd, &pub_val[i][done], pub_len[i] - done);
+	    if (cc <= 0) {
+		fprintf(stderr, "rsaproc_load_privkey: read %d len %d done %d\n",
+				cc, pub_len[i], done);
+		close(fd);
+		return 0;
+	    }
+	    done += cc;
+	}
+    }
+
+    RSA *rsa = RSA_new_method(e);
+    RSA_set_ex_data(rsa, rsa_key_handle, (char *) (long) fd);
+    rsa->e = BN_bin2bn(pub_val[0], pub_len[0], 0);
+    rsa->n = BN_bin2bn(pub_val[1], pub_len[1], 0);
+
+    EVP_PKEY *res = EVP_PKEY_new();
+    EVP_PKEY_assign_RSA(res, rsa);
+
+    return res;
+}
+
+static int
+rsaproc_rsa_op(int flen, const unsigned char *from,
+	       unsigned char *to, RSA *rsa, int padding, int op)
+{
+    int fd = (long) RSA_get_ex_data(rsa, rsa_key_handle);
+
+    write(fd, &op, sizeof(op));
+    write(fd, &flen, sizeof(flen));
+    write(fd, from, flen);
+    write(fd, &padding, sizeof(padding));
+
+    int tlen;
+    read(fd, &tlen, sizeof(tlen));
+    read(fd, to, tlen);		/* How do we know the size of "to"? */
+
+    int rval = -1;
+    read(fd, &rval, sizeof(rval));
+    return rval;
+}
+
+static int
+rsaproc_rsa_priv_enc(int flen, const unsigned char *from,
+		     unsigned char *to, RSA *rsa, int padding)
+{
+    return rsaproc_rsa_op(flen, from, to, rsa, padding, rsaproc_encrypt);
+}
+
+static int
+rsaproc_rsa_priv_dec(int flen, const unsigned char *from,
+		     unsigned char *to, RSA *rsa, int padding)
+{
+    return rsaproc_rsa_op(flen, from, to, rsa, padding, rsaproc_decrypt);
+}
+
+static RSA_METHOD rsaproc_rsa = {
+    "rsaproc RSA method",
+    0,	/* rsa_pub_enc */
+    0,	/* rsa_pub_dec */
+    rsaproc_rsa_priv_enc,
+    rsaproc_rsa_priv_dec,
+    0,	/* rsa_mod_exp */
+    0,	/* bn_mod_exp */
+    0,	/* init */
+    0,	/* finish */
+    0,	/* flags */
+    0,	/* app_data */
+    0,	/* rsa_sign */
+    0,	/* rsa_verify */
+    0,	/* rsa_keygen */
+};
+
+static void
+rsaproc_ex_free(void *obj, void *item, CRYPTO_EX_DATA *ad, int idx,
+	        long argl, void *argp)
+{
+    int fd = (long) item;
+    close(fd);
+}
+
+static int
+rsaproc_init(ENGINE *e)
+{
+    rsa_key_handle = RSA_get_ex_new_index(0, "rsaproc key handle",
+					  0, 0, rsaproc_ex_free);
+    return 1;
+}
+
+void
+ENGINE_load_rsaproc(void)
+{
+    ENGINE *e = ENGINE_new();
+    if (!e)
+	return;
+
+    if (!ENGINE_set_id(e, "rsaproc") ||
+	!ENGINE_set_name(e, "RSA process engine") ||
+	!ENGINE_set_RSA(e, &rsaproc_rsa) ||
+	!ENGINE_set_init_function(e, rsaproc_init) ||
+	!ENGINE_set_load_privkey_function(e, rsaproc_load_privkey))
+	return;
+
+    ENGINE_add(e);
+    ENGINE_free(e);
+    ERR_clear_error();
+}
Index: engines/e_rsaproc.h
===================================================================
RCS file: engines/e_rsaproc.h
diff -N engines/e_rsaproc.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ engines/e_rsaproc.h	23 Mar 2007 06:02:52 -0000
@@ -0,0 +1,9 @@
+#ifndef ENGINE_E_RSAPROC_H
+#define ENGINE_E_RSAPROC_H
+
+enum rsaproc_opcode {
+    rsaproc_encrypt,
+    rsaproc_decrypt,
+};
+
+#endif
