[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] kex: server fix to include first_kex_packet_follows


On 3/27/14, 2:45 AM, Andreas Schneider wrote:
>> Attached is a patch which fixes a host key signature validation bug that can
>> be hit when testing with dropbear clients at or beyond version 2013.57. 
>> The issue is that dropbear now always sets the 'first_kex_packet_follows'
>> field in its KEXINIT message.  Until now libssh would assume this field is
>> zero; but, it needs to be used when computing the session ID.
>>
>> Before the patch I'm able to hit 'Bad hostkey signature' errors with
>> dbclient; after, dbclient is working for me.
...
> I have a small request, as you're already touch code, I would like to see:
> 
> instead of:
> 
>   if (buffer_add_u32(server_hash, 0) < 0) {
> 
> I would like to have:
> 
>   int rc;
> 
>   rc = buffer_add_u32(server_hash, 0);
>   if (rc < 0) {
> 
> This is the code style we should have everywhere. I could just fix it in your 
> patch and push it, but I don't know if you're fine with that. So it would be 
> great if you could change it and resend the patch.

Thanks for the review, Andreas, and whoops -- I should have remembered
to do this.  I've gone ahead and added explicit 'rc' usage throughout
both the 'ssh_packet_kexinit' and 'make_sessionid' functions.  There
should be no change in functionality from the first patch.  I also took
the liberty to make those functions both use softabs of 4 spaces for
indentation, throughout.

Attached is an updated patch.


Thanks Again,
-Jon
From ba2f710d99d9314bee17e7e3ca028d88f7f74d2f Mon Sep 17 00:00:00 2001
From: Jon Simons <jon@xxxxxxxxxxxxx>
Date: Thu, 27 Mar 2014 17:20:07 -0700
Subject: [PATCH] kex: server fix to include first_kex_packet_follows

Ensure to honor the 'first_kex_packet_follow' field when processing
KEXINIT messages in the 'ssh_packet_kexinit' callback.  Until now
libssh would assume that this field is always unset (zero).  But
some clients may set this (dropbear at or beyond version 2013.57),
and it needs to be included when computing the session ID.

While here, update both 'ssh_packet_kexinit' and 'make_sessionid' to
use softabs with a 4 space indent level throughout, and also convert
various error-checking to store intermediate values into an explicit
'rc'.

Signed-off-by: Jon Simons <jon@xxxxxxxxxxxxx>
---
 src/dh.c  | 358 ++++++++++++++++++++++++++++++++------------------------------
 src/kex.c | 165 ++++++++++++++++++-----------
 2 files changed, 288 insertions(+), 235 deletions(-)

diff --git a/src/dh.c b/src/dh.c
index 3c2e5ad..7bc6cb3 100644
--- a/src/dh.c
+++ b/src/dh.c
@@ -587,218 +587,234 @@ error:
   return SSH_ERROR;
 }
 
-
-/*
-static void sha_add(ssh_string str,SHACTX ctx){
-    sha1_update(ctx,str,string_len(str)+4);
-#ifdef DEBUG_CRYPTO
-    ssh_print_hexa("partial hashed sessionid",str,string_len(str)+4);
-#endif
-}
-*/
-
 int make_sessionid(ssh_session session) {
-  ssh_string num = NULL;
-  ssh_string str = NULL;
-  ssh_buffer server_hash = NULL;
-  ssh_buffer client_hash = NULL;
-  ssh_buffer buf = NULL;
-  uint32_t len;
-  int rc = SSH_ERROR;
-
-  buf = ssh_buffer_new();
-  if (buf == NULL) {
-    return rc;
-  }
-
-  str = ssh_string_from_char(session->clientbanner);
-  if (str == NULL) {
-    goto error;
-  }
-
-  if (buffer_add_ssh_string(buf, str) < 0) {
-    goto error;
-  }
-  ssh_string_free(str);
-
-  str = ssh_string_from_char(session->serverbanner);
-  if (str == NULL) {
-    goto error;
-  }
-
-  if (buffer_add_ssh_string(buf, str) < 0) {
-    goto error;
-  }
-
-  if (session->client) {
-    server_hash = session->in_hashbuf;
-    client_hash = session->out_hashbuf;
-  } else {
-    server_hash = session->out_hashbuf;
-    client_hash = session->in_hashbuf;
-  }
+    ssh_string num = NULL;
+    ssh_string str = NULL;
+    ssh_buffer server_hash = NULL;
+    ssh_buffer client_hash = NULL;
+    ssh_buffer buf = NULL;
+    uint32_t len;
+    int rc = SSH_ERROR;
+
+    buf = ssh_buffer_new();
+    if (buf == NULL) {
+        return rc;
+    }
 
-  if (buffer_add_u32(server_hash, 0) < 0) {
-    goto error;
-  }
-  if (buffer_add_u8(server_hash, 0) < 0) {
-    goto error;
-  }
-  if (buffer_add_u32(client_hash, 0) < 0) {
-    goto error;
-  }
-  if (buffer_add_u8(client_hash, 0) < 0) {
-    goto error;
-  }
+    str = ssh_string_from_char(session->clientbanner);
+    if (str == NULL) {
+        goto error;
+    }
 
-  len = ntohl(buffer_get_rest_len(client_hash));
-  if (buffer_add_u32(buf,len) < 0) {
-    goto error;
-  }
-  if (buffer_add_data(buf, buffer_get_rest(client_hash),
-        buffer_get_rest_len(client_hash)) < 0) {
-    goto error;
-  }
+    rc = buffer_add_ssh_string(buf, str);
+    if (rc < 0) {
+        goto error;
+    }
+    ssh_string_free(str);
 
-  len = ntohl(buffer_get_rest_len(server_hash));
-  if (buffer_add_u32(buf, len) < 0) {
-    goto error;
-  }
-  if (buffer_add_data(buf, buffer_get_rest(server_hash),
-        buffer_get_rest_len(server_hash)) < 0) {
-    goto error;
-  }
+    str = ssh_string_from_char(session->serverbanner);
+    if (str == NULL) {
+        goto error;
+    }
 
-  len = ssh_string_len(session->next_crypto->server_pubkey) + 4;
-  if (buffer_add_data(buf, session->next_crypto->server_pubkey, len) < 0) {
-    goto error;
-  }
-  if(session->next_crypto->kex_type == SSH_KEX_DH_GROUP1_SHA1 ||
-     session->next_crypto->kex_type == SSH_KEX_DH_GROUP14_SHA1) {
+    rc = buffer_add_ssh_string(buf, str);
+    if (rc < 0) {
+        goto error;
+    }
 
-    num = make_bignum_string(session->next_crypto->e);
-    if (num == NULL) {
-      goto error;
+    if (session->client) {
+        server_hash = session->in_hashbuf;
+        client_hash = session->out_hashbuf;
+    } else {
+        server_hash = session->out_hashbuf;
+        client_hash = session->in_hashbuf;
     }
 
-    len = ssh_string_len(num) + 4;
-    if (buffer_add_data(buf, num, len) < 0) {
-      goto error;
+    /*
+     * Handle the two final fields for the KEXINIT message (RFC 4253 7.1):
+     *
+     *      boolean      first_kex_packet_follows
+     *      uint32       0 (reserved for future extension)
+     */
+    rc = buffer_add_u8(server_hash, 0);
+    if (rc < 0) {
+        goto error;
+    }
+    rc = buffer_add_u32(server_hash, 0);
+    if (rc < 0) {
+        goto error;
     }
 
-    ssh_string_free(num);
-    num = make_bignum_string(session->next_crypto->f);
-    if (num == NULL) {
-      goto error;
+    /* These fields are handled for the server case in ssh_packet_kexinit. */
+    if (session->client) {
+        rc = buffer_add_u8(client_hash, 0);
+        if (rc < 0) {
+            goto error;
+        }
+        rc = buffer_add_u32(client_hash, 0);
+        if (rc < 0) {
+            goto error;
+        }
     }
 
-    len = ssh_string_len(num) + 4;
-    if (buffer_add_data(buf, num, len) < 0) {
-      goto error;
+    len = ntohl(buffer_get_rest_len(client_hash));
+    rc = buffer_add_u32(buf,len);
+    if (rc < 0) {
+        goto error;
+    }
+    rc = buffer_add_data(buf, buffer_get_rest(client_hash),
+                              buffer_get_rest_len(client_hash));
+    if (rc < 0) {
+        goto error;
     }
 
-    ssh_string_free(num);
-#ifdef HAVE_ECDH
-  } else if (session->next_crypto->kex_type == SSH_KEX_ECDH_SHA2_NISTP256){
-    if(session->next_crypto->ecdh_client_pubkey == NULL ||
-            session->next_crypto->ecdh_server_pubkey == NULL){
-        SSH_LOG(SSH_LOG_WARNING, "ECDH parameted missing");
+    len = ntohl(buffer_get_rest_len(server_hash));
+    rc = buffer_add_u32(buf, len);
+    if (rc < 0) {
         goto error;
     }
-    rc = buffer_add_ssh_string(buf,session->next_crypto->ecdh_client_pubkey);
+    rc = buffer_add_data(buf, buffer_get_rest(server_hash),
+                              buffer_get_rest_len(server_hash));
     if (rc < 0) {
         goto error;
     }
-    rc = buffer_add_ssh_string(buf,session->next_crypto->ecdh_server_pubkey);
+
+    len = ssh_string_len(session->next_crypto->server_pubkey) + 4;
+    rc = buffer_add_data(buf, session->next_crypto->server_pubkey, len);
     if (rc < 0) {
         goto error;
     }
+
+    if (session->next_crypto->kex_type == SSH_KEX_DH_GROUP1_SHA1 ||
+        session->next_crypto->kex_type == SSH_KEX_DH_GROUP14_SHA1) {
+
+        num = make_bignum_string(session->next_crypto->e);
+        if (num == NULL) {
+            goto error;
+        }
+
+        len = ssh_string_len(num) + 4;
+        rc = buffer_add_data(buf, num, len);
+        if (rc < 0) {
+            goto error;
+        }
+
+        ssh_string_free(num);
+        num = make_bignum_string(session->next_crypto->f);
+        if (num == NULL) {
+            goto error;
+        }
+
+        len = ssh_string_len(num) + 4;
+        rc = buffer_add_data(buf, num, len);
+        if (rc < 0) {
+          goto error;
+        }
+
+        ssh_string_free(num);
+#ifdef HAVE_ECDH
+    } else if (session->next_crypto->kex_type == SSH_KEX_ECDH_SHA2_NISTP256) {
+        if (session->next_crypto->ecdh_client_pubkey == NULL ||
+            session->next_crypto->ecdh_server_pubkey == NULL) {
+            SSH_LOG(SSH_LOG_WARNING, "ECDH parameted missing");
+            goto error;
+        }
+        rc = buffer_add_ssh_string(buf,session->next_crypto->ecdh_client_pubkey);
+        if (rc < 0) {
+            goto error;
+        }
+        rc = buffer_add_ssh_string(buf,session->next_crypto->ecdh_server_pubkey);
+        if (rc < 0) {
+            goto error;
+        }
 #endif
 #ifdef HAVE_CURVE25519
-  } else if(session->next_crypto->kex_type == SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG){
-	  rc = buffer_add_u32(buf, htonl(CURVE25519_PUBKEY_SIZE));
-	  rc += buffer_add_data(buf, session->next_crypto->curve25519_client_pubkey,
-			  CURVE25519_PUBKEY_SIZE);
-	  rc += buffer_add_u32(buf, htonl(CURVE25519_PUBKEY_SIZE));
-	  rc += buffer_add_data(buf, session->next_crypto->curve25519_server_pubkey,
-			  CURVE25519_PUBKEY_SIZE);
-	  if (rc != SSH_OK) {
-		  goto error;
-      }
+    } else if (session->next_crypto->kex_type == SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG) {
+        rc = buffer_add_u32(buf, htonl(CURVE25519_PUBKEY_SIZE));
+        rc += buffer_add_data(buf, session->next_crypto->curve25519_client_pubkey,
+                                   CURVE25519_PUBKEY_SIZE);
+        rc += buffer_add_u32(buf, htonl(CURVE25519_PUBKEY_SIZE));
+        rc += buffer_add_data(buf, session->next_crypto->curve25519_server_pubkey,
+                                   CURVE25519_PUBKEY_SIZE);
+        if (rc != SSH_OK) {
+                goto error;
+        }
 #endif
-  }
-  num = make_bignum_string(session->next_crypto->k);
-  if (num == NULL) {
-    goto error;
-  }
+    }
 
-  len = ssh_string_len(num) + 4;
-  if (buffer_add_data(buf, num, len) < 0) {
-    goto error;
-  }
+    num = make_bignum_string(session->next_crypto->k);
+    if (num == NULL) {
+        goto error;
+    }
+
+    len = ssh_string_len(num) + 4;
+    rc = buffer_add_data(buf, num, len);
+    if (rc < 0) {
+        goto error;
+    }
 
 #ifdef DEBUG_CRYPTO
-  ssh_print_hexa("hash buffer", ssh_buffer_get_begin(buf), ssh_buffer_get_len(buf));
+    ssh_print_hexa("hash buffer", ssh_buffer_get_begin(buf), ssh_buffer_get_len(buf));
 #endif
 
-  switch(session->next_crypto->kex_type){
+    switch (session->next_crypto->kex_type) {
     case SSH_KEX_DH_GROUP1_SHA1:
     case SSH_KEX_DH_GROUP14_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);
-      if(session->next_crypto->secret_hash == NULL){
-        ssh_set_error_oom(session);
-        goto error;
-      }
-      sha1(buffer_get_rest(buf), buffer_get_rest_len(buf),
-                session->next_crypto->secret_hash);
-      break;
+        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);
+        if (session->next_crypto->secret_hash == NULL) {
+            ssh_set_error_oom(session);
+            goto error;
+        }
+        sha1(buffer_get_rest(buf), buffer_get_rest_len(buf),
+                                   session->next_crypto->secret_hash);
+        break;
     case SSH_KEX_ECDH_SHA2_NISTP256:
     case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
-      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);
-      if(session->next_crypto->secret_hash == NULL){
-        ssh_set_error_oom(session);
-        goto error;
-      }
-      sha256(buffer_get_rest(buf), buffer_get_rest_len(buf),
-          session->next_crypto->secret_hash);
-      break;
-  }
-  /* During the first kex, secret hash and session ID are equal. However, after
-   * a key re-exchange, a new secret hash is calculated. This hash will not replace
-   * but complement existing session id.
-   */
-  if (!session->next_crypto->session_id){
-      session->next_crypto->session_id = malloc(session->next_crypto->digest_len);
-      if (session->next_crypto->session_id == NULL){
-          ssh_set_error_oom(session);
-          goto error;
-      }
-      memcpy(session->next_crypto->session_id, session->next_crypto->secret_hash,
-              session->next_crypto->digest_len);
-  }
+        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);
+        if (session->next_crypto->secret_hash == NULL) {
+            ssh_set_error_oom(session);
+            goto error;
+        }
+        sha256(buffer_get_rest(buf), buffer_get_rest_len(buf),
+                                     session->next_crypto->secret_hash);
+        break;
+    }
+    /* During the first kex, secret hash and session ID are equal. However, after
+     * a key re-exchange, a new secret hash is calculated. This hash will not replace
+     * but complement existing session id.
+     */
+    if (!session->next_crypto->session_id) {
+        session->next_crypto->session_id = malloc(session->next_crypto->digest_len);
+        if (session->next_crypto->session_id == NULL) {
+            ssh_set_error_oom(session);
+            goto error;
+        }
+        memcpy(session->next_crypto->session_id, session->next_crypto->secret_hash,
+                session->next_crypto->digest_len);
+    }
 #ifdef DEBUG_CRYPTO
-  printf("Session hash: \n");
-  ssh_print_hexa("secret hash", session->next_crypto->secret_hash, session->next_crypto->digest_len);
-  ssh_print_hexa("session id", session->next_crypto->session_id, session->next_crypto->digest_len);
+    printf("Session hash: \n");
+    ssh_print_hexa("secret hash", session->next_crypto->secret_hash, session->next_crypto->digest_len);
+    ssh_print_hexa("session id", session->next_crypto->session_id, session->next_crypto->digest_len);
 #endif
 
-  rc = SSH_OK;
+    rc = SSH_OK;
 error:
-  ssh_buffer_free(buf);
-  ssh_buffer_free(client_hash);
-  ssh_buffer_free(server_hash);
+    ssh_buffer_free(buf);
+    ssh_buffer_free(client_hash);
+    ssh_buffer_free(server_hash);
 
-  session->in_hashbuf = NULL;
-  session->out_hashbuf = NULL;
+    session->in_hashbuf = NULL;
+    session->out_hashbuf = NULL;
 
-  ssh_string_free(str);
-  ssh_string_free(num);
+    ssh_string_free(str);
+    ssh_string_free(num);
 
-  return rc;
+    return rc;
 }
 
 int hashbufout_add_cookie(ssh_session session) {
diff --git a/src/kex.c b/src/kex.c
index 563c6a5..02848d0 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -276,86 +276,123 @@ char *ssh_find_matching(const char *available_d, const char *preferred_d){
 }
 
 SSH_PACKET_CALLBACK(ssh_packet_kexinit){
-	int server_kex=session->server;
-  ssh_string str = NULL;
-  char *strings[KEX_METHODS_SIZE];
-  int i;
-
-  (void)type;
-  (void)user;
-  memset(strings, 0, sizeof(strings));
-  if (session->session_state == SSH_SESSION_STATE_AUTHENTICATED){
-      SSH_LOG(SSH_LOG_WARNING, "Other side initiating key re-exchange");
-  } else if(session->session_state != SSH_SESSION_STATE_INITIAL_KEX){
-  	ssh_set_error(session,SSH_FATAL,"SSH_KEXINIT received in wrong state");
-  	goto error;
-  }
-  if (server_kex) {
-      if (buffer_get_data(packet,session->next_crypto->client_kex.cookie,16) != 16) {
-        ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: no cookie in packet");
+    int i;
+    int server_kex=session->server;
+    ssh_string str = NULL;
+    char *strings[KEX_METHODS_SIZE];
+    int rc = SSH_ERROR;
+
+    uint8_t first_kex_packet_follows = 0;
+    uint32_t kexinit_reserved = 0;
+
+    (void)type;
+    (void)user;
+
+    memset(strings, 0, sizeof(strings));
+    if (session->session_state == SSH_SESSION_STATE_AUTHENTICATED){
+        SSH_LOG(SSH_LOG_WARNING, "Other side initiating key re-exchange");
+    } else if(session->session_state != SSH_SESSION_STATE_INITIAL_KEX){
+        ssh_set_error(session,SSH_FATAL,"SSH_KEXINIT received in wrong state");
         goto error;
-      }
+    }
 
-      if (hashbufin_add_cookie(session, session->next_crypto->client_kex.cookie) < 0) {
-        ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: adding cookie failed");
-        goto error;
-      }
-  } else {
-      if (buffer_get_data(packet,session->next_crypto->server_kex.cookie,16) != 16) {
-        ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: no cookie in packet");
-        goto error;
-      }
+    if (server_kex) {
+        rc = buffer_get_data(packet,session->next_crypto->client_kex.cookie, 16);
+        if (rc != 16) {
+            ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: no cookie in packet");
+            goto error;
+        }
 
-      if (hashbufin_add_cookie(session, session->next_crypto->server_kex.cookie) < 0) {
-        ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: adding cookie failed");
-        goto error;
-      }
-  }
+        rc = hashbufin_add_cookie(session, session->next_crypto->client_kex.cookie);
+        if (rc < 0) {
+            ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: adding cookie failed");
+            goto error;
+        }
+    } else {
+        rc = buffer_get_data(packet,session->next_crypto->server_kex.cookie, 16);
+        if (rc != 16) {
+            ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: no cookie in packet");
+            goto error;
+        }
 
-  for (i = 0; i < KEX_METHODS_SIZE; i++) {
-    str = buffer_get_ssh_string(packet);
-    if (str == NULL) {
-      break;
+        rc = hashbufin_add_cookie(session, session->next_crypto->server_kex.cookie);
+        if (rc < 0) {
+            ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: adding cookie failed");
+            goto error;
+        }
     }
 
-    if (buffer_add_ssh_string(session->in_hashbuf, str) < 0) {
-    	ssh_set_error(session, SSH_FATAL, "Error adding string in hash buffer");
-      goto error;
+    for (i = 0; i < KEX_METHODS_SIZE; i++) {
+        str = buffer_get_ssh_string(packet);
+        if (str == NULL) {
+          break;
+        }
+
+        rc = buffer_add_ssh_string(session->in_hashbuf, str);
+        if (rc < 0) {
+            ssh_set_error(session, SSH_FATAL, "Error adding string in hash buffer");
+            goto error;
+        }
+
+        strings[i] = ssh_string_to_char(str);
+        if (strings[i] == NULL) {
+            ssh_set_error_oom(session);
+            goto error;
+        }
+        ssh_string_free(str);
+        str = NULL;
     }
 
-    strings[i] = ssh_string_to_char(str);
-    if (strings[i] == NULL) {
-    	ssh_set_error_oom(session);
-      goto error;
+    /* copy the server kex info into an array of strings */
+    if (server_kex) {
+        for (i = 0; i < SSH_KEX_METHODS; i++) {
+            session->next_crypto->client_kex.methods[i] = strings[i];
+        }
+    } else { /* client */
+        for (i = 0; i < SSH_KEX_METHODS; i++) {
+            session->next_crypto->server_kex.methods[i] = strings[i];
+        }
     }
-    ssh_string_free(str);
-    str = NULL;
-  }
 
-  /* copy the server kex info into an array of strings */
-  if (server_kex) {
-    for (i = 0; i < SSH_KEX_METHODS; i++) {
-      session->next_crypto->client_kex.methods[i] = strings[i];
+    /*
+     * Handle the two final fields for the KEXINIT message (RFC 4253 7.1):
+     *
+     *      boolean      first_kex_packet_follows
+     *      uint32       0 (reserved for future extension)
+     *
+     * Notably if clients set 'first_kex_packet_follows', it is expected
+     * that its value is included when computing the session ID (see
+     * 'make_sessionid').
+     */
+    rc = buffer_get_u8(packet, &first_kex_packet_follows);
+    if (rc != 1) {
+        goto error;
     }
-  } else { /* client */
-    for (i = 0; i < SSH_KEX_METHODS; i++) {
-      session->next_crypto->server_kex.methods[i] = strings[i];
+
+    rc = buffer_add_u8(session->in_hashbuf, first_kex_packet_follows);
+    if (rc < 0) {
+        goto error;
+    }
+
+    rc = buffer_add_u32(session->in_hashbuf, kexinit_reserved);
+    if (rc < 0) {
+        goto error;
     }
-  }
 
-  session->session_state=SSH_SESSION_STATE_KEXINIT_RECEIVED;
-  session->dh_handshake_state=DH_STATE_INIT;
-  session->ssh_connection_callback(session);
-  return SSH_PACKET_USED;
+    session->session_state = SSH_SESSION_STATE_KEXINIT_RECEIVED;
+    session->dh_handshake_state = DH_STATE_INIT;
+    session->ssh_connection_callback(session);
+    return SSH_PACKET_USED;
+
 error:
-  ssh_string_free(str);
-  for (i = 0; i < SSH_KEX_METHODS; i++) {
-    SAFE_FREE(strings[i]);
-  }
+    ssh_string_free(str);
+    for (i = 0; i < SSH_KEX_METHODS; i++) {
+        SAFE_FREE(strings[i]);
+    }
 
-  session->session_state = SSH_SESSION_STATE_ERROR;
+    session->session_state = SSH_SESSION_STATE_ERROR;
 
-  return SSH_PACKET_USED;
+    return SSH_PACKET_USED;
 }
 
 void ssh_list_kex(struct ssh_kex_struct *kex) {
-- 
1.8.4.21.g992c386


References:
[PATCH] kex: server fix to include first_kex_packet_followsJon Simons <jon@xxxxxxxxxxxxx>
Re: [PATCH] kex: server fix to include first_kex_packet_followsAndreas Schneider <asn@xxxxxxxxxxxxxx>
Archive administrator: postmaster@lists.cynapses.org