All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] openssh: build support openssl 1.1
@ 2018-09-11  8:59 Hongxu Jia
  2018-09-11  9:10 ` Hongxu Jia
  2018-09-11 10:39 ` Alexander Kanavin
  0 siblings, 2 replies; 11+ messages in thread
From: Hongxu Jia @ 2018-09-11  8:59 UTC (permalink / raw)
  To: openembedded-core, ross.burton; +Cc: alexander.kanavin

As commit `5ccf4a9 openssh: depend on openssl 1.0' suggested,
take a patch from Fedora 29 to get openssl 1.1 support

Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
---
 .../openssh/0001-build-support-openssl-1.1.0.patch | 2502 ++++++++++++++++++++
 meta/recipes-connectivity/openssh/openssh_7.8p1.bb |    4 +-
 2 files changed, 2504 insertions(+), 2 deletions(-)
 create mode 100644 meta/recipes-connectivity/openssh/openssh/0001-build-support-openssl-1.1.0.patch

diff --git a/meta/recipes-connectivity/openssh/openssh/0001-build-support-openssl-1.1.0.patch b/meta/recipes-connectivity/openssh/openssh/0001-build-support-openssl-1.1.0.patch
new file mode 100644
index 0000000..24cb3e7
--- /dev/null
+++ b/meta/recipes-connectivity/openssh/openssh/0001-build-support-openssl-1.1.0.patch
@@ -0,0 +1,2502 @@
+From f0c0eabc6912fae1c8f3b856c1e80c561d7995eb Mon Sep 17 00:00:00 2001
+From: Hongxu Jia <hongxu.jia@windriver.com>
+Date: Tue, 11 Sep 2018 16:33:13 +0800
+Subject: [PATCH] build support openssl-1.1.0
+
+Backport a patch from fedora 29 to support openssl-1.1.0
+
+Upstream-Status: Backport [https://src.fedoraproject.org/git/rpms/openssh.git]
+
+Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
+---
+ Makefile.in                            |   3 +-
+ auth-pam.c                             |   4 +
+ cipher.c                               |  14 +-
+ configure.ac                           |   1 +
+ dh.c                                   |  54 ++--
+ dh.h                                   |   2 +-
+ digest-openssl.c                       |  18 +-
+ includes.h                             |   1 +
+ kexdhc.c                               |  19 +-
+ kexdhs.c                               |  10 +-
+ kexgexc.c                              |  22 +-
+ kexgexs.c                              |  19 +-
+ libcrypto-compat.c                     | 428 ++++++++++++++++++++++++++
+ libcrypto-compat.h                     |  59 ++++
+ monitor.c                              |   7 +-
+ openbsd-compat/openssl-compat.c        |   7 +
+ regress/unittests/sshkey/test_file.c   |  17 +-
+ regress/unittests/sshkey/test_sshkey.c |  22 +-
+ ssh-dss.c                              |  24 +-
+ ssh-ecdsa.c                            |  23 +-
+ ssh-keygen.c                           |  94 ++++--
+ ssh-pkcs11-client.c                    |  14 +-
+ ssh-pkcs11.c                           |  49 ++-
+ ssh-rsa.c                              |  38 ++-
+ sshkey.c                               | 534 +++++++++++++++++++++++----------
+ sshkey.h                               |   2 +-
+ 26 files changed, 1160 insertions(+), 325 deletions(-)
+ create mode 100644 libcrypto-compat.c
+ create mode 100644 libcrypto-compat.h
+
+diff --git a/Makefile.in b/Makefile.in
+index 2385c62..2232450 100644
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -100,7 +100,8 @@ 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-misc.o
++	platform-pledge.o platform-tracing.o platform-misc.o \
++	libcrypto-compat.o
+ 
+ SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
+ 	sshconnect.o sshconnect2.o mux.o
+diff --git a/auth-pam.c b/auth-pam.c
+index 8c01383..d6423e9 100644
+--- a/auth-pam.c
++++ b/auth-pam.c
+@@ -128,6 +128,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 {
+diff --git a/cipher.c b/cipher.c
+index a72682a..9cd0ce7 100644
+--- a/cipher.c
++++ b/cipher.c
+@@ -281,7 +281,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;
+@@ -299,10 +299,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;
+-	}
+ 	ret = 0;
+ #endif /* WITH_OPENSSL */
+  out:
+@@ -485,7 +481,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);
+ #endif
+ 	return 0;
+ }
+@@ -519,14 +515,14 @@ 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);
+ #endif
+ 	return 0;
+ }
+ 
+ #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/configure.ac b/configure.ac
+index 83e5307..3346b80 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -2602,6 +2602,7 @@ if test "x$openssl" = "xyes" ; then
+ 					AC_MSG_ERROR([OpenSSL >= 1.0.1 required (have "$ssl_library_ver")])
+ 			                ;;
+ 				100*)   ;; # 1.0.x
++				101*)   ;; # 1.1.x is supported by this patch too
+ 				200*)   ;; # LibreSSL
+ 			        *)
+ 					AC_MSG_ERROR([OpenSSL >= 1.1.0 is not yet supported (have "$ssl_library_ver")])
+diff --git a/dh.c b/dh.c
+index ac8d5a0..760bfd8 100644
+--- a/dh.c
++++ b/dh.c
+@@ -216,14 +216,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;
+ 	}
+@@ -236,7 +237,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");
+@@ -247,14 +249,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;
+@@ -264,9 +266,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)
+@@ -275,11 +279,11 @@ 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->priv_key = NULL;
++	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;
+@@ -289,15 +293,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 = NULL, *g = NULL;
++
++	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;
+ }
+ 
+ /*
+@@ -312,8 +323,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 2770999..6570c5b 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 {
+@@ -106,7 +106,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 *
+@@ -118,8 +118,10 @@ 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) {
++		EVP_MD_CTX_free(ret->mdctx);
+ 		free(ret);
+ 		return NULL;
+ 	}
+@@ -132,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;
+ }
+@@ -140,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;
+ }
+@@ -161,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;
+@@ -172,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 0fd7179..487b7a1 100644
+--- a/includes.h
++++ b/includes.h
+@@ -166,6 +166,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 9a9f1ea..bb9b67b 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;
+ }
+ 
+@@ -109,6 +116,7 @@ input_kex_dh(int type, u_int32_t seq, struct ssh *ssh)
+ 	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;
+@@ -168,6 +176,7 @@ input_kex_dh(int type, u_int32_t seq, struct ssh *ssh)
+ #endif
+ 
+ 	/* calc and verify H */
++	DH_get0_key(kex->dh, &pub_key, NULL);
+ 	hashlen = sizeof(hash);
+ 	if ((r = kex_dh_hash(
+ 	    kex->hash_alg,
+@@ -176,7 +185,7 @@ input_kex_dh(int type, u_int32_t seq, struct ssh *ssh)
+ 	    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 5dfca0a..3bb8a5c 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;
+ }
+ 
+@@ -101,6 +105,7 @@ input_kex_dh_init(int type, u_int32_t seq, struct ssh *ssh)
+ 	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) {
+@@ -163,6 +168,7 @@ input_kex_dh_init(int type, u_int32_t seq, struct ssh *ssh)
+ 		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,
+@@ -171,7 +177,7 @@ input_kex_dh_init(int type, u_int32_t seq, struct ssh *ssh)
+ 	    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;
+@@ -197,7 +203,7 @@ input_kex_dh_init(int type, u_int32_t seq, struct ssh *ssh)
+ 	/* send server hostkey, DH pubkey 'f' and signed 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 762a9a3..3d07225 100644
+--- a/kexgexc.c
++++ b/kexgexc.c
+@@ -94,6 +94,7 @@ input_kex_dh_gex_group(int type, u_int32_t seq, struct ssh *ssh)
+ 	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");
+ 
+@@ -118,16 +119,18 @@ input_kex_dh_gex_group(int type, u_int32_t seq, struct ssh *ssh)
+ 	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);
+@@ -136,6 +139,10 @@ input_kex_dh_gex_group(int type, u_int32_t seq, struct ssh *ssh)
+ out:
+ 	BN_clear_free(p);
+ 	BN_clear_free(g);
++	if (r != 0) {
++		DH_free(kex->dh);
++		kex->dh = NULL;
++	}
+ 	return r;
+ }
+ 
+@@ -149,6 +156,7 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh)
+ 	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) {
+@@ -211,6 +219,8 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh)
+ 		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,
+@@ -220,8 +230,8 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh)
+ 	    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 f6983fd..581d8ae 100644
+--- a/kexgexs.c
++++ b/kexgexs.c
+@@ -72,6 +72,7 @@ input_kex_dh_gex_request(int type, u_int32_t seq, struct ssh *ssh)
+ 	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 ||
+@@ -101,9 +102,10 @@ input_kex_dh_gex_request(int type, u_int32_t seq, struct ssh *ssh)
+ 		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;
+ 
+@@ -115,6 +117,10 @@ input_kex_dh_gex_request(int type, u_int32_t seq, struct ssh *ssh)
+ 	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;
+ }
+ 
+@@ -129,6 +135,7 @@ input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh)
+ 	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) {
+@@ -191,6 +198,8 @@ input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh)
+ 		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,
+@@ -199,9 +208,9 @@ input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh)
+ 	    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;
+@@ -227,7 +236,7 @@ input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh)
+ 	/* send server hostkey, DH pubkey 'f' and signed 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..8203f6b
+--- /dev/null
++++ b/libcrypto-compat.c
+@@ -0,0 +1,428 @@
++/*
++ * 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_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 */
++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));
++}
++
++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) {
++        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..674e382
+--- /dev/null
++++ b/libcrypto-compat.h
+@@ -0,0 +1,59 @@
++#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_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
++#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);
++int DSA_bits(const DSA *d);
++
++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 d4b4b04..3d46f30 100644
+--- a/monitor.c
++++ b/monitor.c
+@@ -590,9 +590,12 @@ mm_answer_moduli(int sock, struct sshbuf *m)
+ 		return (0);
+ 	} else {
+ 		/* Send first bignum */
++		const BIGNUM *p, *g;
++
++		DH_get0_pqg(dh, &p, NULL, &g);
+ 		if ((r = sshbuf_put_u8(m, 1)) != 0 ||
+-		    (r = sshbuf_put_bignum2(m, dh->p)) != 0 ||
+-		    (r = sshbuf_put_bignum2(m, dh->g)) != 0)
++		    (r = sshbuf_put_bignum2(m, p)) != 0 ||
++		    (r = sshbuf_put_bignum2(m, g)) != 0)
+ 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
+ 
+ 		DH_free(dh);
+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
+ 
+diff --git a/regress/unittests/sshkey/test_file.c b/regress/unittests/sshkey/test_file.c
+index 99b7e21..3262e87 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");
+@@ -60,9 +61,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);
+@@ -151,9 +154,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 72367bd..1d1af0f 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_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();
+ 
+@@ -207,8 +204,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();
+ 
+@@ -234,9 +229,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();
+@@ -245,8 +237,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();
+@@ -285,18 +275,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
+@@ -323,9 +308,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");
+@@ -339,8 +321,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/ssh-dss.c b/ssh-dss.c
+index 9f832ee..ba69b76 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 ((b = sshbuf_new()) == NULL) {
+ 		ret = SSH_ERR_ALLOC_FAIL;
+@@ -123,6 +125,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 ||
+@@ -155,16 +158,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,
+@@ -185,6 +191,8 @@ ssh_dss_verify(const struct sshkey *key,
+ 
+  out:
+ 	explicit_bzero(digest, sizeof(digest));
++	BN_free(r);
++	BN_free(s);
+ 	DSA_SIG_free(sig);
+ 	sshbuf_free(b);
+ 	free(ktype);
+diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c
+index 3d3b78d..18ac03b 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)
+@@ -118,6 +120,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 ||
+@@ -146,15 +149,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;
+@@ -179,6 +190,8 @@ ssh_ecdsa_verify(const struct sshkey *key,
+ 	explicit_bzero(digest, sizeof(digest));
+ 	sshbuf_free(sigbuf);
+ 	sshbuf_free(b);
++	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 22860ad..ed1b4df 100644
+--- a/ssh-keygen.c
++++ b/ssh-keygen.c
+@@ -493,40 +493,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 = ssh_rsa_generate_additional_parameters(key, 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 = ssh_rsa_generate_additional_parameters(key)) != 0)
+-			fatal("generate RSA parameters failed: %s", ssh_err(r));
+ 		break;
+ 	}
+ 	rlen = sshbuf_len(b);
+@@ -634,7 +661,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");
+@@ -658,7 +685,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;
+@@ -1785,6 +1812,7 @@ do_ca_sign(struct passwd *pw, int argc, char **argv)
+ #ifdef ENABLE_PKCS11
+ 	pkcs11_terminate();
+ #endif
++	free(ca);
+ 	exit(0);
+ }
+ 
+diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c
+index 028b272..47d964f 100644
+--- a/ssh-pkcs11-client.c
++++ b/ssh-pkcs11-client.c
+@@ -156,12 +156,16 @@ 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());
++		if (helper_rsa == NULL)
++			error("RSA_meth_dup failed");
++		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 65a7b58..fb2aed0 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;
+ };
+@@ -183,6 +183,7 @@ pkcs11_rsa_finish(RSA *rsa)
+ 		if (k11->provider)
+ 			pkcs11_provider_unref(k11->provider);
+ 		free(k11->keyid);
++		RSA_meth_free(k11->rsa_method);
+ 		free(k11);
+ 	}
+ 	return (rv);
+@@ -326,13 +327,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 +469,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 +522,18 @@ 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_n == NULL || rsa_e == NULL)
++					error("BN_bin2bn failed");
++				if (RSA_set0_key(rsa, rsa_n, rsa_e, NULL) == 0)
++					error("RSA_set0_key failed");
++
+ 			}
+ 		} else {
+ 			cp = attribs[2].pValue;
+@@ -525,16 +543,19 @@ 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");
+ 			}
+ 			X509_free(x509);
+ 		}
+-		if (rsa && rsa->n && rsa->e &&
++
++		if (rsa)
++			RSA_get0_key(rsa, &n, &e, NULL);
++		if (rsa && n && e &&
+ 		    pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0) {
+ 			if ((key = sshkey_new(KEY_UNSPEC)) == NULL)
+ 				fatal("sshkey_new failed");
+diff --git a/ssh-rsa.c b/ssh-rsa.c
+index 1756315..496e61c 100644
+--- a/ssh-rsa.c
++++ b/ssh-rsa.c
+@@ -104,38 +104,50 @@ rsa_hash_alg_nid(int type)
+ }
+ 
+ int
+-ssh_rsa_generate_additional_parameters(struct sshkey *key)
++ssh_rsa_generate_additional_parameters(struct sshkey *key, BIGNUM *iqmp)
+ {
+ 	BIGNUM *aux = NULL;
+ 	BN_CTX *ctx = NULL;
+-	BIGNUM d;
++	BIGNUM *d = NULL;
+ 	int r;
++	const BIGNUM *p, *q, *rsa_d;
++	BIGNUM *dmp1 = NULL, *dmq1 = NULL;
+ 
+ 	if (key == NULL || key->rsa == NULL ||
+ 	    sshkey_type_plain(key->type) != KEY_RSA)
+ 		return SSH_ERR_INVALID_ARGUMENT;
+ 
+-	if ((ctx = BN_CTX_new()) == NULL)
+-		return SSH_ERR_ALLOC_FAIL;
+-	if ((aux = BN_new()) == NULL) {
++	RSA_get0_factors(key->rsa, &p, &q);
++	RSA_get0_key(key->rsa, NULL, NULL, &rsa_d);
++
++	if ((ctx = BN_CTX_new()) == NULL ||
++	    (aux = BN_new()) == NULL ||
++	    (d = BN_new()) == NULL ||
++	    (dmp1 = BN_new()) == NULL ||
++	    (dmq1 = BN_new()) == NULL) {
+ 		r = SSH_ERR_ALLOC_FAIL;
+ 		goto out;
+ 	}
+ 	BN_set_flags(aux, BN_FLG_CONSTTIME);
+ 
+-	BN_init(&d);
+-	BN_with_flags(&d, key->rsa->d, BN_FLG_CONSTTIME);
++	BN_with_flags(d, rsa_d, BN_FLG_CONSTTIME);
+ 
+-	if ((BN_sub(aux, key->rsa->q, BN_value_one()) == 0) ||
+-	    (BN_mod(key->rsa->dmq1, &d, aux, ctx) == 0) ||
+-	    (BN_sub(aux, key->rsa->p, BN_value_one()) == 0) ||
+-	    (BN_mod(key->rsa->dmp1, &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(key->rsa, dmp1, dmq1, iqmp) == 0)) {
+ 		r = SSH_ERR_LIBCRYPTO_ERROR;
+ 		goto out;
+ 	}
++	dmp1 = NULL;
++	dmq1 = NULL;
+ 	r = 0;
+  out:
++	BN_free(d);
+ 	BN_clear_free(aux);
++	BN_clear_free(dmp1);
++	BN_clear_free(dmq1);
+ 	BN_CTX_free(ctx);
+ 	return r;
+ }
+@@ -163,7 +175,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;
+-	if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
++	if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE)
+ 		return SSH_ERR_KEY_LENGTH;
+ 	slen = RSA_size(key->rsa);
+ 	if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM)
+@@ -235,7 +247,7 @@ ssh_rsa_verify(const struct sshkey *key,
+ 	    sshkey_type_plain(key->type) != KEY_RSA ||
+ 	    sig == NULL || siglen == 0)
+ 		return SSH_ERR_INVALID_ARGUMENT;
+-	if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
++	if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE)
+ 		return SSH_ERR_KEY_LENGTH;
+ 
+ 	if ((b = sshbuf_from(sig, siglen)) == NULL)
+diff --git a/sshkey.c b/sshkey.c
+index 72c08c7..a9c8e0c 100644
+--- a/sshkey.c
++++ b/sshkey.c
+@@ -292,10 +292,10 @@ sshkey_size(const struct sshkey *k)
+ #ifdef WITH_OPENSSL
+ 	case KEY_RSA:
+ 	case KEY_RSA_CERT:
+-		return BN_num_bits(k->rsa->n);
++		return RSA_bits(k->rsa);
+ 	case KEY_DSA:
+ 	case KEY_DSA_CERT:
+-		return BN_num_bits(k->dsa->p);
++		return DSA_bits(k->dsa);
+ 	case KEY_ECDSA:
+ 	case KEY_ECDSA_CERT:
+ 		return sshkey_curve_nid_to_bits(k->ecdsa_nid);
+@@ -500,10 +500,7 @@ sshkey_new(int type)
+ #ifdef WITH_OPENSSL
+ 	case KEY_RSA:
+ 	case KEY_RSA_CERT:
+-		if ((rsa = RSA_new()) == NULL ||
+-		    (rsa->n = BN_new()) == NULL ||
+-		    (rsa->e = BN_new()) == NULL) {
+-			RSA_free(rsa);
++		if ((rsa = RSA_new()) == NULL) {
+ 			free(k);
+ 			return NULL;
+ 		}
+@@ -511,12 +508,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) {
+-			DSA_free(dsa);
++		if ((dsa = DSA_new()) == NULL) {
+ 			free(k);
+ 			return NULL;
+ 		}
+@@ -557,21 +549,10 @@ sshkey_add_private(struct sshkey *k)
+ #ifdef WITH_OPENSSL
+ 	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 */
+@@ -694,17 +675,31 @@ sshkey_equal_public(const struct sshkey *a, const struct sshkey *b)
+ 	switch (a->type) {
+ #ifdef WITH_OPENSSL
+ 	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:
+@@ -790,15 +785,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:
+@@ -811,13 +812,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:
+@@ -1755,15 +1761,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
+@@ -1785,13 +1808,22 @@ sshkey_from_private(const struct sshkey *k, struct sshkey **pkp)
+ 		break;
+ # endif /* OPENSSL_HAS_ECC */
+ 	case KEY_RSA:
+-	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 */
+@@ -2013,12 +2045,22 @@ 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;
++			}
+ 		}
+-		if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
++		if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
+ 			ret = SSH_ERR_KEY_LENGTH;
+ 			goto out;
+ 		}
+@@ -2038,12 +2080,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);
+@@ -2388,26 +2452,53 @@ sshkey_demote(const struct sshkey *k, struct sshkey **dkp)
+ 		if ((ret = sshkey_cert_copy(k, pk)) != 0)
+ 			goto fail;
+ 		/* FALLTHROUGH */
+-	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:
+@@ -2557,12 +2648,17 @@ sshkey_certify_custom(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: {
++			const BIGNUM *p, *q, *g, *pub_key;
++
++			DSA_get0_pqg(k->dsa, &p, &q, &g);
++			DSA_get0_key(k->dsa, &pub_key, NULL);
++			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)
++				goto out;
++		}
+ 		break;
+ # ifdef OPENSSL_HAS_ECC
+ 	case KEY_ECDSA_CERT:
+@@ -2574,10 +2670,15 @@ sshkey_certify_custom(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: {
++			const BIGNUM *e, *n;
++
++			RSA_get0_key(k->rsa, &n, &e, NULL);
++			if (e == NULL || n == NULL ||
++			    (ret = sshbuf_put_bignum2(cert, e)) != 0 ||
++			    (ret = sshbuf_put_bignum2(cert, n)) != 0)
++				goto out;
++		}
+ 		break;
+ #endif /* WITH_OPENSSL */
+ 	case KEY_ED25519_CERT:
+@@ -2763,43 +2864,65 @@ sshkey_private_serialize_opt(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:
+@@ -2913,18 +3036,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:
+@@ -2983,29 +3139,89 @@ 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 = ssh_rsa_generate_additional_parameters(k)) != 0)
+-			goto out;
+-		if (BN_num_bits(k->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
++		{
++			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 = ssh_rsa_generate_additional_parameters(k, iqmp)) != 0) {
++				BN_free(iqmp);
++				goto out;
++			}
++		}
++		if (RSA_bits(k->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
+ 			r = SSH_ERR_KEY_LENGTH;
+ 			goto out;
+ 		}
+ 		break;
+-	case KEY_RSA_CERT:
+-		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 = ssh_rsa_generate_additional_parameters(k)) != 0)
+-			goto out;
+-		if (BN_num_bits(k->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
++	case KEY_RSA_CERT: {
++			BIGNUM *d, *iqmp, *p, *q;
++
++			/* N and E are already set so make sure we will not overwrite them */
++			d = BN_new();
++			iqmp = BN_new();
++			p = BN_new();
++			q = BN_new();
++
++			if (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, NULL, NULL, d) == 0)
++			        ? SSH_ERR_LIBCRYPTO_ERROR : 0)) != 0) {
++				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(p);
++				BN_free(q);
++				goto out;
++			}
++			if (ssh_rsa_generate_additional_parameters(k, iqmp) != 0) {
++			        r = SSH_ERR_LIBCRYPTO_ERROR;
++				free(iqmp);
++				goto out;
++			}
++		}
++		if (RSA_bits(k->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
+ 			r = SSH_ERR_KEY_LENGTH;
+ 			goto out;
+ 		}
+@@ -3769,7 +3985,9 @@ translate_libcrypto_error(unsigned long pem_err)
+ 		switch (pem_reason) {
+ 		case EVP_R_BAD_DECRYPT:
+ 			return SSH_ERR_KEY_WRONG_PASSPHRASE;
++#ifdef EVP_R_BN_DECODE_ERROR
+ 		case EVP_R_BN_DECODE_ERROR:
++#endif
+ 		case EVP_R_DECODE_ERROR:
+ #ifdef EVP_R_PRIVATE_KEY_DECODE_ERROR
+ 		case EVP_R_PRIVATE_KEY_DECODE_ERROR:
+@@ -3834,7 +4052,7 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
+ 		r = convert_libcrypto_error();
+ 		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;
+@@ -3849,11 +4067,11 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
+ 			r = SSH_ERR_LIBCRYPTO_ERROR;
+ 			goto out;
+ 		}
+-		if (BN_num_bits(prv->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
++		if (RSA_bits(prv->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
+ 			r = SSH_ERR_KEY_LENGTH;
+ 			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;
+@@ -3865,7 +4083,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;
+diff --git a/sshkey.h b/sshkey.h
+index 9060b2e..adbd14a 100644
+--- a/sshkey.h
++++ b/sshkey.h
+@@ -218,7 +218,7 @@ int	sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
+     const char *passphrase, struct sshkey **keyp, char **commentp);
+ 
+ /* XXX should be internal, but used by ssh-keygen */
+-int ssh_rsa_generate_additional_parameters(struct sshkey *);
++int ssh_rsa_generate_additional_parameters(struct sshkey *, BIGNUM *iqmp);
+ 
+ /* stateful keys (e.g. XMSS) */
+ #ifdef NO_ATTRIBUTE_ON_PROTOTYPE_ARGS
+-- 
+2.7.4
+
diff --git a/meta/recipes-connectivity/openssh/openssh_7.8p1.bb b/meta/recipes-connectivity/openssh/openssh_7.8p1.bb
index f4b295f..8b83929 100644
--- a/meta/recipes-connectivity/openssh/openssh_7.8p1.bb
+++ b/meta/recipes-connectivity/openssh/openssh_7.8p1.bb
@@ -8,8 +8,7 @@ SECTION = "console/network"
 LICENSE = "BSD"
 LIC_FILES_CHKSUM = "file://LICENCE;md5=429658c6612f3a9b1293782366ab29d8"
 
-# openssl 1.1 patches are proposed at https://github.com/openssh/openssh-portable/pull/48
-DEPENDS = "zlib openssl10"
+DEPENDS = "zlib openssl"
 DEPENDS += "${@bb.utils.contains('DISTRO_FEATURES', 'pam', 'libpam', '', d)}"
 
 SRC_URI = "http://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-${PV}.tar.gz \
@@ -25,6 +24,7 @@ SRC_URI = "http://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-${PV}.tar
            file://fix-potential-signed-overflow-in-pointer-arithmatic.patch \
            file://sshd_check_keys \
            file://add-test-support-for-busybox.patch \
+           file://0001-build-support-openssl-1.1.0.patch \
            "
 
 PAM_SRC_URI = "file://sshd"
-- 
2.7.4



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH] openssh: build support openssl 1.1
  2018-09-11  8:59 [PATCH] openssh: build support openssl 1.1 Hongxu Jia
@ 2018-09-11  9:10 ` Hongxu Jia
  2018-09-11 10:39 ` Alexander Kanavin
  1 sibling, 0 replies; 11+ messages in thread
From: Hongxu Jia @ 2018-09-11  9:10 UTC (permalink / raw)
  To: openembedded-core, ross.burton; +Cc: alexander.kanavin

The reason why has this patch is the build failure with meta-selinux

[snip]
ERROR: The file /usr/include/openssl/stack.h is installed by both 
openssl and openssl10, aborting
[snip]

While adding meta-selinux, openssh -> libselinux -> python -> openssl
and openssh -> openssl10,
(`->' means depends)

