]> git.ipfire.org Git - thirdparty/openssh-portable.git/commitdiff
upstream: factor out kex_dh_compute_key() - it's shared between
authordjm@openbsd.org <djm@openbsd.org>
Mon, 21 Jan 2019 10:03:37 +0000 (10:03 +0000)
committerDamien Miller <djm@mindrot.org>
Mon, 21 Jan 2019 10:47:28 +0000 (21:47 +1100)
plain DH KEX and DH GEX in both the client and server implementations

from markus@ ok djm@

OpenBSD-Commit-ID: 12186e18791fffcd4642c82e7e0cfdd7ea37e2ec

kex.h
kexdh.c
kexdhc.c
kexdhs.c
kexgex.c
kexgexc.c
kexgexs.c

diff --git a/kex.h b/kex.h
index 4394e100b209368024f1c7f7045967007ca9b932..a11bd5ae6371a3dcb1bfbe678041027784c2da12 100644 (file)
--- a/kex.h
+++ b/kex.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: kex.h,v 1.95 2019/01/21 10:00:23 djm Exp $ */
+/* $OpenBSD: kex.h,v 1.96 2019/01/21 10:03:37 djm Exp $ */
 
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
@@ -203,15 +203,16 @@ int        kexc25519_client(struct ssh *);
 int     kexc25519_server(struct ssh *);
 
 int     kex_dh_keygen(struct kex *);
