[OE-core] [PATCH] openssh: build support openssl 1.1

Alexander Kanavin alex.kanavin at gmail.com
Tue Sep 11 10:39:30 UTC 2018


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 at 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 at 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 at 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 at 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 at lists.openembedded.org
> http://lists.openembedded.org/mailman/listinfo/openembedded-core



More information about the Openembedded-core mailing list