The openssl and openssl10 conflicts.

//Hongxu

On 2018年09月11日 16:59, Hongxu Jia wrote:
> As commit `5ccf4a9 openssh: depend on openssl 1.0' suggested,
> take a patch from Fedora 29 to get openssl 1.1 support
>
> Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
> ---
>   .../openssh/0001-build-support-openssl-1.1.0.patch | 2502 ++++++++++++++++++++
>   meta/recipes-connectivity/openssh/openssh_7.8p1.bb |    4 +-
>   2 files changed, 2504 insertions(+), 2 deletions(-)
>   create mode 100644 meta/recipes-connectivity/openssh/openssh/0001-build-support-openssl-1.1.0.patch
>
> diff --git a/meta/recipes-connectivity/openssh/openssh/0001-build-support-openssl-1.1.0.patch b/meta/recipes-connectivity/openssh/openssh/0001-build-support-openssl-1.1.0.patch
> new file mode 100644
> index 0000000..24cb3e7
> --- /dev/null
> +++ b/meta/recipes-connectivity/openssh/openssh/0001-build-support-openssl-1.1.0.patch
> @@ -0,0 +1,2502 @@
> +From f0c0eabc6912fae1c8f3b856c1e80c561d7995eb Mon Sep 17 00:00:00 2001
> +From: Hongxu Jia <hongxu.jia@windriver.com>
> +Date: Tue, 11 Sep 2018 16:33:13 +0800
> +Subject: [PATCH] build support openssl-1.1.0
> +
> +Backport a patch from fedora 29 to support openssl-1.1.0
> +
> +Upstream-Status: Backport [https://src.fedoraproject.org/git/rpms/openssh.git]
> +
> +Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
> +---
> + Makefile.in                            |   3 +-
> + auth-pam.c                             |   4 +
> + cipher.c                               |  14 +-
> + configure.ac                           |   1 +
> + dh.c                                   |  54 ++--
> + dh.h                                   |   2 +-
> + digest-openssl.c                       |  18 +-
> + includes.h                             |   1 +
> + kexdhc.c                               |  19 +-
> + kexdhs.c                               |  10 +-
> + kexgexc.c                              |  22 +-
> + kexgexs.c                              |  19 +-
> + libcrypto-compat.c                     | 428 ++++++++++++++++++++++++++
> + libcrypto-compat.h                     |  59 ++++
> + monitor.c                              |   7 +-
> + openbsd-compat/openssl-compat.c        |   7 +
> + regress/unittests/sshkey/test_file.c   |  17 +-
> + regress/unittests/sshkey/test_sshkey.c |  22 +-
> + ssh-dss.c                              |  24 +-
> + ssh-ecdsa.c                            |  23 +-
> + ssh-keygen.c                           |  94 ++++--
> + ssh-pkcs11-client.c                    |  14 +-
> + ssh-pkcs11.c                           |  49 ++-
> + ssh-rsa.c                              |  38 ++-
> + sshkey.c                               | 534 +++++++++++++++++++++++----------
> + sshkey.h                               |   2 +-
> + 26 files changed, 1160 insertions(+), 325 deletions(-)
> + create mode 100644 libcrypto-compat.c
> + create mode 100644 libcrypto-compat.h
> +
> +diff --git a/Makefile.in b/Makefile.in
> +index 2385c62..2232450 100644
> +--- a/Makefile.in
> ++++ b/Makefile.in
> +@@ -100,7 +100,8 @@ 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-misc.o
> ++	platform-pledge.o platform-tracing.o platform-misc.o \
> ++	libcrypto-compat.o
> +
> + SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
> + 	sshconnect.o sshconnect2.o mux.o
> +diff --git a/auth-pam.c b/auth-pam.c
> +index 8c01383..d6423e9 100644
> +--- a/auth-pam.c
> ++++ b/auth-pam.c
> +@@ -128,6 +128,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 {
> +diff --git a/cipher.c b/cipher.c
> +index a72682a..9cd0ce7 100644
> +--- a/cipher.c
> ++++ b/cipher.c
> +@@ -281,7 +281,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;
> +@@ -299,10 +299,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;
> +-	}
> + 	ret = 0;
> + #endif /* WITH_OPENSSL */
> +  out:
> +@@ -485,7 +481,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);
> + #endif
> + 	return 0;
> + }
> +@@ -519,14 +515,14 @@ 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);
> + #endif
> + 	return 0;
> + }
> +
> + #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/configure.ac b/configure.ac
> +index 83e5307..3346b80 100644
> +--- a/configure.ac
> ++++ b/configure.ac
> +@@ -2602,6 +2602,7 @@ if test "x$openssl" = "xyes" ; then
> + 					AC_MSG_ERROR([OpenSSL >= 1.0.1 required (have "$ssl_library_ver")])
> + 			                ;;
> + 				100*)   ;; # 1.0.x
> ++				101*)   ;; # 1.1.x is supported by this patch too
> + 				200*)   ;; # LibreSSL
> + 			        *)
> + 					AC_MSG_ERROR([OpenSSL >= 1.1.0 is not yet supported (have "$ssl_library_ver")])
> +diff --git a/dh.c b/dh.c
> +index ac8d5a0..760bfd8 100644
> +--- a/dh.c
> ++++ b/dh.c
> +@@ -216,14 +216,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;
> + 	}
> +@@ -236,7 +237,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");
> +@@ -247,14 +249,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;
> +@@ -264,9 +266,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)
> +@@ -275,11 +279,11 @@ 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->priv_key = NULL;
> ++	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;
> +@@ -289,15 +293,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 = NULL, *g = NULL;
> ++
> ++	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;
> + }
> +
> + /*
> +@@ -312,8 +323,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 2770999..6570c5b 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 {
> +@@ -106,7 +106,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 *
> +@@ -118,8 +118,10 @@ 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) {
> ++		EVP_MD_CTX_free(ret->mdctx);
> + 		free(ret);
> + 		return NULL;
> + 	}
> +@@ -132,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;
> + }
> +@@ -140,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;
> + }
> +@@ -161,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;
> +@@ -172,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 0fd7179..487b7a1 100644
> +--- a/includes.h
> ++++ b/includes.h
> +@@ -166,6 +166,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 9a9f1ea..bb9b67b 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;
> + }
> +
> +@@ -109,6 +116,7 @@ input_kex_dh(int type, u_int32_t seq, struct ssh *ssh)
> + 	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;
> +@@ -168,6 +176,7 @@ input_kex_dh(int type, u_int32_t seq, struct ssh *ssh)
> + #endif
> +
> + 	/* calc and verify H */
> ++	DH_get0_key(kex->dh, &pub_key, NULL);
> + 	hashlen = sizeof(hash);
> + 	if ((r = kex_dh_hash(
> + 	    kex->hash_alg,
> +@@ -176,7 +185,7 @@ input_kex_dh(int type, u_int32_t seq, struct ssh *ssh)
> + 	    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 5dfca0a..3bb8a5c 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;
> + }
> +
> +@@ -101,6 +105,7 @@ input_kex_dh_init(int type, u_int32_t seq, struct ssh *ssh)
> + 	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) {
> +@@ -163,6 +168,7 @@ input_kex_dh_init(int type, u_int32_t seq, struct ssh *ssh)
> + 		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,
> +@@ -171,7 +177,7 @@ input_kex_dh_init(int type, u_int32_t seq, struct ssh *ssh)
> + 	    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;
> +@@ -197,7 +203,7 @@ input_kex_dh_init(int type, u_int32_t seq, struct ssh *ssh)
> + 	/* send server hostkey, DH pubkey 'f' and signed 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 762a9a3..3d07225 100644
> +--- a/kexgexc.c
> ++++ b/kexgexc.c
> +@@ -94,6 +94,7 @@ input_kex_dh_gex_group(int type, u_int32_t seq, struct ssh *ssh)
> + 	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");
> +
> +@@ -118,16 +119,18 @@ input_kex_dh_gex_group(int type, u_int32_t seq, struct ssh *ssh)
> + 	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);
> +@@ -136,6 +139,10 @@ input_kex_dh_gex_group(int type, u_int32_t seq, struct ssh *ssh)
> + out:
> + 	BN_clear_free(p);
> + 	BN_clear_free(g);
> ++	if (r != 0) {
> ++		DH_free(kex->dh);
> ++		kex->dh = NULL;
> ++	}
> + 	return r;
> + }
> +
> +@@ -149,6 +156,7 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh)
> + 	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) {
> +@@ -211,6 +219,8 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh)
> + 		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,
> +@@ -220,8 +230,8 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh)
> + 	    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 f6983fd..581d8ae 100644
> +--- a/kexgexs.c
> ++++ b/kexgexs.c
> +@@ -72,6 +72,7 @@ input_kex_dh_gex_request(int type, u_int32_t seq, struct ssh *ssh)
> + 	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 ||
> +@@ -101,9 +102,10 @@ input_kex_dh_gex_request(int type, u_int32_t seq, struct ssh *ssh)
> + 		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;
> +
> +@@ -115,6 +117,10 @@ input_kex_dh_gex_request(int type, u_int32_t seq, struct ssh *ssh)
> + 	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;
> + }
> +
> +@@ -129,6 +135,7 @@ input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh)
> + 	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) {
> +@@ -191,6 +198,8 @@ input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh)
> + 		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,
> +@@ -199,9 +208,9 @@ input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh)
> + 	    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;
> +@@ -227,7 +236,7 @@ input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh)
> + 	/* send server hostkey, DH pubkey 'f' and signed 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..8203f6b
> +--- /dev/null
> ++++ b/libcrypto-compat.c
> +@@ -0,0 +1,428 @@
> ++/*
> ++ * 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_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 */
> ++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));
> ++}
> ++
> ++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) {
> ++        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..674e382
> +--- /dev/null
> ++++ b/libcrypto-compat.h
> +@@ -0,0 +1,59 @@
> ++#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_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
> ++#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);
> ++int DSA_bits(const DSA *d);
> ++
> ++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 d4b4b04..3d46f30 100644
> +--- a/monitor.c
> ++++ b/monitor.c
> +@@ -590,9 +590,12 @@ mm_answer_moduli(int sock, struct sshbuf *m)
> + 		return (0);
> + 	} else {
> + 		/* Send first bignum */
> ++		const BIGNUM *p, *g;
> ++
> ++		DH_get0_pqg(dh, &p, NULL, &g);
> + 		if ((r = sshbuf_put_u8(m, 1)) != 0 ||
> +-		    (r = sshbuf_put_bignum2(m, dh->p)) != 0 ||
> +-		    (r = sshbuf_put_bignum2(m, dh->g)) != 0)
> ++		    (r = sshbuf_put_bignum2(m, p)) != 0 ||
> ++		    (r = sshbuf_put_bignum2(m, g)) != 0)
> + 			fatal("%s: buffer error: %s", __func__, ssh_err(r));
> +
> + 		DH_free(dh);
> +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
> +
> +diff --git a/regress/unittests/sshkey/test_file.c b/regress/unittests/sshkey/test_file.c
> +index 99b7e21..3262e87 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");
> +@@ -60,9 +61,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);
> +@@ -151,9 +154,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 72367bd..1d1af0f 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_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();
> +
> +@@ -207,8 +204,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();
> +
> +@@ -234,9 +229,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();
> +@@ -245,8 +237,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();
> +@@ -285,18 +275,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
> +@@ -323,9 +308,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");
> +@@ -339,8 +321,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/ssh-dss.c b/ssh-dss.c
> +index 9f832ee..ba69b76 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 ((b = sshbuf_new()) == NULL) {
> + 		ret = SSH_ERR_ALLOC_FAIL;
> +@@ -123,6 +125,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 ||
> +@@ -155,16 +158,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,
> +@@ -185,6 +191,8 @@ ssh_dss_verify(const struct sshkey *key,
> +
> +  out:
> + 	explicit_bzero(digest, sizeof(digest));
> ++	BN_free(r);
> ++	BN_free(s);
> + 	DSA_SIG_free(sig);
> + 	sshbuf_free(b);
> + 	free(ktype);
> +diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c
> +index 3d3b78d..18ac03b 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)
> +@@ -118,6 +120,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 ||
> +@@ -146,15 +149,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;
> +@@ -179,6 +190,8 @@ ssh_ecdsa_verify(const struct sshkey *key,
> + 	explicit_bzero(digest, sizeof(digest));
> + 	sshbuf_free(sigbuf);
> + 	sshbuf_free(b);
> ++	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 22860ad..ed1b4df 100644
> +--- a/ssh-keygen.c
> ++++ b/ssh-keygen.c
> +@@ -493,40 +493,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 = ssh_rsa_generate_additional_parameters(key, 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 = ssh_rsa_generate_additional_parameters(key)) != 0)
> +-			fatal("generate RSA parameters failed: %s", ssh_err(r));
> + 		break;
> + 	}
> + 	rlen = sshbuf_len(b);
> +@@ -634,7 +661,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");
> +@@ -658,7 +685,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;
> +@@ -1785,6 +1812,7 @@ do_ca_sign(struct passwd *pw, int argc, char **argv)
> + #ifdef ENABLE_PKCS11
> + 	pkcs11_terminate();
> + #endif
> ++	free(ca);
> + 	exit(0);
> + }
> +
> +diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c
> +index 028b272..47d964f 100644
> +--- a/ssh-pkcs11-client.c
> ++++ b/ssh-pkcs11-client.c
> +@@ -156,12 +156,16 @@ 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());
> ++		if (helper_rsa == NULL)
> ++			error("RSA_meth_dup failed");
> ++		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 65a7b58..fb2aed0 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;
> + };
> +@@ -183,6 +183,7 @@ pkcs11_rsa_finish(RSA *rsa)
> + 		if (k11->provider)
> + 			pkcs11_provider_unref(k11->provider);
> + 		free(k11->keyid);
> ++		RSA_meth_free(k11->rsa_method);
> + 		free(k11);
> + 	}
> + 	return (rv);
> +@@ -326,13 +327,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 +469,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 +522,18 @@ 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_n == NULL || rsa_e == NULL)
> ++					error("BN_bin2bn failed");
> ++				if (RSA_set0_key(rsa, rsa_n, rsa_e, NULL) == 0)
> ++					error("RSA_set0_key failed");
> ++
> + 			}
> + 		} else {
> + 			cp = attribs[2].pValue;
> +@@ -525,16 +543,19 @@ 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");
> + 			}
> + 			X509_free(x509);
> + 		}
> +-		if (rsa && rsa->n && rsa->e &&
> ++
> ++		if (rsa)
> ++			RSA_get0_key(rsa, &n, &e, NULL);
> ++		if (rsa && n && e &&
> + 		    pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0) {
> + 			if ((key = sshkey_new(KEY_UNSPEC)) == NULL)
> + 				fatal("sshkey_new failed");
> +diff --git a/ssh-rsa.c b/ssh-rsa.c
> +index 1756315..496e61c 100644
> +--- a/ssh-rsa.c
> ++++ b/ssh-rsa.c
> +@@ -104,38 +104,50 @@ rsa_hash_alg_nid(int type)
> + }
> +
> + int
> +-ssh_rsa_generate_additional_parameters(struct sshkey *key)
> ++ssh_rsa_generate_additional_parameters(struct sshkey *key, BIGNUM *iqmp)
> + {
> + 	BIGNUM *aux = NULL;
> + 	BN_CTX *ctx = NULL;
> +-	BIGNUM d;
> ++	BIGNUM *d = NULL;
> + 	int r;
> ++	const BIGNUM *p, *q, *rsa_d;
> ++	BIGNUM *dmp1 = NULL, *dmq1 = NULL;
> +
> + 	if (key == NULL || key->rsa == NULL ||
> + 	    sshkey_type_plain(key->type) != KEY_RSA)
> + 		return SSH_ERR_INVALID_ARGUMENT;
> +
> +-	if ((ctx = BN_CTX_new()) == NULL)
> +-		return SSH_ERR_ALLOC_FAIL;
> +-	if ((aux = BN_new()) == NULL) {
> ++	RSA_get0_factors(key->rsa, &p, &q);
> ++	RSA_get0_key(key->rsa, NULL, NULL, &rsa_d);
> ++
> ++	if ((ctx = BN_CTX_new()) == NULL ||
> ++	    (aux = BN_new()) == NULL ||
> ++	    (d = BN_new()) == NULL ||
> ++	    (dmp1 = BN_new()) == NULL ||
> ++	    (dmq1 = BN_new()) == NULL) {
> + 		r = SSH_ERR_ALLOC_FAIL;
> + 		goto out;
> + 	}
> + 	BN_set_flags(aux, BN_FLG_CONSTTIME);
> +
> +-	BN_init(&d);
> +-	BN_with_flags(&d, key->rsa->d, BN_FLG_CONSTTIME);
> ++	BN_with_flags(d, rsa_d, BN_FLG_CONSTTIME);
> +
> +-	if ((BN_sub(aux, key->rsa->q, BN_value_one()) == 0) ||
> +-	    (BN_mod(key->rsa->dmq1, &d, aux, ctx) == 0) ||
> +-	    (BN_sub(aux, key->rsa->p, BN_value_one()) == 0) ||
> +-	    (BN_mod(key->rsa->dmp1, &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(key->rsa, dmp1, dmq1, iqmp) == 0)) {
> + 		r = SSH_ERR_LIBCRYPTO_ERROR;
> + 		goto out;
> + 	}
> ++	dmp1 = NULL;
> ++	dmq1 = NULL;
> + 	r = 0;
> +  out:
> ++	BN_free(d);
> + 	BN_clear_free(aux);
> ++	BN_clear_free(dmp1);
> ++	BN_clear_free(dmq1);
> + 	BN_CTX_free(ctx);
> + 	return r;
> + }
> +@@ -163,7 +175,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;
> +-	if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
> ++	if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE)
> + 		return SSH_ERR_KEY_LENGTH;
> + 	slen = RSA_size(key->rsa);
> + 	if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM)
> +@@ -235,7 +247,7 @@ ssh_rsa_verify(const struct sshkey *key,
> + 	    sshkey_type_plain(key->type) != KEY_RSA ||
> + 	    sig == NULL || siglen == 0)
> + 		return SSH_ERR_INVALID_ARGUMENT;
> +-	if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
> ++	if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE)
> + 		return SSH_ERR_KEY_LENGTH;
> +
> + 	if ((b = sshbuf_from(sig, siglen)) == NULL)
> +diff --git a/sshkey.c b/sshkey.c
> +index 72c08c7..a9c8e0c 100644
> +--- a/sshkey.c
> ++++ b/sshkey.c
> +@@ -292,10 +292,10 @@ sshkey_size(const struct sshkey *k)
> + #ifdef WITH_OPENSSL
> + 	case KEY_RSA:
> + 	case KEY_RSA_CERT:
> +-		return BN_num_bits(k->rsa->n);
> ++		return RSA_bits(k->rsa);
> + 	case KEY_DSA:
> + 	case KEY_DSA_CERT:
> +-		return BN_num_bits(k->dsa->p);
> ++		return DSA_bits(k->dsa);
> + 	case KEY_ECDSA:
> + 	case KEY_ECDSA_CERT:
> + 		return sshkey_curve_nid_to_bits(k->ecdsa_nid);
> +@@ -500,10 +500,7 @@ sshkey_new(int type)
> + #ifdef WITH_OPENSSL
> + 	case KEY_RSA:
> + 	case KEY_RSA_CERT:
> +-		if ((rsa = RSA_new()) == NULL ||
> +-		    (rsa->n = BN_new()) == NULL ||
> +-		    (rsa->e = BN_new()) == NULL) {
> +-			RSA_free(rsa);
> ++		if ((rsa = RSA_new()) == NULL) {
> + 			free(k);
> + 			return NULL;
> + 		}
> +@@ -511,12 +508,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) {
> +-			DSA_free(dsa);
> ++		if ((dsa = DSA_new()) == NULL) {
> + 			free(k);
> + 			return NULL;
> + 		}
> +@@ -557,21 +549,10 @@ sshkey_add_private(struct sshkey *k)
> + #ifdef WITH_OPENSSL
> + 	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 */
> +@@ -694,17 +675,31 @@ sshkey_equal_public(const struct sshkey *a, const struct sshkey *b)
> + 	switch (a->type) {
> + #ifdef WITH_OPENSSL
> + 	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:
> +@@ -790,15 +785,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:
> +@@ -811,13 +812,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:
> +@@ -1755,15 +1761,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
> +@@ -1785,13 +1808,22 @@ sshkey_from_private(const struct sshkey *k, struct sshkey **pkp)
> + 		break;
> + # endif /* OPENSSL_HAS_ECC */
> + 	case KEY_RSA:
> +-	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 */
> +@@ -2013,12 +2045,22 @@ 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;
> ++			}
> + 		}
> +-		if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
> ++		if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
> + 			ret = SSH_ERR_KEY_LENGTH;
> + 			goto out;
> + 		}
> +@@ -2038,12 +2080,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);
> +@@ -2388,26 +2452,53 @@ sshkey_demote(const struct sshkey *k, struct sshkey **dkp)
> + 		if ((ret = sshkey_cert_copy(k, pk)) != 0)
> + 			goto fail;
> + 		/* FALLTHROUGH */
> +-	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:
> +@@ -2557,12 +2648,17 @@ sshkey_certify_custom(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: {
> ++			const BIGNUM *p, *q, *g, *pub_key;
> ++
> ++			DSA_get0_pqg(k->dsa, &p, &q, &g);
> ++			DSA_get0_key(k->dsa, &pub_key, NULL);
> ++			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)
> ++				goto out;
> ++		}
> + 		break;
> + # ifdef OPENSSL_HAS_ECC
> + 	case KEY_ECDSA_CERT:
> +@@ -2574,10 +2670,15 @@ sshkey_certify_custom(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: {
> ++			const BIGNUM *e, *n;
> ++
> ++			RSA_get0_key(k->rsa, &n, &e, NULL);
> ++			if (e == NULL || n == NULL ||
> ++			    (ret = sshbuf_put_bignum2(cert, e)) != 0 ||
> ++			    (ret = sshbuf_put_bignum2(cert, n)) != 0)
> ++				goto out;
> ++		}
> + 		break;
> + #endif /* WITH_OPENSSL */
> + 	case KEY_ED25519_CERT:
> +@@ -2763,43 +2864,65 @@ sshkey_private_serialize_opt(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:
> +@@ -2913,18 +3036,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:
> +@@ -2983,29 +3139,89 @@ 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 = ssh_rsa_generate_additional_parameters(k)) != 0)
> +-			goto out;
> +-		if (BN_num_bits(k->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
> ++		{
> ++			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 = ssh_rsa_generate_additional_parameters(k, iqmp)) != 0) {
> ++				BN_free(iqmp);
> ++				goto out;
> ++			}
> ++		}
> ++		if (RSA_bits(k->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
> + 			r = SSH_ERR_KEY_LENGTH;
> + 			goto out;
> + 		}
> + 		break;
> +-	case KEY_RSA_CERT:
> +-		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 = ssh_rsa_generate_additional_parameters(k)) != 0)
> +-			goto out;
> +-		if (BN_num_bits(k->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
> ++	case KEY_RSA_CERT: {
> ++			BIGNUM *d, *iqmp, *p, *q;
> ++
> ++			/* N and E are already set so make sure we will not overwrite them */
> ++			d = BN_new();
> ++			iqmp = BN_new();
> ++			p = BN_new();
> ++			q = BN_new();
> ++
> ++			if (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, NULL, NULL, d) == 0)
> ++			        ? SSH_ERR_LIBCRYPTO_ERROR : 0)) != 0) {
> ++				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(p);
> ++				BN_free(q);
> ++				goto out;
> ++			}
> ++			if (ssh_rsa_generate_additional_parameters(k, iqmp) != 0) {
> ++			        r = SSH_ERR_LIBCRYPTO_ERROR;
> ++				free(iqmp);
> ++				goto out;
> ++			}
> ++		}
> ++		if (RSA_bits(k->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
> + 			r = SSH_ERR_KEY_LENGTH;
> + 			goto out;
> + 		}
> +@@ -3769,7 +3985,9 @@ translate_libcrypto_error(unsigned long pem_err)
> + 		switch (pem_reason) {
> + 		case EVP_R_BAD_DECRYPT:
> + 			return SSH_ERR_KEY_WRONG_PASSPHRASE;
> ++#ifdef EVP_R_BN_DECODE_ERROR
> + 		case EVP_R_BN_DECODE_ERROR:
> ++#endif
> + 		case EVP_R_DECODE_ERROR:
> + #ifdef EVP_R_PRIVATE_KEY_DECODE_ERROR
> + 		case EVP_R_PRIVATE_KEY_DECODE_ERROR:
> +@@ -3834,7 +4052,7 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
> + 		r = convert_libcrypto_error();
> + 		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;
> +@@ -3849,11 +4067,11 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
> + 			r = SSH_ERR_LIBCRYPTO_ERROR;
> + 			goto out;
> + 		}
> +-		if (BN_num_bits(prv->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
> ++		if (RSA_bits(prv->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
> + 			r = SSH_ERR_KEY_LENGTH;
> + 			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;
> +@@ -3865,7 +4083,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;
> +diff --git a/sshkey.h b/sshkey.h
> +index 9060b2e..adbd14a 100644
> +--- a/sshkey.h
> ++++ b/sshkey.h
> +@@ -218,7 +218,7 @@ int	sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
> +     const char *passphrase, struct sshkey **keyp, char **commentp);
> +
> + /* XXX should be internal, but used by ssh-keygen */
> +-int ssh_rsa_generate_additional_parameters(struct sshkey *);
> ++int ssh_rsa_generate_additional_parameters(struct sshkey *, BIGNUM *iqmp);
> +
> + /* stateful keys (e.g. XMSS) */
> + #ifdef NO_ATTRIBUTE_ON_PROTOTYPE_ARGS
> +--
> +2.7.4
> +
> diff --git a/meta/recipes-connectivity/openssh/openssh_7.8p1.bb b/meta/recipes-connectivity/openssh/openssh_7.8p1.bb
> index f4b295f..8b83929 100644
> --- a/meta/recipes-connectivity/openssh/openssh_7.8p1.bb
> +++ b/meta/recipes-connectivity/openssh/openssh_7.8p1.bb
> @@ -8,8 +8,7 @@ SECTION = "console/network"
>   LICENSE = "BSD"
>   LIC_FILES_CHKSUM = "file://LICENCE;md5=429658c6612f3a9b1293782366ab29d8"
>   
> -# openssl 1.1 patches are proposed at https://github.com/openssh/openssh-portable/pull/48
> -DEPENDS = "zlib openssl10"
> +DEPENDS = "zlib openssl"
>   DEPENDS += "${@bb.utils.contains('DISTRO_FEATURES', 'pam', 'libpam', '', d)}"
>   
>   SRC_URI = "http://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-${PV}.tar.gz \
> @@ -25,6 +24,7 @@ SRC_URI = "http://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-${PV}.tar
>              file://fix-potential-signed-overflow-in-pointer-arithmatic.patch \
>              file://sshd_check_keys \
>              file://add-test-support-for-busybox.patch \
> +           file://0001-build-support-openssl-1.1.0.patch \
>              "
>   
>   PAM_SRC_URI = "file://sshd"




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] openssh: build support openssl 1.1
  2018-09-11  8:59 [PATCH] openssh: build support openssl 1.1 Hongxu Jia
  2018-09-11  9:10 ` Hongxu Jia
