Compare commits

...

10 Commits

Author SHA1 Message Date
openeuler-ci-bot
024712fe13
!70 [sync] PR-67: fix CVE-2023-6004,CVE-2023-6918 and CVE-2023-48795
From: @openeuler-sync-bot 
Reviewed-by: @gebidelidaye 
Signed-off-by: @gebidelidaye
2024-01-05 08:39:53 +00:00
renmingshuai
1831be094e fix CVE-2023-6004,CVE-2023-48795 and CVE-2023-6918
(cherry picked from commit 46ed5eb31d4731c058f2b389f7ca4a133c4c9b9d)
2024-01-04 18:08:43 +08:00
openeuler-ci-bot
1ea4d9d18f
!54 [sync] PR-52: fix CVE-2023-1667 and CVE-2023-2283
From: @openeuler-sync-bot 
Reviewed-by: @kircher 
Signed-off-by: @kircher
2023-05-24 11:17:39 +00:00
renmingshuai
dbb2396adf fix CVE-2023-1667 and CVE-2023-2283
(cherry picked from commit e91aad514b5aa162f1bc8f4f6aa451279fe326ad)
2023-05-24 15:21:45 +08:00
openeuler-ci-bot
47b64e6d31
!40 test: fix running timeout tests
From: @xinghe_1 
Reviewed-by: @zengwefeng 
Signed-off-by: @zengwefeng
2022-10-27 08:36:38 +00:00
xinghe
3432023c56 tests: Fix running timeout tests on gitlab windows runners 2022-10-25 07:51:25 +00:00
openeuler-ci-bot
03c0ef07b3
!32 backport upstream patches
From: @eaglegai 
Reviewed-by: @seuzw 
Signed-off-by: @seuzw
2022-09-02 08:37:54 +00:00
eaglegai
29d0bae5d5 backport upstream patches 2022-09-02 08:18:18 +00:00
openeuler-ci-bot
4cf7a78b92 !18 fix CVE-2021-3634
From: @heyh000036041
Reviewed-by: @wangxp006
Signed-off-by: @wangxp006
2021-09-13 12:43:34 +00:00
hwx1054416
7b2f5ab7bd fix CVE-2021-3634 2021-09-13 20:02:02 +08:00
37 changed files with 5030 additions and 1 deletions

213
CVE-2021-3634.patch Normal file
View File

