Re: OpenSSL 1.1.0 support

[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

 



On 11/02/2016 01:43 AM, Colin Watson wrote:
On Sun, Sep 18, 2016 at 08:22:31PM +0200, Kurt Roeckx wrote:
Attached is a patch that add supports for building against OpenSSL
1.1.0. I also made a github pull request for it at:
https://github.com/openssh/openssh-portable/pull/48
Hi,

Debian unstable now has OpenSSL 1.1.0 as the default, so I'll have to
take some kind of positive action if I want my OpenSSH packages to keep
building cleanly.  I know it's a big patch, but is anyone likely to be
able to look at Kurt's changes soon?  I'm not very comfortable with
applying a change of this size as a local patch.
Hello Colin,
Fedora Rawhide has already OpenSSL 1.1.0 and we use the patch based on the Kurt's one (after fixing initial bugs and extending for GSSAPI and SSH1 client support). The full Fedora patch is available in our git [1].

The current set of patches are rebased on current upstream is attached with few more tweaks needed to build, pass testsuite and make it work. The upstream review and insight would be helpful.

[1] https://pkgs.fedoraproject.org/cgit/rpms/openssh.git/tree/openssh-7.3p1-openssl-1.1.0.patch

Regards,

--
Jakub Jelen
Software Engineer
Security Technologies
Red Hat

>From d1419e808e764b7088b5c01674f235558037a1c0 Mon Sep 17 00:00:00 2001
From: Kurt Roeckx <kurt@xxxxxxxxx>
Date: Sat, 17 Sep 2016 19:08:27 +0200
Subject: [PATCH 1/7] Make it build using OpenSSL 1.1.0

---
 Makefile.in                            |   2 +-
 cipher.c                               |  14 +-
 dh.c                                   |  54 ++--
 dh.h                                   |   2 +-
 digest-openssl.c                       |  17 +-
 includes.h                             |   1 +
 kexdhc.c                               |  19 +-
 kexdhs.c                               |  10 +-
 kexgexc.c                              |  28 +-
 kexgexs.c                              |  19 +-
 libcrypto-compat.c                     | 445 ++++++++++++++++++++++++++++
 libcrypto-compat.h                     |  58 ++++
 monitor.c                              |   7 +-
 regress/unittests/sshkey/test_file.c   |  17 +-
 regress/unittests/sshkey/test_sshkey.c |  25 +-
 rsa.c                                  |  41 ++-
 rsa.h                                  |   2 +-
 ssh-dss.c                              |  27 +-
 ssh-ecdsa.c                            |  26 +-
 ssh-keygen.c                           |  93 +++---
 ssh-pkcs11-client.c                    |  12 +-
 ssh-pkcs11.c                           |  42 ++-
 ssh-rsa.c                              |  12 +-
 sshkey.c                               | 524 +++++++++++++++++++++++----------
 24 files changed, 1166 insertions(+), 331 deletions(-)
 create mode 100644 libcrypto-compat.c
 create mode 100644 libcrypto-compat.h

diff --git a/Makefile.in b/Makefile.in
index 3990f55..754a9ad 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -92,7 +92,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
 	kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \
 	kexdhc.o kexgexc.o kexecdhc.o kexc25519c.o \
 	kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o \
-	platform-pledge.o platform-tracing.o
+	platform-pledge.o platform-tracing.o libcrypto-compat.o
 
 SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
 	sshconnect.o sshconnect1.o sshconnect2.o mux.o
diff --git a/cipher.c b/cipher.c
index 2def333..ee9d02e 100644
--- a/cipher.c
+++ b/cipher.c
@@ -372,7 +372,7 @@ cipher_init(struct sshcipher_ctx **ccp, const struct sshcipher *cipher,
 		ret = SSH_ERR_ALLOC_FAIL;
 		goto out;
 	}
-	if (EVP_CipherInit(cc->evp, type, NULL, (u_char *)iv,
+	if (EVP_CipherInit(cc->evp, type, (u_char *)key, (u_char *)iv,
 	    (do_encrypt == CIPHER_ENCRYPT)) == 0) {
 		ret = SSH_ERR_LIBCRYPTO_ERROR;
 		goto out;
@@ -390,10 +390,6 @@ cipher_init(struct sshcipher_ctx **ccp, const struct sshcipher *cipher,
 			goto out;
 		}
 	}
-	if (EVP_CipherInit(cc->evp, NULL, (u_char *)key, NULL, -1) == 0) {
-		ret = SSH_ERR_LIBCRYPTO_ERROR;
-		goto out;
-	}
 
 	if (cipher->discard_len > 0) {
 		if ((junk = malloc(cipher->discard_len)) == NULL ||
@@ -625,7 +621,7 @@ cipher_get_keyiv(struct sshcipher_ctx *cc, u_char *iv, u_int len)
 			   len, iv))
 			       return SSH_ERR_LIBCRYPTO_ERROR;
 		} else
-			memcpy(iv, cc->evp->iv, len);
+			memcpy(iv, EVP_CIPHER_CTX_iv(cc->evp), len);
 		break;
 #endif
 #ifdef WITH_SSH1
@@ -671,7 +667,7 @@ cipher_set_keyiv(struct sshcipher_ctx *cc, const u_char *iv)
 			    EVP_CTRL_GCM_SET_IV_FIXED, -1, (void *)iv))
 				return SSH_ERR_LIBCRYPTO_ERROR;
 		} else
-			memcpy(cc->evp->iv, iv, evplen);
+			memcpy(EVP_CIPHER_CTX_iv_noconst(cc->evp), iv, evplen);
 		break;
 #endif
 #ifdef WITH_SSH1
@@ -685,8 +681,8 @@ cipher_set_keyiv(struct sshcipher_ctx *cc, const u_char *iv)
 }
 
 #ifdef WITH_OPENSSL
-#define EVP_X_STATE(evp)	(evp)->cipher_data
-#define EVP_X_STATE_LEN(evp)	(evp)->cipher->ctx_size
+#define EVP_X_STATE(evp)	EVP_CIPHER_CTX_get_cipher_data(evp)
+#define EVP_X_STATE_LEN(evp)	EVP_CIPHER_impl_ctx_size(EVP_CIPHER_CTX_cipher(evp))
 #endif
 
 int
diff --git a/dh.c b/dh.c
index 194f29b..10a5eb9 100644
--- a/dh.c
+++ b/dh.c
@@ -212,14 +212,15 @@ choose_dh(int min, int wantbits, int max)
 /* diffie-hellman-groupN-sha1 */
 
 int
-dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
+dh_pub_is_valid(const DH *dh, const BIGNUM *dh_pub)
 {
 	int i;
 	int n = BN_num_bits(dh_pub);
 	int bits_set = 0;
 	BIGNUM *tmp;
+	const BIGNUM *p;
 
-	if (dh_pub->neg) {
+	if (BN_is_negative(dh_pub)) {
 		logit("invalid public DH value: negative");
 		return 0;
 	}
@@ -232,7 +233,8 @@ dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
 		error("%s: BN_new failed", __func__);
 		return 0;
 	}
-	if (!BN_sub(tmp, dh->p, BN_value_one()) ||
+	DH_get0_pqg(dh, &p, NULL, NULL);
+	if (!BN_sub(tmp, p, BN_value_one()) ||
 	    BN_cmp(dh_pub, tmp) != -1) {		/* pub_exp > p-2 */
 		BN_clear_free(tmp);
 		logit("invalid public DH value: >= p-1");
@@ -243,14 +245,14 @@ dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
 	for (i = 0; i <= n; i++)
 		if (BN_is_bit_set(dh_pub, i))
 			bits_set++;
-	debug2("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
+	debug2("bits set: %d/%d", bits_set, BN_num_bits(p));
 
 	/*
 	 * if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial
 	 */
 	if (bits_set < 4) {
 		logit("invalid public DH value (%d/%d)",
-		   bits_set, BN_num_bits(dh->p));
+		   bits_set, BN_num_bits(p));
 		return 0;
 	}
 	return 1;
@@ -260,9 +262,11 @@ int
 dh_gen_key(DH *dh, int need)
 {
 	int pbits;
+	const BIGNUM *p, *pub_key;
 
-	if (need < 0 || dh->p == NULL ||
-	    (pbits = BN_num_bits(dh->p)) <= 0 ||
+	DH_get0_pqg(dh, &p, NULL, NULL);
+	if (need < 0 || p == NULL ||
+	    (pbits = BN_num_bits(p)) <= 0 ||
 	    need > INT_MAX / 2 || 2 * need > pbits)
 		return SSH_ERR_INVALID_ARGUMENT;
 	if (need < 256)
@@ -271,12 +275,12 @@ dh_gen_key(DH *dh, int need)
 	 * Pollard Rho, Big step/Little Step attacks are O(sqrt(n)),
 	 * so double requested need here.
 	 */
-	dh->length = MINIMUM(need * 2, pbits - 1);
-	if (DH_generate_key(dh) == 0 ||
-	    !dh_pub_is_valid(dh, dh->pub_key)) {
-		BN_clear_free(dh->priv_key);
+	DH_set_length(dh, MINIMUM(need * 2, pbits - 1));
+	if (DH_generate_key(dh) == 0)
+		return SSH_ERR_LIBCRYPTO_ERROR;
+	DH_get0_key(dh, &pub_key, NULL);
+	if (!dh_pub_is_valid(dh, pub_key))
 		return SSH_ERR_LIBCRYPTO_ERROR;
-	}
 	return 0;
 }
 
@@ -284,15 +288,22 @@ DH *
 dh_new_group_asc(const char *gen, const char *modulus)
 {
 	DH *dh;
-
-	if ((dh = DH_new()) == NULL)
-		return NULL;
-	if (BN_hex2bn(&dh->p, modulus) == 0 ||
-	    BN_hex2bn(&dh->g, gen) == 0) {
-		DH_free(dh);
-		return NULL;
-	}
+	BIGNUM *p, *g;
+
+	if ((dh = DH_new()) == NULL ||
+	    (p = BN_new()) == NULL ||
+	    (g = BN_new()) == NULL)
+		goto err;
+	if (BN_hex2bn(&p, modulus) == 0 ||
+	    BN_hex2bn(&g, gen) == 0 ||
+	    DH_set0_pqg(dh, p, NULL, g) == 0)
+		goto err;
 	return (dh);
+err:
+	DH_free(dh);
+	BN_free(p);
+	BN_free(g);
+	return NULL;
 }
 
 /*
@@ -307,8 +318,7 @@ dh_new_group(BIGNUM *gen, BIGNUM *modulus)
 
 	if ((dh = DH_new()) == NULL)
 		return NULL;
-	dh->p = modulus;
-	dh->g = gen;
+	DH_set0_pqg(dh, modulus, NULL, gen);
 
 	return (dh);
 }
diff --git a/dh.h b/dh.h
index bcd485c..344b29e 100644
--- a/dh.h
+++ b/dh.h
@@ -42,7 +42,7 @@ DH	*dh_new_group18(void);
 DH	*dh_new_group_fallback(int);
 
 int	 dh_gen_key(DH *, int);
-int	 dh_pub_is_valid(DH *, BIGNUM *);
+int	 dh_pub_is_valid(const DH *, const BIGNUM *);
 
 u_int	 dh_estimate(int);
 
diff --git a/digest-openssl.c b/digest-openssl.c
index 13b63c2..b0b95a4 100644
--- a/digest-openssl.c
+++ b/digest-openssl.c
@@ -43,7 +43,7 @@
 
 struct ssh_digest_ctx {
 	int alg;
-	EVP_MD_CTX mdctx;
+	EVP_MD_CTX *mdctx;
 };
 
 struct ssh_digest {
@@ -107,7 +107,7 @@ ssh_digest_bytes(int alg)
 size_t
 ssh_digest_blocksize(struct ssh_digest_ctx *ctx)
 {
-	return EVP_MD_CTX_block_size(&ctx->mdctx);
+	return EVP_MD_CTX_block_size(ctx->mdctx);
 }
 
 struct ssh_digest_ctx *
@@ -119,8 +119,9 @@ ssh_digest_start(int alg)
 	if (digest == NULL || ((ret = calloc(1, sizeof(*ret))) == NULL))
 		return NULL;
 	ret->alg = alg;
-	EVP_MD_CTX_init(&ret->mdctx);
-	if (EVP_DigestInit_ex(&ret->mdctx, digest->mdfunc(), NULL) != 1) {
+	ret->mdctx = EVP_MD_CTX_new();
+	if (ret->mdctx == NULL ||
+	    EVP_DigestInit_ex(ret->mdctx, digest->mdfunc(), NULL) != 1) {
 		free(ret);
 		return NULL;
 	}
@@ -133,7 +134,7 @@ ssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to)
 	if (from->alg != to->alg)
 		return SSH_ERR_INVALID_ARGUMENT;
 	/* we have bcopy-style order while openssl has memcpy-style */
-	if (!EVP_MD_CTX_copy_ex(&to->mdctx, &from->mdctx))
+	if (!EVP_MD_CTX_copy_ex(to->mdctx, from->mdctx))
 		return SSH_ERR_LIBCRYPTO_ERROR;
 	return 0;
 }
@@ -141,7 +142,7 @@ ssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to)
 int
 ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen)
 {
-	if (EVP_DigestUpdate(&ctx->mdctx, m, mlen) != 1)
+	if (EVP_DigestUpdate(ctx->mdctx, m, mlen) != 1)
 		return SSH_ERR_LIBCRYPTO_ERROR;
 	return 0;
 }
@@ -162,7 +163,7 @@ ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen)
 		return SSH_ERR_INVALID_ARGUMENT;
 	if (dlen < digest->digest_len) /* No truncation allowed */
 		return SSH_ERR_INVALID_ARGUMENT;
-	if (EVP_DigestFinal_ex(&ctx->mdctx, d, &l) != 1)
+	if (EVP_DigestFinal_ex(ctx->mdctx, d, &l) != 1)
 		return SSH_ERR_LIBCRYPTO_ERROR;
 	if (l != digest->digest_len) /* sanity */
 		return SSH_ERR_INTERNAL_ERROR;
@@ -173,7 +174,7 @@ void
 ssh_digest_free(struct ssh_digest_ctx *ctx)
 {
 	if (ctx != NULL) {
-		EVP_MD_CTX_cleanup(&ctx->mdctx);
+		EVP_MD_CTX_free(ctx->mdctx);
 		explicit_bzero(ctx, sizeof(*ctx));
 		free(ctx);
 	}
diff --git a/includes.h b/includes.h
index 497a038..7e602f5 100644
--- a/includes.h
+++ b/includes.h
@@ -163,6 +163,7 @@
 
 #ifdef WITH_OPENSSL
 #include <openssl/opensslv.h> /* For OPENSSL_VERSION_NUMBER */
+#include "libcrypto-compat.h"
 #endif
 
 #include "defines.h"
diff --git a/kexdhc.c b/kexdhc.c
index ad3975f..0a55092 100644
--- a/kexdhc.c
+++ b/kexdhc.c
@@ -56,6 +56,7 @@ kexdh_client(struct ssh *ssh)
 {
 	struct kex *kex = ssh->kex;
 	int r;
+	const BIGNUM *pub_key;
 
 	/* generate and send 'e', client DH public key */
 	switch (kex->kex_type) {
@@ -81,21 +82,27 @@ kexdh_client(struct ssh *ssh)
 		goto out;
 	}
 	debug("sending SSH2_MSG_KEXDH_INIT");
-	if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0 ||
-	    (r = sshpkt_start(ssh, SSH2_MSG_KEXDH_INIT)) != 0 ||
-	    (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 ||
+	if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0)
+		goto out;
+	DH_get0_key(kex->dh, &pub_key, NULL);
+	if ((r = sshpkt_start(ssh, SSH2_MSG_KEXDH_INIT)) != 0 ||
+	    (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 ||
 	    (r = sshpkt_send(ssh)) != 0)
 		goto out;
 #ifdef DEBUG_KEXDH
 	DHparams_print_fp(stderr, kex->dh);
 	fprintf(stderr, "pub= ");
-	BN_print_fp(stderr, kex->dh->pub_key);
+	BN_print_fp(stderr, pub_key);
 	fprintf(stderr, "\n");
 #endif
 	debug("expecting SSH2_MSG_KEXDH_REPLY");
 	ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_REPLY, &input_kex_dh);
 	r = 0;
  out:
+	if (r != 0) {
+		DH_free(kex->dh);
+		kex->dh = NULL;
+	}
 	return r;
 }
 
@@ -110,6 +117,7 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
 	u_char hash[SSH_DIGEST_MAX_LENGTH];
 	size_t klen = 0, slen, sbloblen, hashlen;
 	int kout, r;
+	const BIGNUM *pub_key;
 
 	if (kex->verify_host_key == NULL) {
 		r = SSH_ERR_INVALID_ARGUMENT;
@@ -169,6 +177,7 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
 #endif
 
 	/* calc and verify H */
+	DH_get0_key(kex->dh, &pub_key, NULL);
 	hashlen = sizeof(hash);
 	if ((r = kex_dh_hash(
 	    kex->hash_alg,
@@ -177,7 +186,7 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
 	    sshbuf_ptr(kex->my), sshbuf_len(kex->my),
 	    sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
 	    server_host_key_blob, sbloblen,
-	    kex->dh->pub_key,
+	    pub_key,
 	    dh_server_pub,
 	    shared_secret,
 	    hash, &hashlen)) != 0)
diff --git a/kexdhs.c b/kexdhs.c
index 108f664..8d0906e 100644
--- a/kexdhs.c
+++ b/kexdhs.c
@@ -87,6 +87,10 @@ kexdh_server(struct ssh *ssh)
 	ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_INIT, &input_kex_dh_init);
 	r = 0;
  out:
+	if (r != 0) {
+		DH_free(kex->dh);
+		kex->dh = NULL;
+	}
 	return r;
 }
 
@@ -102,6 +106,7 @@ input_kex_dh_init(int type, u_int32_t seq, void *ctxt)
 	size_t sbloblen, slen;
 	size_t klen = 0, hashlen;
 	int kout, r;
+	const BIGNUM *pub_key;
 
 	if (kex->load_host_public_key == NULL ||
 	    kex->load_host_private_key == NULL) {
@@ -164,6 +169,7 @@ input_kex_dh_init(int type, u_int32_t seq, void *ctxt)
 		goto out;
 	/* calc H */
 	hashlen = sizeof(hash);
+	DH_get0_key(kex->dh, &pub_key, NULL);
 	if ((r = kex_dh_hash(
 	    kex->hash_alg,
 	    kex->client_version_string,
@@ -172,7 +178,7 @@ input_kex_dh_init(int type, u_int32_t seq, void *ctxt)
 	    sshbuf_ptr(kex->my), sshbuf_len(kex->my),
 	    server_host_key_blob, sbloblen,
 	    dh_client_pub,
-	    kex->dh->pub_key,
+	    pub_key,
 	    shared_secret,
 	    hash, &hashlen)) != 0)
 		goto out;
@@ -198,7 +204,7 @@ input_kex_dh_init(int type, u_int32_t seq, void *ctxt)
 	/* send server hostkey, DH pubkey 'f' and singed H */
 	if ((r = sshpkt_start(ssh, SSH2_MSG_KEXDH_REPLY)) != 0 ||
 	    (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
-	    (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 ||	/* f */
+	    (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 ||	/* f */
 	    (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
 	    (r = sshpkt_send(ssh)) != 0)
 		goto out;
diff --git a/kexgexc.c b/kexgexc.c
index ad0d1c8..da17c49 100644
--- a/kexgexc.c
+++ b/kexgexc.c
@@ -95,6 +95,7 @@ input_kex_dh_gex_group(int type, u_int32_t seq, void *ctxt)
 	struct kex *kex = ssh->kex;
 	BIGNUM *p = NULL, *g = NULL;
 	int r, bits;
+	const BIGNUM *pub_key;
 
 	debug("got SSH2_MSG_KEX_DH_GEX_GROUP");
 
@@ -119,26 +120,30 @@ input_kex_dh_gex_group(int type, u_int32_t seq, void *ctxt)
 	p = g = NULL; /* belong to kex->dh now */
 
 	/* generate and send 'e', client DH public key */
-	if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0 ||
-	    (r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_INIT)) != 0 ||
-	    (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 ||
+	if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0)
+		goto out;
+	DH_get0_key(kex->dh, &pub_key, NULL);
+	if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_INIT)) != 0 ||
+	    (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 ||
 	    (r = sshpkt_send(ssh)) != 0)
 		goto out;
 	debug("SSH2_MSG_KEX_DH_GEX_INIT sent");
 #ifdef DEBUG_KEXDH
 	DHparams_print_fp(stderr, kex->dh);
 	fprintf(stderr, "pub= ");
-	BN_print_fp(stderr, kex->dh->pub_key);
+	BN_print_fp(stderr, pub_key);
 	fprintf(stderr, "\n");
 #endif
 	ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP, NULL);
 	ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REPLY, &input_kex_dh_gex_reply);
 	r = 0;
 out:
-	if (p)
-		BN_clear_free(p);
-	if (g)
-		BN_clear_free(g);
+	BN_clear_free(p);
+	BN_clear_free(g);
+	if (r != 0) {
+		DH_free(kex->dh);
+		kex->dh = NULL;
+	}
 	return r;
 }
 