@ 2018-09-11 10:39 ` Alexander Kanavin
  2018-09-11 15:18   ` Hongxu Jia
  1 sibling, 1 reply; 11+ messages in thread
From: Alexander Kanavin @ 2018-09-11 10:39 UTC (permalink / raw)
  To: Hongxu Jia, Richard Purdie; +Cc: Alexander Kanavin, OE-core

I'm afraid I have changed my mind, and I have to say no to this. It is
*not* a backport, it is a very large patch that nobody understands, it
will need to be rebased every time there is new openssh out, we cannot
rely on Fedora doing this, as they apply this patch on top of their
other patches. Meanwhile, upstream pull request has been stalled for a
very long time and just isn't going anywhere.

I would suggest you make openssh depend on libressl and find out why
it is working everywhere except arm64 - that's the only reason we
haven't done it yet.

Alex

2018-09-11 10:59 GMT+02:00 Hongxu Jia <hongxu.jia@windriver.com>:
> As commit `5ccf4a9 openssh: depend on openssl 1.0' suggested,
> take a patch from Fedora 29 to get openssl 1.1 support
>
> Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
> ---
>  .../openssh/0001-build-support-openssl-1.1.0.patch | 2502 ++++++++++++++++++++
>  meta/recipes-connectivity/openssh/openssh_7.8p1.bb |    4 +-
>  2 files changed, 2504 insertions(+), 2 deletions(-)
>  create mode 100644 meta/recipes-connectivity/openssh/openssh/0001-build-support-openssl-1.1.0.patch
>
> diff --git a/meta/recipes-connectivity/openssh/openssh/0001-build-support-openssl-1.1.0.patch b/meta/recipes-connectivity/openssh/openssh/0001-build-support-openssl-1.1.0.patch
> new file mode 100644
> index 0000000..24cb3e7
> --- /dev/null
> +++ b/meta/recipes-connectivity/openssh/openssh/0001-build-support-openssl-1.1.0.patch
> @@ -0,0 +1,2502 @@
> +From f0c0eabc6912fae1c8f3b856c1e80c561d7995eb Mon Sep 17 00:00:00 2001
> +From: Hongxu Jia <hongxu.jia@windriver.com>
> +Date: Tue, 11 Sep 2018 16:33:13 +0800
> +Subject: [PATCH] build support openssl-1.1.0
> +
> +Backport a patch from fedora 29 to support openssl-1.1.0
> +
> +Upstream-Status: Backport [https://src.fedoraproject.org/git/rpms/openssh.git]
> +
> +Signed-off-by: Hongxu Jia <hongxu.jia@windriver.com>
> +---
> + Makefile.in                            |   3 +-
> + auth-pam.c                             |   4 +
> + cipher.c                               |  14 +-
> + configure.ac                           |   1 +
> + dh.c                                   |  54 ++--
> + dh.h                                   |   2 +-
> + digest-openssl.c                       |  18 +-
> + includes.h                             |   1 +
> + kexdhc.c                               |  19 +-
> + kexdhs.c                               |  10 +-
> + kexgexc.c                              |  22 +-
> + kexgexs.c                              |  19 +-
> + libcrypto-compat.c                     | 428 ++++++++++++++++++++++++++
> + libcrypto-compat.h                     |  59 ++++
> + monitor.c                              |   7 +-
> + openbsd-compat/openssl-compat.c        |   7 +
> + regress/unittests/sshkey/test_file.c   |  17 +-
> + regress/unittests/sshkey/test_sshkey.c |  22 +-
> + ssh-dss.c                              |  24 +-
> + ssh-ecdsa.c                            |  23 +-
> + ssh-keygen.c                           |  94 ++++--
> + ssh-pkcs11-client.c                    |  14 +-
> + ssh-pkcs11.c                           |  49 ++-
> + ssh-rsa.c                              |  38 ++-
> + sshkey.c                               | 534 +++++++++++++++++++++++----------
> + sshkey.h                               |   2 +-
> + 26 files changed, 1160 insertions(+), 325 deletions(-)
> + create mode 100644 libcrypto-compat.c
> + create mode 100644 libcrypto-compat.h
> +
> +diff --git a/Makefile.in b/Makefile.in
> +index 2385c62..2232450 100644
> +--- a/Makefile.in
> ++++ b/Makefile.in
> +@@ -100,7 +100,8 @@ 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-misc.o
> ++      platform-pledge.o platform-tracing.o platform-misc.o \
> ++      libcrypto-compat.o
> +
> + SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
> +       sshconnect.o sshconnect2.o mux.o
> +diff --git a/auth-pam.c b/auth-pam.c
> +index 8c01383..d6423e9 100644
> +--- a/auth-pam.c
> ++++ b/auth-pam.c
> +@@ -128,6 +128,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 {
> +diff --git a/cipher.c b/cipher.c
> +index a72682a..9cd0ce7 100644
> +--- a/cipher.c
> ++++ b/cipher.c
> +@@ -281,7 +281,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;
> +@@ -299,10 +299,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;
> +-      }
> +       ret = 0;
> + #endif /* WITH_OPENSSL */
> +  out:
> +@@ -485,7 +481,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);
> + #endif
> +       return 0;
> + }
> +@@ -519,14 +515,14 @@ 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);
> + #endif
> +       return 0;
> + }
> +
> + #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/configure.ac b/configure.ac
> +index 83e5307..3346b80 100644
> +--- a/configure.ac
> ++++ b/configure.ac
> +@@ -2602,6 +2602,7 @@ if test "x$openssl" = "xyes" ; then
> +                                       AC_MSG_ERROR([OpenSSL >= 1.0.1 required (have "$ssl_library_ver")])
> +                                       ;;
> +                               100*)   ;; # 1.0.x
> ++                              101*)   ;; # 1.1.x is supported by this patch too
> +                               200*)   ;; # LibreSSL
> +                               *)
> +                                       AC_MSG_ERROR([OpenSSL >= 1.1.0 is not yet supported (have "$ssl_library_ver")])
> +diff --git a/dh.c b/dh.c
> +index ac8d5a0..760bfd8 100644
> +--- a/dh.c
> ++++ b/dh.c
> +@@ -216,14 +216,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;
> +       }
> +@@ -236,7 +237,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");
> +@@ -247,14 +249,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;
> +@@ -264,9 +266,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)
> +@@ -275,11 +279,11 @@ 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->priv_key = NULL;
> ++      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;
> +@@ -289,15 +293,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 = NULL, *g = NULL;
> ++
> ++      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;
> + }
> +
> + /*
> +@@ -312,8 +323,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 2770999..6570c5b 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 {
> +@@ -106,7 +106,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 *
> +@@ -118,8 +118,10 @@ 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) {
> ++              EVP_MD_CTX_free(ret->mdctx);
> +               free(ret);
> +               return NULL;
> +       }
> +@@ -132,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;
> + }
> +@@ -140,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;
> + }
> +@@ -161,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;
> +@@ -172,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 0fd7179..487b7a1 100644
> +--- a/includes.h
> ++++ b/includes.h
> +@@ -166,6 +166,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 9a9f1ea..bb9b67b 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;
> + }
> +
> +@@ -109,6 +116,7 @@ input_kex_dh(int type, u_int32_t seq, struct ssh *ssh)
> +       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;
> +@@ -168,6 +176,7 @@ input_kex_dh(int type, u_int32_t seq, struct ssh *ssh)
> + #endif
> +
> +       /* calc and verify H */
> ++      DH_get0_key(kex->dh, &pub_key, NULL);
> +       hashlen = sizeof(hash);
> +       if ((r = kex_dh_hash(
> +           kex->hash_alg,
> +@@ -176,7 +185,7 @@ input_kex_dh(int type, u_int32_t seq, struct ssh *ssh)
> +           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 5dfca0a..3bb8a5c 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;
> + }
> +
> +@@ -101,6 +105,7 @@ input_kex_dh_init(int type, u_int32_t seq, struct ssh *ssh)
> +       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) {
> +@@ -163,6 +168,7 @@ input_kex_dh_init(int type, u_int32_t seq, struct ssh *ssh)
> +               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,
> +@@ -171,7 +177,7 @@ input_kex_dh_init(int type, u_int32_t seq, struct ssh *ssh)
> +           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;
> +@@ -197,7 +203,7 @@ input_kex_dh_init(int type, u_int32_t seq, struct ssh *ssh)
> +       /* send server hostkey, DH pubkey 'f' and signed 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 762a9a3..3d07225 100644
> +--- a/kexgexc.c
> ++++ b/kexgexc.c
> +@@ -94,6 +94,7 @@ input_kex_dh_gex_group(int type, u_int32_t seq, struct ssh *ssh)
> +       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");
> +
> +@@ -118,16 +119,18 @@ input_kex_dh_gex_group(int type, u_int32_t seq, struct ssh *ssh)
> +       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);
> +@@ -136,6 +139,10 @@ input_kex_dh_gex_group(int type, u_int32_t seq, struct ssh *ssh)
> + out:
> +       BN_clear_free(p);
> +       BN_clear_free(g);
> ++      if (r != 0) {
> ++              DH_free(kex->dh);
> ++              kex->dh = NULL;
> ++      }
> +       return r;
> + }
> +
> +@@ -149,6 +156,7 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh)
> +       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) {
> +@@ -211,6 +219,8 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh)
> +               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,
> +@@ -220,8 +230,8 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh)
> +           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 f6983fd..581d8ae 100644
> +--- a/kexgexs.c
> ++++ b/kexgexs.c
> +@@ -72,6 +72,7 @@ input_kex_dh_gex_request(int type, u_int32_t seq, struct ssh *ssh)
> +       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 ||
> +@@ -101,9 +102,10 @@ input_kex_dh_gex_request(int type, u_int32_t seq, struct ssh *ssh)
> +               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;
> +
> +@@ -115,6 +117,10 @@ input_kex_dh_gex_request(int type, u_int32_t seq, struct ssh *ssh)
> +       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;
> + }
> +
> +@@ -129,6 +135,7 @@ input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh)
> +       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) {
> +@@ -191,6 +198,8 @@ input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh)
> +               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,
> +@@ -199,9 +208,9 @@ input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh)
> +           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;
> +@@ -227,7 +236,7 @@ input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh)
> +       /* send server hostkey, DH pubkey 'f' and signed 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..8203f6b
> +--- /dev/null
> ++++ b/libcrypto-compat.c
> +@@ -0,0 +1,428 @@
> ++/*
> ++ * 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_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 */
> ++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));
> ++}
> ++
> ++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) {
> ++        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..674e382
> +--- /dev/null
> ++++ b/libcrypto-compat.h
> +@@ -0,0 +1,59 @@
> ++#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_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
> ++#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);
> ++int DSA_bits(const DSA *d);
> ++
> ++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 d4b4b04..3d46f30 100644
> +--- a/monitor.c
> ++++ b/monitor.c
> +@@ -590,9 +590,12 @@ mm_answer_moduli(int sock, struct sshbuf *m)
> +               return (0);
> +       } else {
> +               /* Send first bignum */
> ++              const BIGNUM *p, *g;
> ++
> ++              DH_get0_pqg(dh, &p, NULL, &g);
> +               if ((r = sshbuf_put_u8(m, 1)) != 0 ||
> +-                  (r = sshbuf_put_bignum2(m, dh->p)) != 0 ||
> +-                  (r = sshbuf_put_bignum2(m, dh->g)) != 0)
> ++                  (r = sshbuf_put_bignum2(m, p)) != 0 ||
> ++                  (r = sshbuf_put_bignum2(m, g)) != 0)
> +                       fatal("%s: buffer error: %s", __func__, ssh_err(r));
> +
> +               DH_free(dh);
> +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
> +
> +diff --git a/regress/unittests/sshkey/test_file.c b/regress/unittests/sshkey/test_file.c
> +index 99b7e21..3262e87 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");
> +@@ -60,9 +61,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);
> +@@ -151,9 +154,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 72367bd..1d1af0f 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_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();
> +
> +@@ -207,8 +204,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();
> +
> +@@ -234,9 +229,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();
> +@@ -245,8 +237,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();
> +@@ -285,18 +275,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
> +@@ -323,9 +308,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");
> +@@ -339,8 +321,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/ssh-dss.c b/ssh-dss.c
> +index 9f832ee..ba69b76 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 ((b = sshbuf_new()) == NULL) {
> +               ret = SSH_ERR_ALLOC_FAIL;
> +@@ -123,6 +125,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 ||
> +@@ -155,16 +158,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,
> +@@ -185,6 +191,8 @@ ssh_dss_verify(const struct sshkey *key,
> +
> +  out:
> +       explicit_bzero(digest, sizeof(digest));
> ++      BN_free(r);
> ++      BN_free(s);
> +       DSA_SIG_free(sig);
> +       sshbuf_free(b);
> +       free(ktype);
> +diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c
> +index 3d3b78d..18ac03b 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)
> +@@ -118,6 +120,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 ||
> +@@ -146,15 +149,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;
> +@@ -179,6 +190,8 @@ ssh_ecdsa_verify(const struct sshkey *key,
> +       explicit_bzero(digest, sizeof(digest));
> +       sshbuf_free(sigbuf);
> +       sshbuf_free(b);
> ++      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 22860ad..ed1b4df 100644
> +--- a/ssh-keygen.c
> ++++ b/ssh-keygen.c
> +@@ -493,40 +493,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 = ssh_rsa_generate_additional_parameters(key, 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 = ssh_rsa_generate_additional_parameters(key)) != 0)
> +-                      fatal("generate RSA parameters failed: %s", ssh_err(r));
> +               break;
> +       }
> +       rlen = sshbuf_len(b);
> +@@ -634,7 +661,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");
> +@@ -658,7 +685,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;
> +@@ -1785,6 +1812,7 @@ do_ca_sign(struct passwd *pw, int argc, char **argv)
> + #ifdef ENABLE_PKCS11
> +       pkcs11_terminate();
> + #endif
> ++      free(ca);
> +       exit(0);
> + }
> +
> +diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c
> +index 028b272..47d964f 100644
> +--- a/ssh-pkcs11-client.c
> ++++ b/ssh-pkcs11-client.c
> +@@ -156,12 +156,16 @@ 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());
> ++              if (helper_rsa == NULL)
> ++                      error("RSA_meth_dup failed");
> ++              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 65a7b58..fb2aed0 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;
> + };
> +@@ -183,6 +183,7 @@ pkcs11_rsa_finish(RSA *rsa)
> +               if (k11->provider)
> +                       pkcs11_provider_unref(k11->provider);
> +               free(k11->keyid);
> ++              RSA_meth_free(k11->rsa_method);
> +               free(k11);
> +       }
> +       return (rv);
> +@@ -326,13 +327,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 +469,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 +522,18 @@ 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_n == NULL || rsa_e == NULL)
> ++                                      error("BN_bin2bn failed");
> ++                              if (RSA_set0_key(rsa, rsa_n, rsa_e, NULL) == 0)
> ++                                      error("RSA_set0_key failed");
> ++
> +                       }
> +               } else {
> +                       cp = attribs[2].pValue;
> +@@ -525,16 +543,19 @@ 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");
> +                       }
> +                       X509_free(x509);
> +               }
> +-              if (rsa && rsa->n && rsa->e &&
> ++
> ++              if (rsa)
> ++                      RSA_get0_key(rsa, &n, &e, NULL);
> ++              if (rsa && n && e &&
> +                   pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0) {
> +                       if ((key = sshkey_new(KEY_UNSPEC)) == NULL)
> +                               fatal("sshkey_new failed");
> +diff --git a/ssh-rsa.c b/ssh-rsa.c
> +index 1756315..496e61c 100644
> +--- a/ssh-rsa.c
> ++++ b/ssh-rsa.c
> +@@ -104,38 +104,50 @@ rsa_hash_alg_nid(int type)
> + }
> +
> + int
> +-ssh_rsa_generate_additional_parameters(struct sshkey *key)
> ++ssh_rsa_generate_additional_parameters(struct sshkey *key, BIGNUM *iqmp)
> + {
> +       BIGNUM *aux = NULL;
> +       BN_CTX *ctx = NULL;
> +-      BIGNUM d;
> ++      BIGNUM *d = NULL;
> +       int r;
> ++      const BIGNUM *p, *q, *rsa_d;
> ++      BIGNUM *dmp1 = NULL, *dmq1 = NULL;
> +
> +       if (key == NULL || key->rsa == NULL ||
> +           sshkey_type_plain(key->type) != KEY_RSA)
> +               return SSH_ERR_INVALID_ARGUMENT;
> +
> +-      if ((ctx = BN_CTX_new()) == NULL)
> +-              return SSH_ERR_ALLOC_FAIL;
> +-      if ((aux = BN_new()) == NULL) {
> ++      RSA_get0_factors(key->rsa, &p, &q);
> ++      RSA_get0_key(key->rsa, NULL, NULL, &rsa_d);
> ++
> ++      if ((ctx = BN_CTX_new()) == NULL ||
> ++          (aux = BN_new()) == NULL ||
> ++          (d = BN_new()) == NULL ||
> ++          (dmp1 = BN_new()) == NULL ||
> ++          (dmq1 = BN_new()) == NULL) {
> +               r = SSH_ERR_ALLOC_FAIL;
> +               goto out;
> +       }
> +       BN_set_flags(aux, BN_FLG_CONSTTIME);
> +
> +-      BN_init(&d);
> +-      BN_with_flags(&d, key->rsa->d, BN_FLG_CONSTTIME);
> ++      BN_with_flags(d, rsa_d, BN_FLG_CONSTTIME);
> +
> +-      if ((BN_sub(aux, key->rsa->q, BN_value_one()) == 0) ||
> +-          (BN_mod(key->rsa->dmq1, &d, aux, ctx) == 0) ||
> +-          (BN_sub(aux, key->rsa->p, BN_value_one()) == 0) ||
> +-          (BN_mod(key->rsa->dmp1, &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(key->rsa, dmp1, dmq1, iqmp) == 0)) {
> +               r = SSH_ERR_LIBCRYPTO_ERROR;
> +               goto out;
> +       }
> ++      dmp1 = NULL;
> ++      dmq1 = NULL;
> +       r = 0;
> +  out:
> ++      BN_free(d);
> +       BN_clear_free(aux);
> ++      BN_clear_free(dmp1);
> ++      BN_clear_free(dmq1);
> +       BN_CTX_free(ctx);
> +       return r;
> + }
> +@@ -163,7 +175,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;
> +-      if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
> ++      if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE)
> +               return SSH_ERR_KEY_LENGTH;
> +       slen = RSA_size(key->rsa);
> +       if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM)
> +@@ -235,7 +247,7 @@ ssh_rsa_verify(const struct sshkey *key,
> +           sshkey_type_plain(key->type) != KEY_RSA ||
> +           sig == NULL || siglen == 0)
> +               return SSH_ERR_INVALID_ARGUMENT;
> +-      if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
> ++      if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE)
> +               return SSH_ERR_KEY_LENGTH;
> +
> +       if ((b = sshbuf_from(sig, siglen)) == NULL)
> +diff --git a/sshkey.c b/sshkey.c
> +index 72c08c7..a9c8e0c 100644
> +--- a/sshkey.c
> ++++ b/sshkey.c
> +@@ -292,10 +292,10 @@ sshkey_size(const struct sshkey *k)
> + #ifdef WITH_OPENSSL
> +       case KEY_RSA:
> +       case KEY_RSA_CERT:
> +-              return BN_num_bits(k->rsa->n);
> ++              return RSA_bits(k->rsa);
> +       case KEY_DSA:
> +       case KEY_DSA_CERT:
> +-              return BN_num_bits(k->dsa->p);
> ++              return DSA_bits(k->dsa);
> +       case KEY_ECDSA:
> +       case KEY_ECDSA_CERT:
> +               return sshkey_curve_nid_to_bits(k->ecdsa_nid);
> +@@ -500,10 +500,7 @@ sshkey_new(int type)
> + #ifdef WITH_OPENSSL
> +       case KEY_RSA:
> +       case KEY_RSA_CERT:
> +-              if ((rsa = RSA_new()) == NULL ||
> +-                  (rsa->n = BN_new()) == NULL ||
> +-                  (rsa->e = BN_new()) == NULL) {
> +-                      RSA_free(rsa);
> ++              if ((rsa = RSA_new()) == NULL) {
> +                       free(k);
> +                       return NULL;
> +               }
> +@@ -511,12 +508,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) {
> +-                      DSA_free(dsa);
> ++              if ((dsa = DSA_new()) == NULL) {
> +                       free(k);
> +                       return NULL;
> +               }
> +@@ -557,21 +549,10 @@ sshkey_add_private(struct sshkey *k)
> + #ifdef WITH_OPENSSL
> +       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 */
> +@@ -694,17 +675,31 @@ sshkey_equal_public(const struct sshkey *a, const struct sshkey *b)
> +       switch (a->type) {
> + #ifdef WITH_OPENSSL
> +       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:
> +@@ -790,15 +785,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:
> +@@ -811,13 +812,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:
> +@@ -1755,15 +1761,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
> +@@ -1785,13 +1808,22 @@ sshkey_from_private(const struct sshkey *k, struct sshkey **pkp)
> +               break;
> + # endif /* OPENSSL_HAS_ECC */
> +       case KEY_RSA:
> +-      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 */
> +@@ -2013,12 +2045,22 @@ 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;
> ++                      }
> +               }
> +-              if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
> ++              if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
> +                       ret = SSH_ERR_KEY_LENGTH;
> +                       goto out;
> +               }
> +@@ -2038,12 +2080,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);
> +@@ -2388,26 +2452,53 @@ sshkey_demote(const struct sshkey *k, struct sshkey **dkp)
> +               if ((ret = sshkey_cert_copy(k, pk)) != 0)
> +                       goto fail;
> +               /* FALLTHROUGH */
> +-      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:
> +@@ -2557,12 +2648,17 @@ sshkey_certify_custom(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: {
> ++                      const BIGNUM *p, *q, *g, *pub_key;
> ++
> ++                      DSA_get0_pqg(k->dsa, &p, &q, &g);
> ++                      DSA_get0_key(k->dsa, &pub_key, NULL);
> ++                      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)
> ++                              goto out;
> ++              }
> +               break;
> + # ifdef OPENSSL_HAS_ECC
> +       case KEY_ECDSA_CERT:
> +@@ -2574,10 +2670,15 @@ sshkey_certify_custom(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: {
> ++                      const BIGNUM *e, *n;
> ++
> ++                      RSA_get0_key(k->rsa, &n, &e, NULL);
> ++                      if (e == NULL || n == NULL ||
> ++                          (ret = sshbuf_put_bignum2(cert, e)) != 0 ||
> ++                          (ret = sshbuf_put_bignum2(cert, n)) != 0)
> ++                              goto out;
> ++              }
> +               break;
> + #endif /* WITH_OPENSSL */
> +       case KEY_ED25519_CERT:
> +@@ -2763,43 +2864,65 @@ sshkey_private_serialize_opt(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:
> +@@ -2913,18 +3036,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:
> +@@ -2983,29 +3139,89 @@ 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 = ssh_rsa_generate_additional_parameters(k)) != 0)
> +-                      goto out;
> +-              if (BN_num_bits(k->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
> ++              {
> ++                      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 = ssh_rsa_generate_additional_parameters(k, iqmp)) != 0) {
> ++                              BN_free(iqmp);
> ++                              goto out;
> ++                      }
> ++              }
> ++              if (RSA_bits(k->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
> +                       r = SSH_ERR_KEY_LENGTH;
> +                       goto out;
> +               }
> +               break;
> +-      case KEY_RSA_CERT:
> +-              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 = ssh_rsa_generate_additional_parameters(k)) != 0)
> +-                      goto out;
> +-              if (BN_num_bits(k->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
> ++      case KEY_RSA_CERT: {
> ++                      BIGNUM *d, *iqmp, *p, *q;
> ++
> ++                      /* N and E are already set so make sure we will not overwrite them */
> ++                      d = BN_new();
> ++                      iqmp = BN_new();
> ++                      p = BN_new();
> ++                      q = BN_new();
> ++
> ++                      if (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, NULL, NULL, d) == 0)
> ++                              ? SSH_ERR_LIBCRYPTO_ERROR : 0)) != 0) {
> ++                              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(p);
> ++                              BN_free(q);
> ++                              goto out;
> ++                      }
> ++                      if (ssh_rsa_generate_additional_parameters(k, iqmp) != 0) {
> ++                              r = SSH_ERR_LIBCRYPTO_ERROR;
> ++                              free(iqmp);
> ++                              goto out;
> ++                      }
> ++              }
> ++              if (RSA_bits(k->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
> +                       r = SSH_ERR_KEY_LENGTH;
> +                       goto out;
> +               }
> +@@ -3769,7 +3985,9 @@ translate_libcrypto_error(unsigned long pem_err)
> +               switch (pem_reason) {
> +               case EVP_R_BAD_DECRYPT:
> +                       return SSH_ERR_KEY_WRONG_PASSPHRASE;
> ++#ifdef EVP_R_BN_DECODE_ERROR
> +               case EVP_R_BN_DECODE_ERROR:
> ++#endif
> +               case EVP_R_DECODE_ERROR:
> + #ifdef EVP_R_PRIVATE_KEY_DECODE_ERROR
> +               case EVP_R_PRIVATE_KEY_DECODE_ERROR:
> +@@ -3834,7 +4052,7 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
> +               r = convert_libcrypto_error();
> +               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;
> +@@ -3849,11 +4067,11 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
> +                       r = SSH_ERR_LIBCRYPTO_ERROR;
> +                       goto out;
> +               }
> +-              if (BN_num_bits(prv->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
> ++              if (RSA_bits(prv->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) {
> +                       r = SSH_ERR_KEY_LENGTH;
> +                       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;
> +@@ -3865,7 +4083,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;
> +diff --git a/sshkey.h b/sshkey.h
> +index 9060b2e..adbd14a 100644
> +--- a/sshkey.h
> ++++ b/sshkey.h
> +@@ -218,7 +218,7 @@ int        sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
> +     const char *passphrase, struct sshkey **keyp, char **commentp);
> +
> + /* XXX should be internal, but used by ssh-keygen */
> +-int ssh_rsa_generate_additional_parameters(struct sshkey *);
> ++int ssh_rsa_generate_additional_parameters(struct sshkey *, BIGNUM *iqmp);
> +
> + /* stateful keys (e.g. XMSS) */
> + #ifdef NO_ATTRIBUTE_ON_PROTOTYPE_ARGS
> +--
> +2.7.4
> +
> diff --git a/meta/recipes-connectivity/openssh/openssh_7.8p1.bb b/meta/recipes-connectivity/openssh/openssh_7.8p1.bb
> index f4b295f..8b83929 100644
> --- a/meta/recipes-connectivity/openssh/openssh_7.8p1.bb
> +++ b/meta/recipes-connectivity/openssh/openssh_7.8p1.bb
> @@ -8,8 +8,7 @@ SECTION = "console/network"
>  LICENSE = "BSD"
>  LIC_FILES_CHKSUM = "file://LICENCE;md5=429658c6612f3a9b1293782366ab29d8"
>
> -# openssl 1.1 patches are proposed at https://github.com/openssh/openssh-portable/pull/48
> -DEPENDS = "zlib openssl10"
> +DEPENDS = "zlib openssl"
>  DEPENDS += "${@bb.utils.contains('DISTRO_FEATURES', 'pam', 'libpam', '', d)}"
>
>  SRC_URI = "http://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-${PV}.tar.gz \
> @@ -25,6 +24,7 @@ SRC_URI = "http://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-${PV}.tar
>             file://fix-potential-signed-overflow-in-pointer-arithmatic.patch \
>             file://sshd_check_keys \
>             file://add-test-support-for-busybox.patch \
> +           file://0001-build-support-openssl-1.1.0.patch \
>             "
>
>  PAM_SRC_URI = "file://sshd"
> --
> 2.7.4
>
> --
> _______________________________________________
> Openembedded-core mailing list
> Openembedded-core@lists.openembedded.org
> http://lists.openembedded.org/mailman/listinfo/openembedded-core


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] openssh: build support openssl 1.1
  2018-09-11 10:39 ` Alexander Kanavin