@ -0,0 +1,213 @@
From ebd18d65b725948e816be992d1649e7b18e67272 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Wed, 23 Jun 2021 13:16:33 +0200
Subject: [PATCH] CVE-2021-3634:Create a sepatate length for session_id
Normally,the length of session_id and secret_hash is the same,
but if we will get into rekeying with a peer that changes preference
of key exchange algorithm,the new secret hash can be larger or
smaller than the previous session_id causing invalid reads or writes.
Resolves https://bugs.chromium.org/p/oss-fuzz/issues/datail?id=35485
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
---
include/libssh/crypto.h | 3 ++-
src/gssapi.c | 4 ++--
src/kdf.c | 2 +-
src/kex.c | 4 +++-
src/libcrypto.c | 2 +-
src/messages.c | 4 ++--
src/packet.c | 9 +++++----
src/pki.c | 8 ++++----
src/wrapper.c | 2 +-
tests/unittests/torture_session_keys.c | 3 ++-
10 files changed, 23 insertions(+), 18 deletions(-)
diff --git a/include/libssh/crypto.h b/include/libssh/crypto.h
index ede7166..671cf91 100644
--- a/include/libssh/crypto.h
+++ b/include/libssh/crypto.h
@@ -126,8 +126,9 @@ struct ssh_crypto_struct {
ssh_curve25519_pubkey curve25519_server_pubkey;
#endif
ssh_string dh_server_signature; /* information used by dh_handshake. */
- size_t digest_len; /* len of the two fields below */
+ size_t session_id_len;
unsigned char *session_id;
+ size_t digest_len; /* len of the two secret hash */
unsigned char *secret_hash; /* Secret hash is same as session id until re-kex */
unsigned char *encryptIV;
unsigned char *decryptIV;
diff --git a/src/gssapi.c b/src/gssapi.c
index 488df58..1d0fb6a 100644
--- a/src/gssapi.c
+++ b/src/gssapi.c
@@ -465,8 +465,8 @@ static ssh_buffer ssh_gssapi_build_mic(ssh_session session)
rc = ssh_buffer_pack(mic_buffer,
"dPbsss",
- crypto->digest_len,
- (size_t)crypto->digest_len, crypto->session_id,
+ crypto->session_id_len,
+ crypto->session_id_len, crypto->session_id,
SSH2_MSG_USERAUTH_REQUEST,
session->gssapi->user,
"ssh-connection",
diff --git a/src/kdf.c b/src/kdf.c
index 0e90e18..0964473 100644
--- a/src/kdf.c
+++ b/src/kdf.c
@@ -138,7 +138,7 @@ int sshkdf_derive_key(struct ssh_crypto_struct *crypto,
ssh_mac_update(ctx, key, key_len);
ssh_mac_update(ctx, crypto->secret_hash, crypto->digest_len);
ssh_mac_update(ctx, &letter, 1);
- ssh_mac_update(ctx, crypto->session_id, crypto->digest_len);
+ ssh_mac_update(ctx, crypto->session_id, crypto->session_id_len);
ssh_mac_final(digest, ctx);
if (requested_len < output_len) {
diff --git a/src/kex.c b/src/kex.c
index 80b6e8a..602de1c 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -1197,11 +1197,13 @@ int ssh_make_sessionid(ssh_session session)
}
memcpy(session->next_crypto->session_id, session->next_crypto->secret_hash,
session->next_crypto->digest_len);
+ /* Initial length is the same as secret hash */
+ session->next_crypto->session_id_len = session->next_crypto->digest_len;
}
#ifdef DEBUG_CRYPTO
printf("Session hash: \n");
ssh_log_hexdump("secret hash", session->next_crypto->secret_hash, session->next_crypto->digest_len);
- ssh_log_hexdump("session id", session->next_crypto->session_id, session->next_crypto->digest_len);
+ ssh_log_hexdump("session id", session->next_crypto->session_id, session->next_crypto->session_id_len);
#endif
rc = SSH_OK;
diff --git a/src/libcrypto.c b/src/libcrypto.c
index 8ff8a02..3db75df 100644
--- a/src/libcrypto.c
+++ b/src/libcrypto.c
@@ -392,7 +392,7 @@ int ssh_kdf(struct ssh_crypto_struct *crypto,
goto out;
}
rc = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSHKDF_SESSION_ID,
- crypto->session_id, crypto->digest_len);
+ crypto->session_id, crypto->session_id_len);
if (rc != 1) {
goto out;
}
diff --git a/src/messages.c b/src/messages.c
index 25683b2..2891218 100644
--- a/src/messages.c
+++ b/src/messages.c
@@ -708,8 +708,8 @@ static ssh_buffer ssh_msg_userauth_build_digest(ssh_session session,
rc = ssh_buffer_pack(buffer,
"dPbsssbsS",
- crypto->digest_len, /* session ID string */
- (size_t)crypto->digest_len, crypto->session_id,
+ crypto->session_id_len, /* session ID string */
+ crypto->session_id_len, crypto->session_id,
SSH2_MSG_USERAUTH_REQUEST, /* type */
msg->auth_request.username,
service,
diff --git a/src/packet.c b/src/packet.c
index e9ae564..9824fca 100644
--- a/src/packet.c
+++ b/src/packet.c
@@ -1899,7 +1899,7 @@ ssh_packet_set_newkeys(ssh_session session,
/* Both sides switched: do the actual switch now */
if (session->next_crypto->used == SSH_DIRECTION_BOTH) {
- size_t digest_len;
+ size_t session_id_len;
if (session->current_crypto != NULL) {
crypto_free(session->current_crypto);
@@ -1916,8 +1916,8 @@ ssh_packet_set_newkeys(ssh_session session,
return SSH_ERROR;
}
- digest_len = session->current_crypto->digest_len;
- session->next_crypto->session_id = malloc(digest_len);
+ session_id_len = session->current_crypto->session_id_len;
+ session->next_crypto->session_id = malloc(session_id_len);
if (session->next_crypto->session_id == NULL) {
ssh_set_error_oom(session);
return SSH_ERROR;
@@ -1925,7 +1925,8 @@ ssh_packet_set_newkeys(ssh_session session,
memcpy(session->next_crypto->session_id,
session->current_crypto->session_id,
- digest_len);
+ session_id_len);
+ session->next_crypto->session_id_len = session_id_len;
return SSH_OK;
}
diff --git a/src/pki.c b/src/pki.c
index 6dcb120..dba305c 100644
--- a/src/pki.c
+++ b/src/pki.c
@@ -2328,11 +2328,11 @@ ssh_string ssh_pki_do_sign(ssh_session session,
}
/* Get the session ID */
- session_id = ssh_string_new(crypto->digest_len);
+ session_id = ssh_string_new(crypto->session_id_len);
if (session_id == NULL) {
return NULL;
}
- ssh_string_fill(session_id, crypto->session_id, crypto->digest_len);
+ ssh_string_fill(session_id, crypto->session_id, crypto->session_id_len);
/* Fill the input */
sign_input = ssh_buffer_new();
@@ -2389,11 +2389,11 @@ ssh_string ssh_pki_do_sign_agent(ssh_session session,
}
/* prepend session identifier */
- session_id = ssh_string_new(crypto->digest_len);
+ session_id = ssh_string_new(crypto->session_id_len);
if (session_id == NULL) {
return NULL;
}
- ssh_string_fill(session_id, crypto->session_id, crypto->digest_len);
+ ssh_string_fill(session_id, crypto->session_id, crypto->session_id_len);
sig_buf = ssh_buffer_new();
if (sig_buf == NULL) {
diff --git a/src/wrapper.c b/src/wrapper.c
index 7e57ab5..36dc39c 100644
--- a/src/wrapper.c
+++ b/src/wrapper.c
@@ -183,7 +183,7 @@ void crypto_free(struct ssh_crypto_struct *crypto)
}
#endif
if (crypto->session_id != NULL) {
- explicit_bzero(crypto->session_id, crypto->digest_len);
+ explicit_bzero(crypto->session_id, crypto->session_id_len);
SAFE_FREE(crypto->session_id);
}
if (crypto->secret_hash != NULL) {
diff --git a/tests/unittests/torture_session_keys.c b/tests/unittests/torture_session_keys.c
index f220e01..7a4e7ce 100644
--- a/tests/unittests/torture_session_keys.c
+++ b/tests/unittests/torture_session_keys.c
@@ -48,8 +48,9 @@ struct ssh_cipher_struct fake_out_cipher = {
};
struct ssh_crypto_struct test_crypto = {
- .digest_len = 32,
+ .session_id_len = 32,
.session_id = secret,
+ .digest_len = 32,
.secret_hash = secret,
.in_cipher = &fake_in_cipher,
.out_cipher = &fake_out_cipher,
--
1.8.3.1

View File

@ -0,0 +1,34 @@
30339d7b16da7784413e4a4667feb3604ed0458 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Fri, 10 Mar 2023 16:14:08 +0100
Subject: [PATCH] CVE-2023-1667:packet_cb: Log more verbose error if
signature
verification fails
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict:NA
Reference:https://gitlab.com/libssh/libssh-mirror/commit/a30339d7b16da7784413e4a4667feb3604ed0458
---
src/packet_cb.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/packet_cb.c b/src/packet_cb.c
index 4e69291..d1fcfdd 100644
--- a/src/packet_cb.c
+++ b/src/packet_cb.c
@@ -156,6 +156,9 @@ SSH_PACKET_CALLBACK(ssh_packet_newkeys){
SSH_STRING_FREE(sig_blob);
ssh_signature_free(sig);
if (rc == SSH_ERROR) {
+ ssh_set_error(session,
+ SSH_FATAL,
+ "Failed to verify server hostkey signature");
goto error;
}
SSH_LOG(SSH_LOG_PROTOCOL,"Signature verified and valid");
--
2.23.0

View File

@ -0,0 +1,103 @@
From e8dfbb85a28514e1f869dac3000c6cec6cb8d08d Mon Sep 17 00:00:00 2001
From: Norbert Pocs <npocs@redhat.com>
Date: Mon, 24 Apr 2023 11:51:36 +0200
Subject: [PATCH] CVE-2023-2283:pki_crypto: Fix possible authentication bypass
The return value is changed by the call to pki_key_check_hash_compatible
causing the possibility of returning SSH_OK if memory allocation error
happens later in the function.
The assignment of SSH_ERROR if the verification fails is no longer needed,
because the value of the variable is already SSH_ERROR.
Signed-off-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict:NA
Reference:https://gitlab.com/libssh/libssh-mirror/commit/e8dfbb85a28514e1f869dac3000c6cec6cb8d08d
---
src/pki_crypto.c | 32 ++++++++++++++++++--------------
1 file changed, 18 insertions(+), 14 deletions(-)
diff --git a/src/pki_crypto.c b/src/pki_crypto.c
index 013f569e..635b82cb 100644
--- a/src/pki_crypto.c
+++ b/src/pki_crypto.c
@@ -3175,8 +3175,12 @@ int pki_verify_data_signature(ssh_signature signature,
unsigned char *raw_sig_data = NULL;
unsigned int raw_sig_len;
+ /* Function return code
+ * Do not change this variable throughout the function until the signature
+ * is successfully verified!
+ */
int rc = SSH_ERROR;
- int evp_rc;
+ int ok;
if (pubkey == NULL || ssh_key_is_private(pubkey) || input == NULL ||
signature == NULL || (signature->raw_sig == NULL
@@ -3191,8 +3195,8 @@ int pki_verify_data_signature(ssh_signature signature,
}
/* Check if public key and hash type are compatible */
- rc = pki_key_check_hash_compatible(pubkey, signature->hash_type);
- if (rc != SSH_OK) {
+ ok = pki_key_check_hash_compatible(pubkey, signature->hash_type);
+ if (ok != SSH_OK) {
return SSH_ERROR;
}
@@ -3237,8 +3241,8 @@ int pki_verify_data_signature(ssh_signature signature,
}
/* Verify the signature */
- evp_rc = EVP_DigestVerifyInit(ctx, NULL, md, NULL, pkey);
- if (evp_rc != 1){
+ ok = EVP_DigestVerifyInit(ctx, NULL, md, NULL, pkey);
+ if (ok != 1){
SSH_LOG(SSH_LOG_TRACE,
"EVP_DigestVerifyInit() failed: %s",
ERR_error_string(ERR_get_error(), NULL));
@@ -3246,28 +3250,28 @@ int pki_verify_data_signature(ssh_signature signature,
}
#ifdef HAVE_OPENSSL_EVP_DIGESTVERIFY
- evp_rc = EVP_DigestVerify(ctx, raw_sig_data, raw_sig_len, input, input_len);
+ ok = EVP_DigestVerify(ctx, raw_sig_data, raw_sig_len, input, input_len);
#else
- evp_rc = EVP_DigestVerifyUpdate(ctx, input, input_len);
- if (evp_rc != 1) {
+ ok = EVP_DigestVerifyUpdate(ctx, input, input_len);
+ if (ok != 1) {
SSH_LOG(SSH_LOG_TRACE,
"EVP_DigestVerifyUpdate() failed: %s",
ERR_error_string(ERR_get_error(), NULL));
goto out;
}
- evp_rc = EVP_DigestVerifyFinal(ctx, raw_sig_data, raw_sig_len);
+ ok = EVP_DigestVerifyFinal(ctx, raw_sig_data, raw_sig_len);
#endif
- if (evp_rc == 1) {
- SSH_LOG(SSH_LOG_TRACE, "Signature valid");
- rc = SSH_OK;
- } else {
+ if (ok != 1) {
SSH_LOG(SSH_LOG_TRACE,
"Signature invalid: %s",
ERR_error_string(ERR_get_error(), NULL));
- rc = SSH_ERROR;
+ goto out;
}
+ SSH_LOG(SSH_LOG_TRACE, "Signature valid");
+ rc = SSH_OK;
+
out:
if (ctx != NULL) {
EVP_MD_CTX_free(ctx);
--
2.33.0

View File

@ -0,0 +1,453 @@
From 87b93be5a2071be782aa84aa5a91544b18959d5e Mon Sep 17 00:00:00 2001
From: Aris Adamantiadis <aris@0xbadc0de.be>
Date: Tue, 12 Dec 2023 23:09:57 +0100
Subject: [PATCH 1/4] CVE-2023-48795: client side mitigation
Signed-off-by: Aris Adamantiadis <aris@0xbadc0de.be>
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict: NA
Reference:https://gitlab.com/libssh/libssh-mirror/-/commit/87b93be5a2071be782aa84aa5a91544b18959d5e
---
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 561bba8e..c6fbc3fc 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 64e118ef..3cde0dd4 100644
--- a/include/libssh/session.h
+++ b/include/libssh/session.h
@@ -80,6 +80,12 @@ enum ssh_pending_call_e {
* sending it twice during key exchange to simplify the state machine. */
#define SSH_SESSION_FLAG_KEXINIT_SENT 4
+/* 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 37654438..6b7b4238 100644
--- a/src/curve25519.c
+++ b/src/curve25519.c
@@ -335,16 +335,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;
@@ -502,18 +496,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 4a298542..f1880270 100644
--- a/src/dh-gex.c
+++ b/src/dh-gex.c
@@ -287,15 +287,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 c265efcb..1d519c63 100644
--- a/src/dh.c
+++ b/src/dh.c
@@ -386,16 +386,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:
@@ -532,15 +526,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 e5b11ba9..af80beec 100644
--- a/src/ecdh.c
+++ b/src/ecdh.c
@@ -93,16 +93,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 a1de27fd..62578c1b 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 d9c41bf9..dd4332d7 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 718f1522..45251a42 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 3e5ca6ad..0772cae8 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -163,6 +163,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,"\
@@ -491,6 +494,27 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit)
session->first_kex_follows_guess_wrong ? "wrong" : "right");
}
+ /*
+ * 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) {
/*
* If client sent a ext-info-c message in the kex list, it supports
@@ -767,21 +791,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 ca7a03b7..82965fb3 100644
--- a/src/packet.c
+++ b/src/packet.c
@@ -1309,6 +1309,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;
@@ -1331,7 +1344,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);
@@ -1347,6 +1372,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;
}
@@ -1521,7 +1549,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
@@ -1829,6 +1883,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 3e4d5f6d..a08f1d8a 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.33.0

View File

@ -0,0 +1,31 @@
From c3234e5f94b96d6e29f0c1c82821c1e3ebb181ed Mon Sep 17 00:00:00 2001
From: Norbert Pocs <norbertpocs0@gmail.com>
Date: Wed, 1 Nov 2023 11:24:43 +0100
Subject: [PATCH 1/9] CVE-2023-6004: config_parser: Allow multiple '@' in
usernames
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict: NA
Reference:https://git.libssh.org/projects/libssh.git/patch/?id=c3234e5f94b96d6e29f0c1c82821c1e3ebb181ed
---
src/config_parser.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/config_parser.c b/src/config_parser.c
index ae2aa2c8..76cca224 100644
--- a/src/config_parser.c
+++ b/src/config_parser.c
@@ -152,7 +152,7 @@ int ssh_config_parse_uri(const char *tok,
}
/* Username part (optional) */
- endp = strchr(tok, '@');
+ endp = strrchr(tok, '@');
if (endp != NULL) {
/* Zero-length username is not valid */
if (tok == endp) {
--
2.33.0

View File

@ -0,0 +1,75 @@
From 93c1dbd69f07f324c6aa1ab9296a632489cd3ead Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Fri, 15 Dec 2023 10:30:09 +0100
Subject: [PATCH 1/5] CVE-2023-6918: kdf: Reformat
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict: NA
Reference:https://gitlab.com/libssh/libssh-mirror/-/commit/93c1dbd69f07f324c6aa1ab9296a632489cd3ead
---
src/kdf.c | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/src/kdf.c b/src/kdf.c
index 09644739..656a38ed 100644
--- a/src/kdf.c
+++ b/src/kdf.c
@@ -58,7 +58,7 @@ static ssh_mac_ctx ssh_mac_ctx_init(enum ssh_kdf_digest type)
}
ctx->digest_type = type;
- switch(type){
+ switch (type) {
case SSH_KDF_SHA1:
ctx->ctx.sha1_ctx = sha1_init();
return ctx;
@@ -79,7 +79,7 @@ static ssh_mac_ctx ssh_mac_ctx_init(enum ssh_kdf_digest type)
static void ssh_mac_update(ssh_mac_ctx ctx, const void *data, size_t len)
{
- switch(ctx->digest_type){
+ switch (ctx->digest_type) {
case SSH_KDF_SHA1:
sha1_update(ctx->ctx.sha1_ctx, data, len);
break;
@@ -97,26 +97,28 @@ static void ssh_mac_update(ssh_mac_ctx ctx, const void *data, size_t len)
static void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx)
{
- switch(ctx->digest_type){
+ switch (ctx->digest_type) {
case SSH_KDF_SHA1:
- sha1_final(md,ctx->ctx.sha1_ctx);
+ sha1_final(md, ctx->ctx.sha1_ctx);
break;
case SSH_KDF_SHA256:
- sha256_final(md,ctx->ctx.sha256_ctx);
+ sha256_final(md, ctx->ctx.sha256_ctx);
break;
case SSH_KDF_SHA384:
- sha384_final(md,ctx->ctx.sha384_ctx);
+ sha384_final(md, ctx->ctx.sha384_ctx);
break;
case SSH_KDF_SHA512:
- sha512_final(md,ctx->ctx.sha512_ctx);
+ sha512_final(md, ctx->ctx.sha512_ctx);
break;
}
SAFE_FREE(ctx);
}
int sshkdf_derive_key(struct ssh_crypto_struct *crypto,
- unsigned char *key, size_t key_len,
- int key_type, unsigned char *output,
+ unsigned char *key,
+ size_t key_len,
+ int key_type,
+ unsigned char *output,
size_t requested_len)
{
/* Can't use VLAs with Visual Studio, so allocate the biggest
--
2.33.0

View File

@ -0,0 +1,37 @@
From 247a4a761cfa745ed1090290c5107de6321143c9 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Tue, 14 Mar 2023 11:35:43 +0100
Subject: [PATCH] CVE-2023-1667:packet: Do not allow servers to initiate
handshake
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
---
Conflict:NA
Reference:https://gitlab.com/libssh/libssh-mirror/commit/247a4a761cfa745ed1090290c5107de6321143c9
---
src/packet.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/packet.c b/src/packet.c
index 527c5d3..b928121 100644
--- a/src/packet.c
+++ b/src/packet.c
@@ -366,6 +366,11 @@ static enum ssh_packet_filter_result_e ssh_packet_incoming_filter(ssh_session se
* - session->dh_handhsake_state = DH_STATE_NEWKEYS_SENT
* */
+ if (!session->server) {
+ rc = SSH_PACKET_DENIED;
+ break;
+ }
+
if (session->session_state != SSH_SESSION_STATE_DH) {
rc = SSH_PACKET_DENIED;
break;
--
2.33.0

View File

@ -0,0 +1,33 @@
From c68a58575b6d0520e342cb3d3796a8fecd66405d Mon Sep 17 00:00:00 2001
From: Norbert Pocs <npocs@redhat.com>
Date: Mon, 24 Apr 2023 11:55:59 +0200
Subject: [PATCH] CVE-2023-2283:pki_crypto: Remove unnecessary NULL check
Signed-off-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict:NA
Reference:https://gitlab.com/libssh/libssh-mirror/commit/c68a58575b6d0520e342cb3d3796a8fecd66405d
---
src/pki_crypto.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/src/pki_crypto.c b/src/pki_crypto.c
index aaa85ba..9f80086 100644
--- a/src/pki_crypto.c
+++ b/src/pki_crypto.c
@@ -2387,9 +2387,7 @@ int pki_verify_data_signature(ssh_signature signature,
rc = SSH_OK;
out:
- if (ctx != NULL) {
- EVP_MD_CTX_free(ctx);
- }
+ EVP_MD_CTX_free(ctx);
if (pkey != NULL) {
EVP_PKEY_free(pkey);
}
--
2.33.0

View File

@ -0,0 +1,125 @@
From fd4948255560039b51c2d61f0a62784ed8b6f5a6 Mon Sep 17 00:00:00 2001
From: Aris Adamantiadis <aris@0xbadc0de.be>
Date: Tue, 12 Dec 2023 23:30:26 +0100
Subject: [PATCH 2/4] CVE-2023-48795: Server side mitigations
Signed-off-by: Aris Adamantiadis <aris@0xbadc0de.be>
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict: NA
Reference: https://gitlab.com/libssh/libssh-mirror/-/commit/fd4948255560039b51c2d61f0a62784ed8b6f5a6
---
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 2ace69b6..40da4ef2 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);
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 0772cae8..e37c176c 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -738,11 +738,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;
/* Skip if already set, for example for the rekey or when we do the guessing
* it could have been already used to make some protocol decisions. */
@@ -791,11 +788,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;
@@ -805,9 +824,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 ed73e7fb..35e84465 100644
--- a/src/server.c
+++ b/src/server.c
@@ -195,7 +195,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.33.0

View File

@ -0,0 +1,82 @@
From a5b8bd0d8841296cf71d927824d60f576581243f Mon Sep 17 00:00:00 2001
From: Norbert Pocs <norbertpocs0@gmail.com>
Date: Tue, 31 Oct 2023 09:48:52 +0100
Subject: [PATCH 2/9] CVE-2023-6004: options: Simplify the hostname parsing in
ssh_options_set
Using ssh_config_parse_uri can simplify the parsing of the host
parsing inside the function of ssh_options_set
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict: NA
Reference:https://git.libssh.org/projects/libssh.git/patch/?id=a5b8bd0d8841296cf71d927824d60f576581243f
---
src/options.c | 40 ++++++++++++++++------------------------
1 file changed, 16 insertions(+), 24 deletions(-)
diff --git a/src/options.c b/src/options.c
index b5f951ac..7c03e7ab 100644
--- a/src/options.c
+++ b/src/options.c
@@ -36,6 +36,7 @@
#include "libssh/session.h"
#include "libssh/misc.h"
#include "libssh/options.h"
+#include "libssh/config_parser.h"
#ifdef WITH_SERVER
#include "libssh/server.h"
#include "libssh/bind.h"
@@ -490,33 +491,24 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
ssh_set_error_invalid(session);
return -1;
} else {
- q = strdup(value);
- if (q == NULL) {
- ssh_set_error_oom(session);
+ char *username = NULL, *hostname = NULL, *port = NULL;
+ rc = ssh_config_parse_uri(value, &username, &hostname, &port);
+ if (rc != SSH_OK) {
return -1;
}
- p = strchr(q, '@');
-
- SAFE_FREE(session->opts.host);
-
- if (p) {
- *p = '\0';
- session->opts.host = strdup(p + 1);
- if (session->opts.host == NULL) {
- SAFE_FREE(q);
- ssh_set_error_oom(session);
- return -1;
- }
-
+ if (port != NULL) {
+ SAFE_FREE(username);
+ SAFE_FREE(hostname);
+ SAFE_FREE(port);
+ return -1;
+ }
+ if (username != NULL) {
SAFE_FREE(session->opts.username);
- session->opts.username = strdup(q);
- SAFE_FREE(q);
- if (session->opts.username == NULL) {
- ssh_set_error_oom(session);
- return -1;
- }
- } else {
- session->opts.host = q;
+ session->opts.username = username;
+ }
+ if (hostname != NULL) {
+ SAFE_FREE(session->opts.host);
+ session->opts.host = hostname;
}
}
break;
--
2.33.0

View File

@ -0,0 +1,300 @@
From 882d9cb5c8d37d93f9b349d517e59bf496817007 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Fri, 15 Dec 2023 12:55:27 +0100
Subject: [PATCH 2/5] CVE-2023-6918: Remove unused evp functions and types
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict: NA
Reference:https://gitlab.com/libssh/libssh-mirror/-/commit/882d9cb5c8d37d93f9b349d517e59bf496817007
---
include/libssh/libcrypto.h | 5 ---
include/libssh/libgcrypt.h | 1 -
include/libssh/libmbedcrypto.h | 1 -
include/libssh/wrapper.h | 5 ---
src/libcrypto.c | 55 +------------------------
src/libgcrypt.c | 52 ------------------------
src/libmbedcrypto.c | 74 ----------------------------------
7 files changed, 1 insertion(+), 192 deletions(-)
diff --git a/include/libssh/libcrypto.h b/include/libssh/libcrypto.h
index 4117942c..35b277c5 100644
--- a/include/libssh/libcrypto.h
+++ b/include/libssh/libcrypto.h
@@ -39,11 +39,6 @@ typedef EVP_MD_CTX* SHA384CTX;
typedef EVP_MD_CTX* SHA512CTX;
typedef EVP_MD_CTX* MD5CTX;
typedef HMAC_CTX* HMACCTX;
-#ifdef HAVE_ECC
-typedef EVP_MD_CTX *EVPCTX;
-#else
-typedef void *EVPCTX;
-#endif
#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
#define SHA256_DIGEST_LEN SHA256_DIGEST_LENGTH
diff --git a/include/libssh/libgcrypt.h b/include/libssh/libgcrypt.h
index 347d851b..3a803fa4 100644
--- a/include/libssh/libgcrypt.h
+++ b/include/libssh/libgcrypt.h
@@ -32,7 +32,6 @@ typedef gcry_md_hd_t SHA384CTX;
typedef gcry_md_hd_t SHA512CTX;
typedef gcry_md_hd_t MD5CTX;
typedef gcry_md_hd_t HMACCTX;
-typedef gcry_md_hd_t EVPCTX;
#define SHA_DIGEST_LENGTH 20
#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
#define MD5_DIGEST_LEN 16
diff --git a/include/libssh/libmbedcrypto.h b/include/libssh/libmbedcrypto.h
index fe53019b..b6e3e2a3 100644
--- a/include/libssh/libmbedcrypto.h
+++ b/include/libssh/libmbedcrypto.h
@@ -41,7 +41,6 @@ typedef mbedtls_md_context_t *SHA384CTX;
typedef mbedtls_md_context_t *SHA512CTX;
typedef mbedtls_md_context_t *MD5CTX;
typedef mbedtls_md_context_t *HMACCTX;
-typedef mbedtls_md_context_t *EVPCTX;
#define SHA_DIGEST_LENGTH 20
#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
diff --git a/include/libssh/wrapper.h b/include/libssh/wrapper.h
index ba64939b..2f5ce189 100644
--- a/include/libssh/wrapper.h
+++ b/include/libssh/wrapper.h
@@ -90,11 +90,6 @@ void sha512_update(SHA512CTX c, const void *data, unsigned long len);
void sha512_final(unsigned char *md,SHA512CTX c);
void sha512(const unsigned char *digest, int len, unsigned char *hash);
-void evp(int nid, unsigned char *digest, int len, unsigned char *hash, unsigned int *hlen);
-EVPCTX evp_init(int nid);
-void evp_update(EVPCTX ctx, const void *data, unsigned long len);
-void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen);
-
HMACCTX hmac_init(const void *key,int len, enum ssh_hmac_e type);
void hmac_update(HMACCTX c, const void *data, unsigned long len);
void hmac_final(HMACCTX ctx,unsigned char *hashmacbuf,unsigned int *len);
diff --git a/src/libcrypto.c b/src/libcrypto.c
index 3db75df6..5f3917ba 100644
--- a/src/libcrypto.c
+++ b/src/libcrypto.c
@@ -148,60 +148,6 @@ void sha1(const unsigned char *digest, int len, unsigned char *hash)
}
}
-#ifdef HAVE_OPENSSL_ECC
-static const EVP_MD *nid_to_evpmd(int nid)
-{
- switch (nid) {
- case NID_X9_62_prime256v1:
- return EVP_sha256();
- case NID_secp384r1:
- return EVP_sha384();
- case NID_secp521r1:
- return EVP_sha512();
- default:
- return NULL;
- }
-
- return NULL;
-}
-
-void evp(int nid, unsigned char *digest, int len, unsigned char *hash, unsigned int *hlen)
-{
- const EVP_MD *evp_md = nid_to_evpmd(nid);
- EVP_MD_CTX *md = EVP_MD_CTX_new();
-
- EVP_DigestInit(md, evp_md);
- EVP_DigestUpdate(md, digest, len);
- EVP_DigestFinal(md, hash, hlen);
- EVP_MD_CTX_free(md);
-}
-
-EVPCTX evp_init(int nid)
-{
- const EVP_MD *evp_md = nid_to_evpmd(nid);
-
- EVPCTX ctx = EVP_MD_CTX_new();
- if (ctx == NULL) {
- return NULL;
- }
-
- EVP_DigestInit(ctx, evp_md);
-
- return ctx;
-}
-
-void evp_update(EVPCTX ctx, const void *data, unsigned long len)
-{
- EVP_DigestUpdate(ctx, data, len);
-}
-
-void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen)
-{
- EVP_DigestFinal(ctx, md, mdlen);
- EVP_MD_CTX_free(ctx);
-}
-#endif
-
SHA256CTX sha256_init(void)
{
int rc;
@@ -345,6 +291,7 @@ void md5_final(unsigned char *md, MD5CTX c)
EVP_MD_CTX_destroy(c);
}
+
#ifdef HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID
static const EVP_MD *sshkdf_digest_to_md(enum ssh_kdf_digest digest_type)
{
diff --git a/src/libgcrypt.c b/src/libgcrypt.c
index 8fbf2157..49488793 100644
--- a/src/libgcrypt.c
+++ b/src/libgcrypt.c
@@ -82,58 +82,6 @@ void sha1(const unsigned char *digest, int len, unsigned char *hash) {
gcry_md_hash_buffer(GCRY_MD_SHA1, hash, digest, len);
}
-#ifdef HAVE_GCRYPT_ECC
-static int nid_to_md_algo(int nid)
-{
- switch (nid) {
- case NID_gcrypt_nistp256:
- return GCRY_MD_SHA256;
- case NID_gcrypt_nistp384:
- return GCRY_MD_SHA384;
- case NID_gcrypt_nistp521:
- return GCRY_MD_SHA512;
- }
- return GCRY_MD_NONE;
-}
-
-void evp(int nid, unsigned char *digest, int len,
- unsigned char *hash, unsigned int *hlen)
-{
- int algo = nid_to_md_algo(nid);
-
- /* Note: What gcrypt calls 'hash' is called 'digest' here and
- vice-versa. */
- gcry_md_hash_buffer(algo, hash, digest, len);
- *hlen = gcry_md_get_algo_dlen(algo);
-}
-
-EVPCTX evp_init(int nid)
-{
- gcry_error_t err;
- int algo = nid_to_md_algo(nid);
- EVPCTX ctx;
-
- err = gcry_md_open(&ctx, algo, 0);
- if (err) {
- return NULL;
- }
-
- return ctx;
-}
-
-void evp_update(EVPCTX ctx, const void *data, unsigned long len)
-{
- gcry_md_write(ctx, data, len);
-}
-
-void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen)
-{
- int algo = gcry_md_get_algo(ctx);
- *mdlen = gcry_md_get_algo_dlen(algo);
- memcpy(md, gcry_md_read(ctx, algo), *mdlen);
- gcry_md_close(ctx);
-}
-#endif
SHA256CTX sha256_init(void) {
SHA256CTX ctx = NULL;
diff --git a/src/libmbedcrypto.c b/src/libmbedcrypto.c
index a2e74d3b..f37a6a6d 100644
--- a/src/libmbedcrypto.c
+++ b/src/libmbedcrypto.c
@@ -103,80 +103,6 @@ void sha1(const unsigned char *digest, int len, unsigned char *hash)
}
}
-static mbedtls_md_type_t nid_to_md_algo(int nid)
-{
- switch (nid) {
- case NID_mbedtls_nistp256:
- return MBEDTLS_MD_SHA256;
- case NID_mbedtls_nistp384:
- return MBEDTLS_MD_SHA384;
- case NID_mbedtls_nistp521:
- return MBEDTLS_MD_SHA512;
- }
- return MBEDTLS_MD_NONE;
-}
-
-void evp(int nid, unsigned char *digest, int len,
- unsigned char *hash, unsigned int *hlen)
-{
- mbedtls_md_type_t algo = nid_to_md_algo(nid);
- const mbedtls_md_info_t *md_info =
- mbedtls_md_info_from_type(algo);
-
-
- if (md_info != NULL) {
- *hlen = mbedtls_md_get_size(md_info);
- mbedtls_md(md_info, digest, len, hash);
- }
-}
-
-EVPCTX evp_init(int nid)
-{
- EVPCTX ctx = NULL;
- int rc;
- mbedtls_md_type_t algo = nid_to_md_algo(nid);
- const mbedtls_md_info_t *md_info =
- mbedtls_md_info_from_type(algo);
-
- if (md_info == NULL) {
- return NULL;
- }
-
- ctx = malloc(sizeof(mbedtls_md_context_t));
- if (ctx == NULL) {
- return NULL;
- }
-
- mbedtls_md_init(ctx);
-
- rc = mbedtls_md_setup(ctx, md_info, 0);
- if (rc != 0) {
- SAFE_FREE(ctx);
- return NULL;
- }
-
- rc = mbedtls_md_starts(ctx);
- if (rc != 0) {
- SAFE_FREE(ctx);
- return NULL;
- }
-
- return ctx;
-}
-
-void evp_update(EVPCTX ctx, const void *data, unsigned long len)
-{
- mbedtls_md_update(ctx, data, len);
-}
-
-void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen)
-{
- *mdlen = mbedtls_md_get_size(ctx->md_info);
- mbedtls_md_finish(ctx, md);
- mbedtls_md_free(ctx);
- SAFE_FREE(ctx);
-}
-
SHA256CTX sha256_init(void)
{
SHA256CTX ctx = NULL;
--
2.33.0

View File

@ -0,0 +1,107 @@
From 99760776d4552d8e63edd68ba4a7448766517b8c Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Mon, 13 Mar 2023 15:11:25 +0100
Subject: [PATCH] CVE-2023-1667:kex: Remove needless function argument
The information if the session is client or server session is already
part of
the session structure so this argument only duplicated information.
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict:NA
Reference:https://gitlab.com/libssh/libssh-mirror/commit/99760776d4552d8e63edd68ba4a7448766517b8c
---
include/libssh/kex.h | 2 +-
src/client.c | 4 ++--
src/kex.c | 7 ++++---
src/server.c | 4 ++--
4 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/include/libssh/kex.h b/include/libssh/kex.h
index 3a1f4a6..2ace69b 100644
--- a/include/libssh/kex.h
+++ b/include/libssh/kex.h
@@ -33,7 +33,7 @@ struct ssh_kex_struct {
SSH_PACKET_CALLBACK(ssh_packet_kexinit);
-int ssh_send_kex(ssh_session session, int server_kex);
+int ssh_send_kex(ssh_session session);
void ssh_list_kex(struct ssh_kex_struct *kex);
int ssh_set_client_kex(ssh_session session);
int ssh_kex_select_methods(ssh_session session);
diff --git a/src/client.c b/src/client.c
index 6d30356..6b40136 100644
--- a/src/client.c
+++ b/src/client.c
@@ -420,7 +420,7 @@ static void ssh_client_connection_callback(ssh_session session)
if (rc != SSH_OK) {
goto error;
}
- rc = ssh_send_kex(session, 0);
+ rc = ssh_send_kex(session);
if (rc < 0) {
goto error;
}
@@ -439,7 +439,7 @@ static void ssh_client_connection_callback(ssh_session session)
if (rc != SSH_OK) {
goto error;
}
- rc = ssh_send_kex(session, 0);
+ rc = ssh_send_kex(session);
if (rc < 0) {
goto error;
}
diff --git a/src/kex.c b/src/kex.c
index 602de1c..dddfb81 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -806,8 +806,9 @@ int ssh_kex_select_methods (ssh_session session){
/* this function only sends the predefined set of kex methods */
-int ssh_send_kex(ssh_session session, int server_kex) {
- struct ssh_kex_struct *kex = (server_kex ? &session->next_crypto->server_kex :
+int ssh_send_kex(ssh_session session) {
+ struct ssh_kex_struct *kex = (session->server ?
+ &session->next_crypto->server_kex :
&session->next_crypto->client_kex);
ssh_string str = NULL;
int i;
@@ -904,7 +905,7 @@ int ssh_send_rekex(ssh_session session)
}
session->dh_handshake_state = DH_STATE_INIT;
- rc = ssh_send_kex(session, session->server);
+ rc = ssh_send_kex(session);
if (rc < 0) {
SSH_LOG(SSH_LOG_PACKET, "Failed to send kex");
return rc;
diff --git a/src/server.c b/src/server.c
index 841a1c4..9354025 100644
--- a/src/server.c
+++ b/src/server.c
@@ -367,7 +367,7 @@ static void ssh_server_connection_callback(ssh_session session){
ssh_packet_set_default_callbacks(session);
set_status(session, 0.5f);
session->session_state=SSH_SESSION_STATE_INITIAL_KEX;
- if (ssh_send_kex(session, 1) < 0) {
+ if (ssh_send_kex(session) < 0) {
goto error;
}
break;
@@ -380,7 +380,7 @@ static void ssh_server_connection_callback(ssh_session session){
if(server_set_kex(session) == SSH_ERROR)
goto error;
/* We are in a rekeying, so we need to send the server kex */
- if(ssh_send_kex(session, 1) < 0)
+ if (ssh_send_kex(session) < 0)
goto error;
}
ssh_list_kex(&session->next_crypto->client_kex); // log client kex
--
2.23.0

View File

@ -0,0 +1,46 @@
From 03bbbc9e4c93aae2ccdd302d6123e4809be37746 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Thu, 14 Dec 2023 12:22:01 +0100
Subject: [PATCH 3/4] CVE-2023-48795: Strip extensions from both kex lists for
matching
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict: NA
Reference:https://gitlab.com/libssh/libssh-mirror/-/commit/03bbbc9e4c93aae2ccdd302d6123e4809be37747
---
src/kex.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/src/kex.c b/src/kex.c
index e37c176c..eea3604b 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -936,11 +936,19 @@ int ssh_kex_select_methods (ssh_session session)
enum ssh_key_exchange_e kex_type;
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.33.0

View File

@ -0,0 +1,117 @@
From efb24b6472e8b87c5832c0590f14e99e82fcdeeb Mon Sep 17 00:00:00 2001
From: Norbert Pocs <norbertpocs0@gmail.com>
Date: Tue, 10 Oct 2023 12:44:16 +0200
Subject: [PATCH 3/9] CVE-2023-6004: misc: Add function to check allowed
characters of a hostname
The hostname can be a domain name or an ip address. The colon has to be
allowed because of IPv6 even it is prohibited in domain names.
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict: NA
Reference:https://git.libssh.org/projects/libssh.git/patch/?id=efb24b6472e8b87c5832c0590f14e99e82fcdeeb
---
include/libssh/misc.h | 2 ++
src/misc.c | 68 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 70 insertions(+)
diff --git a/include/libssh/misc.h b/include/libssh/misc.h
index 3cc3b113..a5bee930 100644
--- a/include/libssh/misc.h
+++ b/include/libssh/misc.h
@@ -97,4 +97,6 @@ int ssh_mkdirs(const char *pathname, mode_t mode);
int ssh_quote_file_name(const char *file_name, char *buf, size_t buf_len);
int ssh_newline_vis(const char *string, char *buf, size_t buf_len);
+int ssh_check_hostname_syntax(const char *hostname);
+
#endif /* MISC_H_ */
diff --git a/src/misc.c b/src/misc.c
index 149eb85e..e4239e81 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -94,6 +94,8 @@
#define ZLIB_STRING ""
#endif
+#define ARPA_DOMAIN_MAX_LEN 63
+
/**
* @defgroup libssh_misc The SSH helper functions.
* @ingroup libssh
@@ -1734,4 +1736,70 @@ int ssh_newline_vis(const char *string, char *buf, size_t buf_len)
return out - buf;
}
+/**
+ * @brief Checks syntax of a domain name
+ *
+ * The check is made based on the RFC1035 section 2.3.1
+ * Allowed characters are: hyphen, period, digits (0-9) and letters (a-zA-Z)
+ *
+ * The label should be no longer than 63 characters
+ * The label should start with a letter and end with a letter or number
+ * The label in this implementation can start with a number to allow virtual
+ * URLs to pass. Note that this will make IPv4 addresses to pass
+ * this check too.
+ *
+ * @param hostname The domain name to be checked, has to be null terminated
+ *
+ * @return SSH_OK if the hostname passes syntax check
+ * SSH_ERROR otherwise or if hostname is NULL or empty string
+ */
+int ssh_check_hostname_syntax(const char *hostname)
+{
+ char *it = NULL, *s = NULL, *buf = NULL;
+ size_t it_len;
+ char c;
+
+ if (hostname == NULL || strlen(hostname) == 0) {
+ return SSH_ERROR;
+ }
+
+ /* strtok_r writes into the string, keep the input clean */
+ s = strdup(hostname);
+ if (s == NULL) {
+ return SSH_ERROR;
+ }
+
+ it = strtok_r(s, ".", &buf);
+ /* if the token has 0 length */
+ if (it == NULL) {
+ free(s);
+ return SSH_ERROR;
+ }
+ do {
+ it_len = strlen(it);
+ if (it_len > ARPA_DOMAIN_MAX_LEN ||
+ /* the first char must be a letter, but some virtual urls start
+ * with a number */
+ isalnum(it[0]) == 0 ||
+ isalnum(it[it_len - 1]) == 0) {
+ free(s);
+ return SSH_ERROR;
+ }
+ while (*it != '\0') {
+ c = *it;
+ /* the "." is allowed too, but tokenization removes it from the
+ * string */
+ if (isalnum(c) == 0 && c != '-') {
+ free(s);
+ return SSH_ERROR;
+ }
+ it++;
+ }
+ } while ((it = strtok_r(NULL, ".", &buf)) != NULL);
+
+ free(s);
+
+ return SSH_OK;
+}
+
/** @} */
--
2.33.0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,102 @@
From 6df2daea040c47daff0a861a30761092886fe748 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Thu, 16 Mar 2023 14:16:11 +0100
Subject: [PATCH] CVE-2023-1667:kex: Factor out the kex mapping to
internal
enum
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict:NA
Reference:https://gitlab.com/libssh/libssh-mirror/commit/6df2daea040c47daff0a861a30761092886fe748
---
src/kex.c | 64 ++++++++++++++++++++++++++++++++-----------------------
1 file changed, 37 insertions(+), 27 deletions(-)
diff --git a/src/kex.c b/src/kex.c
index dddfb81..47d0eae 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -735,6 +735,40 @@ int ssh_set_client_kex(ssh_session session)
return SSH_OK;
}
+static enum ssh_key_exchange_e
+kex_select_kex_type(const char *kex)
+{
+ if (strcmp(kex, "diffie-hellman-group1-sha1") == 0) {
+ return SSH_KEX_DH_GROUP1_SHA1;
+ } else if (strcmp(kex, "diffie-hellman-group14-sha1") == 0) {
+ return SSH_KEX_DH_GROUP14_SHA1;
+ } else if (strcmp(kex, "diffie-hellman-group14-sha256") == 0) {
+ return SSH_KEX_DH_GROUP14_SHA256;
+ } else if (strcmp(kex, "diffie-hellman-group16-sha512") == 0) {
+ return SSH_KEX_DH_GROUP16_SHA512;
+ } else if (strcmp(kex, "diffie-hellman-group18-sha512") == 0) {
+ return SSH_KEX_DH_GROUP18_SHA512;
+#ifdef WITH_GEX
+ } else if (strcmp(kex, "diffie-hellman-group-exchange-sha1") == 0) {
+ return SSH_KEX_DH_GEX_SHA1;
+ } else if (strcmp(kex, "diffie-hellman-group-exchange-sha256") == 0) {
+ return SSH_KEX_DH_GEX_SHA256;
+#endif /* WITH_GEX */
+ } else if (strcmp(kex, "ecdh-sha2-nistp256") == 0) {
+ return SSH_KEX_ECDH_SHA2_NISTP256;
+ } else if (strcmp(kex, "ecdh-sha2-nistp384") == 0) {
+ return SSH_KEX_ECDH_SHA2_NISTP384;
+ } else if (strcmp(kex, "ecdh-sha2-nistp521") == 0) {
+ return SSH_KEX_ECDH_SHA2_NISTP521;
+ } else if (strcmp(kex, "curve25519-sha256@libssh.org") == 0) {
+ return SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG;
+ } else if (strcmp(kex, "curve25519-sha256") == 0) {
+ return SSH_KEX_CURVE25519_SHA256;
+ }
+ /* should not happen. We should be getting only valid names at this stage */
+ return 0;
+}
+
/** @brief Select the different methods on basis of client's and
* server's kex messages, and watches out if a match is possible.
*/
@@ -762,33 +796,9 @@ int ssh_kex_select_methods (ssh_session session){
session->next_crypto->kex_methods[i] = strdup("");
}
}
- if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group1-sha1") == 0){
- 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-group14-sha256") == 0){
- session->next_crypto->kex_type=SSH_KEX_DH_GROUP14_SHA256;
- } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group16-sha512") == 0){
- session->next_crypto->kex_type=SSH_KEX_DH_GROUP16_SHA512;
- } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group18-sha512") == 0){
- session->next_crypto->kex_type=SSH_KEX_DH_GROUP18_SHA512;
-#ifdef WITH_GEX
- } 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;
-#endif /* WITH_GEX */
- } 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], "ecdh-sha2-nistp384") == 0){
- session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP384;
- } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp521") == 0){
- session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP521;
- } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "curve25519-sha256@libssh.org") == 0){
- session->next_crypto->kex_type=SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG;
- } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "curve25519-sha256") == 0){
- session->next_crypto->kex_type=SSH_KEX_CURVE25519_SHA256;
- }
+ kex = session->next_crypto->kex_methods[SSH_KEX];
+ session->next_crypto->kex_type = kex_select_kex_type(kex);
+
SSH_LOG(SSH_LOG_INFO, "Negotiated %s,%s,%s,%s,%s,%s,%s,%s,%s,%s",
session->next_crypto->kex_methods[SSH_KEX],
session->next_crypto->kex_methods[SSH_HOSTKEYS],
--
2.23.0

View File

@ -0,0 +1,89 @@
From 768d1ed30cf4b3cb9628254ef3ee24b9c38abdbc Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Thu, 14 Dec 2023 12:47:48 +0100
Subject: [PATCH 4/4] CVE-2023-48795: tests: Adjust calculation to strict kex
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict:NA
Reference:https://gitlab.com/libssh/libssh-mirror/-/commit/768d1ed30cf4b3cb9628254ef3ee24b9c38abdbc
---
tests/client/torture_rekey.c | 45 ++++++++++++++++++++----------------
1 file changed, 29 insertions(+), 16 deletions(-)
diff --git a/tests/client/torture_rekey.c b/tests/client/torture_rekey.c
index 13c9a7fe..bfb273af 100644
--- a/tests/client/torture_rekey.c
+++ b/tests/client/torture_rekey.c
@@ -148,6 +148,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
*/
@@ -166,16 +189,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);
@@ -272,14 +289,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);
--
2.33.0

View File

@ -0,0 +1,109 @@
From 234ecdf4d9705efa3727a54dcc1ddfe6377c7bf6 Mon Sep 17 00:00:00 2001
From: Norbert Pocs <norbertpocs0@gmail.com>
Date: Tue, 10 Oct 2023 12:45:28 +0200
Subject: [PATCH 4/9] CVE-2023-6004: torture_misc: Add test for
ssh_check_hostname_syntax
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict: NA
Reference:https://git.libssh.org/projects/libssh.git/patch/?id=234ecdf4d9705efa3727a54dcc1ddfe6377c7bf6
---
tests/unittests/torture_misc.c | 73 ++++++++++++++++++++++++++++++++++
1 file changed, 73 insertions(+)
diff --git a/tests/unittests/torture_misc.c b/tests/unittests/torture_misc.c
index 0a48abbe..d14f4254 100644
--- a/tests/unittests/torture_misc.c
+++ b/tests/unittests/torture_misc.c
@@ -656,6 +656,78 @@ static void torture_ssh_newline_vis(UNUSED_PARAM(void **state))
assert_string_equal(buffer, "a\\nb\\n");
}
+static void torture_ssh_check_hostname_syntax(void **state)
+{
+ int rc;
+ (void)state;
+
+ rc = ssh_check_hostname_syntax("duckduckgo.com");
+ assert_int_equal(rc, SSH_OK);
+ rc = ssh_check_hostname_syntax("www.libssh.org");
+ assert_int_equal(rc, SSH_OK);
+ rc = ssh_check_hostname_syntax("Some-Thing.com");
+ assert_int_equal(rc, SSH_OK);
+ rc = ssh_check_hostname_syntax("amazon.a23456789012345678901234567890123456789012345678901234567890123");
+ assert_int_equal(rc, SSH_OK);
+ rc = ssh_check_hostname_syntax("amazon.a23456789012345678901234567890123456789012345678901234567890123.a23456789012345678901234567890123456789012345678901234567890123.ok");
+ assert_int_equal(rc, SSH_OK);
+ rc = ssh_check_hostname_syntax("amazon.a23456789012345678901234567890123456789012345678901234567890123.a23456789012345678901234567890123456789012345678901234567890123.a23456789012345678901234567890123456789012345678901234567890123");
+ assert_int_equal(rc, SSH_OK);
+ rc = ssh_check_hostname_syntax("lavabo-inter.innocentes-manus-meas");
+ assert_int_equal(rc, SSH_OK);
+ rc = ssh_check_hostname_syntax("localhost");
+ assert_int_equal(rc, SSH_OK);
+ rc = ssh_check_hostname_syntax("a");
+ assert_int_equal(rc, SSH_OK);
+ rc = ssh_check_hostname_syntax("a-0.b-b");
+ assert_int_equal(rc, SSH_OK);
+ rc = ssh_check_hostname_syntax("libssh.");
+ assert_int_equal(rc, SSH_OK);
+
+ rc = ssh_check_hostname_syntax(NULL);
+ assert_int_equal(rc, SSH_ERROR);
+ rc = ssh_check_hostname_syntax("");
+ assert_int_equal(rc, SSH_ERROR);
+ rc = ssh_check_hostname_syntax("/");
+ assert_int_equal(rc, SSH_ERROR);
+ rc = ssh_check_hostname_syntax("@");
+ assert_int_equal(rc, SSH_ERROR);
+ rc = ssh_check_hostname_syntax("[");
+ assert_int_equal(rc, SSH_ERROR);
+ rc = ssh_check_hostname_syntax("`");
+ assert_int_equal(rc, SSH_ERROR);
+ rc = ssh_check_hostname_syntax("{");
+ assert_int_equal(rc, SSH_ERROR);
+ rc = ssh_check_hostname_syntax("&");
+ assert_int_equal(rc, SSH_ERROR);
+ rc = ssh_check_hostname_syntax("|");
+ assert_int_equal(rc, SSH_ERROR);
+ rc = ssh_check_hostname_syntax("\"");
+ assert_int_equal(rc, SSH_ERROR);
+ rc = ssh_check_hostname_syntax("`");
+ assert_int_equal(rc, SSH_ERROR);
+ rc = ssh_check_hostname_syntax(" ");
+ assert_int_equal(rc, SSH_ERROR);
+ rc = ssh_check_hostname_syntax("*the+giant&\"rooks\".c0m");
+ assert_int_equal(rc, SSH_ERROR);
+ rc = ssh_check_hostname_syntax("!www.libssh.org");
+ assert_int_equal(rc, SSH_ERROR);
+ rc = ssh_check_hostname_syntax("--.--");
+ assert_int_equal(rc, SSH_ERROR);
+ rc = ssh_check_hostname_syntax("libssh.a234567890123456789012345678901234567890123456789012345678901234");
+ assert_int_equal(rc, SSH_ERROR);
+ rc = ssh_check_hostname_syntax("libssh.a234567890123456789012345678901234567890123456789012345678901234.a234567890123456789012345678901234567890123456789012345678901234");
+ assert_int_equal(rc, SSH_ERROR);
+ rc = ssh_check_hostname_syntax("libssh-");
+ assert_int_equal(rc, SSH_ERROR);
+ rc = ssh_check_hostname_syntax("fe80::9656:d028:8652:66b6");
+ assert_int_equal(rc, SSH_ERROR);
+ rc = ssh_check_hostname_syntax(".");
+ assert_int_equal(rc, SSH_ERROR);
+ rc = ssh_check_hostname_syntax("..");
+ assert_int_equal(rc, SSH_ERROR);
+}
+
int torture_run_tests(void) {
int rc;
struct CMUnitTest tests[] = {
@@ -678,6 +750,7 @@ int torture_run_tests(void) {
cmocka_unit_test(torture_ssh_newline_vis),
cmocka_unit_test(torture_ssh_mkdirs),
cmocka_unit_test(torture_ssh_quote_file_name),
+ cmocka_unit_test(torture_ssh_check_hostname_syntax),
};
ssh_init();
--
2.33.0

View File

@ -0,0 +1,57 @@
From 9276027c687723886e8277b77061464303845831 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Fri, 15 Dec 2023 13:35:14 +0100
Subject: [PATCH 4/5] CVE-2023-6918: kdf: Detect context init failures
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict:NA
Reference:https://gitlab.com/libssh/libssh-mirror/-/commit/9276027c687723886e8277b77061464303845831
---
src/kdf.c | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/src/kdf.c b/src/kdf.c
index 90f6e9f3..b08f0b2f 100644
--- a/src/kdf.c
+++ b/src/kdf.c
@@ -61,20 +61,32 @@ static ssh_mac_ctx ssh_mac_ctx_init(enum ssh_kdf_digest type)
switch (type) {
case SSH_KDF_SHA1:
ctx->ctx.sha1_ctx = sha1_init();
+ if (ctx->ctx.sha1_ctx == NULL) {
+ goto err;
+ }
return ctx;
case SSH_KDF_SHA256:
ctx->ctx.sha256_ctx = sha256_init();
+ if (ctx->ctx.sha256_ctx == NULL) {
+ goto err;
+ }
return ctx;
case SSH_KDF_SHA384:
ctx->ctx.sha384_ctx = sha384_init();
+ if (ctx->ctx.sha384_ctx == NULL) {
+ goto err;
+ }
return ctx;
case SSH_KDF_SHA512:
ctx->ctx.sha512_ctx = sha512_init();
+ if (ctx->ctx.sha512_ctx == NULL) {
+ goto err;
+ }
return ctx;
- default:
- SAFE_FREE(ctx);
- return NULL;
}
+err:
+ SAFE_FREE(ctx);
+ return NULL;
}
static void ssh_mac_ctx_free(ssh_mac_ctx ctx)
--
2.33.0

View File

@ -0,0 +1,227 @@
From b759ae557d611ba347392c051504de474a8d9b60 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Fri, 17 Mar 2023 14:05:01 +0100
Subject: [PATCH] CVE-2023-1667:dh: Expose the callback cleanup functions
These will be helpful when we already sent the first key exchange packet, but we
found out that our guess was wrong and we need to initiate different key
exchange method with different callbacks.
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict:NA
Reference:https://gitlab.com/libssh/libssh-mirror/commit/b759ae557d611ba347392c051504de474a8d9b60
---
include/libssh/curve25519.h | 1 +
include/libssh/dh-gex.h | 1 +
include/libssh/dh.h | 1 +
include/libssh/ecdh.h | 1 +
src/curve25519.c | 7 ++++++-
src/dh-gex.c | 7 ++++++-
src/dh.c | 7 ++++++-
src/ecdh.c | 7 ++++++-
src/kex.c | 38 +++++++++++++++++++++++++++++++++++++
9 files changed, 66 insertions(+), 4 deletions(-)
diff --git a/include/libssh/curve25519.h b/include/libssh/curve25519.h
index f0cc634..77e6c31 100644
--- a/include/libssh/curve25519.h
+++ b/include/libssh/curve25519.h
@@ -48,6 +48,7 @@ typedef unsigned char ssh_curve25519_privkey[CURVE25519_PRIVKEY_SIZE];
int ssh_client_curve25519_init(ssh_session session);
+void ssh_client_curve25519_remove_callbacks(ssh_session session);
#ifdef WITH_SERVER
void ssh_server_curve25519_init(ssh_session session);
diff --git a/include/libssh/dh-gex.h b/include/libssh/dh-gex.h
index 4fc23d8..7a91d7d 100644
--- a/include/libssh/dh-gex.h
+++ b/include/libssh/dh-gex.h
@@ -24,6 +24,7 @@
#define SRC_DH_GEX_H_
int ssh_client_dhgex_init(ssh_session session);
+void ssh_client_dhgex_remove_callbacks(ssh_session session);
#ifdef WITH_SERVER
void ssh_server_dhgex_init(ssh_session session);
diff --git a/include/libssh/dh.h b/include/libssh/dh.h
index 390b30d..57f37cd 100644
--- a/include/libssh/dh.h
+++ b/include/libssh/dh.h
@@ -65,6 +65,7 @@ int ssh_dh_get_next_server_publickey_blob(ssh_session session,
ssh_string *pubkey_blob);
int ssh_client_dh_init(ssh_session session);
+void ssh_client_dh_remove_callbacks(ssh_session session);
#ifdef WITH_SERVER
void ssh_server_dh_init(ssh_session session);
#endif /* WITH_SERVER */
diff --git a/include/libssh/ecdh.h b/include/libssh/ecdh.h
index 17fe02e..c1f03a9 100644
--- a/include/libssh/ecdh.h
+++ b/include/libssh/ecdh.h
@@ -45,6 +45,7 @@
extern struct ssh_packet_callbacks_struct ssh_ecdh_client_callbacks;
/* Backend-specific functions. */
int ssh_client_ecdh_init(ssh_session session);
+void ssh_client_ecdh_remove_callbacks(ssh_session session);
int ecdh_build_k(ssh_session session);
#ifdef WITH_SERVER
diff --git a/src/curve25519.c b/src/curve25519.c
index d251755..3765443 100644
--- a/src/curve25519.c
+++ b/src/curve25519.c
@@ -172,6 +172,11 @@ int ssh_client_curve25519_init(ssh_session session)
return rc;
}
+void ssh_client_curve25519_remove_callbacks(ssh_session session)
+{
+ ssh_packet_remove_callbacks(session, &ssh_curve25519_client_callbacks);
+}
+
static int ssh_curve25519_build_k(ssh_session session)
{
ssh_curve25519_pubkey k;
@@ -285,7 +290,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_client_curve25519_reply){
(void)type;
(void)user;
- ssh_packet_remove_callbacks(session, &ssh_curve25519_client_callbacks);
+ ssh_client_curve25519_remove_callbacks(session);
pubkey_blob = ssh_buffer_get_ssh_string(packet);
if (pubkey_blob == NULL) {
diff --git a/src/dh-gex.c b/src/dh-gex.c
index 88a9714..4a29854 100644
--- a/src/dh-gex.c
+++ b/src/dh-gex.c
@@ -238,6 +238,11 @@ error:
return SSH_PACKET_USED;
}
+void ssh_client_dhgex_remove_callbacks(ssh_session session)
+{
+ ssh_packet_remove_callbacks(session, &ssh_dhgex_client_callbacks);
+}
+
static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_reply)
{
struct ssh_crypto_struct *crypto=session->next_crypto;
@@ -248,7 +253,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_reply)
(void)user;
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_DH_GEX_REPLY received");
- ssh_packet_remove_callbacks(session, &ssh_dhgex_client_callbacks);
+ ssh_client_dhgex_remove_callbacks(session);
rc = ssh_buffer_unpack(packet,
"SBS",
&pubkey_blob, &server_pubkey,
diff --git a/src/dh.c b/src/dh.c
index 18b7173..c265efc 100644
--- a/src/dh.c
+++ b/src/dh.c
@@ -342,6 +342,11 @@ error:
return SSH_ERROR;
}
+void ssh_client_dh_remove_callbacks(ssh_session session)
+{
+ ssh_packet_remove_callbacks(session, &ssh_dh_client_callbacks);
+}
+
SSH_PACKET_CALLBACK(ssh_packet_client_dh_reply){
struct ssh_crypto_struct *crypto=session->next_crypto;
ssh_string pubkey_blob = NULL;
@@ -351,7 +356,7 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dh_reply){
(void)type;
(void)user;
- ssh_packet_remove_callbacks(session, &ssh_dh_client_callbacks);
+ ssh_client_dh_remove_callbacks(session);
rc = ssh_buffer_unpack(packet, "SBS", &pubkey_blob, &server_pubkey,
&crypto->dh_server_signature);
diff --git a/src/ecdh.c b/src/ecdh.c
index a4c07cc..e5b11ba 100644
--- a/src/ecdh.c
+++ b/src/ecdh.c
@@ -43,6 +43,11 @@ struct ssh_packet_callbacks_struct ssh_ecdh_client_callbacks = {
.user = NULL
};
+void ssh_client_ecdh_remove_callbacks(ssh_session session)
+{
+ ssh_packet_remove_callbacks(session, &ssh_ecdh_client_callbacks);
+}
+
/** @internal
* @brief parses a SSH_MSG_KEX_ECDH_REPLY packet and sends back
* a SSH_MSG_NEWKEYS
@@ -55,7 +60,7 @@ SSH_PACKET_CALLBACK(ssh_packet_client_ecdh_reply){
(void)type;
(void)user;
- ssh_packet_remove_callbacks(session, &ssh_ecdh_client_callbacks);
+ ssh_client_ecdh_remove_callbacks(session);
pubkey_blob = ssh_buffer_get_ssh_string(packet);
if (pubkey_blob == NULL) {
ssh_set_error(session,SSH_FATAL, "No public key in packet");
diff --git a/src/kex.c b/src/kex.c
index 94ccccf..f1dab08 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -783,6 +783,44 @@ kex_select_kex_type(const char *kex)
return 0;
}
+
+/** @internal
+ * @brief Reverts guessed callbacks set during the dh_handshake()
+ * @param session session handle
+ * @returns void
+ */
+static void revert_kex_callbacks(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_GROUP14_SHA256:
+ case SSH_KEX_DH_GROUP16_SHA512:
+ case SSH_KEX_DH_GROUP18_SHA512:
+ ssh_client_dh_remove_callbacks(session);
+ break;
+#ifdef WITH_GEX
+ case SSH_KEX_DH_GEX_SHA1:
+ case SSH_KEX_DH_GEX_SHA256:
+ ssh_client_dhgex_remove_callbacks(session);
+ break;
+#endif /* WITH_GEX */
+#ifdef HAVE_ECDH
+ case SSH_KEX_ECDH_SHA2_NISTP256:
+ case SSH_KEX_ECDH_SHA2_NISTP384:
+ case SSH_KEX_ECDH_SHA2_NISTP521:
+ ssh_client_ecdh_remove_callbacks(session);
+ break;
+#endif
+#ifdef HAVE_CURVE25519
+ case SSH_KEX_CURVE25519_SHA256:
+ case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
+ ssh_client_curve25519_remove_callbacks(session);
+ break;
+#endif
+ }
+}
+
/** @brief Select the different methods on basis of client's and
* server's kex messages, and watches out if a match is possible.
*/
--
2.33.0

View File

@ -0,0 +1,56 @@
From 4d7ae19e9cd8c407012b40f3f2eaf480bfb1da7d Mon Sep 17 00:00:00 2001
From: Norbert Pocs <norbertpocs0@gmail.com>
Date: Tue, 10 Oct 2023 18:33:56 +0200
Subject: [PATCH 5/9] CVE-2023-6004: config_parser: Check for valid syntax of a
hostname if it is a domain name
This prevents code injection.
The domain name syntax checker is based on RFC1035.
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict: NA
Reference:https://git.libssh.org/projects/libssh.git/patch/?id=4d7ae19e9cd8c407012b40f3f2eaf480bfb1da7d
---
src/config_parser.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/src/config_parser.c b/src/config_parser.c
index 76cca224..87bac5d4 100644
--- a/src/config_parser.c
+++ b/src/config_parser.c
@@ -30,6 +30,7 @@
#include "libssh/config_parser.h"
#include "libssh/priv.h"
+#include "libssh/misc.h"
char *ssh_config_get_cmd(char **str)
{
@@ -139,6 +140,7 @@ int ssh_config_parse_uri(const char *tok,
{
char *endp = NULL;
long port_n;
+ int rc;
/* Sanitize inputs */
if (username != NULL) {
@@ -196,6 +198,14 @@ int ssh_config_parse_uri(const char *tok,
if (*hostname == NULL) {
goto error;
}
+ /* if not an ip, check syntax */
+ rc = ssh_is_ipaddr(*hostname);
+ if (rc == 0) {
+ rc = ssh_check_hostname_syntax(*hostname);
+ if (rc != SSH_OK) {
+ goto error;
+ }
+ }
}
/* Skip also the closing bracket */
if (*endp == ']') {
--
2.33.0

View File

@ -0,0 +1,303 @@
From fc1a8bb4555624f85ba1370721ad2086a4feff8c Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Fri, 10 Mar 2023 12:59:48 +0100
Subject: [PATCH] CVE-2023-1667:kex: Correctly handle last fields of KEXINIT
also in the client side
Previously, the last two fields of KEXINIT were considered as always zero for
the key exchange. This was true for the sending side, but might have not been
true for the received KEXINIT from the peer.
This moves the construction of these two fields closer to their reading or
writing, instead of hardcoding them on the last possible moment before they go
as input to the hashing function.
This also allows accepting the first_kex_packet_follows on the client side, even
though there is no kex algorithm now that would allow this.
It also avoid memory leaks in case the server_set_kex() or ssh_set_client_kex()
gets called multiple times, ensuring the algorithms will not change under our
hands.
It also makes use of a new flag to track if we sent KEXINIT.
Previously, this was tracked only implicitly by the content of the
session->next_crypto->{server,client}_kex (local kex). If it was not set, we
considered it was not send. But given that we need to check the local kex even
before sending it when we receive first_kex_packet_follows flag in the KEXINIT,
this can no longer be used.
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict:NA
Reference:https://gitlab.com/libssh/libssh-mirror/commit/fc1a8bb4555624f85ba1370721ad2086a4feff8c
---
include/libssh/session.h | 5 ++
src/client.c | 2 +-
src/kex.c | 124 +++++++++++++++++++++------------------
src/server.c | 8 ++-
4 files changed, 80 insertions(+), 59 deletions(-)
diff --git a/include/libssh/session.h b/include/libssh/session.h
index 03c2bb6..1c33a02 100644
--- a/include/libssh/session.h
+++ b/include/libssh/session.h
@@ -75,6 +75,11 @@ enum ssh_pending_call_e {
/* Client successfully authenticated */
#define SSH_SESSION_FLAG_AUTHENTICATED 2
+/* The KEXINIT message can be sent first by either of the parties so this flag
+ * indicates that the message was already sent to make sure it is sent and avoid
+ * sending it twice during key exchange to simplify the state machine. */
+#define SSH_SESSION_FLAG_KEXINIT_SENT 4
+
/* codes to use with ssh_handle_packets*() */
/* Infinite timeout */
#define SSH_TIMEOUT_INFINITE -1
diff --git a/src/client.c b/src/client.c
index 954ed39..20fa33f 100644
--- a/src/client.c
+++ b/src/client.c
@@ -433,7 +433,7 @@ static void ssh_client_connection_callback(ssh_session session)
case SSH_SESSION_STATE_KEXINIT_RECEIVED:
set_status(session,0.6f);
ssh_list_kex(&session->next_crypto->server_kex);
- if (session->next_crypto->client_kex.methods[0] == NULL) {
+ if ((session->flags & SSH_SESSION_FLAG_KEXINIT_SENT) == 0) {
/* in rekeying state if next_crypto client_kex is empty */
rc = ssh_set_client_kex(session);
if (rc != SSH_OK) {
diff --git a/src/kex.c b/src/kex.c
index f1dab08..49aec45 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -345,13 +345,24 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit)
(void)user;
if (session->session_state == SSH_SESSION_STATE_AUTHENTICATED) {
- SSH_LOG(SSH_LOG_INFO, "Initiating key re-exchange");
+ if (session->dh_handshake_state == DH_STATE_FINISHED) {
+ SSH_LOG(SSH_LOG_DEBUG, "Peer initiated key re-exchange");
+ /* Reset the sent flag if the re-kex was initiated by the peer */
+ session->flags &= ~SSH_SESSION_FLAG_KEXINIT_SENT;
+ } else if (session->dh_handshake_state == DH_STATE_INIT_SENT) {
+ SSH_LOG(SSH_LOG_DEBUG, "Receeved peer kexinit answer");
+ } else {
+ ssh_set_error(session, SSH_FATAL,
+ "SSH_KEXINIT received in wrong state");
+ goto error;
+ }
} 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) {
+#ifdef WITH_SERVER
len = ssh_buffer_get_data(packet,session->next_crypto->client_kex.cookie, 16);
if (len != 16) {
ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: no cookie in packet");
@@ -363,6 +374,12 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit)
ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: adding cookie failed");
goto error;
}
+
+ ok = server_set_kex(session);
+ if (ok == SSH_ERROR) {
+ goto error;
+ }
+#endif
} else {
len = ssh_buffer_get_data(packet,session->next_crypto->server_kex.cookie, 16);
if (len != 16) {
@@ -375,6 +392,11 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit)
ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: adding cookie failed");
goto error;
}
+
+ ok = ssh_set_client_kex(session);
+ if (ok == SSH_ERROR) {
+ goto error;
+ }
}
for (i = 0; i < SSH_KEX_METHODS; i++) {
@@ -419,22 +441,37 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit)
* that its value is included when computing the session ID (see
* 'make_sessionid').
*/
- if (server_kex) {
- rc = ssh_buffer_get_u8(packet, &first_kex_packet_follows);
- if (rc != 1) {
- goto error;
- }
+ rc = ssh_buffer_get_u8(packet, &first_kex_packet_follows);
+ if (rc != 1) {
+ goto error;
+ }
- rc = ssh_buffer_add_u8(session->in_hashbuf, first_kex_packet_follows);
- if (rc < 0) {
- goto error;
- }
+ rc = ssh_buffer_add_u8(session->in_hashbuf, first_kex_packet_follows);
+ if (rc < 0) {
+ goto error;
+ }
- rc = ssh_buffer_add_u32(session->in_hashbuf, kexinit_reserved);
- if (rc < 0) {
- goto error;
- }
+ rc = ssh_buffer_add_u32(session->in_hashbuf, kexinit_reserved);
+ if (rc < 0) {
+ goto error;
+ }
+
+ /*
+ * Remember whether 'first_kex_packet_follows' was set and the client
+ * guess was wrong: in this case the next SSH_MSG_KEXDH_INIT message
+ * must be ignored.
+ */
+ if (first_kex_packet_follows) {
+ char **client_methods = session->next_crypto->client_kex.methods;
+ char **server_methods = session->next_crypto->server_kex.methods;
+ session->first_kex_follows_guess_wrong =
+ cmp_first_kex_algo(client_methods[SSH_KEX],
+ server_methods[SSH_KEX]) ||
+ cmp_first_kex_algo(client_methods[SSH_HOSTKEYS],
+ server_methods[SSH_HOSTKEYS]);
+ }
+ if (server_kex) {
/*
* If client sent a ext-info-c message in the kex list, it supports
* RFC 8308 extension negotiation.
@@ -507,19 +544,6 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit)
session->extensions & SSH_EXT_SIG_RSA_SHA256 ? "SHA256" : "",
session->extensions & SSH_EXT_SIG_RSA_SHA512 ? " SHA512" : "");
}
-
- /*
- * Remember whether 'first_kex_packet_follows' was set and the client
- * guess was wrong: in this case the next SSH_MSG_KEXDH_INIT message
- * must be ignored.
- */
- if (first_kex_packet_follows) {
- session->first_kex_follows_guess_wrong =
- cmp_first_kex_algo(session->next_crypto->client_kex.methods[SSH_KEX],
- session->next_crypto->server_kex.methods[SSH_KEX]) ||
- cmp_first_kex_algo(session->next_crypto->client_kex.methods[SSH_HOSTKEYS],
- session->next_crypto->server_kex.methods[SSH_HOSTKEYS]);
- }
}
/* Note, that his overwrites authenticated state in case of rekeying */
@@ -672,14 +696,18 @@ int ssh_set_client_kex(ssh_session session)
int i;
size_t kex_len, len;
+ /* Skip if already set, for example for the rekey or when we do the guessing
+ * it could have been already used to make some protocol decisions. */
+ if (client->methods[0] != NULL) {
+ return SSH_OK;
+ }
+
ok = ssh_get_random(client->cookie, 16, 0);
if (!ok) {
ssh_set_error(session, SSH_FATAL, "PRNG error");
return SSH_ERROR;
}
- memset(client->methods, 0, SSH_KEX_METHODS * sizeof(char **));
-
/* Set the list of allowed algorithms in order of preference, if it hadn't
* been set yet. */
for (i = 0; i < SSH_KEX_METHODS; i++) {
@@ -924,10 +952,21 @@ int ssh_send_kex(ssh_session session)
goto error;
}
+ /* Prepare also the first_kex_packet_follows and reserved to 0 */
+ rc = ssh_buffer_add_u8(session->out_hashbuf, 0);
+ if (rc < 0) {
+ goto error;
+ }
+ rc = ssh_buffer_add_u32(session->out_hashbuf, 0);
+ if (rc < 0) {
+ goto error;
+ }
+
if (ssh_packet_send(session) == SSH_ERROR) {
return -1;
}
+ session->flags |= SSH_SESSION_FLAG_KEXINIT_SENT;
SSH_LOG(SSH_LOG_PACKET, "SSH_MSG_KEXINIT sent");
return 0;
error:
@@ -1055,33 +1094,6 @@ int ssh_make_sessionid(ssh_session session)
client_hash = session->in_hashbuf;
}
- /*
- * 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 = ssh_buffer_add_u8(server_hash, 0);
- if (rc < 0) {
- goto error;
- }
- rc = ssh_buffer_add_u32(server_hash, 0);
- if (rc < 0) {
- goto error;
- }
-
- /* These fields are handled for the server case in ssh_packet_kexinit. */
- if (session->client) {
- rc = ssh_buffer_add_u8(client_hash, 0);
- if (rc < 0) {
- goto error;
- }
- rc = ssh_buffer_add_u32(client_hash, 0);
- if (rc < 0) {
- goto error;
- }
- }
-
rc = ssh_dh_get_next_server_publickey_blob(session, &server_pubkey_blob);
if (rc != SSH_OK) {
goto error;
diff --git a/src/server.c b/src/server.c
index 2728d9b..fac2e72 100644
--- a/src/server.c
+++ b/src/server.c
@@ -92,7 +92,11 @@ int server_set_kex(ssh_session session)
size_t len;
int ok;
- ZERO_STRUCTP(server);
+ /* Skip if already set, for example for the rekey or when we do the guessing
+ * it could have been already used to make some protocol decisions. */
+ if (server->methods[0] != NULL) {
+ return SSH_OK;
+ }
ok = ssh_get_random(server->cookie, 16, 0);
if (!ok) {
@@ -375,7 +379,7 @@ static void ssh_server_connection_callback(ssh_session session){
break;
case SSH_SESSION_STATE_KEXINIT_RECEIVED:
set_status(session,0.6f);
- if(session->next_crypto->server_kex.methods[0]==NULL){
+ if ((session->flags & SSH_SESSION_FLAG_KEXINIT_SENT) == 0) {
if(server_set_kex(session) == SSH_ERROR)
goto error;
/* We are in a rekeying, so we need to send the server kex */
--
2.33.0

View File

@ -0,0 +1,89 @@
From 8cf4f4bfda968ab526c1a601ea1030bbaccaba17 Mon Sep 17 00:00:00 2001
From: Norbert Pocs <norbertpocs0@gmail.com>
Date: Tue, 10 Oct 2023 10:28:47 +0200
Subject: [PATCH 6/9] CVE-2023-6004: torture_proxycommand: Add test for
proxycommand injection
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict: NA
Reference:https://git.libssh.org/projects/libssh.git/patch/?id=8cf4f4bfda968ab526c1a601ea1030bbaccaba17
---
tests/client/torture_proxycommand.c | 53 +++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
diff --git a/tests/client/torture_proxycommand.c b/tests/client/torture_proxycommand.c
index c04ff2ab..dc17f3d8 100644
--- a/tests/client/torture_proxycommand.c
+++ b/tests/client/torture_proxycommand.c
@@ -161,6 +161,56 @@ static void torture_options_set_proxycommand_ssh_stderr(void **state)
assert_int_equal(rc & O_RDWR, O_RDWR);
}
+static void torture_options_proxycommand_injection(void **state)
+{
+ struct torture_state *s = *state;
+ struct passwd *pwd = NULL;
+ const char *malicious_host = "`echo foo > mfile`";
+ const char *command = "nc %h %p";
+ char *current_dir = NULL;
+ char *malicious_file_path = NULL;
+ int mfp_len;
+ int verbosity = torture_libssh_verbosity();
+ struct stat sb;
+ int rc;
+
+ pwd = getpwnam("bob");
+ assert_non_null(pwd);
+
+ rc = setuid(pwd->pw_uid);
+ assert_return_code(rc, errno);
+
+ s->ssh.session = ssh_new();
+ assert_non_null(s->ssh.session);
+
+ ssh_options_set(s->ssh.session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
+ // if we would be checking the rc, this should fail
+ ssh_options_set(s->ssh.session, SSH_OPTIONS_HOST, malicious_host);
+
+ ssh_options_set(s->ssh.session, SSH_OPTIONS_USER, TORTURE_SSH_USER_ALICE);
+
+ rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_PROXYCOMMAND, command);
+ assert_int_equal(rc, 0);
+ rc = ssh_connect(s->ssh.session);
+ assert_ssh_return_code_equal(s->ssh.session, rc, SSH_ERROR);
+
+ current_dir = torture_get_current_working_dir();
+ assert_non_null(current_dir);
+ mfp_len = strlen(current_dir) + 6;
+ malicious_file_path = malloc(mfp_len);
+ assert_non_null(malicious_file_path);
+ rc = snprintf(malicious_file_path, mfp_len,
+ "%s/mfile", current_dir);
+ assert_int_equal(rc, mfp_len);
+ free(current_dir);
+ rc = stat(malicious_file_path, &sb);
+ assert_int_not_equal(rc, 0);
+
+ // cleanup
+ remove(malicious_file_path);
+ free(malicious_file_path);
+}
+
int torture_run_tests(void) {
int rc;
struct CMUnitTest tests[] = {
@@ -176,6 +226,9 @@ int torture_run_tests(void) {
cmocka_unit_test_setup_teardown(torture_options_set_proxycommand_ssh_stderr,
session_setup,
session_teardown),
+ cmocka_unit_test_setup_teardown(torture_options_proxycommand_injection,
+ NULL,
+ session_teardown),
};
--
2.33.0

View File

@ -0,0 +1,297 @@
From 70565ac43867053871f47378c53e5d90ba9007d8 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Thu, 16 Mar 2023 11:55:12 +0100
Subject: [PATCH] CVE-2023-1667:kex: Add support for sending
first_kex_packet_follows flag
This is not completely straightforward as it requires us to do some
state
shuffling.
We introduce internal flag that can turn this on in client side, so far
for
testing only as we do not want to universally enable this. We also
repurpose the
server flag indicating the guess was wrong also for the client to make
desired
decisions.
If we found out our guess was wrong, we need to hope the server was able
to
figure out this much, we need to revert the DH FSM state, drop the
callbacks
from the "wrong" key exchange method and initiate the right one.
The server side is already tested by the pkd_hello_i1, which is
executing tests
against dropbrear clients, which is using this flag by default out of
the box.
Tested manually also with the pkd_hello --rekey to make sure the server
is able
to handle the rekeying with all key exchange methods.
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict:NA
Reference:https://gitlab.com/libssh/libssh-mirror/commit/70565ac43867053871f47378c53e5d90ba9007d8
---
include/libssh/dh.h | 1 +
include/libssh/session.h | 13 +++++--
src/client.c | 12 +++++-
src/kex.c | 82 +++++++++++++++++++++++++++++++++++-----
4 files changed, 93 insertions(+), 15 deletions(-)
diff --git a/include/libssh/dh.h b/include/libssh/dh.h
index 57f37cd..704888c 100644
--- a/include/libssh/dh.h
+++ b/include/libssh/dh.h
@@ -63,6 +63,7 @@ int ssh_dh_get_current_server_publickey_blob(ssh_session session,
ssh_key ssh_dh_get_next_server_publickey(ssh_session session);
int ssh_dh_get_next_server_publickey_blob(ssh_session session,
ssh_string *pubkey_blob);
+int dh_handshake(ssh_session session);
int ssh_client_dh_init(ssh_session session);
void ssh_client_dh_remove_callbacks(ssh_session session);
diff --git a/include/libssh/session.h b/include/libssh/session.h
index a5cb7ed..584006f 100644
--- a/include/libssh/session.h
+++ b/include/libssh/session.h
@@ -163,14 +163,21 @@ struct ssh_session_struct {
uint32_t current_method;
} auth;
+ /* Sending this flag before key exchange to save one round trip during the
+ * key exchange. This might make sense on high-latency connections.
+ * So far internal only for testing. Usable only on the client side --
+ * there is no key exchange method that would start with server message */
+ bool send_first_kex_follows;
/*
* RFC 4253, 7.1: if the first_kex_packet_follows flag was set in
* the received SSH_MSG_KEXINIT, but the guess was wrong, this
* field will be set such that the following guessed packet will
- * be ignored. Once that packet has been received and ignored,
- * this field is cleared.
+ * be ignored on the receiving side. Once that packet has been received and
+ * ignored, this field is cleared.
+ * On the sending side, this is set after we got peer KEXINIT message and we
+ * need to resend the initial message of the negotiated KEX algorithm.
*/
- int first_kex_follows_guess_wrong;
+ bool first_kex_follows_guess_wrong;
ssh_buffer in_hashbuf;
ssh_buffer out_hashbuf;
diff --git a/src/client.c b/src/client.c
index 701dfe1..6b9a28f 100644
--- a/src/client.c
+++ b/src/client.c
@@ -243,10 +243,13 @@ end:
* @warning this function returning is no proof that DH handshake is
* completed
*/
-static int dh_handshake(ssh_session session) {
-
+int dh_handshake(ssh_session session)
+{
int rc = SSH_AGAIN;
+ SSH_LOG(SSH_LOG_TRACE, "dh_handshake_state = %d, kex_type = %d",
+ session->dh_handshake_state, session->next_crypto->kex_type);
+
switch (session->dh_handshake_state) {
case DH_STATE_INIT:
switch(session->next_crypto->kex_type){
@@ -386,6 +389,8 @@ static void ssh_client_connection_callback(ssh_session session)
{
int rc;
+ SSH_LOG(SSH_LOG_DEBUG, "session_state=%d", session->session_state);
+
switch(session->session_state) {
case SSH_SESSION_STATE_NONE:
case SSH_SESSION_STATE_CONNECTING:
@@ -448,6 +453,9 @@ static void ssh_client_connection_callback(ssh_session session)
goto error;
set_status(session,0.8f);
session->session_state=SSH_SESSION_STATE_DH;
+
+ /* If the init packet was already sent in previous step, this will be no
+ * operation */
if (dh_handshake(session) == SSH_ERROR) {
goto error;
}
diff --git a/src/kex.c b/src/kex.c
index 60618e3..9b81e37 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -28,6 +28,7 @@
#include <stdio.h>
#include <stdbool.h>
+#include "libssh/libssh.h"
#include "libssh/priv.h"
#include "libssh/buffer.h"
#include "libssh/dh.h"
@@ -344,14 +345,19 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit)
(void)type;
(void)user;
+ SSH_LOG(SSH_LOG_TRACE, "KEXINIT received");
+
if (session->session_state == SSH_SESSION_STATE_AUTHENTICATED) {
if (session->dh_handshake_state == DH_STATE_FINISHED) {
SSH_LOG(SSH_LOG_DEBUG, "Peer initiated key re-exchange");
/* Reset the sent flag if the re-kex was initiated by the peer */
session->flags &= ~SSH_SESSION_FLAG_KEXINIT_SENT;
- } else if (session->dh_handshake_state == DH_STATE_INIT_SENT) {
- SSH_LOG(SSH_LOG_DEBUG, "Receeved peer kexinit answer");
- } else {
+ } else if (session->flags & SSH_SESSION_FLAG_KEXINIT_SENT &&
+ session->dh_handshake_state == DH_STATE_INIT_SENT) {
+ /* This happens only when we are sending our-guessed first kex
+ * packet right after our KEXINIT packet. */
+ SSH_LOG(SSH_LOG_DEBUG, "Received peer kexinit answer.");
+ } else if (session->session_state != SSH_SESSION_STATE_INITIAL_KEX) {
ssh_set_error(session, SSH_FATAL,
"SSH_KEXINIT received in wrong state");
goto error;
@@ -459,9 +465,10 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit)
/*
* Remember whether 'first_kex_packet_follows' was set and the client
* guess was wrong: in this case the next SSH_MSG_KEXDH_INIT message
- * must be ignored.
+ * must be ignored on the server side.
+ * Client needs to start the Key exchange over with the correct method
*/
- if (first_kex_packet_follows) {
+ if (first_kex_packet_follows || session->send_first_kex_follows) {
char **client_methods = session->next_crypto->client_kex.methods;
char **server_methods = session->next_crypto->server_kex.methods;
session->first_kex_follows_guess_wrong =
@@ -469,6 +476,8 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit)
server_methods[SSH_KEX]) ||
cmp_first_kex_algo(client_methods[SSH_HOSTKEYS],
server_methods[SSH_HOSTKEYS]);
+ SSH_LOG(SSH_LOG_DEBUG, "The initial guess was %s.",
+ session->first_kex_follows_guess_wrong ? "wrong" : "right");
}
if (server_kex) {
@@ -548,7 +557,12 @@ SSH_PACKET_CALLBACK(ssh_packet_kexinit)
/* Note, that his overwrites authenticated state in case of rekeying */
session->session_state = SSH_SESSION_STATE_KEXINIT_RECEIVED;
- session->dh_handshake_state = DH_STATE_INIT;
+ /* if we already sent our initial key exchange packet, do not reset the
+ * DH state. We will know if we were right with our guess only in
+ * dh_handshake_state() */
+ if (session->send_first_kex_follows == false) {
+ session->dh_handshake_state = DH_STATE_INIT;
+ }
session->ssh_connection_callback(session);
return SSH_PACKET_USED;
@@ -842,6 +856,7 @@ int ssh_kex_select_methods (ssh_session session){
struct ssh_kex_struct *server = &session->next_crypto->server_kex;
struct ssh_kex_struct *client = &session->next_crypto->client_kex;
char *ext_start = NULL;
+ enum ssh_key_exchange_e kex_type;
int i;
/* Here we should drop the ext-info-c from the list so we avoid matching.
@@ -862,8 +877,18 @@ int ssh_kex_select_methods (ssh_session session){
session->next_crypto->kex_methods[i] = strdup("");
}
}
- kex = session->next_crypto->kex_methods[SSH_KEX];
- session->next_crypto->kex_type = kex_select_kex_type(kex);
+
+ /* We can not set this value directly as the old value is needed to revert
+ * callbacks if we are client */
+ kex_type = kex_select_kex_type(session->next_crypto->kex_methods[SSH_KEX]);
+ if (session->client && session->first_kex_follows_guess_wrong) {
+ SSH_LOG(SSH_LOG_DEBUG, "Our guess was wrong. Restarting the KEX");
+ /* We need to remove the wrong callbacks and start kex again */
+ revert_kex_callbacks(session);
+ session->dh_handshake_state = DH_STATE_INIT;
+ session->first_kex_follows_guess_wrong = false;
+ }
+ session->next_crypto->kex_type = kex_type;
SSH_LOG(SSH_LOG_INFO, "Negotiated %s,%s,%s,%s,%s,%s,%s,%s,%s,%s",
session->next_crypto->kex_methods[SSH_KEX],
@@ -889,6 +914,19 @@ int ssh_send_kex(ssh_session session) {
ssh_string str = NULL;
int i;
int rc;
+ int first_kex_packet_follows = 0;
+
+ /* Only client can initiate the handshake methods we implement. If we
+ * already received the peer mechanisms, there is no point in guessing */
+ if (session->client &&
+ session->session_state != SSH_SESSION_STATE_KEXINIT_RECEIVED &&
+ session->send_first_kex_follows) {
+ first_kex_packet_follows = 1;
+ }
+
+ SSH_LOG(SSH_LOG_TRACE,
+ "Sending KEXINIT packet, first_kex_packet_follows = %d",
+ first_kex_packet_follows);
rc = ssh_buffer_pack(session->out_buffer,
"bP",
@@ -921,14 +959,14 @@ int ssh_send_kex(ssh_session session) {
rc = ssh_buffer_pack(session->out_buffer,
"bd",
- 0,
+ first_kex_packet_follows,
0);
if (rc != SSH_OK) {
goto error;
}
/* Prepare also the first_kex_packet_follows and reserved to 0 */
- rc = ssh_buffer_add_u8(session->out_hashbuf, 0);
+ rc = ssh_buffer_add_u8(session->out_hashbuf, first_kex_packet_follows);
if (rc < 0) {
goto error;
}
@@ -943,6 +981,30 @@ int ssh_send_kex(ssh_session session) {
session->flags |= SSH_SESSION_FLAG_KEXINIT_SENT;
SSH_LOG(SSH_LOG_PACKET, "SSH_MSG_KEXINIT sent");
+
+ /* If we indicated that we are sending the guessed key exchange packet,
+ * do it now. The packet is simple, but we need to do some preparations */
+ if (first_kex_packet_follows) {
+ char *list = kex->methods[SSH_KEX];
+ char *colon = strchr(list, ',');
+ size_t kex_name_len = colon ? (size_t)(colon - list) : strlen(list);
+ char *kex_name = calloc(kex_name_len + 1, 1);
+ if (kex_name == NULL) {
+ ssh_set_error_oom(session);
+ goto error;
+ }
+ snprintf(kex_name, kex_name_len + 1, "%.*s", (int)kex_name_len, list);
+ SSH_LOG(SSH_LOG_TRACE, "Sending the first kex packet for %s", kex_name);
+
+ session->next_crypto->kex_type = kex_select_kex_type(kex_name);
+ free(kex_name);
+
+ /* run the first step of the DH handshake */
+ session->dh_handshake_state = DH_STATE_INIT;
+ if (dh_handshake(session) == SSH_ERROR) {
+ goto error;
+ }
+ }
return 0;
error:
ssh_buffer_reinit(session->out_buffer);
--
2.23.0

View File

@ -0,0 +1,61 @@
From a0dbe0d556e073804cc549802569577bb24757d9 Mon Sep 17 00:00:00 2001
From: Norbert Pocs <norbertpocs0@gmail.com>
Date: Mon, 6 Nov 2023 20:11:38 +0100
Subject: [PATCH 7/9] CVE-2023-6004: torture_misc: Add test for ssh_is_ipaddr
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict: NA
Reference:https://git.libssh.org/projects/libssh.git/patch/?id=a0dbe0d556e073804cc549802569577bb24757d9
---
tests/unittests/torture_misc.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/tests/unittests/torture_misc.c b/tests/unittests/torture_misc.c
index d14f4254..073bc54c 100644
--- a/tests/unittests/torture_misc.c
+++ b/tests/unittests/torture_misc.c
@@ -728,6 +728,31 @@ static void torture_ssh_check_hostname_syntax(void **state)
assert_int_equal(rc, SSH_ERROR);
}
+static void torture_ssh_is_ipaddr(void **state) {
+ int rc;
+ (void)state;
+
+ rc = ssh_is_ipaddr("201.255.3.69");
+ assert_int_equal(rc, 1);
+ rc = ssh_is_ipaddr("::1");
+ assert_int_equal(rc, 1);
+ rc = ssh_is_ipaddr("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
+ assert_int_equal(rc, 1);
+
+ rc = ssh_is_ipaddr("..");
+ assert_int_equal(rc, 0);
+ rc = ssh_is_ipaddr(":::");
+ assert_int_equal(rc, 0);
+ rc = ssh_is_ipaddr("1.1.1.1.1");
+ assert_int_equal(rc, 0);
+ rc = ssh_is_ipaddr("1.1");
+ assert_int_equal(rc, 0);
+ rc = ssh_is_ipaddr("caesar");
+ assert_int_equal(rc, 0);
+ rc = ssh_is_ipaddr("::xa:1");
+ assert_int_equal(rc, 0);
+}
+
int torture_run_tests(void) {
int rc;
struct CMUnitTest tests[] = {
@@ -751,6 +776,7 @@ int torture_run_tests(void) {
cmocka_unit_test(torture_ssh_mkdirs),
cmocka_unit_test(torture_ssh_quote_file_name),
cmocka_unit_test(torture_ssh_check_hostname_syntax),
+ cmocka_unit_test(torture_ssh_is_ipaddr),
};
ssh_init();
--
2.33.0

View File

@ -0,0 +1,152 @@
From d08f1b2377fead6489aa1d6a102bf65895ecf858 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Fri, 17 Mar 2023 14:09:14 +0100
Subject: [PATCH] CVE-2023-1667:tests: Client coverage for key exchange
with kex guessing
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict:NA
Reference:https://gitlab.com/libssh/libssh-mirror/commit/d08f1b2377fead6489aa1d6a102bf65895ecf858
---
tests/client/torture_rekey.c | 107 ++++++++++++++++++++++++++++++++++-
1 file changed, 105 insertions(+), 2 deletions(-)
diff --git a/tests/client/torture_rekey.c b/tests/client/torture_rekey.c
index 7c9d812..9284782 100644
--- a/tests/client/torture_rekey.c
+++ b/tests/client/torture_rekey.c
@@ -504,6 +504,91 @@ static void torture_rekey_server_recv(void **state)
}
#endif /* WITH_SFTP */
+static void setup_server_for_good_guess(void *state)
+{
+ const char *default_sshd_config = "KexAlgorithms curve25519-sha256";
+ const char *fips_sshd_config = "KexAlgorithms ecdh-sha2-nistp256";
+ const char *sshd_config = default_sshd_config;
+
+ if (ssh_fips_mode()) {
+ sshd_config = fips_sshd_config;
+ }
+ /* This sets an only supported kex algorithm that we do not have as a first
+ * option */
+ torture_update_sshd_config(state, sshd_config);
+}
+
+static void torture_rekey_guess_send(void **state)
+{
+ struct torture_state *s = *state;
+
+ setup_server_for_good_guess(state);
+
+ /* Make the client send the first_kex_packet_follows flag during key
+ * exchange as well as during the rekey */
+ s->ssh.session->send_first_kex_follows = true;
+
+ torture_rekey_send(state);
+}
+
+static void torture_rekey_guess_wrong_send(void **state)
+{
+ struct torture_state *s = *state;
+ const char *sshd_config = "KexAlgorithms diffie-hellman-group14-sha256";
+
+ /* This sets an only supported kex algorithm that we do not have as a first
+ * option */
+ torture_update_sshd_config(state, sshd_config);
+
+ /* Make the client send the first_kex_packet_follows flag during key
+ * exchange as well as during the rekey */
+ s->ssh.session->send_first_kex_follows = true;
+
+ torture_rekey_send(state);
+}
+
+#ifdef WITH_SFTP
+static void torture_rekey_guess_recv(void **state)
+{
+ struct torture_state *s = *state;
+ int rc;
+
+ setup_server_for_good_guess(state);
+
+ /* Make the client send the first_kex_packet_follows flag during key
+ * exchange as well as during the rekey */
+ s->ssh.session->send_first_kex_follows = true;
+
+ rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_REKEY_DATA, &bytes);
+ assert_ssh_return_code(s->ssh.session, rc);
+
+ session_setup_sftp(state);
+
+ torture_rekey_recv(state);
+}
+
+static void torture_rekey_guess_wrong_recv(void **state)
+{
+ struct torture_state *s = *state;
+ const char *sshd_config = "KexAlgorithms diffie-hellman-group14-sha256";
+ int rc;
+
+ /* This sets an only supported kex algorithm that we do not have as a first
+ * option */
+ torture_update_sshd_config(state, sshd_config);
+
+ /* Make the client send the first_kex_packet_follows flag during key
+ * exchange as well as during the rekey */
+ s->ssh.session->send_first_kex_follows = true;
+
+ rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_REKEY_DATA, &bytes);
+ assert_ssh_return_code(s->ssh.session, rc);
+
+ session_setup_sftp(state);
+
+ torture_rekey_recv(state);
+}
+#endif /* WITH_SFTP */
int torture_run_tests(void) {
int rc;
@@ -522,16 +607,34 @@ int torture_run_tests(void) {
cmocka_unit_test_setup_teardown(torture_rekey_send,
session_setup,
session_teardown),
- /* Note, that this modifies the sshd_config */
+ /* TODO verify the two rekey are possible and the states are not broken after rekey */
+
+ cmocka_unit_test_setup_teardown(torture_rekey_server_different_kex,
+ session_setup,
+ session_teardown),
+ /* Note, that these tests modify the sshd_config so follow-up tests
+ * might get unexpected behavior if they do not update the server with
+ * torture_update_sshd_config() too */
cmocka_unit_test_setup_teardown(torture_rekey_server_send,
session_setup,
session_teardown),
+ cmocka_unit_test_setup_teardown(torture_rekey_guess_send,
+ session_setup,
+ session_teardown),
+ cmocka_unit_test_setup_teardown(torture_rekey_guess_wrong_send,
+ session_setup,
+ session_teardown),
#ifdef WITH_SFTP
cmocka_unit_test_setup_teardown(torture_rekey_server_recv,
session_setup_sftp_server,
session_teardown),
+ cmocka_unit_test_setup_teardown(torture_rekey_guess_recv,
+ session_setup,
+ session_teardown),
+ cmocka_unit_test_setup_teardown(torture_rekey_guess_wrong_recv,
+ session_setup,
+ session_teardown),
#endif /* WITH_SFTP */
- /* TODO verify the two rekey are possible and the states are not broken after rekey */
};
ssh_init();
--
2.23.0

View File

@ -0,0 +1,165 @@
From cdaec0d6273243a03f460cc5ba1a2265b4afb93a Mon Sep 17 00:00:00 2001
From: Norbert Pocs <norbertpocs0@gmail.com>
Date: Tue, 28 Nov 2023 15:26:45 +0100
Subject: [PATCH 8/9] CVE-2023-6004: misc: Add ipv6 link-local check for an ip
address
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict: NA
Reference:https://git.libssh.org/projects/libssh.git/patch/?id=cdaec0d6273243a03f460cc5ba1a2265b4afb93a
---
src/CMakeLists.txt | 17 ++++++++++-------
src/connect.c | 2 +-
src/misc.c | 44 ++++++++++++++++++++++++++++++++++++++------
3 files changed, 49 insertions(+), 14 deletions(-)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a576cf71..fc401793 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -9,13 +9,6 @@ set(LIBSSH_LINK_LIBRARIES
${LIBSSH_REQUIRED_LIBRARIES}
)
-if (WIN32)
- set(LIBSSH_LINK_LIBRARIES
- ${LIBSSH_LINK_LIBRARIES}
- ws2_32
- )
-endif (WIN32)
-
if (OPENSSL_CRYPTO_LIBRARY)
set(LIBSSH_PRIVATE_INCLUDE_DIRS
${LIBSSH_PRIVATE_INCLUDE_DIRS}
@@ -93,6 +86,16 @@ if (MINGW AND Threads_FOUND)
)
endif()
+# This needs to be last for mingw to build
+# https://gitlab.com/libssh/libssh-mirror/-/issues/84
+if (WIN32)
+ set(LIBSSH_LINK_LIBRARIES
+ ${LIBSSH_LINK_LIBRARIES}
+ iphlpapi
+ ws2_32
+ )
+endif (WIN32)
+
if (BUILD_STATIC_LIB)
set(LIBSSH_STATIC_LIBRARY
ssh_static
diff --git a/src/connect.c b/src/connect.c
index ce4d58df..ca62dcf0 100644
--- a/src/connect.c
+++ b/src/connect.c
@@ -136,7 +136,7 @@ static int getai(const char *host, int port, struct addrinfo **ai)
#endif
}
- if (ssh_is_ipaddr(host)) {
+ if (ssh_is_ipaddr(host) == 1) {
/* this is an IP address */
SSH_LOG(SSH_LOG_PACKET, "host %s matches an IP address", host);
hints.ai_flags |= AI_NUMERICHOST;
diff --git a/src/misc.c b/src/misc.c
index e4239e81..6f5d2d60 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -32,6 +32,7 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <net/if.h>
#endif /* _WIN32 */
@@ -59,6 +60,7 @@
#include <ws2tcpip.h>
#include <shlobj.h>
#include <direct.h>
+#include <netioapi.h>
#ifdef HAVE_IO_H
#include <io.h>
@@ -216,22 +218,37 @@ int ssh_is_ipaddr_v4(const char *str) {
int ssh_is_ipaddr(const char *str) {
int rc = SOCKET_ERROR;
+ char *s = strdup(str);
- if (strchr(str, ':')) {
+ if (s == NULL) {
+ return -1;
+ }
+ if (strchr(s, ':')) {
struct sockaddr_storage ss;
int sslen = sizeof(ss);
+ char *network_interface = strchr(s, '%');
- /* TODO link-local (IP:v6:addr%ifname). */
- rc = WSAStringToAddressA((LPSTR) str,
+ /* link-local (IP:v6:addr%ifname). */
+ if (network_interface != NULL) {
+ rc = if_nametoindex(network_interface + 1);
+ if (rc == 0) {
+ free(s);
+ return 0;
+ }
+ *network_interface = '\0';
+ }
+ rc = WSAStringToAddressA((LPSTR) s,
AF_INET6,
NULL,
(struct sockaddr*)&ss,
&sslen);
if (rc == 0) {
+ free(s);
return 1;
}
}
+ free(s);
return ssh_is_ipaddr_v4(str);
}
#else /* _WIN32 */
@@ -335,17 +352,32 @@ int ssh_is_ipaddr_v4(const char *str) {
int ssh_is_ipaddr(const char *str) {
int rc = -1;
+ char *s = strdup(str);
- if (strchr(str, ':')) {
+ if (s == NULL) {
+ return -1;
+ }
+ if (strchr(s, ':')) {
struct in6_addr dest6;
+ char *network_interface = strchr(s, '%');
- /* TODO link-local (IP:v6:addr%ifname). */
- rc = inet_pton(AF_INET6, str, &dest6);
+ /* link-local (IP:v6:addr%ifname). */
+ if (network_interface != NULL) {
+ rc = if_nametoindex(network_interface + 1);
+ if (rc == 0) {
+ free(s);
+ return 0;
+ }
+ *network_interface = '\0';
+ }
+ rc = inet_pton(AF_INET6, s, &dest6);
if (rc > 0) {
+ free(s);
return 1;
}
}
+ free(s);
return ssh_is_ipaddr_v4(str);
}
--
2.33.0

View File

@ -0,0 +1,40 @@
From dc1254d53e4fc6cbeb4797fc6ca1c9ed2c21f15c Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Mon, 17 Apr 2023 16:53:35 +0200
Subject: [PATCH] CVE-2023-1667:tests: Send a bit more to make sure rekey is
completed
This was for some reason failing on CentOS 7 in 0.10 branch so bringing this to
the master too.
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict:NA
Reference:https://gitlab.com/libssh/libssh-mirror/commit/dc1254d53e4fc6cbeb4797fc6ca1c9ed2c21f15c
---
tests/client/torture_rekey.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/tests/client/torture_rekey.c b/tests/client/torture_rekey.c
index d9667267..ccd5ae2c 100644
--- a/tests/client/torture_rekey.c
+++ b/tests/client/torture_rekey.c
@@ -192,10 +192,11 @@ static void torture_rekey_send(void **state)
rc = ssh_userauth_publickey_auto(s->ssh.session, NULL, NULL);
assert_int_equal(rc, SSH_AUTH_SUCCESS);
- /* send ignore packets of up to 1KB to trigger rekey */
+ /* send ignore packets of up to 1KB to trigger rekey. Send little bit more
+ * to make sure it completes with all different ciphers */
memset(data, 0, sizeof(data));
memset(data, 'A', 128);
- for (i = 0; i < 16; i++) {
+ for (i = 0; i < KEX_RETRY; i++) {
ssh_send_ignore(s->ssh.session, data);
ssh_handle_packets(s->ssh.session, 50);
}
--
2.33.0

View File

@ -0,0 +1,65 @@
From 6a8a18c73e73a338283dfbade0a7d83e5cfafe3b Mon Sep 17 00:00:00 2001
From: Norbert Pocs <norbertpocs0@gmail.com>
Date: Tue, 28 Nov 2023 15:27:31 +0100
Subject: [PATCH 9/9] CVE-2023-6004: torture_misc: Add tests for ipv6
link-local
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict: NA
Reference:https://git.libssh.org/projects/libssh.git/patch/?id=6a8a18c73e73a338283dfbade0a7d83e5cfafe3b
---
tests/unittests/torture_misc.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/tests/unittests/torture_misc.c b/tests/unittests/torture_misc.c
index 073bc54c..f16b766e 100644
--- a/tests/unittests/torture_misc.c
+++ b/tests/unittests/torture_misc.c
@@ -17,7 +17,14 @@
#include "misc.c"
#include "error.c"
+#ifdef _WIN32
+#include <netioapi.h>
+#else
+#include <net/if.h>
+#endif
+
#define TORTURE_TEST_DIR "/usr/local/bin/truc/much/.."
+#define TORTURE_IPV6_LOCAL_LINK "fe80::98e1:82ff:fe8d:28b3%%%s"
const char template[] = "temp_dir_XXXXXX";
@@ -730,14 +737,27 @@ static void torture_ssh_check_hostname_syntax(void **state)
static void torture_ssh_is_ipaddr(void **state) {
int rc;
+ char *interf = malloc(64);
+ char *test_interf = malloc(128);
(void)state;
+ assert_non_null(interf);
+ assert_non_null(test_interf);
rc = ssh_is_ipaddr("201.255.3.69");
assert_int_equal(rc, 1);
rc = ssh_is_ipaddr("::1");
assert_int_equal(rc, 1);
rc = ssh_is_ipaddr("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
assert_int_equal(rc, 1);
+ if_indextoname(1, interf);
+ assert_non_null(interf);
+ rc = sprintf(test_interf, TORTURE_IPV6_LOCAL_LINK, interf);
+ /* the "%%s" is not written */
+ assert_int_equal(rc, strlen(interf) + strlen(TORTURE_IPV6_LOCAL_LINK) - 3);
+ rc = ssh_is_ipaddr(test_interf);
+ assert_int_equal(rc, 1);
+ free(interf);
+ free(test_interf);
rc = ssh_is_ipaddr("..");
assert_int_equal(rc, 0);
--
2.33.0

View File

@ -0,0 +1,89 @@
From 11bd6e6ad926a38cd7b9f8308a4c2fd8dfd9200c Mon Sep 17 00:00:00 2001
From: Norbert Pocs <norbertpocs0@gmail.com>
Date: Sun, 5 Nov 2023 13:12:47 +0100
Subject: [PATCH] CVE-2023-6004: torture_config: Allow multiple '@' in
usernames
Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Conflict: NA
Reference:https://gitlab.com/libssh/libssh-mirror/-/commit/11bd6e6ad926a38cd7b9f8308a4c2fd8dfd9200c
---
tests/unittests/torture_config.c | 44 ++++++++++++++++++--------------
1 file changed, 25 insertions(+), 19 deletions(-)
diff --git a/tests/unittests/torture_config.c b/tests/unittests/torture_config.c
index f91112a9..3a5a74bf 100644
--- a/tests/unittests/torture_config.c
+++ b/tests/unittests/torture_config.c
@@ -671,24 +671,40 @@ static void torture_config_proxyjump(void **state) {
assert_string_equal(session->opts.ProxyCommand,
"ssh -W [%h]:%p 2620:52:0::fed");
- /* Try to create some invalid configurations */
- /* Non-numeric port */
+ /* Multiple @ is allowed in second jump */
torture_write_file(LIBSSH_TESTCONFIG11,
- "Host bad-port\n"
- "\tProxyJump jumpbox:22bad22\n"
+ "Host allowed-hostname\n"
+ "\tProxyJump localhost,user@principal.com@jumpbox:22\n"
"");
torture_reset_config(session);
- ssh_options_set(session, SSH_OPTIONS_HOST, "bad-port");
+ ssh_options_set(session, SSH_OPTIONS_HOST, "allowed-hostname");
ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code_equal(session, ret, SSH_ERROR);
+ assert_ssh_return_code(session, ret);
+ assert_string_equal(session->opts.ProxyCommand,
+ "ssh -J user@principal.com@jumpbox:22 -W [%h]:%p localhost");
- /* Too many @ */
+ /* Multiple @ is allowed */
torture_write_file(LIBSSH_TESTCONFIG11,
- "Host bad-hostname\n"
+ "Host allowed-hostname\n"
"\tProxyJump user@principal.com@jumpbox:22\n"
"");
torture_reset_config(session);
- ssh_options_set(session, SSH_OPTIONS_HOST, "bad-hostname");
+ ssh_options_set(session, SSH_OPTIONS_HOST, "allowed-hostname");
+ ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
+ assert_ssh_return_code(session, ret);
+ assert_string_equal(session->opts.ProxyCommand,
+ "ssh -l user@principal.com -p 22 -W [%h]:%p jumpbox");
+
+ /* In this part, we try various other config files and strings. */
+
+ /* Try to create some invalid configurations */
+ /* Non-numeric port */
+ torture_write_file(LIBSSH_TESTCONFIG11,
+ "Host bad-port\n"
+ "\tProxyJump jumpbox:22bad22\n"
+ "");
+ torture_reset_config(session);
+ ssh_options_set(session, SSH_OPTIONS_HOST, "bad-port");
ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
assert_ssh_return_code_equal(session, ret, SSH_ERROR);
@@ -752,16 +768,6 @@ static void torture_config_proxyjump(void **state) {
ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
assert_ssh_return_code_equal(session, ret, SSH_ERROR);
- /* Too many @ in second jump */
- torture_write_file(LIBSSH_TESTCONFIG11,
- "Host bad-hostname\n"
- "\tProxyJump localhost,user@principal.com@jumpbox:22\n"
- "");
- torture_reset_config(session);
- ssh_options_set(session, SSH_OPTIONS_HOST, "bad-hostname");
- ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11);
- assert_ssh_return_code_equal(session, ret, SSH_ERROR);
-
/* Braces mismatch in second jump */
torture_write_file(LIBSSH_TESTCONFIG11,
"Host mismatch\n"
--
2.33.0

View File

@ -0,0 +1,62 @@
From eb9dc8cfc45875ddf8dd193eb16e506937ce5355 Mon Sep 17 00:00:00 2001
From: Norbert Pocs <npocs@redhat.com>
Date: Tue, 7 Jun 2022 14:28:30 +0200
Subject: [PATCH] Add errno reset with strtoul call
Contaminated errno can happen before strtoul call, thereofore
cleaning it before the call.
The errno is not used for checking later in code if fail happens,
therefore cleaning it right after error.
Signed-off-by: Norbert Pocs <npocs@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
---
src/misc.c | 4 ++++
tests/pkd/pkd_util.c | 1 +
2 files changed, 5 insertions(+)
diff --git a/src/misc.c b/src/misc.c
index f7efb9df..e890e829 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -1361,21 +1361,25 @@ int ssh_analyze_banner(ssh_session session, int server)
* 012345678901234567890
*/
if (strlen(openssh) > 9) {
+ errno = 0;
major = strtoul(openssh + 8, &tmp, 10);
if ((tmp == (openssh + 8)) ||
((errno == ERANGE) && (major == ULONG_MAX)) ||
((errno != 0) && (major == 0)) ||
((major < 1) || (major > 100))) {
/* invalid major */
+ errno = 0;
goto done;
}
+ errno = 0;
minor = strtoul(openssh + 10, &tmp, 10);
if ((tmp == (openssh + 10)) ||
((errno == ERANGE) && (major == ULONG_MAX)) ||
((errno != 0) && (major == 0)) ||
(minor > 100)) {
/* invalid minor */
+ errno = 0;
goto done;
}
diff --git a/tests/pkd/pkd_util.c b/tests/pkd/pkd_util.c
index 0e3b19b4..e8e6fbb7 100644
--- a/tests/pkd/pkd_util.c
+++ b/tests/pkd/pkd_util.c
@@ -81,6 +81,7 @@ static int is_openssh_client_new_enough(void) {
((major < 1) || (major > 100))) {
fprintf(stderr, "failed to parse OpenSSH client version, "
"errno %d\n", errno);
+ errno = 0;
goto errversion;
}
--
2.33.0

View File

@ -0,0 +1,27 @@
From f6ad8057a71e7a690d31d43c3797081ff544e3fd Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn@cryptomilk.org>
Date: Wed, 22 Jun 2022 15:22:37 +0200
Subject: [PATCH] auth: Fix error returned in ssh_userauth_try_publickey()
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
---
src/auth.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/auth.c b/src/auth.c
index 2e48cfc6..6343c6a9 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -518,7 +518,7 @@ int ssh_userauth_try_publickey(ssh_session session,
SSH_FATAL,
"Wrong state (%d) during pending SSH call",
session->pending_call_state);
- return SSH_ERROR;
+ return SSH_AUTH_ERROR;
}
/* Check if the given public key algorithm is allowed */
--
2.33.0

View File

@ -0,0 +1,32 @@
From 4b20d7ad1882feafb28e4371cd7c7c1c9c499153 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn@cryptomilk.org>
Date: Tue, 19 Apr 2022 16:22:12 +0200
Subject: [PATCH] client: Do not close the socket if it was set via options
Fixes #122
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
---
src/client.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/client.c b/src/client.c
index 4e2a299d..a41764f1 100644
--- a/src/client.c
+++ b/src/client.c
@@ -720,7 +720,10 @@ ssh_disconnect(ssh_session session)
}
ssh_packet_send(session);
- ssh_socket_close(session->socket);
+ /* Do not close the socket, if the fd was set via options. */
+ if (session->opts.fd == SSH_INVALID_SOCKET) {
+ ssh_socket_close(session->socket);
+ }
}
error:
session->recv_seq = 0;
--
2.33.0

View File

@ -0,0 +1,32 @@
From a889527c1b8f9831b47ceac510057585cdc81d39 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn@cryptomilk.org>
Date: Wed, 15 Jun 2022 15:10:08 +0200
Subject: [PATCH] libsshpp: Fix openForward to not set sourcehost to NULL by
default
This parameter is required.
Fixes #25
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
---
include/libssh/libsshpp.hpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/libssh/libsshpp.hpp b/include/libssh/libsshpp.hpp
index a678d375..602c7aec 100644
--- a/include/libssh/libsshpp.hpp
+++ b/include/libssh/libsshpp.hpp
@@ -523,7 +523,7 @@ public:
return ssh_channel_is_open(channel) != 0;
}
int openForward(const char *remotehost, int remoteport,
- const char *sourcehost=NULL, int localport=0){
+ const char *sourcehost, int localport=0){
int err=ssh_channel_open_forward(channel,remotehost,remoteport,
sourcehost, localport);
ssh_throw(err);
--
2.33.0

View File

@ -0,0 +1,29 @@
From 332f1c2e093de27e7fcfe22d80f0660c57e002eb Mon Sep 17 00:00:00 2001
From: tatataeki <shengzeyu19_98@163.com>
Date: Wed, 29 Jun 2022 14:20:48 +0800
Subject: [PATCH] sftp: fix the length calculation of packet in sftp_write
Signed-off-by: tatataeki <shengzeyu19_98@163.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
---
src/sftp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/sftp.c b/src/sftp.c
index b1fa931e..e01012a8 100644
--- a/src/sftp.c
+++ b/src/sftp.c
@@ -2178,8 +2178,8 @@ ssize_t sftp_write(sftp_file file, const void *buf, size_t count) {
sftp_set_error(sftp, SSH_FX_FAILURE);
return -1;
}
- packetlen=ssh_buffer_get_len(buffer);
len = sftp_packet_write(file->sftp, SSH_FXP_WRITE, buffer);
+ packetlen=ssh_buffer_get_len(buffer);
SSH_BUFFER_FREE(buffer);
if (len < 0) {
return -1;
--
2.33.0

View File

@ -0,0 +1,32 @@
From d2a41e606bbd6074b88be46f7b0fd3cd3f7d5536 Mon Sep 17 00:00:00 2001
From: Andreas Schneider <asn@cryptomilk.org>
Date: Wed, 26 May 2021 17:06:42 +0200
Subject: tests: Fix running timeout tests on gitlab windows runners
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Conflict: NA
Reference: https://git.libssh.org/projects/libssh.git/patch/tests/unittests/torture_misc.c?id=d2a41e606bbd6074b88be46f7b0fd3cd3f7d5536
---
tests/unittests/torture_misc.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'tests/unittests/torture_misc.c')
diff --git a/tests/unittests/torture_misc.c b/tests/unittests/torture_misc.c
index 2d2d6860..c7b99b5d 100644
--- a/tests/unittests/torture_misc.c
+++ b/tests/unittests/torture_misc.c
@@ -209,7 +209,8 @@ static void torture_timeout_elapsed(void **state){
struct ssh_timestamp ts;
(void) state;
ssh_timestamp_init(&ts);
- usleep(50000);
+ usleep(30000);
+
assert_true(ssh_timeout_elapsed(&ts,25));
assert_false(ssh_timeout_elapsed(&ts,30000));
assert_false(ssh_timeout_elapsed(&ts,75));
--
cgit v1.2.3

View File

@ -1,6 +1,6 @@
Name: libssh
Version: 0.9.4
Release: 4
Release: 9
Summary: A library implementing the SSH protocol
License: LGPLv2+
URL: http://www.libssh.org
@ -14,6 +14,42 @@ Patch2: CVE-2020-16135-1.patch
Patch3: CVE-2020-16135-2.patch
Patch4: CVE-2020-16135-3.patch
Patch5: CVE-2020-16135-4.patch
Patch6: CVE-2021-3634.patch
Patch7: backport-Add-errno-reset-with-strtoul-call.patch
Patch8: backport-auth-Fix-error-returned-in-ssh_userauth_try_publicke.patch
Patch9: backport-client-Do-not-close-the-socket-if-it-was-set-via-opt.patch
Patch10: backport-libsshpp-Fix-openForward-to-not-set-sourcehost-to-NU.patch
Patch11: backport-sftp-fix-the-length-calculation-of-packet-in-sftp_wr.patch
Patch12: backport-tests-Fix-running-timeout-tests-on-gitlab-windows-ru.patch
Patch13: backport-0001-CVE-2023-1667-packet_cb-Log-more-verbose-error-if-si.patch
Patch14: backport-0002-CVE-2023-1667-packet-Do-not-allow-servers-to-initiat.patch
Patch15: backport-0003-CVE-2023-1667-kex-Remove-needless-function-argument.patch
Patch16: backport-0004-CVE-2023-1667-kex-Factor-out-the-kex-mapping-to-inte.patch
Patch17: backport-0005-CVE-2023-1667-dh-Expose-the-callback-cleanup-functio.patch
Patch18: backport-0006-CVE-2023-1667-kex-Correctly-handle-last-fields-of-KE.patch
Patch19: backport-0007-CVE-2023-1667-kex-Add-support-for-sending-first_kex_.patch
Patch20: backport-0008-CVE-2023-1667-tests-Client-coverage-for-key-exchange.patch
Patch21: backport-0009-CVE-2023-1667-tests-Send-a-bit-more-to-make-sure-rek.patch
Patch22: backport-0001-CVE-2023-2283-pki_crypto-Fix-possible-authentication.patch
Patch23: backport-0002-CVE-2023-2283-pki_crypto-Remove-unnecessary-NUL.patch
Patch24: backport-0001-CVE-2023-6004-config_parser-Allow-multiple-in-userna.patch
Patch25: backport-0002-CVE-2023-6004-options-Simplify-the-hostname-parsing-.patch
Patch26: backport-0003-CVE-2023-6004-misc-Add-function-to-check-allowed-cha.patch
Patch27: backport-0004-CVE-2023-6004-torture_misc-Add-test-for-ssh_check_ho.patch
Patch28: backport-0005-CVE-2023-6004-config_parser-Check-for-valid-syntax-o.patch
Patch29: backport-0006-CVE-2023-6004-torture_proxycommand-Add-test-for-prox.patch
Patch30: backport-0007-CVE-2023-6004-torture_misc-Add-test-for-ssh_is_ipadd.patch
Patch31: backport-0008-CVE-2023-6004-misc-Add-ipv6-link-local-check-for-an-.patch
Patch32: backport-0009-CVE-2023-6004-torture_misc-Add-tests-for-ipv6-link-l.patch
Patch33: backport-0001-CVE-2023-48795-client-side-mitigation.patch
Patch34: backport-0002-CVE-2023-48795-Server-side-mitigations.patch
Patch35: backport-0003-CVE-2023-48795-Strip-extensions-from-both-kex-lists-.patch
Patch36: backport-0004-CVE-2023-48795-tests-Adjust-calculation-to-strict-ke.patch
Patch37: backport-0001-CVE-2023-6918-kdf-Reformat.patch
Patch38: backport-0002-CVE-2023-6918-Remove-unused-evp-functions-and-types.patch
Patch39: backport-0003-CVE-2023-6918-Systematically-check-return-values-whe.patch
Patch40: backport-0004-CVE-2023-6918-kdf-Detect-context-init-failures.patch
Patch41: backport-0010-CVE-2023-6004-torture_config-Allow-multiple-in-usern.patch
BuildRequires: cmake gcc-c++ gnupg2 openssl-devel pkgconfig zlib-devel
BuildRequires: krb5-devel libcmocka-devel openssh-clients openssh-server
@ -98,6 +134,41 @@ popd
%doc ChangeLog README
%changelog
* Thu Jan 4 2024 renmingshuai <renmingshuai@huawei.com> - 0.9.4-9
- Type:CVE
- Id:CVE-2023-6004,CVE-2023-48795,CVE-2023-6918
- SUG:NA
- DESC:fix CVE-2023-6004,CVE-2023-48795 and CVE-2023-6918
* Fri May 19 2023 renmingshuai <renmingshuai@huawei.com> - 0.9.4-8
- Type:CVE
- Id:CVE-2023-1667,CVE-2023-2283
- SUG:NA
- DESC:fix CVE-2023-1667 and CVE-2023-2283
* Tue Oct 25 2022 xinghe <xinghe2@h-partners.com> - 0.9.4-7
- Type:bugfix
- Id:NA
- SUG:NA
- DESC:tests: Fix running timeout tests on gitlab windows runners
* Fri Sep 02 2022 gaihuiying <eaglegai@163.com> - 0.9.4-6
- Type:bugfix
- Id:NA
- SUG:NA
- DESC:backport upstream patches:
add errno while reset with strtoul call
fix error returned in ssh_userauth_try_publicke
client do not close the socket if it was set via opt
fix openForward to not set sourcehost to NULL
fix the length calculation of packet in sftp_write
* Mon Sep 13 2021 heyaohua<heyaohua1@huawei.com> - 0.9.4-5
- Type:CVE
- CVE:CVE-2021-3634
- SUG:NA
- DESC:fix CVE-2021-3634
* Tue Aug 3 2021 Jianmin <jianmin@iscas.ac.cn> - 0.9.4-4
- Type:enchancement
- CVE:NA