@@ -153,6 +158,7 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
 	u_char hash[SSH_DIGEST_MAX_LENGTH];
 	size_t klen = 0, slen, sbloblen, hashlen;
 	int kout, r;
+	const BIGNUM *p, *g, *pub_key;
 
 	debug("got SSH2_MSG_KEX_DH_GEX_REPLY");
 	if (kex->verify_host_key == NULL) {
@@ -219,6 +225,8 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
 		kex->min = kex->max = -1;
 
 	/* calc and verify H */
+	DH_get0_pqg(kex->dh, &p, NULL, &g);
+	DH_get0_key(kex->dh, &pub_key, NULL);
 	hashlen = sizeof(hash);
 	if ((r = kexgex_hash(
 	    kex->hash_alg,
@@ -228,8 +236,8 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
 	    sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
 	    server_host_key_blob, sbloblen,
 	    kex->min, kex->nbits, kex->max,
-	    kex->dh->p, kex->dh->g,
-	    kex->dh->pub_key,
+	    p, g,
+	    pub_key,
 	    dh_server_pub,
 	    shared_secret,
 	    hash, &hashlen)) != 0)
diff --git a/kexgexs.c b/kexgexs.c
index 4496035..7cd8c7e 100644
--- a/kexgexs.c
+++ b/kexgexs.c
@@ -73,6 +73,7 @@ input_kex_dh_gex_request(int type, u_int32_t seq, void *ctxt)
 	struct kex *kex = ssh->kex;
 	int r;
 	u_int min = 0, max = 0, nbits = 0;
+	const BIGNUM *p, *g;
 
 	debug("SSH2_MSG_KEX_DH_GEX_REQUEST received");
 	if ((r = sshpkt_get_u32(ssh, &min)) != 0 ||
@@ -102,9 +103,10 @@ input_kex_dh_gex_request(int type, u_int32_t seq, void *ctxt)
 		goto out;
 	}
 	debug("SSH2_MSG_KEX_DH_GEX_GROUP sent");
+	DH_get0_pqg(kex->dh, &p, NULL, &g);
 	if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_GROUP)) != 0 ||
-	    (r = sshpkt_put_bignum2(ssh, kex->dh->p)) != 0 ||
-	    (r = sshpkt_put_bignum2(ssh, kex->dh->g)) != 0 ||
+	    (r = sshpkt_put_bignum2(ssh, p)) != 0 ||
+	    (r = sshpkt_put_bignum2(ssh, g)) != 0 ||
 	    (r = sshpkt_send(ssh)) != 0)
 		goto out;
 
@@ -116,6 +118,10 @@ input_kex_dh_gex_request(int type, u_int32_t seq, void *ctxt)
 	ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_INIT, &input_kex_dh_gex_init);
 	r = 0;
  out:
+	if (r != 0) {
+		DH_free(kex->dh);
+		kex->dh = NULL;
+	}
 	return r;
 }
 
@@ -131,6 +137,7 @@ input_kex_dh_gex_init(int type, u_int32_t seq, void *ctxt)
 	size_t sbloblen, slen;
 	size_t klen = 0, hashlen;
 	int kout, r;
+	const BIGNUM *p, *g, *pub_key;
 
 	if (kex->load_host_public_key == NULL ||
 	    kex->load_host_private_key == NULL) {
@@ -193,6 +200,8 @@ input_kex_dh_gex_init(int type, u_int32_t seq, void *ctxt)
 		goto out;
 	/* calc H */
 	hashlen = sizeof(hash);
+	DH_get0_pqg(kex->dh, &p, NULL, &g);
+	DH_get0_key(kex->dh, &pub_key, NULL);
 	if ((r = kexgex_hash(
 	    kex->hash_alg,
 	    kex->client_version_string,
@@ -201,9 +210,9 @@ input_kex_dh_gex_init(int type, u_int32_t seq, void *ctxt)
 	    sshbuf_ptr(kex->my), sshbuf_len(kex->my),
 	    server_host_key_blob, sbloblen,
 	    kex->min, kex->nbits, kex->max,
-	    kex->dh->p, kex->dh->g,
+	    p, g,
 	    dh_client_pub,
-	    kex->dh->pub_key,
+	    pub_key,
 	    shared_secret,
 	    hash, &hashlen)) != 0)
 		goto out;
@@ -229,7 +238,7 @@ input_kex_dh_gex_init(int type, u_int32_t seq, void *ctxt)
 	/* send server hostkey, DH pubkey 'f' and singed H */
 	if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REPLY)) != 0 ||
 	    (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
-	    (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 ||     /* f */
+	    (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 ||     /* f */
 	    (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
 	    (r = sshpkt_send(ssh)) != 0)
 		goto out;
diff --git a/libcrypto-compat.c b/libcrypto-compat.c
new file mode 100644
index 0000000..d92c8d9
--- /dev/null
+++ b/libcrypto-compat.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "includes.h"
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+
+#include <string.h>
+#include <openssl/engine.h>
+
+static void *OPENSSL_zalloc(size_t num)
+{
+    void *ret = OPENSSL_malloc(num);
+
+    if (ret != NULL)
+        memset(ret, 0, num);
+    return ret;
+}
+
+int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
+{
+    /* If the fields n and e in r are NULL, the corresponding input
+     * parameters MUST be non-NULL for n and e.  d may be
+     * left NULL (in case only the public key is used).
+     */
+    if ((r->n == NULL && n == NULL)
+        || (r->e == NULL && e == NULL))
+        return 0;
+
+    if (n != NULL) {
+        BN_free(r->n);
+        r->n = n;
+    }
+    if (e != NULL) {
+        BN_free(r->e);
+        r->e = e;
+    }
+    if (d != NULL) {
+        BN_free(r->d);
+        r->d = d;
+    }
+
+    return 1;
+}
+
+int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
+{
+    /* If the fields p and q in r are NULL, the corresponding input
+     * parameters MUST be non-NULL.
+     */
+    if ((r->p == NULL && p == NULL)
+        || (r->q == NULL && q == NULL))
+        return 0;
+
+    if (p != NULL) {
+        BN_free(r->p);
+        r->p = p;
+    }
+    if (q != NULL) {
+        BN_free(r->q);
+        r->q = q;
+    }
+
+    return 1;
+}
+
+int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp)
+{
+    /* If the fields dmp1, dmq1 and iqmp in r are NULL, the corresponding input
+     * parameters MUST be non-NULL.
+     */
+    if ((r->dmp1 == NULL && dmp1 == NULL)
+        || (r->dmq1 == NULL && dmq1 == NULL)
+        || (r->iqmp == NULL && iqmp == NULL))
+        return 0;
+
+    if (dmp1 != NULL) {
+        BN_free(r->dmp1);
+        r->dmp1 = dmp1;
+    }
+    if (dmq1 != NULL) {
+        BN_free(r->dmq1);
+        r->dmq1 = dmq1;
+    }
+    if (iqmp != NULL) {
+        BN_free(r->iqmp);
+        r->iqmp = iqmp;
+    }
+
+    return 1;
+}
+
+void RSA_get0_key(const RSA *r,
+                  const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
+{
+    if (n != NULL)
+        *n = r->n;
+    if (e != NULL)
+        *e = r->e;
+    if (d != NULL)
+        *d = r->d;
+}
+
+void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
+{
+    if (p != NULL)
+        *p = r->p;
+    if (q != NULL)
+        *q = r->q;
+}
+
+void RSA_get0_crt_params(const RSA *r,
+                         const BIGNUM **dmp1, const BIGNUM **dmq1,
+                         const BIGNUM **iqmp)
+{
+    if (dmp1 != NULL)
+        *dmp1 = r->dmp1;
+    if (dmq1 != NULL)
+        *dmq1 = r->dmq1;
+    if (iqmp != NULL)
+        *iqmp = r->iqmp;
+}
+
+void DSA_get0_pqg(const DSA *d,
+                  const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
+{
+    if (p != NULL)
+        *p = d->p;
+    if (q != NULL)
+        *q = d->q;
+    if (g != NULL)
+        *g = d->g;
+}
+
+int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
+{
+    /* If the fields p, q and g in d are NULL, the corresponding input
+     * parameters MUST be non-NULL.
+     */
+    if ((d->p == NULL && p == NULL)
+        || (d->q == NULL && q == NULL)
+        || (d->g == NULL && g == NULL))
+        return 0;
+
+    if (p != NULL) {
+        BN_free(d->p);
+        d->p = p;
+    }
+    if (q != NULL) {
+        BN_free(d->q);
+        d->q = q;
+    }
+    if (g != NULL) {
+        BN_free(d->g);
+        d->g = g;
+    }
+
+    return 1;
+}
+
+void DSA_get0_key(const DSA *d,
+                  const BIGNUM **pub_key, const BIGNUM **priv_key)
+{
+    if (pub_key != NULL)
+        *pub_key = d->pub_key;
+    if (priv_key != NULL)
+        *priv_key = d->priv_key;
+}
+
+int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
+{
+    /* If the field pub_key in d is NULL, the corresponding input
+     * parameters MUST be non-NULL.  The priv_key field may
+     * be left NULL.
+     */
+    if (d->pub_key == NULL && pub_key == NULL)
+        return 0;
+
+    if (pub_key != NULL) {
+        BN_free(d->pub_key);
+        d->pub_key = pub_key;
+    }
+    if (priv_key != NULL) {
+        BN_free(d->priv_key);
+        d->priv_key = priv_key;
+    }
+
+    return 1;
+}
+
+void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
+{
+    if (pr != NULL)
+        *pr = sig->r;
+    if (ps != NULL)
+        *ps = sig->s;
+}
+
+int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s)
+{
+    if (r == NULL || s == NULL)
+        return 0;
+    BN_clear_free(sig->r);
+    BN_clear_free(sig->s);
+    sig->r = r;
+    sig->s = s;
+    return 1;
+}
+
+void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
+{
+    if (pr != NULL)
+        *pr = sig->r;
+    if (ps != NULL)
+        *ps = sig->s;
+}
+
+int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
+{
+    if (r == NULL || s == NULL)
+        return 0;
+    BN_clear_free(sig->r);
+    BN_clear_free(sig->s);
+    sig->r = r;
+    sig->s = s;
+    return 1;
+}
+
+void DH_get0_pqg(const DH *dh,
+                 const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
+{
+    if (p != NULL)
+        *p = dh->p;
+    if (q != NULL)
+        *q = dh->q;
+    if (g != NULL)
+        *g = dh->g;
+}
+
+int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
+{
+    /* If the fields p and g in d are NULL, the corresponding input
+     * parameters MUST be non-NULL.  q may remain NULL.
+     */
+    if ((dh->p == NULL && p == NULL)
+        || (dh->g == NULL && g == NULL))
+        return 0;
+
+    if (p != NULL) {
+        BN_free(dh->p);
+        dh->p = p;
+    }
+    if (q != NULL) {
+        BN_free(dh->q);
+        dh->q = q;
+    }
+    if (g != NULL) {
+        BN_free(dh->g);
+        dh->g = g;
+    }
+
+    if (q != NULL) {
+        dh->length = BN_num_bits(q);
+    }
+
+    return 1;
+}
+
+void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
+{
+    if (pub_key != NULL)
+        *pub_key = dh->pub_key;
+    if (priv_key != NULL)
+        *priv_key = dh->priv_key;
+}
+
+int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
+{
+    /* If the field pub_key in dh is NULL, the corresponding input
+     * parameters MUST be non-NULL.  The priv_key field may
+     * be left NULL.
+     */
+    if (dh->pub_key == NULL && pub_key == NULL)
+        return 0;
+
+    if (pub_key != NULL) {
+        BN_free(dh->pub_key);
+        dh->pub_key = pub_key;
+    }
+    if (priv_key != NULL) {
+        BN_free(dh->priv_key);
+        dh->priv_key = priv_key;
+    }
+
+    return 1;
+}
+
+int DH_set_length(DH *dh, long length)
+{
+    dh->length = length;
+    return 1;
+}
+
+const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx)
+{
+    return ctx->iv;
+}
+
+unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx)
+{
+    return ctx->iv;
+}
+
+EVP_MD_CTX *EVP_MD_CTX_new(void)
+{
+    return OPENSSL_zalloc(sizeof(EVP_MD_CTX));
+}
+
+static void OPENSSL_clear_free(void *str, size_t num)
+{
+    if (str == NULL)
+        return;
+    if (num)
+        OPENSSL_cleanse(str, num);
+    OPENSSL_free(str);
+}
+
+/* This call frees resources associated with the context */
+static int EVP_MD_CTX_reset(EVP_MD_CTX *ctx)
+{
+    if (ctx == NULL)
+        return 1;
+
+    /*
+     * Don't assume ctx->md_data was cleaned in EVP_Digest_Final, because
+     * sometimes only copies of the context are ever finalised.
+     */
+    if (ctx->digest && ctx->digest->cleanup
+        && !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_CLEANED))
+        ctx->digest->cleanup(ctx);
+    if (ctx->digest && ctx->digest->ctx_size && ctx->md_data
+        && !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE)) {
+        OPENSSL_clear_free(ctx->md_data, ctx->digest->ctx_size);
+    }
+    EVP_PKEY_CTX_free(ctx->pctx);
+#ifndef OPENSSL_NO_ENGINE
+    ENGINE_finish(ctx->engine);
+#endif
+    OPENSSL_cleanse(ctx, sizeof(*ctx));
+
+    return 1;
+}
+
+void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
+{
+    EVP_MD_CTX_reset(ctx);
+    OPENSSL_free(ctx);
+}
+
+RSA_METHOD *RSA_meth_dup(const RSA_METHOD *meth)
+{
+    RSA_METHOD *ret;
+
+    ret = OPENSSL_malloc(sizeof(RSA_METHOD));
+
+    if (ret != NULL) {
+        memcpy(ret, meth, sizeof(*meth));
+        ret->name = OPENSSL_strdup(meth->name);
+        if (ret->name == NULL) {
+            OPENSSL_free(ret);
+            return NULL;
+        }
+    }
+
+    return ret;
+}
+
+int RSA_meth_set1_name(RSA_METHOD *meth, const char *name)
+{
+    char *tmpname;
+
+    tmpname = OPENSSL_strdup(name);
+    if (tmpname == NULL) {
+        return 0;
+    }
+
+    OPENSSL_free((char *)meth->name);
+    meth->name = tmpname;
+
+    return 1;
+}
+
+int RSA_meth_set_priv_enc(RSA_METHOD *meth,
+                          int (*priv_enc) (int flen, const unsigned char *from,
+                                           unsigned char *to, RSA *rsa,
+                                           int padding))
+{
+    meth->rsa_priv_enc = priv_enc;
+    return 1;
+}
+
+int RSA_meth_set_priv_dec(RSA_METHOD *meth,
+                          int (*priv_dec) (int flen, const unsigned char *from,
+                                           unsigned char *to, RSA *rsa,
+                                           int padding))
+{
+    meth->rsa_priv_dec = priv_dec;
+    return 1;
+}
+
+int RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa))
+{
+    meth->finish = finish;
+    return 1;
+}
+
+void RSA_meth_free(RSA_METHOD *meth)
+{
+    if (meth != NULL) {
+        OPENSSL_free((char *)meth->name);
+        OPENSSL_free(meth);
+    }
+}
+
+int RSA_bits(const RSA *r)
+{
+    return (BN_num_bits(r->n));
+}
+
+RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey)
+{
+    if (pkey->type != EVP_PKEY_RSA) {
+        return NULL;
+    }
+    return pkey->pkey.rsa;
+}
+
+
+#endif /* OPENSSL_VERSION_NUMBER */
diff --git a/libcrypto-compat.h b/libcrypto-compat.h
new file mode 100644
index 0000000..e0599b4
--- /dev/null
+++ b/libcrypto-compat.h
@@ -0,0 +1,58 @@
+#ifndef LIBCRYPTO_COMPAT_H
+#define LIBCRYPTO_COMPAT_H
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+#include <openssl/ecdsa.h>
+#include <openssl/dh.h>
+#include <openssl/evp.h>
+
+int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d);
+int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q);
+int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp);
+void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d);
+void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q);
+void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp);
+
+void DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
+int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g);
+void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key);
+int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key);
+
+void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps);
+int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s);
+
+void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps);
+int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s);
+
+void DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
+int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g);
+void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key);
+int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key);
+int DH_set_length(DH *dh, long length);
+
+const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx);
+unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx);
+EVP_MD_CTX *EVP_MD_CTX_new(void);
+void EVP_MD_CTX_free(EVP_MD_CTX *ctx);
+#define EVP_CIPHER_impl_ctx_size(e) e->ctx_size
+#define EVP_CIPHER_CTX_get_cipher_data(ctx) ctx->cipher_data
+
+RSA_METHOD *RSA_meth_dup(const RSA_METHOD *meth);
+int RSA_meth_set1_name(RSA_METHOD *meth, const char *name);
+#define RSA_meth_get_finish(meth) meth->finish
+int RSA_meth_set_priv_enc(RSA_METHOD *meth, int (*priv_enc) (int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding));
+int RSA_meth_set_priv_dec(RSA_METHOD *meth, int (*priv_dec) (int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding));
+int RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa));
+void RSA_meth_free(RSA_METHOD *meth);
+
+int RSA_bits(const RSA *r);
+
+RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey);
+
+#endif /* OPENSSL_VERSION_NUMBER */
+
+#endif /* LIBCRYPTO_COMPAT_H */
+
diff --git a/monitor.c b/monitor.c
index 43f4847..17169f2 100644
--- a/monitor.c
+++ b/monitor.c
@@ -579,9 +579,12 @@ mm_answer_moduli(int sock, Buffer *m)
 		return (0);
 	} else {
 		/* Send first bignum */
+		const BIGNUM *p, *g;
+
+		DH_get0_pqg(dh, &p, NULL, &g);
 		buffer_put_char(m, 1);
-		buffer_put_bignum2(m, dh->p);
-		buffer_put_bignum2(m, dh->g);
+		buffer_put_bignum2(m, p);
+		buffer_put_bignum2(m, g);
 
 		DH_free(dh);
 	}
diff --git a/regress/unittests/sshkey/test_file.c b/regress/unittests/sshkey/test_file.c
index 906491f..7235a25 100644
--- a/regress/unittests/sshkey/test_file.c
+++ b/regress/unittests/sshkey/test_file.c
@@ -46,6 +46,7 @@ sshkey_file_tests(void)
 	struct sshbuf *buf, *pw;
 	BIGNUM *a, *b, *c;
 	char *cp;
+	const BIGNUM *n, *p, *q, *g, *pub_key, *priv_key;
 
 	TEST_START("load passphrase");
 	pw = load_text_file("pw");
@@ -109,9 +110,11 @@ sshkey_file_tests(void)
 	a = load_bignum("rsa_1.param.n");
 	b = load_bignum("rsa_1.param.p");
 	c = load_bignum("rsa_1.param.q");
-	ASSERT_BIGNUM_EQ(k1->rsa->n, a);
-	ASSERT_BIGNUM_EQ(k1->rsa->p, b);
-	ASSERT_BIGNUM_EQ(k1->rsa->q, c);
+	RSA_get0_key(k1->rsa, &n, NULL, NULL);
+	RSA_get0_factors(k1->rsa, &p, &q);
+	ASSERT_BIGNUM_EQ(n, a);
+	ASSERT_BIGNUM_EQ(p, b);
+	ASSERT_BIGNUM_EQ(q, c);
 	BN_free(a);
 	BN_free(b);
 	BN_free(c);
@@ -200,9 +203,11 @@ sshkey_file_tests(void)
 	a = load_bignum("dsa_1.param.g");
 	b = load_bignum("dsa_1.param.priv");
 	c = load_bignum("dsa_1.param.pub");
-	ASSERT_BIGNUM_EQ(k1->dsa->g, a);
-	ASSERT_BIGNUM_EQ(k1->dsa->priv_key, b);
-	ASSERT_BIGNUM_EQ(k1->dsa->pub_key, c);
+	DSA_get0_pqg(k1->dsa, NULL, NULL, &g);
+	DSA_get0_key(k1->dsa, &pub_key, &priv_key);
+	ASSERT_BIGNUM_EQ(g, a);
+	ASSERT_BIGNUM_EQ(priv_key, b);
+	ASSERT_BIGNUM_EQ(pub_key, c);
 	BN_free(a);
 	BN_free(b);
 	BN_free(c);
diff --git a/regress/unittests/sshkey/test_sshkey.c b/regress/unittests/sshkey/test_sshkey.c
index 1476dc2..c0f94ee 100644
--- a/regress/unittests/sshkey/test_sshkey.c
+++ b/regress/unittests/sshkey/test_sshkey.c
@@ -197,9 +197,6 @@ sshkey_tests(void)
 	k1 = sshkey_new(KEY_RSA1);
 	ASSERT_PTR_NE(k1, NULL);
 	ASSERT_PTR_NE(k1->rsa, NULL);
-	ASSERT_PTR_NE(k1->rsa->n, NULL);
-	ASSERT_PTR_NE(k1->rsa->e, NULL);
-	ASSERT_PTR_EQ(k1->rsa->p, NULL);
 	sshkey_free(k1);
 	TEST_DONE();
 