@ 2018-09-11 15:18   ` Hongxu Jia
  2018-09-12  9:26     ` Alexander Kanavin
  0 siblings, 1 reply; 11+ messages in thread
From: Hongxu Jia @ 2018-09-11 15:18 UTC (permalink / raw)
  To: Alexander Kanavin, Richard Purdie; +Cc: Alexander Kanavin, OE-core

[-- Attachment #1: Type: text/plain, Size: 2194 bytes --]

On 2018年09月11日 18:39, Alexander Kanavin wrote:
> I'm afraid I have changed my mind, and I have to say no to this. It is
> *not*  a backport, it is a very large patch that nobody understands, it
> will need to be rebased every time there is new openssh out, we cannot
> rely on Fedora doing this, as they apply this patch on top of their
> other patches. Meanwhile, upstream pull request has been stalled for a
> very long time and just isn't going anywhere.
>
> I would suggest you make openssh depend on libressl and find out why
> it is working everywhere except arm64 - that's the only reason we
> haven't done it yet.

Use openssh depends on libressl could not fix the issue, which also 
conflicts
with openssl in the meta-selinux example (they provides the same 
headers/libraries)

The root cause is since rename libssl (1.0) -> libssl10, and drop 
PRFERRED_VERSION,
there are multiple recipes provide ssl (openssl, openssl10, libressl) 
with different name

BTW, even though openssh depends `openssl10',  the `openssl' is installed
to rootfs. It breaks DEPEND/RDEPENDS principle

[local.conf]
IMAGE_INSTALL_append = " openssh"
[local.conf]

$ bitbake core-image-minimal

[log.do_rootfs]
   Installing       : openssl-1.1.1~pre9-r0.core2_64
[log.do_rootfs]

The recipe depends on openssl10, but openssl10 will not be installed.

Here are my suggestions

1: Replace dependence openssl10  -> openssl, such as this fix, and drop 
recipe openssl10 finally;
     1 (openssh) in oe-core, 3 (umip, ipsec-tools, mailx) in oe, 3 
(openssl-tpm-engine,
     tpm-tools, trousers) in meta-secure-core

Or 2: Unify openssl,openssl10 and libressl to provide one ssl,
         we could add PROVIDER = 'virtual/ssl' to above recipe, any recipe
         depends on `openssl' will be replced with `virtual/ssl', the recipe
        depends on `openssl10' will not be changed.

        Set PREFERRED_PROVIDER_virtual//ssl = "openssl | openssl10 | 
libressl" in conf

Or 3: Revert previously patch, rename recipe openssl10 -> openssl 1.0, 
and set
       PREFERRED_VERSION


//Hongxu

>
> Alex



[-- Attachment #2: Type: text/html, Size: 3187 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] openssh: build support openssl 1.1
  2018-09-11 15:18   ` Hongxu Jia
@ 2018-09-12  9:26     ` Alexander Kanavin
  2018-09-12  9:59       ` Hongxu Jia
  0 siblings, 1 reply; 11+ messages in thread
From: Alexander Kanavin @ 2018-09-12  9:26 UTC (permalink / raw)
  To: Hongxu Jia; +Cc: OE-core

2018-09-11 17:18 GMT+02:00 Hongxu Jia <hongxu.jia@windriver.com>:
> Here are my suggestions
>
> 1: Replace dependence openssl10  -> openssl, such as this fix, and drop
> recipe openssl10 finally;
>     1 (openssh) in oe-core, 3 (umip, ipsec-tools, mailx) in oe, 3
> (openssl-tpm-engine,
>     tpm-tools, trousers) in meta-secure-core
>
> Or 2: Unify openssl,openssl10 and libressl to provide one ssl,
>         we could add PROVIDER = 'virtual/ssl' to above recipe, any recipe
>         depends on `openssl' will be replced with `virtual/ssl', the recipe
>        depends on `openssl10' will not be changed.
>
>        Set PREFERRED_PROVIDER_virtual//ssl = "openssl | openssl10 |
> libressl" in conf
>
> Or 3: Revert previously patch, rename recipe openssl10 -> openssl 1.0, and
> set
>       PREFERRED_VERSION

Option 1 creates a maintainability issue for openssh. You add the big
patch that no one understands, then someone else has to rebase it
later. Of course over time we need to move everything to 1.1 across
all layers, but at the moment it is not feasible for openssh
specifically.

Option 2 implies that openssl, openssl10 and libressl are all drop-in
replacements for each other which is not true. openssl 1.1 API is
significantly different, and choosing one or the other option will
cause significant build breakage. Especially as upstream components
begin to drop 1.0 support.

Option 3 has the same issue.

Can I suggest option 4? As openssh is already patched in meta-selinux,
and the problem is specific to that layer, you can add the 1.1 support
patch there, and replace the openssl10 dependency with openssl (1.1).
If, over time, that patch can be rebased to new versions of openssh
without too much trouble, and upstream still hasn't taken it, we can
re-consider adding it to oe-core.

Alex


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] openssh: build support openssl 1.1
  2018-09-12  9:26     ` Alexander Kanavin
@ 2018-09-12  9:59       ` Hongxu Jia
  2018-09-12 10:30         ` Alexander Kanavin
  0 siblings, 1 reply; 11+ messages in thread
From: Hongxu Jia @ 2018-09-12  9:59 UTC (permalink / raw)
  To: Alexander Kanavin, Richard Purdie; +Cc: lpd-cdc-core-dev, OE-core

On 2018年09月12日 17:26, Alexander Kanavin wrote:
> 2018-09-11 17:18 GMT+02:00 Hongxu Jia <hongxu.jia@windriver.com>:
>> Here are my suggestions
>>
>> 1: Replace dependence openssl10  -> openssl, such as this fix, and drop
>> recipe openssl10 finally;
>>      1 (openssh) in oe-core, 3 (umip, ipsec-tools, mailx) in oe, 3
>> (openssl-tpm-engine,
>>      tpm-tools, trousers) in meta-secure-core
>>
>> Or 2: Unify openssl,openssl10 and libressl to provide one ssl,
>>          we could add PROVIDER = 'virtual/ssl' to above recipe, any recipe
>>          depends on `openssl' will be replced with `virtual/ssl', the recipe
>>         depends on `openssl10' will not be changed.
>>
>>         Set PREFERRED_PROVIDER_virtual//ssl = "openssl | openssl10 |
>> libressl" in conf
>>
>> Or 3: Revert previously patch, rename recipe openssl10 -> openssl 1.0, and
>> set
>>        PREFERRED_VERSION
> Option 1 creates a maintainability issue for openssh. You add the big
> patch that no one understands, then someone else has to rebase it
> later. Of course over time we need to move everything to 1.1 across
> all layers, but at the moment it is not feasible for openssh
> specifically.

It's a long term target, we should try to push upstream to accept
openssl 1.1, such as split one patch to multiple sub patches step
by step, make it more reviewable,  not only openssh, ideally any
recipe depends on 1.0 should be turned to 1.1

> Option 2 implies that openssl, openssl10 and libressl are all drop-in
> replacements for each other which is not true. openssl 1.1 API is
> significantly different, and choosing one or the other option will
> cause significant build breakage. Especially as upstream components
> begin to drop 1.0 support.

Currently, use openssl10 as the standalone recipe to provide openssl,
everything works well in oe-core + oe.

As I mention before, there is still a issue at run time image. Even though
openssh depends on `openssl10',  but the `openssl' is installed at do_rootfs

It breaks DEPEND/RDEPENDS principle

[local.conf]
IMAGE_INSTALL_append = " openssh"
[local.conf]

$ bitbake core-image-minimal

[log.do_rootfs]
   Installing       : openssl-1.1.1~pre9-r0.core2_64
[log.do_rootfs]

The recipe depends on openssl10, but openssl10 will not be installed.
BTW, Is pre9 1.1.1 openssl a stable release?

> Option 3 has the same issue.
>
> Can I suggest option 4? As openssh is already patched in meta-selinux,
> and the problem is specific to that layer, you can add the 1.1 support
> patch there, and replace the openssl10 dependency with openssl (1.1).
> If, over time, that patch can be rebased to new versions of openssh
> without too much trouble, and upstream still hasn't taken it, we can
> re-consider adding it to oe-core.

The meta-selinux only exposes the issue, any recipe depends on
openssl10 and indirect depends openssl will trigger the conflict.

A -> openssl10
A -> B
B -> openssl

In oe-core, the most common situation is any recipe depends on
openssl10 and python2/3, will have the problem

Only openssh patched to meta-selinux is not enough, there are  3
(umip, ipsec-tools, mailx) in oe, 3 (openssl-tpm-engine, tpm-tools,
trousers) in meta-secure-core required to be patched. I think it is
not acceptable for meta-selinux maintainer.

Hi RP,

What about your suggestions?

//Hongxu

> Alex




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] openssh: build support openssl 1.1
  2018-09-12  9:59       ` Hongxu Jia
@ 2018-09-12 10:30         ` Alexander Kanavin
  2018-09-12 14:22           ` Khem Raj
  2018-09-13  1:13           ` Andre McCurdy
  0 siblings, 2 replies; 11+ messages in thread
