OpenSSL 1.1.0 support

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

 



Hi,

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

It has the same regression tests failures as the master branch,
and it has been tested with both 1.0.2 and 1.1.0.

Some comments about the patch:
- I've included an libcrypto-compat.c to add new functions from
  OpenSSL that are needed with 1.1.0 but didn't exist in 1.0.2.
  Since they are copied from the OpenSSL source code, I also added
  the OpenSSL license to it. If this is a problem we can probably
  agree to put that file under a different license.
- I've replaced the 2 EVP_CipherInit() calls in cipher_init() with
  1. OpenSSL now clears everything when you call EVP_CipherInit()
  again, so what was passed in the first but not in the second
  call, and what the function calls between them did, was lost.
- The test suite was insitng that things like rsa->n where not
  NULL in sshkey/test_sshkey.c. sshkey_add_private was also doing
  something like that for the private parts. I don't agree that it
  should just have BN members that are not set to a real value. So I
  removed that code and the checks. I'm not even sure why this was
  done. But sshkey_add_private() ends up as a rather useless
  function now.
- In sshkey_private_deserialize() there was a KEY_RSA_CERT case.
  I'm not sure what it's about and I guess the test suite also
  doesn't check it. But it seems that it only has the private key
  in that case and OpenSSL now seems to insist that an RSA needs
  to have the public key information too.


PS: I didn't subscribe to the list.


Kurt

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

---
 Makefile.in                            |   2 +-
 cipher-3des1.c                         |   4 +
 cipher-bf1.c                           |   4 +-
 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 +++++++++++++++++++++++----------
 26 files changed, 1172 insertions(+), 333 deletions(-)
 create mode 100644 libcrypto-compat.c
 create mode 100644 libcrypto-compat.h

diff --git a/Makefile.in b/Makefile.in
index d6df2ff..68d9c46 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-3des1.c b/cipher-3des1.c
index 6a0f1f3..7d428c0 100644
--- a/cipher-3des1.c
+++ b/cipher-3des1.c
@@ -26,6 +26,8 @@
 
 #include "ssherr.h"
 
+#if defined(WITH_SSH1)
+
 /*
  * This is used by SSH1:
  *
@@ -153,3 +155,5 @@ evp_ssh1_3des(void)
 	ssh1_3des.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH;
 	return &ssh1_3des;
 }
+
+#endif /* defined(WITH_SSH1) */
diff --git a/cipher-bf1.c b/cipher-bf1.c
index 7d51f51..4c295b9 100644
--- a/cipher-bf1.c
+++ b/cipher-bf1.c
@@ -20,7 +20,7 @@
 
 #include "includes.h"
 
-#if defined(WITH_OPENSSL) && !defined(OPENSSL_NO_BF)
+#if defined(WITH_OPENSSL) && !defined(OPENSSL_NO_BF) && defined(WITH_SSH1)
 
 #include <sys/types.h>
 
@@ -100,4 +100,4 @@ evp_ssh1_bf(void)
 	ssh1_bf.key_len = 32;
 	return (&ssh1_bf);
 }
-#endif /* defined(WITH_OPENSSL) && !defined(OPENSSL_NO_BF) */
+#endif /* defined(WITH_OPENSSL) && !defined(OPENSSL_NO_BF) && defined(WITH_SSH1)*/
diff --git a/cipher.c b/cipher.c
index 747b59b..66c451b 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
@@ -665,7 +661,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
@@ -679,8 +675,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 bea8d8b..af7e49e 100644
--- a/monitor.c
+++ b/monitor.c
@@ -605,9 +605,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 e6df94a..6f06790 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;
 		}
@@ -533,21 +526,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 */
@@ -666,17 +648,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:
@@ -751,15 +747,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:
@@ -772,13 +774,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:
@@ -884,8 +891,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);
 
 		blob_len = nlen + elen;
 		if (nlen >= INT_MAX - elen ||
@@ -893,8 +905,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;
@@ -1760,15 +1772,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
@@ -1791,13 +1820,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 */
@@ -1995,10 +2033,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);
@@ -2016,12 +2064,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);
@@ -2261,26 +2331,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:
@@ -2401,12 +2498,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:
@@ -2418,10 +2537,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:
@@ -2578,43 +2708,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:
@@ -2690,18 +2842,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:
@@ -2760,16 +2945,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 ||
@@ -2778,6 +2996,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:
@@ -3779,7 +4001,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;
@@ -3794,7 +4016,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;
@@ -3806,7 +4028,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.9.3

_______________________________________________
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