diff options
author | Aris Adamantiadis <aris@0xbadc0de.be> | 2016-05-31 19:38:57 +0200 |
---|---|---|
committer | Aris Adamantiadis <aris@0xbadc0de.be> | 2017-06-08 10:45:54 +0200 |
commit | ddaf2fe2c1e56aeffb7fab5093b692564898dd87 (patch) | |
tree | 213ab0d90524f16598091717166ec68c6785e40d | |
parent | dd74ab889f7634e691acb0fb05890640af49eec2 (diff) | |
download | libssh-ddaf2fe2c1e56aeffb7fab5093b692564898dd87.tar.gz libssh-ddaf2fe2c1e56aeffb7fab5093b692564898dd87.tar.xz libssh-ddaf2fe2c1e56aeffb7fab5093b692564898dd87.zip |
dh-gex: client implementation
-rw-r--r-- | include/libssh/crypto.h | 3 | ||||
-rw-r--r-- | include/libssh/dh-gex.h | 2 | ||||
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/client.c | 5 | ||||
-rw-r--r-- | src/dh-gex.c | 90 | ||||
-rw-r--r-- | src/kex.c | 21 |
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; +} @@ -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); |