From: Alexander Kanavin @ 2018-09-12 10:30 UTC (permalink / raw)
  To: Hongxu Jia; +Cc: lpd-cdc-core-dev, OE-core

2018-09-12 11:59 GMT+02:00 Hongxu Jia <hongxu.jia@windriver.com>:
> It's a long term target, we should try to push upstream to accept
> openssl 1.1, such as split one patch to multiple sub patches step
> by step, make it more reviewable,  not only openssh, ideally any
> recipe depends on 1.0 should be turned to 1.1

The pull request has been open for two years now:
https://github.com/openssh/openssh-portable/pull/48

I don't think you'll get far with the pushing the upstream. They are
happy using libressl on *BSD, and don't particularly care about Linux
or openssl.

> Currently, use openssl10 as the standalone recipe to provide openssl,
> everything works well in oe-core + oe.

openssl10 upstream support ends at the end of 2019. We can no longer
afford to do nothing about the situation.

> As I mention before, there is still a issue at run time image. Even though
> openssh depends on `openssl10',  but the `openssl' is installed at do_rootfs
>
> It breaks DEPEND/RDEPENDS principle
>
> [local.conf]
> IMAGE_INSTALL_append = " openssh"
> [local.conf]
>
> $ bitbake core-image-minimal
>
> [log.do_rootfs]
>   Installing       : openssl-1.1.1~pre9-r0.core2_64
> [log.do_rootfs]
>
> The recipe depends on openssl10, but openssl10 will not be installed.

