A new user interface for you! Read more...

File 0003-OpenSSL-1.1-compatibility.patch of Package openssl_tpm_engine

From ade88cc6abb7b389f8d73efd7700f284953e8d81 Mon Sep 17 00:00:00 2001
From: Matthias Gerstner <mgerstner@suse.de>
Date: Thu, 30 Nov 2017 18:29:44 +0100
Subject: [PATCH] OpenSSL 1.1 compatibility

support compiling against both OpenSSL 1.0 and OpenSSL 1.1 by means of
suitable wrapper functions.
---
 create_tpm_key.c          |  11 ++-
 e_tpm.c                   | 113 ++++++++++++---------
 e_tpm_err.c               |   1 -
 ssl_compat.h              | 243 ++++++++++++++++++++++++++++++++++++++++++++++
 test/Makefile.am          |   1 +
 test/engine_key_loading.c |  22 +++--
 6 files changed, 336 insertions(+), 55 deletions(-)
 create mode 100644 ssl_compat.h

diff --git a/create_tpm_key.c b/create_tpm_key.c
index fee917f..a73d549 100644
--- a/create_tpm_key.c
+++ b/create_tpm_key.c
@@ -46,6 +46,8 @@
 #include <trousers/tss.h>
 #include <trousers/trousers.h>
 
+#include "ssl_compat.h"
+
 #define print_error(a,b) \
 	fprintf(stderr, "%s:%d %s result: 0x%x (%s)\n", __FILE__, __LINE__, \
 		a, b, Trspi_Error_String(b))