@@ -207,9 +204,6 @@ sshkey_tests(void)
 	k1 = sshkey_new(KEY_RSA);
 	ASSERT_PTR_NE(k1, NULL);
 	ASSERT_PTR_NE(k1->rsa, NULL);
-	ASSERT_PTR_NE(k1->rsa->n, NULL);
-	ASSERT_PTR_NE(k1->rsa->e, NULL);
-	ASSERT_PTR_EQ(k1->rsa->p, NULL);
 	sshkey_free(k1);
 	TEST_DONE();
 
@@ -217,8 +211,6 @@ sshkey_tests(void)
 	k1 = sshkey_new(KEY_DSA);
 	ASSERT_PTR_NE(k1, NULL);
 	ASSERT_PTR_NE(k1->dsa, NULL);
-	ASSERT_PTR_NE(k1->dsa->g, NULL);
-	ASSERT_PTR_EQ(k1->dsa->priv_key, NULL);
 	sshkey_free(k1);
 	TEST_DONE();
 
@@ -244,9 +236,6 @@ sshkey_tests(void)
 	k1 = sshkey_new_private(KEY_RSA);
 	ASSERT_PTR_NE(k1, NULL);
 	ASSERT_PTR_NE(k1->rsa, NULL);
-	ASSERT_PTR_NE(k1->rsa->n, NULL);
-	ASSERT_PTR_NE(k1->rsa->e, NULL);
-	ASSERT_PTR_NE(k1->rsa->p, NULL);
 	ASSERT_INT_EQ(sshkey_add_private(k1), 0);
 	sshkey_free(k1);
 	TEST_DONE();
@@ -255,8 +244,6 @@ sshkey_tests(void)
 	k1 = sshkey_new_private(KEY_DSA);
 	ASSERT_PTR_NE(k1, NULL);
 	ASSERT_PTR_NE(k1->dsa, NULL);
-	ASSERT_PTR_NE(k1->dsa->g, NULL);
-	ASSERT_PTR_NE(k1->dsa->priv_key, NULL);
 	ASSERT_INT_EQ(sshkey_add_private(k1), 0);
 	sshkey_free(k1);
 	TEST_DONE();
@@ -295,18 +282,13 @@ sshkey_tests(void)
 	ASSERT_INT_EQ(sshkey_generate(KEY_RSA, 1024, &kr), 0);
 	ASSERT_PTR_NE(kr, NULL);
 	ASSERT_PTR_NE(kr->rsa, NULL);
-	ASSERT_PTR_NE(kr->rsa->n, NULL);
-	ASSERT_PTR_NE(kr->rsa->e, NULL);
-	ASSERT_PTR_NE(kr->rsa->p, NULL);
-	ASSERT_INT_EQ(BN_num_bits(kr->rsa->n), 1024);
+	ASSERT_INT_EQ(RSA_bits(kr->rsa), 1024);
 	TEST_DONE();
 
 	TEST_START("generate KEY_DSA");
 	ASSERT_INT_EQ(sshkey_generate(KEY_DSA, 1024, &kd), 0);
 	ASSERT_PTR_NE(kd, NULL);
 	ASSERT_PTR_NE(kd->dsa, NULL);
-	ASSERT_PTR_NE(kd->dsa->g, NULL);
-	ASSERT_PTR_NE(kd->dsa->priv_key, NULL);
 	TEST_DONE();
 
 #ifdef OPENSSL_HAS_ECC
@@ -333,9 +315,6 @@ sshkey_tests(void)
 	ASSERT_PTR_NE(kr, k1);
 	ASSERT_INT_EQ(k1->type, KEY_RSA);
 	ASSERT_PTR_NE(k1->rsa, NULL);
-	ASSERT_PTR_NE(k1->rsa->n, NULL);
-	ASSERT_PTR_NE(k1->rsa->e, NULL);
-	ASSERT_PTR_EQ(k1->rsa->p, NULL);
 	TEST_DONE();
 
 	TEST_START("equal KEY_RSA/demoted KEY_RSA");
@@ -349,8 +328,6 @@ sshkey_tests(void)
 	ASSERT_PTR_NE(kd, k1);
 	ASSERT_INT_EQ(k1->type, KEY_DSA);
 	ASSERT_PTR_NE(k1->dsa, NULL);
-	ASSERT_PTR_NE(k1->dsa->g, NULL);
-	ASSERT_PTR_EQ(k1->dsa->priv_key, NULL);
 	TEST_DONE();
 
 	TEST_START("equal KEY_DSA/demoted KEY_DSA");