+int     kex_dh_compute_key(struct kex *, BIGNUM *, struct sshbuf *);
 int     kex_dh_hash(int, const struct sshbuf *, const struct sshbuf *,
     const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
-    const BIGNUM *, const BIGNUM *, const BIGNUM *, u_char *, size_t *);
+    const BIGNUM *, const BIGNUM *, const u_char *, size_t, u_char *, size_t *);
 
 int     kexgex_hash(int, const struct sshbuf *, const struct sshbuf *,
     const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
     int, int, int,
     const BIGNUM *, const BIGNUM *, const BIGNUM *,
-    const BIGNUM *, const BIGNUM *,
+    const BIGNUM *, const u_char *, size_t,
     u_char *, size_t *);
 
 int kex_ecdh_hash(int, const EC_GROUP *,
diff --git a/kexdh.c b/kexdh.c
index 916036994179f1fe5fa4d5e62f1f05137c73c95a..5324857b216c455d42b43d559047726f96b0181c 100644 (file)
--- a/kexdh.c
+++ b/kexdh.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kexdh.c,v 1.28 2019/01/21 10:00:23 djm Exp $ */
+/* $OpenBSD: kexdh.c,v 1.29 2019/01/21 10:03:37 djm Exp $ */
 /*
  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
  *
@@ -43,6 +43,7 @@
 #include "ssherr.h"
 #include "sshbuf.h"
 #include "digest.h"
+#include "dh.h"
 
 int
 kex_dh_keygen(struct kex *kex)
@@ -69,6 +70,48 @@ kex_dh_keygen(struct kex *kex)
        return (dh_gen_key(kex->dh, kex->we_need * 8));
 }
 
+int
+kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out)
+{
+       BIGNUM *shared_secret = NULL;
+       u_char *kbuf = NULL;
+       size_t klen = 0;
+       int kout, r;
+
+#ifdef DEBUG_KEXDH
+       fprintf(stderr, "dh_pub= ");
+       BN_print_fp(stderr, dh_pub);
+       fprintf(stderr, "\n");
+       debug("bits %d", BN_num_bits(dh_pub));
+       DHparams_print_fp(stderr, kex->dh);
+       fprintf(stderr, "\n");
+#endif
+
+       if (!dh_pub_is_valid(kex->dh, dh_pub)) {
+               r = SSH_ERR_MESSAGE_INCOMPLETE;
+               goto out;
+       }
+       klen = DH_size(kex->dh);
+       if ((kbuf = malloc(klen)) == NULL ||
+           (shared_secret = BN_new()) == NULL) {
+               r = SSH_ERR_ALLOC_FAIL;
+               goto out;
+       }
+       if ((kout = DH_compute_key(kbuf, dh_pub, kex->dh)) < 0 ||
+           BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
+               r = SSH_ERR_LIBCRYPTO_ERROR;
+               goto out;
+       }
+#ifdef DEBUG_KEXDH
+       dump_digest("shared secret", kbuf, kout);
+#endif
+       r = sshbuf_put_bignum2(out, shared_secret);
+ out:
+       freezero(kbuf, klen);
+       BN_clear_free(shared_secret);
+       return r;
+}
+
 int
 kex_dh_hash(
     int hash_alg,
@@ -79,7 +122,7 @@ kex_dh_hash(
     const u_char *serverhostkeyblob, size_t sbloblen,
     const BIGNUM *client_dh_pub,
     const BIGNUM *server_dh_pub,
-    const BIGNUM *shared_secret,
+    const u_char *shared_secret, size_t secretlen,
     u_char *hash, size_t *hashlen)
 {
        struct sshbuf *b;
@@ -101,7 +144,7 @@ kex_dh_hash(
            (r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 ||
            (r = sshbuf_put_bignum2(b, client_dh_pub)) != 0 ||
            (r = sshbuf_put_bignum2(b, server_dh_pub)) != 0 ||
-           (r = sshbuf_put_bignum2(b, shared_secret)) != 0) {
+           (r = sshbuf_put(b, shared_secret, secretlen)) != 0) {
                sshbuf_free(b);
                return r;
        }
index a7ea0baad59ed0b5454cecfe5afedf59b4526349..2e26f22ea8743a1e3e100aa44781384731895b4e 100644 (file)
--- a/kexdhc.c
+++ b/kexdhc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kexdhc.c,v 1.27 2019/01/21 10:00:23 djm Exp $ */
+/* $OpenBSD: kexdhc.c,v 1.28 2019/01/21 10:03:37 djm Exp $ */
 /*
  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
  *
@@ -86,13 +86,14 @@ static int
 input_kex_dh(int type, u_int32_t seq, struct ssh *ssh)
 {
        struct kex *kex = ssh->kex;
-       BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
+       BIGNUM *dh_server_pub = NULL;
        const BIGNUM *pub_key;
        struct sshkey *server_host_key = NULL;
-       u_char *kbuf = NULL, *server_host_key_blob = NULL, *signature = NULL;
+       struct sshbuf *shared_secret = NULL;
+       u_char *server_host_key_blob = NULL, *signature = NULL;
        u_char hash[SSH_DIGEST_MAX_LENGTH];
-       size_t klen = 0, slen, sbloblen, hashlen;
-       int kout, r;
+       size_t slen, sbloblen, hashlen;
+       int r;
 
        if (kex->verify_host_key == NULL) {
                r = SSH_ERR_INVALID_ARGUMENT;
@@ -119,32 +120,12 @@ input_kex_dh(int type, u_int32_t seq, struct ssh *ssh)
            (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
            (r = sshpkt_get_end(ssh)) != 0)
                goto out;
-#ifdef DEBUG_KEXDH
-       fprintf(stderr, "dh_server_pub= ");
-       BN_print_fp(stderr, dh_server_pub);
-       fprintf(stderr, "\n");
-       debug("bits %d", BN_num_bits(dh_server_pub));
-#endif
-       if (!dh_pub_is_valid(kex->dh, dh_server_pub)) {
-               sshpkt_disconnect(ssh, "bad server public DH value");
-               r = SSH_ERR_MESSAGE_INCOMPLETE;
-               goto out;
-       }
-
-       klen = DH_size(kex->dh);
-       if ((kbuf = malloc(klen)) == NULL ||
-           (shared_secret = BN_new()) == NULL) {
+       if ((shared_secret = sshbuf_new()) == NULL) {
                r = SSH_ERR_ALLOC_FAIL;
                goto out;
        }
-       if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 ||
-           BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
-               r = SSH_ERR_LIBCRYPTO_ERROR;
+       if ((r = kex_dh_compute_key(kex, dh_server_pub, shared_secret)) != 0)
                goto out;
-       }
-#ifdef DEBUG_KEXDH
-       dump_digest("shared secret", kbuf, kout);
-#endif
 
        /* calc and verify H */
        DH_get0_key(kex->dh, &pub_key, NULL);
@@ -158,7 +139,7 @@ input_kex_dh(int type, u_int32_t seq, struct ssh *ssh)
            server_host_key_blob, sbloblen,
            pub_key,
            dh_server_pub,
-           shared_secret,
+           sshbuf_ptr(shared_secret), sshbuf_len(shared_secret),
            hash, &hashlen)) != 0)
                goto out;
 
