diff --git a/0001-CVE-2023-48795-client-side-mitigation.patch b/0001-CVE-2023-48795-client-side-mitigation.patch new file mode 100644 index 0000000000000000000000000000000000000000..35159f7c8a207beb82aebe5be91b09ea0564ec1f --- /dev/null +++ b/0001-CVE-2023-48795-client-side-mitigation.patch @@ -0,0 +1,447 @@ +From fafeb91c0cfd27510b850912a778681d3311a031 Mon Sep 17 00:00:00 2001 +From: wangkaiqiang +Date: Thu, 11 Jan 2024 15:27:14 +0800 +Subject: [PATCH 1/4] CVE-2023-48795: client side mitigation + +--- + include/libssh/packet.h | 1 + + include/libssh/session.h | 6 +++++ + src/curve25519.c | 19 +++---------- + src/dh-gex.c | 7 +---- + src/dh.c | 17 +++--------- + src/ecdh.c | 8 +----- + src/ecdh_crypto.c | 12 +++------ + src/ecdh_gcrypt.c | 10 +++---- + src/ecdh_mbedcrypto.c | 11 +++----- + src/kex.c | 34 +++++++++++++++++++---- + src/packet.c | 58 ++++++++++++++++++++++++++++++++++++++++ + src/packet_cb.c | 12 +++++++++ + 12 files changed, 126 insertions(+), 69 deletions(-) + +diff --git a/include/libssh/packet.h b/include/libssh/packet.h +index 561bba8..c6fbc3f 100644 +--- a/include/libssh/packet.h ++++ b/include/libssh/packet.h +@@ -63,6 +63,7 @@ SSH_PACKET_CALLBACK(ssh_packet_ext_info); + SSH_PACKET_CALLBACK(ssh_packet_kexdh_init); + #endif + ++int ssh_packet_send_newkeys(ssh_session session); + int ssh_packet_send_unimplemented(ssh_session session, uint32_t seqnum); + int ssh_packet_parse_type(ssh_session session); + //int packet_flush(ssh_session session, int enforce_blocking); +diff --git a/include/libssh/session.h b/include/libssh/session.h +index 2225615..7bce3b9 100644 +--- a/include/libssh/session.h ++++ b/include/libssh/session.h +@@ -75,6 +75,12 @@ enum ssh_pending_call_e { + /* Client successfully authenticated */ + #define SSH_SESSION_FLAG_AUTHENTICATED 2 + ++/* The current SSH2 session implements the "strict KEX" feature and should behave ++ * differently on SSH2_MSG_NEWKEYS. */ ++#define SSH_SESSION_FLAG_KEX_STRICT 0x0010 ++/* Unexpected packets have been sent while the session was still unencrypted */ ++#define SSH_SESSION_FLAG_KEX_TAINTED 0x0020 ++ + /* codes to use with ssh_handle_packets*() */ + /* Infinite timeout */ + #define SSH_TIMEOUT_INFINITE -1 +diff --git a/src/curve25519.c b/src/curve25519.c +index d251755..696d3e2 100644 +--- a/src/curve25519.c ++++ b/src/curve25519.c +@@ -330,16 +330,10 @@ static SSH_PACKET_CALLBACK(ssh_packet_client_curve25519_reply){ + } + + /* Send the MSG_NEWKEYS */ +- if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) { +- goto error; +- } +- +- rc=ssh_packet_send(session); ++ rc = ssh_packet_send_newkeys(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; +@@ -497,18 +491,13 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){ + return SSH_ERROR; + } + +- /* Send the MSG_NEWKEYS */ +- rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS); +- if (rc < 0) { +- goto error; +- } +- + session->dh_handshake_state = DH_STATE_NEWKEYS_SENT; +- rc = ssh_packet_send(session); ++ ++ /* Send the MSG_NEWKEYS */ ++ rc = ssh_packet_send_newkeys(session); + if (rc == SSH_ERROR) { + goto error; + } +- SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); + + return SSH_PACKET_USED; + error: +diff --git a/src/dh-gex.c b/src/dh-gex.c +index 88a9714..3329660 100644 +--- a/src/dh-gex.c ++++ b/src/dh-gex.c +@@ -282,15 +282,10 @@ static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_reply) + } + + /* Send the MSG_NEWKEYS */ +- if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) { +- goto error; +- } +- +- rc = ssh_packet_send(session); ++ rc = ssh_packet_send_newkeys(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; +diff --git a/src/dh.c b/src/dh.c +index 18b7173..7befea7 100644 +--- a/src/dh.c ++++ b/src/dh.c +@@ -381,16 +381,10 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dh_reply){ + } + + /* Send the MSG_NEWKEYS */ +- if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) { +- goto error; +- } +- +- rc=ssh_packet_send(session); ++ rc = ssh_packet_send_newkeys(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: +@@ -527,15 +521,12 @@ int ssh_server_dh_process_init(ssh_session session, ssh_buffer packet) + } + SSH_LOG(SSH_LOG_DEBUG, "Sent KEX_DH_[GEX]_REPLY"); + +- if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) { +- ssh_buffer_reinit(session->out_buffer); +- goto error; +- } + session->dh_handshake_state=DH_STATE_NEWKEYS_SENT; +- if (ssh_packet_send(session) == SSH_ERROR) { ++ /* Send the MSG_NEWKEYS */ ++ rc = ssh_packet_send_newkeys(session); ++ if (rc == SSH_ERROR) { + goto error; + } +- SSH_LOG(SSH_LOG_PACKET, "SSH_MSG_NEWKEYS sent"); + + return SSH_OK; + error: +diff --git a/src/ecdh.c b/src/ecdh.c +index a4c07cc..b722ecd 100644 +--- a/src/ecdh.c ++++ b/src/ecdh.c +@@ -88,16 +88,10 @@ SSH_PACKET_CALLBACK(ssh_packet_client_ecdh_reply){ + } + + /* Send the MSG_NEWKEYS */ +- if (ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS) < 0) { +- goto error; +- } +- +- rc=ssh_packet_send(session); ++ rc = ssh_packet_send_newkeys(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; +diff --git a/src/ecdh_crypto.c b/src/ecdh_crypto.c +index a1de27f..62578c1 100644 +--- a/src/ecdh_crypto.c ++++ b/src/ecdh_crypto.c +@@ -323,18 +323,12 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){ + goto error; + } + +- /* Send the MSG_NEWKEYS */ +- rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS); +- if (rc < 0) { +- goto error; +- } +- + session->dh_handshake_state = DH_STATE_NEWKEYS_SENT; +- rc = ssh_packet_send(session); +- if (rc == SSH_ERROR){ ++ /* Send the MSG_NEWKEYS */ ++ rc = ssh_packet_send_newkeys(session); ++ if (rc == SSH_ERROR) { + goto error; + } +- SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); + + return SSH_PACKET_USED; + error: +diff --git a/src/ecdh_gcrypt.c b/src/ecdh_gcrypt.c +index d9c41bf..dd4332d 100644 +--- a/src/ecdh_gcrypt.c ++++ b/src/ecdh_gcrypt.c +@@ -372,17 +372,13 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){ + goto out; + } + +- ++ session->dh_handshake_state = DH_STATE_NEWKEYS_SENT; + /* Send the MSG_NEWKEYS */ +- rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS); +- if (rc != SSH_OK) { ++ rc = ssh_packet_send_newkeys(session); ++ if (rc == SSH_ERROR) { + goto out; + } + +- session->dh_handshake_state = DH_STATE_NEWKEYS_SENT; +- rc = ssh_packet_send(session); +- SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); +- + out: + gcry_sexp_release(param); + gcry_sexp_release(key); +diff --git a/src/ecdh_mbedcrypto.c b/src/ecdh_mbedcrypto.c +index 718f152..45251a4 100644 +--- a/src/ecdh_mbedcrypto.c ++++ b/src/ecdh_mbedcrypto.c +@@ -300,16 +300,13 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){ + goto out; + } + +- rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS); +- if (rc < 0) { +- rc = SSH_ERROR; ++ session->dh_handshake_state = DH_STATE_NEWKEYS_SENT; ++ /* Send the MSG_NEWKEYS */ ++ rc = ssh_packet_send_newkeys(session); ++ if (rc == SSH_ERROR) { + goto out; + } + +- session->dh_handshake_state = DH_STATE_NEWKEYS_SENT; +- rc = ssh_packet_send(session); +- SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); +- + out: + mbedtls_ecp_group_free(&grp); + if (rc == SSH_ERROR) { +diff --git a/src/kex.c b/src/kex.c +index 82071c7..54fd861 100644 +--- a/src/kex.c ++++ b/src/kex.c +@@ -162,6 +162,9 @@ + + /* RFC 8308 */ + #define KEX_EXTENSION_CLIENT "ext-info-c" ++/* Strict kex mitigation against CVE-2023-48795 */ ++#define KEX_STRICT_CLIENT "kex-strict-c-v00@openssh.com" ++#define KEX_STRICT_SERVER "kex-strict-s-v00@openssh.com" + + /* Allowed algorithms in FIPS mode */ + #define FIPS_ALLOWED_CIPHERS "aes256-gcm@openssh.com,"\ +@@ -351,6 +354,27 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit) + goto error; + } + ++ /* ++ * handle the "strict KEX" feature. If supported by peer, then set up the ++ * flag and verify packet sequence numbers. ++ */ ++ if (server_kex) { ++ ok = ssh_match_group(session->next_crypto->client_kex.methods[SSH_KEX], ++ KEX_STRICT_CLIENT); ++ if (ok) { ++ SSH_LOG(SSH_LOG_DEBUG, "Client supports strict kex, enabling."); ++ session->flags |= SSH_SESSION_FLAG_KEX_STRICT; ++ } ++ } else { ++ /* client kex */ ++ ok = ssh_match_group(session->next_crypto->server_kex.methods[SSH_KEX], ++ KEX_STRICT_SERVER); ++ if (ok) { ++ SSH_LOG(SSH_LOG_DEBUG, "Server supports strict kex, enabling."); ++ session->flags |= SSH_SESSION_FLAG_KEX_STRICT; ++ } ++ } ++ + if (server_kex) { + len = ssh_buffer_get_data(packet,session->next_crypto->client_kex.cookie, 16); + if (len != 16) { +@@ -715,21 +739,21 @@ int ssh_set_client_kex(ssh_session session) + return SSH_OK; + } + +- /* Here we append ext-info-c to the list of kex algorithms */ ++ /* Here we append ext-info-c and kex-strict-c-v00@openssh.com to the list of kex algorithms */ + kex = client->methods[SSH_KEX]; + len = strlen(kex); +- if (len + strlen(KEX_EXTENSION_CLIENT) + 2 < len) { ++ /* Comma, comma, nul byte */ ++ kex_len = len + 1 + strlen(KEX_EXTENSION_CLIENT) + 1 + strlen(KEX_STRICT_CLIENT ) + 1; ++ if (kex_len >= MAX_PACKET_LEN) { + /* Overflow */ + return SSH_ERROR; + } +- kex_len = len + strlen(KEX_EXTENSION_CLIENT) + 2; /* comma, NULL */ + kex_tmp = realloc(kex, kex_len); + if (kex_tmp == NULL) { +- free(kex); + ssh_set_error_oom(session); + return SSH_ERROR; + } +- snprintf(kex_tmp + len, kex_len - len, ",%s", KEX_EXTENSION_CLIENT); ++ snprintf(kex_tmp + len, kex_len - len, ",%s,%s", KEX_EXTENSION_CLIENT, KEX_STRICT_CLIENT); + client->methods[SSH_KEX] = kex_tmp; + + return SSH_OK; +diff --git a/src/packet.c b/src/packet.c +index ec4a720..329b810 100644 +--- a/src/packet.c ++++ b/src/packet.c +@@ -1304,6 +1304,19 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) + } + #endif /* WITH_ZLIB */ + payloadsize = ssh_buffer_get_len(session->in_buffer); ++ if (session->recv_seq == UINT32_MAX) { ++ /* Overflowing sequence numbers is always fishy */ ++ if (crypto == NULL) { ++ /* don't allow sequence number overflow when unencrypted */ ++ ssh_set_error(session, ++ SSH_FATAL, ++ "Incoming sequence number overflow"); ++ goto error; ++ } else { ++ SSH_LOG(SSH_LOG_WARNING, ++ "Incoming sequence number overflow"); ++ } ++ } + session->recv_seq++; + if (crypto != NULL) { + struct ssh_cipher_struct *cipher = NULL; +@@ -1326,7 +1339,19 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) + SSH_LOG(SSH_LOG_PACKET, + "packet: read type %hhd [len=%d,padding=%hhd,comp=%d,payload=%d]", + session->in_packet.type, packet_len, padding, compsize, payloadsize); ++ if (crypto == NULL) { ++ /* In strict kex, only a few packets are allowed. Taint the session ++ * if we received packets that are normally allowed but to be ++ * refused if we are in strict kex when KEX is over. ++ */ ++ uint8_t type = session->in_packet.type; + ++ if (type != SSH2_MSG_KEXINIT && type != SSH2_MSG_NEWKEYS && ++ (type < SSH2_MSG_KEXDH_INIT || ++ type > SSH2_MSG_KEX_DH_GEX_REQUEST)) { ++ session->flags |= SSH_SESSION_FLAG_KEX_TAINTED; ++ } ++ } + /* Check if the packet is expected */ + filter_result = ssh_packet_incoming_filter(session); + +@@ -1342,6 +1367,9 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) + session->in_packet.type); + goto error; + case SSH_PACKET_UNKNOWN: ++ if (crypto == NULL) { ++ session->flags |= SSH_SESSION_FLAG_KEX_TAINTED; ++ } + ssh_packet_send_unimplemented(session, session->recv_seq - 1); + break; + } +@@ -1505,7 +1533,33 @@ void ssh_packet_process(ssh_session session, uint8_t type) + SSH_LOG(SSH_LOG_RARE, "Failed to send unimplemented: %s", + ssh_get_error(session)); + } ++ if (session->current_crypto == NULL) { ++ session->flags |= SSH_SESSION_FLAG_KEX_TAINTED; ++ } ++ } ++} ++ ++/** @internal ++ * @brief sends a SSH_MSG_NEWKEYS when enabling the new negotiated ciphers ++ * @param session the SSH session ++ * @return SSH_ERROR on error, else SSH_OK ++ */ ++int ssh_packet_send_newkeys(ssh_session session) ++{ ++ int rc; ++ ++ /* Send the MSG_NEWKEYS */ ++ rc = ssh_buffer_add_u8(session->out_buffer, SSH2_MSG_NEWKEYS); ++ if (rc < 0) { ++ return rc; + } ++ ++ rc = ssh_packet_send(session); ++ if (rc == SSH_ERROR) { ++ return rc; ++ } ++ SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_NEWKEYS sent"); ++ return rc; + } + + /** @internal +@@ -1813,6 +1867,10 @@ int ssh_packet_send(ssh_session session) + if (rc == SSH_OK && type == SSH2_MSG_NEWKEYS) { + struct ssh_iterator *it; + ++ if (session->flags & SSH_SESSION_FLAG_KEX_STRICT) { ++ /* reset packet sequence number when running in strict kex mode */ ++ session->send_seq = 0; ++ } + for (it = ssh_list_get_iterator(session->out_queue); + it != NULL; + it = ssh_list_get_iterator(session->out_queue)) { +diff --git a/src/packet_cb.c b/src/packet_cb.c +index 39575b1..2a4751c 100644 +--- a/src/packet_cb.c ++++ b/src/packet_cb.c +@@ -110,6 +110,18 @@ SSH_PACKET_CALLBACK(ssh_packet_newkeys){ + goto error; + } + ++ if (session->flags & SSH_SESSION_FLAG_KEX_STRICT) { ++ /* reset packet sequence number when running in strict kex mode */ ++ session->recv_seq = 0; ++ /* Check that we aren't tainted */ ++ if (session->flags & SSH_SESSION_FLAG_KEX_TAINTED) { ++ ssh_set_error(session, ++ SSH_FATAL, ++ "Received unexpected packets in strict KEX mode."); ++ goto error; ++ } ++ } ++ + if(session->server){ + /* server things are done in server.c */ + session->dh_handshake_state=DH_STATE_FINISHED; +-- +2.31.1 + diff --git a/0002-CVE-2023-48795-Server-side-mitigations.patch b/0002-CVE-2023-48795-Server-side-mitigations.patch new file mode 100644 index 0000000000000000000000000000000000000000..bccd7b0bef2f2ca9fedbf129bf567cc6e51efc0c --- /dev/null +++ b/0002-CVE-2023-48795-Server-side-mitigations.patch @@ -0,0 +1,119 @@ +From bbad6610515a6e0b09c5b1a29adf51ddba585221 Mon Sep 17 00:00:00 2001 +From: wangkaiqiang +Date: Thu, 11 Jan 2024 15:27:45 +0800 +Subject: [PATCH 2/4] CVE-2023-48795: Server side mitigations + +--- + include/libssh/kex.h | 1 + + src/kex.c | 46 ++++++++++++++++++++++++++++++++++---------- + src/server.c | 8 +++++++- + 3 files changed, 44 insertions(+), 11 deletions(-) + +diff --git a/include/libssh/kex.h b/include/libssh/kex.h +index 3a1f4a6..50df0a7 100644 +--- a/include/libssh/kex.h ++++ b/include/libssh/kex.h +@@ -36,6 +36,7 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit); + int ssh_send_kex(ssh_session session, int server_kex); + void ssh_list_kex(struct ssh_kex_struct *kex); + int ssh_set_client_kex(ssh_session session); ++int ssh_kex_append_extensions(ssh_session session, struct ssh_kex_struct *pkex); + int ssh_kex_select_methods(ssh_session session); + int ssh_verify_existing_algo(enum ssh_kex_types_e algo, const char *name); + char *ssh_keep_known_algos(enum ssh_kex_types_e algo, const char *list); +diff --git a/src/kex.c b/src/kex.c +index 54fd861..529e2eb 100644 +--- a/src/kex.c ++++ b/src/kex.c +@@ -690,11 +690,8 @@ int ssh_set_client_kex(ssh_session session) + { + struct ssh_kex_struct *client = &session->next_crypto->client_kex; + const char *wanted; +- char *kex = NULL; +- char *kex_tmp = NULL; + int ok; + int i; +- size_t kex_len, len; + + ok = ssh_get_random(client->cookie, 16, 0); + if (!ok) { +@@ -739,11 +736,33 @@ int ssh_set_client_kex(ssh_session session) + return SSH_OK; + } + +- /* Here we append ext-info-c and kex-strict-c-v00@openssh.com to the list of kex algorithms */ +- kex = client->methods[SSH_KEX]; ++ ok = ssh_kex_append_extensions(session, client); ++ if (ok != SSH_OK){ ++ return ok; ++ } ++ ++ return SSH_OK; ++} ++ ++int ssh_kex_append_extensions(ssh_session session, struct ssh_kex_struct *pkex) ++{ ++ char *kex = NULL; ++ char *kex_tmp = NULL; ++ size_t kex_len, len; ++ ++ /* Here we append ext-info-c and kex-strict-c-v00@openssh.com for client ++ * and kex-strict-s-v00@openssh.com for server to the list of kex algorithms ++ */ ++ kex = pkex->methods[SSH_KEX]; + len = strlen(kex); +- /* Comma, comma, nul byte */ +- kex_len = len + 1 + strlen(KEX_EXTENSION_CLIENT) + 1 + strlen(KEX_STRICT_CLIENT ) + 1; ++ if (session->server) { ++ /* Comma, nul byte */ ++ kex_len = len + 1 + strlen(KEX_STRICT_SERVER) + 1; ++ } else { ++ /* Comma, comma, nul byte */ ++ kex_len = len + 1 + strlen(KEX_EXTENSION_CLIENT) + 1 + ++ strlen(KEX_STRICT_CLIENT) + 1; ++ } + if (kex_len >= MAX_PACKET_LEN) { + /* Overflow */ + return SSH_ERROR; +@@ -753,9 +772,16 @@ int ssh_set_client_kex(ssh_session session) + ssh_set_error_oom(session); + return SSH_ERROR; + } +- snprintf(kex_tmp + len, kex_len - len, ",%s,%s", KEX_EXTENSION_CLIENT, KEX_STRICT_CLIENT); +- client->methods[SSH_KEX] = kex_tmp; +- ++ if (session->server){ ++ snprintf(kex_tmp + len, kex_len - len, ",%s", KEX_STRICT_SERVER); ++ } else { ++ snprintf(kex_tmp + len, ++ kex_len - len, ++ ",%s,%s", ++ KEX_EXTENSION_CLIENT, ++ KEX_STRICT_CLIENT); ++ } ++ pkex->methods[SSH_KEX] = kex_tmp; + return SSH_OK; + } + +diff --git a/src/server.c b/src/server.c +index 841a1c4..eb2021a 100644 +--- a/src/server.c ++++ b/src/server.c +@@ -191,7 +191,13 @@ int server_set_kex(ssh_session session) + } + } + +- return 0; ++ /* Do not append the extensions during rekey */ ++ if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) { ++ return SSH_OK; ++ } ++ ++ rc = ssh_kex_append_extensions(session, server); ++ return rc; + } + + int ssh_server_init_kex(ssh_session session) { +-- +2.31.1 + diff --git a/0003-CVE-2023-48795-Strip-extensions-from-both-kex-lists-.patch b/0003-CVE-2023-48795-Strip-extensions-from-both-kex-lists-.patch new file mode 100644 index 0000000000000000000000000000000000000000..c081541ab03fcef0599519f4d60f268aa0a0c1d8 --- /dev/null +++ b/0003-CVE-2023-48795-Strip-extensions-from-both-kex-lists-.patch @@ -0,0 +1,41 @@ +From 5828f94e99123d9e95e596db6cb8e1d931e5ee1c Mon Sep 17 00:00:00 2001 +From: wangkaiqiang +Date: Thu, 11 Jan 2024 15:28:45 +0800 +Subject: [PATCH 3/4] CVE-2023-48795: Strip extensions from both kex lists for + matching + +--- + src/kex.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/src/kex.c b/src/kex.c +index 529e2eb..1cbb1f8 100644 +--- a/src/kex.c ++++ b/src/kex.c +@@ -810,11 +810,19 @@ int ssh_kex_select_methods (ssh_session session) + const char *aead_hmac = NULL; + int i; + +- /* Here we should drop the ext-info-c from the list so we avoid matching. ++ /* Here we should drop the extensions from the list so we avoid matching. + * it. We added it to the end, so we can just truncate the string here */ +- ext_start = strstr(client->methods[SSH_KEX], ","KEX_EXTENSION_CLIENT); +- if (ext_start != NULL) { +- ext_start[0] = '\0'; ++ if (session->client) { ++ ext_start = strstr(client->methods[SSH_KEX], "," KEX_EXTENSION_CLIENT); ++ if (ext_start != NULL) { ++ ext_start[0] = '\0'; ++ } ++ } ++ if (session->server) { ++ ext_start = strstr(server->methods[SSH_KEX], "," KEX_STRICT_SERVER); ++ if (ext_start != NULL) { ++ ext_start[0] = '\0'; ++ } + } + + for (i = 0; i < SSH_KEX_METHODS; i++) { +-- +2.31.1 + diff --git a/0004-CVE-2023-48795-tests-Adjust-calculation-to-strict-ke.patch b/0004-CVE-2023-48795-tests-Adjust-calculation-to-strict-ke.patch new file mode 100644 index 0000000000000000000000000000000000000000..5ca402a7fb9963df4a47195a09bd861bfe972aec --- /dev/null +++ b/0004-CVE-2023-48795-tests-Adjust-calculation-to-strict-ke.patch @@ -0,0 +1,103 @@ +From 3cf1a32364985f745bf379e5ae8b54daf33bad9d Mon Sep 17 00:00:00 2001 +From: wangkaiqiang +Date: Thu, 11 Jan 2024 15:29:24 +0800 +Subject: [PATCH 4/4] CVE-2023-48795: tests: Adjust calculation to strict kex + +--- + tests/client/torture_rekey.c | 56 ++++++++++++++++++++---------------- + 1 file changed, 32 insertions(+), 24 deletions(-) + +diff --git a/tests/client/torture_rekey.c b/tests/client/torture_rekey.c +index 46a015d..ba0d80f 100644 +--- a/tests/client/torture_rekey.c ++++ b/tests/client/torture_rekey.c +@@ -146,6 +146,29 @@ static void torture_rekey_default(void **state) + ssh_disconnect(s->ssh.session); + } + ++static void sanity_check_session(void **state) ++{ ++ struct torture_state *s = *state; ++ struct ssh_crypto_struct *c = NULL; ++ ++ c = s->ssh.session->current_crypto; ++ assert_non_null(c); ++ assert_int_equal(c->in_cipher->max_blocks, ++ bytes / c->in_cipher->blocksize); ++ assert_int_equal(c->out_cipher->max_blocks, ++ bytes / c->out_cipher->blocksize); ++ /* when strict kex is used, the newkeys reset the sequence number */ ++ if ((s->ssh.session->flags & SSH_SESSION_FLAG_KEX_STRICT) != 0) { ++ assert_int_equal(c->out_cipher->packets, s->ssh.session->send_seq); ++ assert_int_equal(c->in_cipher->packets, s->ssh.session->recv_seq); ++ } else { ++ /* Otherwise we have less encrypted packets than transferred ++ * (first are not encrypted) */ ++ assert_true(c->out_cipher->packets < s->ssh.session->send_seq); ++ assert_true(c->in_cipher->packets < s->ssh.session->recv_seq); ++ } ++} ++ + /* We lower the rekey limits manually and check that the rekey + * really happens when sending data + */ +@@ -164,16 +187,10 @@ static void torture_rekey_send(void **state) + rc = ssh_connect(s->ssh.session); + assert_ssh_return_code(s->ssh.session, rc); + +- /* The blocks limit is set correctly */ +- c = s->ssh.session->current_crypto; +- assert_int_equal(c->in_cipher->max_blocks, +- bytes / c->in_cipher->blocksize); +- assert_int_equal(c->out_cipher->max_blocks, +- bytes / c->out_cipher->blocksize); +- /* We should have less encrypted packets than transfered (first are not encrypted) */ +- assert_true(c->out_cipher->packets < s->ssh.session->send_seq); +- assert_true(c->in_cipher->packets < s->ssh.session->recv_seq); ++ sanity_check_session(state); + /* Copy the initial secret hash = session_id so we know we changed keys later */ ++ c = s->ssh.session->current_crypto; ++ assert_non_null(c); + secret_hash = malloc(c->digest_len); + assert_non_null(secret_hash); + memcpy(secret_hash, c->secret_hash, c->digest_len); +@@ -269,14 +286,10 @@ static void torture_rekey_recv(void **state) + sftp_file file; + mode_t mask; + +- /* The blocks limit is set correctly */ +- c = s->ssh.session->current_crypto; +- assert_int_equal(c->in_cipher->max_blocks, bytes / c->in_cipher->blocksize); +- assert_int_equal(c->out_cipher->max_blocks, bytes / c->out_cipher->blocksize); +- /* We should have less encrypted packets than transfered (first are not encrypted) */ +- assert_true(c->out_cipher->packets < s->ssh.session->send_seq); +- assert_true(c->in_cipher->packets < s->ssh.session->recv_seq); ++ sanity_check_session(state); + /* Copy the initial secret hash = session_id so we know we changed keys later */ ++ c = s->ssh.session->current_crypto; ++ assert_non_null(c); + secret_hash = malloc(c->digest_len); + assert_non_null(secret_hash); + memcpy(secret_hash, c->secret_hash, c->digest_len); +@@ -461,15 +474,10 @@ static void torture_rekey_different_kex(void **state) + assert_ssh_return_code(s->ssh.session, rc); + + /* The blocks limit is set correctly */ +- c = s->ssh.session->current_crypto; +- assert_int_equal(c->in_cipher->max_blocks, +- bytes / c->in_cipher->blocksize); +- assert_int_equal(c->out_cipher->max_blocks, +- bytes / c->out_cipher->blocksize); +- /* We should have less encrypted packets than transfered (first are not encrypted) */ +- assert_true(c->out_cipher->packets < s->ssh.session->send_seq); +- assert_true(c->in_cipher->packets < s->ssh.session->recv_seq); ++ sanity_check_session(state); + /* Copy the initial secret hash = session_id so we know we changed keys later */ ++ c = s->ssh.session->current_crypto; ++ assert_non_null(c); + secret_hash = malloc(c->digest_len); + assert_non_null(secret_hash); + memcpy(secret_hash, c->secret_hash, c->digest_len); +-- +2.31.1 + diff --git a/libssh.spec b/libssh.spec index a1da45219c6290ea29e04b35929b29e0ef73eab0..c2c14aac3379a6e65b8e441a25fa513591a46d9a 100644 --- a/libssh.spec +++ b/libssh.spec @@ -1,7 +1,7 @@ %define anolis_release .0.1 Name: libssh Version: 0.9.6 -Release: 3%{anolis_release}%{?dist} +Release: 4%{anolis_release}%{?dist} Summary: A library implementing the SSH protocol License: LGPLv2+ URL: http://www.libssh.org @@ -11,6 +11,14 @@ Source1: https://www.libssh.org/files/0.9/%{name}-%{version}.tar.xz.asc Source2: https://cryptomilk.org/gpgkey-8DFF53E18F2ABC8D8F3C92237EE0FC4DCC014E3D.gpg#/%{name}.keyring Source3: libssh_client.config Source4: libssh_server.config +#Reference:https://gitlab.com/libssh/libssh-mirror/-/commit/87b93be5a2071be782aa84aa5a91544b18959d5e +Patch0: 0001-CVE-2023-48795-client-side-mitigation.patch +#Reference: https://gitlab.com/libssh/libssh-mirror/-/commit/fd4948255560039b51c2d61f0a62784ed8b6f5a6 +Patch1: 0002-CVE-2023-48795-Server-side-mitigations.patch +#Reference:https://gitlab.com/libssh/libssh-mirror/-/commit/03bbbc9e4c93aae2ccdd302d6123e4809be37746 +Patch2: 0003-CVE-2023-48795-Strip-extensions-from-both-kex-lists-.patch +#Reference:https://gitlab.com/libssh/libssh-mirror/-/commit/768d1ed30cf4b3cb9628254ef3ee24b9c38abdbc +Patch3: 0004-CVE-2023-48795-tests-Adjust-calculation-to-strict-ke.patch BuildRequires: cmake BuildRequires: doxygen @@ -149,6 +157,9 @@ popd %doc AUTHORS BSD ChangeLog README %changelog +* Thu Jan 11 2024 Kaiqiang Wang - 0.9.6.4.0.1 +- fix CVE-2023-48795 + * Fri Jul 15 2022 Weisson - 0.9.6-3.0.1 - Add doc sub package