diff --git a/rsa.c b/rsa.c
index 5ecacef..6ff9947 100644
--- a/rsa.c
+++ b/rsa.c
@@ -76,11 +76,14 @@ rsa_public_encrypt(BIGNUM *out, BIGNUM *in, RSA *key)
 {
 	u_char *inbuf = NULL, *outbuf = NULL;
 	int len, ilen, olen, r = SSH_ERR_INTERNAL_ERROR;
+	const BIGNUM *e, *n;
 
-	if (BN_num_bits(key->e) < 2 || !BN_is_odd(key->e))
+	RSA_get0_key(key, &n, &e, NULL);
+
+	if (BN_num_bits(e) < 2 || !BN_is_odd(e))
 		return SSH_ERR_INVALID_ARGUMENT;
 
-	olen = BN_num_bytes(key->n);
+	olen = BN_num_bytes(n);
 	if ((outbuf = malloc(olen)) == NULL) {
 		r = SSH_ERR_ALLOC_FAIL;
 		goto out;
@@ -122,8 +125,11 @@ rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key)
 {
 	u_char *inbuf = NULL, *outbuf = NULL;
 	int len, ilen, olen, r = SSH_ERR_INTERNAL_ERROR;
+	const BIGNUM *n;
+
+	RSA_get0_key(key, &n, NULL, NULL);
 
-	olen = BN_num_bytes(key->n);
+	olen = BN_num_bytes(n);
 	if ((outbuf = malloc(olen)) == NULL) {
 		r = SSH_ERR_ALLOC_FAIL;
 		goto out;
@@ -157,31 +163,42 @@ rsa_private_decrypt(BIGNUM *out, BIGNUM *in, RSA *key)
 	return r;
 }
 
-/* calculate p-1 and q-1 */
+/* calculate d mod p-1 and d mod q-1 */
 int
-rsa_generate_additional_parameters(RSA *rsa)
+rsa_generate_additional_parameters(RSA *rsa, BIGNUM *iqmp)
 {
 	BIGNUM *aux = NULL;
 	BN_CTX *ctx = NULL;
 	int r;
+	const BIGNUM *p, *q, *d;
+	BIGNUM *dmp1 = NULL, *dmq1 = NULL;
+
+	RSA_get0_factors(rsa, &p, &q);
+	RSA_get0_key(rsa, NULL, NULL, &d);
 
-	if ((ctx = BN_CTX_new()) == NULL)
-		return SSH_ERR_ALLOC_FAIL;
-	if ((aux = BN_new()) == NULL) {
+	if ((ctx = BN_CTX_new()) == NULL ||
+	    (aux = BN_new()) == NULL ||
+	    (dmp1 = BN_new()) == NULL ||
+	    (dmq1 = BN_new()) == NULL) {
 		r = SSH_ERR_ALLOC_FAIL;
 		goto out;
 	}
 
-	if ((BN_sub(aux, rsa->q, BN_value_one()) == 0) ||
-	    (BN_mod(rsa->dmq1, rsa->d, aux, ctx) == 0) ||
-	    (BN_sub(aux, rsa->p, BN_value_one()) == 0) ||
-	    (BN_mod(rsa->dmp1, rsa->d, aux, ctx) == 0)) {
+	if ((BN_sub(aux, q, BN_value_one()) == 0) ||
+	    (BN_mod(dmq1, d, aux, ctx) == 0) ||
+	    (BN_sub(aux, p, BN_value_one()) == 0) ||
+	    (BN_mod(dmp1, d, aux, ctx) == 0) ||
+	    (RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp) == 0)) {
 		r = SSH_ERR_LIBCRYPTO_ERROR;
 		goto out;
 	}
+	dmp1 = NULL;
+	dmq1 = NULL;
 	r = 0;
  out:
 	BN_clear_free(aux);
+	BN_clear_free(dmp1);
+	BN_clear_free(dmq1);
 	BN_CTX_free(ctx);
 	return r;
 }
diff --git a/rsa.h b/rsa.h
index c476707..4da6936 100644
--- a/rsa.h
+++ b/rsa.h
@@ -21,6 +21,6 @@
 
 int	 rsa_public_encrypt(BIGNUM *, BIGNUM *, RSA *);
 int	 rsa_private_decrypt(BIGNUM *, BIGNUM *, RSA *);
-int	 rsa_generate_additional_parameters(RSA *);
+int	 rsa_generate_additional_parameters(RSA *, BIGNUM *);
 
 #endif				/* RSA_H */
diff --git a/ssh-dss.c b/ssh-dss.c
index 7af59fa..e36751e 100644
--- a/ssh-dss.c
+++ b/ssh-dss.c
@@ -55,6 +55,7 @@ ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
 	size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
 	struct sshbuf *b = NULL;
 	int ret = SSH_ERR_INVALID_ARGUMENT;
+	const BIGNUM *r, *s;
 
 	if (lenp != NULL)
 		*lenp = 0;
@@ -76,15 +77,16 @@ ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
 		goto out;
 	}
 
-	rlen = BN_num_bytes(sig->r);
-	slen = BN_num_bytes(sig->s);
+	DSA_SIG_get0(sig, &r, &s);
+	rlen = BN_num_bytes(r);
+	slen = BN_num_bytes(s);
 	if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
 		ret = SSH_ERR_INTERNAL_ERROR;
 		goto out;
 	}
 	explicit_bzero(sigblob, SIGBLOB_LEN);
-	BN_bn2bin(sig->r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen);
-	BN_bn2bin(sig->s, sigblob + SIGBLOB_LEN - slen);
+	BN_bn2bin(r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen);
+	BN_bn2bin(s, sigblob + SIGBLOB_LEN - slen);
 
 	if (compat & SSH_BUG_SIGBLOB) {
 		if (sigp != NULL) {
@@ -137,6 +139,7 @@ ssh_dss_verify(const struct sshkey *key,
 	int ret = SSH_ERR_INTERNAL_ERROR;
 	struct sshbuf *b = NULL;
 	char *ktype = NULL;
+	BIGNUM *r = NULL, *s = NULL;
 
 	if (key == NULL || key->dsa == NULL ||
 	    sshkey_type_plain(key->type) != KEY_DSA ||
@@ -177,16 +180,19 @@ ssh_dss_verify(const struct sshkey *key,
 
 	/* parse signature */
 	if ((sig = DSA_SIG_new()) == NULL ||
-	    (sig->r = BN_new()) == NULL ||
-	    (sig->s = BN_new()) == NULL) {
+	    (r = BN_new()) == NULL ||
+	    (s = BN_new()) == NULL) {
 		ret = SSH_ERR_ALLOC_FAIL;
 		goto out;
 	}
-	if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig->r) == NULL) ||
-	    (BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s) == NULL)) {
+	if ((BN_bin2bn(sigblob, INTBLOB_LEN, r) == NULL) ||
+	    (BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, s) == NULL) ||
+	    (DSA_SIG_set0(sig, r, s) == 0)) {
 		ret = SSH_ERR_LIBCRYPTO_ERROR;
 		goto out;
 	}
+	r = NULL;
+	s = NULL;
 
 	/* sha1 the data */
 	if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen,
@@ -207,8 +213,9 @@ ssh_dss_verify(const struct sshkey *key,
 
  out:
 	explicit_bzero(digest, sizeof(digest));
-	if (sig != NULL)
-		DSA_SIG_free(sig);
+	BN_free(r);
+	BN_free(s);
+	DSA_SIG_free(sig);
 	sshbuf_free(b);
 	free(ktype);
 	if (sigblob != NULL) {
diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c
index d7bf3c6..985b7e5 100644
--- a/ssh-ecdsa.c
+++ b/ssh-ecdsa.c
@@ -54,6 +54,7 @@ ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
 	size_t len, dlen;
 	struct sshbuf *b = NULL, *bb = NULL;
 	int ret = SSH_ERR_INTERNAL_ERROR;
+	const BIGNUM *r, *s;
 
 	if (lenp != NULL)
 		*lenp = 0;
@@ -80,8 +81,9 @@ ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
 		ret = SSH_ERR_ALLOC_FAIL;
 		goto out;
 	}
-	if ((ret = sshbuf_put_bignum2(bb, sig->r)) != 0 ||
-	    (ret = sshbuf_put_bignum2(bb, sig->s)) != 0)
+	ECDSA_SIG_get0(sig, &r, &s);
+	if ((ret = sshbuf_put_bignum2(bb, r)) != 0 ||
+	    (ret = sshbuf_put_bignum2(bb, s)) != 0)
 		goto out;
 	if ((ret = sshbuf_put_cstring(b, sshkey_ssh_name_plain(key))) != 0 ||
 	    (ret = sshbuf_put_stringb(b, bb)) != 0)
@@ -119,6 +121,7 @@ ssh_ecdsa_verify(const struct sshkey *key,
 	int ret = SSH_ERR_INTERNAL_ERROR;
 	struct sshbuf *b = NULL, *sigbuf = NULL;
 	char *ktype = NULL;
+	BIGNUM *r = NULL, *s = NULL;
 
 	if (key == NULL || key->ecdsa == NULL ||
 	    sshkey_type_plain(key->type) != KEY_ECDSA ||
@@ -147,15 +150,23 @@ ssh_ecdsa_verify(const struct sshkey *key,
 	}
 
 	/* parse signature */
-	if ((sig = ECDSA_SIG_new()) == NULL) {
+	if ((sig = ECDSA_SIG_new()) == NULL ||
+	    (r = BN_new()) == NULL ||
+	    (s = BN_new()) == NULL) {
 		ret = SSH_ERR_ALLOC_FAIL;
 		goto out;
 	}
-	if (sshbuf_get_bignum2(sigbuf, sig->r) != 0 ||
-	    sshbuf_get_bignum2(sigbuf, sig->s) != 0) {
+	if (sshbuf_get_bignum2(sigbuf, r) != 0 ||
+	    sshbuf_get_bignum2(sigbuf, s) != 0) {
 		ret = SSH_ERR_INVALID_FORMAT;
 		goto out;
 	}
+	if (ECDSA_SIG_set0(sig, r, s) == 0) {
+		ret = SSH_ERR_LIBCRYPTO_ERROR;
+		goto out;
+	}
+	r = NULL;
+	s = NULL;
 	if (sshbuf_len(sigbuf) != 0) {
 		ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
 		goto out;
@@ -180,8 +191,9 @@ ssh_ecdsa_verify(const struct sshkey *key,
 	explicit_bzero(digest, sizeof(digest));
 	sshbuf_free(sigbuf);
 	sshbuf_free(b);
-	if (sig != NULL)
-		ECDSA_SIG_free(sig);
+	BN_free(r);
+	BN_free(s);
+	ECDSA_SIG_free(sig);
 	free(ktype);
 	return ret;
 }
diff --git a/ssh-keygen.c b/ssh-keygen.c
index 2a7939b..95cfed8 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -480,40 +480,67 @@ do_convert_private_ssh2_from_blob(u_char *blob, u_int blen)
 	free(type);
 
 	switch (key->type) {
-	case KEY_DSA:
-		buffer_get_bignum_bits(b, key->dsa->p);
-		buffer_get_bignum_bits(b, key->dsa->g);
-		buffer_get_bignum_bits(b, key->dsa->q);
-		buffer_get_bignum_bits(b, key->dsa->pub_key);
-		buffer_get_bignum_bits(b, key->dsa->priv_key);
+	case KEY_DSA: {
+			BIGNUM *p = NULL, *g = NULL, *q = NULL, *pub_key = NULL, *priv_key = NULL;
+
+			if ((p = BN_new()) == NULL ||
+			    (g = BN_new()) == NULL ||
+			    (q = BN_new()) == NULL ||
+			    (pub_key = BN_new()) == NULL ||
+			    (priv_key = BN_new()) == NULL)
+				fatal("BN_new() failed");
+			buffer_get_bignum_bits(b, p);
+			buffer_get_bignum_bits(b, g);
+			buffer_get_bignum_bits(b, q);
+			buffer_get_bignum_bits(b, pub_key);
+			buffer_get_bignum_bits(b, priv_key);
+			if (DSA_set0_pqg(key->dsa, p, q, g) == 0 ||
+			    DSA_set0_key(key->dsa, pub_key, priv_key) == 0) {
+				fatal("failed to set DSA key");
+			}
+		}
 		break;
-	case KEY_RSA:
-		if ((r = sshbuf_get_u8(b, &e1)) != 0 ||
-		    (e1 < 30 && (r = sshbuf_get_u8(b, &e2)) != 0) ||
-		    (e1 < 30 && (r = sshbuf_get_u8(b, &e3)) != 0))
-			fatal("%s: buffer error: %s", __func__, ssh_err(r));
-		e = e1;
-		debug("e %lx", e);
-		if (e < 30) {
-			e <<= 8;
-			e += e2;
+	case KEY_RSA: {
+			BIGNUM *bn_e = NULL, *bn_d = NULL, *bn_n = NULL, *bn_iqmp = NULL, *bn_p = NULL, *bn_q = NULL;
+
+			if ((bn_e = BN_new()) == NULL ||
+			    (bn_d = BN_new()) == NULL ||
+			    (bn_n = BN_new()) == NULL ||
+			    (bn_iqmp = BN_new()) == NULL ||
+			    (bn_p = BN_new()) == NULL ||
+			    (bn_q = BN_new()) == NULL)
+				fatal("BN_new() failed");
+
+			if ((r = sshbuf_get_u8(b, &e1)) != 0 ||
+			    (e1 < 30 && (r = sshbuf_get_u8(b, &e2)) != 0) ||
+			    (e1 < 30 && (r = sshbuf_get_u8(b, &e3)) != 0))
+				fatal("%s: buffer error: %s", __func__, ssh_err(r));
+			e = e1;
 			debug("e %lx", e);
-			e <<= 8;
-			e += e3;
-			debug("e %lx", e);
-		}
-		if (!BN_set_word(key->rsa->e, e)) {
-			sshbuf_free(b);
-			sshkey_free(key);
-			return NULL;
+			if (e < 30) {
+				e <<= 8;
+				e += e2;
+				debug("e %lx", e);
+				e <<= 8;
+				e += e3;
+				debug("e %lx", e);
+			}
+			if (!BN_set_word(bn_e, e)) {
+				sshbuf_free(b);
+				sshkey_free(key);
+				return NULL;
+			}
+			buffer_get_bignum_bits(b, bn_d);
+			buffer_get_bignum_bits(b, bn_n);
+			buffer_get_bignum_bits(b, bn_iqmp);
+			buffer_get_bignum_bits(b, bn_q);
+			buffer_get_bignum_bits(b, bn_p);
+			if (RSA_set0_key(key->rsa, bn_n, bn_e, bn_d) == 0 ||
+			    RSA_set0_factors(key->rsa, bn_p, bn_q) == 0)
+				fatal("Failed to set RSA parameters");
+			if ((r = rsa_generate_additional_parameters(key->rsa, bn_iqmp)) != 0)
+				fatal("generate RSA parameters failed: %s", ssh_err(r));
 		}
-		buffer_get_bignum_bits(b, key->rsa->d);
-		buffer_get_bignum_bits(b, key->rsa->n);
-		buffer_get_bignum_bits(b, key->rsa->iqmp);
-		buffer_get_bignum_bits(b, key->rsa->q);
-		buffer_get_bignum_bits(b, key->rsa->p);
-		if ((r = rsa_generate_additional_parameters(key->rsa)) != 0)
-			fatal("generate RSA parameters failed: %s", ssh_err(r));
 		break;
 	}
 	rlen = sshbuf_len(b);
@@ -621,7 +648,7 @@ do_convert_from_pkcs8(struct sshkey **k, int *private)
 		    identity_file);
 	}
 	fclose(fp);
-	switch (EVP_PKEY_type(pubkey->type)) {
+	switch (EVP_PKEY_base_id(pubkey)) {
 	case EVP_PKEY_RSA:
 		if ((*k = sshkey_new(KEY_UNSPEC)) == NULL)
 			fatal("sshkey_new failed");
@@ -645,7 +672,7 @@ do_convert_from_pkcs8(struct sshkey **k, int *private)
 #endif
 	default:
 		fatal("%s: unsupported pubkey type %d", __func__,
-		    EVP_PKEY_type(pubkey->type));
+		    EVP_PKEY_base_id(pubkey));
 	}
 	EVP_PKEY_free(pubkey);
 	return;
diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c
index fac0167..b82deec 100644
--- a/ssh-pkcs11-client.c
+++ b/ssh-pkcs11-client.c
@@ -143,12 +143,14 @@ pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
 static int
 wrap_key(RSA *rsa)
 {
-	static RSA_METHOD helper_rsa;
+	static RSA_METHOD *helper_rsa;
 
-	memcpy(&helper_rsa, RSA_get_default_method(), sizeof(helper_rsa));
-	helper_rsa.name = "ssh-pkcs11-helper";
-	helper_rsa.rsa_priv_enc = pkcs11_rsa_private_encrypt;
-	RSA_set_method(rsa, &helper_rsa);
+	if (helper_rsa == NULL) {
+		helper_rsa = RSA_meth_dup(RSA_get_default_method());
+		RSA_meth_set1_name(helper_rsa, "ssh-pkcs11-helper");
+		RSA_meth_set_priv_enc(helper_rsa, pkcs11_rsa_private_encrypt);
+	}
+	RSA_set_method(rsa, helper_rsa);
 	return (0);
 }
 
diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c
index d1f750d..18ce16e 100644
--- a/ssh-pkcs11.c
+++ b/ssh-pkcs11.c
@@ -67,7 +67,7 @@ struct pkcs11_key {
 	struct pkcs11_provider	*provider;
 	CK_ULONG		slotidx;
 	int			(*orig_finish)(RSA *rsa);
-	RSA_METHOD		rsa_method;
+	RSA_METHOD		*rsa_method;
 	char			*keyid;
 	int			keyid_len;
 };
@@ -326,13 +326,21 @@ pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
 		k11->keyid = xmalloc(k11->keyid_len);
 		memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
 	}
-	k11->orig_finish = def->finish;
-	memcpy(&k11->rsa_method, def, sizeof(k11->rsa_method));
-	k11->rsa_method.name = "pkcs11";
-	k11->rsa_method.rsa_priv_enc = pkcs11_rsa_private_encrypt;
-	k11->rsa_method.rsa_priv_dec = pkcs11_rsa_private_decrypt;
-	k11->rsa_method.finish = pkcs11_rsa_finish;
-	RSA_set_method(rsa, &k11->rsa_method);
+	k11->orig_finish = RSA_meth_get_finish(def);
+	if ((k11->rsa_method = RSA_meth_dup(def)) == NULL ||
+	    RSA_meth_set1_name(k11->rsa_method, "pkcs11") == 0 ||
+	    RSA_meth_set_priv_enc(k11->rsa_method, pkcs11_rsa_private_encrypt) == 0 ||
+	    RSA_meth_set_priv_dec(k11->rsa_method, pkcs11_rsa_private_decrypt) == 0 ||
+	    RSA_meth_set_finish(k11->rsa_method, pkcs11_rsa_finish) == 0) {
+		RSA_meth_free(k11->rsa_method);
+		k11->rsa_method = NULL;
+		pkcs11_provider_unref(k11->provider);
+		free(k11->keyid);
+		free(k11);
+		return (-1);
+	}
+
+	RSA_set_method(rsa, k11->rsa_method);
 	RSA_set_app_data(rsa, k11);
 	return (0);
 }
@@ -460,6 +468,7 @@ pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx,
 	CK_ULONG		nfound;
 	CK_SESSION_HANDLE	session;
 	CK_FUNCTION_LIST	*f;
+	const BIGNUM		*n, *e;
 
 	f = p->function_list;
 	session = p->slotinfo[slotidx].session;
@@ -512,10 +521,14 @@ pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx,
 			if ((rsa = RSA_new()) == NULL) {
 				error("RSA_new failed");
 			} else {
-				rsa->n = BN_bin2bn(attribs[1].pValue,
+				BIGNUM *rsa_n, *rsa_e;
+
+				rsa_n = BN_bin2bn(attribs[1].pValue,
 				    attribs[1].ulValueLen, NULL);
-				rsa->e = BN_bin2bn(attribs[2].pValue,
+				rsa_e = BN_bin2bn(attribs[2].pValue,
 				    attribs[2].ulValueLen, NULL);
+				if (RSA_set0_key(rsa, rsa_n, rsa_e, NULL) == 0)
+					error("RSA_set0_key failed");
 			}
 		} else {
 			cp = attribs[2].pValue;
@@ -525,17 +538,18 @@ pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx,
 			    == NULL) {
 				error("d2i_X509 failed");
 			} else if ((evp = X509_get_pubkey(x509)) == NULL ||
-			    evp->type != EVP_PKEY_RSA ||
-			    evp->pkey.rsa == NULL) {
+			    EVP_PKEY_id(evp) != EVP_PKEY_RSA ||
+			    EVP_PKEY_get0_RSA(evp) == NULL) {
 				debug("X509_get_pubkey failed or no rsa");
-			} else if ((rsa = RSAPublicKey_dup(evp->pkey.rsa))
+			} else if ((rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(evp)))
 			    == NULL) {
 				error("RSAPublicKey_dup");
 			}
 			if (x509)
 				X509_free(x509);
 		}
-		if (rsa && rsa->n && rsa->e &&
+		RSA_get0_key(rsa, &n, &e, NULL);
+		if (rsa && n && e &&
 		    pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0) {
 			key = sshkey_new(KEY_UNSPEC);
 			key->rsa = rsa;
diff --git a/ssh-rsa.c b/ssh-rsa.c
index cde05df..8197949 100644
--- a/ssh-rsa.c
+++ b/ssh-rsa.c
@@ -88,6 +88,7 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
 	u_int dlen, len;
 	int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR;
 	struct sshbuf *b = NULL;
+	const BIGNUM *n;
 
 	if (lenp != NULL)
 		*lenp = 0;
@@ -99,8 +100,10 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
 	else
 		hash_alg = rsa_hash_alg_from_ident(alg_ident);
 	if (key == NULL || key->rsa == NULL || hash_alg == -1 ||
-	    sshkey_type_plain(key->type) != KEY_RSA ||
-	    BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
+	    sshkey_type_plain(key->type) != KEY_RSA)
+		return SSH_ERR_INVALID_ARGUMENT;
+	RSA_get0_key(key->rsa, &n, NULL, NULL);
+	if (BN_num_bits(n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
 		return SSH_ERR_INVALID_ARGUMENT;
 	slen = RSA_size(key->rsa);
 	if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM)
@@ -169,12 +172,15 @@ ssh_rsa_verify(const struct sshkey *key,
 	size_t len, diff, modlen, dlen;
 	struct sshbuf *b = NULL;
 	u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL;
+	const BIGNUM *n;
 
 	if (key == NULL || key->rsa == NULL ||
 	    sshkey_type_plain(key->type) != KEY_RSA ||
-	    BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE ||
 	    sig == NULL || siglen == 0)
 		return SSH_ERR_INVALID_ARGUMENT;
+	RSA_get0_key(key->rsa, &n, NULL, NULL);
+	if (BN_num_bits(n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
+		return SSH_ERR_INVALID_ARGUMENT;
 
 	if ((b = sshbuf_from(sig, siglen)) == NULL)
 		return SSH_ERR_ALLOC_FAIL;
diff --git a/sshkey.c b/sshkey.c
index c01da6c..f43b11a 100644
--- a/sshkey.c
+++ b/sshkey.c
@@ -266,15 +266,18 @@ sshkey_names_valid2(const char *names, int allow_wildcard)
 u_int
 sshkey_size(const struct sshkey *k)
 {
+	const BIGNUM *bn;
 	switch (k->type) {
 #ifdef WITH_OPENSSL
 	case KEY_RSA1:
 	case KEY_RSA:
 	case KEY_RSA_CERT:
-		return BN_num_bits(k->rsa->n);
+		RSA_get0_key(k->rsa, &bn, NULL, NULL);
+		return BN_num_bits(bn);
 	case KEY_DSA:
 	case KEY_DSA_CERT:
-		return BN_num_bits(k->dsa->p);
+		DSA_get0_pqg(k->dsa, &bn, NULL, NULL);
+		return BN_num_bits(bn);
 	case KEY_ECDSA:
 	case KEY_ECDSA_CERT:
 		return sshkey_curve_nid_to_bits(k->ecdsa_nid);
@@ -474,11 +477,7 @@ sshkey_new(int type)
 	case KEY_RSA1:
 	case KEY_RSA:
 	case KEY_RSA_CERT:
-		if ((rsa = RSA_new()) == NULL ||
-		    (rsa->n = BN_new()) == NULL ||
-		    (rsa->e = BN_new()) == NULL) {
-			if (rsa != NULL)
-				RSA_free(rsa);
+		if ((rsa = RSA_new()) == NULL) {
 			free(k);
 			return NULL;
 		}
@@ -486,13 +485,7 @@ sshkey_new(int type)
 		break;
 	case KEY_DSA:
 	case KEY_DSA_CERT:
-		if ((dsa = DSA_new()) == NULL ||
-		    (dsa->p = BN_new()) == NULL ||
-		    (dsa->q = BN_new()) == NULL ||
-		    (dsa->g = BN_new()) == NULL ||
-		    (dsa->pub_key = BN_new()) == NULL) {
-			if (dsa != NULL)
-				DSA_free(dsa);
+		if ((dsa = DSA_new()) == NULL) {
 			free(k);
 			return NULL;
 		}
@@ -532,21 +525,10 @@ sshkey_add_private(struct sshkey *k)
 	case KEY_RSA1:
 	case KEY_RSA:
 	case KEY_RSA_CERT:
-#define bn_maybe_alloc_failed(p) (p == NULL && (p = BN_new()) == NULL)
-		if (bn_maybe_alloc_failed(k->rsa->d) ||
-		    bn_maybe_alloc_failed(k->rsa->iqmp) ||
-		    bn_maybe_alloc_failed(k->rsa->q) ||
-		    bn_maybe_alloc_failed(k->rsa->p) ||
-		    bn_maybe_alloc_failed(k->rsa->dmq1) ||
-		    bn_maybe_alloc_failed(k->rsa->dmp1))
-			return SSH_ERR_ALLOC_FAIL;
 		break;
 	case KEY_DSA:
 	case KEY_DSA_CERT:
-		if (bn_maybe_alloc_failed(k->dsa->priv_key))
-			return SSH_ERR_ALLOC_FAIL;
 		break;
-#undef bn_maybe_alloc_failed
 	case KEY_ECDSA:
 	case KEY_ECDSA_CERT:
 		/* Cannot do anything until we know the group */
@@ -665,17 +647,31 @@ sshkey_equal_public(const struct sshkey *a, const struct sshkey *b)
 #ifdef WITH_OPENSSL
 	case KEY_RSA1:
 	case KEY_RSA_CERT:
-	case KEY_RSA:
-		return a->rsa != NULL && b->rsa != NULL &&
-		    BN_cmp(a->rsa->e, b->rsa->e) == 0 &&
-		    BN_cmp(a->rsa->n, b->rsa->n) == 0;
+	case KEY_RSA: {
+			const BIGNUM *a_e, *a_n, *b_e, *b_n;
+
+			if (a->rsa == NULL || b->rsa == NULL)
+				return 0;
+			RSA_get0_key(a->rsa, &a_n, &a_e, NULL);
+			RSA_get0_key(b->rsa, &b_n, &b_e, NULL);
+			return BN_cmp(a_e, b_e) == 0 && BN_cmp(a_n, b_n) == 0;
+		}
 	case KEY_DSA_CERT:
-	case KEY_DSA:
-		return a->dsa != NULL && b->dsa != NULL &&
-		    BN_cmp(a->dsa->p, b->dsa->p) == 0 &&
-		    BN_cmp(a->dsa->q, b->dsa->q) == 0 &&
-		    BN_cmp(a->dsa->g, b->dsa->g) == 0 &&
-		    BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0;
+	case KEY_DSA: {
+			const BIGNUM *a_p, *a_q, *a_g, *a_pub_key;
+			const BIGNUM *b_p, *b_q, *b_g, *b_pub_key;
+
+			if (a->dsa == NULL || b->dsa == NULL)
+				return 0;
+			DSA_get0_pqg(a->dsa, &a_p, &a_q, &a_g);
+			DSA_get0_key(a->dsa, &a_pub_key, NULL);
+			DSA_get0_pqg(b->dsa, &b_p, &b_q, &b_g);
+			DSA_get0_key(b->dsa, &b_pub_key, NULL);
+			return BN_cmp(a_p, b_p) == 0 &&
+			    BN_cmp(a_q, b_q) == 0 &&
+			    BN_cmp(a_g, b_g) == 0 &&
+			    BN_cmp(a_pub_key, b_pub_key) == 0;
+		}
 # ifdef OPENSSL_HAS_ECC
 	case KEY_ECDSA_CERT:
 	case KEY_ECDSA:
@@ -750,15 +746,21 @@ to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain)
 			return ret;
 		break;
 #ifdef WITH_OPENSSL
-	case KEY_DSA:
-		if (key->dsa == NULL)
-			return SSH_ERR_INVALID_ARGUMENT;
-		if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
-		    (ret = sshbuf_put_bignum2(b, key->dsa->p)) != 0 ||
-		    (ret = sshbuf_put_bignum2(b, key->dsa->q)) != 0 ||
-		    (ret = sshbuf_put_bignum2(b, key->dsa->g)) != 0 ||
-		    (ret = sshbuf_put_bignum2(b, key->dsa->pub_key)) != 0)
-			return ret;
+	case KEY_DSA: {
+			const BIGNUM *p, *q, *g, *pub_key;
+
+			if (key->dsa == NULL)
+				return SSH_ERR_INVALID_ARGUMENT;
+
+			DSA_get0_pqg(key->dsa, &p, &q, &g);
+			DSA_get0_key(key->dsa, &pub_key, NULL);
+			if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
+			    (ret = sshbuf_put_bignum2(b, p)) != 0 ||
+			    (ret = sshbuf_put_bignum2(b, q)) != 0 ||
+			    (ret = sshbuf_put_bignum2(b, g)) != 0 ||
+			    (ret = sshbuf_put_bignum2(b, pub_key)) != 0)
+				return ret;
+		}
 		break;
 # ifdef OPENSSL_HAS_ECC
 	case KEY_ECDSA:
@@ -771,13 +773,18 @@ to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain)
 			return ret;
 		break;
 # endif
-	case KEY_RSA:
-		if (key->rsa == NULL)
-			return SSH_ERR_INVALID_ARGUMENT;
-		if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
-		    (ret = sshbuf_put_bignum2(b, key->rsa->e)) != 0 ||
-		    (ret = sshbuf_put_bignum2(b, key->rsa->n)) != 0)
-			return ret;
+	case KEY_RSA: {
+			const BIGNUM *e, *n;
+
+			if (key->rsa == NULL)
+				return SSH_ERR_INVALID_ARGUMENT;
+
+			RSA_get0_key(key->rsa, &n, &e, NULL);
+			if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
+			    (ret = sshbuf_put_bignum2(b, e)) != 0 ||
+			    (ret = sshbuf_put_bignum2(b, n)) != 0)
+				return ret;
+		}
 		break;
 #endif /* WITH_OPENSSL */
 	case KEY_ED25519:
@@ -883,8 +890,13 @@ sshkey_fingerprint_raw(const struct sshkey *k, int dgst_alg,
 
 	if (k->type == KEY_RSA1) {
 #ifdef WITH_OPENSSL
-		int nlen = BN_num_bytes(k->rsa->n);
-		int elen = BN_num_bytes(k->rsa->e);
+		const BIGNUM *n, *e;
+		int nlen, elen;
+
+		RSA_get0_key(k->rsa, &n, &e, NULL);
+
+		nlen = BN_num_bytes(n);
+		elen = BN_num_bytes(e);
 
 		if (nlen < 0 || elen < 0 || nlen >= INT_MAX - elen) {
 			r = SSH_ERR_INVALID_FORMAT;
@@ -895,8 +907,8 @@ sshkey_fingerprint_raw(const struct sshkey *k, int dgst_alg,
 			r = SSH_ERR_ALLOC_FAIL;
 			goto out;
 		}
-		BN_bn2bin(k->rsa->n, blob);
-		BN_bn2bin(k->rsa->e, blob + nlen);
+		BN_bn2bin(n, blob);
+		BN_bn2bin(e, blob + nlen);
 #endif /* WITH_OPENSSL */
 	} else if ((r = to_blob(k, &blob, &blob_len, 1)) != 0)
 		goto out;
@@ -1762,15 +1774,32 @@ sshkey_from_private(const struct sshkey *k, struct sshkey **pkp)
 	switch (k->type) {
 #ifdef WITH_OPENSSL
 	case KEY_DSA:
-	case KEY_DSA_CERT:
-		if ((n = sshkey_new(k->type)) == NULL)
-			return SSH_ERR_ALLOC_FAIL;
-		if ((BN_copy(n->dsa->p, k->dsa->p) == NULL) ||
-		    (BN_copy(n->dsa->q, k->dsa->q) == NULL) ||
-		    (BN_copy(n->dsa->g, k->dsa->g) == NULL) ||
-		    (BN_copy(n->dsa->pub_key, k->dsa->pub_key) == NULL)) {
-			sshkey_free(n);
-			return SSH_ERR_ALLOC_FAIL;
+	case KEY_DSA_CERT: {
+			const BIGNUM *k_p, *k_q, *k_g, *k_pub_key;
+			BIGNUM *n_p = NULL, *n_q = NULL, *n_g = NULL, *n_pub_key = NULL;
+
+			if ((n = sshkey_new(k->type)) == NULL)
+				return SSH_ERR_ALLOC_FAIL;
+
+			DSA_get0_pqg(k->dsa, &k_p, &k_q, &k_g);
+			DSA_get0_key(k->dsa, &k_pub_key, NULL);
+
+			if (((n_p = BN_dup(k_p)) == NULL) ||
+			    ((n_q = BN_dup(k_q)) == NULL) ||
+			    ((n_g = BN_dup(k_g)) == NULL) ||
+			    (DSA_set0_pqg(n->dsa, n_p, n_q, n_g) == 0)) {
+				sshkey_free(n);
+				BN_free(n_p);
+				BN_free(n_q);
+				BN_free(n_g);
+				return SSH_ERR_ALLOC_FAIL;
+			}
+			if (((n_pub_key = BN_dup(k_pub_key)) == NULL) ||
+			    (DSA_set0_key(n->dsa, n_pub_key, NULL) == 0)) {
+				sshkey_free(n);
+				BN_free(n_pub_key);
+				return SSH_ERR_ALLOC_FAIL;
+			}
 		}
 		break;
 # ifdef OPENSSL_HAS_ECC
@@ -1793,13 +1822,22 @@ sshkey_from_private(const struct sshkey *k, struct sshkey **pkp)
 # endif /* OPENSSL_HAS_ECC */
 	case KEY_RSA:
 	case KEY_RSA1:
-	case KEY_RSA_CERT:
-		if ((n = sshkey_new(k->type)) == NULL)
-			return SSH_ERR_ALLOC_FAIL;
-		if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) ||
-		    (BN_copy(n->rsa->e, k->rsa->e) == NULL)) {
-			sshkey_free(n);
-			return SSH_ERR_ALLOC_FAIL;
+	case KEY_RSA_CERT: {
+			const BIGNUM *k_n, *k_e;
+			BIGNUM *n_n = NULL, *n_e = NULL;
+
+			if ((n = sshkey_new(k->type)) == NULL)
+				return SSH_ERR_ALLOC_FAIL;
+
+			RSA_get0_key(k->rsa, &k_n, &k_e, NULL);
+			if (((n_n = BN_dup(k_n)) == NULL) ||
+			    ((n_e = BN_dup(k_e)) == NULL) ||
+			    (RSA_set0_key(n->rsa, n_n, n_e, NULL) == 0)) {
+				sshkey_free(n);
+				BN_free(n_n);
+				BN_free(n_e);
+				return SSH_ERR_ALLOC_FAIL;
+			}
 		}
 		break;
 #endif /* WITH_OPENSSL */
@@ -1997,10 +2035,20 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
 			ret = SSH_ERR_ALLOC_FAIL;
 			goto out;
 		}
-		if (sshbuf_get_bignum2(b, key->rsa->e) != 0 ||
-		    sshbuf_get_bignum2(b, key->rsa->n) != 0) {
-			ret = SSH_ERR_INVALID_FORMAT;
-			goto out;
+		{
+			BIGNUM *e, *n;
+
+			e = BN_new();
+			n = BN_new();
+			if (e == NULL || n == NULL ||
+			    sshbuf_get_bignum2(b, e) != 0 ||
+			    sshbuf_get_bignum2(b, n) != 0 ||
+			    RSA_set0_key(key->rsa, n, e, NULL) == 0) {
+				BN_free(e);
+				BN_free(n);
+				ret = SSH_ERR_ALLOC_FAIL;
+				goto out;
+			}
 		}
 #ifdef DEBUG_PK
 		RSA_print_fp(stderr, key->rsa, 8);
@@ -2018,12 +2066,34 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
 			ret = SSH_ERR_ALLOC_FAIL;
 			goto out;
 		}
-		if (sshbuf_get_bignum2(b, key->dsa->p) != 0 ||
-		    sshbuf_get_bignum2(b, key->dsa->q) != 0 ||
-		    sshbuf_get_bignum2(b, key->dsa->g) != 0 ||
-		    sshbuf_get_bignum2(b, key->dsa->pub_key) != 0) {
-			ret = SSH_ERR_INVALID_FORMAT;
-			goto out;
+		{
+			BIGNUM *p, *q, *g, *pub_key;
+
+			p = BN_new();
+			q = BN_new();
+			g = BN_new();
+			pub_key = BN_new();
+
+			if (p == NULL || q == NULL || g == NULL ||
+			    pub_key == NULL ||
+			    sshbuf_get_bignum2(b, p) != 0 ||
+			    sshbuf_get_bignum2(b, q) != 0 ||
+			    sshbuf_get_bignum2(b, g) != 0 ||
+			    sshbuf_get_bignum2(b, pub_key) != 0 ||
+			    DSA_set0_pqg(key->dsa, p, q, g) == 0) {
+				BN_free(p);
+				BN_free(q);
+				BN_free(g);
+				BN_free(pub_key);
+				ret = SSH_ERR_ALLOC_FAIL;
+				goto out;
+			}
+
+			if (DSA_set0_key(key->dsa, pub_key, NULL) == 0) {
+				BN_free(pub_key);
+				ret = SSH_ERR_LIBCRYPTO_ERROR;
+				goto out;
+			}
 		}
 #ifdef DEBUG_PK
 		DSA_print_fp(stderr, key->dsa, 8);
@@ -2263,26 +2333,53 @@ sshkey_demote(const struct sshkey *k, struct sshkey **dkp)
 			goto fail;
 		/* FALLTHROUGH */
 	case KEY_RSA1:
-	case KEY_RSA:
-		if ((pk->rsa = RSA_new()) == NULL ||
-		    (pk->rsa->e = BN_dup(k->rsa->e)) == NULL ||
-		    (pk->rsa->n = BN_dup(k->rsa->n)) == NULL) {
-			ret = SSH_ERR_ALLOC_FAIL;
-			goto fail;
+	case KEY_RSA: {
+			const BIGNUM *k_e, *k_n;
+			BIGNUM *pk_e = NULL, *pk_n = NULL;
+
+			RSA_get0_key(k->rsa, &k_n, &k_e, NULL);
+			if ((pk->rsa = RSA_new()) == NULL ||
+			    (pk_e = BN_dup(k_e)) == NULL ||
+			    (pk_n = BN_dup(k_n)) == NULL ||
+			    RSA_set0_key(pk->rsa, pk_n, pk_e, NULL) == 0) {
+				BN_free(pk_e);
+				BN_free(pk_n);
+				ret = SSH_ERR_ALLOC_FAIL;
+				goto fail;
 			}
+		}
 		break;
 	case KEY_DSA_CERT:
 		if ((ret = sshkey_cert_copy(k, pk)) != 0)
 			goto fail;
 		/* FALLTHROUGH */
-	case KEY_DSA:
-		if ((pk->dsa = DSA_new()) == NULL ||
-		    (pk->dsa->p = BN_dup(k->dsa->p)) == NULL ||
-		    (pk->dsa->q = BN_dup(k->dsa->q)) == NULL ||
-		    (pk->dsa->g = BN_dup(k->dsa->g)) == NULL ||
-		    (pk->dsa->pub_key = BN_dup(k->dsa->pub_key)) == NULL) {
-			ret = SSH_ERR_ALLOC_FAIL;
-			goto fail;
+	case KEY_DSA: {
+			const BIGNUM *k_p, *k_q, *k_g, *k_pub_key;
+			BIGNUM *pk_p = NULL, *pk_q = NULL, *pk_g = NULL;
+			BIGNUM *pk_pub_key = NULL;
+
+			DSA_get0_pqg(k->dsa, &k_p, &k_q, &k_g);
+			DSA_get0_key(k->dsa, &k_pub_key, NULL);
+
+			if ((pk->dsa = DSA_new()) == NULL ||
+			    (pk_p = BN_dup(k_p)) == NULL ||
+			    (pk_q = BN_dup(k_q)) == NULL ||
+			    (pk_g = BN_dup(k_g)) == NULL ||
+			    (pk_pub_key = BN_dup(k_pub_key)) == NULL ||
+			    DSA_set0_pqg(pk->dsa, pk_p, pk_q, pk_g) == 0) {
+				BN_free(pk_p);
+				BN_free(pk_q);
+				BN_free(pk_g);
+				BN_free(pk_pub_key);
+				ret = SSH_ERR_ALLOC_FAIL;
+				goto fail;
+			}
+
+			if (DSA_set0_key(pk->dsa, pk_pub_key, NULL) == 0) {
+				BN_free(pk_pub_key);
+				ret = SSH_ERR_LIBCRYPTO_ERROR;
+				goto fail;
+			}
 		}
 		break;
 	case KEY_ECDSA_CERT:
@@ -2403,12 +2500,34 @@ sshkey_certify(struct sshkey *k, struct sshkey *ca, const char *alg)
 	/* XXX this substantially duplicates to_blob(); refactor */
 	switch (k->type) {
 #ifdef WITH_OPENSSL
-	case KEY_DSA_CERT:
-		if ((ret = sshbuf_put_bignum2(cert, k->dsa->p)) != 0 ||
-		    (ret = sshbuf_put_bignum2(cert, k->dsa->q)) != 0 ||
-		    (ret = sshbuf_put_bignum2(cert, k->dsa->g)) != 0 ||
-		    (ret = sshbuf_put_bignum2(cert, k->dsa->pub_key)) != 0)
-			goto out;
+	case KEY_DSA_CERT: {
+			BIGNUM *p, *q, *g, *pub_key;
+
+			p = BN_new();
+			q = BN_new();
+			g = BN_new();
+			pub_key = BN_new();
+
+			if (p == NULL || q == NULL || g == NULL ||
+			    pub_key == NULL ||
+			    (ret = sshbuf_put_bignum2(cert, p)) != 0 ||
+			    (ret = sshbuf_put_bignum2(cert, q)) != 0 ||
+			    (ret = sshbuf_put_bignum2(cert, g)) != 0 ||
+			    (ret = sshbuf_put_bignum2(cert, pub_key)) != 0 ||
+			    (ret = ((DSA_set0_pqg(k->dsa, p, q, g) == 0)
+			    ? SSH_ERR_LIBCRYPTO_ERROR : 0)) != 0) {
+				BN_free(p);
+				BN_free(q);
+				BN_free(g);
+				BN_free(pub_key);
+				goto out;
+			}
+			if (DSA_set0_key(k->dsa, pub_key, NULL) == 0) {
+				ret = SSH_ERR_LIBCRYPTO_ERROR;
+				BN_free(pub_key);
+				goto out;
+			}
+		}
 		break;
 # ifdef OPENSSL_HAS_ECC
 	case KEY_ECDSA_CERT:
@@ -2420,10 +2539,21 @@ sshkey_certify(struct sshkey *k, struct sshkey *ca, const char *alg)
 			goto out;
 		break;
 # endif /* OPENSSL_HAS_ECC */
-	case KEY_RSA_CERT:
-		if ((ret = sshbuf_put_bignum2(cert, k->rsa->e)) != 0 ||
-		    (ret = sshbuf_put_bignum2(cert, k->rsa->n)) != 0)
-			goto out;
+	case KEY_RSA_CERT: {
+			BIGNUM *e, *n;
+
+			e = BN_new();
+			n = BN_new();
+			if (e == NULL || n == NULL ||
+			    (ret = sshbuf_put_bignum2(cert, e)) != 0 ||
+			    (ret = sshbuf_put_bignum2(cert, n)) != 0 ||
+			    (ret = ((RSA_set0_key(k->rsa, n, e, NULL) == 0)
+			    ? SSH_ERR_LIBCRYPTO_ERROR : 0)) != 0) {
+				BN_free(e);
+				BN_free(n);
+				goto out;
+			}
+		}
 		break;
 #endif /* WITH_OPENSSL */
 	case KEY_ED25519_CERT:
@@ -2580,43 +2710,65 @@ sshkey_private_serialize(const struct sshkey *key, struct sshbuf *b)
 		goto out;
 	switch (key->type) {
 #ifdef WITH_OPENSSL
-	case KEY_RSA:
-		if ((r = sshbuf_put_bignum2(b, key->rsa->n)) != 0 ||
-		    (r = sshbuf_put_bignum2(b, key->rsa->e)) != 0 ||
-		    (r = sshbuf_put_bignum2(b, key->rsa->d)) != 0 ||
-		    (r = sshbuf_put_bignum2(b, key->rsa->iqmp)) != 0 ||
-		    (r = sshbuf_put_bignum2(b, key->rsa->p)) != 0 ||
-		    (r = sshbuf_put_bignum2(b, key->rsa->q)) != 0)
-			goto out;
+	case KEY_RSA: {
+			const BIGNUM *n, *e, *d, *iqmp, *p, *q;
+			RSA_get0_key(key->rsa, &n, &e, &d);
+			RSA_get0_crt_params(key->rsa, NULL, NULL, &iqmp);
+			RSA_get0_factors(key->rsa, &p, &q);
+			if ((r = sshbuf_put_bignum2(b, n)) != 0 ||
+			    (r = sshbuf_put_bignum2(b, e)) != 0 ||
+			    (r = sshbuf_put_bignum2(b, d)) != 0 ||
+			    (r = sshbuf_put_bignum2(b, iqmp)) != 0 ||
+			    (r = sshbuf_put_bignum2(b, p)) != 0 ||
+			    (r = sshbuf_put_bignum2(b, q)) != 0)
+				goto out;
+		}
 		break;
 	case KEY_RSA_CERT:
 		if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
 			r = SSH_ERR_INVALID_ARGUMENT;
 			goto out;
 		}
-		if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
-		    (r = sshbuf_put_bignum2(b, key->rsa->d)) != 0 ||
-		    (r = sshbuf_put_bignum2(b, key->rsa->iqmp)) != 0 ||
-		    (r = sshbuf_put_bignum2(b, key->rsa->p)) != 0 ||
-		    (r = sshbuf_put_bignum2(b, key->rsa->q)) != 0)
-			goto out;
+		{
+			const BIGNUM *d, *iqmp, *p, *q;
+
+			RSA_get0_key(key->rsa, NULL, NULL, &d);
+			RSA_get0_factors(key->rsa, &p, &q);
+			RSA_get0_crt_params(key->rsa, NULL, NULL, &iqmp);
+			if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
+			    (r = sshbuf_put_bignum2(b, d)) != 0 ||
+			    (r = sshbuf_put_bignum2(b, iqmp)) != 0 ||
+			    (r = sshbuf_put_bignum2(b, p)) != 0 ||
+			    (r = sshbuf_put_bignum2(b, q)) != 0)
+				goto out;
+		}
 		break;
-	case KEY_DSA:
-		if ((r = sshbuf_put_bignum2(b, key->dsa->p)) != 0 ||
-		    (r = sshbuf_put_bignum2(b, key->dsa->q)) != 0 ||
-		    (r = sshbuf_put_bignum2(b, key->dsa->g)) != 0 ||
-		    (r = sshbuf_put_bignum2(b, key->dsa->pub_key)) != 0 ||
-		    (r = sshbuf_put_bignum2(b, key->dsa->priv_key)) != 0)
-			goto out;
+	case KEY_DSA: {
+			const BIGNUM *p, *q, *g, *pub_key, *priv_key;
+
+			DSA_get0_pqg(key->dsa, &p, &q, &g);
+			DSA_get0_key(key->dsa, &pub_key, &priv_key);
+			if ((r = sshbuf_put_bignum2(b, p)) != 0 ||
+			    (r = sshbuf_put_bignum2(b, q)) != 0 ||
+			    (r = sshbuf_put_bignum2(b, g)) != 0 ||
+			    (r = sshbuf_put_bignum2(b, pub_key)) != 0 ||
+			    (r = sshbuf_put_bignum2(b, priv_key)) != 0)
+				goto out;
+		}
 		break;
 	case KEY_DSA_CERT:
 		if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) {
 			r = SSH_ERR_INVALID_ARGUMENT;
 			goto out;
 		}
-		if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
-		    (r = sshbuf_put_bignum2(b, key->dsa->priv_key)) != 0)
-			goto out;
+		{
+			const BIGNUM *priv_key;
+
+			DSA_get0_key(key->dsa, NULL, &priv_key);
+			if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
+			    (r = sshbuf_put_bignum2(b, priv_key)) != 0)
+				goto out;
+		}
 		break;
 # ifdef OPENSSL_HAS_ECC
 	case KEY_ECDSA:
@@ -2692,18 +2844,51 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
 			r = SSH_ERR_ALLOC_FAIL;
 			goto out;
 		}
-		if ((r = sshbuf_get_bignum2(buf, k->dsa->p)) != 0 ||
-		    (r = sshbuf_get_bignum2(buf, k->dsa->q)) != 0 ||
-		    (r = sshbuf_get_bignum2(buf, k->dsa->g)) != 0 ||
-		    (r = sshbuf_get_bignum2(buf, k->dsa->pub_key)) != 0 ||
-		    (r = sshbuf_get_bignum2(buf, k->dsa->priv_key)) != 0)
-			goto out;
+		{
+			BIGNUM *p, *q, *g, *pub_key, *priv_key;
+
+			p = BN_new();
+			q = BN_new();
+			g = BN_new();
+			pub_key = BN_new();
+			priv_key = BN_new();
+			if (p == NULL || q == NULL || g == NULL ||
+			    pub_key == NULL || priv_key == NULL ||
+			    (r = sshbuf_get_bignum2(buf, p)) != 0 ||
+			    (r = sshbuf_get_bignum2(buf, q)) != 0 ||
+			    (r = sshbuf_get_bignum2(buf, g)) != 0 ||
+			    (r = sshbuf_get_bignum2(buf, pub_key)) != 0 ||
+			    (r = sshbuf_get_bignum2(buf, priv_key)) != 0 ||
+			    (r = ((DSA_set0_pqg(k->dsa, p, q, g) == 0)
+			    ? SSH_ERR_LIBCRYPTO_ERROR : 0)) != 0) {
+				BN_free(p);
+				BN_free(q);
+				BN_free(g);
+				BN_free(pub_key);
+				BN_free(priv_key);
+				goto out;
+			}
+			if (DSA_set0_key(k->dsa, pub_key, priv_key) == 0) {
+				r = SSH_ERR_LIBCRYPTO_ERROR;
+				BN_free(pub_key);
+				BN_free(priv_key);
+				goto out;
+			}
+		}
 		break;
-	case KEY_DSA_CERT:
-		if ((r = sshkey_froms(buf, &k)) != 0 ||
-		    (r = sshkey_add_private(k)) != 0 ||
-		    (r = sshbuf_get_bignum2(buf, k->dsa->priv_key)) != 0)
-			goto out;
+	case KEY_DSA_CERT: {
+			BIGNUM *priv_key = BN_new();
+
+			if (priv_key == NULL ||
+			    (r = sshkey_froms(buf, &k)) != 0 ||
+			    (r = sshkey_add_private(k)) != 0 ||
+			    (r = sshbuf_get_bignum2(buf, priv_key)) != 0 ||
+			    (r = ((DSA_set0_key(k->dsa, NULL, priv_key) == 0)
+			    ? SSH_ERR_LIBCRYPTO_ERROR : 0)) != 0) {
+				BN_free(priv_key);
+				goto out;
+			}
+		}
 		break;
 # ifdef OPENSSL_HAS_ECC
 	case KEY_ECDSA:
@@ -2762,16 +2947,49 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
 			r = SSH_ERR_ALLOC_FAIL;
 			goto out;
 		}
-		if ((r = sshbuf_get_bignum2(buf, k->rsa->n)) != 0 ||
-		    (r = sshbuf_get_bignum2(buf, k->rsa->e)) != 0 ||
-		    (r = sshbuf_get_bignum2(buf, k->rsa->d)) != 0 ||
-		    (r = sshbuf_get_bignum2(buf, k->rsa->iqmp)) != 0 ||
-		    (r = sshbuf_get_bignum2(buf, k->rsa->p)) != 0 ||
-		    (r = sshbuf_get_bignum2(buf, k->rsa->q)) != 0 ||
-		    (r = rsa_generate_additional_parameters(k->rsa)) != 0)
-			goto out;
+		{
+			BIGNUM *n, *e, *d, *iqmp, *p, *q;
+
+			n = BN_new();
+			e = BN_new();
+			d = BN_new();
+			iqmp = BN_new();
+			p = BN_new();
+			q = BN_new();
+
+			if (n == NULL || e == NULL || d == NULL ||
+			    iqmp == NULL || p == NULL || q == NULL ||
+			    (r = sshbuf_get_bignum2(buf, n)) != 0 ||
+			    (r = sshbuf_get_bignum2(buf, e)) != 0 ||
+			    (r = sshbuf_get_bignum2(buf, d)) != 0 ||
+			    (r = sshbuf_get_bignum2(buf, iqmp)) != 0 ||
+			    (r = sshbuf_get_bignum2(buf, p)) != 0 ||
+			    (r = sshbuf_get_bignum2(buf, q)) != 0 ||
+			    (r = ((RSA_set0_key(k->rsa, n, e, d) == 0)
+			    ? SSH_ERR_LIBCRYPTO_ERROR : 0)) != 0) {
+				BN_free(n);
+				BN_free(e);
+				BN_free(d);
+				BN_free(iqmp);
+				BN_free(p);
+				BN_free(q);
+				goto out;
+			}
+			if (RSA_set0_factors(k->rsa, p, q) == 0) {
+				r = SSH_ERR_LIBCRYPTO_ERROR;
+				BN_free(iqmp);
+				BN_free(p);
+				BN_free(q);
+				goto out;
+			}
+			if ((r = rsa_generate_additional_parameters(k->rsa, iqmp)) != 0) {
+				BN_free(iqmp);
+				goto out;
+			}
+		}
 		break;
 	case KEY_RSA_CERT:
+#if 0
 		if ((r = sshkey_froms(buf, &k)) != 0 ||
 		    (r = sshkey_add_private(k)) != 0 ||
 		    (r = sshbuf_get_bignum2(buf, k->rsa->d)) != 0 ||
@@ -2780,6 +2998,10 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
 		    (r = sshbuf_get_bignum2(buf, k->rsa->q)) != 0 ||
 		    (r = rsa_generate_additional_parameters(k->rsa)) != 0)
 			goto out;
+#endif
+		/* XXX: public key is missing */
+		r = SSH_ERR_INTERNAL_ERROR;
+		goto out;
 		break;
 #endif /* WITH_OPENSSL */
 	case KEY_ED25519:
@@ -3789,7 +4011,7 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
 		r = SSH_ERR_KEY_WRONG_PASSPHRASE;
 		goto out;
 	}
-	if (pk->type == EVP_PKEY_RSA &&
+	if (EVP_PKEY_id(pk) == EVP_PKEY_RSA &&
 	    (type == KEY_UNSPEC || type == KEY_RSA)) {
 		if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
 			r = SSH_ERR_ALLOC_FAIL;
@@ -3804,7 +4026,7 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
 			r = SSH_ERR_LIBCRYPTO_ERROR;
 			goto out;
 		}
-	} else if (pk->type == EVP_PKEY_DSA &&
+	} else if (EVP_PKEY_id(pk) == EVP_PKEY_DSA &&
 	    (type == KEY_UNSPEC || type == KEY_DSA)) {
 		if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
 			r = SSH_ERR_ALLOC_FAIL;
@@ -3816,7 +4038,7 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
 		DSA_print_fp(stderr, prv->dsa, 8);
 #endif
 #ifdef OPENSSL_HAS_ECC
-	} else if (pk->type == EVP_PKEY_EC &&
+	} else if (EVP_PKEY_id(pk) == EVP_PKEY_EC &&
 	    (type == KEY_UNSPEC || type == KEY_ECDSA)) {
 		if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) {
 			r = SSH_ERR_ALLOC_FAIL;
-- 
2.7.4


>From 7b461cd2a3a98f5a65e3a6f06a09946edd353e45 Mon Sep 17 00:00:00 2001
From: Kurt Roeckx <kurt@xxxxxxxxx>
Date: Thu, 27 Oct 2016 16:51:31 +0200
Subject: [PATCH 2/7] Fix sshkey_certify(), it was the wrong way around.

---
 sshkey.c | 41 +++++++++--------------------------------
 1 file changed, 9 insertions(+), 32 deletions(-)

diff --git a/sshkey.c b/sshkey.c
index f43b11a..723f332 100644
--- a/sshkey.c
+++ b/sshkey.c
@@ -2501,32 +2501,16 @@ sshkey_certify(struct sshkey *k, struct sshkey *ca, const char *alg)
 	switch (k->type) {
 #ifdef WITH_OPENSSL
 	case KEY_DSA_CERT: {
-			BIGNUM *p, *q, *g, *pub_key;
+			const BIGNUM *p, *q, *g, *pub_key;
 
-			p = BN_new();
-			q = BN_new();
-			g = BN_new();
-			pub_key = BN_new();
+			DSA_get0_pqg(k->dsa, &p, &q, &g);
+			DSA_get0_key(k->dsa, &pub_key, NULL);
 
-			if (p == NULL || q == NULL || g == NULL ||
-			    pub_key == NULL ||
-			    (ret = sshbuf_put_bignum2(cert, p)) != 0 ||
+			if ((ret = sshbuf_put_bignum2(cert, p)) != 0 ||
 			    (ret = sshbuf_put_bignum2(cert, q)) != 0 ||
 			    (ret = sshbuf_put_bignum2(cert, g)) != 0 ||
-			    (ret = sshbuf_put_bignum2(cert, pub_key)) != 0 ||
-			    (ret = ((DSA_set0_pqg(k->dsa, p, q, g) == 0)
-			    ? SSH_ERR_LIBCRYPTO_ERROR : 0)) != 0) {
-				BN_free(p);
-				BN_free(q);
-				BN_free(g);
-				BN_free(pub_key);
+			    (ret = sshbuf_put_bignum2(cert, pub_key)) != 0)
 				goto out;
-			}
-			if (DSA_set0_key(k->dsa, pub_key, NULL) == 0) {
-				ret = SSH_ERR_LIBCRYPTO_ERROR;
-				BN_free(pub_key);
-				goto out;
-			}
 		}
 		break;
 # ifdef OPENSSL_HAS_ECC
@@ -2540,19 +2524,12 @@ sshkey_certify(struct sshkey *k, struct sshkey *ca, const char *alg)
 		break;
 # endif /* OPENSSL_HAS_ECC */
 	case KEY_RSA_CERT: {
-			BIGNUM *e, *n;
+			const BIGNUM *e, *n;
 
-			e = BN_new();
-			n = BN_new();
-			if (e == NULL || n == NULL ||
-			    (ret = sshbuf_put_bignum2(cert, e)) != 0 ||
-			    (ret = sshbuf_put_bignum2(cert, n)) != 0 ||
-			    (ret = ((RSA_set0_key(k->rsa, n, e, NULL) == 0)
-			    ? SSH_ERR_LIBCRYPTO_ERROR : 0)) != 0) {
-				BN_free(e);
-				BN_free(n);
+			RSA_get0_key(k->rsa, &n, &e, NULL);
+			if ((ret = sshbuf_put_bignum2(cert, e)) != 0 ||
+			    (ret = sshbuf_put_bignum2(cert, n)) != 0)
 				goto out;
-			}
 		}
 		break;
 #endif /* WITH_OPENSSL */
-- 
2.7.4


>From 72e736d706bce01ed7fc207d8bfb6cbc8c29d679 Mon Sep 17 00:00:00 2001
From: Kurt Roeckx <kurt@xxxxxxxxx>
Date: Thu, 27 Oct 2016 17:03:12 +0200
Subject: [PATCH 3/7] Simplify compat layer.

---
 libcrypto-compat.c | 37 +------------------------------------
 1 file changed, 1 insertion(+), 36 deletions(-)

diff --git a/libcrypto-compat.c b/libcrypto-compat.c
index d92c8d9..fafccd0 100644
--- a/libcrypto-compat.c
+++ b/libcrypto-compat.c
@@ -322,44 +322,9 @@ EVP_MD_CTX *EVP_MD_CTX_new(void)
     return OPENSSL_zalloc(sizeof(EVP_MD_CTX));
 }
 
-static void OPENSSL_clear_free(void *str, size_t num)
-{
-    if (str == NULL)
-        return;
-    if (num)
-        OPENSSL_cleanse(str, num);
-    OPENSSL_free(str);
-}
-
-/* This call frees resources associated with the context */
-static int EVP_MD_CTX_reset(EVP_MD_CTX *ctx)
-{
-    if (ctx == NULL)
-        return 1;
-
-    /*
-     * Don't assume ctx->md_data was cleaned in EVP_Digest_Final, because
-     * sometimes only copies of the context are ever finalised.
-     */
-    if (ctx->digest && ctx->digest->cleanup
-        && !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_CLEANED))
-        ctx->digest->cleanup(ctx);
-    if (ctx->digest && ctx->digest->ctx_size && ctx->md_data
-        && !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE)) {
-        OPENSSL_clear_free(ctx->md_data, ctx->digest->ctx_size);
-    }
-    EVP_PKEY_CTX_free(ctx->pctx);
-#ifndef OPENSSL_NO_ENGINE
-    ENGINE_finish(ctx->engine);
-#endif
-    OPENSSL_cleanse(ctx, sizeof(*ctx));
-
-    return 1;
-}
-
 void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
 {
-    EVP_MD_CTX_reset(ctx);
+    EVP_MD_CTX_cleanup(ctx);
     OPENSSL_free(ctx);
 }
 
-- 
2.7.4


>From 60fc7e0973b2ed590ab91ce639eccbbc723580af Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Wed, 2 Nov 2016 10:01:24 +0100
Subject: [PATCH 4/7] Build SSH1 client with OpenSSL 1.1.0 and fix missing bits

 * simplify changes using *_bits()
---
 authfd.c           |  51 ++++++++++++-------
 cipher-3des1.c     |  68 +++++++++++++------------
 cipher-bf1.c       |  27 +++++++---
 libcrypto-compat.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 libcrypto-compat.h |  41 +++++++++++++++-
 ssh-agent.c        |  73 ++++++++++++++++++---------
 ssh-keyscan.c      |  11 +++--
 ssh-rsa.c          |   8 +--
 sshconnect1.c      |  64 +++++++++++++++---------
 sshkey.c           | 142 ++++++++++++++++++++++++++++++++++++-----------------
 10 files changed, 462 insertions(+), 161 deletions(-)

diff --git a/authfd.c b/authfd.c
index a634bcb..d032419 100644
--- a/authfd.c
+++ b/authfd.c
@@ -207,15 +207,22 @@ deserialise_identity1(struct sshbuf *ids, struct sshkey **keyp, char **commentp)
 	int r, keybits;
 	u_int32_t bits;
 	char *comment = NULL;
+	BIGNUM *e = NULL, *n = NULL;
 
 	if ((key = sshkey_new(KEY_RSA1)) == NULL)
 		return SSH_ERR_ALLOC_FAIL;
-	if ((r = sshbuf_get_u32(ids, &bits)) != 0 ||
-	    (r = sshbuf_get_bignum1(ids, key->rsa->e)) != 0 ||
-	    (r = sshbuf_get_bignum1(ids, key->rsa->n)) != 0 ||
-	    (r = sshbuf_get_cstring(ids, &comment, NULL)) != 0)
+	if ((e = BN_new()) == NULL ||
+	    (n = BN_new()) == NULL ||
+	    (r = sshbuf_get_u32(ids, &bits)) != 0 ||
+	    (r = sshbuf_get_bignum1(ids, e)) != 0 ||
+	    (r = sshbuf_get_bignum1(ids, n)) != 0 ||
+	    (RSA_set0_key(key->rsa, n, e, NULL) == 0) ||
+	    (r = sshbuf_get_cstring(ids, &comment, NULL)) != 0) {
+		BN_free(n);
+		BN_free(e);
 		goto out;
-	keybits = BN_num_bits(key->rsa->n);
+	}
+	keybits = BN_num_bits(n);
 	/* XXX previously we just warned here. I think we should be strict */
 	if (keybits < 0 || bits != (u_int)keybits) {
 		r = SSH_ERR_KEY_BITS_MISMATCH;
@@ -393,15 +400,17 @@ ssh_decrypt_challenge(int sock, struct sshkey* key, BIGNUM *challenge,
 	struct sshbuf *msg;
 	int r;
 	u_char type;
+	const BIGNUM *e, *n;
 
 	if (key->type != KEY_RSA1)
 		return SSH_ERR_INVALID_ARGUMENT;
 	if ((msg = sshbuf_new()) == NULL)
 		return SSH_ERR_ALLOC_FAIL;
+	RSA_get0_key(key->rsa, &n, &e, NULL);
 	if ((r = sshbuf_put_u8(msg, SSH_AGENTC_RSA_CHALLENGE)) != 0 ||
-	    (r = sshbuf_put_u32(msg, BN_num_bits(key->rsa->n))) != 0 ||
-	    (r = sshbuf_put_bignum1(msg, key->rsa->e)) != 0 ||
-	    (r = sshbuf_put_bignum1(msg, key->rsa->n)) != 0 ||
+	    (r = sshbuf_put_u32(msg, BN_num_bits(n))) != 0 ||
+	    (r = sshbuf_put_bignum1(msg, e)) != 0 ||
+	    (r = sshbuf_put_bignum1(msg, n)) != 0 ||
 	    (r = sshbuf_put_bignum1(msg, challenge)) != 0 ||
 	    (r = sshbuf_put(msg, session_id, 16)) != 0 ||
 	    (r = sshbuf_put_u32(msg, 1)) != 0) /* Response type for proto 1.1 */
@@ -499,15 +508,19 @@ static int
 ssh_encode_identity_rsa1(struct sshbuf *b, RSA *key, const char *comment)
 {
 	int r;
+	const BIGNUM *n, *e, *d, *q, *p, *iqmp;
 
+	RSA_get0_key(key, &n, &e, &d);
+	RSA_get0_factors(key, &p, &q);
+	RSA_get0_crt_params(key, NULL, NULL, &iqmp);
 	/* To keep within the protocol: p < q for ssh. in SSL p > q */
-	if ((r = sshbuf_put_u32(b, BN_num_bits(key->n))) != 0 ||
-	    (r = sshbuf_put_bignum1(b, key->n)) != 0 ||
-	    (r = sshbuf_put_bignum1(b, key->e)) != 0 ||
-	    (r = sshbuf_put_bignum1(b, key->d)) != 0 ||
-	    (r = sshbuf_put_bignum1(b, key->iqmp)) != 0 ||
-	    (r = sshbuf_put_bignum1(b, key->q)) != 0 ||
-	    (r = sshbuf_put_bignum1(b, key->p)) != 0 ||
+	if ((r = sshbuf_put_u32(b, BN_num_bits(n))) != 0 ||
+	    (r = sshbuf_put_bignum1(b, n)) != 0 ||
+	    (r = sshbuf_put_bignum1(b, e)) != 0 ||
+	    (r = sshbuf_put_bignum1(b, d)) != 0 ||
+	    (r = sshbuf_put_bignum1(b, iqmp)) != 0 ||
+	    (r = sshbuf_put_bignum1(b, q)) != 0 ||
+	    (r = sshbuf_put_bignum1(b, p)) != 0 ||
 	    (r = sshbuf_put_cstring(b, comment)) != 0)
 		return r;
 	return 0;
@@ -622,11 +635,13 @@ ssh_remove_identity(int sock, struct sshkey *key)
 
 #ifdef WITH_SSH1
 	if (key->type == KEY_RSA1) {
+		const BIGNUM *e, *n;
+		RSA_get0_key(key->rsa, &n, &e, NULL);
 		if ((r = sshbuf_put_u8(msg,
 		    SSH_AGENTC_REMOVE_RSA_IDENTITY)) != 0 ||
-		    (r = sshbuf_put_u32(msg, BN_num_bits(key->rsa->n))) != 0 ||
-		    (r = sshbuf_put_bignum1(msg, key->rsa->e)) != 0 ||
-		    (r = sshbuf_put_bignum1(msg, key->rsa->n)) != 0)
+		    (r = sshbuf_put_u32(msg, BN_num_bits(n))) != 0 ||
+		    (r = sshbuf_put_bignum1(msg, e)) != 0 ||
+		    (r = sshbuf_put_bignum1(msg, n)) != 0)
 			goto out;
 	} else
 #endif
diff --git a/cipher-3des1.c b/cipher-3des1.c
index 9fcc278..2051030 100644
--- a/cipher-3des1.c
+++ b/cipher-3des1.c
@@ -44,7 +44,7 @@
  */
 struct ssh1_3des_ctx
 {
-	EVP_CIPHER_CTX	k1, k2, k3;
+	EVP_CIPHER_CTX	*k1, *k2, *k3;
 };
 
 const EVP_CIPHER * evp_ssh1_3des(void);
@@ -65,7 +65,7 @@ ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
 	if (key == NULL)
 		return 1;
 	if (enc == -1)
-		enc = ctx->encrypt;
+		enc = EVP_CIPHER_CTX_encrypting(ctx);
 	k1 = k2 = k3 = (u_char *) key;
 	k2 += 8;
 	if (EVP_CIPHER_CTX_key_length(ctx) >= 16+8) {
@@ -74,12 +74,19 @@ ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv,
 		else
 			k1 += 16;
 	}
-	EVP_CIPHER_CTX_init(&c->k1);
-	EVP_CIPHER_CTX_init(&c->k2);
-	EVP_CIPHER_CTX_init(&c->k3);
-	if (EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc) == 0 ||
-	    EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc) == 0 ||
-	    EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc) == 0) {
+	c->k1 = EVP_CIPHER_CTX_new();
+	c->k2 = EVP_CIPHER_CTX_new();
+	c->k3 = EVP_CIPHER_CTX_new();
+	if (c->k1 == NULL || c->k2 == NULL || c->k3 == NULL) {
+		EVP_CIPHER_CTX_free(c->k1);
+		EVP_CIPHER_CTX_free(c->k2);
+		EVP_CIPHER_CTX_free(c->k3);
+		free(c);
+		return 0;
+	}
+	if (EVP_CipherInit(c->k1, EVP_des_cbc(), k1, NULL, enc) == 0 ||
+	    EVP_CipherInit(c->k2, EVP_des_cbc(), k2, NULL, !enc) == 0 ||
+	    EVP_CipherInit(c->k3, EVP_des_cbc(), k3, NULL, enc) == 0) {
 		explicit_bzero(c, sizeof(*c));
 		free(c);
 		EVP_CIPHER_CTX_set_app_data(ctx, NULL);
@@ -95,9 +102,9 @@ ssh1_3des_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, size_t len)
 
 	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL)
 		return 0;
-	if (EVP_Cipher(&c->k1, dest, (u_char *)src, len) == 0 ||
-	    EVP_Cipher(&c->k2, dest, dest, len) == 0 ||
-	    EVP_Cipher(&c->k3, dest, dest, len) == 0)
+	if (EVP_Cipher(c->k1, dest, (u_char *)src, len) == 0 ||
+	    EVP_Cipher(c->k2, dest, dest, len) == 0 ||
+	    EVP_Cipher(c->k3, dest, dest, len) == 0)
 		return 0;
 	return 1;
 }
@@ -108,9 +115,9 @@ ssh1_3des_cleanup(EVP_CIPHER_CTX *ctx)
 	struct ssh1_3des_ctx *c;
 
 	if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
-		EVP_CIPHER_CTX_cleanup(&c->k1);
-		EVP_CIPHER_CTX_cleanup(&c->k2);
-		EVP_CIPHER_CTX_cleanup(&c->k3);
+		EVP_CIPHER_CTX_free(c->k1);
+		EVP_CIPHER_CTX_free(c->k2);
+		EVP_CIPHER_CTX_free(c->k3);
 		explicit_bzero(c, sizeof(*c));
 		free(c);
 		EVP_CIPHER_CTX_set_app_data(ctx, NULL);
@@ -128,13 +135,13 @@ ssh1_3des_iv(EVP_CIPHER_CTX *evp, int doset, u_char *iv, int len)
 	if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL)
 		return SSH_ERR_INTERNAL_ERROR;
 	if (doset) {
-		memcpy(c->k1.iv, iv, 8);
-		memcpy(c->k2.iv, iv + 8, 8);
-		memcpy(c->k3.iv, iv + 16, 8);
+		memcpy(EVP_CIPHER_CTX_iv_noconst(c->k1), iv, 8);
+		memcpy(EVP_CIPHER_CTX_iv_noconst(c->k2), iv + 8, 8);
+		memcpy(EVP_CIPHER_CTX_iv_noconst(c->k3), iv + 16, 8);
 	} else {
-		memcpy(iv, c->k1.iv, 8);
-		memcpy(iv + 8, c->k2.iv, 8);
-		memcpy(iv + 16, c->k3.iv, 8);
+		memcpy(iv, EVP_CIPHER_CTX_iv(c->k1), 8);
+		memcpy(iv + 8, EVP_CIPHER_CTX_iv(c->k2), 8);
+		memcpy(iv + 16, EVP_CIPHER_CTX_iv(c->k3), 8);
 	}
 	return 0;
 }
@@ -142,17 +149,14 @@ ssh1_3des_iv(EVP_CIPHER_CTX *evp, int doset, u_char *iv, int len)
 const EVP_CIPHER *
 evp_ssh1_3des(void)
 {
-	static EVP_CIPHER ssh1_3des;
-
-	memset(&ssh1_3des, 0, sizeof(ssh1_3des));
-	ssh1_3des.nid = NID_undef;
-	ssh1_3des.block_size = 8;
-	ssh1_3des.iv_len = 0;
-	ssh1_3des.key_len = 16;
-	ssh1_3des.init = ssh1_3des_init;
-	ssh1_3des.cleanup = ssh1_3des_cleanup;
-	ssh1_3des.do_cipher = ssh1_3des_cbc;
-	ssh1_3des.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH;
-	return &ssh1_3des;
+	EVP_CIPHER *ssh1_3des;
+
+	ssh1_3des = EVP_CIPHER_meth_new(NID_undef, 8, 16);
+	EVP_CIPHER_meth_set_iv_length(ssh1_3des, 0);
+	EVP_CIPHER_meth_set_init(ssh1_3des, ssh1_3des_init);
+	EVP_CIPHER_meth_set_cleanup(ssh1_3des, ssh1_3des_cleanup);
+	EVP_CIPHER_meth_set_do_cipher(ssh1_3des, ssh1_3des_cbc);
+	EVP_CIPHER_meth_set_flags(ssh1_3des, EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH);
+	return ssh1_3des;
 }
 #endif /* WITH_SSH1 */
diff --git a/cipher-bf1.c b/cipher-bf1.c
index c205b07..b23bda7 100644
--- a/cipher-bf1.c
+++ b/cipher-bf1.c
@@ -89,17 +89,28 @@ bf_ssh1_cipher(EVP_CIPHER_CTX *ctx, u_char *out, const u_char *in,
 const EVP_CIPHER *
 evp_ssh1_bf(void)
 {
-	static EVP_CIPHER ssh1_bf;
+	EVP_CIPHER *ssh1_bf;
 
-	memcpy(&ssh1_bf, EVP_bf_cbc(), sizeof(EVP_CIPHER));
-	orig_bf = ssh1_bf.do_cipher;
-	ssh1_bf.nid = NID_undef;
+	orig_bf = EVP_CIPHER_meth_get_do_cipher(EVP_bf_cbc());
+	/* block_size, length, flags from openssl/crypto/engine/eng_cryptodev.c:638 */
+	ssh1_bf = EVP_CIPHER_meth_new(NID_undef, 8, 32);
+	EVP_CIPHER_meth_set_iv_length(ssh1_bf, 8);
+	EVP_CIPHER_meth_set_flags(ssh1_bf, EVP_CIPH_CBC_MODE);
 #ifdef SSH_OLD_EVP
-	ssh1_bf.init = bf_ssh1_init;
+	EVP_CIPHER_meth_set_init(ssh1_bf, ssh1_bf_init);
+#else
+	EVP_CIPHER_meth_set_init(ssh1_bf,
+	    EVP_CIPHER_meth_get_init(EVP_bf_cbc()));
 #endif
-	ssh1_bf.do_cipher = bf_ssh1_cipher;
-	ssh1_bf.key_len = 32;
-	return (&ssh1_bf);
+	/* copy methods and parameters from old EVP_BF_cbc()
+	 * meth_dup does not allow to change type and key_len */
+	EVP_CIPHER_meth_set_cleanup(ssh1_bf,
+	    EVP_CIPHER_meth_get_cleanup(EVP_bf_cbc()));
+	EVP_CIPHER_meth_set_ctrl(ssh1_bf,
+	    EVP_CIPHER_meth_get_ctrl(EVP_bf_cbc()));
+	/* ASN1 params??? */
+	EVP_CIPHER_meth_set_do_cipher(ssh1_bf, bf_ssh1_cipher);
+	return ssh1_bf;
 }
 #endif /* defined(WITH_OPENSSL) && !defined(OPENSSL_NO_BF) */
 
diff --git a/libcrypto-compat.c b/libcrypto-compat.c
index fafccd0..1e17fec 100644
--- a/libcrypto-compat.c
+++ b/libcrypto-compat.c
@@ -322,9 +322,44 @@ EVP_MD_CTX *EVP_MD_CTX_new(void)
     return OPENSSL_zalloc(sizeof(EVP_MD_CTX));
 }
 
+static void OPENSSL_clear_free(void *str, size_t num)
+{
+    if (str == NULL)
+        return;
+    if (num)
+        OPENSSL_cleanse(str, num);
+    OPENSSL_free(str);
+}
+
+/* This call frees resources associated with the context */
+int EVP_MD_CTX_reset(EVP_MD_CTX *ctx)
+{
+    if (ctx == NULL)
+        return 1;
+
+    /*
+     * Don't assume ctx->md_data was cleaned in EVP_Digest_Final, because
+     * sometimes only copies of the context are ever finalised.
+     */
+    if (ctx->digest && ctx->digest->cleanup
+        && !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_CLEANED))
+        ctx->digest->cleanup(ctx);
+    if (ctx->digest && ctx->digest->ctx_size && ctx->md_data
+        && !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE)) {
+        OPENSSL_clear_free(ctx->md_data, ctx->digest->ctx_size);
+    }
+    EVP_PKEY_CTX_free(ctx->pctx);
+#ifndef OPENSSL_NO_ENGINE
+    ENGINE_finish(ctx->engine);
+#endif
+    OPENSSL_cleanse(ctx, sizeof(*ctx));
+
+    return 1;
+}
+
 void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
 {
-    EVP_MD_CTX_cleanup(ctx);
+    EVP_MD_CTX_reset(ctx);
     OPENSSL_free(ctx);
 }
 
