aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAris Adamantiadis <aris@0xbadc0de.be>2016-05-31 19:38:57 +0200
committerAris Adamantiadis <aris@0xbadc0de.be>2017-06-08 10:45:54 +0200
commitddaf2fe2c1e56aeffb7fab5093b692564898dd87 (patch)
tree213ab0d90524f16598091717166ec68c6785e40d
parentdd74ab889f7634e691acb0fb05890640af49eec2 (diff)
downloadlibssh-ddaf2fe2c1e56aeffb7fab5093b692564898dd87.tar.gz
libssh-ddaf2fe2c1e56aeffb7fab5093b692564898dd87.tar.xz
libssh-ddaf2fe2c1e56aeffb7fab5093b692564898dd87.zip
dh-gex: client implementation
-rw-r--r--include/libssh/crypto.h3
-rw-r--r--include/libssh/dh-gex.h2
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/client.c5
-rw-r--r--src/dh-gex.c90
-rw-r--r--src/kex.c21
6 files changed, 113 insertions, 9 deletions
diff --git a/include/libssh/crypto.h b/include/libssh/crypto.h
index 10798b83..bdb31d87 100644
--- a/include/libssh/crypto.h
+++ b/include/libssh/crypto.h
@@ -53,6 +53,9 @@ enum ssh_key_exchange_e {
SSH_KEX_DH_GROUP1_SHA1=1,
/* diffie-hellman-group14-sha1 */
SSH_KEX_DH_GROUP14_SHA1,
+ /* diffie-hellman-group-exchange-sha1 */
+ SSH_KEX_DH_GEX_SHA1,
+ SSH_KEX_DH_GEX_SHA256,
/* ecdh-sha2-nistp256 */
SSH_KEX_ECDH_SHA2_NISTP256,
/* curve25519-sha256@libssh.org */
diff --git a/include/libssh/dh-gex.h b/include/libssh/dh-gex.h
index 2963c297..3b3c4f89 100644
--- a/include/libssh/dh-gex.h
+++ b/include/libssh/dh-gex.h
@@ -24,7 +24,7 @@
#define SRC_DH_GEX_H_
#include "config.h"
-
+#include "libssh/libssh.h"
int ssh_client_dhgex_init(ssh_session session);
#ifdef WITH_SERVER
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e5a93538..5dfb6899 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -118,6 +118,7 @@ set(libssh_SRCS
connector.c
curve25519.c
dh.c
+ dh-gex.c
ecdh.c
error.c
getpass.c
diff --git a/src/client.c b/src/client.c
index e84a9be5..134596db 100644
--- a/src/client.c
+++ b/src/client.c
@@ -38,6 +38,7 @@
#include "libssh/socket.h"
#include "libssh/session.h"
#include "libssh/dh.h"
+#include "libssh/dh-gex.h"
#include "libssh/ecdh.h"
#include "libssh/threads.h"
#include "libssh/misc.h"
@@ -258,6 +259,10 @@ static int dh_handshake(ssh_session session) {
case SSH_KEX_DH_GROUP14_SHA1:
rc = ssh_client_dh_init(session);
break;
+ case SSH_KEX_DH_GEX_SHA1:
+ case SSH_KEX_DH_GEX_SHA256:
+ rc = ssh_client_dhgex_init(session);
+ break;
#ifdef HAVE_ECDH
case SSH_KEX_ECDH_SHA2_NISTP256:
rc = ssh_client_ecdh_init(session);
diff --git a/src/dh-gex.c b/src/dh-gex.c
index f72684e6..40887c7c 100644
--- a/src/dh-gex.c
+++ b/src/dh-gex.c
@@ -26,6 +26,8 @@
#include "libssh/ssh2.h"
#include "libssh/callbacks.h"
#include "libssh/dh.h"
+#include "libssh/buffer.h"
+#include "libssh/session.h"
static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group);
static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_reply);
@@ -36,7 +38,7 @@ static ssh_packet_callback dhgex_client_callbacks[]= {
ssh_packet_client_dhgex_reply /* SSH_MSG_KEX_DH_GEX_REPLY */
};
-static struct ssh_packet_callbacks_struct ssh_dh_client_callbacks = {
+static struct ssh_packet_callbacks_struct ssh_dhgex_client_callbacks = {
.start = SSH2_MSG_KEX_DH_GEX_GROUP,
.n_callbacks = 3,
.callbacks = dhgex_client_callbacks,
@@ -51,16 +53,23 @@ int ssh_client_dhgex_init(ssh_session session){
rc = ssh_dh_init_common(session);
if (rc != SSH_OK){
- return rc;
+ goto error;
}
/* Minimum group size, preferred group size, maximum group size */
rc = ssh_buffer_pack(session->out_buffer, "bddd",
SSH2_MSG_KEX_DH_GEX_REQUEST, 1534, 2048, 8192);
+ if (rc != SSH_OK){
+ goto error;
+ }
+
/* register the packet callbacks */
- ssh_packet_set_callbacks(session, &ssh_dh_client_callbacks);
+ ssh_packet_set_callbacks(session, &ssh_dhgex_client_callbacks);
session->dh_handshake_state = DH_STATE_REQUEST_SENT;
- rc = packet_send(session);
+ rc = ssh_packet_send(session);
+ if (rc == SSH_ERROR){
+ goto error;
+ }
return rc;
error:
ssh_dh_cleanup(session);
@@ -75,6 +84,13 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group){
int rc;
int blen;
bignum pmin1=NULL, one=NULL;
+ bignum_CTX ctx = bignum_ctx_new();
+
+ SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_DH_GEX_GROUP received");
+
+ if (bignum_ctx_invalid(ctx)) {
+ goto error;
+ }
if (session->dh_handshake_state != DH_STATE_REQUEST_SENT){
ssh_set_error(session, SSH_FATAL, "Received DH_GEX_GROUP in invalid state");
@@ -83,7 +99,7 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group){
one = bignum_new();
pmin1 = bignum_new();
if (one == NULL || pmin1 == NULL){
- ssh_error_oom(session);
+ ssh_set_error_oom(session);
goto error;
}
session->next_crypto->dh_group_is_mutable = 1;
@@ -95,8 +111,8 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group){
/* basic checks */
bignum_set_word(one, 1);
blen = bignum_num_bits(session->next_crypto->p);
- if (blen < 1024 || blen > 8192){
- ssh_set_error(session, SSH_FATAL, "Invalid dh group parameter p: %d not in [1024:8192]", blen);
+ if (blen < 1534 || blen > 8192){
+ ssh_set_error(session, SSH_FATAL, "Invalid dh group parameter p: %d not in [1534:8192]", blen);
goto error;
}
if (bignum_cmp(session->next_crypto->p, one) <= 0){
@@ -115,8 +131,27 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group){
ssh_set_error(session, SSH_FATAL, "Invalid dh group parameter g");
goto error;
}
+ /* compute and send DH public parameter */
+ rc = ssh_dh_generate_secret(session, session->next_crypto->x);
+ if (rc == SSH_ERROR){
+ goto error;
+ }
+ bignum_mod_exp(session->next_crypto->e, session->next_crypto->g, session->next_crypto->x,
+ session->next_crypto->p, ctx);
+
+ bignum_ctx_free(ctx);
+
+ rc = ssh_buffer_pack(session->out_buffer, "bB", SSH2_MSG_KEX_DH_GEX_INIT, session->next_crypto->e);
+ if (rc != SSH_OK) {
+ goto error;
+ }
session->dh_handshake_state = DH_STATE_INIT_SENT;
+
+ rc = ssh_packet_send(session);
+
+ bignum_safe_free(one);
+ bignum_safe_free(pmin1);
return SSH_PACKET_USED;
error:
bignum_safe_free(one);
@@ -125,3 +160,44 @@ error:
session->session_state=SSH_SESSION_STATE_ERROR;
return SSH_PACKET_USED;
}
+
+static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_reply) {
+ struct ssh_crypto_struct *crypto=session->next_crypto;
+ int rc;
+ (void)type;
+ (void)user;
+ SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_DH_GEX_REPLY received");
+
+ ssh_packet_remove_callbacks(session, &ssh_dhgex_client_callbacks);
+ rc = ssh_buffer_unpack(packet, "SBS", &crypto->server_pubkey, &crypto->f,
+ &crypto->dh_server_signature);
+
+ if (rc == SSH_ERROR){
+ ssh_set_error(session, SSH_FATAL, "Invalid DH_GEX_REPLY packet");
+ goto error;
+ }
+
+ rc = ssh_dh_build_k(session);
+ if (rc == SSH_ERROR) {
+ ssh_set_error(session, SSH_FATAL, "Could not generate shared secret");
+ goto error;
+ }
+
+ /* Send the MSG_NEWKEYS */
+ if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) {
+ goto error;
+ }
+
+ rc=ssh_packet_send(session);
+ if (rc==SSH_ERROR){
+ goto error;
+ }
+ SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent");
+ session->dh_handshake_state = DH_STATE_NEWKEYS_SENT;
+
+ return SSH_PACKET_USED;
+ error:
+ ssh_dh_cleanup(session);
+ session->session_state=SSH_SESSION_STATE_ERROR;
+ return SSH_PACKET_USED;
+}
diff --git a/src/kex.c b/src/kex.c
index bbf71583..64d9a369 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -86,7 +86,7 @@
#define ECDH ""
#endif
-#define KEY_EXCHANGE CURVE25519 ECDH "diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
+#define KEY_EXCHANGE CURVE25519 ECDH "diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1"
#define KEX_METHODS_SIZE 10
/* NOTE: This is a fixed API and the index is defined by ssh_kex_types_e */
@@ -588,6 +588,10 @@ int ssh_kex_select_methods (ssh_session session){
session->next_crypto->kex_type=SSH_KEX_DH_GROUP1_SHA1;
} else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group14-sha1") == 0){
session->next_crypto->kex_type=SSH_KEX_DH_GROUP14_SHA1;
+ } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group-exchange-sha1") == 0){
+ session->next_crypto->kex_type=SSH_KEX_DH_GEX_SHA1;
+ } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group-exchange-sha256") == 0){
+ session->next_crypto->kex_type=SSH_KEX_DH_GEX_SHA256;
} else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp256") == 0){
session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP256;
} else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "curve25519-sha256@libssh.org") == 0){
@@ -760,6 +764,19 @@ int ssh_make_sessionid(ssh_session session) {
goto error;
}
break;
+ case SSH_KEX_DH_GEX_SHA1:
+ case SSH_KEX_DH_GEX_SHA256:
+ rc = ssh_buffer_pack(buf,
+ "dddBBBB",
+ 1534, 2048, 8192,
+ session->next_crypto->p,
+ session->next_crypto->g,
+ session->next_crypto->e,
+ session->next_crypto->f);
+ if (rc != SSH_OK) {
+ goto error;
+ }
+ break;
#ifdef HAVE_ECDH
case SSH_KEX_ECDH_SHA2_NISTP256:
if (session->next_crypto->ecdh_client_pubkey == NULL ||
@@ -803,6 +820,7 @@ int ssh_make_sessionid(ssh_session session) {
switch (session->next_crypto->kex_type) {
case SSH_KEX_DH_GROUP1_SHA1:
case SSH_KEX_DH_GROUP14_SHA1:
+ case SSH_KEX_DH_GEX_SHA1:
session->next_crypto->digest_len = SHA_DIGEST_LENGTH;
session->next_crypto->mac_type = SSH_MAC_SHA1;
session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);
@@ -815,6 +833,7 @@ int ssh_make_sessionid(ssh_session session) {
break;
case SSH_KEX_ECDH_SHA2_NISTP256:
case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
+ case SSH_KEX_DH_GEX_SHA256:
session->next_crypto->digest_len = SHA256_DIGEST_LENGTH;
session->next_crypto->mac_type = SSH_MAC_SHA256;
session->next_crypto->secret_hash = malloc(session->next_crypto->digest_len);