@@ -115,14 +117,19 @@ int
 openssl_get_modulus_and_prime(RSA *rsa, unsigned int *size_n, unsigned char *n,
 			      unsigned int *size_p, unsigned char *p)
 {
+	const BIGNUM *bn_n = NULL, *bn_p = NULL;
+
+	RSA_get0_key(rsa, &bn_n, NULL, NULL);
+	RSA_get0_factors(rsa, &bn_p, NULL);
+
 	/* get the modulus from the RSA object */
-	if ((*size_n = BN_bn2bin(rsa->n, n)) <= 0) {
+	if ((*size_n = BN_bn2bin(bn_n, n)) <= 0) {
 		openssl_print_errors();
 		return -1;
 	}
 
 	/* get one of the primes from the RSA object */
-	if ((*size_p = BN_bn2bin(rsa->p, p)) <= 0) {
+	if ((*size_p = BN_bn2bin(bn_p, p)) <= 0) {
 		openssl_print_errors();
 		return -1;
 	}
diff --git a/e_tpm.c b/e_tpm.c
index 0ebf636..f671771 100644
--- a/e_tpm.c
+++ b/e_tpm.c
@@ -19,7 +19,6 @@
 #include <string.h>
 
 #include <openssl/crypto.h>
-#include <openssl/dso.h>
 #include <openssl/engine.h>
 #include <openssl/evp.h>
 #include <openssl/objects.h>
@@ -37,6 +36,7 @@
 #include <trousers/trousers.h>  // XXX DEBUG
 
 #include "e_tpm.h"
+#include "ssl_compat.h"
 
 //#define DLOPEN_TSPI
 
@@ -66,7 +66,7 @@ static int tpm_rsa_keygen(RSA *, int, BIGNUM *, BN_GENCB *);
 /* random functions */
 static int tpm_rand_bytes(unsigned char *, int);
 static int tpm_rand_status(void);
-static void tpm_rand_seed(const void *, int);
+static RAND_SEED_RET_TYPE tpm_rand_seed(const void *, int);
 
 /* The definitions for control commands specific to this engine */
 #define TPM_CMD_SO_PATH		ENGINE_CMD_BASE
@@ -88,24 +88,8 @@ static const ENGINE_CMD_DEFN tpm_cmd_defns[] = {
 	{0, NULL, NULL, 0}
 };
 
-#ifndef OPENSSL_NO_RSA
-static RSA_METHOD tpm_rsa = {
-	"TPM RSA method",
-	tpm_rsa_pub_enc,
-	tpm_rsa_pub_dec,
-	tpm_rsa_priv_enc,
-	tpm_rsa_priv_dec,
-	NULL, /* set in tpm_engine_init */
-	BN_mod_exp_mont,
-	tpm_rsa_init,
-	tpm_rsa_finish,
-	(RSA_FLAG_SIGN_VER | RSA_FLAG_NO_BLINDING),
-	NULL,
-	NULL, /* sign */
-	NULL, /* verify */
-	tpm_rsa_keygen
-};
-#endif
+static RSA_METHOD *tpm_rsa;
+static const RSA_METHOD *ssl_rsa;
 
 static RAND_METHOD tpm_rand = {
 	/* "TPM RAND method", */
@@ -195,14 +179,44 @@ static unsigned int (*p_tspi_Policy_AssignToObject)();
 #define Tspi_Policy_AssignToObject p_tspi_Policy_AssignToObject
 #endif /* DLOPEN_TSPI */
 
+static int setup_rsa_method()
+{
+	tpm_rsa = RSA_meth_new("TPM RSA method", 0);
+	if (tpm_rsa == NULL)
+		return 0;
+
+	if (!RSA_meth_set_flags(tpm_rsa,
+				RSA_FLAG_SIGN_VER | RSA_FLAG_NO_BLINDING) ||
+	    !RSA_meth_set_pub_enc(tpm_rsa, tpm_rsa_pub_enc) ||
+	    !RSA_meth_set_pub_dec(tpm_rsa, tpm_rsa_pub_dec) ||
+	    !RSA_meth_set_priv_enc(tpm_rsa, tpm_rsa_priv_enc) ||
+	    !RSA_meth_set_priv_dec(tpm_rsa, tpm_rsa_priv_dec) ||
+	    !RSA_meth_set_bn_mod_exp(tpm_rsa, BN_mod_exp_mont) ||
+	    !RSA_meth_set_init(tpm_rsa, tpm_rsa_init) ||
+	    !RSA_meth_set_finish(tpm_rsa, tpm_rsa_finish) ||
+	    !RSA_meth_set_keygen(tpm_rsa, tpm_rsa_keygen))
+	{
+		RSA_meth_free(tpm_rsa);
+		tpm_rsa = NULL;
+		return 0;
+	}
+
+	return 1;
+}
+
 /* This internal function is used by ENGINE_tpm() and possibly by the
  * "dynamic" ENGINE support too */
 static int bind_helper(ENGINE * e)
 {
+	if (!setup_rsa_method())
+		return 0;
+
+	ssl_rsa = RSA_PKCS1_OpenSSL();
+
 	if (!ENGINE_set_id(e, engine_tpm_id) ||
 	    !ENGINE_set_name(e, engine_tpm_name) ||
 #ifndef OPENSSL_NO_RSA
-	    !ENGINE_set_RSA(e, &tpm_rsa) ||
+	    !ENGINE_set_RSA(e, tpm_rsa) ||
 #endif
 	    !ENGINE_set_RAND(e, &tpm_rand) ||
 	    !ENGINE_set_destroy_function(e, tpm_engine_destroy) ||
@@ -399,7 +413,7 @@ static int tpm_engine_init(ENGINE * e)
 		goto err;
 	}
 
-	tpm_rsa.rsa_mod_exp = RSA_PKCS1_SSLeay()->rsa_mod_exp;
+	RSA_meth_set_mod_exp(tpm_rsa, RSA_meth_get_mod_exp(ssl_rsa));
 
 	return 1;
 err:
@@ -491,6 +505,8 @@ static int tpm_engine_finish(ENGINE * e)
 	}
 	tpm_dso = NULL;
 #endif
+	RSA_meth_free(tpm_rsa);
+	tpm_rsa = NULL;
 	return 1;
 }
 
@@ -500,6 +516,7 @@ int fill_out_rsa_object(RSA *rsa, TSS_HKEY hKey)
 	UINT32 pubkey_len, encScheme, sigScheme;
 	BYTE *pubkey;
 	struct rsa_app_data *app_data;
+	BIGNUM *e = NULL, *n = NULL;
 
 	DBG("%s", __FUNCTION__);
 
@@ -525,7 +542,7 @@ int fill_out_rsa_object(RSA *rsa, TSS_HKEY hKey)
 		return 0;
 	}
 
-	if ((rsa->n = BN_bin2bn(pubkey, pubkey_len, rsa->n)) == NULL) {
+	if ((n = BN_bin2bn(pubkey, pubkey_len, n)) == NULL) {
 		Tspi_Context_FreeMemory(hContext, pubkey);
 		TSSerr(TPM_F_TPM_FILL_RSA_OBJECT, TPM_R_BN_CONVERSION_FAILED);
 		return 0;
@@ -534,23 +551,24 @@ int fill_out_rsa_object(RSA *rsa, TSS_HKEY hKey)
 	Tspi_Context_FreeMemory(hContext, pubkey);
 
 	/* set e in the RSA object */
-	if (!rsa->e && ((rsa->e = BN_new()) == NULL)) {
+	if (((e = BN_new()) == NULL)) {
 		TSSerr(TPM_F_TPM_FILL_RSA_OBJECT, ERR_R_MALLOC_FAILURE);
-		return 0;
+		goto err;
 	}
 
-	if (!BN_set_word(rsa->e, 65537)) {
+	if (!BN_set_word(e, 65537)) {
 		TSSerr(TPM_F_TPM_FILL_RSA_OBJECT, TPM_R_REQUEST_FAILED);
-		BN_free(rsa->e);
-		rsa->e = NULL;
-		return 0;
+		goto err;
 	}
 
 	if ((app_data = OPENSSL_malloc(sizeof(struct rsa_app_data))) == NULL) {
 		TSSerr(TPM_F_TPM_FILL_RSA_OBJECT, ERR_R_MALLOC_FAILURE);
-		BN_free(rsa->e);
-		rsa->e = NULL;
-		return 0;
+		goto err;
+	}
+
+	if (RSA_set0_key(rsa, n, e, NULL) == 0) {
+		TSSerr(TPM_F_TPM_FILL_RSA_OBJECT, TPM_R_REQUEST_FAILED);
+		goto err;
 	}
 
 	DBG("Setting hKey(0x%x) in RSA object", hKey);
@@ -564,6 +582,12 @@ int fill_out_rsa_object(RSA *rsa, TSS_HKEY hKey)
 	RSA_set_ex_data(rsa, ex_app_data, app_data);
 
 	return 1;
+err:
+	if (e)
+		BN_free(e);
+	if (n)
+		BN_free(n);
+	return 0;
 }
 
 static EVP_PKEY *tpm_engine_load_key(ENGINE *e, const char *key_id,
@@ -681,7 +705,6 @@ static EVP_PKEY *tpm_engine_load_key(ENGINE *e, const char *key_id,
 		TSSerr(TPM_F_TPM_ENGINE_LOAD_KEY, ERR_R_MALLOC_FAILURE);
 		return NULL;
 	}
-	pkey->type = EVP_PKEY_RSA;
 
 	if ((rsa = RSA_new()) == NULL) {
 		EVP_PKEY_free(pkey);
@@ -689,10 +712,8 @@ static EVP_PKEY *tpm_engine_load_key(ENGINE *e, const char *key_id,
 		TSSerr(TPM_F_TPM_ENGINE_LOAD_KEY, ERR_R_MALLOC_FAILURE);
 		return NULL;
 	}
-	rsa->meth = &tpm_rsa;
-	/* call our local init function here */
-	rsa->meth->init(rsa);
-	pkey->pkey.rsa = rsa;
+
+	RSA_set_method(rsa, tpm_rsa);
 
 	if (!fill_out_rsa_object(rsa, hKey)) {
 		EVP_PKEY_free(pkey);
@@ -841,8 +862,8 @@ static int tpm_rsa_pub_dec(int flen,
 
 	DBG("%s", __FUNCTION__);
 
-	if ((rv = RSA_PKCS1_SSLeay()->rsa_pub_dec(flen, from, to, rsa,
-						  padding)) < 0) {
+	if ((rv = RSA_meth_get_pub_dec(ssl_rsa)(
+					flen, from, to, rsa, padding)) < 0) {
 		TSSerr(TPM_F_TPM_RSA_PUB_DEC, TPM_R_REQUEST_FAILED);
 		return 0;
 	}
@@ -867,7 +888,7 @@ static int tpm_rsa_priv_dec(int flen,
 	if (!app_data) {
 		DBG("No app data found for RSA object %p. Calling software.",
 		    rsa);
-		if ((rv = RSA_PKCS1_SSLeay()->rsa_priv_dec(flen, from, to, rsa,
+		if ((rv = RSA_meth_get_priv_dec(ssl_rsa)(flen, from, to, rsa,
 						padding)) < 0) {
 			TSSerr(TPM_F_TPM_RSA_PRIV_DEC, TPM_R_REQUEST_FAILED);
 		}
@@ -944,7 +965,7 @@ static int tpm_rsa_pub_enc(int flen,
 	if (!app_data) {
 		DBG("No app data found for RSA object %p. Calling software.",
 		    rsa);
-		if ((rv = RSA_PKCS1_SSLeay()->rsa_pub_enc(flen, from, to, rsa,
+		if ((rv = RSA_meth_get_pub_enc(ssl_rsa)(flen, from, to, rsa,
 						padding)) < 0) {
 			TSSerr(TPM_F_TPM_RSA_PUB_ENC, TPM_R_REQUEST_FAILED);
 		}
@@ -1051,8 +1072,8 @@ static int tpm_rsa_priv_enc(int flen,
 	if (!app_data) {
 		DBG("No app data found for RSA object %p. Calling software.",
 		    rsa);
-		if ((rv = RSA_PKCS1_SSLeay()->rsa_priv_enc(flen, from, to, rsa,
-							   padding)) < 0) {
+		if ((rv = RSA_meth_get_priv_enc(ssl_rsa)(flen, from, to, rsa,
+						padding)) < 0) {
 			TSSerr(TPM_F_TPM_RSA_PRIV_ENC, TPM_R_REQUEST_FAILED);
 		}
 
@@ -1254,7 +1275,7 @@ static int tpm_rand_status(void)
 	return 1;
 }
 
-static void tpm_rand_seed(const void *buf, int num)
+static RAND_SEED_RET_TYPE tpm_rand_seed(const void *buf, int num)
 {
 	TSS_RESULT result;
 	UINT32 total_stirred = 0;
@@ -1267,7 +1288,7 @@ static void tpm_rand_seed(const void *buf, int num)
 		if ((result = Tspi_TPM_StirRandom(hTPM, 255,
 						((BYTE*)buf) + total_stirred))) {
 			TSSerr(TPM_F_TPM_RAND_SEED, TPM_R_REQUEST_FAILED);
-			return;
+			return RAND_SEED_BAD_RETURN;
 		}
 
 		total_stirred += 255;
@@ -1278,7 +1299,7 @@ static void tpm_rand_seed(const void *buf, int num)
 		TSSerr(TPM_F_TPM_RAND_SEED, TPM_R_REQUEST_FAILED);
 	}
 
-	return;
+	return RAND_SEED_GOOD_RETURN;
 }
 
 /* This stuff is needed if this ENGINE is being compiled into a self-contained
diff --git a/e_tpm_err.c b/e_tpm_err.c
index 25a5d0f..c913dff 100644
--- a/e_tpm_err.c
+++ b/e_tpm_err.c
@@ -18,7 +18,6 @@
 #include <stdio.h>
 
 #include <openssl/err.h>
-#include <openssl/dso.h>
 #include <openssl/engine.h>
 
 #include <tss/platform.h>
diff --git a/ssl_compat.h b/ssl_compat.h
new file mode 100644
index 0000000..b332a85
--- /dev/null
+++ b/ssl_compat.h
@@ -0,0 +1,243 @@
+#ifndef _SSL_COMPAT_H
+#define _SSL_COMPAT_H
+
+// C std. headers
+#include <stdlib.h>
+
+// OpenSSL
+#include <openssl/rsa.h>
+#include <openssl/opensslv.h>
+
+/*
+ * Matthias Gerstner
+ * Copyright (C) SUSE Linux GmbH 2017
+ * mgerstner@suse.de
+ *
+ * This header provides a compatibility layer for being able to compile
+ * against OpenSSL 1.0 as well as OpenSSL 1.1 versions. In OpenSSL 1.1 various
+ * data structures have been made opaque and can no longer be accessed
+ * directly.
+ *
+ * This header provides wrapper functions that do the right thing
+ */
+
+#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
+#	define USE_OPENSSL_OPAQUE_API
+#	define HAVE_OPENSSL_110
+// this flag was removed in 1.1.0, no longer needed, see commit OpenSSL
+// 19c6d3ea2d3b4e0ad3e978e42cc7cbdf0c09891f
+#	define RSA_FLAG_SIGN_VER 0
+#endif
+
+/*
+ * the RAND_METHOD seed function has got an error return type in OpenSSL
+ * 1.1.0.
+ *
+ * these defines help dealing with it.
+ */
+#ifdef HAVE_OPENSSL_110
+#	define RAND_SEED_RET_TYPE int
+#	define RAND_SEED_GOOD_RETURN 1
+#	define RAND_SEED_BAD_RETURN 0
+#else
+#	define RAND_SEED_RET_TYPE void
+#	define RAND_SEED_GOOD_RETURN
+#	define RAND_SEED_BAD_RETURN
+#endif
+
+/*
+ * callback function pointer typedefs
+ */
+
+typedef int (*func_rsa_pub_enc)(int, const unsigned char *, unsigned char *,
+		RSA *, int);
+typedef int (*func_rsa_pub_dec)(int, const unsigned char *, unsigned char *,
+		RSA *, int);
+typedef int (*func_rsa_priv_enc)(int, const unsigned char *, unsigned char *,
+		RSA *, int);
+typedef int (*func_rsa_priv_dec)(int, const unsigned char *, unsigned char *,
+		RSA *, int);
+typedef int (*func_rsa_mod_exp)(BIGNUM *r0, const BIGNUM *I, RSA *rsa,
+		BN_CTX *ctx);
+typedef int (*func_rsa_bn_mod_exp)(BIGNUM *, const BIGNUM *, const BIGNUM *,
+	       const BIGNUM *, BN_CTX *, BN_MONT_CTX *);
+typedef int (*func_rsa_init)(RSA *rsa);
+typedef int (*func_rsa_finish)(RSA *rsa);
+typedef int (*func_rsa_keygen)(RSA *, int, BIGNUM *, BN_GENCB *);
+
+/*
+ * wrapper functions which provide the OpenSSL 1.1 accessor functions to
+ * OpenSSL 1.0.
+ */
+
+#ifndef USE_OPENSSL_OPAQUE_API
+RSA_METHOD* RSA_meth_new(const char *name, int flags)
+{
+	RSA_METHOD *ret = malloc(sizeof(RSA_METHOD));
+	if (ret) {
+		ret->name = name;
+		ret->flags = flags;
+	}
+
+	return ret;
+}
+
+void RSA_meth_free(RSA_METHOD *meth)
+{
+	free(meth);
+}
+
+int RSA_meth_set_flags(RSA_METHOD *method, int flags)
+{
+	method->flags = flags;
+	return 1;
+}
+
+int RSA_meth_set_pub_enc(RSA_METHOD *method, func_rsa_pub_enc pub_enc)
+{
+	method->rsa_pub_enc = pub_enc;
+	return 1;
+}
+
+func_rsa_pub_enc RSA_meth_get_pub_enc(const RSA_METHOD *method)
+{
+	return method->rsa_pub_enc;
+}
+
+int RSA_meth_set_pub_dec(RSA_METHOD *method, func_rsa_pub_dec pub_dec)
+{
+	method->rsa_pub_dec = pub_dec;
+	return 1;
+}
+
+func_rsa_pub_dec RSA_meth_get_pub_dec(const RSA_METHOD *method)
+{
+	return method->rsa_pub_dec;
+}
+
+int RSA_meth_set_priv_enc(RSA_METHOD *method, func_rsa_priv_enc priv_enc)
+{
+	method->rsa_priv_enc = priv_enc;
+	return 1;
+}
+
+func_rsa_priv_enc RSA_meth_get_priv_enc(const RSA_METHOD *method)
+{
+	return method->rsa_priv_enc;
+}
+
+int RSA_meth_set_priv_dec(RSA_METHOD *method, func_rsa_priv_dec priv_dec)
+{
+	method->rsa_priv_dec = priv_dec;
+	return 1;
+}
+
+func_rsa_priv_dec RSA_meth_get_priv_dec(const RSA_METHOD *method)
+{
+	return method->rsa_priv_dec;
+}
+
+int RSA_meth_set_mod_exp(RSA_METHOD *method, func_rsa_mod_exp mod_exp)
+{
+	method->rsa_mod_exp = mod_exp;
+	return 1;
+}
+
+func_rsa_mod_exp RSA_meth_get_mod_exp(const RSA_METHOD *method)
+{
+	return method->rsa_mod_exp;
+}
+
+int RSA_meth_set_bn_mod_exp(RSA_METHOD *method,
+		func_rsa_bn_mod_exp bn_mod_exp)
+{
+	method->bn_mod_exp = bn_mod_exp;
+	return 1;
+}
+
+int RSA_meth_set_init(RSA_METHOD *method, func_rsa_init init)
+{
+	method->init = init;
+	return 1;
+}
+
+int RSA_meth_set_finish(RSA_METHOD *method, func_rsa_finish finish)
+{
+	method->finish = finish;
+	return 1;
+}
+
+int RSA_meth_set_keygen(RSA_METHOD *method, func_rsa_keygen keygen)
+{
+	method->rsa_keygen = keygen;
+	return 1;
+}
+
+int RSA_set0_key(RSA *key, BIGNUM *n, BIGNUM *e, BIGNUM *d)
+{
+	if (key->n == NULL && n == NULL)
+		return 0;
+	if (key->e == NULL && e == NULL)
+		return 0;
+
+	if (n != NULL) {
+		BN_free(key->n);
+		key->n = n;
+	}
+	if (e != NULL) {
+		BN_free(key->e);
+		key->e = e;
+	}
+	if (d != NULL) {
+		BN_free(key->d);
+		key->d = d;
+	}
+
+	return 1;
+}
+
+void RSA_get0_key(RSA *key, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
+{
+	if (n)
+		*n = key->n;
+	if (e)
+		*e = key->e;
+	if (d)
+		*d = key->d;
+}
+
+void RSA_get0_factors(RSA *key, const BIGNUM **p, const BIGNUM **q)
+{
+	if (p)
+		*p = key->p;
+	if (q)
+		*q = key->q;
+}
+
+int RSA_set_method(RSA *key, const RSA_METHOD *method)
+{
+	key->meth = method;
+	/* call our local init function here, the original RSA_set_method()
+	 * does this internally */
+	key->meth->init(key);
+	return 1;
+}
+
+RSA* EVP_PKEY_get0_RSA(EVP_PKEY *key)
+{
+	return key->pkey.rsa;
+}
+
+#endif // ! USE_OPENSSL_OPAQUE_API
+
+#ifndef HAVE_OPENSSL_110
+
+const RSA_METHOD* RSA_PKCS1_OpenSSL()
+{
+	// was renamed in 1.1.0
+	return RSA_PKCS1_SSLeay();
+}
+
+#endif // ! HAVE_OPENSSL_110
+
+#endif // include guard
diff --git a/test/Makefile.am b/test/Makefile.am
index 2e0de61..a0e2a1d 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,4 +1,5 @@
 noinst_PROGRAMS=engine_key_loading
 
+engine_key_loading_CFLAGS=-I../
 engine_key_loading_SOURCES=engine_key_loading.c
 engine_key_loading_LDADD=-ltspi -lcrypto
diff --git a/test/engine_key_loading.c b/test/engine_key_loading.c
index 4bc2ef8..c425f36 100644
--- a/test/engine_key_loading.c
+++ b/test/engine_key_loading.c
@@ -32,6 +32,7 @@
 #include <tss/tss_error.h>
 #include <tss/tspi.h>
 
+#include "ssl_compat.h"
 
 #define ERR(x, ...)	fprintf(stderr, "%s:%d " x "\n", __FILE__, __LINE__, ##__VA_ARGS__)
 
@@ -71,8 +72,8 @@ int test_num[] = { 1, 1, 2, 2 };
 int
 run_test(EVP_PKEY *key)
 {
-	RSA *rsa;
-	char signature[256], data_to_sign[DATA_SIZE], data_recovered[DATA_SIZE];
+	RSA *rsa = NULL;
+	unsigned char signature[256], data_to_sign[DATA_SIZE], data_recovered[DATA_SIZE];
 	int sig_size;
 
 	if (RAND_bytes(data_to_sign, sizeof(data_to_sign)) != 1) {
@@ -80,10 +81,19 @@ run_test(EVP_PKEY *key)
 		return 1;
 	}
 
-	if (key)
-		rsa = key->pkey.rsa;
-	else
-		rsa = RSA_generate_key(KEY_SIZE_BITS, 65537, NULL, NULL);
+	if (key) {
+		rsa = EVP_PKEY_get0_RSA(key);
+	}
+	else {
+		BIGNUM *e = BN_new();
+		rsa = RSA_new();
+		if( !e || !rsa || !BN_set_word(e, 65537) )
+			return 1;
+		if( RSA_generate_key_ex(rsa, KEY_SIZE_BITS, e, NULL) != 1 )
+		{
+			return 1;
+		}
+	}
 
 	if (!rsa)
 		return 1;
-- 
2.13.6