@@ -398,6 +433,11 @@ int RSA_bits(const RSA *r)
     return (BN_num_bits(r->n));
 }
 
+int DSA_bits(const DSA *dsa)
+{
+    return BN_num_bits(dsa->p);
+}
+
 RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey)
 {
     if (pkey->type != EVP_PKEY_RSA) {
@@ -406,5 +446,101 @@ RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey)
     return pkey->pkey.rsa;
 }
 
+EVP_CIPHER *EVP_CIPHER_meth_new(int cipher_type, int block_size, int key_len)
+{
+    EVP_CIPHER *cipher = OPENSSL_zalloc(sizeof(EVP_CIPHER));
+
+    if (cipher != NULL) {
+        cipher->nid = cipher_type;
+        cipher->block_size = block_size;
+        cipher->key_len = key_len;
+    }
+    return cipher;
+}
+
+void EVP_CIPHER_meth_free(EVP_CIPHER *cipher)
+{
+    OPENSSL_free(cipher);
+}
+
+int EVP_CIPHER_meth_set_iv_length(EVP_CIPHER *cipher, int iv_len)
+{
+    cipher->iv_len = iv_len;
+    return 1;
+}
+
+int EVP_CIPHER_meth_set_flags(EVP_CIPHER *cipher, unsigned long flags)
+{
+    cipher->flags = flags;
+    return 1;
+}
+
+int EVP_CIPHER_meth_set_init(EVP_CIPHER *cipher,
+                             int (*init) (EVP_CIPHER_CTX *ctx,
+                                          const unsigned char *key,
+                                          const unsigned char *iv,
+                                          int enc))
+{
+    cipher->init = init;
+    return 1;
+}
+
+int EVP_CIPHER_meth_set_do_cipher(EVP_CIPHER *cipher,
+                                  int (*do_cipher) (EVP_CIPHER_CTX *ctx,
+                                                    unsigned char *out,
+                                                    const unsigned char *in,
+                                                    size_t inl))
+{
+    cipher->do_cipher = do_cipher;
+    return 1;
+}
+
+int EVP_CIPHER_meth_set_cleanup(EVP_CIPHER *cipher,
+                                int (*cleanup) (EVP_CIPHER_CTX *))
+{
+    cipher->cleanup = cleanup;
+    return 1;
+}
+
+int EVP_CIPHER_meth_set_ctrl(EVP_CIPHER *cipher,
+                             int (*ctrl) (EVP_CIPHER_CTX *, int type,
+                                          int arg, void *ptr))
+{
+    cipher->ctrl = ctrl;
+    return 1;
+}
+
+int (*EVP_CIPHER_meth_get_init(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *ctx,
+                                                          const unsigned char *key,
+                                                          const unsigned char *iv,
+                                                          int enc)
+{
+    return cipher->init;
+}
+
+int (*EVP_CIPHER_meth_get_do_cipher(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *ctx,
+                                                               unsigned char *out,
+                                                               const unsigned char *in,
+                                                               size_t inl)
+{
+    return cipher->do_cipher;
+}
+
+int (*EVP_CIPHER_meth_get_cleanup(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *)
+{
+    return cipher->cleanup;
+}
+
+int (*EVP_CIPHER_meth_get_ctrl(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *,
+                                                          int type, int arg,
+                                                          void *ptr)
+{
+    return cipher->ctrl;
+}
+
+int EVP_CIPHER_CTX_encrypting(const EVP_CIPHER_CTX *ctx)
+{
+    return ctx->encrypt;
+}
 
 #endif /* OPENSSL_VERSION_NUMBER */
diff --git a/libcrypto-compat.h b/libcrypto-compat.h
index e0599b4..a5c0bf1 100644
--- a/libcrypto-compat.h
+++ b/libcrypto-compat.h
@@ -35,6 +35,7 @@ int DH_set_length(DH *dh, long length);
 
 const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx);
 unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx);
+int EVP_MD_CTX_reset(EVP_MD_CTX *ctx);
 EVP_MD_CTX *EVP_MD_CTX_new(void);
 void EVP_MD_CTX_free(EVP_MD_CTX *ctx);
 #define EVP_CIPHER_impl_ctx_size(e) e->ctx_size
@@ -49,10 +50,48 @@ int RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa));
 void RSA_meth_free(RSA_METHOD *meth);
 
 int RSA_bits(const RSA *r);
