aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAris Adamantiadis <aris@0xbadc0de.be>2017-06-11 11:57:32 +0200
committerAris Adamantiadis <aris@0xbadc0de.be>2017-06-11 11:57:32 +0200
commit18ad598f2e02e4fbf3e5bc311e1f05b80f70fa56 (patch)
tree3e43c49767013fb27a28393a9a05a0ab700f5897
parent3bd1b80c85d6657f47031b10211265fa216da37c (diff)
downloadlibssh-18ad598f2e02e4fbf3e5bc311e1f05b80f70fa56.tar.gz
libssh-18ad598f2e02e4fbf3e5bc311e1f05b80f70fa56.tar.xz
libssh-18ad598f2e02e4fbf3e5bc311e1f05b80f70fa56.zip
dh-gex: WIPgex_to_polish
-rw-r--r--src/dh-gex.c107
1 files changed, 97 insertions, 10 deletions
diff --git a/src/dh-gex.c b/src/dh-gex.c
index 1bd1b49a..18e1b477 100644
--- a/src/dh-gex.c
+++ b/src/dh-gex.c
@@ -32,6 +32,8 @@
#include "libssh/buffer.h"
#include "libssh/session.h"
+#define PMIN 1534
+
static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group);
static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_reply);
@@ -59,9 +61,15 @@ int ssh_client_dhgex_init(ssh_session session){
goto error;
}
+ session->next_crypto->dh_pmin = PMIN;
+ session->next_crypto->dh_pn = 2048;
+ session->next_crypto->dh_pmax = 8192;
/* 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);
+ SSH2_MSG_KEX_DH_GEX_REQUEST,
+ session->next_crypto->dh_pmin,
+ session->next_crypto->dh_pn,
+ session->next_crypto->dh_pmax);
if (rc != SSH_OK){
goto error;
}
@@ -75,7 +83,7 @@ int ssh_client_dhgex_init(ssh_session session){
}
return rc;
error:
- ssh_dh_cleanup(session);
+ ssh_dh_cleanup(session->next_crypto);
return SSH_ERROR;
}
@@ -89,6 +97,9 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group){
bignum pmin1=NULL, one=NULL;
bignum_CTX ctx = bignum_ctx_new();
+ (void) type;
+ (void) user;
+
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_DH_GEX_GROUP received");
if (bignum_ctx_invalid(ctx)) {
@@ -114,8 +125,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 < 1534 || blen > 8192){
- ssh_set_error(session, SSH_FATAL, "Invalid dh group parameter p: %d not in [1534:8192]", blen);
+ if (blen < PMIN || blen > 8192){
+ ssh_set_error(session, SSH_FATAL, "Invalid dh group parameter p: %d not in [%d:8192]", blen, PMIN);
goto error;
}
if (bignum_cmp(session->next_crypto->p, one) <= 0){
@@ -139,6 +150,11 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group){
if (rc == SSH_ERROR){
goto error;
}
+ session->next_crypto->e = bignum_new();
+ if (session->next_crypto->e == NULL){
+ ssh_set_error_oom(session);
+ goto error;
+ }
bignum_mod_exp(session->next_crypto->e, session->next_crypto->g, session->next_crypto->x,
session->next_crypto->p, ctx);
@@ -159,7 +175,7 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group){
error:
bignum_safe_free(one);
bignum_safe_free(pmin1);
- ssh_dh_cleanup(session);
+ ssh_dh_cleanup(session->next_crypto);
session->session_state=SSH_SESSION_STATE_ERROR;
return SSH_PACKET_USED;
}
@@ -197,10 +213,9 @@ static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_reply) {
}
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);
+ ssh_dh_cleanup(session->next_crypto);
session->session_state=SSH_SESSION_STATE_ERROR;
return SSH_PACKET_USED;
}
@@ -358,6 +373,8 @@ static int ssh_retrieve_dhgroup(int pmin, int pn, int pmax, int *size, bignum *p
if (*size == 0){
return SSH_ERROR;
}
+ *p=NULL;
+ *g=NULL;
rc = bignum_hex2bn(generator, g);
if (rc == 0){
goto error;
@@ -379,13 +396,14 @@ error:
}
static SSH_PACKET_CALLBACK(ssh_packet_server_dhgex_request);
+static SSH_PACKET_CALLBACK(ssh_packet_server_dhgex_init);
static ssh_packet_callback dhgex_server_callbacks[]= {
NULL, /* SSH_MSG_KEX_DH_GEX_REQUEST_OLD */
NULL, /* SSH_MSG_KEX_DH_GEX_GROUP */
- NULL, /* SSH_MSG_KEX_DH_GEX_INIT */
- NULL, /* SSH_MSG_KEX_DH_GEX_REPLY */
- ssh_packet_server_dhgex_request
+ ssh_packet_server_dhgex_init, /* SSH_MSG_KEX_DH_GEX_INIT */
+ NULL, /* SSH_MSG_KEX_DH_GEX_REPLY */
+ ssh_packet_server_dhgex_request /* SSH_MSG_GEX_DH_GEX_REQUEST */
};
static struct ssh_packet_callbacks_struct ssh_dhgex_server_callbacks = {
@@ -402,9 +420,78 @@ void ssh_server_dhgex_init(ssh_session session){
/* register the packet callbacks */
ssh_packet_set_callbacks(session, &ssh_dhgex_server_callbacks);
ssh_dh_init_common(session);
+ session->dh_handshake_state = DH_STATE_INIT;
}
static SSH_PACKET_CALLBACK(ssh_packet_server_dhgex_request){
+ int pmin, pn, pmax;
+ int size = 0;
+ int rc;
+
+ (void) type;
+ (void) user;
+ if (session->dh_handshake_state != DH_STATE_INIT){
+ ssh_set_error(session, SSH_FATAL, "Received DH_GEX_REQUEST in invalid state");
+ goto error;
+ }
+
+ rc = ssh_dh_init_common(session);
+ if (rc != SSH_OK){
+ goto error;
+ }
+
+ /* Minimum group size, preferred group size, maximum group size */
+ rc = ssh_buffer_unpack(packet, "ddd", &pmin, &pn, &pmax);
+ if (rc != SSH_OK){
+ goto error;
+ }
+ SSH_LOG(SSH_LOG_INFO, "dh-gex: DHGEX_REQUEST[%d:%d:%d]", pmin, pn, pmax);
+ if (pmin > pn || pn > pmax || pn > pmax || pmax < PMIN){
+ ssh_set_error(session, SSH_FATAL, "Invalid dh-gex arguments [%d:%d:%d]", pmin, pn, pmax);
+ goto error;
+ }
+ session->next_crypto->dh_pmin = pmin;
+ session->next_crypto->dh_pn = pn;
+ session->next_crypto->dh_pmax = pmax;
+
+ /* ensure safe parameters */
+ if (pmin < PMIN){
+ pmin = PMIN;
+ if (pn < pmin){
+ pn = pmin;
+ }
+ }
+ rc = ssh_retrieve_dhgroup(pmin, pn, pmax, &size, &session->next_crypto->p, &session->next_crypto->g);
+ if (rc == SSH_ERROR){
+ ssh_set_error(session, SSH_FATAL, "Couldn't find DH group for [%d:%d:%d]", pmin, pn, pmax);
+ goto error;
+ }
+ session->next_crypto->dh_group_is_mutable = 1;
+ rc = ssh_buffer_pack(session->out_buffer, "bBB", SSH2_MSG_KEX_DH_GEX_GROUP,
+ session->next_crypto->p, session->next_crypto->g);
+ if (rc != SSH_OK) {
+ goto error;
+ }
+
+ session->dh_handshake_state = DH_STATE_GROUP_SENT;
+
+ rc = ssh_packet_send(session);
+error:
+
+ return SSH_PACKET_USED;
+}
+
+/** @internal
+ * @brief parse an incoming SSH_MSG_KEX_DH_GEX_INIT packet and complete
+ * Diffie-Hellman key exchange
+ **/
+static SSH_PACKET_CALLBACK(ssh_packet_server_dhgex_init){
+
+ (void) type;
+ (void) user;
+ SSH_LOG(SSH_LOG_DEBUG, "Received SSH_MSG_KEX_DHGEX_INIT");
+ ssh_packet_remove_callbacks(session, &ssh_dhgex_server_callbacks);
+ ssh_server_dh_process_init(session, packet);
return SSH_PACKET_USED;
}