There is a library package split, so you should be seeing libcrypto10
or libssl10 installed as well. Can you provide the full log please?

> BTW, Is pre9 1.1.1 openssl a stable release?

Final 1.1.1 has been released yesterday, so I'll send a patch in a moment.

Alex


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] openssh: build support openssl 1.1
  2018-09-12 10:30         ` Alexander Kanavin
@ 2018-09-12 14:22           ` Khem Raj
  2018-09-13  1:13           ` Andre McCurdy
  1 sibling, 0 replies; 11+ messages in thread
From: Khem Raj @ 2018-09-12 14:22 UTC (permalink / raw)
  To: Alexander Kanavin
  Cc: +lpd-cdc-core-dev, Patches and discussions about the oe-core layer

On Wed, Sep 12, 2018 at 3:30 AM Alexander Kanavin
<alex.kanavin@gmail.com> wrote:
>
> 2018-09-12 11:59 GMT+02:00 Hongxu Jia <hongxu.jia@windriver.com>:
> > It's a long term target, we should try to push upstream to accept
> > openssl 1.1, such as split one patch to multiple sub patches step
> > by step, make it more reviewable,  not only openssh, ideally any
> > recipe depends on 1.0 should be turned to 1.1
>
> The pull request has been open for two years now:
> https://github.com/openssh/openssh-portable/pull/48
>

I agree we should not take the patch if its large and has no momentum upstream.

> I don't think you'll get far with the pushing the upstream. They are
> happy using libressl on *BSD, and don't particularly care about Linux
> or openssl.
>
> > Currently, use openssl10 as the standalone recipe to provide openssl,
> > everything works well in oe-core + oe.
>
> openssl10 upstream support ends at the end of 2019. We can no longer
> afford to do nothing about the situation.
>
> > As I mention before, there is still a issue at run time image. Even though
> > openssh depends on `openssl10',  but the `openssl' is installed at do_rootfs
> >
> > It breaks DEPEND/RDEPENDS principle
> >
> > [local.conf]
> > IMAGE_INSTALL_append = " openssh"
> > [local.conf]
> >
> > $ bitbake core-image-minimal
> >
> > [log.do_rootfs]
> >   Installing       : openssl-1.1.1~pre9-r0.core2_64
> > [log.do_rootfs]
> >
> > The recipe depends on openssl10, but openssl10 will not be installed.
>
> There is a library package split, so you should be seeing libcrypto10
> or libssl10 installed as well. Can you provide the full log please?
>
> > BTW, Is pre9 1.1.1 openssl a stable release?
>
> Final 1.1.1 has been released yesterday, so I'll send a patch in a moment.
>
> Alex


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] openssh: build support openssl 1.1
  2018-09-12 10:30         ` Alexander Kanavin
  2018-09-12 14:22           ` Khem Raj