+int DSA_bits(const DSA *d);
 
 RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey);
 
+EVP_CIPHER *EVP_CIPHER_meth_new(int cipher_type, int block_size, int key_len);
+void EVP_CIPHER_meth_free(EVP_CIPHER *cipher);
+
+int EVP_CIPHER_meth_set_iv_length(EVP_CIPHER *cipher, int iv_len);
+int EVP_CIPHER_meth_set_flags(EVP_CIPHER *cipher, unsigned long flags);
+int EVP_CIPHER_meth_set_init(EVP_CIPHER *cipher,
+                             int (*init) (EVP_CIPHER_CTX *ctx,
+                                          const unsigned char *key,
+                                          const unsigned char *iv,
+                                          int enc));
+int EVP_CIPHER_meth_set_do_cipher(EVP_CIPHER *cipher,
+                                  int (*do_cipher) (EVP_CIPHER_CTX *ctx,
+                                                    unsigned char *out,
+                                                    const unsigned char *in,
+                                                    size_t inl));
+int EVP_CIPHER_meth_set_cleanup(EVP_CIPHER *cipher,
+                                int (*cleanup) (EVP_CIPHER_CTX *));
+int EVP_CIPHER_meth_set_ctrl(EVP_CIPHER *cipher,
+                             int (*ctrl) (EVP_CIPHER_CTX *, int type,
+                                          int arg, void *ptr));
+
+int (*EVP_CIPHER_meth_get_init(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *ctx,
+                                                          const unsigned char *key,
+                                                          const unsigned char *iv,
+                                                          int enc);
+int (*EVP_CIPHER_meth_get_do_cipher(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *ctx,
+                                                               unsigned char *out,
+                                                               const unsigned char *in,
+                                                               size_t inl);
+int (*EVP_CIPHER_meth_get_cleanup(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *);
+int (*EVP_CIPHER_meth_get_ctrl(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *,
+                                                          int type, int arg,
+                                                          void *ptr);
+
+#define EVP_CIPHER_CTX_reset(c)      EVP_CIPHER_CTX_init(c)
+
+int EVP_CIPHER_CTX_encrypting(const EVP_CIPHER_CTX *ctx);
+
 #endif /* OPENSSL_VERSION_NUMBER */
 
 #endif /* LIBCRYPTO_COMPAT_H */
-
diff --git a/ssh-agent.c b/ssh-agent.c
index fd5f2b3..d98c101 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -250,12 +250,12 @@ process_request_identities(SocketEntry *e, int version)
 	TAILQ_FOREACH(id, &tab->idlist, next) {
 		if (id->key->type == KEY_RSA1) {
 #ifdef WITH_SSH1
+			const BIGNUM *r_n, *r_e;
+			RSA_get0_key(id->key->rsa, &r_n, &r_e, NULL);
 			if ((r = sshbuf_put_u32(msg,
-			    BN_num_bits(id->key->rsa->n))) != 0 ||
-			    (r = sshbuf_put_bignum1(msg,
-			    id->key->rsa->e)) != 0 ||
-			    (r = sshbuf_put_bignum1(msg,
-			    id->key->rsa->n)) != 0)
+			    BN_num_bits(r_n))) != 0 ||
+			    (r = sshbuf_put_bignum1(msg, r_e)) != 0 ||
+			    (r = sshbuf_put_bignum1(msg, r_n)) != 0)
 				fatal("%s: buffer error: %s",
 				    __func__, ssh_err(r));
 #endif
@@ -290,10 +290,11 @@ process_authentication_challenge1(SocketEntry *e)
 	u_int response_type;
 	BIGNUM *challenge;
 	Identity *id;
-	int r, len;
+	int len, r = SSH_ERR_ALLOC_FAIL;
 	struct sshbuf *msg;
 	struct ssh_digest_ctx *md;
 	struct sshkey *key;
+	BIGNUM *r_n = NULL, *r_e = NULL;
 
 	if ((msg = sshbuf_new()) == NULL)
 		fatal("%s: sshbuf_new failed", __func__);
@@ -302,11 +303,17 @@ process_authentication_challenge1(SocketEntry *e)
 	if ((challenge = BN_new()) == NULL)
 		fatal("%s: BN_new failed", __func__);
 
-	if ((r = sshbuf_get_u32(e->request, NULL)) != 0 || /* ignored */
-	    (r = sshbuf_get_bignum1(e->request, key->rsa->e)) != 0 ||
-	    (r = sshbuf_get_bignum1(e->request, key->rsa->n)) != 0 ||
-	    (r = sshbuf_get_bignum1(e->request, challenge)))
+	if ((r_n = BN_new()) == NULL || (r_e = BN_new()) == NULL ||
+	    (r = sshbuf_get_u32(e->request, NULL)) != 0 || /* ignored */
+	    (r = sshbuf_get_bignum1(e->request, r_e)) != 0 ||
+	    (r = sshbuf_get_bignum1(e->request, r_n)) != 0 ||
+	    (r = sshbuf_get_bignum1(e->request, challenge)) ||
+	    (r = ((RSA_set0_key(key->rsa, r_n, r_e, NULL) == 0)
+	    ? SSH_ERR_LIBCRYPTO_ERROR : 0)) != 0) {
+		BN_free(r_n);
+		BN_free(r_e);
 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
+	}
 
 	/* Only protocol 1.1 is supported */
 	if (sshbuf_len(e->request) == 0)
@@ -437,11 +444,12 @@ static void
 process_remove_identity(SocketEntry *e, int version)
 {
 	size_t blen;
-	int r, success = 0;
+	int r = SSH_ERR_ALLOC_FAIL, success = 0;
 	struct sshkey *key = NULL;
 	u_char *blob;
 #ifdef WITH_SSH1
 	u_int bits;
+	BIGNUM *r_n = NULL, *r_e = NULL;
 #endif /* WITH_SSH1 */
 
 	switch (version) {
@@ -451,10 +459,16 @@ process_remove_identity(SocketEntry *e, int version)
 			error("%s: sshkey_new failed", __func__);
 			return;
 		}
-		if ((r = sshbuf_get_u32(e->request, &bits)) != 0 ||
-		    (r = sshbuf_get_bignum1(e->request, key->rsa->e)) != 0 ||
-		    (r = sshbuf_get_bignum1(e->request, key->rsa->n)) != 0)
+		if ((r_n = BN_new()) == NULL || (r_e = BN_new()) == NULL ||
+		    (r = sshbuf_get_u32(e->request, &bits)) != 0 ||
+		    (r = sshbuf_get_bignum1(e->request, r_e)) != 0 ||
+		    (r = sshbuf_get_bignum1(e->request, r_n)) != 0 ||
+		    (r = ((RSA_set0_key(key->rsa, r_n, r_e, NULL) == 0)
+		    ? SSH_ERR_LIBCRYPTO_ERROR : 0)) != 0) {
+			BN_free(r_n);
+			BN_free(r_e);
 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
+		}
 
 		if (bits != sshkey_size(key))
 			logit("Warning: identity keysize mismatch: "
@@ -557,23 +571,38 @@ agent_decode_rsa1(struct sshbuf *m, struct sshkey **kp)
 {
 	struct sshkey *k = NULL;
 	int r = SSH_ERR_INTERNAL_ERROR;
+	BIGNUM *n = NULL, *e = NULL, *d = NULL,
+	    *iqmp = NULL, *q = NULL, *p = NULL;
 
 	*kp = NULL;
 	if ((k = sshkey_new_private(KEY_RSA1)) == NULL)
 		return SSH_ERR_ALLOC_FAIL;
 
-	if ((r = sshbuf_get_u32(m, NULL)) != 0 ||		/* ignored */
-	    (r = sshbuf_get_bignum1(m, k->rsa->n)) != 0 ||
-	    (r = sshbuf_get_bignum1(m, k->rsa->e)) != 0 ||
-	    (r = sshbuf_get_bignum1(m, k->rsa->d)) != 0 ||
-	    (r = sshbuf_get_bignum1(m, k->rsa->iqmp)) != 0 ||
+	if ((n = BN_new()) == NULL || (e = BN_new()) == NULL ||
+	    (d = BN_new()) == NULL || (iqmp = BN_new()) == NULL ||
+	    (q = BN_new()) == NULL || (p = BN_new()) == NULL ||
+	    (r = sshbuf_get_u32(m, NULL)) != 0 ||		/* ignored */
+	    (r = sshbuf_get_bignum1(m, n)) != 0 ||
+	    (r = sshbuf_get_bignum1(m, e)) != 0 ||
+	    (r = sshbuf_get_bignum1(m, d)) != 0 ||
+	    (r = sshbuf_get_bignum1(m, iqmp)) != 0 ||
 	    /* SSH1 and SSL have p and q swapped */
-	    (r = sshbuf_get_bignum1(m, k->rsa->q)) != 0 ||	/* p */
-	    (r = sshbuf_get_bignum1(m, k->rsa->p)) != 0) 	/* q */
+	    (r = sshbuf_get_bignum1(m, q)) != 0 ||	/* p */
+	    (r = sshbuf_get_bignum1(m, p)) != 0 || 	/* q */
+	    RSA_set0_key(k->rsa, n, e, d) == 0 ||
+	    RSA_set0_factors(k->rsa, p, q) == 0 ||
+	    RSA_set0_crt_params(k->rsa, NULL, NULL, iqmp) == 0) {
+		BN_free(n);
+		BN_free(e);
+		BN_free(d);
+		BN_free(p);
+		BN_free(q);
+		BN_free(iqmp);
 		goto out;
+	}
 
 	/* Generate additional parameters */
-	if ((r = rsa_generate_additional_parameters(k->rsa)) != 0)
+	if ((r = rsa_generate_additional_parameters(k->rsa, NULL)) != 0)
 		goto out;
 	/* enable blinding */
 	if (RSA_blinding_on(k->rsa, NULL) != 1) {
diff --git a/ssh-keyscan.c b/ssh-keyscan.c
index c30d54e..1197151 100644
--- a/ssh-keyscan.c
+++ b/ssh-keyscan.c
@@ -195,6 +195,7 @@ keygrab_ssh1(con *c)
 	static struct sshbuf *msg;
 	int r;
 	u_char type;
+	BIGNUM *n = NULL, *e = NULL;
 
 	if (rsa == NULL) {
 		if ((rsa = sshkey_new(KEY_RSA1)) == NULL) {
@@ -213,16 +214,20 @@ keygrab_ssh1(con *c)
 		sshbuf_reset(msg);
 		return NULL;
 	}
-	if ((r = sshbuf_consume(msg, 8)) != 0 || /* cookie */
+	if ((n = BN_new()) == NULL || (e = BN_new()) == NULL || 
+	    (r = sshbuf_consume(msg, 8)) != 0 || /* cookie */
 	    /* server key */
 	    (r = sshbuf_get_u32(msg, NULL)) != 0 ||
 	    (r = sshbuf_get_bignum1(msg, NULL)) != 0 ||
 	    (r = sshbuf_get_bignum1(msg, NULL)) != 0 ||
 	    /* host key */
 	    (r = sshbuf_get_u32(msg, NULL)) != 0 ||
-	    (r = sshbuf_get_bignum1(msg, rsa->rsa->e)) != 0 ||
-	    (r = sshbuf_get_bignum1(msg, rsa->rsa->n)) != 0) {
+	    (r = sshbuf_get_bignum1(msg, e)) != 0 ||
+	    (r = sshbuf_get_bignum1(msg, n)) != 0 ||
+	    RSA_set0_key(rsa->rsa, n, e, NULL) == 0) {
  buf_err:
+		BN_free(n);
+		BN_free(e);
 		error("%s: buffer error: %s", __func__, ssh_err(r));
 		sshbuf_reset(msg);
 		return NULL;
diff --git a/ssh-rsa.c b/ssh-rsa.c
index 8197949..e80a458 100644
--- a/ssh-rsa.c
+++ b/ssh-rsa.c
@@ -88,7 +88,6 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
 	u_int dlen, len;
 	int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR;
 	struct sshbuf *b = NULL;
-	const BIGNUM *n;
 
 	if (lenp != NULL)
 		*lenp = 0;
@@ -102,8 +101,7 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
 	if (key == NULL || key->rsa == NULL || hash_alg == -1 ||
 	    sshkey_type_plain(key->type) != KEY_RSA)
 		return SSH_ERR_INVALID_ARGUMENT;
-	RSA_get0_key(key->rsa, &n, NULL, NULL);
-	if (BN_num_bits(n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
+	if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE)
 		return SSH_ERR_INVALID_ARGUMENT;
 	slen = RSA_size(key->rsa);
 	if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM)
@@ -172,14 +170,12 @@ ssh_rsa_verify(const struct sshkey *key,
 	size_t len, diff, modlen, dlen;
 	struct sshbuf *b = NULL;
 	u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL;
-	const BIGNUM *n;
 
 	if (key == NULL || key->rsa == NULL ||
 	    sshkey_type_plain(key->type) != KEY_RSA ||
 	    sig == NULL || siglen == 0)
 		return SSH_ERR_INVALID_ARGUMENT;
-	RSA_get0_key(key->rsa, &n, NULL, NULL);
-	if (BN_num_bits(n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
+	if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE)
 		return SSH_ERR_INVALID_ARGUMENT;
 
 	if ((b = sshbuf_from(sig, siglen)) == NULL)
diff --git a/sshconnect1.c b/sshconnect1.c
index a045361..f9b81de 100644
--- a/sshconnect1.c
+++ b/sshconnect1.c
@@ -70,6 +70,7 @@ try_agent_authentication(void)
 	u_char response[16];
 	size_t i;
 	BIGNUM *challenge;
+	const BIGNUM *n;
 	struct ssh_identitylist *idlist = NULL;
 
 	/* Get connection to the agent. */
@@ -96,8 +97,9 @@ try_agent_authentication(void)
 		    idlist->comments[i]);
 
 		/* Tell the server that we are willing to authenticate using this key. */
+		RSA_get0_key(idlist->keys[i]->rsa, &n, NULL, NULL);
 		packet_start(SSH_CMSG_AUTH_RSA);
-		packet_put_bignum(idlist->keys[i]->rsa->n);
+		packet_put_bignum((BIGNUM *)n);
 		packet_send();
 		packet_write_wait();
 
@@ -220,6 +222,7 @@ static int
 try_rsa_authentication(int idx)
 {
 	BIGNUM *challenge;
+	const BIGNUM *n;
 	Key *public, *private;
 	char buf[300], *passphrase = NULL, *comment, *authfile;
 	int i, perm_ok = 1, type, quit;
@@ -231,8 +234,9 @@ try_rsa_authentication(int idx)
 	debug("Trying RSA authentication with key '%.100s'", comment);
 
 	/* Tell the server that we are willing to authenticate using this key. */
+	RSA_get0_key(public->rsa, &n, NULL, NULL);
 	packet_start(SSH_CMSG_AUTH_RSA);
-	packet_put_bignum(public->rsa->n);
+	packet_put_bignum((BIGNUM *)n);
 	packet_send();
 	packet_write_wait();
 
@@ -348,15 +352,17 @@ try_rhosts_rsa_authentication(const char *local_user, Key * host_key)
 {
 	int type;
 	BIGNUM *challenge;
+	const BIGNUM *n, *e;
 
 	debug("Trying rhosts or /etc/hosts.equiv with RSA host authentication.");
 
 	/* Tell the server that we are willing to authenticate using this key. */
+	RSA_get0_key(host_key->rsa, &n, &e, NULL);
 	packet_start(SSH_CMSG_AUTH_RHOSTS_RSA);
 	packet_put_cstring(local_user);
-	packet_put_int(BN_num_bits(host_key->rsa->n));
-	packet_put_bignum(host_key->rsa->e);
-	packet_put_bignum(host_key->rsa->n);
+	packet_put_int(BN_num_bits(n));
+	packet_put_bignum((BIGNUM *)e);
+	packet_put_bignum((BIGNUM *)n);
 	packet_send();
 	packet_write_wait();
 
@@ -502,6 +508,8 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
 {
 	int i;
 	BIGNUM *key;
+	BIGNUM *server_n = NULL, *server_e = NULL,
+	    *host_n = NULL, *host_e = NULL;
 	Key *host_key, *server_key;
 	int bits, rbits;
 	int ssh_cipher_default = SSH_CIPHER_3DES;
@@ -522,10 +530,14 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
 	/* Get the public key. */
 	server_key = key_new(KEY_RSA1);
 	bits = packet_get_int();
-	packet_get_bignum(server_key->rsa->e);
-	packet_get_bignum(server_key->rsa->n);
-
-	rbits = BN_num_bits(server_key->rsa->n);
+	if ((server_e = BN_new()) == NULL ||
+	    (server_n = BN_new()) == NULL)
+		fatal("BN_new() failed");
+	packet_get_bignum(server_e);
+	packet_get_bignum(server_n);
+	RSA_set0_key(server_key->rsa, server_n, server_e, NULL);
+
+	rbits = BN_num_bits(server_n);
 	if (bits != rbits) {
 		logit("Warning: Server lies about size of server public key: "
 		    "actual size is %d bits vs. announced %d.", rbits, bits);
@@ -534,10 +546,14 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
 	/* Get the host key. */
 	host_key = key_new(KEY_RSA1);
 	bits = packet_get_int();
-	packet_get_bignum(host_key->rsa->e);
-	packet_get_bignum(host_key->rsa->n);
-
-	rbits = BN_num_bits(host_key->rsa->n);
+	if ((host_e = BN_new()) == NULL ||
+	    (host_n = BN_new()) == NULL)
+		fatal("BN_new() failed");
+	packet_get_bignum(host_e);
+	packet_get_bignum(host_n);
+	RSA_set0_key(host_key->rsa, host_n, host_e, NULL);
+
+	rbits = BN_num_bits(host_n);
 	if (bits != rbits) {
 		logit("Warning: Server lies about size of server host key: "
 		    "actual size is %d bits vs. announced %d.", rbits, bits);
@@ -553,14 +569,14 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
 	packet_check_eom();
 
 	debug("Received server public key (%d bits) and host key (%d bits).",
-	    BN_num_bits(server_key->rsa->n), BN_num_bits(host_key->rsa->n));
+	    BN_num_bits(server_n), BN_num_bits(host_n));
 
 	if (verify_host_key(host, hostaddr, host_key) == -1)
 		fatal("Host key verification failed.");
 
 	client_flags = SSH_PROTOFLAG_SCREEN_NUMBER | SSH_PROTOFLAG_HOST_IN_FWD_OPEN;
 
-	derive_ssh1_session_id(host_key->rsa->n, server_key->rsa->n, cookie, session_id);
+	derive_ssh1_session_id(host_n, server_n, cookie, session_id);
 
 	/*
 	 * Generate an encryption key for the session.   The key is a 256 bit
@@ -595,14 +611,14 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
 	 * Encrypt the integer using the public key and host key of the
 	 * server (key with smaller modulus first).
 	 */
-	if (BN_cmp(server_key->rsa->n, host_key->rsa->n) < 0) {
+	if (BN_cmp(server_n, host_n) < 0) {
 		/* Public key has smaller modulus. */
-		if (BN_num_bits(host_key->rsa->n) <
-		    BN_num_bits(server_key->rsa->n) + SSH_KEY_BITS_RESERVED) {
+		if (BN_num_bits(host_n) <
+		    BN_num_bits(server_n) + SSH_KEY_BITS_RESERVED) {
 			fatal("respond_to_rsa_challenge: host_key %d < server_key %d + "
 			    "SSH_KEY_BITS_RESERVED %d",
-			    BN_num_bits(host_key->rsa->n),
-			    BN_num_bits(server_key->rsa->n),
+			    BN_num_bits(host_n),
+			    BN_num_bits(server_n),
 			    SSH_KEY_BITS_RESERVED);
 		}
 		if (rsa_public_encrypt(key, key, server_key->rsa) != 0 ||
@@ -610,12 +626,12 @@ ssh_kex(char *host, struct sockaddr *hostaddr)
 			fatal("%s: rsa_public_encrypt failed", __func__);
 	} else {
 		/* Host key has smaller modulus (or they are equal). */
-		if (BN_num_bits(server_key->rsa->n) <
-		    BN_num_bits(host_key->rsa->n) + SSH_KEY_BITS_RESERVED) {
+		if (BN_num_bits(server_n) <
+		    BN_num_bits(host_n) + SSH_KEY_BITS_RESERVED) {
 			fatal("respond_to_rsa_challenge: server_key %d < host_key %d + "
 			    "SSH_KEY_BITS_RESERVED %d",
-			    BN_num_bits(server_key->rsa->n),
-			    BN_num_bits(host_key->rsa->n),
+			    BN_num_bits(server_n),
+			    BN_num_bits(host_n),
 			    SSH_KEY_BITS_RESERVED);
 		}
 		if (rsa_public_encrypt(key, key, host_key->rsa) != 0 ||
diff --git a/sshkey.c b/sshkey.c
index 723f332..de954c1 100644
--- a/sshkey.c
+++ b/sshkey.c
@@ -266,18 +266,15 @@ sshkey_names_valid2(const char *names, int allow_wildcard)
 u_int
 sshkey_size(const struct sshkey *k)
 {
-	const BIGNUM *bn;
 	switch (k->type) {
 #ifdef WITH_OPENSSL
 	case KEY_RSA1:
 	case KEY_RSA:
 	case KEY_RSA_CERT:
-		RSA_get0_key(k->rsa, &bn, NULL, NULL);
-		return BN_num_bits(bn);
+		return RSA_bits(k->rsa);
 	case KEY_DSA:
 	case KEY_DSA_CERT:
-		DSA_get0_pqg(k->dsa, &bn, NULL, NULL);
-		return BN_num_bits(bn);
+		return DSA_bits(k->dsa);
 	case KEY_ECDSA:
 	case KEY_ECDSA_CERT:
 		return sshkey_curve_nid_to_bits(k->ecdsa_nid);
@@ -1247,6 +1244,7 @@ sshkey_read(struct sshkey *ret, char **cpp)
 	struct sshbuf *blob;
 #ifdef WITH_SSH1
 	u_long bits;
+	BIGNUM *e = NULL, *n = NULL;
 #endif /* WITH_SSH1 */
 
 	cp = *cpp;
@@ -1260,12 +1258,21 @@ sshkey_read(struct sshkey *ret, char **cpp)
 		    bits == 0 || bits > SSHBUF_MAX_BIGNUM * 8)
 			return SSH_ERR_INVALID_FORMAT;	/* Bad bit count... */
 		/* Get public exponent, public modulus. */
-		if ((r = read_decimal_bignum(&ep, ret->rsa->e)) < 0)
+		if ((e = BN_new()) == NULL || (n = BN_new()) == NULL) {
+			BN_free(e);
+			return SSH_ERR_ALLOC_FAIL;
+		}
+		if ((r = read_decimal_bignum(&ep, e)) < 0)
 			return r;
-		if ((r = read_decimal_bignum(&ep, ret->rsa->n)) < 0)
+		if ((r = read_decimal_bignum(&ep, n)) < 0)
 			return r;
+		if (RSA_set0_key(ret->rsa, n, e, NULL) == 0) {
+			BN_free(e);
+			BN_free(n);
+			return -1;
+		}
 		/* validate the claimed number of bits */
-		if (BN_num_bits(ret->rsa->n) != (int)bits)
+		if (BN_num_bits(n) != (int)bits)
 			return SSH_ERR_KEY_BITS_MISMATCH;
 		*cpp = ep;
 		retval = 0;
@@ -1430,19 +1437,20 @@ sshkey_format_rsa1(const struct sshkey *key, struct sshbuf *b)
 #ifdef WITH_SSH1
 	u_int bits = 0;
 	char *dec_e = NULL, *dec_n = NULL;
+	const BIGNUM *e, *n;
 
-	if (key->rsa == NULL || key->rsa->e == NULL ||
-	    key->rsa->n == NULL) {
+	RSA_get0_key(key->rsa, &n, &e, NULL);
+	if (key->rsa == NULL || e == NULL || n == NULL) {
 		r = SSH_ERR_INVALID_ARGUMENT;
 		goto out;
 	}
-	if ((dec_e = BN_bn2dec(key->rsa->e)) == NULL ||
-	    (dec_n = BN_bn2dec(key->rsa->n)) == NULL) {
+	if ((dec_e = BN_bn2dec(e)) == NULL ||
+	    (dec_n = BN_bn2dec(n)) == NULL) {
 		r = SSH_ERR_ALLOC_FAIL;
 		goto out;
 	}
 	/* size of modulus 'n' */
-	if ((bits = BN_num_bits(key->rsa->n)) <= 0) {
+	if ((bits = BN_num_bits(n)) <= 0) {
 		r = SSH_ERR_INVALID_ARGUMENT;
 		goto out;
 	}
@@ -2965,20 +2973,32 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
 			}
 		}
 		break;
-	case KEY_RSA_CERT:
-#if 0
-		if ((r = sshkey_froms(buf, &k)) != 0 ||
-		    (r = sshkey_add_private(k)) != 0 ||
-		    (r = sshbuf_get_bignum2(buf, k->rsa->d)) != 0 ||
-		    (r = sshbuf_get_bignum2(buf, k->rsa->iqmp)) != 0 ||
-		    (r = sshbuf_get_bignum2(buf, k->rsa->p)) != 0 ||
-		    (r = sshbuf_get_bignum2(buf, k->rsa->q)) != 0 ||
-		    (r = rsa_generate_additional_parameters(k->rsa)) != 0)
-			goto out;
-#endif
-		/* XXX: public key is missing */
-		r = SSH_ERR_INTERNAL_ERROR;
-		goto out;
+	case KEY_RSA_CERT: {
+			BIGNUM *n, *e, *d, *iqmp, *p, *q;
+
+			/* XXX leave N, E as zero */
+			n = BN_new();
+			e = BN_new();
+			d = BN_new();
+			iqmp = BN_new();
+			p = BN_new();
+			q = BN_new();
+
+			if (n == NULL || e == NULL || d == NULL ||
+			    iqmp == NULL || p == NULL || q == NULL ||
+			    (r = sshkey_froms(buf, &k)) != 0 ||
+			    (r = sshkey_add_private(k)) != 0 ||
+			    (r = sshbuf_get_bignum2(buf, d)) != 0 ||
+			    (r = sshbuf_get_bignum2(buf, iqmp)) != 0 ||
+			    (r = sshbuf_get_bignum2(buf, p)) != 0 ||
+			    (r = sshbuf_get_bignum2(buf, q)) != 0 ||
+			    (r = ((RSA_set0_key(k->rsa, n, e, d) == 0)
+			        ? SSH_ERR_LIBCRYPTO_ERROR : 0)) != 0 ||
+			    (r = ((RSA_set0_factors(k->rsa, p, q) == 0)
+			        ? SSH_ERR_LIBCRYPTO_ERROR : 0)) != 0 ||
+			    (r = rsa_generate_additional_parameters(k->rsa, iqmp)) != 0)
+				goto out;
+		}
 		break;
 #endif /* WITH_OPENSSL */
 	case KEY_ED25519:
@@ -3613,6 +3633,7 @@ sshkey_private_rsa1_to_blob(struct sshkey *key, struct sshbuf *blob,
 	struct sshcipher_ctx *ciphercontext = NULL;
 	const struct sshcipher *cipher;
 	u_char *cp;
+	const BIGNUM *n, *e, *d, *q, *p, *iqmp;
 
 	/*
 	 * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting
@@ -3639,10 +3660,13 @@ sshkey_private_rsa1_to_blob(struct sshkey *key, struct sshbuf *blob,
 	 * format would just give known plaintext).
 	 * Note: q and p are stored in reverse order to SSL.
 	 */
-	if ((r = sshbuf_put_bignum1(buffer, key->rsa->d)) != 0 ||
-	    (r = sshbuf_put_bignum1(buffer, key->rsa->iqmp)) != 0 ||
-	    (r = sshbuf_put_bignum1(buffer, key->rsa->q)) != 0 ||
-	    (r = sshbuf_put_bignum1(buffer, key->rsa->p)) != 0)
+	RSA_get0_key(key->rsa, &n, &e, &d);
+	RSA_get0_factors(key->rsa, &p, &q);
+	RSA_get0_crt_params(key->rsa, NULL, NULL, &iqmp);
+	if ((r = sshbuf_put_bignum1(buffer, d)) != 0 ||
+	    (r = sshbuf_put_bignum1(buffer, iqmp)) != 0 ||
+	    (r = sshbuf_put_bignum1(buffer, q)) != 0 ||
+	    (r = sshbuf_put_bignum1(buffer, p)) != 0)
 		goto out;
 
 	/* Pad the part to be encrypted to a size that is a multiple of 8. */
@@ -3667,9 +3691,9 @@ sshkey_private_rsa1_to_blob(struct sshkey *key, struct sshbuf *blob,
 		goto out;
 
 	/* Store public key.  This will be in plain text. */
-	if ((r = sshbuf_put_u32(encrypted, BN_num_bits(key->rsa->n))) != 0 ||
-	    (r = sshbuf_put_bignum1(encrypted, key->rsa->n)) != 0 ||
-	    (r = sshbuf_put_bignum1(encrypted, key->rsa->e)) != 0 ||
+	if ((r = sshbuf_put_u32(encrypted, BN_num_bits(n))) != 0 ||
+	    (r = sshbuf_put_bignum1(encrypted, n)) != 0 ||
+	    (r = sshbuf_put_bignum1(encrypted, e)) != 0 ||
 	    (r = sshbuf_put_cstring(encrypted, comment)) != 0)
 		goto out;
 
@@ -3796,6 +3820,7 @@ sshkey_parse_public_rsa1_fileblob(struct sshbuf *blob,
 	int r;
 	struct sshkey *pub = NULL;
 	struct sshbuf *copy = NULL;
+	BIGNUM *n = NULL, *e = NULL;
 
 	if (keyp != NULL)
 		*keyp = NULL;
@@ -3825,10 +3850,16 @@ sshkey_parse_public_rsa1_fileblob(struct sshbuf *blob,
 		goto out;
 
 	/* Read the public key from the buffer. */
-	if ((pub = sshkey_new(KEY_RSA1)) == NULL ||
-	    (r = sshbuf_get_bignum1(copy, pub->rsa->n)) != 0 ||
-	    (r = sshbuf_get_bignum1(copy, pub->rsa->e)) != 0)
+	if ((n = BN_new()) == NULL ||
+	    (e = BN_new()) == NULL ||
+	    (pub = sshkey_new(KEY_RSA1)) == NULL ||
+	    (r = sshbuf_get_bignum1(copy, n)) != 0 ||
+	    (r = sshbuf_get_bignum1(copy, e)) != 0 ||
+	    RSA_set0_key(pub->rsa, n, e, NULL) == 0) {
+		BN_free(n);
+		BN_free(e);
 		goto out;
+	}
 
 	/* Finally, the comment */
 	if ((r = sshbuf_get_string(copy, (u_char**)commentp, NULL)) != 0)
@@ -3860,6 +3891,8 @@ sshkey_parse_private_rsa1(struct sshbuf *blob, const char *passphrase,
 	struct sshcipher_ctx *ciphercontext = NULL;
 	const struct sshcipher *cipher;
 	struct sshkey *prv = NULL;
+	BIGNUM *n = NULL, *e = NULL, *d = NULL, *q = NULL, *p = NULL,
+	    *iqmp = NULL;
 
 	if (keyp != NULL)
 		*keyp = NULL;
@@ -3895,11 +3928,17 @@ sshkey_parse_private_rsa1(struct sshbuf *blob, const char *passphrase,
 		goto out;
 
 	/* Read the public key and comment from the buffer. */
-	if ((r = sshbuf_get_u32(copy, NULL)) != 0 ||	/* key bits */
-	    (r = sshbuf_get_bignum1(copy, prv->rsa->n)) != 0 ||
-	    (r = sshbuf_get_bignum1(copy, prv->rsa->e)) != 0 ||
-	    (r = sshbuf_get_cstring(copy, &comment, NULL)) != 0)
+	if ((n = BN_new()) == NULL ||
+	    (e = BN_new()) == NULL ||
+	    (r = sshbuf_get_u32(copy, NULL)) != 0 ||	/* key bits */
+	    (r = sshbuf_get_bignum1(copy, n)) != 0 ||
+	    (r = sshbuf_get_bignum1(copy, e)) != 0 ||
+	    (r = sshbuf_get_cstring(copy, &comment, NULL)) != 0 ||
+	    RSA_set0_key(prv->rsa, n, e, NULL) == 0) {
+		BN_free(n);
+		BN_free(e);
 		goto out;
+	}
 
 	/* Check that it is a supported cipher. */
 	cipher = cipher_by_number(cipher_type);
@@ -3928,14 +3967,25 @@ sshkey_parse_private_rsa1(struct sshbuf *blob, const char *passphrase,
 	}
 
 	/* Read the rest of the private key. */
-	if ((r = sshbuf_get_bignum1(decrypted, prv->rsa->d)) != 0 ||
-	    (r = sshbuf_get_bignum1(decrypted, prv->rsa->iqmp)) != 0 ||
-	    (r = sshbuf_get_bignum1(decrypted, prv->rsa->q)) != 0 ||
-	    (r = sshbuf_get_bignum1(decrypted, prv->rsa->p)) != 0)
+	if ((d = BN_new()) == NULL ||
+	    (p = BN_new()) == NULL ||
+	    (q = BN_new()) == NULL ||
+	    (iqmp = BN_new()) == NULL ||
+	    (r = sshbuf_get_bignum1(decrypted, d)) != 0 ||
+	    (r = sshbuf_get_bignum1(decrypted, iqmp)) != 0 ||
+	    (r = sshbuf_get_bignum1(decrypted, q)) != 0 ||
+	    (r = sshbuf_get_bignum1(decrypted, p)) != 0 ||
+	    (RSA_set0_key(prv->rsa, NULL, NULL, d) == 0) ||
+	    (RSA_set0_factors(prv->rsa, p, q) == 0)) {
+		BN_free(d);
+		BN_free(p);
+		BN_free(q);
+		BN_free(iqmp);
 		goto out;
+	}
 
 	/* calculate p-1 and q-1 */
-	if ((r = rsa_generate_additional_parameters(prv->rsa)) != 0)
+	if ((r = rsa_generate_additional_parameters(prv->rsa, iqmp)) != 0)
 		goto out;
 
 	/* enable blinding */
-- 
2.7.4


>From fc4557d26ad2ec1b3278bd2f105af093c99a46aa Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Wed, 2 Nov 2016 10:02:57 +0100
Subject: [PATCH 5/7] Improve OpenSSL initialization

 * OpenSSL_add_all_algoritms() is deprecated in 1.1.0 in favoiur of OPENSSL_init_crypto() to initialize engines
 * ENGINE_register_all_complete() is needed only before 1.0.1
---
 openbsd-compat/openssl-compat.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/openbsd-compat/openssl-compat.c b/openbsd-compat/openssl-compat.c
index 259fccb..74f65f8 100644
--- a/openbsd-compat/openssl-compat.c
+++ b/openbsd-compat/openssl-compat.c
@@ -70,12 +70,19 @@ ssh_compatible_openssl(long headerver, long libver)
 void
 ssh_OpenSSL_add_all_algorithms(void)
 {
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
 	OpenSSL_add_all_algorithms();
 
 	/* Enable use of crypto hardware */
 	ENGINE_load_builtin_engines();
+#if OPENSSL_VERSION_NUMBER < 0x10001000L
 	ENGINE_register_all_complete();
+#endif
 	OPENSSL_config(NULL);
+#else
+	OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_DIGESTS |
+	    OPENSSL_INIT_ADD_ALL_DIGESTS | OPENSSL_INIT_LOAD_CONFIG, NULL);
+#endif
 }
 #endif
 
-- 
2.7.4


>From 5a5a00c8cf8926206beee03e5899f567a2e22b50 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Wed, 2 Nov 2016 10:03:58 +0100
Subject: [PATCH 6/7] Move incompatible definitions of pthread_* to its own
 namespace (conflict with pthread.h included from OpenSSL)

---
 auth-pam.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/auth-pam.c b/auth-pam.c
index 7d8b292..e554ec4 100644
--- a/auth-pam.c
+++ b/auth-pam.c
@@ -129,6 +129,10 @@ extern u_int utmp_len;
 typedef pthread_t sp_pthread_t;
 #else
 typedef pid_t sp_pthread_t;
+# define pthread_create(a, b, c, d)	_ssh_compat_pthread_create(a, b, c, d)
+# define pthread_exit(a)		_ssh_compat_pthread_exit(a)
+# define pthread_cancel(a)		_ssh_compat_pthread_cancel(a)
+# define pthread_join(a, b)		_ssh_compat_pthread_join(a, b)
 #endif
 
 struct pam_ctxt {
-- 
2.7.4


>From 6be9785c9f1a8a96456193fc6065fe4a52ffa265 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Wed, 2 Nov 2016 10:05:12 +0100
Subject: [PATCH 7/7] Free missing bits identified by valgrind

---
 ssh.c        | 1 +
 sshconnect.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/ssh.c b/ssh.c
index 5e50fa0..fda77d9 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1230,6 +1230,7 @@ main(int ac, char **av)
 		free(cp);
 	}
 	free(conn_hash_hex);
+	free(host_arg);
 
 	if (config_test) {
 		dump_client_config(&options, host);
diff --git a/sshconnect.c b/sshconnect.c
index 96b91ce..07f80cd 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1363,6 +1363,7 @@ ssh_login(Sensitive *sensitive, const char *orighost,
 	char *server_user, *local_user;
 
 	local_user = xstrdup(pw->pw_name);
+	free(pw);
 	server_user = options.user ? options.user : local_user;
 
 	/* Convert the user-supplied hostname into all lowercase. */
-- 
2.7.4

_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@xxxxxxxxxxx
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev

[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux