diff --git a/contrib/win32/openssh/libssh.vcxproj b/contrib/win32/openssh/libssh.vcxproj
index 49889c4..499cfa3 100644
--- a/contrib/win32/openssh/libssh.vcxproj
+++ b/contrib/win32/openssh/libssh.vcxproj
@@ -258,6 +258,7 @@
+
diff --git a/contrib/win32/openssh/libssh.vcxproj.filters b/contrib/win32/openssh/libssh.vcxproj.filters
index 730bc3d..00d4658 100644
--- a/contrib/win32/openssh/libssh.vcxproj.filters
+++ b/contrib/win32/openssh/libssh.vcxproj.filters
@@ -288,5 +288,8 @@
Source Files
+
+ Source Files
+
\ No newline at end of file
diff --git a/kex.h b/kex.h
index d71b532..98a2b42 100644
--- a/kex.h
+++ b/kex.h
@@ -121,6 +121,26 @@ struct newkeys {
struct ssh;
+//KEX DH interface start
+struct sshbuf;
+typedef struct kexdhi_
+{
+ //consume p and g from "in"
+ int(*read_p_g)(struct kexdhi_*, struct sshbuf* in);
+ //encode p and g in "out"
+ int(*get_p_g)(struct kexdhi_*, struct sshbuf* out);
+ //encode public key in pub
+ int(*get_pub_key)(struct kexdhi_*, struct sshbuf* pub);
+ //read other public key from other_pub and encode secretagreement in secret
+ int(*get_secret)(struct kexdhi_*, struct sshbuf* other_pub, struct sshbuf* secret);
+ void(*done)(struct kexdhi_*);
+}kexdhi;
+
+kexdhi* kexdh_openssl_init(struct ssh* ssh);
+//KEX DH interface end
+
+
+
struct kex {
u_char *session_id;
size_t session_id_len;
@@ -150,6 +170,8 @@ struct kex {
u_char **, size_t *, const u_char *, size_t, u_int);
int (*kex[KEX_MAX])(struct ssh *);
/* kex specific state */
+ kexdhi* kexdh;
+
DH *dh; /* DH */
u_int min, max, nbits; /* GEX */
EC_KEY *ec_client_key; /* ECDH */
@@ -191,6 +213,12 @@ int kex_dh_hash(const char *, const char *,
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 *);
+//version of kex_dh_hash with public keys and secret passed as sshbuf instead of BIGNUM
+int kex_dh_hash_(
+ const char *, const char *, const u_char *, size_t , const u_char *, size_t ,
+ const u_char *, size_t , const struct sshbuf *, const struct sshbuf *, const struct sshbuf *,
+ u_char *hash, size_t *);
+
int kexgex_hash(int, const char *, const char *,
const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
int, int, int,
diff --git a/kexdh-openssl.c b/kexdh-openssl.c
new file mode 100644
index 0000000..cf5aed8
--- /dev/null
+++ b/kexdh-openssl.c
@@ -0,0 +1,152 @@
+#include "includes.h"
+
+#ifdef WITH_OPENSSL
+
+#include
+
+#include
+#include
+
+#include "kex.h"
+#include "log.h"
+#include "packet.h"
+#include "dh.h"
+#include "ssh2.h"
+#include "dispatch.h"
+#include "compat.h"
+#include "ssherr.h"
+#include "sshbuf.h"
+
+typedef struct kexdh_openssl_
+{
+ kexdhi dhi;
+ struct ssh* ssh;
+ DH* dh;
+}kexdh_openssl;
+
+
+static int kexdh_get_pub_key(kexdhi* dh_, struct sshbuf* pub)
+{
+ int r = 0;
+ kexdh_openssl* dh = (kexdh_openssl*)dh_;
+ struct kex* kex = dh->ssh->kex;
+
+ /* generate and send 'e', client DH public key */
+ switch (kex->kex_type) {
+ case KEX_DH_GRP1_SHA1:
+ dh->dh = dh_new_group1();
+ break;
+ case KEX_DH_GRP14_SHA1:
+ dh->dh = dh_new_group14();
+ break;
+ default:
+ r = SSH_ERR_INVALID_ARGUMENT;
+ goto out;
+ }
+
+ if ((r = dh_gen_key(dh->dh, kex->we_need * 8)) != 0 ||
+ (r = sshpkt_put_bignum2(pub, dh->dh->pub_key)) != 0)
+ goto out;
+#ifdef DEBUG_KEXDH
+ DHparams_print_fp(stderr, dh->dh);
+ fprintf(stderr, "pub= ");
+ BN_print_fp(stderr, dh->dh->pub_key);
+ fprintf(stderr, "\n");
+#endif
+ return 0;
+out:
+ return r;
+}
+
+static int kexdh_get_secret(kexdhi* dh_, struct sshbuf* other_pub, struct sshbuf* secret)
+{
+ int r = 0, kout;
+ BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
+ kexdh_openssl* dh = (kexdh_openssl*)dh_;
+ struct kex* kex = dh->ssh->kex;
+ size_t klen = 0;
+ u_char *kbuf = NULL;
+
+ /* DH parameter f, server public DH key */
+ if ((dh_server_pub = BN_new()) == NULL) {
+ r = SSH_ERR_ALLOC_FAIL;
+ goto out;
+ }
+
+ if ((r = sshbuf_get_bignum2(other_pub, dh_server_pub)) != 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(dh->dh, dh_server_pub)) {
+ sshpkt_disconnect(dh->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) {
+ 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;
+ goto out;
+ }
+#ifdef DEBUG_KEXDH
+ dump_digest("shared secret", kbuf, kout);
+#endif
+
+ if ((r == sshbuf_put_bignum2(secret, shared_secret)) != 0) {
+ goto out;
+ }
+out:
+ if (dh_server_pub)
+ BN_clear_free(dh_server_pub);
+ if (kbuf) {
+ explicit_bzero(kbuf, klen);
+ free(kbuf);
+ }
+ if (shared_secret)
+ BN_clear_free(shared_secret);
+
+ return r;
+}
+
+static void kexdh_done(kexdhi* dh_)
+{
+ kexdh_openssl* dh = (kexdh_openssl*)dh_;
+
+ if (dh->dh)
+ DH_free(dh->dh);
+ free(dh_);
+}
+
+
+kexdhi* kexdh_openssl_init(struct ssh* ssh)
+{
+
+ kexdh_openssl *dh = malloc(sizeof(kexdh_openssl));
+
+ if (dh)
+ {
+ dh->ssh = ssh;
+ dh->dhi.get_pub_key = kexdh_get_pub_key;
+ dh->dhi.get_secret = kexdh_get_secret;
+ dh->dhi.done = kexdh_done;
+ dh->dhi.get_p_g = NULL;
+ dh->dhi.read_p_g = NULL;
+ }
+
+ return dh;
+}
+
+
+#endif
\ No newline at end of file
diff --git a/kexdh.c b/kexdh.c
index feea669..a6c092c 100644
--- a/kexdh.c
+++ b/kexdh.c
@@ -90,4 +90,52 @@ kex_dh_hash(
#endif
return 0;
}
+kex_dh_hash_(
+ const char *client_version_string,
+ const char *server_version_string,
+ const u_char *ckexinit, size_t ckexinitlen,
+ const u_char *skexinit, size_t skexinitlen,
+ const u_char *serverhostkeyblob, size_t sbloblen,
+ const struct sshbuf *client_dh_pub,
+ const struct sshbuf *server_dh_pub,
+ const struct sshbuf *shared_secret,
+ u_char *hash, size_t *hashlen)
+{
+ struct sshbuf *b;
+ int r;
+
+ if (*hashlen < ssh_digest_bytes(SSH_DIGEST_SHA1))
+ return SSH_ERR_INVALID_ARGUMENT;
+ if ((b = sshbuf_new()) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+ if ((r = sshbuf_put_cstring(b, client_version_string)) != 0 ||
+ (r = sshbuf_put_cstring(b, server_version_string)) != 0 ||
+ /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
+ (r = sshbuf_put_u32(b, ckexinitlen + 1)) != 0 ||
+ (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
+ (r = sshbuf_put(b, ckexinit, ckexinitlen)) != 0 ||
+ (r = sshbuf_put_u32(b, skexinitlen + 1)) != 0 ||
+ (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
+ (r = sshbuf_put(b, skexinit, skexinitlen)) != 0 ||
+ (r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 ||
+ (r = sshbuf_put_b(b, client_dh_pub)) != 0 ||
+ (r = sshbuf_put_b(b, server_dh_pub)) != 0 ||
+ (r = sshbuf_put_b(b, shared_secret)) != 0) {
+ sshbuf_free(b);
+ return r;
+ }
+#ifdef DEBUG_KEX
+ sshbuf_dump(b, stderr);
+#endif
+ if (ssh_digest_buffer(SSH_DIGEST_SHA1, b, hash, *hashlen) != 0) {
+ sshbuf_free(b);
+ return SSH_ERR_LIBCRYPTO_ERROR;
+ }
+ sshbuf_free(b);
+ *hashlen = ssh_digest_bytes(SSH_DIGEST_SHA1);
+#ifdef DEBUG_KEX
+ dump_digest("hash", hash, *hashlen);
+#endif
+ return 0;
+}
#endif /* WITH_OPENSSL */
diff --git a/kexdhc.c b/kexdhc.c
index af259f1..bc646a5 100644
--- a/kexdhc.c
+++ b/kexdhc.c
@@ -56,39 +56,29 @@ kexdh_client(struct ssh *ssh)
{
struct kex *kex = ssh->kex;
int r;
+ struct sshbuf *client_pub = NULL;
+
+ kex->kexdh = kexdh_openssl_init(ssh);
- /* generate and send 'e', client DH public key */
- switch (kex->kex_type) {
- case KEX_DH_GRP1_SHA1:
- kex->dh = dh_new_group1();
- break;
- case KEX_DH_GRP14_SHA1:
- kex->dh = dh_new_group14();
- break;
- default:
- r = SSH_ERR_INVALID_ARGUMENT;
- goto out;
- }
- if (kex->dh == NULL) {
+ if (kex->kexdh == NULL ||
+ (client_pub = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
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 = sshpkt_start(ssh, SSH2_MSG_KEXDH_INIT)) != 0 ||
+ (r = kex->kexdh->get_pub_key(kex->kexdh, client_pub)) != 0 ||
+ (r = sshpkt_putb(ssh, client_pub)) != 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);
- fprintf(stderr, "\n");
-#endif
debug("expecting SSH2_MSG_KEXDH_REPLY");
ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_REPLY, &input_kex_dh);
r = 0;
- out:
+
+out:
+ if (client_pub)
+ sshbuf_free(client_pub);
return r;
}
@@ -97,12 +87,14 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
{
struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex;
- BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
struct sshkey *server_host_key = NULL;
- u_char *kbuf = NULL, *server_host_key_blob = NULL, *signature = 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;
+ const u_char* server_pub_ptr = NULL;
+ size_t server_pub_len = 0;
+ struct sshbuf *server_pub = NULL, *client_pub = NULL, *secret = NULL;
+ int r;
if (kex->verify_host_key == NULL) {
r = SSH_ERR_INVALID_ARGUMENT;
@@ -110,13 +102,13 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
}
/* key, cert */
if ((r = sshpkt_get_string(ssh, &server_host_key_blob,
- &sbloblen)) != 0 ||
- (r = sshkey_from_blob(server_host_key_blob, sbloblen,
- &server_host_key)) != 0)
+ &sbloblen)) != 0 ||
+ (r = sshkey_from_blob(server_host_key_blob, sbloblen,
+ &server_host_key)) != 0)
goto out;
if (server_host_key->type != kex->hostkey_type ||
- (kex->hostkey_type == KEY_ECDSA &&
- server_host_key->ecdsa_nid != kex->hostkey_nid)) {
+ (kex->hostkey_type == KEY_ECDSA &&
+ server_host_key->ecdsa_nid != kex->hostkey_nid)) {
r = SSH_ERR_KEY_TYPE_MISMATCH;
goto out;
}
@@ -124,54 +116,38 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
r = SSH_ERR_SIGNATURE_INVALID;
goto out;
}
- /* DH parameter f, server public DH key */
- if ((dh_server_pub = BN_new()) == NULL) {
- r = SSH_ERR_ALLOC_FAIL;
- goto out;
- }
+
/* signed H */
- if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 ||
- (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
- (r = sshpkt_get_end(ssh)) != 0)
+ if ((r = sshpkt_get_string_direct(ssh, &server_pub_ptr, &server_pub_len)) != 0 ||
+ (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 ((server_pub = sshbuf_from(server_pub_ptr - 4, server_pub_len + 4)) == NULL ||
+ (secret = sshbuf_new()) == NULL ||
+ (client_pub = 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->kexdh->get_secret(kex->kexdh, server_pub, secret)) != 0 ||
+ (r = kex->kexdh->get_pub_key(kex->kexdh, client_pub)) != 0)
+ {
goto out;
}
-#ifdef DEBUG_KEXDH
- dump_digest("shared secret", kbuf, kout);
-#endif
-
+
/* calc and verify H */
hashlen = sizeof(hash);
- if ((r = kex_dh_hash(
+ if ((r = kex_dh_hash_(
kex->client_version_string,
kex->server_version_string,
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,
- dh_server_pub,
- shared_secret,
+ client_pub,
+ server_pub,
+ secret,
hash, &hashlen)) != 0)
goto out;
@@ -190,20 +166,18 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
memcpy(kex->session_id, hash, kex->session_id_len);
}
- if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
+ if ((r = kex_derive_keys(ssh, hash, hashlen, secret)) == 0)
r = kex_send_newkeys(ssh);
out:
explicit_bzero(hash, sizeof(hash));
- DH_free(kex->dh);
- kex->dh = NULL;
- if (dh_server_pub)
- BN_clear_free(dh_server_pub);
- if (kbuf) {
- explicit_bzero(kbuf, klen);
- free(kbuf);
- }
- if (shared_secret)
- BN_clear_free(shared_secret);
+ if (client_pub)
+ sshbuf_free(client_pub);
+ if (server_pub)
+ sshbuf_free(server_pub);
+ if (secret)
+ sshbuf_free(secret);
+ kex->kexdh->done(kex->kexdh);
+ kex->kexdh = NULL;
sshkey_free(server_host_key);
free(server_host_key_blob);
free(signature);