@ 2018-09-13  1:13           ` Andre McCurdy
  2018-09-13 12:27             ` Alexander Kanavin
  1 sibling, 1 reply; 11+ messages in thread
From: Andre McCurdy @ 2018-09-13  1:13 UTC (permalink / raw)
  To: Alexander Kanavin; +Cc: lpd-cdc-core-dev, OE-core

On Wed, Sep 12, 2018 at 3:30 AM, Alexander Kanavin
<alex.kanavin@gmail.com> wrote:
> 2018-09-12 11:59 GMT+02:00 Hongxu Jia <hongxu.jia@windriver.com>:
>> It's a long term target, we should try to push upstream to accept
>> openssl 1.1, such as split one patch to multiple sub patches step
>> by step, make it more reviewable,  not only openssh, ideally any
>> recipe depends on 1.0 should be turned to 1.1
>
> The pull request has been open for two years now:
> https://github.com/openssh/openssh-portable/pull/48
>
> I don't think you'll get far with the pushing the upstream. They are
> happy using libressl on *BSD, and don't particularly care about Linux
> or openssl.
>
>> Currently, use openssl10 as the standalone recipe to provide openssl,
>> everything works well in oe-core + oe.
>
> openssl10 upstream support ends at the end of 2019. We can no longer
> afford to do nothing about the situation.
>
>> As I mention before, there is still a issue at run time image. Even though
>> openssh depends on `openssl10',  but the `openssl' is installed at do_rootfs
>>
>> It breaks DEPEND/RDEPENDS principle
>>
>> [local.conf]
>> IMAGE_INSTALL_append = " openssh"
>> [local.conf]
>>
>> $ bitbake core-image-minimal
>>
>> [log.do_rootfs]
>>   Installing       : openssl-1.1.1~pre9-r0.core2_64
>> [log.do_rootfs]
>>
>> The recipe depends on openssl10, but openssl10 will not be installed.
>
> There is a library package split, so you should be seeing libcrypto10
> or libssl10 installed as well. Can you provide the full log please?