@@ -166,18 +147,14 @@ input_kex_dh(int type, u_int32_t seq, struct ssh *ssh)
            kex->hostkey_alg, ssh->compat)) != 0)
                goto out;
 
-       if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
+       if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
                r = kex_send_newkeys(ssh);
  out:
        explicit_bzero(hash, sizeof(hash));
        DH_free(kex->dh);
        kex->dh = NULL;
        BN_clear_free(dh_server_pub);
-       if (kbuf) {
-               explicit_bzero(kbuf, klen);
-               free(kbuf);
-       }
-       BN_clear_free(shared_secret);
+       sshbuf_free(shared_secret);
        sshkey_free(server_host_key);
        free(server_host_key_blob);
        free(signature);
index cd2e52e00bfdc9805a967283cdac1c48b457f627..0f028aaeb38ec3a4e70a45fc6eb40ac3f54c629e 100644 (file)
--- a/kexdhs.c
+++ b/kexdhs.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kexdhs.c,v 1.33 2019/01/21 10:00:23 djm Exp $ */
+/* $OpenBSD: kexdhs.c,v 1.34 2019/01/21 10:03:37 djm Exp $ */
 /*
  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
  *
@@ -71,14 +71,15 @@ int
 input_kex_dh_init(int type, u_int32_t seq, struct ssh *ssh)
 {
        struct kex *kex = ssh->kex;
-       BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
+       BIGNUM *dh_client_pub = NULL;
        const BIGNUM *pub_key;
        struct sshkey *server_host_public, *server_host_private;
-       u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL;
+       struct sshbuf *shared_secret = NULL;
+       u_char *signature = NULL, *server_host_key_blob = NULL;
        u_char hash[SSH_DIGEST_MAX_LENGTH];
        size_t sbloblen, slen;
-       size_t klen = 0, hashlen;
-       int kout, r;
+       size_t hashlen;
+       int r;
 
        if (kex->load_host_public_key == NULL ||
            kex->load_host_private_key == NULL) {
@@ -98,42 +99,17 @@ input_kex_dh_init(int type, u_int32_t seq, struct ssh *ssh)
        if ((r = sshpkt_get_bignum2(ssh, &dh_client_pub)) != 0 ||
            (r = sshpkt_get_end(ssh)) != 0)
                goto out;
-       DH_get0_key(kex->dh, &pub_key, NULL);
-
-#ifdef DEBUG_KEXDH
-       fprintf(stderr, "dh_client_pub= ");
-       BN_print_fp(stderr, dh_client_pub);
-       fprintf(stderr, "\n");
-       debug("bits %d", BN_num_bits(dh_client_pub));
-       DHparams_print_fp(stderr, kex->dh);
-       fprintf(stderr, "pub= ");
-       BN_print_fp(stderr, pub_key);
-       fprintf(stderr, "\n");
-#endif
-       if (!dh_pub_is_valid(kex->dh, dh_client_pub)) {
-               sshpkt_disconnect(ssh, "bad client public DH value");
-               r = SSH_ERR_MESSAGE_INCOMPLETE;
-               goto out;
-       }
-
-       klen = DH_size(kex->dh);
-       if ((kbuf = malloc(klen)) == NULL ||
-           (shared_secret = BN_new()) == NULL) {
+       if ((shared_secret = sshbuf_new()) == NULL) {
                r = SSH_ERR_ALLOC_FAIL;
                goto out;
        }
-       if ((kout = DH_compute_key(kbuf, dh_client_pub, kex->dh)) < 0 ||
-           BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
-               r = SSH_ERR_LIBCRYPTO_ERROR;
+       if ((r = kex_dh_compute_key(kex, dh_client_pub, shared_secret)) != 0)
                goto out;
-       }
-#ifdef DEBUG_KEXDH
-       dump_digest("shared secret", kbuf, kout);
-#endif
        if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob,
            &sbloblen)) != 0)
                goto out;
        /* calc H */
