|
@@ -1,467 +0,0 @@
|
|
|
-From 3a80751dce7b7d98b9d9006fb37213a1e4af7ac5 Mon Sep 17 00:00:00 2001
|
|
|
-From: Michael Buckley <michael@buckleyisms.com>
|
|
|
-Date: Thu, 30 Nov 2023 15:08:02 -0800
|
|
|
-Subject: [PATCH] src: add 'strict KEX' to fix CVE-2023-48795 "Terrapin Attack"
|
|
|
-
|
|
|
-Refs:
|
|
|
-https://terrapin-attack.com/
|
|
|
-https://seclists.org/oss-sec/2023/q4/292
|
|
|
-https://osv.dev/list?ecosystem=&q=CVE-2023-48795
|
|
|
-https://github.com/advisories/GHSA-45x7-px36-x8w8
|
|
|
-https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-48795
|
|
|
-
|
|
|
-Fixes #1290
|
|
|
-Closes #1291
|
|
|
-
|
|
|
-Upstream: https://github.com/libssh2/libssh2/commit/d34d9258b8420b19ec3f97b4cc5bf7aa7d98e35a
|
|
|
-Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
|
|
|
-[Dario: make the patch to be applied with fuzz factor 0]
|
|
|
-Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
|
|
|
----
|
|
|
- src/kex.c | 63 +++++++++++++++++++++++------------
|
|
|
- src/libssh2_priv.h | 18 +++++++---
|
|
|
- src/packet.c | 83 +++++++++++++++++++++++++++++++++++++++++++---
|
|
|
- src/packet.h | 2 +-
|
|
|
- src/session.c | 3 ++
|
|
|
- src/transport.c | 12 ++++++-
|
|
|
- 6 files changed, 149 insertions(+), 32 deletions(-)
|
|
|
-
|
|
|
-diff --git a/src/kex.c b/src/kex.c
|
|
|
-index d4034a0a953e..b4b748cac4ee 100644
|
|
|
---- a/src/kex.c
|
|
|
-+++ b/src/kex.c
|
|
|
-@@ -3037,6 +3037,13 @@ kex_method_extension_negotiation = {
|
|
|
- 0,
|
|
|
- };
|
|
|
-
|
|
|
-+static const LIBSSH2_KEX_METHOD
|
|
|
-+kex_method_strict_client_extension = {
|
|
|
-+ "kex-strict-c-v00@openssh.com",
|
|
|
-+ NULL,
|
|
|
-+ 0,
|
|
|
-+};
|
|
|
-+
|
|
|
- static const LIBSSH2_KEX_METHOD *libssh2_kex_methods[] = {
|
|
|
- #if LIBSSH2_ED25519
|
|
|
- &kex_method_ssh_curve25519_sha256,
|
|
|
-@@ -3055,6 +3062,7 @@ static const LIBSSH2_KEX_METHOD *libssh2_kex_methods[] = {
|
|
|
- &kex_method_diffie_helman_group1_sha1,
|
|
|
- &kex_method_diffie_helman_group_exchange_sha1,
|
|
|
- &kex_method_extension_negotiation,
|
|
|
-+ &kex_method_strict_client_extension,
|
|
|
- NULL
|
|
|
- };
|
|
|
-
|
|
|
-@@ -3307,13 +3315,13 @@ static int kexinit(LIBSSH2_SESSION * session)
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
--/* kex_agree_instr
|
|
|
-+/* _libssh2_kex_agree_instr
|
|
|
- * Kex specific variant of strstr()
|
|
|
- * Needle must be preceded by BOL or ',', and followed by ',' or EOL
|
|
|
- */
|
|
|
--static unsigned char *
|
|
|
--kex_agree_instr(unsigned char *haystack, size_t haystack_len,
|
|
|
-- const unsigned char *needle, size_t needle_len)
|
|
|
-+unsigned char *
|
|
|
-+_libssh2_kex_agree_instr(unsigned char *haystack, size_t haystack_len,
|
|
|
-+ const unsigned char *needle, size_t needle_len)
|
|
|
- {
|
|
|
- unsigned char *s;
|
|
|
- unsigned char *end_haystack;
|
|
|
-@@ -3398,7 +3406,7 @@ static int kex_agree_hostkey(LIBSSH2_SESSION * session,
|
|
|
- while(s && *s) {
|
|
|
- unsigned char *p = (unsigned char *) strchr((char *) s, ',');
|
|
|
- size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s));
|
|
|
-- if(kex_agree_instr(hostkey, hostkey_len, s, method_len)) {
|
|
|
-+ if(_libssh2_kex_agree_instr(hostkey, hostkey_len, s, method_len)) {
|
|
|
- const LIBSSH2_HOSTKEY_METHOD *method =
|
|
|
- (const LIBSSH2_HOSTKEY_METHOD *)
|
|
|
- kex_get_method_by_name((char *) s, method_len,
|
|
|
-@@ -3432,9 +3440,9 @@ static int kex_agree_hostkey(LIBSSH2_SESSION * session,
|
|
|
- }
|
|
|
-
|
|
|
- while(hostkeyp && (*hostkeyp) && (*hostkeyp)->name) {
|
|
|
-- s = kex_agree_instr(hostkey, hostkey_len,
|
|
|
-- (unsigned char *) (*hostkeyp)->name,
|
|
|
-- strlen((*hostkeyp)->name));
|
|
|
-+ s = _libssh2_kex_agree_instr(hostkey, hostkey_len,
|
|
|
-+ (unsigned char *) (*hostkeyp)->name,
|
|
|
-+ strlen((*hostkeyp)->name));
|
|
|
- if(s) {
|
|
|
- /* So far so good, but does it suit our purposes? (Encrypting vs
|
|
|
- Signing) */
|
|
|
-@@ -3468,6 +3476,12 @@ static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex,
|
|
|
- {
|
|
|
- const LIBSSH2_KEX_METHOD **kexp = libssh2_kex_methods;
|
|
|
- unsigned char *s;
|
|
|
-+ const unsigned char *strict =
|
|
|
-+ (unsigned char *)"kex-strict-s-v00@openssh.com";
|
|
|
-+
|
|
|
-+ if(_libssh2_kex_agree_instr(kex, kex_len, strict, 28)) {
|
|
|
-+ session->kex_strict = 1;
|
|
|
-+ }
|
|
|
-
|
|
|
- if(session->kex_prefs) {
|
|
|
- s = (unsigned char *) session->kex_prefs;
|
|
|
-@@ -3475,7 +3489,7 @@ static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex,
|
|
|
- while(s && *s) {
|
|
|
- unsigned char *q, *p = (unsigned char *) strchr((char *) s, ',');
|
|
|
- size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s));
|
|
|
-- q = kex_agree_instr(kex, kex_len, s, method_len);
|
|
|
-+ q = _libssh2_kex_agree_instr(kex, kex_len, s, method_len);
|
|
|
- if(q) {
|
|
|
- const LIBSSH2_KEX_METHOD *method = (const LIBSSH2_KEX_METHOD *)
|
|
|
- kex_get_method_by_name((char *) s, method_len,
|
|
|
-@@ -3509,9 +3523,9 @@ static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex,
|
|
|
- }
|
|
|
-
|
|
|
- while(*kexp && (*kexp)->name) {
|
|
|
-- s = kex_agree_instr(kex, kex_len,
|
|
|
-- (unsigned char *) (*kexp)->name,
|
|
|
-- strlen((*kexp)->name));
|
|
|
-+ s = _libssh2_kex_agree_instr(kex, kex_len,
|
|
|
-+ (unsigned char *) (*kexp)->name,
|
|
|
-+ strlen((*kexp)->name));
|
|
|
- if(s) {
|
|
|
- /* We've agreed on a key exchange method,
|
|
|
- * Can we agree on a hostkey that works with this kex?
|
|
|
-@@ -3555,7 +3569,7 @@ static int kex_agree_crypt(LIBSSH2_SESSION * session,
|
|
|
- unsigned char *p = (unsigned char *) strchr((char *) s, ',');
|
|
|
- size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s));
|
|
|
-
|
|
|
-- if(kex_agree_instr(crypt, crypt_len, s, method_len)) {
|
|
|
-+ if(_libssh2_kex_agree_instr(crypt, crypt_len, s, method_len)) {
|
|
|
- const LIBSSH2_CRYPT_METHOD *method =
|
|
|
- (const LIBSSH2_CRYPT_METHOD *)
|
|
|
- kex_get_method_by_name((char *) s, method_len,
|
|
|
-@@ -3577,9 +3591,9 @@ static int kex_agree_crypt(LIBSSH2_SESSION * session,
|
|
|
- }
|
|
|
-
|
|
|
- while(*cryptp && (*cryptp)->name) {
|
|
|
-- s = kex_agree_instr(crypt, crypt_len,
|
|
|
-- (unsigned char *) (*cryptp)->name,
|
|
|
-- strlen((*cryptp)->name));
|
|
|
-+ s = _libssh2_kex_agree_instr(crypt, crypt_len,
|
|
|
-+ (unsigned char *) (*cryptp)->name,
|
|
|
-+ strlen((*cryptp)->name));
|
|
|
- if(s) {
|
|
|
- endpoint->crypt = *cryptp;
|
|
|
- return 0;
|
|
|
-@@ -3619,7 +3633,7 @@ static int kex_agree_mac(LIBSSH2_SESSION * session,
|
|
|
- unsigned char *p = (unsigned char *) strchr((char *) s, ',');
|
|
|
- size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s));
|
|
|
-
|
|
|
-- if(kex_agree_instr(mac, mac_len, s, method_len)) {
|
|
|
-+ if(_libssh2_kex_agree_instr(mac, mac_len, s, method_len)) {
|
|
|
- const LIBSSH2_MAC_METHOD *method = (const LIBSSH2_MAC_METHOD *)
|
|
|
- kex_get_method_by_name((char *) s, method_len,
|
|
|
- (const LIBSSH2_COMMON_METHOD **)
|
|
|
-@@ -3640,8 +3654,9 @@ static int kex_agree_mac(LIBSSH2_SESSION * session,
|
|
|
- }
|
|
|
-
|
|
|
- while(*macp && (*macp)->name) {
|
|
|
-- s = kex_agree_instr(mac, mac_len, (unsigned char *) (*macp)->name,
|
|
|
-- strlen((*macp)->name));
|
|
|
-+ s = _libssh2_kex_agree_instr(mac, mac_len,
|
|
|
-+ (unsigned char *) (*macp)->name,
|
|
|
-+ strlen((*macp)->name));
|
|
|
- if(s) {
|
|
|
- endpoint->mac = *macp;
|
|
|
- return 0;
|
|
|
-@@ -3672,7 +3687,7 @@ static int kex_agree_comp(LIBSSH2_SESSION *session,
|
|
|
- unsigned char *p = (unsigned char *) strchr((char *) s, ',');
|
|
|
- size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s));
|
|
|
-
|
|
|
-- if(kex_agree_instr(comp, comp_len, s, method_len)) {
|
|
|
-+ if(_libssh2_kex_agree_instr(comp, comp_len, s, method_len)) {
|
|
|
- const LIBSSH2_COMP_METHOD *method =
|
|
|
- (const LIBSSH2_COMP_METHOD *)
|
|
|
- kex_get_method_by_name((char *) s, method_len,
|
|
|
-@@ -3694,8 +3709,9 @@ static int kex_agree_comp(LIBSSH2_SESSION *session,
|
|
|
- }
|
|
|
-
|
|
|
- while(*compp && (*compp)->name) {
|
|
|
-- s = kex_agree_instr(comp, comp_len, (unsigned char *) (*compp)->name,
|
|
|
-- strlen((*compp)->name));
|
|
|
-+ s = _libssh2_kex_agree_instr(comp, comp_len,
|
|
|
-+ (unsigned char *) (*compp)->name,
|
|
|
-+ strlen((*compp)->name));
|
|
|
- if(s) {
|
|
|
- endpoint->comp = *compp;
|
|
|
- return 0;
|
|
|
-@@ -3876,6 +3892,7 @@ _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
|
|
|
- session->local.kexinit = key_state->oldlocal;
|
|
|
- session->local.kexinit_len = key_state->oldlocal_len;
|
|
|
- key_state->state = libssh2_NB_state_idle;
|
|
|
-+ session->state &= ~LIBSSH2_STATE_INITIAL_KEX;
|
|
|
- session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
|
|
|
- session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
|
|
|
- return -1;
|
|
|
-@@ -3901,6 +3918,7 @@ _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
|
|
|
- session->local.kexinit = key_state->oldlocal;
|
|
|
- session->local.kexinit_len = key_state->oldlocal_len;
|
|
|
- key_state->state = libssh2_NB_state_idle;
|
|
|
-+ session->state &= ~LIBSSH2_STATE_INITIAL_KEX;
|
|
|
- session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
|
|
|
- session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
|
|
|
- return -1;
|
|
|
-@@ -3949,6 +3967,7 @@ _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
|
|
|
- session->remote.kexinit = NULL;
|
|
|
- }
|
|
|
-
|
|
|
-+ session->state &= ~LIBSSH2_STATE_INITIAL_KEX;
|
|
|
- session->state &= ~LIBSSH2_STATE_KEX_ACTIVE;
|
|
|
- session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
|
|
|
-
|
|
|
-diff --git a/src/libssh2_priv.h b/src/libssh2_priv.h
|
|
|
-index 82c3afe250b0..ee1d8b5c2b9b 100644
|
|
|
---- a/src/libssh2_priv.h
|
|
|
-+++ b/src/libssh2_priv.h
|
|
|
-@@ -699,6 +699,9 @@ struct _LIBSSH2_SESSION
|
|
|
- /* key signing algorithm preferences -- NULL yields server order */
|
|
|
- char *sign_algo_prefs;
|
|
|
-
|
|
|
-+ /* Whether to use the OpenSSH Strict KEX extension */
|
|
|
-+ int kex_strict;
|
|
|
-+
|
|
|
- /* (remote as source of data -- packet_read ) */
|
|
|
- libssh2_endpoint_data remote;
|
|
|
-
|
|
|
-@@ -870,6 +873,7 @@ struct _LIBSSH2_SESSION
|
|
|
- int fullpacket_macstate;
|
|
|
- size_t fullpacket_payload_len;
|
|
|
- int fullpacket_packet_type;
|
|
|
-+ uint32_t fullpacket_required_type;
|
|
|
-
|
|
|
- /* State variables used in libssh2_sftp_init() */
|
|
|
- libssh2_nonblocking_states sftpInit_state;
|
|
|
-@@ -910,10 +914,11 @@ struct _LIBSSH2_SESSION
|
|
|
- };
|
|
|
-
|
|
|
- /* session.state bits */
|
|
|
--#define LIBSSH2_STATE_EXCHANGING_KEYS 0x00000001
|
|
|
--#define LIBSSH2_STATE_NEWKEYS 0x00000002
|
|
|
--#define LIBSSH2_STATE_AUTHENTICATED 0x00000004
|
|
|
--#define LIBSSH2_STATE_KEX_ACTIVE 0x00000008
|
|
|
-+#define LIBSSH2_STATE_INITIAL_KEX 0x00000001
|
|
|
-+#define LIBSSH2_STATE_EXCHANGING_KEYS 0x00000002
|
|
|
-+#define LIBSSH2_STATE_NEWKEYS 0x00000004
|
|
|
-+#define LIBSSH2_STATE_AUTHENTICATED 0x00000008
|
|
|
-+#define LIBSSH2_STATE_KEX_ACTIVE 0x00000010
|
|
|
-
|
|
|
- /* session.flag helpers */
|
|
|
- #ifdef MSG_NOSIGNAL
|
|
|
-@@ -1144,6 +1149,11 @@ ssize_t _libssh2_send(libssh2_socket_t socket, const void *buffer,
|
|
|
- int _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange,
|
|
|
- key_exchange_state_t * state);
|
|
|
-
|
|
|
-+unsigned char *_libssh2_kex_agree_instr(unsigned char *haystack,
|
|
|
-+ size_t haystack_len,
|
|
|
-+ const unsigned char *needle,
|
|
|
-+ size_t needle_len);
|
|
|
-+
|
|
|
- /* Let crypt.c/hostkey.c expose their method structs */
|
|
|
- const LIBSSH2_CRYPT_METHOD **libssh2_crypt_methods(void);
|
|
|
- const LIBSSH2_HOSTKEY_METHOD **libssh2_hostkey_methods(void);
|
|
|
-diff --git a/src/packet.c b/src/packet.c
|
|
|
-index b5b41981a108..35d4d39eff87 100644
|
|
|
---- a/src/packet.c
|
|
|
-+++ b/src/packet.c
|
|
|
-@@ -605,14 +605,13 @@ authagent_exit:
|
|
|
- * layer when it has received a packet.
|
|
|
- *
|
|
|
- * The input pointer 'data' is pointing to allocated data that this function
|
|
|
-- * is asked to deal with so on failure OR success, it must be freed fine.
|
|
|
-- * The only exception is when the return code is LIBSSH2_ERROR_EAGAIN.
|
|
|
-+ * will be freed unless return the code is LIBSSH2_ERROR_EAGAIN.
|
|
|
- *
|
|
|
- * This function will always be called with 'datalen' greater than zero.
|
|
|
- */
|
|
|
- int
|
|
|
- _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
|
|
-- size_t datalen, int macstate)
|
|
|
-+ size_t datalen, int macstate, uint32_t seq)
|
|
|
- {
|
|
|
- int rc = 0;
|
|
|
- unsigned char *message = NULL;
|
|
|
-@@ -657,6 +656,70 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
-+ if(session->state & LIBSSH2_STATE_INITIAL_KEX) {
|
|
|
-+ if(msg == SSH_MSG_KEXINIT) {
|
|
|
-+ if(!session->kex_strict) {
|
|
|
-+ if(datalen < 17) {
|
|
|
-+ LIBSSH2_FREE(session, data);
|
|
|
-+ session->packAdd_state = libssh2_NB_state_idle;
|
|
|
-+ return _libssh2_error(session,
|
|
|
-+ LIBSSH2_ERROR_BUFFER_TOO_SMALL,
|
|
|
-+ "Data too short extracting kex");
|
|
|
-+ }
|
|
|
-+ else {
|
|
|
-+ const unsigned char *strict =
|
|
|
-+ (unsigned char *)"kex-strict-s-v00@openssh.com";
|
|
|
-+ struct string_buf buf;
|
|
|
-+ unsigned char *algs = NULL;
|
|
|
-+ size_t algs_len = 0;
|
|
|
-+
|
|
|
-+ buf.data = (unsigned char *)data;
|
|
|
-+ buf.dataptr = buf.data;
|
|
|
-+ buf.len = datalen;
|
|
|
-+ buf.dataptr += 17; /* advance past type and cookie */
|
|
|
-+
|
|
|
-+ if(_libssh2_get_string(&buf, &algs, &algs_len)) {
|
|
|
-+ LIBSSH2_FREE(session, data);
|
|
|
-+ session->packAdd_state = libssh2_NB_state_idle;
|
|
|
-+ return _libssh2_error(session,
|
|
|
-+ LIBSSH2_ERROR_BUFFER_TOO_SMALL,
|
|
|
-+ "Algs too short");
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if(algs_len == 0 ||
|
|
|
-+ _libssh2_kex_agree_instr(algs, algs_len, strict, 28)) {
|
|
|
-+ session->kex_strict = 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if(session->kex_strict && seq) {
|
|
|
-+ LIBSSH2_FREE(session, data);
|
|
|
-+ session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
|
|
|
-+ session->packAdd_state = libssh2_NB_state_idle;
|
|
|
-+ libssh2_session_disconnect(session, "strict KEX violation: "
|
|
|
-+ "KEXINIT was not the first packet");
|
|
|
-+
|
|
|
-+ return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT,
|
|
|
-+ "strict KEX violation: "
|
|
|
-+ "KEXINIT was not the first packet");
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if(session->kex_strict && session->fullpacket_required_type &&
|
|
|
-+ session->fullpacket_required_type != msg) {
|
|
|
-+ LIBSSH2_FREE(session, data);
|
|
|
-+ session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
|
|
|
-+ session->packAdd_state = libssh2_NB_state_idle;
|
|
|
-+ libssh2_session_disconnect(session, "strict KEX violation: "
|
|
|
-+ "unexpected packet type");
|
|
|
-+
|
|
|
-+ return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT,
|
|
|
-+ "strict KEX violation: "
|
|
|
-+ "unexpected packet type");
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
- if(session->packAdd_state == libssh2_NB_state_allocated) {
|
|
|
- /* A couple exceptions to the packet adding rule: */
|
|
|
- switch(msg) {
|
|
|
-@@ -1341,6 +1404,15 @@ _libssh2_packet_ask(LIBSSH2_SESSION * session, unsigned char packet_type,
|
|
|
-
|
|
|
- return 0;
|
|
|
- }
|
|
|
-+ else if(session->kex_strict &&
|
|
|
-+ (session->state & LIBSSH2_STATE_INITIAL_KEX)) {
|
|
|
-+ libssh2_session_disconnect(session, "strict KEX violation: "
|
|
|
-+ "unexpected packet type");
|
|
|
-+
|
|
|
-+ return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT,
|
|
|
-+ "strict KEX violation: "
|
|
|
-+ "unexpected packet type");
|
|
|
-+ }
|
|
|
- packet = _libssh2_list_next(&packet->node);
|
|
|
- }
|
|
|
- return -1;
|
|
|
-@@ -1402,7 +1474,10 @@ _libssh2_packet_require(LIBSSH2_SESSION * session, unsigned char packet_type,
|
|
|
- }
|
|
|
-
|
|
|
- while(session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
|
|
|
-- int ret = _libssh2_transport_read(session);
|
|
|
-+ int ret;
|
|
|
-+ session->fullpacket_required_type = packet_type;
|
|
|
-+ ret = _libssh2_transport_read(session);
|
|
|
-+ session->fullpacket_required_type = 0;
|
|
|
- if(ret == LIBSSH2_ERROR_EAGAIN)
|
|
|
- return ret;
|
|
|
- else if(ret < 0) {
|
|
|
-diff --git a/src/packet.h b/src/packet.h
|
|
|
-index 79018bcf1d55..6ea100a5cfb3 100644
|
|
|
---- a/src/packet.h
|
|
|
-+++ b/src/packet.h
|
|
|
-@@ -71,6 +71,6 @@ int _libssh2_packet_burn(LIBSSH2_SESSION * session,
|
|
|
- int _libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data,
|
|
|
- unsigned long data_len);
|
|
|
- int _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
|
|
-- size_t datalen, int macstate);
|
|
|
-+ size_t datalen, int macstate, uint32_t seq);
|
|
|
-
|
|
|
- #endif /* __LIBSSH2_PACKET_H */
|
|
|
-diff --git a/src/session.c b/src/session.c
|
|
|
-index a4d602bad002..f4bafb57b2a6 100644
|
|
|
---- a/src/session.c
|
|
|
-+++ b/src/session.c
|
|
|
-@@ -464,6 +464,8 @@ libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)),
|
|
|
- session->abstract = abstract;
|
|
|
- session->api_timeout = 0; /* timeout-free API by default */
|
|
|
- session->api_block_mode = 1; /* blocking API by default */
|
|
|
-+ session->state = LIBSSH2_STATE_INITIAL_KEX;
|
|
|
-+ session->fullpacket_required_type = 0;
|
|
|
- session->packet_read_timeout = LIBSSH2_DEFAULT_READ_TIMEOUT;
|
|
|
- session->flag.quote_paths = 1; /* default behavior is to quote paths
|
|
|
- for the scp subsystem */
|
|
|
-@@ -1186,6 +1188,7 @@ libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason,
|
|
|
- const char *desc, const char *lang)
|
|
|
- {
|
|
|
- int rc;
|
|
|
-+ session->state &= ~LIBSSH2_STATE_INITIAL_KEX;
|
|
|
- session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS;
|
|
|
- BLOCK_ADJUST(rc, session,
|
|
|
- session_disconnect(session, reason, desc, lang));
|
|
|
-diff --git a/src/transport.c b/src/transport.c
|
|
|
-index 6d902d3372b4..3b30ff848726 100644
|
|
|
---- a/src/transport.c
|
|
|
-+++ b/src/transport.c
|
|
|
-@@ -187,6 +187,7 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
|
|
|
- struct transportpacket *p = &session->packet;
|
|
|
- int rc;
|
|
|
- int compressed;
|
|
|
-+ uint32_t seq = session->remote.seqno;
|
|
|
-
|
|
|
- if(session->fullpacket_state == libssh2_NB_state_idle) {
|
|
|
- session->fullpacket_macstate = LIBSSH2_MAC_CONFIRMED;
|
|
|
-@@ -318,7 +319,7 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
|
|
|
- if(session->fullpacket_state == libssh2_NB_state_created) {
|
|
|
- rc = _libssh2_packet_add(session, p->payload,
|
|
|
- session->fullpacket_payload_len,
|
|
|
-- session->fullpacket_macstate);
|
|
|
-+ session->fullpacket_macstate, seq);
|
|
|
- if(rc == LIBSSH2_ERROR_EAGAIN)
|
|
|
- return rc;
|
|
|
- if(rc) {
|
|
|
-@@ -329,6 +330,11 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
|
|
|
-
|
|
|
- session->fullpacket_state = libssh2_NB_state_idle;
|
|
|
-
|
|
|
-+ if(session->kex_strict &&
|
|
|
-+ session->fullpacket_packet_type == SSH_MSG_NEWKEYS) {
|
|
|
-+ session->remote.seqno = 0;
|
|
|
-+ }
|
|
|
-+
|
|
|
- return session->fullpacket_packet_type;
|
|
|
- }
|
|
|
-
|
|
|
-@@ -1091,6 +1097,10 @@ int _libssh2_transport_send(LIBSSH2_SESSION *session,
|
|
|
-
|
|
|
- session->local.seqno++;
|
|
|
-
|
|
|
-+ if(session->kex_strict && data[0] == SSH_MSG_NEWKEYS) {
|
|
|
-+ session->local.seqno = 0;
|
|
|
-+ }
|
|
|
-+
|
|
|
- ret = LIBSSH2_SEND(session, p->outbuf, total_length,
|
|
|
- LIBSSH2_SOCKET_SEND_FLAGS(session));
|
|
|
- if(ret < 0)
|
|
|
---
|
|
|
-2.43.0
|
|
|
-
|