It's deliberate that including openssl10 in an image will at least
cause openssl 1.1 to built as the openssl10 libcrypto depends on
openssl10-conf and that's now provided by the openssl-conf package
from openssl 1.1

So the expected outcome of adding openssh to a minimal image would be
for the image to include libcrypto10 and libssl10 from openssl10 and
openssl-conf from openssl 1.1. Is that what you see?

(As a potential cleanup, we should perhaps remove openssl10-conf and
have libcrypto10 RDEPEND directly on openssl-conf, to make it a little
clearer that we expect to use the openssl 1.1 config for all versions
of the openssl libs).

>> BTW, Is pre9 1.1.1 openssl a stable release?
>
> Final 1.1.1 has been released yesterday, so I'll send a patch in a moment.
>
> Alex
> --
> _______________________________________________
> Openembedded-core mailing list
> Openembedded-core@lists.openembedded.org
> http://lists.openembedded.org/mailman/listinfo/openembedded-core


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] openssh: build support openssl 1.1
  2018-09-13  1:13           ` Andre McCurdy
@ 2018-09-13 12:27             ` Alexander Kanavin
  2018-09-18 20:17               ` Randy MacLeod
  0 siblings, 1 reply; 11+ messages in thread
From: Alexander Kanavin @ 2018-09-13 12:27 UTC (permalink / raw)
  To: Andre McCurdy; +Cc: OE-core

2018-09-13 3:13 GMT+02:00 Andre McCurdy <armccurdy@gmail.com>:
> It's deliberate that including openssl10 in an image will at least
> cause openssl 1.1 to built as the openssl10 libcrypto depends on
> openssl10-conf and that's now provided by the openssl-conf package
> from openssl 1.1
>
> So the expected outcome of adding openssh to a minimal image would be
> for the image to include libcrypto10 and libssl10 from openssl10 and
> openssl-conf from openssl 1.1. Is that what you see?
>
> (As a potential cleanup, we should perhaps remove openssl10-conf and
> have libcrypto10 RDEPEND directly on openssl-conf, to make it a little
> clearer that we expect to use the openssl 1.1 config for all versions
> of the openssl libs).

Good news everyone! Upstream openssh has finally gave into user
pressure, and added 1.1 support in the master branch. So the issue is
moot; we just need to wait for them to tag a release (no backports
please).
https://github.com/openssh/openssh-portable/commits/master

This will make oe-core entirely free of openssl10 dependencies.

Alex


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] openssh: build support openssl 1.1
  2018-09-13 12:27             ` Alexander Kanavin
@ 2018-09-18 20:17               ` Randy MacLeod
  0 siblings, 0 replies; 11+ messages in thread
From: Randy MacLeod @ 2018-09-18 20:17 UTC (permalink / raw)
  To: Alexander Kanavin, Andre McCurdy; +Cc: OE-core

On 09/13/2018 08:27 AM, Alexander Kanavin wrote:
...
> 
> Good news everyone! Upstream openssh has finally gave into user
> pressure, and added 1.1 support in the master branch. So the issue is
> moot; we just need to wait for them to tag a release (no backports
> please).
> https://github.com/openssh/openssh-portable/commits/master
> 
> This will make oe-core entirely free of openssl10 dependencies.

Excellent.

Is there a planned release of openssh in the next day or
does someone need to switch to git or backport some/all of
the 36 post 7.8p1 commits for M3?

../Randy


$ git log --oneline V_7_8_P1...
cce8cbe0 Fix openssl-1.1 fallout for --without-openssl.
149519b9 add futex(2) syscall to seccomp sandbox
4488ae1a really add source for authopt_fuzz this time
9201784b remove accidentally checked-in authopt_fuzz binary
beb9e522 upstream:
            second try, deals properly with missing and private-only
6bc5a24a fuzzer harness for authorized_keys option parsing
6c8b82fc upstream: revert following; deals badly with agent keys
6da046f9 upstream: garbage-collect moribund ssh_new_private() API.
1f24ac5f upstream: Use consistent format in debug log for keys readied,
488c9325 upstream: Fix warnings caused by
             user_from_uid() and group_from_gid()
0aa1f230 allow SIGUSR1 as synonym for SIGINFO
d64e7852 add compat header
a3fd8074 upstream: missed a bit of openssl-1.0.x API in this unittest
86e0a9f3 upstream: use only openssl-1.1.x API here too
48f54b9d adapt -portable to OpenSSL 1.1x API
86112951 forgot to stage these test files in commit d70d061
482d23bc upstream: hold our collective noses and
             use the openssl-1.1.x API in
d70d0618 upstream: Include certs with multiple RSA signature variants in
f803b268 upstream: test revocation by explicit hash and by fingerprint
2de78bc7 upstream: s/sshkey_demote/sshkey_from_private/g
41c115a5 delete the correct thing; kexfuzz binary
f0fcd7e6 upstream: fix edit mistake; spotted by jmc@
4cc259ba upstream: add SSH_ALLOWED_CA_SIGALGS - the default list of
ba9e7883 upstream: add sshkey_check_cert_sigtype() that checks a
a70fd4ad upstream: add cert->signature_type field and
             keep it in sync with
357128ac upstream: Add "ssh -Q sig" to allow listing supported signature
9405c621 upstream: allow key revocation by SHA256 hash and
             allow ssh-keygen
50e2687e upstream: log certificate fingerprint in authentication
de37ca90 upstream: Add FALLTHROUGH comments where appropriate.
                       Patch from
247766cd upstream: ssh -MM requires confirmation for all operations that
db8bb80e upstream: fix misplaced parenthesis inside if-clause.
                       it's harmless
086cc614 upstream: fix build with DEBUG_PK enabled
26788330 Handle ngroups>_SC_NGROUPS_MAX.
039bf2a8 Initial len for the fmt=NULL case.
ea9c06e1 Include stdlib.h.
9617816d document some more regress control env variables

../Randy

> 
> Alex
> 


-- 
# Randy MacLeod
# Wind River Linux


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2018-09-18 20:17 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-11  8:59 [PATCH] openssh: build support openssl 1.1 Hongxu Jia
2018-09-11  9:10 ` Hongxu Jia
2018-09-11 10:39 ` Alexander Kanavin
2018-09-11 15:18   ` Hongxu Jia
2018-09-12  9:26     ` Alexander Kanavin
2018-09-12  9:59       ` Hongxu Jia
2018-09-12 10:30         ` Alexander Kanavin
2018-09-12 14:22           ` Khem Raj
2018-09-13  1:13           ` Andre McCurdy
2018-09-13 12:27             ` Alexander Kanavin
2018-09-18 20:17               ` Randy MacLeod

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.