+       DH_get0_key(kex->dh, &pub_key, NULL);
        hashlen = sizeof(hash);
        if ((r = kex_dh_hash(
            kex->hash_alg,
@@ -144,7 +120,7 @@ input_kex_dh_init(int type, u_int32_t seq, struct ssh *ssh)
            server_host_key_blob, sbloblen,
            dh_client_pub,
            pub_key,
-           shared_secret,
+           sshbuf_ptr(shared_secret), sshbuf_len(shared_secret),
            hash, &hashlen)) != 0)
                goto out;
 
@@ -153,8 +129,6 @@ input_kex_dh_init(int type, u_int32_t seq, struct ssh *ssh)
            &signature, &slen, hash, hashlen, kex->hostkey_alg)) < 0)
                goto out;
 
-       /* destroy_sensitive_data(); */
-
        /* 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 ||
@@ -163,18 +137,14 @@ input_kex_dh_init(int type, u_int32_t seq, struct ssh *ssh)
            (r = sshpkt_send(ssh)) != 0)
                goto out;
 
-       if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
+       if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
                r = kex_send_newkeys(ssh);
  out:
        explicit_bzero(hash, sizeof(hash));
        DH_free(kex->dh);
        kex->dh = NULL;
        BN_clear_free(dh_client_pub);
-       if (kbuf) {
-               explicit_bzero(kbuf, klen);
-               free(kbuf);
-       }
-       BN_clear_free(shared_secret);
+       sshbuf_free(shared_secret);
        free(server_host_key_blob);
        free(signature);
        return r;
index a5d591b0ad621202a3976094e4bbfbe38413e59f..f828f2b2088647e83e9e2ca40f84e1fea1539871 100644 (file)
--- a/kexgex.c
+++ b/kexgex.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kexgex.c,v 1.30 2018/12/27 03:25:25 djm Exp $ */
+/* $OpenBSD: kexgex.c,v 1.31 2019/01/21 10:03:37 djm Exp $ */
 /*
  * Copyright (c) 2000 Niels Provos.  All rights reserved.
  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
@@ -56,7 +56,7 @@ kexgex_hash(
     const BIGNUM *gen,
     const BIGNUM *client_dh_pub,
     const BIGNUM *server_dh_pub,
-    const BIGNUM *shared_secret,
+    const u_char *shared_secret, size_t secretlen,
     u_char *hash, size_t *hashlen)
 {
        struct sshbuf *b;
@@ -83,7 +83,7 @@ kexgex_hash(
            (r = sshbuf_put_bignum2(b, gen)) != 0 ||
            (r = sshbuf_put_bignum2(b, client_dh_pub)) != 0 ||
            (r = sshbuf_put_bignum2(b, server_dh_pub)) != 0 ||
-           (r = sshbuf_put_bignum2(b, shared_secret)) != 0) {
+           (r = sshbuf_put(b, shared_secret, secretlen)) != 0) {
                sshbuf_free(b);
                return r;
        }
index 0425309d4aeeb36a34c0d5e203b303dde0628713..600d91acc2dd97b86738b407f047efac66f522f9 100644 (file)
--- a/kexgexc.c
+++ b/kexgexc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kexgexc.c,v 1.31 2019/01/21 09:55:52 djm Exp $ */
+/* $OpenBSD: kexgexc.c,v 1.32 2019/01/21 10:03:37 djm Exp $ */
 /*
  * Copyright (c) 2000 Niels Provos.  All rights reserved.
  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
@@ -143,13 +143,14 @@ static int
 input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh)
 {
        struct kex *kex = ssh->kex;
-       BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
+       BIGNUM *dh_server_pub = NULL;
        const BIGNUM *pub_key, *dh_p, *dh_g;
+       struct sshbuf *shared_secret = NULL;
        struct sshkey *server_host_key = NULL;
-       u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL;
+       u_char *signature = NULL, *server_host_key_blob = NULL;
        u_char hash[SSH_DIGEST_MAX_LENGTH];
-       size_t klen = 0, slen, sbloblen, hashlen;
-       int kout, r;
+       size_t slen, sbloblen, hashlen;
+       int r;
 
        debug("got SSH2_MSG_KEX_DH_GEX_REPLY");
        if (kex->verify_host_key == NULL) {
@@ -177,32 +178,12 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh)
            (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
            (r = sshpkt_get_end(ssh)) != 0)
                goto out;
-#ifdef DEBUG_KEXDH
-       fprintf(stderr, "dh_server_pub= ");
-       BN_print_fp(stderr, dh_server_pub);
-       fprintf(stderr, "\n");
-       debug("bits %d", BN_num_bits(dh_server_pub));
-#endif
-       if (!dh_pub_is_valid(kex->dh, dh_server_pub)) {
-               sshpkt_disconnect(ssh, "bad server public DH value");
-               r = SSH_ERR_MESSAGE_INCOMPLETE;
-               goto out;
-       }
-
-       klen = DH_size(kex->dh);
-       if ((kbuf = malloc(klen)) == NULL ||
-           (shared_secret = BN_new()) == NULL) {
+       if ((shared_secret = sshbuf_new()) == NULL) {
                r = SSH_ERR_ALLOC_FAIL;
                goto out;
        }
-       if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 ||
-           BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
-               r = SSH_ERR_LIBCRYPTO_ERROR;
+       if ((r = kex_dh_compute_key(kex, dh_server_pub, shared_secret)) != 0)
                goto out;
-       }
-#ifdef DEBUG_KEXDH
-       dump_digest("shared secret", kbuf, kout);
-#endif
        if (ssh->compat & SSH_OLD_DHGEX)
                kex->min = kex->max = -1;
 
@@ -221,7 +202,7 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh)
            dh_p, dh_g,
            pub_key,
            dh_server_pub,
-           shared_secret,
+           sshbuf_ptr(shared_secret), sshbuf_len(shared_secret),
            hash, &hashlen)) != 0)
                goto out;
 
@@ -229,18 +210,14 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh)
            hashlen, kex->hostkey_alg, ssh->compat)) != 0)
                goto out;
 
-       if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
+       if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
                r = kex_send_newkeys(ssh);
  out:
        explicit_bzero(hash, sizeof(hash));
        DH_free(kex->dh);
        kex->dh = NULL;
        BN_clear_free(dh_server_pub);
-       if (kbuf) {
-               explicit_bzero(kbuf, klen);
-               free(kbuf);
-       }
-       BN_clear_free(shared_secret);
+       sshbuf_free(shared_secret);
        sshkey_free(server_host_key);
        free(server_host_key_blob);
        free(signature);
index 4ffbb191817550d9e3611e91d779ccc7f157332d..f8eb365455c1f8775adeabae5df54c60342d91c7 100644 (file)
--- a/kexgexs.c
+++ b/kexgexs.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kexgexs.c,v 1.39 2019/01/21 09:55:52 djm Exp $ */
+/* $OpenBSD: kexgexs.c,v 1.40 2019/01/21 10:03:37 djm Exp $ */
 /*
  * Copyright (c) 2000 Niels Provos.  All rights reserved.
  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
@@ -126,14 +126,15 @@ static int
 input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh)
 {
        struct kex *kex = ssh->kex;
-       BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
+       BIGNUM *dh_client_pub = NULL;
        const BIGNUM *pub_key, *dh_p, *dh_g;
+       struct sshbuf *shared_secret = NULL;
        struct sshkey *server_host_public, *server_host_private;
-       u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL;
+       u_char *signature = NULL, *server_host_key_blob = NULL;
        u_char hash[SSH_DIGEST_MAX_LENGTH];
        size_t sbloblen, slen;
-       size_t klen = 0, hashlen;
-       int kout, r;
+       size_t hashlen;
+       int r;
 
        if (kex->load_host_public_key == NULL ||
            kex->load_host_private_key == NULL) {
@@ -153,44 +154,19 @@ input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh)
        if ((r = sshpkt_get_bignum2(ssh, &dh_client_pub)) != 0 ||
            (r = sshpkt_get_end(ssh)) != 0)
                goto out;
-
-       DH_get0_key(kex->dh, &pub_key, NULL);
-       DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g);
-
-#ifdef DEBUG_KEXDH
-       fprintf(stderr, "dh_client_pub= ");
-       BN_print_fp(stderr, dh_client_pub);
-       fprintf(stderr, "\n");
-       debug("bits %d", BN_num_bits(dh_client_pub));
-       DHparams_print_fp(stderr, kex->dh);
-       fprintf(stderr, "pub= ");
-       BN_print_fp(stderr, pub_key);
-       fprintf(stderr, "\n");
-#endif
-       if (!dh_pub_is_valid(kex->dh, dh_client_pub)) {
-               sshpkt_disconnect(ssh, "bad client public DH value");
-               r = SSH_ERR_MESSAGE_INCOMPLETE;
-               goto out;
-       }
-
-       klen = DH_size(kex->dh);
-       if ((kbuf = malloc(klen)) == NULL ||
-           (shared_secret = BN_new()) == NULL) {
+       if ((shared_secret = sshbuf_new()) == NULL) {
                r = SSH_ERR_ALLOC_FAIL;
                goto out;
        }
-       if ((kout = DH_compute_key(kbuf, dh_client_pub, kex->dh)) < 0 ||
-           BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
-               r = SSH_ERR_LIBCRYPTO_ERROR;
+       if ((r = kex_dh_compute_key(kex, dh_client_pub, shared_secret)) != 0)
                goto out;
-       }
-#ifdef DEBUG_KEXDH
-       dump_digest("shared secret", kbuf, kout);
-#endif
        if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob,
            &sbloblen)) != 0)
                goto out;
+
        /* calc H */
+       DH_get0_key(kex->dh, &pub_key, NULL);
+       DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g);
        hashlen = sizeof(hash);
        if ((r = kexgex_hash(
            kex->hash_alg,
@@ -203,7 +179,7 @@ input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh)
            dh_p, dh_g,
            dh_client_pub,
            pub_key,
-           shared_secret,
+           sshbuf_ptr(shared_secret), sshbuf_len(shared_secret),
            hash, &hashlen)) != 0)
                goto out;
 
@@ -212,8 +188,6 @@ input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh)
            &signature, &slen, hash, hashlen, kex->hostkey_alg)) < 0)
                goto out;
 
-       /* destroy_sensitive_data(); */
-
        /* 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 ||
@@ -222,18 +196,14 @@ input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh)
            (r = sshpkt_send(ssh)) != 0)
                goto out;
 
-       if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
+       if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
                r = kex_send_newkeys(ssh);
  out:
        explicit_bzero(hash, sizeof(hash));
        DH_free(kex->dh);
        kex->dh = NULL;
        BN_clear_free(dh_client_pub);
-       if (kbuf) {
-               explicit_bzero(kbuf, klen);
-               free(kbuf);
-       }
-       BN_clear_free(shared_secret);
+       sshbuf_free(shared_secret);
        free(server_host_key_blob);
        free(signature);
        return r;