commit e73ec2f16d3c50673f35ebc4c97691b0045a2a69 Author: MSVSphere Packaging Team Date: Fri Mar 29 15:56:45 2024 +0300 import libssh-0.9.6-14.el8 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..76fb7b8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +SOURCES/libssh-0.9.6.tar.xz +SOURCES/libssh.keyring diff --git a/.libssh.metadata b/.libssh.metadata new file mode 100644 index 0000000..6b8b582 --- /dev/null +++ b/.libssh.metadata @@ -0,0 +1,2 @@ +1b2dd673b58e1eaf20fde45cd8de2197cfab2f78 SOURCES/libssh-0.9.6.tar.xz +3f2ab0bca02893402ba0ad172a6bd44456a65f86 SOURCES/libssh.keyring diff --git a/SOURCES/CVE-2023-48795.patch b/SOURCES/CVE-2023-48795.patch new file mode 100644 index 0000000..9ff6031 --- /dev/null +++ b/SOURCES/CVE-2023-48795.patch @@ -0,0 +1,723 @@ +From 87b93be5a2071be782aa84aa5a91544b18959d5e Mon Sep 17 00:00:00 2001 +From: Aris Adamantiadis +Date: Tue, 12 Dec 2023 23:09:57 +0100 +Subject: [PATCH 1/4] CVE-2023-48795: client side mitigation + +Signed-off-by: Aris Adamantiadis +Signed-off-by: Jakub Jelen +Reviewed-by: Andreas Schneider +--- + 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_DEBUG, "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_DEBUG, "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_DEBUG, "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_DEBUG, "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_DEBUG, "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_DEBUG, "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_DEBUG, "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_DEBUG, "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(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(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.41.0 + + +From fd4948255560039b51c2d61f0a62784ed8b6f5a6 Mon Sep 17 00:00:00 2001 +From: Aris Adamantiadis +Date: Tue, 12 Dec 2023 23:30:26 +0100 +Subject: [PATCH 2/4] CVE-2023-48795: Server side mitigations + +Signed-off-by: Aris Adamantiadis +Signed-off-by: Jakub Jelen +Reviewed-by: Andreas Schneider +--- + 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.41.0 + + +From 03bbbc9e4c93aae2ccdd302d6123e4809be37746 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +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 +Reviewed-by: Andreas Schneider +--- + 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.41.0 + + +From 768d1ed30cf4b3cb9628254ef3ee24b9c38abdbc Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +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 +Reviewed-by: Andreas Schneider +--- + tests/client/torture_rekey.c | 56 ++++++++++++++++++++---------------- + 1 file changed, 32 insertions(+), 24 deletions(-) + +diff --git a/tests/client/torture_rekey.c b/tests/client/torture_rekey.c +index 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); +@@ -464,15 +477,10 @@ static void torture_rekey_different_kex(void **state) + assert_ssh_return_code(s->ssh.session, rc); + + /* The blocks limit is set correctly */ +- c = s->ssh.session->current_crypto; +- assert_int_equal(c->in_cipher->max_blocks, +- bytes / c->in_cipher->blocksize); +- assert_int_equal(c->out_cipher->max_blocks, +- bytes / c->out_cipher->blocksize); +- /* We should have less encrypted packets than transfered (first are not encrypted) */ +- assert_true(c->out_cipher->packets < s->ssh.session->send_seq); +- assert_true(c->in_cipher->packets < s->ssh.session->recv_seq); ++ sanity_check_session(state); + /* Copy the initial secret hash = session_id so we know we changed keys later */ ++ c = s->ssh.session->current_crypto; ++ assert_non_null(c); + secret_hash = malloc(c->digest_len); + assert_non_null(secret_hash); + memcpy(secret_hash, c->secret_hash, c->digest_len); +-- +2.41.0 + diff --git a/SOURCES/CVE-2023-6004.patch b/SOURCES/CVE-2023-6004.patch new file mode 100644 index 0000000..27a72d6 --- /dev/null +++ b/SOURCES/CVE-2023-6004.patch @@ -0,0 +1,1114 @@ +From 11bd6e6ad926a38cd7b9f8308a4c2fd8dfd9200c Mon Sep 17 00:00:00 2001 +From: Norbert Pocs +Date: Sun, 5 Nov 2023 13:12:47 +0100 +Subject: [PATCH 01/12] CVE-2023-6004: torture_config: Allow multiple '@' in + usernames + +Signed-off-by: Norbert Pocs +Reviewed-by: Andreas Schneider +--- + 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.41.0 + + +From c3234e5f94b96d6e29f0c1c82821c1e3ebb181ed Mon Sep 17 00:00:00 2001 +From: Norbert Pocs +Date: Wed, 1 Nov 2023 11:24:43 +0100 +Subject: [PATCH 02/12] CVE-2023-6004: config_parser: Allow multiple '@' in + usernames + +Signed-off-by: Norbert Pocs +Reviewed-by: Andreas Schneider +--- + 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.41.0 + + +From a5b8bd0d8841296cf71d927824d60f576581243f Mon Sep 17 00:00:00 2001 +From: Norbert Pocs +Date: Tue, 31 Oct 2023 09:48:52 +0100 +Subject: [PATCH 03/12] 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 +Reviewed-by: Andreas Schneider +--- + 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.41.0 + + +From efb24b6472e8b87c5832c0590f14e99e82fcdeeb Mon Sep 17 00:00:00 2001 +From: Norbert Pocs +Date: Tue, 10 Oct 2023 12:44:16 +0200 +Subject: [PATCH 04/12] 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 +Reviewed-by: Andreas Schneider +--- + 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.41.0 + + +From 234ecdf4d9705efa3727a54dcc1ddfe6377c7bf6 Mon Sep 17 00:00:00 2001 +From: Norbert Pocs +Date: Tue, 10 Oct 2023 12:45:28 +0200 +Subject: [PATCH 05/12] CVE-2023-6004: torture_misc: Add test for + ssh_check_hostname_syntax + +Signed-off-by: Norbert Pocs +Reviewed-by: Andreas Schneider +--- + 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.41.0 + + +From 4d7ae19e9cd8c407012b40f3f2eaf480bfb1da7d Mon Sep 17 00:00:00 2001 +From: Norbert Pocs +Date: Tue, 10 Oct 2023 18:33:56 +0200 +Subject: [PATCH 06/12] 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 +Reviewed-by: Andreas Schneider +--- + 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.41.0 + + +From 8cf4f4bfda968ab526c1a601ea1030bbaccaba17 Mon Sep 17 00:00:00 2001 +From: Norbert Pocs +Date: Tue, 10 Oct 2023 10:28:47 +0200 +Subject: [PATCH 07/12] CVE-2023-6004: torture_proxycommand: Add test for + proxycommand injection + +Signed-off-by: Norbert Pocs +Reviewed-by: Andreas Schneider +--- + 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.41.0 + + +From a0dbe0d556e073804cc549802569577bb24757d9 Mon Sep 17 00:00:00 2001 +From: Norbert Pocs +Date: Mon, 6 Nov 2023 20:11:38 +0100 +Subject: [PATCH 08/12] CVE-2023-6004: torture_misc: Add test for ssh_is_ipaddr + +Signed-off-by: Norbert Pocs +Reviewed-by: Andreas Schneider +--- + 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.41.0 + + +From cdaec0d6273243a03f460cc5ba1a2265b4afb93a Mon Sep 17 00:00:00 2001 +From: Norbert Pocs +Date: Tue, 28 Nov 2023 15:26:45 +0100 +Subject: [PATCH 09/12] CVE-2023-6004: misc: Add ipv6 link-local check for an + ip address + +Signed-off-by: Norbert Pocs +Reviewed-by: Andreas Schneider +--- + 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_LIBRARIES) + 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 + #include + #include ++#include + + #endif /* _WIN32 */ + +@@ -59,6 +60,7 @@ + #include + #include + #include ++#include + + #ifdef HAVE_IO_H + #include +@@ -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.41.0 + + +From 6a8a18c73e73a338283dfbade0a7d83e5cfafe3b Mon Sep 17 00:00:00 2001 +From: Norbert Pocs +Date: Tue, 28 Nov 2023 15:27:31 +0100 +Subject: [PATCH 10/12] CVE-2023-6004: torture_misc: Add tests for ipv6 + link-local + +Signed-off-by: Norbert Pocs +Reviewed-by: Andreas Schneider +--- + 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 ++#else ++#include ++#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.41.0 + + +From 72f59157e6ccbd4c0bb806690931413169a0886f Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Fri, 22 Dec 2023 10:32:40 +0100 +Subject: [PATCH 11/12] Fix regression in IPv6 addresses in hostname parsing + +Signed-off-by: Jakub Jelen +Reviewed-by: Andreas Schneider +(cherry picked from commit 4f997aee7c7d7ea346b3e8ba505da0b7601ff318) +--- + include/libssh/config_parser.h | 11 ++++++++--- + src/config.c | 4 ++-- + src/config_parser.c | 16 +++++++++++----- + src/options.c | 10 ++-------- + 4 files changed, 23 insertions(+), 18 deletions(-) + +diff --git a/include/libssh/config_parser.h b/include/libssh/config_parser.h +index e974917c..ee647bfb 100644 +--- a/include/libssh/config_parser.h ++++ b/include/libssh/config_parser.h +@@ -26,6 +26,8 @@ + #ifndef CONFIG_PARSER_H_ + #define CONFIG_PARSER_H_ + ++#include ++ + char *ssh_config_get_cmd(char **str); + + char *ssh_config_get_token(char **str); +@@ -45,13 +47,16 @@ int ssh_config_get_yesno(char **str, int notfound); + * be stored or NULL if we do not care about the result. + * @param[out] port Pointer to the location, where the new port will + * be stored or NULL if we do not care about the result. ++ * @param[in] ignore_port Set to true if the we should not attempt to parse ++ * port number. + * + * @returns SSH_OK if the provided string is in format of SSH URI, + * SSH_ERROR on failure + */ + int ssh_config_parse_uri(const char *tok, +- char **username, +- char **hostname, +- char **port); ++ char **username, ++ char **hostname, ++ char **port, ++ bool ignore_port); + + #endif /* LIBSSH_CONFIG_H_ */ +diff --git a/src/config.c b/src/config.c +index 54ada276..a813568d 100644 +--- a/src/config.c ++++ b/src/config.c +@@ -324,7 +324,7 @@ ssh_config_parse_proxy_jump(ssh_session session, const char *s, bool do_parsing) + } + if (parse_entry) { + /* We actually care only about the first item */ +- rv = ssh_config_parse_uri(cp, &username, &hostname, &port); ++ rv = ssh_config_parse_uri(cp, &username, &hostname, &port, false); + /* The rest of the list needs to be passed on */ + if (endp != NULL) { + next = strdup(endp + 1); +@@ -335,7 +335,7 @@ ssh_config_parse_proxy_jump(ssh_session session, const char *s, bool do_parsing) + } + } else { + /* The rest is just sanity-checked to avoid failures later */ +- rv = ssh_config_parse_uri(cp, NULL, NULL, NULL); ++ rv = ssh_config_parse_uri(cp, NULL, NULL, NULL, false); + } + if (rv != SSH_OK) { + goto out; +diff --git a/src/config_parser.c b/src/config_parser.c +index 87bac5d4..a2da0a62 100644 +--- a/src/config_parser.c ++++ b/src/config_parser.c +@@ -134,9 +134,10 @@ int ssh_config_get_yesno(char **str, int notfound) + } + + int ssh_config_parse_uri(const char *tok, +- char **username, +- char **hostname, +- char **port) ++ char **username, ++ char **hostname, ++ char **port, ++ bool ignore_port) + { + char *endp = NULL; + long port_n; +@@ -182,12 +183,17 @@ int ssh_config_parse_uri(const char *tok, + if (endp == NULL) { + goto error; + } +- } else { +- /* Hostnames or aliases expand to the last colon or to the end */ ++ } else if (!ignore_port) { ++ /* Hostnames or aliases expand to the last colon (if port is requested) ++ * or to the end */ + endp = strrchr(tok, ':'); + if (endp == NULL) { + endp = strchr(tok, '\0'); + } ++ } else { ++ /* If no port is requested, expand to the end of line ++ * (to accommodate the IPv6 addresses) */ ++ endp = strchr(tok, '\0'); + } + if (tok == endp) { + /* Zero-length hostnames are not valid */ +diff --git a/src/options.c b/src/options.c +index 7c03e7ab..0890ff2e 100644 +--- a/src/options.c ++++ b/src/options.c +@@ -491,17 +491,11 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type, + ssh_set_error_invalid(session); + return -1; + } else { +- char *username = NULL, *hostname = NULL, *port = NULL; +- rc = ssh_config_parse_uri(value, &username, &hostname, &port); ++ char *username = NULL, *hostname = NULL; ++ rc = ssh_config_parse_uri(value, &username, &hostname, NULL, true); + if (rc != SSH_OK) { + 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 = username; +-- +2.41.0 + + +From 5dc10ff63ca2e8db91abfdccf1d095f5b4261b8e Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Fri, 22 Dec 2023 09:52:18 +0100 +Subject: [PATCH 12/12] tests: Increase test coverage for IPv6 address parsing + as hostnames + +This was an issue in cockpit: + +https://github.com/cockpit-project/cockpit/issues/19772 + +Signed-off-by: Jakub Jelen +Reviewed-by: Andreas Schneider +(cherry picked from commit 6f6e453d7b0ad4ee6a6f6a1c96a9a6b27821410d) +--- + tests/unittests/torture_config.c | 49 +++++++++++++++++++++++++++++++ + tests/unittests/torture_options.c | 22 ++++++++++++++ + 2 files changed, 71 insertions(+) + +diff --git a/tests/unittests/torture_config.c b/tests/unittests/torture_config.c +index 3a5a74bf..d8097e79 100644 +--- a/tests/unittests/torture_config.c ++++ b/tests/unittests/torture_config.c +@@ -2,6 +2,7 @@ + + #define LIBSSH_STATIC + ++#include + #include "torture.h" + #include "libssh/options.h" + #include "libssh/session.h" +@@ -997,6 +998,53 @@ static void torture_config_match_pattern(void **state) + + } + ++static void torture_config_parse_uri(void **state) ++{ ++ char *username = NULL; ++ char *hostname = NULL; ++ char *port = NULL; ++ int rc; ++ ++ (void)state; /* unused */ ++ ++ rc = ssh_config_parse_uri("localhost", &username, &hostname, &port, false); ++ assert_return_code(rc, errno); ++ assert_null(username); ++ assert_string_equal(hostname, "localhost"); ++ SAFE_FREE(hostname); ++ assert_null(port); ++ ++ rc = ssh_config_parse_uri("1.2.3.4", &username, &hostname, &port, false); ++ assert_return_code(rc, errno); ++ assert_null(username); ++ assert_string_equal(hostname, "1.2.3.4"); ++ SAFE_FREE(hostname); ++ assert_null(port); ++ ++ rc = ssh_config_parse_uri("1.2.3.4:2222", &username, &hostname, &port, false); ++ assert_return_code(rc, errno); ++ assert_null(username); ++ assert_string_equal(hostname, "1.2.3.4"); ++ SAFE_FREE(hostname); ++ assert_string_equal(port, "2222"); ++ SAFE_FREE(port); ++ ++ rc = ssh_config_parse_uri("[1:2:3::4]:2222", &username, &hostname, &port, false); ++ assert_return_code(rc, errno); ++ assert_null(username); ++ assert_string_equal(hostname, "1:2:3::4"); ++ SAFE_FREE(hostname); ++ assert_string_equal(port, "2222"); ++ SAFE_FREE(port); ++ ++ /* do not want port */ ++ rc = ssh_config_parse_uri("1:2:3::4", &username, &hostname, NULL, true); ++ assert_return_code(rc, errno); ++ assert_null(username); ++ assert_string_equal(hostname, "1:2:3::4"); ++ SAFE_FREE(hostname); ++} ++ + + int torture_run_tests(void) { + int rc; +@@ -1012,6 +1060,7 @@ int torture_run_tests(void) { + cmocka_unit_test(torture_config_rekey), + cmocka_unit_test(torture_config_pubkeyacceptedkeytypes), + cmocka_unit_test(torture_config_match_pattern), ++ cmocka_unit_test(torture_config_parse_uri), + }; + + +diff --git a/tests/unittests/torture_options.c b/tests/unittests/torture_options.c +index d0fdaed1..576ca9cd 100644 +--- a/tests/unittests/torture_options.c ++++ b/tests/unittests/torture_options.c +@@ -59,12 +59,34 @@ static void torture_options_set_host(void **state) { + assert_non_null(session->opts.host); + assert_string_equal(session->opts.host, "localhost"); + ++ /* IPv4 address */ ++ rc = ssh_options_set(session, SSH_OPTIONS_HOST, "127.1.1.1"); ++ assert_true(rc == 0); ++ assert_non_null(session->opts.host); ++ assert_string_equal(session->opts.host, "127.1.1.1"); ++ assert_null(session->opts.username); ++ ++ /* IPv6 address */ ++ rc = ssh_options_set(session, SSH_OPTIONS_HOST, "::1"); ++ assert_true(rc == 0); ++ assert_non_null(session->opts.host); ++ assert_string_equal(session->opts.host, "::1"); ++ assert_null(session->opts.username); ++ + rc = ssh_options_set(session, SSH_OPTIONS_HOST, "guru@meditation"); + assert_true(rc == 0); + assert_non_null(session->opts.host); + assert_string_equal(session->opts.host, "meditation"); + assert_non_null(session->opts.username); + assert_string_equal(session->opts.username, "guru"); ++ ++ /* more @ in uri is OK -- it should go to the username */ ++ rc = ssh_options_set(session, SSH_OPTIONS_HOST, "at@login@hostname"); ++ assert_true(rc == 0); ++ assert_non_null(session->opts.host); ++ assert_string_equal(session->opts.host, "hostname"); ++ assert_non_null(session->opts.username); ++ assert_string_equal(session->opts.username, "at@login"); + } + + static void torture_options_set_ciphers(void **state) { +-- +2.41.0 + diff --git a/SOURCES/CVE-2023-6918.patch b/SOURCES/CVE-2023-6918.patch new file mode 100644 index 0000000..a5bd07d --- /dev/null +++ b/SOURCES/CVE-2023-6918.patch @@ -0,0 +1,1577 @@ +From 93c1dbd69f07f324c6aa1ab9296a632489cd3ead Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Fri, 15 Dec 2023 10:30:09 +0100 +Subject: [PATCH 1/5] CVE-2023-6918: kdf: Reformat + +Signed-off-by: Jakub Jelen +Reviewed-by: Andreas Schneider +--- + 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.41.0 + + +From 882d9cb5c8d37d93f9b349d517e59bf496817007 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +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 +Reviewed-by: Andreas Schneider +--- + 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.41.0 + + +From a45a3c940d17abb3bcd2b924ccd5cd68eb8fd753 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Fri, 15 Dec 2023 12:55:54 +0100 +Subject: [PATCH 3/5] CVE-2023-6918: Systematically check return values when + calculating digests + +with all crypto backends + +Signed-off-by: Jakub Jelen +Reviewed-by: Andreas Schneider +--- + include/libssh/wrapper.h | 34 +++++--- + src/kdf.c | 96 +++++++++++++++++---- + src/libcrypto.c | 166 +++++++++++++++++++++++++++-------- + src/libgcrypt.c | 142 +++++++++++++++++++++++------- + src/libmbedcrypto.c | 182 ++++++++++++++++++++++++++++++--------- + src/session.c | 72 ++++++++++++---- + 6 files changed, 533 insertions(+), 159 deletions(-) + +diff --git a/include/libssh/wrapper.h b/include/libssh/wrapper.h +index 2f5ce189..e6384b50 100644 +--- a/include/libssh/wrapper.h ++++ b/include/libssh/wrapper.h +@@ -67,32 +67,38 @@ struct ssh_crypto_struct; + + typedef struct ssh_mac_ctx_struct *ssh_mac_ctx; + MD5CTX md5_init(void); +-void md5_update(MD5CTX c, const void *data, unsigned long len); +-void md5_final(unsigned char *md,MD5CTX c); ++void md5_ctx_free(MD5CTX); ++int md5_update(MD5CTX c, const void *data, unsigned long len); ++int md5_final(unsigned char *md,MD5CTX c); + + SHACTX sha1_init(void); +-void sha1_update(SHACTX c, const void *data, unsigned long len); +-void sha1_final(unsigned char *md,SHACTX c); +-void sha1(const unsigned char *digest,int len,unsigned char *hash); ++void sha1_ctx_free(SHACTX); ++int sha1_update(SHACTX c, const void *data, unsigned long len); ++int sha1_final(unsigned char *md,SHACTX c); ++int sha1(const unsigned char *digest,int len,unsigned char *hash); + + SHA256CTX sha256_init(void); +-void sha256_update(SHA256CTX c, const void *data, unsigned long len); +-void sha256_final(unsigned char *md,SHA256CTX c); +-void sha256(const unsigned char *digest, int len, unsigned char *hash); ++void sha256_ctx_free(SHA256CTX); ++int sha256_update(SHA256CTX c, const void *data, unsigned long len); ++int sha256_final(unsigned char *md,SHA256CTX c); ++int sha256(const unsigned char *digest, int len, unsigned char *hash); + + SHA384CTX sha384_init(void); +-void sha384_update(SHA384CTX c, const void *data, unsigned long len); +-void sha384_final(unsigned char *md,SHA384CTX c); +-void sha384(const unsigned char *digest, int len, unsigned char *hash); ++void sha384_ctx_free(SHA384CTX); ++int sha384_update(SHA384CTX c, const void *data, unsigned long len); ++int sha384_final(unsigned char *md,SHA384CTX c); ++int sha384(const unsigned char *digest, int len, unsigned char *hash); + + SHA512CTX sha512_init(void); +-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 sha512_ctx_free(SHA512CTX); ++int sha512_update(SHA512CTX c, const void *data, unsigned long len); ++int sha512_final(unsigned char *md,SHA512CTX c); ++int sha512(const unsigned char *digest, int len, unsigned char *hash); + + 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); ++ + size_t hmac_digest_len(enum ssh_hmac_e type); + + int ssh_kdf(struct ssh_crypto_struct *crypto, +diff --git a/src/kdf.c b/src/kdf.c +index 656a38ed..90f6e9f3 100644 +--- a/src/kdf.c ++++ b/src/kdf.c +@@ -77,41 +77,64 @@ 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) ++static void ssh_mac_ctx_free(ssh_mac_ctx ctx) + { ++ if (ctx == NULL) { ++ return; ++ } ++ + switch (ctx->digest_type) { + case SSH_KDF_SHA1: +- sha1_update(ctx->ctx.sha1_ctx, data, len); ++ sha1_ctx_free(ctx->ctx.sha1_ctx); + break; + case SSH_KDF_SHA256: +- sha256_update(ctx->ctx.sha256_ctx, data, len); ++ sha256_ctx_free(ctx->ctx.sha256_ctx); + break; + case SSH_KDF_SHA384: +- sha384_update(ctx->ctx.sha384_ctx, data, len); ++ sha384_ctx_free(ctx->ctx.sha384_ctx); + break; + case SSH_KDF_SHA512: +- sha512_update(ctx->ctx.sha512_ctx, data, len); ++ sha512_ctx_free(ctx->ctx.sha512_ctx); + break; + } ++ SAFE_FREE(ctx); ++} ++ ++static int ssh_mac_update(ssh_mac_ctx ctx, const void *data, size_t len) ++{ ++ switch (ctx->digest_type) { ++ case SSH_KDF_SHA1: ++ return sha1_update(ctx->ctx.sha1_ctx, data, len); ++ case SSH_KDF_SHA256: ++ return sha256_update(ctx->ctx.sha256_ctx, data, len); ++ case SSH_KDF_SHA384: ++ return sha384_update(ctx->ctx.sha384_ctx, data, len); ++ case SSH_KDF_SHA512: ++ return sha512_update(ctx->ctx.sha512_ctx, data, len); ++ } ++ return SSH_ERROR; + } + +-static void ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx) ++static int ssh_mac_final(unsigned char *md, ssh_mac_ctx ctx) + { ++ int rc = SSH_ERROR; ++ + switch (ctx->digest_type) { + case SSH_KDF_SHA1: +- sha1_final(md, ctx->ctx.sha1_ctx); ++ rc = sha1_final(md, ctx->ctx.sha1_ctx); + break; + case SSH_KDF_SHA256: +- sha256_final(md, ctx->ctx.sha256_ctx); ++ rc = sha256_final(md, ctx->ctx.sha256_ctx); + break; + case SSH_KDF_SHA384: +- sha384_final(md, ctx->ctx.sha384_ctx); ++ rc = sha384_final(md, ctx->ctx.sha384_ctx); + break; + case SSH_KDF_SHA512: +- sha512_final(md, ctx->ctx.sha512_ctx); ++ rc = sha512_final(md, ctx->ctx.sha512_ctx); + break; + } + SAFE_FREE(ctx); ++ return rc; + } + + int sshkdf_derive_key(struct ssh_crypto_struct *crypto, +@@ -127,6 +150,7 @@ int sshkdf_derive_key(struct ssh_crypto_struct *crypto, + size_t output_len = crypto->digest_len; + char letter = key_type; + ssh_mac_ctx ctx; ++ int rc; + + if (DIGEST_MAX_LEN < crypto->digest_len) { + return -1; +@@ -137,11 +161,30 @@ int sshkdf_derive_key(struct ssh_crypto_struct *crypto, + return -1; + } + +- 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->session_id_len); +- ssh_mac_final(digest, ctx); ++ rc = ssh_mac_update(ctx, key, key_len); ++ if (rc != SSH_OK) { ++ ssh_mac_ctx_free(ctx); ++ return -1; ++ } ++ rc = ssh_mac_update(ctx, crypto->secret_hash, crypto->digest_len); ++ if (rc != SSH_OK) { ++ ssh_mac_ctx_free(ctx); ++ return -1; ++ } ++ rc = ssh_mac_update(ctx, &letter, 1); ++ if (rc != SSH_OK) { ++ ssh_mac_ctx_free(ctx); ++ return -1; ++ } ++ rc = ssh_mac_update(ctx, crypto->session_id, crypto->session_id_len); ++ if (rc != SSH_OK) { ++ ssh_mac_ctx_free(ctx); ++ return -1; ++ } ++ rc = ssh_mac_final(digest, ctx); ++ if (rc != SSH_OK) { ++ return -1; ++ } + + if (requested_len < output_len) { + output_len = requested_len; +@@ -153,10 +196,25 @@ int sshkdf_derive_key(struct ssh_crypto_struct *crypto, + if (ctx == NULL) { + return -1; + } +- ssh_mac_update(ctx, key, key_len); +- ssh_mac_update(ctx, crypto->secret_hash, crypto->digest_len); +- ssh_mac_update(ctx, output, output_len); +- ssh_mac_final(digest, ctx); ++ rc = ssh_mac_update(ctx, key, key_len); ++ if (rc != SSH_OK) { ++ ssh_mac_ctx_free(ctx); ++ return -1; ++ } ++ rc = ssh_mac_update(ctx, crypto->secret_hash, crypto->digest_len); ++ if (rc != SSH_OK) { ++ ssh_mac_ctx_free(ctx); ++ return -1; ++ } ++ rc = ssh_mac_update(ctx, output, output_len); ++ if (rc != SSH_OK) { ++ ssh_mac_ctx_free(ctx); ++ return -1; ++ } ++ rc = ssh_mac_final(digest, ctx); ++ if (rc != SSH_OK) { ++ return -1; ++ } + if (requested_len < output_len + crypto->digest_len) { + memcpy(output + output_len, digest, requested_len - output_len); + } else { +diff --git a/src/libcrypto.c b/src/libcrypto.c +index 5f3917ba..45f45a9e 100644 +--- a/src/libcrypto.c ++++ b/src/libcrypto.c +@@ -126,26 +126,46 @@ SHACTX sha1_init(void) + return c; + } + +-void sha1_update(SHACTX c, const void *data, unsigned long len) ++void sha1_ctx_free(SHACTX c) + { +- EVP_DigestUpdate(c, data, len); ++ EVP_MD_CTX_destroy(c); + } + +-void sha1_final(unsigned char *md, SHACTX c) ++int sha1_update(SHACTX c, const void *data, unsigned long len) ++{ ++ int rc = EVP_DigestUpdate(c, data, len); ++ if (rc != 1) { ++ return SSH_ERROR; ++ } ++ return SSH_OK; ++} ++ ++int sha1_final(unsigned char *md, SHACTX c) + { + unsigned int mdlen = 0; ++ int rc = EVP_DigestFinal(c, md, &mdlen); + +- EVP_DigestFinal(c, md, &mdlen); + EVP_MD_CTX_destroy(c); ++ if (rc != 1) { ++ return SSH_ERROR; ++ } ++ return SSH_OK; + } + +-void sha1(const unsigned char *digest, int len, unsigned char *hash) ++int sha1(const unsigned char *digest, int len, unsigned char *hash) + { + SHACTX c = sha1_init(); +- if (c != NULL) { +- sha1_update(c, digest, len); +- sha1_final(hash, c); ++ int rc; ++ ++ if (c == NULL) { ++ return SSH_ERROR; + } ++ rc = sha1_update(c, digest, len); ++ if (rc != SSH_OK) { ++ sha1_ctx_free(c); ++ return SSH_ERROR; ++ } ++ return sha1_final(hash, c); + } + + SHA256CTX sha256_init(void) +@@ -164,26 +184,46 @@ SHA256CTX sha256_init(void) + return c; + } + +-void sha256_update(SHA256CTX c, const void *data, unsigned long len) ++void sha256_ctx_free(SHA256CTX c) ++{ ++ EVP_MD_CTX_destroy(c); ++} ++ ++int sha256_update(SHA256CTX c, const void *data, unsigned long len) + { +- EVP_DigestUpdate(c, data, len); ++ int rc = EVP_DigestUpdate(c, data, len); ++ if (rc != 1) { ++ return SSH_ERROR; ++ } ++ return SSH_OK; + } + +-void sha256_final(unsigned char *md, SHA256CTX c) ++int sha256_final(unsigned char *md, SHA256CTX c) + { + unsigned int mdlen = 0; ++ int rc = EVP_DigestFinal(c, md, &mdlen); + +- EVP_DigestFinal(c, md, &mdlen); + EVP_MD_CTX_destroy(c); ++ if (rc != 1) { ++ return SSH_ERROR; ++ } ++ return SSH_OK; + } + +-void sha256(const unsigned char *digest, int len, unsigned char *hash) ++int sha256(const unsigned char *digest, int len, unsigned char *hash) + { + SHA256CTX c = sha256_init(); +- if (c != NULL) { +- sha256_update(c, digest, len); +- sha256_final(hash, c); ++ int rc; ++ ++ if (c == NULL) { ++ return SSH_ERROR; + } ++ rc = sha256_update(c, digest, len); ++ if (rc != SSH_OK) { ++ sha256_ctx_free(c); ++ return SSH_ERROR; ++ } ++ return sha256_final(hash, c); + } + + SHA384CTX sha384_init(void) +@@ -202,26 +242,47 @@ SHA384CTX sha384_init(void) + return c; + } + +-void sha384_update(SHA384CTX c, const void *data, unsigned long len) ++void ++sha384_ctx_free(SHA384CTX c) ++{ ++ EVP_MD_CTX_destroy(c); ++} ++ ++int sha384_update(SHA384CTX c, const void *data, unsigned long len) + { +- EVP_DigestUpdate(c, data, len); ++ int rc = EVP_DigestUpdate(c, data, len); ++ if (rc != 1) { ++ return SSH_ERROR; ++ } ++ return SSH_OK; + } + +-void sha384_final(unsigned char *md, SHA384CTX c) ++int sha384_final(unsigned char *md, SHA384CTX c) + { + unsigned int mdlen = 0; ++ int rc = EVP_DigestFinal(c, md, &mdlen); + +- EVP_DigestFinal(c, md, &mdlen); + EVP_MD_CTX_destroy(c); ++ if (rc != 1) { ++ return SSH_ERROR; ++ } ++ return SSH_OK; + } + +-void sha384(const unsigned char *digest, int len, unsigned char *hash) ++int sha384(const unsigned char *digest, int len, unsigned char *hash) + { + SHA384CTX c = sha384_init(); +- if (c != NULL) { +- sha384_update(c, digest, len); +- sha384_final(hash, c); ++ int rc; ++ ++ if (c == NULL) { ++ return SSH_ERROR; + } ++ rc = sha384_update(c, digest, len); ++ if (rc != SSH_OK) { ++ sha384_ctx_free(c); ++ return SSH_ERROR; ++ } ++ return sha384_final(hash, c); + } + + SHA512CTX sha512_init(void) +@@ -240,26 +301,46 @@ SHA512CTX sha512_init(void) + return c; + } + +-void sha512_update(SHA512CTX c, const void *data, unsigned long len) ++void sha512_ctx_free(SHA512CTX c) ++{ ++ EVP_MD_CTX_destroy(c); ++} ++ ++int sha512_update(SHA512CTX c, const void *data, unsigned long len) + { +- EVP_DigestUpdate(c, data, len); ++ int rc = EVP_DigestUpdate(c, data, len); ++ if (rc != 1) { ++ return SSH_ERROR; ++ } ++ return SSH_OK; + } + +-void sha512_final(unsigned char *md, SHA512CTX c) ++int sha512_final(unsigned char *md, SHA512CTX c) + { + unsigned int mdlen = 0; ++ int rc = EVP_DigestFinal(c, md, &mdlen); + +- EVP_DigestFinal(c, md, &mdlen); + EVP_MD_CTX_destroy(c); ++ if (rc != 1) { ++ return SSH_ERROR; ++ } ++ return SSH_OK; + } + +-void sha512(const unsigned char *digest, int len, unsigned char *hash) ++int sha512(const unsigned char *digest, int len, unsigned char *hash) + { + SHA512CTX c = sha512_init(); +- if (c != NULL) { +- sha512_update(c, digest, len); +- sha512_final(hash, c); ++ int rc; ++ ++ if (c == NULL) { ++ return SSH_ERROR; ++ } ++ rc = sha512_update(c, digest, len); ++ if (rc != SSH_OK) { ++ sha512_ctx_free(c); ++ return SSH_ERROR; + } ++ return sha512_final(hash, c); + } + + MD5CTX md5_init(void) +@@ -278,17 +359,30 @@ MD5CTX md5_init(void) + return c; + } + +-void md5_update(MD5CTX c, const void *data, unsigned long len) ++void md5_ctx_free(MD5CTX c) + { +- EVP_DigestUpdate(c, data, len); ++ EVP_MD_CTX_destroy(c); + } + +-void md5_final(unsigned char *md, MD5CTX c) ++int md5_update(MD5CTX c, const void *data, unsigned long len) ++{ ++ int rc = EVP_DigestUpdate(c, data, len); ++ if (rc != 1) { ++ return SSH_ERROR; ++ } ++ return SSH_OK; ++} ++ ++int md5_final(unsigned char *md, MD5CTX c) + { + unsigned int mdlen = 0; ++ int rc = EVP_DigestFinal(c, md, &mdlen); + +- EVP_DigestFinal(c, md, &mdlen); + EVP_MD_CTX_destroy(c); ++ if (rc != 1) { ++ return SSH_ERROR; ++ } ++ return SSH_OK; + } + + +diff --git a/src/libgcrypt.c b/src/libgcrypt.c +index 49488793..d1332af3 100644 +--- a/src/libgcrypt.c ++++ b/src/libgcrypt.c +@@ -68,18 +68,35 @@ SHACTX sha1_init(void) { + return ctx; + } + +-void sha1_update(SHACTX c, const void *data, unsigned long len) { ++void ++sha1_ctx_free(SHACTX c) ++{ ++ gcry_md_close(c); ++} ++ ++int sha1_update(SHACTX c, const void *data, unsigned long len) { + gcry_md_write(c, data, len); ++ return SSH_OK; + } + +-void sha1_final(unsigned char *md, SHACTX c) { +- gcry_md_final(c); +- memcpy(md, gcry_md_read(c, 0), SHA_DIGEST_LEN); +- gcry_md_close(c); ++int sha1_final(unsigned char *md, SHACTX c) ++{ ++ unsigned char *tmp = NULL; ++ ++ gcry_md_final(c); ++ tmp = gcry_md_read(c, 0); ++ if (tmp == NULL) { ++ gcry_md_close(c); ++ return SSH_ERROR; ++ } ++ memcpy(md, tmp, SHA_DIGEST_LEN); ++ gcry_md_close(c); ++ return SSH_OK; + } + +-void sha1(const unsigned char *digest, int len, unsigned char *hash) { ++int sha1(const unsigned char *digest, int len, unsigned char *hash) { + gcry_md_hash_buffer(GCRY_MD_SHA1, hash, digest, len); ++ return SSH_OK; + } + + +@@ -90,18 +107,35 @@ SHA256CTX sha256_init(void) { + return ctx; + } + +-void sha256_update(SHACTX c, const void *data, unsigned long len) { ++void ++sha256_ctx_free(SHA256CTX c) ++{ ++ gcry_md_close(c); ++} ++ ++int sha256_update(SHACTX c, const void *data, unsigned long len) { + gcry_md_write(c, data, len); ++ return SSH_OK; + } + +-void sha256_final(unsigned char *md, SHACTX c) { +- gcry_md_final(c); +- memcpy(md, gcry_md_read(c, 0), SHA256_DIGEST_LEN); +- gcry_md_close(c); ++int sha256_final(unsigned char *md, SHACTX c) ++{ ++ unsigned char *tmp = NULL; ++ ++ gcry_md_final(c); ++ tmp = gcry_md_read(c, 0); ++ if (tmp == NULL) { ++ gcry_md_close(c); ++ return SSH_ERROR; ++ } ++ memcpy(md, tmp, SHA256_DIGEST_LEN); ++ gcry_md_close(c); ++ return SSH_OK; + } + +-void sha256(const unsigned char *digest, int len, unsigned char *hash){ ++int sha256(const unsigned char *digest, int len, unsigned char *hash){ + gcry_md_hash_buffer(GCRY_MD_SHA256, hash, digest, len); ++ return SSH_OK; + } + + SHA384CTX sha384_init(void) { +@@ -111,18 +145,35 @@ SHA384CTX sha384_init(void) { + return ctx; + } + +-void sha384_update(SHACTX c, const void *data, unsigned long len) { ++void ++sha384_ctx_free(SHA384CTX c) ++{ ++ gcry_md_close(c); ++} ++ ++int sha384_update(SHACTX c, const void *data, unsigned long len) { + gcry_md_write(c, data, len); ++ return SSH_OK; + } + +-void sha384_final(unsigned char *md, SHACTX c) { +- gcry_md_final(c); +- memcpy(md, gcry_md_read(c, 0), SHA384_DIGEST_LEN); +- gcry_md_close(c); ++int sha384_final(unsigned char *md, SHACTX c) ++{ ++ unsigned char *tmp = NULL; ++ ++ gcry_md_final(c); ++ tmp = gcry_md_read(c, 0); ++ if (tmp == NULL) { ++ gcry_md_close(c); ++ return SSH_ERROR; ++ } ++ memcpy(md, tmp, SHA384_DIGEST_LEN); ++ gcry_md_close(c); ++ return SSH_OK; + } + +-void sha384(const unsigned char *digest, int len, unsigned char *hash) { ++int sha384(const unsigned char *digest, int len, unsigned char *hash) { + gcry_md_hash_buffer(GCRY_MD_SHA384, hash, digest, len); ++ return SSH_OK; + } + + SHA512CTX sha512_init(void) { +@@ -132,18 +183,35 @@ SHA512CTX sha512_init(void) { + return ctx; + } + +-void sha512_update(SHACTX c, const void *data, unsigned long len) { ++void ++sha512_ctx_free(SHA512CTX c) ++{ ++ gcry_md_close(c); ++} ++ ++int sha512_update(SHACTX c, const void *data, unsigned long len) { + gcry_md_write(c, data, len); ++ return SSH_OK; + } + +-void sha512_final(unsigned char *md, SHACTX c) { +- gcry_md_final(c); +- memcpy(md, gcry_md_read(c, 0), SHA512_DIGEST_LEN); +- gcry_md_close(c); ++int sha512_final(unsigned char *md, SHACTX c) ++{ ++ unsigned char *tmp = NULL; ++ ++ gcry_md_final(c); ++ tmp = gcry_md_read(c, 0); ++ if (tmp == NULL) { ++ gcry_md_close(c); ++ return SSH_ERROR; ++ } ++ memcpy(md, tmp, SHA512_DIGEST_LEN); ++ gcry_md_close(c); ++ return SSH_OK; + } + +-void sha512(const unsigned char *digest, int len, unsigned char *hash) { ++int sha512(const unsigned char *digest, int len, unsigned char *hash) { + gcry_md_hash_buffer(GCRY_MD_SHA512, hash, digest, len); ++ return SSH_OK; + } + + MD5CTX md5_init(void) { +@@ -153,14 +221,30 @@ MD5CTX md5_init(void) { + return c; + } + +-void md5_update(MD5CTX c, const void *data, unsigned long len) { ++void ++md5_ctx_free(MD5CTX c) ++{ ++ gcry_md_close(c); ++} ++ ++int md5_update(MD5CTX c, const void *data, unsigned long len) { + gcry_md_write(c,data,len); ++ return SSH_OK; + } + +-void md5_final(unsigned char *md, MD5CTX c) { +- gcry_md_final(c); +- memcpy(md, gcry_md_read(c, 0), MD5_DIGEST_LEN); +- gcry_md_close(c); ++int md5_final(unsigned char *md, MD5CTX c) ++{ ++ unsigned char *tmp = NULL; ++ ++ gcry_md_final(c); ++ tmp = gcry_md_read(c, 0); ++ if (tmp == NULL) { ++ gcry_md_close(c); ++ return SSH_ERROR; ++ } ++ memcpy(md, tmp, MD5_DIGEST_LEN); ++ gcry_md_close(c); ++ return SSH_OK; + } + + int ssh_kdf(struct ssh_crypto_struct *crypto, +diff --git a/src/libmbedcrypto.c b/src/libmbedcrypto.c +index f37a6a6d..e9a2b8e5 100644 +--- a/src/libmbedcrypto.c ++++ b/src/libmbedcrypto.c +@@ -82,25 +82,46 @@ SHACTX sha1_init(void) + return ctx; + } + +-void sha1_update(SHACTX c, const void *data, unsigned long len) ++void ++sha1_ctx_free(SHACTX c) + { +- mbedtls_md_update(c, data, len); ++ mbedtls_md_free(c); ++ SAFE_FREE(c); + } + +-void sha1_final(unsigned char *md, SHACTX c) ++int sha1_update(SHACTX c, const void *data, unsigned long len) + { +- mbedtls_md_finish(c, md); +- mbedtls_md_free(c); +- SAFE_FREE(c); ++ int rc = mbedtls_md_update(c, data, len); ++ if (rc != 0) { ++ return SSH_ERROR; ++ } ++ return SSH_OK; + } + +-void sha1(const unsigned char *digest, int len, unsigned char *hash) ++int sha1_final(unsigned char *md, SHACTX c) ++{ ++ int rc = mbedtls_md_finish(c, md); ++ sha1_ctx_free(c); ++ if (rc != 0) { ++ return SSH_ERROR; ++ } ++ return SSH_OK; ++} ++ ++int sha1(const unsigned char *digest, int len, unsigned char *hash) + { + const mbedtls_md_info_t *md_info = + mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); +- if (md_info != NULL) { +- mbedtls_md(md_info, digest, len, hash); ++ int rc; ++ ++ if (md_info == NULL) { ++ return SSH_ERROR; + } ++ rc = mbedtls_md(md_info, digest, len, hash); ++ if (rc != 0) { ++ return SSH_ERROR; ++ } ++ return SSH_OK; + } + + SHA256CTX sha256_init(void) +@@ -136,25 +157,46 @@ SHA256CTX sha256_init(void) + return ctx; + } + +-void sha256_update(SHA256CTX c, const void *data, unsigned long len) ++void ++sha256_ctx_free(SHA256CTX c) + { +- mbedtls_md_update(c, data, len); ++ mbedtls_md_free(c); ++ SAFE_FREE(c); + } + +-void sha256_final(unsigned char *md, SHA256CTX c) ++int sha256_update(SHA256CTX c, const void *data, unsigned long len) + { +- mbedtls_md_finish(c, md); +- mbedtls_md_free(c); +- SAFE_FREE(c); ++ int rc = mbedtls_md_update(c, data, len); ++ if (rc != 0) { ++ return SSH_ERROR; ++ } ++ return SSH_OK; ++} ++ ++int sha256_final(unsigned char *md, SHA256CTX c) ++{ ++ int rc = mbedtls_md_finish(c, md); ++ sha256_ctx_free(c); ++ if (rc != 0) { ++ return SSH_ERROR; ++ } ++ return SSH_OK; + } + +-void sha256(const unsigned char *digest, int len, unsigned char *hash) ++int sha256(const unsigned char *digest, int len, unsigned char *hash) + { + const mbedtls_md_info_t *md_info = + mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); +- if (md_info != NULL) { +- mbedtls_md(md_info, digest, len, hash); ++ int rc; ++ ++ if (md_info == NULL) { ++ return SSH_ERROR; ++ } ++ rc = mbedtls_md(md_info, digest, len, hash); ++ if (rc != 0) { ++ return SSH_ERROR; + } ++ return SSH_OK; + } + + SHA384CTX sha384_init(void) +@@ -190,25 +232,46 @@ SHA384CTX sha384_init(void) + return ctx; + } + +-void sha384_update(SHA384CTX c, const void *data, unsigned long len) ++void ++sha384_ctx_free(SHA384CTX c) + { +- mbedtls_md_update(c, data, len); ++ mbedtls_md_free(c); ++ SAFE_FREE(c); + } + +-void sha384_final(unsigned char *md, SHA384CTX c) ++int sha384_update(SHA384CTX c, const void *data, unsigned long len) + { +- mbedtls_md_finish(c, md); +- mbedtls_md_free(c); +- SAFE_FREE(c); ++ int rc = mbedtls_md_update(c, data, len); ++ if (rc != 0) { ++ return SSH_ERROR; ++ } ++ return SSH_OK; + } + +-void sha384(const unsigned char *digest, int len, unsigned char *hash) ++int sha384_final(unsigned char *md, SHA384CTX c) ++{ ++ int rc = mbedtls_md_finish(c, md); ++ sha384_ctx_free(c); ++ if (rc != 0) { ++ return SSH_ERROR; ++ } ++ return SSH_OK; ++} ++ ++int sha384(const unsigned char *digest, int len, unsigned char *hash) + { + const mbedtls_md_info_t *md_info = + mbedtls_md_info_from_type(MBEDTLS_MD_SHA384); +- if (md_info != NULL) { +- mbedtls_md(md_info, digest, len, hash); ++ int rc; ++ ++ if (md_info == NULL) { ++ return SSH_ERROR; ++ } ++ rc = mbedtls_md(md_info, digest, len, hash); ++ if (rc != 0) { ++ return SSH_ERROR; + } ++ return SSH_OK; + } + + SHA512CTX sha512_init(void) +@@ -243,25 +306,46 @@ SHA512CTX sha512_init(void) + return ctx; + } + +-void sha512_update(SHA512CTX c, const void *data, unsigned long len) ++void ++sha512_ctx_free(SHA512CTX c) + { +- mbedtls_md_update(c, data, len); ++ mbedtls_md_free(c); ++ SAFE_FREE(c); + } + +-void sha512_final(unsigned char *md, SHA512CTX c) ++int sha512_update(SHA512CTX c, const void *data, unsigned long len) + { +- mbedtls_md_finish(c, md); +- mbedtls_md_free(c); +- SAFE_FREE(c); ++ int rc = mbedtls_md_update(c, data, len); ++ if (rc != 0) { ++ return SSH_ERROR; ++ } ++ return SSH_OK; + } + +-void sha512(const unsigned char *digest, int len, unsigned char *hash) ++int sha512_final(unsigned char *md, SHA512CTX c) ++{ ++ int rc = mbedtls_md_finish(c, md); ++ sha512_ctx_free(c); ++ if (rc != 0) { ++ return SSH_ERROR; ++ } ++ return SSH_OK; ++} ++ ++int sha512(const unsigned char *digest, int len, unsigned char *hash) + { + const mbedtls_md_info_t *md_info = + mbedtls_md_info_from_type(MBEDTLS_MD_SHA512); +- if (md_info != NULL) { +- mbedtls_md(md_info, digest, len, hash); ++ int rc; ++ ++ if (md_info == NULL) { ++ return SSH_ERROR; + } ++ rc = mbedtls_md(md_info, digest, len, hash); ++ if (rc != 0) { ++ return SSH_ERROR; ++ } ++ return SSH_OK; + } + + MD5CTX md5_init(void) +@@ -296,16 +380,30 @@ MD5CTX md5_init(void) + return ctx; + } + ++void ++md5_ctx_free(MD5CTX c) ++{ ++ mbedtls_md_free(c); ++ SAFE_FREE(c); ++} + +-void md5_update(MD5CTX c, const void *data, unsigned long len) { +- mbedtls_md_update(c, data, len); ++int md5_update(MD5CTX c, const void *data, unsigned long len) ++{ ++ int rc = mbedtls_md_update(c, data, len); ++ if (rc != 0) { ++ return SSH_ERROR; ++ } ++ return SSH_OK; + } + +-void md5_final(unsigned char *md, MD5CTX c) ++int md5_final(unsigned char *md, MD5CTX c) + { +- mbedtls_md_finish(c, md); +- mbedtls_md_free(c); +- SAFE_FREE(c); ++ int rc = mbedtls_md_finish(c, md); ++ md5_ctx_free(c); ++ if (rc != 0) { ++ return SSH_ERROR; ++ } ++ return SSH_OK; + } + + int ssh_kdf(struct ssh_crypto_struct *crypto, +diff --git a/src/session.c b/src/session.c +index 0cf59e99..349373aa 100644 +--- a/src/session.c ++++ b/src/session.c +@@ -1001,7 +1001,18 @@ int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash) + *hash = NULL; + if (session->current_crypto == NULL || + session->current_crypto->server_pubkey == NULL) { +- ssh_set_error(session,SSH_FATAL,"No current cryptographic context"); ++ ssh_set_error(session, SSH_FATAL, "No current cryptographic context"); ++ return SSH_ERROR; ++ } ++ ++ rc = ssh_get_server_publickey(session, &pubkey); ++ if (rc != SSH_OK) { ++ return SSH_ERROR; ++ } ++ ++ rc = ssh_pki_export_pubkey_blob(pubkey, &pubkey_blob); ++ ssh_key_free(pubkey); ++ if (rc != SSH_OK) { + return SSH_ERROR; + } + +@@ -1016,25 +1027,21 @@ int ssh_get_pubkey_hash(ssh_session session, unsigned char **hash) + return SSH_ERROR; + } + +- rc = ssh_get_server_publickey(session, &pubkey); ++ rc = md5_update(ctx, ++ ssh_string_data(pubkey_blob), ++ ssh_string_len(pubkey_blob)); + if (rc != SSH_OK) { +- md5_final(h, ctx); ++ md5_ctx_free(ctx); + SAFE_FREE(h); +- return SSH_ERROR; ++ return rc; + } +- +- rc = ssh_pki_export_pubkey_blob(pubkey, &pubkey_blob); +- ssh_key_free(pubkey); ++ SSH_STRING_FREE(pubkey_blob); ++ rc = md5_final(h, ctx); + if (rc != SSH_OK) { +- md5_final(h, ctx); + SAFE_FREE(h); +- return SSH_ERROR; ++ return rc; + } + +- md5_update(ctx, ssh_string_data(pubkey_blob), ssh_string_len(pubkey_blob)); +- SSH_STRING_FREE(pubkey_blob); +- md5_final(h, ctx); +- + *hash = h; + + return MD5_DIGEST_LEN; +@@ -1153,8 +1160,17 @@ int ssh_get_publickey_hash(const ssh_key key, + goto out; + } + +- sha1_update(ctx, ssh_string_data(blob), ssh_string_len(blob)); +- sha1_final(h, ctx); ++ rc = sha1_update(ctx, ssh_string_data(blob), ssh_string_len(blob)); ++ if (rc != SSH_OK) { ++ free(h); ++ sha1_ctx_free(ctx); ++ goto out; ++ } ++ rc = sha1_final(h, ctx); ++ if (rc != SSH_OK) { ++ free(h); ++ goto out; ++ } + + *hlen = SHA_DIGEST_LEN; + } +@@ -1176,8 +1192,17 @@ int ssh_get_publickey_hash(const ssh_key key, + goto out; + } + +- sha256_update(ctx, ssh_string_data(blob), ssh_string_len(blob)); +- sha256_final(h, ctx); ++ rc = sha256_update(ctx, ssh_string_data(blob), ssh_string_len(blob)); ++ if (rc != SSH_OK) { ++ free(h); ++ sha256_ctx_free(ctx); ++ goto out; ++ } ++ rc = sha256_final(h, ctx); ++ if (rc != SSH_OK) { ++ free(h); ++ goto out; ++ } + + *hlen = SHA256_DIGEST_LEN; + } +@@ -1207,8 +1232,17 @@ int ssh_get_publickey_hash(const ssh_key key, + goto out; + } + +- md5_update(ctx, ssh_string_data(blob), ssh_string_len(blob)); +- md5_final(h, ctx); ++ rc = md5_update(ctx, ssh_string_data(blob), ssh_string_len(blob)); ++ if (rc != SSH_OK) { ++ free(h); ++ md5_ctx_free(ctx); ++ goto out; ++ } ++ rc = md5_final(h, ctx); ++ if (rc != SSH_OK) { ++ free(h); ++ goto out; ++ } + + *hlen = MD5_DIGEST_LEN; + } +-- +2.41.0 + + +From 9276027c687723886e8277b77061464303845831 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +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 +Reviewed-by: Andreas Schneider +--- + 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.41.0 + + +From aef4a470003bdede61fa17c22418d25ccedaa983 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Fri, 15 Dec 2023 15:39:12 +0100 +Subject: [PATCH 5/5] CVE-2023-6918: tests: Code coverage for + ssh_get_pubkey_hash() + +Signed-off-by: Jakub Jelen +Reviewed-by: Andreas Schneider +--- + tests/client/torture_session.c | 35 ++++++++++++++++++++++++++++++++++ + 1 file changed, 35 insertions(+) + +diff --git a/tests/client/torture_session.c b/tests/client/torture_session.c +index b5ed7a62..abe458d0 100644 +--- a/tests/client/torture_session.c ++++ b/tests/client/torture_session.c +@@ -118,12 +118,47 @@ static void torture_channel_read_error(void **state) { + ssh_channel_free(channel); + } + ++static void torture_pubkey_hash(void **state) ++{ ++ struct torture_state *s = *state; ++ ssh_session session = s->ssh.session; ++ char *hash = NULL; ++ char *hexa = NULL; ++ int rc = 0; ++ ++ /* bad arguments */ ++ rc = ssh_get_pubkey_hash(session, NULL); ++ assert_int_equal(rc, SSH_ERROR); ++ ++ rc = ssh_get_pubkey_hash(NULL, (unsigned char **)&hash); ++ assert_int_equal(rc, SSH_ERROR); ++ ++ /* deprecated, but should be covered by tests! */ ++ rc = ssh_get_pubkey_hash(session, (unsigned char **)&hash); ++ if (ssh_fips_mode()) { ++ /* When in FIPS mode, expect the call to fail */ ++ assert_int_equal(rc, SSH_ERROR); ++ } else { ++ assert_int_equal(rc, MD5_DIGEST_LEN); ++ ++ hexa = ssh_get_hexa((unsigned char *)hash, rc); ++ SSH_STRING_FREE_CHAR(hash); ++ assert_string_equal(hexa, ++ "ee:80:7f:61:f9:d5:be:f1:96:86:cc:96:7a:db:7a:7b"); ++ ++ SSH_STRING_FREE_CHAR(hexa); ++ } ++} ++ + int torture_run_tests(void) { + int rc; + struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(torture_channel_read_error, + session_setup, + session_teardown), ++ cmocka_unit_test_setup_teardown(torture_pubkey_hash, ++ session_setup, ++ session_teardown), + }; + + ssh_init(); +-- +2.41.0 + diff --git a/SOURCES/auth_bypass.patch b/SOURCES/auth_bypass.patch new file mode 100644 index 0000000..8b91601 --- /dev/null +++ b/SOURCES/auth_bypass.patch @@ -0,0 +1,86 @@ +diff --color -ru ../libssh-0.9.6/src/pki_crypto.c ./src/pki_crypto.c +--- ../libssh-0.9.6/src/pki_crypto.c 2023-04-27 12:59:08.463259052 +0200 ++++ ./src/pki_crypto.c 2023-04-27 13:05:24.020610873 +0200 +@@ -2291,8 +2291,12 @@ + 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 +@@ -2307,8 +2311,8 @@ + } + + /* 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; + } + +@@ -2351,8 +2355,8 @@ + } + + /* 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)); +@@ -2360,35 +2364,31 @@ + } + + #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); +- } +- if (pkey != NULL) { +- EVP_PKEY_free(pkey); +- } ++ EVP_MD_CTX_free(ctx); ++ EVP_PKEY_free(pkey); + return rc; + } + diff --git a/SOURCES/covscan23.patch b/SOURCES/covscan23.patch new file mode 100644 index 0000000..a79658f --- /dev/null +++ b/SOURCES/covscan23.patch @@ -0,0 +1,228 @@ +diff --color -ru ../libssh-0.9.6/src/buffer.c ./src/buffer.c +--- ../libssh-0.9.6/src/buffer.c 2023-05-03 11:53:48.710217753 +0200 ++++ ./src/buffer.c 2023-05-03 11:58:21.995200990 +0200 +@@ -747,7 +747,8 @@ + */ + int ssh_buffer_validate_length(struct ssh_buffer_struct *buffer, size_t len) + { +- if (buffer->pos + len < len || buffer->pos + len > buffer->used) { ++ if (buffer == NULL || buffer->pos + len < len || ++ buffer->pos + len > buffer->used) { + return SSH_ERROR; + } + +diff --color -ru ../libssh-0.9.6/src/gssapi.c ./src/gssapi.c +--- ../libssh-0.9.6/src/gssapi.c 2023-05-03 11:53:48.732217993 +0200 ++++ ./src/gssapi.c 2023-05-03 11:58:21.976200782 +0200 +@@ -437,11 +437,18 @@ + hexa = ssh_get_hexa(output_token.value, output_token.length); + SSH_LOG(SSH_LOG_PACKET, "GSSAPI: sending token %s",hexa); + SAFE_FREE(hexa); +- ssh_buffer_pack(session->out_buffer, +- "bdP", +- SSH2_MSG_USERAUTH_GSSAPI_TOKEN, +- output_token.length, +- (size_t)output_token.length, output_token.value); ++ rc = ssh_buffer_pack(session->out_buffer, ++ "bdP", ++ SSH2_MSG_USERAUTH_GSSAPI_TOKEN, ++ output_token.length, ++ (size_t)output_token.length, output_token.value); ++ if (rc != SSH_OK) { ++ ssh_set_error_oom(session); ++ ssh_auth_reply_default(session, 0); ++ ssh_gssapi_free(session); ++ session->gssapi = NULL; ++ return SSH_PACKET_USED; ++ } + ssh_packet_send(session); + } + +@@ -846,6 +853,7 @@ + } + + SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_response){ ++ int rc; + ssh_string oid_s; + gss_uint32 maj_stat, min_stat; + gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; +@@ -897,11 +905,15 @@ + hexa = ssh_get_hexa(output_token.value, output_token.length); + SSH_LOG(SSH_LOG_PACKET, "GSSAPI: sending token %s", hexa); + SAFE_FREE(hexa); +- ssh_buffer_pack(session->out_buffer, +- "bdP", +- SSH2_MSG_USERAUTH_GSSAPI_TOKEN, +- output_token.length, +- (size_t)output_token.length, output_token.value); ++ rc = ssh_buffer_pack(session->out_buffer, ++ "bdP", ++ SSH2_MSG_USERAUTH_GSSAPI_TOKEN, ++ output_token.length, ++ (size_t)output_token.length, output_token.value); ++ if (rc != SSH_OK) { ++ ssh_set_error_oom(session); ++ goto error; ++ } + ssh_packet_send(session); + session->auth.state = SSH_AUTH_STATE_GSSAPI_TOKEN; + } +@@ -963,6 +975,7 @@ + } + + SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_client){ ++ int rc; + ssh_string token; + char *hexa; + OM_uint32 maj_stat, min_stat; +@@ -1015,11 +1028,15 @@ + hexa = ssh_get_hexa(output_token.value, output_token.length); + SSH_LOG(SSH_LOG_PACKET, "GSSAPI: sending token %s",hexa); + SAFE_FREE(hexa); +- ssh_buffer_pack(session->out_buffer, +- "bdP", +- SSH2_MSG_USERAUTH_GSSAPI_TOKEN, +- output_token.length, +- (size_t)output_token.length, output_token.value); ++ rc = ssh_buffer_pack(session->out_buffer, ++ "bdP", ++ SSH2_MSG_USERAUTH_GSSAPI_TOKEN, ++ output_token.length, ++ (size_t)output_token.length, output_token.value); ++ if (rc != SSH_OK) { ++ ssh_set_error_oom(session); ++ goto error; ++ } + ssh_packet_send(session); + } + +diff --color -ru ../libssh-0.9.6/src/options.c ./src/options.c +--- ../libssh-0.9.6/src/options.c 2021-08-26 14:27:42.000000000 +0200 ++++ ./src/options.c 2023-05-03 11:58:22.000201044 +0200 +@@ -547,7 +547,9 @@ + } + i = strtol(q, &p, 10); + if (q == p) { ++ SSH_LOG(SSH_LOG_DEBUG, "No port number was parsed"); + SAFE_FREE(q); ++ return -1; + } + SAFE_FREE(q); + if (i <= 0) { +@@ -743,7 +745,9 @@ + } + i = strtol(q, &p, 10); + if (q == p) { ++ SSH_LOG(SSH_LOG_DEBUG, "No log verbositiy was parsed"); + SAFE_FREE(q); ++ return -1; + } + SAFE_FREE(q); + if (i < 0) { +@@ -1818,7 +1822,9 @@ + } + i = strtol(q, &p, 10); + if (q == p) { +- SAFE_FREE(q); ++ SSH_LOG(SSH_LOG_DEBUG, "No bind port was parsed"); ++ SAFE_FREE(q); ++ return -1; + } + SAFE_FREE(q); + +@@ -1845,7 +1851,9 @@ + } + i = strtol(q, &p, 10); + if (q == p) { +- SAFE_FREE(q); ++ SSH_LOG(SSH_LOG_DEBUG, "No log verbositiy was parsed"); ++ SAFE_FREE(q); ++ return -1; + } + SAFE_FREE(q); + +diff --color -ru ../libssh-0.9.6/src/pki_container_openssh.c ./src/pki_container_openssh.c +--- ../libssh-0.9.6/src/pki_container_openssh.c 2023-05-03 11:53:48.713217785 +0200 ++++ ./src/pki_container_openssh.c 2023-05-03 11:58:21.976200782 +0200 +@@ -630,7 +630,11 @@ + goto error; + } + +- ssh_buffer_pack(kdf_buf, "Sd", salt, rounds); ++ rc = ssh_buffer_pack(kdf_buf, "Sd", salt, rounds); ++ if (rc != SSH_OK) { ++ SSH_BUFFER_FREE(kdf_buf); ++ goto error; ++ } + kdf_options = ssh_string_new(ssh_buffer_get_len(kdf_buf)); + if (kdf_options == NULL){ + SSH_BUFFER_FREE(kdf_buf); +diff --color -ru ../libssh-0.9.6/tests/unittests/torture_options.c ./tests/unittests/torture_options.c +--- ../libssh-0.9.6/tests/unittests/torture_options.c 2021-08-26 14:27:42.000000000 +0200 ++++ ./tests/unittests/torture_options.c 2023-05-03 11:59:21.726853027 +0200 +@@ -311,6 +311,7 @@ + + rc = ssh_options_set(session, SSH_OPTIONS_PORT_STR, "five"); + assert_true(rc == -1); ++ assert_int_not_equal(session->opts.port, 0); + + rc = ssh_options_set(session, SSH_OPTIONS_PORT, NULL); + assert_true(rc == -1); +@@ -853,6 +854,26 @@ + ssh_free(new); + } + ++static void torture_options_set_verbosity (void **state) ++{ ++ ssh_session session = *state; ++ int rc, new_level; ++ ++ rc = ssh_options_set(session, ++ SSH_OPTIONS_LOG_VERBOSITY_STR, ++ "3"); ++ assert_int_equal(rc, SSH_OK); ++ new_level = ssh_get_log_level(); ++ assert_int_equal(new_level, SSH_LOG_PACKET); ++ ++ rc = ssh_options_set(session, ++ SSH_OPTIONS_LOG_VERBOSITY_STR, ++ "datsun"); ++ assert_int_equal(rc, -1); ++ new_level = ssh_get_log_level(); ++ assert_int_not_equal(new_level, 0); ++} ++ + #ifdef WITH_SERVER + const char template[] = "temp_dir_XXXXXX"; + +@@ -1107,6 +1128,10 @@ + rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BINDPORT_STR, "23"); + assert_int_equal(rc, 0); + assert_int_equal(bind->bindport, 23); ++ ++ rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BINDPORT_STR, "twentythree"); ++ assert_int_equal(rc, -1); ++ assert_int_not_equal(bind->bindport, 0); + } + + static void torture_bind_options_log_verbosity(void **state) +@@ -1156,6 +1181,11 @@ + new_level = ssh_get_log_level(); + assert_int_equal(new_level, SSH_LOG_PACKET); + ++ rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_LOG_VERBOSITY_STR, "verbosity"); ++ assert_int_equal(rc, -1); ++ new_level = ssh_get_log_level(); ++ assert_int_not_equal(new_level, 0); ++ + rc = ssh_set_log_level(previous_level); + assert_int_equal(rc, SSH_OK); + } +@@ -1643,6 +1673,7 @@ + cmocka_unit_test_setup_teardown(torture_options_config_host, setup, teardown), + cmocka_unit_test_setup_teardown(torture_options_config_match, + setup, teardown), ++ cmocka_unit_test_setup_teardown(torture_options_set_verbosity, setup, teardown), + }; + + #ifdef WITH_SERVER diff --git a/SOURCES/fix_tests.patch b/SOURCES/fix_tests.patch new file mode 100644 index 0000000..084fb49 --- /dev/null +++ b/SOURCES/fix_tests.patch @@ -0,0 +1,668 @@ +diff --color -ru ../libssh-0.9.6/examples/sshnetcat.c ./examples/sshnetcat.c +--- ../libssh-0.9.6/examples/sshnetcat.c 2021-08-26 14:27:42.000000000 +0200 ++++ ./examples/sshnetcat.c 2023-05-02 10:36:00.793381735 +0200 +@@ -233,9 +233,10 @@ + } + + void cleanup_pcap(void); +-void cleanup_pcap(){ ++void cleanup_pcap(void) ++{ + ssh_pcap_file_free(pcap); +- pcap=NULL; ++ pcap = NULL; + } + #endif + +diff --color -ru ../libssh-0.9.6/src/init.c ./src/init.c +--- ../libssh-0.9.6/src/init.c 2021-03-15 08:11:33.000000000 +0100 ++++ ./src/init.c 2023-05-02 10:36:00.793381735 +0200 +@@ -269,7 +269,7 @@ + * + * @see ssh_init() + */ +-bool is_ssh_initialized() { ++bool is_ssh_initialized(void) { + + bool is_initialized = false; + +diff --color -ru ../libssh-0.9.6/tests/client/torture_auth.c ./tests/client/torture_auth.c +--- ../libssh-0.9.6/tests/client/torture_auth.c 2021-08-26 14:27:42.000000000 +0200 ++++ ./tests/client/torture_auth.c 2023-05-02 10:36:00.815381960 +0200 +@@ -200,7 +200,8 @@ + assert_non_null(ssh_agent_pidfile); + + /* kill agent pid */ +- torture_terminate_process(ssh_agent_pidfile); ++ rc = torture_terminate_process(ssh_agent_pidfile); ++ assert_return_code(rc, errno); + + unlink(ssh_agent_pidfile); + +@@ -551,6 +552,7 @@ + + static void torture_auth_agent_cert(void **state) + { ++#if OPENSSH_VERSION_MAJOR < 8 || (OPENSSH_VERSION_MAJOR == 8 && OPENSSH_VERSION_MINOR == 0) + struct torture_state *s = *state; + ssh_session session = s->ssh.session; + int rc; +@@ -570,6 +572,7 @@ + "ssh-rsa-cert-v01@openssh.com"); + assert_int_equal(rc, SSH_OK); + } ++#endif /* OPENSSH_VERSION_MAJOR < 8.1 */ + + /* Setup loads a different key, tests are exactly the same. */ + torture_auth_agent(state); +@@ -577,6 +580,7 @@ + + static void torture_auth_agent_cert_nonblocking(void **state) + { ++#if OPENSSH_VERSION_MAJOR < 8 || (OPENSSH_VERSION_MAJOR == 8 && OPENSSH_VERSION_MINOR == 0) + struct torture_state *s = *state; + ssh_session session = s->ssh.session; + int rc; +@@ -596,6 +600,7 @@ + "ssh-rsa-cert-v01@openssh.com"); + assert_int_equal(rc, SSH_OK); + } ++#endif /* OPENSSH_VERSION_MAJOR < 8.1 */ + + torture_auth_agent_nonblocking(state); + } +diff --color -ru ../libssh-0.9.6/tests/client/torture_rekey.c ./tests/client/torture_rekey.c +--- ../libssh-0.9.6/tests/client/torture_rekey.c 2023-04-28 17:26:41.472315318 +0200 ++++ ./tests/client/torture_rekey.c 2023-05-02 10:36:00.805381857 +0200 +@@ -38,6 +38,8 @@ + #include + #include + ++#define KEX_RETRY 32 ++ + static uint64_t bytes = 2048; /* 2KB (more than the authentication phase) */ + + static int sshd_setup(void **state) +@@ -190,10 +192,11 @@ + 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); + } +@@ -496,9 +499,15 @@ + * to make sure the rekey it completes with all different ciphers (paddings */ + memset(data, 0, sizeof(data)); + memset(data, 'A', 128); +- for (i = 0; i < 20; i++) { ++ for (i = 0; i < KEX_RETRY; i++) { + ssh_send_ignore(s->ssh.session, data); +- ssh_handle_packets(s->ssh.session, 50); ++ ssh_handle_packets(s->ssh.session, 100); ++ ++ c = s->ssh.session->current_crypto; ++ /* SHA256 len */ ++ if (c->digest_len != 32) { ++ break; ++ } + } + + /* The rekey limit was restored in the new crypto to the same value */ +@@ -568,9 +577,15 @@ + * to make sure the rekey it completes with all different ciphers (paddings */ + memset(data, 0, sizeof(data)); + memset(data, 'A', 128); +- for (i = 0; i < 25; i++) { ++ for (i = 0; i < KEX_RETRY; i++) { + ssh_send_ignore(s->ssh.session, data); +- ssh_handle_packets(s->ssh.session, 50); ++ ssh_handle_packets(s->ssh.session, 100); ++ ++ c = s->ssh.session->current_crypto; ++ /* SHA256 len */ ++ if (c->digest_len != 32) { ++ break; ++ } + } + + /* Check that the secret hash is different than initially */ +diff --color -ru ../libssh-0.9.6/tests/CMakeLists.txt ./tests/CMakeLists.txt +--- ../libssh-0.9.6/tests/CMakeLists.txt 2021-08-26 14:27:42.000000000 +0200 ++++ ./tests/CMakeLists.txt 2023-05-02 10:32:03.964511860 +0200 +@@ -153,6 +153,17 @@ + execute_process(COMMAND ${ID_EXECUTABLE} -u OUTPUT_VARIABLE LOCAL_UID OUTPUT_STRIP_TRAILING_WHITESPACE) + endif() + ++ find_program(TIMEOUT_EXECUTABLE ++ NAME ++ timeout ++ PATHS ++ /bin ++ /usr/bin ++ /usr/local/bin) ++ if (TIMEOUT_EXECUTABLE) ++ set(WITH_TIMEOUT "1") ++ endif() ++ + # chroot_wrapper + add_library(chroot_wrapper SHARED chroot_wrapper.c) + set(CHROOT_WRAPPER_LIBRARY ${libssh_BINARY_DIR}/lib/${CMAKE_SHARED_LIBRARY_PREFIX}chroot_wrapper${CMAKE_SHARED_LIBRARY_SUFFIX}) +diff --color -ru ../libssh-0.9.6/tests/pkd/pkd_keyutil.c ./tests/pkd/pkd_keyutil.c +--- ../libssh-0.9.6/tests/pkd/pkd_keyutil.c 2021-03-15 08:11:33.000000000 +0100 ++++ ./tests/pkd/pkd_keyutil.c 2023-05-02 10:36:00.793381735 +0200 +@@ -22,7 +22,7 @@ + #include "pkd_keyutil.h" + #include "pkd_util.h" + +-void setup_rsa_key() { ++void setup_rsa_key(void) { + int rc = 0; + if (access(LIBSSH_RSA_TESTKEY, F_OK) != 0) { + rc = system_checked(OPENSSH_KEYGEN " -t rsa -q -N \"\" -f " +@@ -31,7 +31,7 @@ + assert_int_equal(rc, 0); + } + +-void setup_ed25519_key() { ++void setup_ed25519_key(void) { + int rc = 0; + if (access(LIBSSH_ED25519_TESTKEY, F_OK) != 0) { + rc = system_checked(OPENSSH_KEYGEN " -t ed25519 -q -N \"\" -f " +@@ -41,7 +41,7 @@ + } + + #ifdef HAVE_DSA +-void setup_dsa_key() { ++void setup_dsa_key(void) { + int rc = 0; + if (access(LIBSSH_DSA_TESTKEY, F_OK) != 0) { + rc = system_checked(OPENSSH_KEYGEN " -t dsa -q -N \"\" -f " +@@ -51,7 +51,7 @@ + } + #endif + +-void setup_ecdsa_keys() { ++void setup_ecdsa_keys(void) { + int rc = 0; + + if (access(LIBSSH_ECDSA_256_TESTKEY, F_OK) != 0) { +@@ -71,27 +71,27 @@ + } + } + +-void cleanup_rsa_key() { ++void cleanup_rsa_key(void) { + cleanup_key(LIBSSH_RSA_TESTKEY); + } + +-void cleanup_ed25519_key() { ++void cleanup_ed25519_key(void) { + cleanup_key(LIBSSH_ED25519_TESTKEY); + } + + #ifdef HAVE_DSA +-void cleanup_dsa_key() { ++void cleanup_dsa_key(void) { + cleanup_key(LIBSSH_DSA_TESTKEY); + } + #endif + +-void cleanup_ecdsa_keys() { ++void cleanup_ecdsa_keys(void) { + cleanup_key(LIBSSH_ECDSA_256_TESTKEY); + cleanup_key(LIBSSH_ECDSA_384_TESTKEY); + cleanup_key(LIBSSH_ECDSA_521_TESTKEY); + } + +-void setup_openssh_client_keys() { ++void setup_openssh_client_keys(void) { + int rc = 0; + + if (access(OPENSSH_CA_TESTKEY, F_OK) != 0) { +@@ -184,7 +184,7 @@ + } + } + +-void cleanup_openssh_client_keys() { ++void cleanup_openssh_client_keys(void) { + cleanup_key(OPENSSH_CA_TESTKEY); + cleanup_key(OPENSSH_RSA_TESTKEY); + cleanup_file(OPENSSH_RSA_TESTKEY "-sha256-cert.pub"); +@@ -199,7 +199,7 @@ + } + } + +-void setup_dropbear_client_rsa_key() { ++void setup_dropbear_client_rsa_key(void) { + int rc = 0; + if (access(DROPBEAR_RSA_TESTKEY, F_OK) != 0) { + rc = system_checked(DROPBEAR_KEYGEN " -t rsa -f " +@@ -208,6 +208,6 @@ + assert_int_equal(rc, 0); + } + +-void cleanup_dropbear_client_rsa_key() { ++void cleanup_dropbear_client_rsa_key(void) { + unlink(DROPBEAR_RSA_TESTKEY); + } +diff --color -ru ../libssh-0.9.6/tests/server/torture_server_config.c ./tests/server/torture_server_config.c +--- ../libssh-0.9.6/tests/server/torture_server_config.c 2021-08-26 14:27:42.000000000 +0200 ++++ ./tests/server/torture_server_config.c 2023-05-02 10:36:00.815381960 +0200 +@@ -285,9 +285,7 @@ + assert_non_null(s); + + rc = torture_terminate_process(s->srv_pidfile); +- if (rc != 0) { +- fprintf(stderr, "XXXXXX Failed to terminate sshd\n"); +- } ++ assert_return_code(rc, errno); + + unlink(s->srv_pidfile); + +@@ -513,6 +511,12 @@ + /* Try each algorithm individually */ + j = 0; + while(tokens->tokens[j] != NULL) { ++ char *cmp = strstr(OPENSSH_CIPHERS, tokens->tokens[j]); ++ if (cmp == NULL) { ++ /* This cipher is not supported by the OpenSSH. Skip it */ ++ j++; ++ continue; ++ } + snprintf(config_content, + sizeof(config_content), + "HostKey %s\nCiphers %s\n", +diff --color -ru ../libssh-0.9.6/tests/tests_config.h.cmake ./tests/tests_config.h.cmake +--- ../libssh-0.9.6/tests/tests_config.h.cmake 2021-08-26 14:27:42.000000000 +0200 ++++ ./tests/tests_config.h.cmake 2023-05-02 10:32:03.964511860 +0200 +@@ -66,4 +66,6 @@ + + #cmakedefine NC_EXECUTABLE "${NC_EXECUTABLE}" + #cmakedefine SSHD_EXECUTABLE "${SSHD_EXECUTABLE}" +-#cmakedefine SSH_EXECUTABLE "${SSH_EXECUTABLE}" +\ No newline at end of file ++#cmakedefine SSH_EXECUTABLE "${SSH_EXECUTABLE}" ++#cmakedefine WITH_TIMEOUT ${WITH_TIMEOUT} ++#cmakedefine TIMEOUT_EXECUTABLE "${TIMEOUT_EXECUTABLE}" +diff --color -ru ../libssh-0.9.6/tests/torture.c ./tests/torture.c +--- ../libssh-0.9.6/tests/torture.c 2021-08-26 14:27:44.000000000 +0200 ++++ ./tests/torture.c 2023-05-02 10:36:00.815381960 +0200 +@@ -51,6 +51,7 @@ + #include "torture.h" + #include "torture_key.h" + #include "libssh/misc.h" ++#include "libssh/token.h" + + #define TORTURE_SSHD_SRV_IPV4 "127.0.0.10" + /* socket wrapper IPv6 prefix fd00::5357:5fxx */ +@@ -250,8 +251,12 @@ + + rc = kill(pid, 0); + if (rc != 0) { +- is_running = 0; +- break; ++ /* Process not found */ ++ if (errno == ESRCH) { ++ is_running = 0; ++ rc = 0; ++ break; ++ } + } + } + +@@ -260,7 +265,7 @@ + "WARNING: The process with pid %u is still running!\n", pid); + } + +- return 0; ++ return rc; + } + + ssh_session torture_ssh_session(struct torture_state *s, +@@ -611,6 +616,112 @@ + *state = s; + } + ++/** ++ * @brief Create a libssh server configuration file ++ * ++ * It is expected the socket directory to be already created before by calling ++ * torture_setup_socket_dir(). The created configuration file will be stored in ++ * the socket directory and the srv_config pointer in the state will be ++ * initialized. ++ * ++ * @param[in] state A pointer to a pointer to an initialized torture_state ++ * structure ++ */ ++void torture_setup_create_libssh_config(void **state) ++{ ++ struct torture_state *s = *state; ++ char ed25519_hostkey[1024] = {0}; ++#ifdef HAVE_DSA ++ char dsa_hostkey[1024]; ++#endif /* HAVE_DSA */ ++ char rsa_hostkey[1024]; ++ char ecdsa_hostkey[1024]; ++ char sshd_config[2048]; ++ char sshd_path[1024]; ++ const char *additional_config = NULL; ++ struct stat sb; ++ const char config_string[]= ++ "LogLevel DEBUG3\n" ++ "Port 22\n" ++ "ListenAddress 127.0.0.10\n" ++ "%s %s\n" ++ "%s %s\n" ++ "%s %s\n" ++#ifdef HAVE_DSA ++ "%s %s\n" ++#endif /* HAVE_DSA */ ++ "%s\n"; /* The space for test-specific options */ ++ bool written = false; ++ int rc; ++ ++ assert_non_null(s->socket_dir); ++ ++ snprintf(sshd_path, ++ sizeof(sshd_path), ++ "%s/sshd", ++ s->socket_dir); ++ ++ rc = lstat(sshd_path, &sb); ++ if (rc == 0 ) { /* The directory is already in place */ ++ written = true; ++ } ++ ++ if (!written) { ++ rc = mkdir(sshd_path, 0755); ++ assert_return_code(rc, errno); ++ } ++ ++ snprintf(ed25519_hostkey, ++ sizeof(ed25519_hostkey), ++ "%s/sshd/ssh_host_ed25519_key", ++ s->socket_dir); ++ ++ snprintf(rsa_hostkey, ++ sizeof(rsa_hostkey), ++ "%s/sshd/ssh_host_rsa_key", ++ s->socket_dir); ++ ++ snprintf(ecdsa_hostkey, ++ sizeof(ecdsa_hostkey), ++ "%s/sshd/ssh_host_ecdsa_key", ++ s->socket_dir); ++ ++#ifdef HAVE_DSA ++ snprintf(dsa_hostkey, ++ sizeof(dsa_hostkey), ++ "%s/sshd/ssh_host_dsa_key", ++ s->socket_dir); ++#endif /* HAVE_DSA */ ++ ++ if (!written) { ++ torture_write_file(ed25519_hostkey, ++ torture_get_openssh_testkey(SSH_KEYTYPE_ED25519, 0)); ++ torture_write_file(rsa_hostkey, ++ torture_get_testkey(SSH_KEYTYPE_RSA, 0)); ++ torture_write_file(ecdsa_hostkey, ++ torture_get_testkey(SSH_KEYTYPE_ECDSA_P521, 0)); ++#ifdef HAVE_DSA ++ torture_write_file(dsa_hostkey, ++ torture_get_testkey(SSH_KEYTYPE_DSS, 0)); ++#endif /* HAVE_DSA */ ++ } ++ ++ additional_config = (s->srv_additional_config != NULL ? ++ s->srv_additional_config : ""); ++ ++ snprintf(sshd_config, sizeof(sshd_config), ++ config_string, ++ "HostKey", ed25519_hostkey, ++ "HostKey", rsa_hostkey, ++ "HostKey", ecdsa_hostkey, ++#ifdef HAVE_DSA ++ "HostKey", dsa_hostkey, ++#endif /* HAVE_DSA */ ++ additional_config); ++ ++ torture_write_file(s->srv_config, sshd_config); ++} ++ + static void torture_setup_create_sshd_config(void **state, bool pam) + { + struct torture_state *s = *state; +@@ -856,21 +967,140 @@ + return 1; + } + +-void torture_setup_sshd_server(void **state, bool pam) ++/** ++ * @brief Run a libssh based server under timeout. ++ * ++ * It is expected that the socket directory and libssh configuration file were ++ * already created before by calling torture_setup_socket_dir() and ++ * torture_setup_create_libssh_config() (or alternatively setup the state with ++ * the correct values). ++ * ++ * @param[in] state The content of the address pointed by this variable must be ++ * a pointer to an initialized instance of torture_state ++ * structure; it can be obtained by calling ++ * torture_setup_socket_dir() and ++ * torture_setup_create_libssh_config(). ++ * @param[in] server_path The path to the server executable. ++ * ++ * @note This function will use the state->srv_additional_config field as ++ * additional command line option used when starting the server instead of extra ++ * configuration file options. ++ * */ ++void torture_setup_libssh_server(void **state, const char *server_path) + { + struct torture_state *s; +- char sshd_start_cmd[1024]; ++ char start_cmd[1024]; ++ char timeout_cmd[512]; ++ char env[1024]; ++ char extra_options[1024]; + int rc; ++ char *ld_preload = NULL; ++ const char *force_fips = NULL; + +- torture_setup_socket_dir(state); +- torture_setup_create_sshd_config(state, pam); ++ struct ssh_tokens_st *env_tokens; ++ struct ssh_tokens_st *arg_tokens; ++ ++ pid_t pid; ++ ssize_t printed; ++ ++ s = *state; ++ ++ /* Get all the wrapper libraries to be pre-loaded */ ++ ld_preload = getenv("LD_PRELOAD"); ++ ++ if (s->srv_additional_config != NULL) { ++ printed = snprintf(extra_options, sizeof(extra_options), " %s ", ++ s->srv_additional_config); ++ if (printed < 0) { ++ fail_msg("Failed to print additional config!"); ++ } ++ } else { ++ printed = snprintf(extra_options, sizeof(extra_options), " "); ++ if (printed < 0) { ++ fail_msg("Failed to print empty additional config!"); ++ } ++ } ++ ++ if (ssh_fips_mode()) { ++ force_fips = "OPENSSL_FORCE_FIPS_MODE=1 "; ++ } else { ++ force_fips = ""; ++ } ++ ++ /* Write the environment setting */ ++ printed = snprintf(env, sizeof(env), ++ "SOCKET_WRAPPER_DIR=%s " ++ "SOCKET_WRAPPER_DEFAULT_IFACE=10 " ++ "LD_PRELOAD=%s " ++ "%s", ++ s->socket_dir, ld_preload, force_fips); ++ if (printed < 0) { ++ fail_msg("Failed to print env!"); ++ } ++ ++#ifdef WITH_TIMEOUT ++ snprintf(timeout_cmd, sizeof(timeout_cmd), ++ "%s %s ", TIMEOUT_EXECUTABLE, "5m"); ++#else ++ timeout_cmd[0] = '\0'; ++#endif ++ ++ /* Write the start command */ ++ printed = snprintf(start_cmd, sizeof(start_cmd), ++ "%s" ++ "%s -f%s -v4 -p22 -i%s -C%s%s%s", ++ timeout_cmd, ++ server_path, s->pcap_file, s->srv_pidfile, ++ s->srv_config, extra_options, TORTURE_SSH_SERVER); ++ if (printed < 0) { ++ fail_msg("Failed to print start command!"); ++ } ++ ++ pid = fork(); ++ switch(pid) { ++ case 0: ++ env_tokens = ssh_tokenize(env, ' '); ++ if (env_tokens == NULL || env_tokens->tokens == NULL) { ++ fail_msg("Failed to tokenize env!"); ++ } ++ ++ arg_tokens = ssh_tokenize(start_cmd, ' '); ++ if (arg_tokens == NULL || arg_tokens->tokens == NULL) { ++ ssh_tokens_free(env_tokens); ++ fail_msg("Failed to tokenize args!"); ++ } ++ ++ rc = execve(arg_tokens->tokens[0], (char **)arg_tokens->tokens, ++ (char **)env_tokens->tokens); ++ ++ /* execve returns only in case of error */ ++ ssh_tokens_free(env_tokens); ++ ssh_tokens_free(arg_tokens); ++ fail_msg("Error in execve: %s", strerror(errno)); ++ case -1: ++ fail_msg("Failed to fork!"); ++ default: ++ /* The parent continues the execution of the tests */ ++ setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "21", 1); ++ unsetenv("PAM_WRAPPER"); ++ ++ /* Wait until the server is ready to accept connections */ ++ rc = torture_wait_for_daemon(15); ++ assert_int_equal(rc, 0); ++ break; ++ } ++} ++ ++static int torture_start_sshd_server(void **state) ++{ ++ struct torture_state *s = *state; ++ char sshd_start_cmd[1024]; ++ int rc; + + /* Set the default interface for the server */ + setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "10", 1); + setenv("PAM_WRAPPER", "1", 1); + +- s = *state; +- + snprintf(sshd_start_cmd, sizeof(sshd_start_cmd), + SSHD_EXECUTABLE " -r -f %s -E %s/sshd/daemon.log 2> %s/sshd/cwrap.log", + s->srv_config, s->socket_dir, s->socket_dir); +@@ -882,7 +1112,20 @@ + unsetenv("PAM_WRAPPER"); + + /* Wait until the sshd is ready to accept connections */ +- rc = torture_wait_for_daemon(5); ++ rc = torture_wait_for_daemon(15); ++ assert_int_equal(rc, 0); ++ ++ return SSH_OK; ++} ++ ++void torture_setup_sshd_server(void **state, bool pam) ++{ ++ int rc; ++ ++ torture_setup_socket_dir(state); ++ torture_setup_create_sshd_config(state, pam); ++ ++ rc = torture_start_sshd_server(state); + assert_int_equal(rc, 0); + } + +@@ -922,29 +1165,12 @@ + torture_reload_sshd_server(void **state) + { + struct torture_state *s = *state; +- pid_t pid; + int rc; + +- /* read the pidfile */ +- pid = torture_read_pidfile(s->srv_pidfile); +- assert_int_not_equal(pid, -1); +- +- kill(pid, SIGHUP); +- +- /* 10 ms */ +- usleep(10 * 1000); +- +- rc = kill(pid, 0); +- if (rc != 0) { +- fprintf(stderr, +- "ERROR: SSHD process %u died during reload!\n", pid); +- return SSH_ERROR; +- } ++ rc = torture_terminate_process(s->srv_pidfile); ++ assert_return_code(rc, errno); + +- /* Wait until the sshd is ready to accept connections */ +- rc = torture_wait_for_daemon(5); +- assert_int_equal(rc, 0); +- return SSH_OK; ++ return torture_start_sshd_server(state); + } + + /* @brief: Updates SSHD server configuration with more options and +@@ -980,9 +1206,7 @@ + int rc; + + rc = torture_terminate_process(s->srv_pidfile); +- if (rc != 0) { +- fprintf(stderr, "XXXXXX Failed to terminate sshd\n"); +- } ++ assert_return_code(rc, errno); + + torture_teardown_socket_dir(state); + } +diff --color -ru ../libssh-0.9.6/tests/torture.h ./tests/torture.h +--- ../libssh-0.9.6/tests/torture.h 2021-08-26 14:27:44.000000000 +0200 ++++ ./tests/torture.h 2023-05-02 10:32:03.964511860 +0200 +@@ -132,6 +132,10 @@ + + void torture_reset_config(ssh_session session); + ++void torture_setup_create_libssh_config(void **state); ++ ++void torture_setup_libssh_server(void **state, const char *server_path); ++ + /* + * This function must be defined in every unit test file. + */ diff --git a/SOURCES/libssh-0.9.6.tar.xz.asc b/SOURCES/libssh-0.9.6.tar.xz.asc new file mode 100644 index 0000000..cbed27f --- /dev/null +++ b/SOURCES/libssh-0.9.6.tar.xz.asc @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNATURE----- + +iQIzBAABCgAdFiEEjf9T4Y8qvI2PPJIjfuD8TcwBTj0FAmEniOkACgkQfuD8TcwB +Tj0TKQ/9HiMAGSMHoQ+iPVLP06iTc6Cy7rNyON2nPDQwAz0V/dfvkrKAAEflfgYd +3pt3dbE/qgh2kgQLb9kpbCUmFoGuLgKz36RPOsggwuOsN+eD1n65q8W39sMOQid3 +bjUIOKRdYWC1suZ9fMAO1Ignl69Opd8dAq1Has9YzglaeQaV/lnYQOW4UG0xKHck +ZOp2qLfjmaQiBAI61eRyxqIYC0F67WKd0bo9D2csoocDVvHLq4syPdbMOfDTB+LL +KZSAZVW1R1JUVZMkp/P/HU11jNNy3wKoLafocnq8bXkPVrqhyuo+hDJV/OPUvFLa +VE/BzIRoMNG+1R+GJpwE7ut2DIHPxnZTThRkeVN5qP1+hbhgLJhW62I+HeAnD4s+ ++W7fwJovN28I+wqSjVEP8JguprVuoDAX5jVHbeZoMT7p8ATA4Nh3KCbYELEwTtFG +zsEIlBvoNXD3ce7xGXL3MPqfgKqrZQjRG/iOWvKwDV7WrqK1cFFyL7aeBfK2+dQq +1Ew7aYlTsH6Hap7XByeSsy4Z5ts3VXIoFix/h+Br5OTYKYgITM7bijNAQ6A2ZWQN +TxCv8X0sVyaGyXhxG6QhrEWZjFe496MneZkq9e6HKZyaSbzwFwMgOvrUUC7fa8e5 +o1Rvozah81U0nsikwTmDrm15RSK3mr2X34zPW2Ahzr1I5tGZzOk= +=cO0k +-----END PGP SIGNATURE----- diff --git a/SOURCES/libssh_client.config b/SOURCES/libssh_client.config new file mode 100644 index 0000000..1d293bd --- /dev/null +++ b/SOURCES/libssh_client.config @@ -0,0 +1,4 @@ +# Parse system-wide crypto configuration file +Include /etc/crypto-policies/back-ends/libssh.config +# Parse OpenSSH configuration file for consistency +Include /etc/ssh/ssh_config diff --git a/SOURCES/libssh_server.config b/SOURCES/libssh_server.config new file mode 100644 index 0000000..d3ef5c2 --- /dev/null +++ b/SOURCES/libssh_server.config @@ -0,0 +1,2 @@ +# Parse system-wide crypto configuration file +Include /etc/crypto-policies/back-ends/libssh.config diff --git a/SOURCES/loglevel.patch b/SOURCES/loglevel.patch new file mode 100644 index 0000000..fb2c5b5 --- /dev/null +++ b/SOURCES/loglevel.patch @@ -0,0 +1,3424 @@ +diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h +index 1664dfce..8ce364a3 100644 +--- a/include/libssh/libssh.h ++++ b/include/libssh/libssh.h +@@ -322,7 +322,7 @@ enum { + /** No logging at all + */ + SSH_LOG_NOLOG=0, +- /** Only warnings ++ /** Only fatal warnings + */ + SSH_LOG_WARNING, + /** High level protocol information +@@ -347,7 +347,7 @@ enum { + + /** No logging at all */ + #define SSH_LOG_NONE 0 +-/** Show only warnings */ ++/** Show only fatal warnings */ + #define SSH_LOG_WARN 1 + /** Get some information what's going on */ + #define SSH_LOG_INFO 2 +diff --git a/src/agent.c b/src/agent.c +index 62b0093e..02f628cd 100644 +--- a/src/agent.c ++++ b/src/agent.c +@@ -261,12 +261,12 @@ static int agent_talk(struct ssh_session_struct *session, + if (atomicio(session->agent, payload, 4, 0) == 4) { + if (atomicio(session->agent, ssh_buffer_get(request), len, 0) + != len) { +- SSH_LOG(SSH_LOG_WARN, "atomicio sending request failed: %s", ++ SSH_LOG(SSH_LOG_TRACE, "atomicio sending request failed: %s", + strerror(errno)); + return -1; + } + } else { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "atomicio sending request length failed: %s", + strerror(errno)); + return -1; +@@ -274,7 +274,7 @@ static int agent_talk(struct ssh_session_struct *session, + + /* wait for response, read the length of the response packet */ + if (atomicio(session->agent, payload, 4, 1) != 4) { +- SSH_LOG(SSH_LOG_WARN, "atomicio read response length failed: %s", ++ SSH_LOG(SSH_LOG_TRACE, "atomicio read response length failed: %s", + strerror(errno)); + return -1; + } +@@ -293,12 +293,12 @@ static int agent_talk(struct ssh_session_struct *session, + n = sizeof(payload); + } + if (atomicio(session->agent, payload, n, 1) != n) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_DEBUG, + "Error reading response from authentication socket."); + return -1; + } + if (ssh_buffer_add_data(reply, payload, n) < 0) { +- SSH_LOG(SSH_LOG_WARN, "Not enough space"); ++ SSH_LOG(SSH_LOG_DEBUG, "Not enough space"); + return -1; + } + len -= n; +@@ -353,7 +353,7 @@ uint32_t ssh_agent_get_ident_count(struct ssh_session_struct *session) + type = bswap_32(type); + #endif + +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Answer type: %d, expected answer: %d", + type, SSH2_AGENT_IDENTITIES_ANSWER); + +@@ -573,7 +573,7 @@ ssh_string ssh_agent_sign_data(ssh_session session, + #endif + + if (agent_failed(type)) { +- SSH_LOG(SSH_LOG_WARN, "Agent reports failure in signing the key"); ++ SSH_LOG(SSH_LOG_DEBUG, "Agent reports failure in signing the key"); + SSH_BUFFER_FREE(reply); + return NULL; + } else if (type != SSH2_AGENT_SIGN_RESPONSE) { +diff --git a/src/auth.c b/src/auth.c +index 3a5f0efb..59d7e8dd 100644 +--- a/src/auth.c ++++ b/src/auth.c +@@ -71,7 +71,7 @@ static int ssh_userauth_request_service(ssh_session session) { + + rc = ssh_service_request(session, "ssh-userauth"); + if ((rc != SSH_OK) && (rc != SSH_AGAIN)) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Failed to request \"ssh-userauth\" service"); + } + +@@ -199,7 +199,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_banner) { + + banner = ssh_buffer_get_ssh_string(packet); + if (banner == NULL) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Invalid SSH_USERAUTH_BANNER packet"); + } else { + SSH_LOG(SSH_LOG_DEBUG, +@@ -237,7 +237,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_failure) { + + if (partial) { + session->auth.state = SSH_AUTH_STATE_PARTIAL; +- SSH_LOG(SSH_LOG_INFO, ++ SSH_LOG(SSH_LOG_DEBUG, + "Partial success for '%s'. Authentication that can continue: %s", + current_method, + auth_methods); +@@ -247,7 +247,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_failure) { + "Access denied for '%s'. Authentication that can continue: %s", + current_method, + auth_methods); +- SSH_LOG(SSH_LOG_INFO, ++ SSH_LOG(SSH_LOG_DEBUG, + "%s", + ssh_get_error(session)); + +@@ -942,7 +942,7 @@ int ssh_userauth_agent(ssh_session session, + session->agent_state = NULL; + return rc; + } else if (rc != SSH_AUTH_SUCCESS) { +- SSH_LOG(SSH_LOG_INFO, ++ SSH_LOG(SSH_LOG_DEBUG, + "Server accepted public key but refused the signature"); + ssh_key_free(state->pubkey); + state->pubkey = ssh_agent_get_next_ident(session, &state->comment); +@@ -1102,7 +1102,7 @@ int ssh_userauth_publickey_auto(ssh_session session, + + rc = ssh_pki_export_pubkey_file(state->pubkey, pubkey_file); + if (rc == SSH_ERROR) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Could not write public key to file: %s", + pubkey_file); + } +@@ -1112,7 +1112,7 @@ int ssh_userauth_publickey_auto(ssh_session session, + if (state->state == SSH_AUTH_AUTO_STATE_KEY_IMPORTED) { + rc = ssh_userauth_try_publickey(session, username, state->pubkey); + if (rc == SSH_AUTH_ERROR) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Public key authentication error for %s", + privkey_file); + ssh_key_free(state->privkey); +@@ -1159,7 +1159,7 @@ int ssh_userauth_publickey_auto(ssh_session session, + /* If the file doesn't exist, continue */ + ssh_key_free(state->pubkey); + state->pubkey = NULL; +- SSH_LOG(SSH_LOG_INFO, ++ SSH_LOG(SSH_LOG_DEBUG, + "Private key %s doesn't exist.", + privkey_file); + state->it = state->it->next; +@@ -1174,7 +1174,7 @@ int ssh_userauth_publickey_auto(ssh_session session, + ssh_key_free(state->pubkey); + SAFE_FREE(session->auth.auto_state); + if (rc == SSH_AUTH_SUCCESS) { +- SSH_LOG(SSH_LOG_INFO, ++ SSH_LOG(SSH_LOG_DEBUG, + "Successfully authenticated using %s", + privkey_file); + } +@@ -1187,15 +1187,15 @@ int ssh_userauth_publickey_auto(ssh_session session, + ssh_key_free(state->privkey); + ssh_key_free(state->pubkey); + +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_DEBUG, + "The server accepted the public key but refused the signature"); + state->it = state->it->next; + state->state = SSH_AUTH_AUTO_STATE_PUBKEY; + /* continue */ + } + } +- SSH_LOG(SSH_LOG_INFO, +- "Tried every public key, none matched"); ++ SSH_LOG(SSH_LOG_WARN, ++ "Access denied: Tried every public key, none matched"); + SAFE_FREE(session->auth.auto_state); + return SSH_AUTH_DENIED; + } +@@ -1917,7 +1917,7 @@ int ssh_userauth_gssapi(ssh_session session) { + } else if (rc == SSH_ERROR) { + return SSH_AUTH_ERROR; + } +- SSH_LOG(SSH_LOG_PROTOCOL, "Authenticating with gssapi-with-mic"); ++ SSH_LOG(SSH_LOG_DEBUG, "Authenticating with gssapi-with-mic"); + + session->auth.current_method = SSH_AUTH_METHOD_GSSAPI_MIC; + session->auth.state = SSH_AUTH_STATE_NONE; +diff --git a/src/bind.c b/src/bind.c +index fa8df9ea..d65a789e 100644 +--- a/src/bind.c ++++ b/src/bind.c +@@ -294,7 +294,7 @@ int ssh_bind_listen(ssh_bind sshbind) { + + sshbind->bindfd = fd; + } else { +- SSH_LOG(SSH_LOG_INFO, "Using app-provided bind socket"); ++ SSH_LOG(SSH_LOG_DEBUG, "Using app-provided bind socket"); + } + return 0; + } +diff --git a/src/bind_config.c b/src/bind_config.c +index 14b84db0..56b66660 100644 +--- a/src/bind_config.c ++++ b/src/bind_config.c +@@ -343,7 +343,7 @@ ssh_bind_config_parse_line(ssh_bind bind, + if (p && (*parser_flags & PARSING)) { + rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HOSTKEY, p); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "line %d: Failed to set Hostkey value '%s'", + count, p); + } +@@ -354,7 +354,7 @@ ssh_bind_config_parse_line(ssh_bind bind, + if (p && (*parser_flags & PARSING)) { + rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BINDADDR, p); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "line %d: Failed to set ListenAddress value '%s'", + count, p); + } +@@ -365,7 +365,7 @@ ssh_bind_config_parse_line(ssh_bind bind, + if (p && (*parser_flags & PARSING)) { + rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BINDPORT_STR, p); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "line %d: Failed to set Port value '%s'", + count, p); + } +@@ -376,7 +376,7 @@ ssh_bind_config_parse_line(ssh_bind bind, + if (p && (*parser_flags & PARSING)) { + rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_CIPHERS_C_S, p); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "line %d: Failed to set C->S Ciphers value '%s'", + count, p); + break; +@@ -384,7 +384,7 @@ ssh_bind_config_parse_line(ssh_bind bind, + + rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_CIPHERS_S_C, p); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "line %d: Failed to set S->C Ciphers value '%s'", + count, p); + } +@@ -395,7 +395,7 @@ ssh_bind_config_parse_line(ssh_bind bind, + if (p && (*parser_flags & PARSING)) { + rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HMAC_C_S, p); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "line %d: Failed to set C->S MAC value '%s'", + count, p); + break; +@@ -403,7 +403,7 @@ ssh_bind_config_parse_line(ssh_bind bind, + + rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HMAC_S_C, p); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "line %d: Failed to set S->C MAC value '%s'", + count, p); + } +@@ -417,10 +417,10 @@ ssh_bind_config_parse_line(ssh_bind bind, + if (strcasecmp(p, "quiet") == 0) { + value = SSH_LOG_NONE; + } else if (strcasecmp(p, "fatal") == 0 || +- strcasecmp(p, "error")== 0 || +- strcasecmp(p, "info") == 0) { ++ strcasecmp(p, "error")== 0) { + value = SSH_LOG_WARN; +- } else if (strcasecmp(p, "verbose") == 0) { ++ } else if (strcasecmp(p, "verbose") == 0 || ++ strcasecmp(p, "info") == 0) { + value = SSH_LOG_INFO; + } else if (strcasecmp(p, "DEBUG") == 0 || + strcasecmp(p, "DEBUG1") == 0) { +@@ -433,7 +433,7 @@ ssh_bind_config_parse_line(ssh_bind bind, + rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_LOG_VERBOSITY, + &value); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "line %d: Failed to set LogLevel value '%s'", + count, p); + } +@@ -445,7 +445,7 @@ ssh_bind_config_parse_line(ssh_bind bind, + if (p && (*parser_flags & PARSING)) { + rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_KEY_EXCHANGE, p); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "line %d: Failed to set KexAlgorithms value '%s'", + count, p); + } +@@ -520,13 +520,13 @@ ssh_bind_config_parse_line(ssh_bind bind, + /* Skip one argument */ + p = ssh_config_get_str_tok(&s, NULL); + if (p == NULL || p[0] == '\0') { +- SSH_LOG(SSH_LOG_WARN, "line %d: Match keyword " ++ SSH_LOG(SSH_LOG_TRACE, "line %d: Match keyword " + "'%s' requires argument\n", count, p2); + SAFE_FREE(x); + return -1; + } + args++; +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_DEBUG, + "line %d: Unsupported Match keyword '%s', ignoring\n", + count, + p2); +@@ -556,7 +556,7 @@ ssh_bind_config_parse_line(ssh_bind bind, + rc = ssh_bind_options_set(bind, + SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES, p); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "line %d: Failed to set PubKeyAcceptedKeyTypes value '%s'", + count, p); + } +@@ -568,26 +568,26 @@ ssh_bind_config_parse_line(ssh_bind bind, + rc = ssh_bind_options_set(bind, + SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS, p); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "line %d: Failed to set HostkeyAlgorithms value '%s'", + count, p); + } + } + break; + case BIND_CFG_NOT_ALLOWED_IN_MATCH: +- SSH_LOG(SSH_LOG_WARN, "Option not allowed in Match block: %s, line: %d", ++ SSH_LOG(SSH_LOG_DEBUG, "Option not allowed in Match block: %s, line: %d", + keyword, count); + break; + case BIND_CFG_UNKNOWN: +- SSH_LOG(SSH_LOG_WARN, "Unknown option: %s, line: %d", ++ SSH_LOG(SSH_LOG_TRACE, "Unknown option: %s, line: %d", + keyword, count); + break; + case BIND_CFG_UNSUPPORTED: +- SSH_LOG(SSH_LOG_WARN, "Unsupported option: %s, line: %d", ++ SSH_LOG(SSH_LOG_TRACE, "Unsupported option: %s, line: %d", + keyword, count); + break; + case BIND_CFG_NA: +- SSH_LOG(SSH_LOG_WARN, "Option not applicable: %s, line: %d", ++ SSH_LOG(SSH_LOG_TRACE, "Option not applicable: %s, line: %d", + keyword, count); + break; + default: +diff --git a/src/buffer.c b/src/buffer.c +index ce12f491..685fd455 100644 +--- a/src/buffer.c ++++ b/src/buffer.c +@@ -878,7 +878,7 @@ static int ssh_buffer_pack_allocate_va(struct ssh_buffer_struct *buffer, + cstring = NULL; + break; + default: +- SSH_LOG(SSH_LOG_WARN, "Invalid buffer format %c", *p); ++ SSH_LOG(SSH_LOG_TRACE, "Invalid buffer format %c", *p); + rc = SSH_ERROR; + } + if (rc != SSH_OK){ +@@ -1007,7 +1007,7 @@ int ssh_buffer_pack_va(struct ssh_buffer_struct *buffer, + cstring = NULL; + break; + default: +- SSH_LOG(SSH_LOG_WARN, "Invalid buffer format %c", *p); ++ SSH_LOG(SSH_LOG_TRACE, "Invalid buffer format %c", *p); + rc = SSH_ERROR; + } + if (rc != SSH_OK){ +@@ -1238,7 +1238,7 @@ int ssh_buffer_unpack_va(struct ssh_buffer_struct *buffer, + rc = SSH_OK; + break; + default: +- SSH_LOG(SSH_LOG_WARN, "Invalid buffer format %c", *p); ++ SSH_LOG(SSH_LOG_TRACE, "Invalid buffer format %c", *p); + } + if (rc != SSH_OK) { + break; +diff --git a/src/channels.c b/src/channels.c +index 1041dbff..36e19598 100644 +--- a/src/channels.c ++++ b/src/channels.c +@@ -187,7 +187,7 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf){ + if (rc != SSH_OK) + goto error; + +- SSH_LOG(SSH_LOG_PROTOCOL, ++ SSH_LOG(SSH_LOG_DEBUG, + "Received a CHANNEL_OPEN_CONFIRMATION for channel %d:%d", + channel->local_channel, + channel->remote_channel); +@@ -200,7 +200,7 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf){ + goto error; + } + +- SSH_LOG(SSH_LOG_PROTOCOL, ++ SSH_LOG(SSH_LOG_DEBUG, + "Remote window : %"PRIu32", maxpacket : %"PRIu32, + (uint32_t) channel->remote_window, + (uint32_t) channel->remote_maxpacket); +@@ -264,11 +264,14 @@ error: + + static int ssh_channel_open_termination(void *c){ + ssh_channel channel = (ssh_channel) c; +- if (channel->state != SSH_CHANNEL_STATE_OPENING || +- channel->session->session_state == SSH_SESSION_STATE_ERROR) ++ if (channel->state != SSH_CHANNEL_STATE_OPENING) { + return 1; +- else ++ } else if (channel->session->session_state == SSH_SESSION_STATE_ERROR) { ++ SSH_LOG(SSH_LOG_WARN, "Error: %s", ssh_get_error(channel->session)); ++ return 1; ++ } else { + return 0; ++ } + } + + /** +@@ -320,7 +323,7 @@ channel_open(ssh_channel channel, + channel->local_maxpacket = maxpacket; + channel->local_window = window; + +- SSH_LOG(SSH_LOG_PROTOCOL, ++ SSH_LOG(SSH_LOG_DEBUG, + "Creating a channel %d with %d window and %d max packet", + channel->local_channel, window, maxpacket); + +@@ -410,7 +413,7 @@ static int grow_window(ssh_session session, + int rc; + + if(new_window <= channel->local_window){ +- SSH_LOG(SSH_LOG_PROTOCOL, ++ SSH_LOG(SSH_LOG_DEBUG, + "growing window (channel %d:%d) to %d bytes : not needed (%d bytes)", + channel->local_channel, channel->remote_channel, new_window, + channel->local_window); +@@ -434,7 +437,7 @@ static int grow_window(ssh_session session, + goto error; + } + +- SSH_LOG(SSH_LOG_PROTOCOL, ++ SSH_LOG(SSH_LOG_DEBUG, + "growing window (channel %d:%d) to %d bytes", + channel->local_channel, + channel->remote_channel, +@@ -504,7 +507,7 @@ SSH_PACKET_CALLBACK(channel_rcv_change_window) { + return SSH_PACKET_USED; + } + +- SSH_LOG(SSH_LOG_PROTOCOL, ++ SSH_LOG(SSH_LOG_DEBUG, + "Adding %d bytes to channel (%d:%d) (from %d bytes)", + bytes, + channel->local_channel, +@@ -808,7 +811,7 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { + } + if(strcmp(request,"keepalive@openssh.com")==0){ + SAFE_FREE(request); +- SSH_LOG(SSH_LOG_PROTOCOL,"Responding to Openssh's keepalive"); ++ SSH_LOG(SSH_LOG_DEBUG,"Responding to Openssh's keepalive"); + + rc = ssh_buffer_pack(session->out_buffer, + "bd", +@@ -824,7 +827,7 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { + + if (strcmp(request, "auth-agent-req@openssh.com") == 0) { + SAFE_FREE(request); +- SSH_LOG(SSH_LOG_PROTOCOL, "Received an auth-agent-req request"); ++ SSH_LOG(SSH_LOG_DEBUG, "Received an auth-agent-req request"); + ssh_callbacks_execute_list(channel->callbacks, + ssh_channel_callbacks, + channel_auth_agent_req_function, +@@ -840,7 +843,7 @@ SSH_PACKET_CALLBACK(channel_rcv_request) { + */ + ssh_message_handle_channel_request(session,channel,packet,request,status); + #else +- SSH_LOG(SSH_LOG_WARNING, "Unhandled channel request %s", request); ++ SSH_LOG(SSH_LOG_DEBUG, "Unhandled channel request %s", request); + #endif + + SAFE_FREE(request); +@@ -1403,7 +1406,7 @@ static int channel_write_common(ssh_channel channel, + } + + if (len > INT_MAX) { +- SSH_LOG(SSH_LOG_PROTOCOL, ++ SSH_LOG(SSH_LOG_TRACE, + "Length (%u) is bigger than INT_MAX", len); + return SSH_ERROR; + } +@@ -1440,14 +1443,14 @@ static int channel_write_common(ssh_channel channel, + } + while (len > 0) { + if (channel->remote_window < len) { +- SSH_LOG(SSH_LOG_PROTOCOL, ++ SSH_LOG(SSH_LOG_DEBUG, + "Remote window is %d bytes. going to write %d bytes", + channel->remote_window, + len); + /* What happens when the channel window is zero? */ + if(channel->remote_window == 0) { + /* nothing can be written */ +- SSH_LOG(SSH_LOG_PROTOCOL, ++ SSH_LOG(SSH_LOG_DEBUG, + "Wait for a growing window message..."); + rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_DEFAULT, + ssh_channel_waitwindow_termination,channel); +@@ -1698,11 +1701,14 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_failure){ + + static int ssh_channel_request_termination(void *c){ + ssh_channel channel = (ssh_channel)c; +- if(channel->request_state != SSH_CHANNEL_REQ_STATE_PENDING || +- channel->session->session_state == SSH_SESSION_STATE_ERROR) ++ if(channel->request_state != SSH_CHANNEL_REQ_STATE_PENDING) { + return 1; +- else ++ } else if (channel->session->session_state == SSH_SESSION_STATE_ERROR) { ++ SSH_LOG(SSH_LOG_WARN, "Error: %s", ssh_get_error(channel->session)); ++ return 1; ++ } else { + return 0; ++ } + } + + static int channel_request(ssh_channel channel, const char *request, +@@ -1767,7 +1773,7 @@ pending: + rc=SSH_ERROR; + break; + case SSH_CHANNEL_REQ_STATE_ACCEPTED: +- SSH_LOG(SSH_LOG_PROTOCOL, ++ SSH_LOG(SSH_LOG_DEBUG, + "Channel request %s success",request); + rc=SSH_OK; + break; +@@ -2237,11 +2243,14 @@ SSH_PACKET_CALLBACK(ssh_request_denied){ + + static int ssh_global_request_termination(void *s){ + ssh_session session = (ssh_session) s; +- if (session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING || +- session->session_state == SSH_SESSION_STATE_ERROR) ++ if (session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING) { + return 1; +- else ++ } else if (session->session_state == SSH_SESSION_STATE_ERROR) { ++ SSH_LOG(SSH_LOG_WARN, "Error: %s", ssh_get_error(session)); ++ return 1; ++ } else { + return 0; ++ } + } + + /** +@@ -2324,7 +2333,7 @@ pending: + } + switch(session->global_req_state){ + case SSH_CHANNEL_REQ_STATE_ACCEPTED: +- SSH_LOG(SSH_LOG_PROTOCOL, "Global request %s success",request); ++ SSH_LOG(SSH_LOG_DEBUG, "Global request %s success",request); + rc=SSH_OK; + break; + case SSH_CHANNEL_REQ_STATE_DENIED: +@@ -2808,11 +2817,14 @@ struct ssh_channel_read_termination_struct { + static int ssh_channel_read_termination(void *s){ + struct ssh_channel_read_termination_struct *ctx = s; + if (ssh_buffer_get_len(ctx->buffer) >= ctx->count || +- ctx->channel->remote_eof || +- ctx->channel->session->session_state == SSH_SESSION_STATE_ERROR) ++ ctx->channel->remote_eof) { + return 1; +- else ++ } else if (ctx->channel->session->session_state == SSH_SESSION_STATE_ERROR) { ++ SSH_LOG(SSH_LOG_WARN, "Error: %s", ssh_get_error(ctx->channel->session)); ++ return 1; ++ } else { + return 0; ++ } + } + + /* TODO FIXME Fix the delayed close thing */ +@@ -3172,10 +3184,12 @@ static int ssh_channel_exit_status_termination(void *c){ + /* When a channel is closed, no exit status message can + * come anymore */ + (channel->flags & SSH_CHANNEL_FLAG_CLOSED_REMOTE) || +- channel->session->session_state == SSH_SESSION_STATE_ERROR) ++ channel->session->session_state == SSH_SESSION_STATE_ERROR) { ++ SSH_LOG(SSH_LOG_WARN, "Error: %s", ssh_get_error(channel->session)); + return 1; +- else ++ } else { + return 0; ++ } + } + + /** +diff --git a/src/client.c b/src/client.c +index a4a7317e..82a436fc 100644 +--- a/src/client.c ++++ b/src/client.c +@@ -72,7 +72,7 @@ static void socket_callback_connected(int code, int errno_code, void *user){ + return; + } + +- SSH_LOG(SSH_LOG_RARE,"Socket connection callback: %d (%d)",code, errno_code); ++ SSH_LOG(SSH_LOG_TRACE,"Socket connection callback: %d (%d)",code, errno_code); + if(code == SSH_SOCKET_CONNECTED_OK) + session->session_state=SSH_SESSION_STATE_SOCKET_CONNECTED; + else { +@@ -400,7 +400,7 @@ static void ssh_client_connection_callback(ssh_session session) + goto error; + } + set_status(session, 0.4f); +- SSH_LOG(SSH_LOG_PROTOCOL, ++ SSH_LOG(SSH_LOG_DEBUG, + "SSH server banner: %s", session->serverbanner); + + /* Here we analyze the different protocols the server allows. */ +@@ -475,7 +475,7 @@ error: + ssh_socket_close(session->socket); + session->alive = 0; + session->session_state=SSH_SESSION_STATE_ERROR; +- ++ SSH_LOG(SSH_LOG_WARN, "%s", ssh_get_error(session)); + } + + /** @internal +@@ -558,7 +558,7 @@ int ssh_connect(ssh_session session) + return SSH_ERROR; + } + +- SSH_LOG(SSH_LOG_PROTOCOL, ++ SSH_LOG(SSH_LOG_DEBUG, + "libssh %s, using threading %s", + ssh_copyright(), + ssh_threads_get_type()); +@@ -593,7 +593,7 @@ int ssh_connect(ssh_session session) + set_status(session, 0.2f); + + session->alive = 1; +- SSH_LOG(SSH_LOG_PROTOCOL, ++ SSH_LOG(SSH_LOG_DEBUG, + "Socket connecting, now waiting for the callbacks to work"); + + pending: +diff --git a/src/config.c b/src/config.c +index 54ada276..5a5058c1 100644 +--- a/src/config.c ++++ b/src/config.c +@@ -360,7 +360,7 @@ ssh_config_parse_proxy_jump(ssh_session session, const char *s, bool do_parsing) + next ? next : "", + hostname); + if (rv < 0 || rv >= (int)sizeof(com)) { +- SSH_LOG(SSH_LOG_WARN, "Too long ProxyJump configuration line"); ++ SSH_LOG(SSH_LOG_TRACE, "Too long ProxyJump configuration line"); + rv = SSH_ERROR; + goto out; + } +@@ -494,7 +494,7 @@ ssh_config_parse_line(ssh_session session, + + case MATCH_FINAL: + case MATCH_CANONICAL: +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_DEBUG, + "line %d: Unsupported Match keyword '%s', skipping", + count, + p); +@@ -506,13 +506,13 @@ ssh_config_parse_line(ssh_session session, + /* Skip to the end of line as unsupported */ + p = ssh_config_get_cmd(&s); + if (p == NULL || p[0] == '\0') { +- SSH_LOG(SSH_LOG_WARN, "line %d: Match keyword " ++ SSH_LOG(SSH_LOG_TRACE, "line %d: Match keyword " + "'%s' requires argument", count, p2); + SAFE_FREE(x); + return -1; + } + args++; +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_DEBUG, + "line %d: Unsupported Match keyword '%s', ignoring", + count, + p2); +@@ -531,7 +531,7 @@ ssh_config_parse_line(ssh_session session, + } + localuser = ssh_get_local_username(); + if (localuser == NULL) { +- SSH_LOG(SSH_LOG_WARN, "line %d: Can not get local username " ++ SSH_LOG(SSH_LOG_TRACE, "line %d: Can not get local username " + "for conditional matching.", count); + SAFE_FREE(x); + return -1; +@@ -545,13 +545,13 @@ ssh_config_parse_line(ssh_session session, + /* Skip one argument */ + p = ssh_config_get_str_tok(&s, NULL); + if (p == NULL || p[0] == '\0') { +- SSH_LOG(SSH_LOG_WARN, "line %d: Match keyword " ++ SSH_LOG(SSH_LOG_TRACE, "line %d: Match keyword " + "'%s' requires argument", count, p2); + SAFE_FREE(x); + return -1; + } + args++; +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "line %d: Unsupported Match keyword '%s', ignoring", + count, + p2); +@@ -786,10 +786,10 @@ ssh_config_parse_line(ssh_session session, + if (strcasecmp(p, "quiet") == 0) { + value = SSH_LOG_NONE; + } else if (strcasecmp(p, "fatal") == 0 || +- strcasecmp(p, "error")== 0 || +- strcasecmp(p, "info") == 0) { ++ strcasecmp(p, "error")== 0) { + value = SSH_LOG_WARN; +- } else if (strcasecmp(p, "verbose") == 0) { ++ } else if (strcasecmp(p, "verbose") == 0 || ++ strcasecmp(p, "info") == 0) { + value = SSH_LOG_INFO; + } else if (strcasecmp(p, "DEBUG") == 0 || + strcasecmp(p, "DEBUG1") == 0) { +@@ -834,13 +834,13 @@ ssh_config_parse_line(ssh_session session, + ll = strtoll(p, &endp, 10); + if (p == endp || ll < 0) { + /* No number or negative */ +- SSH_LOG(SSH_LOG_WARN, "Invalid argument to rekey limit"); ++ SSH_LOG(SSH_LOG_TRACE, "Invalid argument to rekey limit"); + break; + } + switch (*endp) { + case 'G': + if (ll > LLONG_MAX / 1024) { +- SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit"); ++ SSH_LOG(SSH_LOG_TRACE, "Possible overflow of rekey limit"); + ll = -1; + break; + } +@@ -848,7 +848,7 @@ ssh_config_parse_line(ssh_session session, + FALL_THROUGH; + case 'M': + if (ll > LLONG_MAX / 1024) { +- SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit"); ++ SSH_LOG(SSH_LOG_TRACE, "Possible overflow of rekey limit"); + ll = -1; + break; + } +@@ -856,7 +856,7 @@ ssh_config_parse_line(ssh_session session, + FALL_THROUGH; + case 'K': + if (ll > LLONG_MAX / 1024) { +- SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit"); ++ SSH_LOG(SSH_LOG_TRACE, "Possible overflow of rekey limit"); + ll = -1; + break; + } +@@ -872,7 +872,7 @@ ssh_config_parse_line(ssh_session session, + break; + } + if (*endp != ' ' && *endp != '\0') { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Invalid trailing characters after the rekey limit: %s", + endp); + break; +@@ -893,14 +893,14 @@ ssh_config_parse_line(ssh_session session, + ll = strtoll(p, &endp, 10); + if (p == endp || ll < 0) { + /* No number or negative */ +- SSH_LOG(SSH_LOG_WARN, "Invalid argument to rekey limit"); ++ SSH_LOG(SSH_LOG_TRACE, "Invalid argument to rekey limit"); + break; + } + switch (*endp) { + case 'w': + case 'W': + if (ll > LLONG_MAX / 7) { +- SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit"); ++ SSH_LOG(SSH_LOG_TRACE, "Possible overflow of rekey limit"); + ll = -1; + break; + } +@@ -909,7 +909,7 @@ ssh_config_parse_line(ssh_session session, + case 'd': + case 'D': + if (ll > LLONG_MAX / 24) { +- SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit"); ++ SSH_LOG(SSH_LOG_TRACE, "Possible overflow of rekey limit"); + ll = -1; + break; + } +@@ -918,7 +918,7 @@ ssh_config_parse_line(ssh_session session, + case 'h': + case 'H': + if (ll > LLONG_MAX / 60) { +- SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit"); ++ SSH_LOG(SSH_LOG_TRACE, "Possible overflow of rekey limit"); + ll = -1; + break; + } +@@ -927,7 +927,7 @@ ssh_config_parse_line(ssh_session session, + case 'm': + case 'M': + if (ll > LLONG_MAX / 60) { +- SSH_LOG(SSH_LOG_WARN, "Possible overflow of rekey limit"); ++ SSH_LOG(SSH_LOG_TRACE, "Possible overflow of rekey limit"); + ll = -1; + break; + } +@@ -946,7 +946,7 @@ ssh_config_parse_line(ssh_session session, + break; + } + if (*endp != '\0') { +- SSH_LOG(SSH_LOG_WARN, "Invalid trailing characters after the" ++ SSH_LOG(SSH_LOG_TRACE, "Invalid trailing characters after the" + " rekey limit: %s", endp); + break; + } +@@ -982,7 +982,7 @@ ssh_config_parse_line(ssh_session session, + } + break; + case SOC_NA: +- SSH_LOG(SSH_LOG_INFO, "Unapplicable option: %s, line: %d", ++ SSH_LOG(SSH_LOG_TRACE, "Unapplicable option: %s, line: %d", + keyword, count); + break; + case SOC_UNSUPPORTED: +@@ -990,7 +990,7 @@ ssh_config_parse_line(ssh_session session, + keyword, count); + break; + case SOC_UNKNOWN: +- SSH_LOG(SSH_LOG_WARN, "Unknown option: %s, line: %d", ++ SSH_LOG(SSH_LOG_TRACE, "Unknown option: %s, line: %d", + keyword, count); + break; + default: +diff --git a/src/config_parser.c b/src/config_parser.c +index ae2aa2c8..3a219d61 100644 +--- a/src/config_parser.c ++++ b/src/config_parser.c +@@ -209,7 +209,7 @@ int ssh_config_parse_uri(const char *tok, + /* Verify the port is valid positive number */ + port_n = strtol(endp + 1, &port_end, 10); + if (port_n < 1 || *port_end != '\0') { +- SSH_LOG(SSH_LOG_WARN, "Failed to parse port number." ++ SSH_LOG(SSH_LOG_TRACE, "Failed to parse port number." + " The value '%ld' is invalid or there are some" + " trailing characters: '%s'", port_n, port_end); + goto error; +diff --git a/src/curve25519.c b/src/curve25519.c +index d2517551..d8e0456a 100644 +--- a/src/curve25519.c ++++ b/src/curve25519.c +@@ -339,7 +339,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_client_curve25519_reply){ + goto error; + } + +- SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); ++ SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_NEWKEYS sent"); + session->dh_handshake_state = DH_STATE_NEWKEYS_SENT; + + return SSH_PACKET_USED; +@@ -491,7 +491,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){ + goto error; + } + +- SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_ECDH_REPLY sent"); ++ SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_KEX_ECDH_REPLY sent"); + rc = ssh_packet_send(session); + if (rc == SSH_ERROR) { + return SSH_ERROR; +@@ -508,7 +508,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_curve25519_init){ + if (rc == SSH_ERROR) { + goto error; + } +- SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); ++ SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_NEWKEYS sent"); + + return SSH_PACKET_USED; + error: +diff --git a/src/dh-gex.c b/src/dh-gex.c +index 88a97140..ace572dc 100644 +--- a/src/dh-gex.c ++++ b/src/dh-gex.c +@@ -112,7 +112,7 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_group) + (void) type; + (void) user; + +- SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_DH_GEX_GROUP received"); ++ SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_KEX_DH_GEX_GROUP received"); + + if (bignum_ctx_invalid(ctx)) { + goto error; +@@ -246,7 +246,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_reply) + bignum server_pubkey = NULL; + (void)type; + (void)user; +- SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_DH_GEX_REPLY received"); ++ SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_KEX_DH_GEX_REPLY received"); + + ssh_packet_remove_callbacks(session, &ssh_dhgex_client_callbacks); + rc = ssh_buffer_unpack(packet, +@@ -290,7 +290,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_reply) + if (rc == SSH_ERROR) { + goto error; + } +- SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); ++ SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_NEWKEYS sent"); + session->dh_handshake_state = DH_STATE_NEWKEYS_SENT; + + return SSH_PACKET_USED; +@@ -425,7 +425,7 @@ static int ssh_retrieve_dhgroup_file(FILE *moduli, + if (rc == EOF) { + break; + } +- SSH_LOG(SSH_LOG_INFO, "Invalid moduli entry line %zu", line); ++ SSH_LOG(SSH_LOG_DEBUG, "Invalid moduli entry line %zu", line); + do { + firstbyte = getc(moduli); + } while(firstbyte != '\n' && firstbyte != EOF); +@@ -463,13 +463,13 @@ static int ssh_retrieve_dhgroup_file(FILE *moduli, + } + } + if (*best_size != 0) { +- SSH_LOG(SSH_LOG_INFO, ++ SSH_LOG(SSH_LOG_DEBUG, + "Selected %zu bits modulus out of %zu candidates in %zu lines", + *best_size, + best_nlines - 1, + line); + } else { +- SSH_LOG(SSH_LOG_WARNING, ++ SSH_LOG(SSH_LOG_DEBUG, + "No moduli found for [%u:%u:%u]", + pmin, + pn, +@@ -510,7 +510,7 @@ static int ssh_retrieve_dhgroup(uint32_t pmin, + + moduli = fopen(MODULI_FILE, "r"); + if (moduli == NULL) { +- SSH_LOG(SSH_LOG_WARNING, ++ SSH_LOG(SSH_LOG_DEBUG, + "Unable to open moduli file: %s", + strerror(errno)); + return ssh_fallback_group(pmax, p, g); +@@ -605,7 +605,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_server_dhgex_request) + ssh_set_error_invalid(session); + goto error; + } +- SSH_LOG(SSH_LOG_INFO, "dh-gex: DHGEX_REQUEST[%u:%u:%u]", pmin, pn, pmax); ++ SSH_LOG(SSH_LOG_DEBUG, "dh-gex: DHGEX_REQUEST[%u:%u:%u]", pmin, pn, pmax); + + if (pmin > pn || pn > pmax || pn > DH_PMAX || pmax < DH_PMIN) { + ssh_set_error(session, +diff --git a/src/dh.c b/src/dh.c +index 18b71734..ede4855d 100644 +--- a/src/dh.c ++++ b/src/dh.c +@@ -390,7 +390,7 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dh_reply){ + goto error; + } + +- SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); ++ SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_NEWKEYS sent"); + session->dh_handshake_state = DH_STATE_NEWKEYS_SENT; + return SSH_PACKET_USED; + error: +diff --git a/src/ecdh.c b/src/ecdh.c +index a4c07ccb..b57789d4 100644 +--- a/src/ecdh.c ++++ b/src/ecdh.c +@@ -97,7 +97,7 @@ SSH_PACKET_CALLBACK(ssh_packet_client_ecdh_reply){ + goto error; + } + +- SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); ++ SSH_LOG(SSH_LOG_DEBUG, "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..d050544f 100644 +--- a/src/ecdh_crypto.c ++++ b/src/ecdh_crypto.c +@@ -317,7 +317,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){ + goto error; + } + +- SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEXDH_REPLY sent"); ++ SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_KEXDH_REPLY sent"); + rc = ssh_packet_send(session); + if (rc == SSH_ERROR) { + goto error; +@@ -334,7 +334,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){ + if (rc == SSH_ERROR){ + goto error; + } +- SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); ++ SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_NEWKEYS sent"); + + return SSH_PACKET_USED; + error: +diff --git a/src/ecdh_gcrypt.c b/src/ecdh_gcrypt.c +index d9c41bf9..ca643467 100644 +--- a/src/ecdh_gcrypt.c ++++ b/src/ecdh_gcrypt.c +@@ -366,7 +366,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){ + goto out; + } + +- SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEXDH_REPLY sent"); ++ SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_KEXDH_REPLY sent"); + rc = ssh_packet_send(session); + if (rc != SSH_OK) { + goto out; +@@ -381,7 +381,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){ + + session->dh_handshake_state = DH_STATE_NEWKEYS_SENT; + rc = ssh_packet_send(session); +- SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); ++ SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_NEWKEYS sent"); + + out: + gcry_sexp_release(param); +diff --git a/src/ecdh_mbedcrypto.c b/src/ecdh_mbedcrypto.c +index 718f1522..855d4770 100644 +--- a/src/ecdh_mbedcrypto.c ++++ b/src/ecdh_mbedcrypto.c +@@ -293,7 +293,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){ + goto out; + } + +- SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEXDH_REPLY sent"); ++ SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_KEXDH_REPLY sent"); + rc = ssh_packet_send(session); + if (rc != SSH_OK) { + rc = SSH_ERROR; +@@ -308,7 +308,7 @@ SSH_PACKET_CALLBACK(ssh_packet_server_ecdh_init){ + + session->dh_handshake_state = DH_STATE_NEWKEYS_SENT; + rc = ssh_packet_send(session); +- SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_NEWKEYS sent"); ++ SSH_LOG(SSH_LOG_DEBUG, "SSH_MSG_NEWKEYS sent"); + + out: + mbedtls_ecp_group_free(&grp); +diff --git a/src/error.c b/src/error.c +index 22180407..5e850adb 100644 +--- a/src/error.c ++++ b/src/error.c +@@ -63,8 +63,8 @@ void _ssh_set_error(void *error, + va_end(va); + + err->error.error_code = code; +- if (ssh_get_log_level() >= SSH_LOG_WARN) { +- ssh_log_function(SSH_LOG_WARN, ++ if (ssh_get_log_level() == SSH_LOG_TRACE) { ++ ssh_log_function(SSH_LOG_TRACE, + function, + err->error.error_buffer); + } +diff --git a/src/gssapi.c b/src/gssapi.c +index 1d0fb6ae..cfa36a95 100644 +--- a/src/gssapi.c ++++ b/src/gssapi.c +@@ -218,8 +218,8 @@ int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n + + maj_stat = gss_indicate_mechs(&min_stat, &supported); + if (maj_stat != GSS_S_COMPLETE) { +- SSH_LOG(SSH_LOG_WARNING, "indicate mecks %d, %d", maj_stat, min_stat); +- ssh_gssapi_log_error(SSH_LOG_WARNING, ++ SSH_LOG(SSH_LOG_DEBUG, "indicate mecks %d, %d", maj_stat, min_stat); ++ ssh_gssapi_log_error(SSH_LOG_DEBUG, + "indicate mechs", + maj_stat, + min_stat); +@@ -240,7 +240,7 @@ int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n + continue; + } + if(len < 2 || oid_s[0] != SSH_OID_TAG || ((size_t)oid_s[1]) != len - 2){ +- SSH_LOG(SSH_LOG_WARNING,"GSSAPI: received invalid OID"); ++ SSH_LOG(SSH_LOG_TRACE,"GSSAPI: received invalid OID"); + continue; + } + oid.elements = &oid_s[2]; +@@ -253,7 +253,7 @@ int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n + } + gss_release_oid_set(&min_stat, &supported); + if (oid_count == 0){ +- SSH_LOG(SSH_LOG_PROTOCOL,"GSSAPI: no OID match"); ++ SSH_LOG(SSH_LOG_DEBUG,"GSSAPI: no OID match"); + ssh_auth_reply_default(session, 0); + gss_release_oid_set(&min_stat, &both_supported); + return SSH_OK; +@@ -267,8 +267,8 @@ int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n + maj_stat = gss_import_name(&min_stat, &name_buf, + (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &server_name); + if (maj_stat != GSS_S_COMPLETE) { +- SSH_LOG(SSH_LOG_WARNING, "importing name %d, %d", maj_stat, min_stat); +- ssh_gssapi_log_error(SSH_LOG_WARNING, ++ SSH_LOG(SSH_LOG_DEBUG, "importing name %d, %d", maj_stat, min_stat); ++ ssh_gssapi_log_error(SSH_LOG_DEBUG, + "importing name", + maj_stat, + min_stat); +@@ -282,8 +282,8 @@ int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n + gss_release_oid_set(&min_stat, &both_supported); + + if (maj_stat != GSS_S_COMPLETE) { +- SSH_LOG(SSH_LOG_WARNING, "error acquiring credentials %d, %d", maj_stat, min_stat); +- ssh_gssapi_log_error(SSH_LOG_WARNING, ++ SSH_LOG(SSH_LOG_TRACE, "error acquiring credentials %d, %d", maj_stat, min_stat); ++ ssh_gssapi_log_error(SSH_LOG_TRACE, + "acquiring creds", + maj_stat, + min_stat); +@@ -291,7 +291,7 @@ int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n + return SSH_ERROR; + } + +- SSH_LOG(SSH_LOG_PROTOCOL, "acquiring credentials %d, %d", maj_stat, min_stat); ++ SSH_LOG(SSH_LOG_DEBUG, "acquiring credentials %d, %d", maj_stat, min_stat); + + /* finding which OID from client we selected */ + for (i=0 ; i< n_oid ; ++i){ +@@ -302,7 +302,7 @@ int ssh_gssapi_handle_userauth(ssh_session session, const char *user, uint32_t n + continue; + } + if(len < 2 || oid_s[0] != SSH_OID_TAG || ((size_t)oid_s[1]) != len - 2){ +- SSH_LOG(SSH_LOG_WARNING,"GSSAPI: received invalid OID"); ++ SSH_LOG(SSH_LOG_TRACE,"GSSAPI: received invalid OID"); + continue; + } + oid.elements = &oid_s[2]; +@@ -332,7 +332,7 @@ static char *ssh_gssapi_name_to_char(gss_name_t name){ + OM_uint32 maj_stat, min_stat; + char *ptr; + maj_stat = gss_display_name(&min_stat, name, &buffer, NULL); +- ssh_gssapi_log_error(SSH_LOG_WARNING, ++ ssh_gssapi_log_error(SSH_LOG_DEBUG, + "converting name", + maj_stat, + min_stat); +@@ -407,7 +407,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server){ + maj_stat = gss_accept_sec_context(&min_stat, &session->gssapi->ctx, session->gssapi->server_creds, + &input_token, input_bindings, &client_name, NULL /*mech_oid*/, &output_token, &ret_flags, + NULL /*time*/, &session->gssapi->client_creds); +- ssh_gssapi_log_error(SSH_LOG_PROTOCOL, ++ ssh_gssapi_log_error(SSH_LOG_DEBUG, + "accepting token", + maj_stat, + min_stat); +@@ -417,7 +417,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_server){ + session->gssapi->canonic_user = ssh_gssapi_name_to_char(client_name); + } + if (GSS_ERROR(maj_stat)){ +- ssh_gssapi_log_error(SSH_LOG_WARNING, ++ ssh_gssapi_log_error(SSH_LOG_DEBUG, + "Gssapi error", + maj_stat, + min_stat); +@@ -524,7 +524,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_mic) + mic_token_buf.value = ssh_string_data(mic_token); + + maj_stat = gss_verify_mic(&min_stat, session->gssapi->ctx, &mic_buf, &mic_token_buf, NULL); +- ssh_gssapi_log_error(SSH_LOG_PROTOCOL, ++ ssh_gssapi_log_error(SSH_LOG_DEBUG, + "verifying MIC", + maj_stat, + min_stat); +@@ -739,8 +739,8 @@ int ssh_gssapi_auth_mic(ssh_session session){ + (gss_OID)GSS_C_NT_HOSTBASED_SERVICE, + &session->gssapi->client.server_name); + if (maj_stat != GSS_S_COMPLETE) { +- SSH_LOG(SSH_LOG_WARNING, "importing name %d, %d", maj_stat, min_stat); +- ssh_gssapi_log_error(SSH_LOG_WARNING, ++ SSH_LOG(SSH_LOG_DEBUG, "importing name %d, %d", maj_stat, min_stat); ++ ssh_gssapi_log_error(SSH_LOG_DEBUG, + "importing name", + maj_stat, + min_stat); +@@ -754,7 +754,7 @@ int ssh_gssapi_auth_mic(ssh_session session){ + return SSH_AUTH_ERROR; + } + +- SSH_LOG(SSH_LOG_PROTOCOL, "Authenticating with gssapi to host %s with user %s", ++ SSH_LOG(SSH_LOG_DEBUG, "Authenticating with gssapi to host %s with user %s", + session->opts.host, session->gssapi->user); + rc = ssh_gssapi_match(session, &selected); + if (rc == SSH_ERROR) { +@@ -762,7 +762,7 @@ int ssh_gssapi_auth_mic(ssh_session session){ + } + + n_oids = selected->count; +- SSH_LOG(SSH_LOG_PROTOCOL, "Sending %zu oids", n_oids); ++ SSH_LOG(SSH_LOG_DEBUG, "Sending %zu oids", n_oids); + + oids = calloc(n_oids, sizeof(ssh_string)); + if (oids == NULL) { +@@ -875,7 +875,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_response){ + 0, NULL, &input_token, NULL, + &output_token, NULL, NULL); + if(GSS_ERROR(maj_stat)){ +- ssh_gssapi_log_error(SSH_LOG_WARNING, ++ ssh_gssapi_log_error(SSH_LOG_DEBUG, + "Initializing gssapi context", + maj_stat, + min_stat); +@@ -923,7 +923,7 @@ static int ssh_gssapi_send_mic(ssh_session session){ + &mic_buf, &mic_token_buf); + if (GSS_ERROR(maj_stat)){ + SSH_BUFFER_FREE(mic_buffer); +- ssh_gssapi_log_error(SSH_LOG_PROTOCOL, ++ ssh_gssapi_log_error(SSH_LOG_DEBUG, + "generating MIC", + maj_stat, + min_stat); +@@ -980,13 +980,13 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_client){ + 0, NULL, &input_token, NULL, + &output_token, NULL, NULL); + +- ssh_gssapi_log_error(SSH_LOG_PROTOCOL, ++ ssh_gssapi_log_error(SSH_LOG_DEBUG, + "accepting token", + maj_stat, + min_stat); + SSH_STRING_FREE(token); + if (GSS_ERROR(maj_stat)){ +- ssh_gssapi_log_error(SSH_LOG_PROTOCOL, ++ ssh_gssapi_log_error(SSH_LOG_DEBUG, + "Gssapi error", + maj_stat, + min_stat); +diff --git a/src/kex.c b/src/kex.c +index 82071c74..9b599657 100644 +--- a/src/kex.c ++++ b/src/kex.c +@@ -345,7 +345,7 @@ 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"); ++ SSH_LOG(SSH_LOG_DEBUG, "Initiating key re-exchange"); + } else if (session->session_state != SSH_SESSION_STATE_INITIAL_KEX) { + ssh_set_error(session,SSH_FATAL,"SSH_KEXINIT received in wrong state"); + goto error; +@@ -590,7 +590,7 @@ char *ssh_client_select_hostkeys(ssh_session session) + /* This removes the certificate types, unsupported for now */ + wanted_without_certs = ssh_find_all_matching(HOSTKEYS, wanted); + if (wanted_without_certs == NULL) { +- SSH_LOG(SSH_LOG_WARNING, ++ SSH_LOG(SSH_LOG_TRACE, + "List of allowed host key algorithms is empty or contains only " + "unsupported algorithms"); + return NULL; +@@ -643,7 +643,7 @@ char *ssh_client_select_hostkeys(ssh_session session) + fips_hostkeys = ssh_keep_fips_algos(SSH_HOSTKEYS, new_hostkeys); + SAFE_FREE(new_hostkeys); + if (fips_hostkeys == NULL) { +- SSH_LOG(SSH_LOG_WARNING, ++ SSH_LOG(SSH_LOG_TRACE, + "None of the wanted host keys or keys in known_hosts files " + "is allowed in FIPS mode."); + return NULL; +@@ -813,7 +813,7 @@ int ssh_kex_select_methods (ssh_session session) + } else if (strcmp(session->next_crypto->kex_methods[SSH_KEX], "curve25519-sha256") == 0){ + session->next_crypto->kex_type=SSH_KEX_CURVE25519_SHA256; + } +- SSH_LOG(SSH_LOG_INFO, "Negotiated %s,%s,%s,%s,%s,%s,%s,%s,%s,%s", ++ SSH_LOG(SSH_LOG_DEBUG, "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], + session->next_crypto->kex_methods[SSH_CRYPT_C_S], +@@ -1114,7 +1114,7 @@ int ssh_make_sessionid(ssh_session session) + case SSH_KEX_ECDH_SHA2_NISTP521: + if (session->next_crypto->ecdh_client_pubkey == NULL || + session->next_crypto->ecdh_server_pubkey == NULL) { +- SSH_LOG(SSH_LOG_WARNING, "ECDH parameted missing"); ++ SSH_LOG(SSH_LOG_TRACE, "ECDH parameted missing"); + goto error; + } + rc = ssh_buffer_pack(buf, +diff --git a/src/knownhosts.c b/src/knownhosts.c +index f2ef088c..e632ef22 100644 +--- a/src/knownhosts.c ++++ b/src/knownhosts.c +@@ -224,7 +224,7 @@ static int ssh_known_hosts_read_entries(const char *match, + + fp = fopen(filename, "r"); + if (fp == NULL) { +- SSH_LOG(SSH_LOG_WARN, "Failed to open the known_hosts file '%s': %s", ++ SSH_LOG(SSH_LOG_TRACE, "Failed to open the known_hosts file '%s': %s", + filename, strerror(errno)); + /* The missing file is not an error here */ + return SSH_OK; +@@ -483,7 +483,7 @@ static const char *ssh_known_host_sigs_from_hostkey_type(enum ssh_keytypes_e typ + #endif + case SSH_KEYTYPE_UNKNOWN: + default: +- SSH_LOG(SSH_LOG_WARN, "The given type %d is not a base private key type " ++ SSH_LOG(SSH_LOG_TRACE, "The given type %d is not a base private key type " + "or is unsupported", type); + return NULL; + } +@@ -719,7 +719,7 @@ int ssh_known_hosts_parse_line(const char *hostname, + + key_type = ssh_key_type_from_name(p); + if (key_type == SSH_KEYTYPE_UNKNOWN) { +- SSH_LOG(SSH_LOG_WARN, "key type '%s' unknown!", p); ++ SSH_LOG(SSH_LOG_TRACE, "key type '%s' unknown!", p); + rc = SSH_ERROR; + goto out; + } +@@ -735,7 +735,7 @@ int ssh_known_hosts_parse_line(const char *hostname, + key_type, + &e->publickey); + if (rc != SSH_OK) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Failed to parse %s key for entry: %s!", + ssh_key_type_to_char(key_type), + e->unparsed); +@@ -806,7 +806,7 @@ enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session) + if (session->opts.knownhosts != NULL) { + known_hosts_found = ssh_file_readaccess_ok(session->opts.knownhosts); + if (!known_hosts_found) { +- SSH_LOG(SSH_LOG_WARN, "Cannot access file %s", ++ SSH_LOG(SSH_LOG_TRACE, "Cannot access file %s", + session->opts.knownhosts); + } + } +@@ -815,7 +815,7 @@ enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session) + global_known_hosts_found = + ssh_file_readaccess_ok(session->opts.global_knownhosts); + if (!global_known_hosts_found) { +- SSH_LOG(SSH_LOG_WARN, "Cannot access file %s", ++ SSH_LOG(SSH_LOG_TRACE, "Cannot access file %s", + session->opts.global_knownhosts); + } + } +diff --git a/src/libcrypto.c b/src/libcrypto.c +index 3db75df6..c002262a 100644 +--- a/src/libcrypto.c ++++ b/src/libcrypto.c +@@ -496,7 +496,7 @@ static void evp_cipher_init(struct ssh_cipher_struct *cipher) { + case SSH_AES128_CTR: + case SSH_AES192_CTR: + case SSH_AES256_CTR: +- SSH_LOG(SSH_LOG_WARNING, "This cipher is not available in evp_cipher_init"); ++ SSH_LOG(SSH_LOG_TRACE, "This cipher is not available in evp_cipher_init"); + break; + #endif + #ifdef HAVE_OPENSSL_EVP_AES_GCM +@@ -509,7 +509,7 @@ static void evp_cipher_init(struct ssh_cipher_struct *cipher) { + #else + case SSH_AEAD_AES128_GCM: + case SSH_AEAD_AES256_GCM: +- SSH_LOG(SSH_LOG_WARNING, "This cipher is not available in evp_cipher_init"); ++ SSH_LOG(SSH_LOG_TRACE, "This cipher is not available in evp_cipher_init"); + break; + #endif /* HAVE_OPENSSL_EVP_AES_GCM */ + case SSH_3DES_CBC: +@@ -522,10 +522,10 @@ static void evp_cipher_init(struct ssh_cipher_struct *cipher) { + /* ciphers not using EVP */ + #endif + case SSH_AEAD_CHACHA20_POLY1305: +- SSH_LOG(SSH_LOG_WARNING, "The ChaCha cipher cannot be handled here"); ++ SSH_LOG(SSH_LOG_TRACE, "The ChaCha cipher cannot be handled here"); + break; + case SSH_NO_CIPHER: +- SSH_LOG(SSH_LOG_WARNING, "No valid ciphertype found"); ++ SSH_LOG(SSH_LOG_TRACE, "No valid ciphertype found"); + break; + } + } +@@ -540,7 +540,7 @@ static int evp_cipher_set_encrypt_key(struct ssh_cipher_struct *cipher, + + rc = EVP_EncryptInit_ex(cipher->ctx, cipher->cipher, NULL, key, IV); + if (rc != 1){ +- SSH_LOG(SSH_LOG_WARNING, "EVP_EncryptInit_ex failed"); ++ SSH_LOG(SSH_LOG_TRACE, "EVP_EncryptInit_ex failed"); + return SSH_ERROR; + } + +@@ -553,7 +553,7 @@ static int evp_cipher_set_encrypt_key(struct ssh_cipher_struct *cipher, + -1, + (uint8_t *)IV); + if (rc != 1) { +- SSH_LOG(SSH_LOG_WARNING, "EVP_CTRL_GCM_SET_IV_FIXED failed"); ++ SSH_LOG(SSH_LOG_TRACE, "EVP_CTRL_GCM_SET_IV_FIXED failed"); + return SSH_ERROR; + } + } +@@ -573,7 +573,7 @@ static int evp_cipher_set_decrypt_key(struct ssh_cipher_struct *cipher, + + rc = EVP_DecryptInit_ex(cipher->ctx, cipher->cipher, NULL, key, IV); + if (rc != 1){ +- SSH_LOG(SSH_LOG_WARNING, "EVP_DecryptInit_ex failed"); ++ SSH_LOG(SSH_LOG_TRACE, "EVP_DecryptInit_ex failed"); + return SSH_ERROR; + } + +@@ -586,7 +586,7 @@ static int evp_cipher_set_decrypt_key(struct ssh_cipher_struct *cipher, + -1, + (uint8_t *)IV); + if (rc != 1) { +- SSH_LOG(SSH_LOG_WARNING, "EVP_CTRL_GCM_SET_IV_FIXED failed"); ++ SSH_LOG(SSH_LOG_TRACE, "EVP_CTRL_GCM_SET_IV_FIXED failed"); + return SSH_ERROR; + } + } +@@ -612,11 +612,11 @@ static void evp_cipher_encrypt(struct ssh_cipher_struct *cipher, + (unsigned char *)in, + (int)len); + if (rc != 1){ +- SSH_LOG(SSH_LOG_WARNING, "EVP_EncryptUpdate failed"); ++ SSH_LOG(SSH_LOG_TRACE, "EVP_EncryptUpdate failed"); + return; + } + if (outlen != (int)len){ +- SSH_LOG(SSH_LOG_WARNING, ++ SSH_LOG(SSH_LOG_DEBUG, + "EVP_EncryptUpdate: output size %d for %zu in", + outlen, + len); +@@ -638,11 +638,11 @@ static void evp_cipher_decrypt(struct ssh_cipher_struct *cipher, + (unsigned char *)in, + (int)len); + if (rc != 1){ +- SSH_LOG(SSH_LOG_WARNING, "EVP_DecryptUpdate failed"); ++ SSH_LOG(SSH_LOG_TRACE, "EVP_DecryptUpdate failed"); + return; + } + if (outlen != (int)len){ +- SSH_LOG(SSH_LOG_WARNING, ++ SSH_LOG(SSH_LOG_DEBUG, + "EVP_DecryptUpdate: output size %d for %zu in", + outlen, + len); +@@ -759,7 +759,7 @@ evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher, + 1, + lastiv); + if (rc == 0) { +- SSH_LOG(SSH_LOG_WARNING, "EVP_CTRL_GCM_IV_GEN failed"); ++ SSH_LOG(SSH_LOG_TRACE, "EVP_CTRL_GCM_IV_GEN failed"); + return; + } + +@@ -771,7 +771,7 @@ evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher, + (int)aadlen); + outlen = tmplen; + if (rc == 0 || outlen != aadlen) { +- SSH_LOG(SSH_LOG_WARNING, "Failed to pass authenticated data"); ++ SSH_LOG(SSH_LOG_TRACE, "Failed to pass authenticated data"); + return; + } + memcpy(out, in, aadlen); +@@ -784,7 +784,7 @@ evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher, + (int)len - aadlen); + outlen = tmplen; + if (rc != 1 || outlen != (int)len - aadlen) { +- SSH_LOG(SSH_LOG_WARNING, "EVP_EncryptUpdate failed"); ++ SSH_LOG(SSH_LOG_TRACE, "EVP_EncryptUpdate failed"); + return; + } + +@@ -793,7 +793,7 @@ evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher, + NULL, + &tmplen); + if (rc < 0) { +- SSH_LOG(SSH_LOG_WARNING, "EVP_EncryptFinal failed: Failed to create a tag"); ++ SSH_LOG(SSH_LOG_TRACE, "EVP_EncryptFinal failed: Failed to create a tag"); + return; + } + +@@ -802,7 +802,7 @@ evp_cipher_aead_encrypt(struct ssh_cipher_struct *cipher, + authlen, + (unsigned char *)tag); + if (rc != 1) { +- SSH_LOG(SSH_LOG_WARNING, "EVP_CTRL_GCM_GET_TAG failed"); ++ SSH_LOG(SSH_LOG_TRACE, "EVP_CTRL_GCM_GET_TAG failed"); + return; + } + } +@@ -830,7 +830,7 @@ evp_cipher_aead_decrypt(struct ssh_cipher_struct *cipher, + 1, + lastiv); + if (rc == 0) { +- SSH_LOG(SSH_LOG_WARNING, "EVP_CTRL_GCM_IV_GEN failed"); ++ SSH_LOG(SSH_LOG_TRACE, "EVP_CTRL_GCM_IV_GEN failed"); + return SSH_ERROR; + } + +@@ -840,7 +840,7 @@ evp_cipher_aead_decrypt(struct ssh_cipher_struct *cipher, + authlen, + (unsigned char *)complete_packet + aadlen + encrypted_size); + if (rc == 0) { +- SSH_LOG(SSH_LOG_WARNING, "EVP_CTRL_GCM_SET_TAG failed"); ++ SSH_LOG(SSH_LOG_TRACE, "EVP_CTRL_GCM_SET_TAG failed"); + return SSH_ERROR; + } + +@@ -851,7 +851,7 @@ evp_cipher_aead_decrypt(struct ssh_cipher_struct *cipher, + (unsigned char *)complete_packet, + (int)aadlen); + if (rc == 0) { +- SSH_LOG(SSH_LOG_WARNING, "Failed to pass authenticated data"); ++ SSH_LOG(SSH_LOG_TRACE, "Failed to pass authenticated data"); + return SSH_ERROR; + } + /* Do not copy the length to the target buffer, because it is already processed */ +@@ -864,12 +864,12 @@ evp_cipher_aead_decrypt(struct ssh_cipher_struct *cipher, + (unsigned char *)complete_packet + aadlen, + encrypted_size /* already substracted aadlen*/); + if (rc != 1) { +- SSH_LOG(SSH_LOG_WARNING, "EVP_DecryptUpdate failed"); ++ SSH_LOG(SSH_LOG_TRACE, "EVP_DecryptUpdate failed"); + return SSH_ERROR; + } + + if (outlen != (int)encrypted_size) { +- SSH_LOG(SSH_LOG_WARNING, ++ SSH_LOG(SSH_LOG_TRACE, + "EVP_DecryptUpdate: output size %d for %zd in", + outlen, + encrypted_size); +@@ -881,7 +881,7 @@ evp_cipher_aead_decrypt(struct ssh_cipher_struct *cipher, + NULL, + &outlen); + if (rc < 0) { +- SSH_LOG(SSH_LOG_WARNING, "EVP_DecryptFinal failed: Failed authentication"); ++ SSH_LOG(SSH_LOG_TRACE, "EVP_DecryptFinal failed: Failed authentication"); + return SSH_ERROR; + } + +@@ -1084,7 +1084,7 @@ int ssh_crypto_init(void) + return SSH_OK; + } + if (OpenSSL_version_num() != OPENSSL_VERSION_NUMBER){ +- SSH_LOG(SSH_LOG_WARNING, "libssh compiled with %s " ++ SSH_LOG(SSH_LOG_DEBUG, "libssh compiled with %s " + "headers, currently running with %s.", + OPENSSL_VERSION_TEXT, + OpenSSL_version(OpenSSL_version_num()) +diff --git a/src/libgcrypt.c b/src/libgcrypt.c +index 8fbf2157..9a811005 100644 +--- a/src/libgcrypt.c ++++ b/src/libgcrypt.c +@@ -329,7 +329,7 @@ static int aes_set_key(struct ssh_cipher_struct *cipher, void *key, void *IV) { + } + break; + default: +- SSH_LOG(SSH_LOG_WARNING, "Unksupported key length %u.", cipher->keysize); ++ SSH_LOG(SSH_LOG_TRACE, "Unsupported key length %u.", cipher->keysize); + SAFE_FREE(cipher->key); + return -1; + } +@@ -420,7 +420,7 @@ aes_gcm_encrypt(struct ssh_cipher_struct *cipher, + */ + uint64_inc(cipher->last_iv + 4); + if (err) { +- SSH_LOG(SSH_LOG_WARNING, "gcry_cipher_setiv failed: %s", ++ SSH_LOG(SSH_LOG_TRACE, "gcry_cipher_setiv failed: %s", + gpg_strerror(err)); + return; + } +@@ -428,7 +428,7 @@ aes_gcm_encrypt(struct ssh_cipher_struct *cipher, + /* Pass the authenticated data (packet_length) */ + err = gcry_cipher_authenticate(cipher->key[0], in, aadlen); + if (err) { +- SSH_LOG(SSH_LOG_WARNING, "gcry_cipher_authenticate failed: %s", ++ SSH_LOG(SSH_LOG_TRACE, "gcry_cipher_authenticate failed: %s", + gpg_strerror(err)); + return; + } +@@ -441,7 +441,7 @@ aes_gcm_encrypt(struct ssh_cipher_struct *cipher, + (unsigned char *)in + aadlen, + len - aadlen); + if (err) { +- SSH_LOG(SSH_LOG_WARNING, "gcry_cipher_encrypt failed: %s", ++ SSH_LOG(SSH_LOG_TRACE, "gcry_cipher_encrypt failed: %s", + gpg_strerror(err)); + return; + } +@@ -451,7 +451,7 @@ aes_gcm_encrypt(struct ssh_cipher_struct *cipher, + (void *)tag, + authlen); + if (err) { +- SSH_LOG(SSH_LOG_WARNING, "gcry_cipher_gettag failed: %s", ++ SSH_LOG(SSH_LOG_TRACE, "gcry_cipher_gettag failed: %s", + gpg_strerror(err)); + return; + } +@@ -485,7 +485,7 @@ aes_gcm_decrypt(struct ssh_cipher_struct *cipher, + */ + uint64_inc(cipher->last_iv + 4); + if (err) { +- SSH_LOG(SSH_LOG_WARNING, "gcry_cipher_setiv failed: %s", ++ SSH_LOG(SSH_LOG_TRACE, "gcry_cipher_setiv failed: %s", + gpg_strerror(err)); + return SSH_ERROR; + } +@@ -495,7 +495,7 @@ aes_gcm_decrypt(struct ssh_cipher_struct *cipher, + complete_packet, + aadlen); + if (err) { +- SSH_LOG(SSH_LOG_WARNING, "gcry_cipher_authenticate failed: %s", ++ SSH_LOG(SSH_LOG_TRACE, "gcry_cipher_authenticate failed: %s", + gpg_strerror(err)); + return SSH_ERROR; + } +@@ -509,7 +509,7 @@ aes_gcm_decrypt(struct ssh_cipher_struct *cipher, + (unsigned char *)complete_packet + aadlen, + encrypted_size); + if (err) { +- SSH_LOG(SSH_LOG_WARNING, "gcry_cipher_decrypt failed: %s", ++ SSH_LOG(SSH_LOG_TRACE, "gcry_cipher_decrypt failed: %s", + gpg_strerror(err)); + return SSH_ERROR; + } +@@ -519,10 +519,10 @@ aes_gcm_decrypt(struct ssh_cipher_struct *cipher, + (unsigned char *)complete_packet + aadlen + encrypted_size, + authlen); + if (gpg_err_code(err) == GPG_ERR_CHECKSUM) { +- SSH_LOG(SSH_LOG_WARNING, "The authentication tag does not match"); ++ SSH_LOG(SSH_LOG_DEBUG, "The authentication tag does not match"); + return SSH_ERROR; + } else if (err != GPG_ERR_NO_ERROR) { +- SSH_LOG(SSH_LOG_WARNING, "General error while decryption: %s", ++ SSH_LOG(SSH_LOG_TRACE, "General error while decryption: %s", + gpg_strerror(err)); + return SSH_ERROR; + } +diff --git a/src/libmbedcrypto.c b/src/libmbedcrypto.c +index a2e74d3b..ee30c38a 100644 +--- a/src/libmbedcrypto.c ++++ b/src/libmbedcrypto.c +@@ -468,7 +468,7 @@ cipher_init(struct ssh_cipher_struct *cipher, + } else if (operation == MBEDTLS_DECRYPT) { + ctx = &cipher->decrypt_ctx; + } else { +- SSH_LOG(SSH_LOG_WARNING, "unknown operation"); ++ SSH_LOG(SSH_LOG_TRACE, "unknown operation"); + return 1; + } + +@@ -477,7 +477,7 @@ cipher_init(struct ssh_cipher_struct *cipher, + + rc = mbedtls_cipher_setup(ctx, cipher_info); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setup failed"); ++ SSH_LOG(SSH_LOG_TRACE, "mbedtls_cipher_setup failed"); + goto error; + } + +@@ -485,13 +485,13 @@ cipher_init(struct ssh_cipher_struct *cipher, + cipher_info->key_bitlen, + operation); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_setkey failed"); ++ SSH_LOG(SSH_LOG_TRACE, "mbedtls_cipher_setkey failed"); + goto error; + } + + rc = mbedtls_cipher_set_iv(ctx, IV, cipher_info->iv_size); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_iv failed"); ++ SSH_LOG(SSH_LOG_TRACE, "mbedtls_cipher_set_iv failed"); + goto error; + } + +@@ -510,13 +510,13 @@ cipher_set_encrypt_key(struct ssh_cipher_struct *cipher, + + rc = cipher_init(cipher, MBEDTLS_ENCRYPT, key, IV); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "cipher_init failed"); ++ SSH_LOG(SSH_LOG_TRACE, "cipher_init failed"); + goto error; + } + + rc = mbedtls_cipher_reset(&cipher->encrypt_ctx); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed"); ++ SSH_LOG(SSH_LOG_TRACE, "mbedtls_cipher_reset failed"); + goto error; + } + +@@ -534,7 +534,7 @@ cipher_set_encrypt_key_cbc(struct ssh_cipher_struct *cipher, + + rc = cipher_init(cipher, MBEDTLS_ENCRYPT, key, IV); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "cipher_init failed"); ++ SSH_LOG(SSH_LOG_TRACE, "cipher_init failed"); + goto error; + } + +@@ -544,13 +544,13 @@ cipher_set_encrypt_key_cbc(struct ssh_cipher_struct *cipher, + MBEDTLS_PADDING_NONE); + + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_padding_mode failed"); ++ SSH_LOG(SSH_LOG_TRACE, "mbedtls_cipher_set_padding_mode failed"); + goto error; + } + + rc = mbedtls_cipher_reset(&cipher->encrypt_ctx); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed"); ++ SSH_LOG(SSH_LOG_TRACE, "mbedtls_cipher_reset failed"); + goto error; + } + +@@ -577,7 +577,7 @@ cipher_set_key_gcm(struct ssh_cipher_struct *cipher, + key, + cipher_info->key_bitlen); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_gcm_setkey failed"); ++ SSH_LOG(SSH_LOG_TRACE, "mbedtls_gcm_setkey failed"); + goto error; + } + +@@ -600,13 +600,13 @@ cipher_set_decrypt_key(struct ssh_cipher_struct *cipher, + + rc = cipher_init(cipher, MBEDTLS_DECRYPT, key, IV); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "cipher_init failed"); ++ SSH_LOG(SSH_LOG_TRACE, "cipher_init failed"); + goto error; + } + + mbedtls_cipher_reset(&cipher->decrypt_ctx); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed"); ++ SSH_LOG(SSH_LOG_TRACE, "mbedtls_cipher_reset failed"); + goto error; + } + +@@ -625,20 +625,20 @@ cipher_set_decrypt_key_cbc(struct ssh_cipher_struct *cipher, + + rc = cipher_init(cipher, MBEDTLS_DECRYPT, key, IV); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "cipher_init failed"); ++ SSH_LOG(SSH_LOG_TRACE, "cipher_init failed"); + goto error; + } + + rc = mbedtls_cipher_set_padding_mode(&cipher->decrypt_ctx, + MBEDTLS_PADDING_NONE); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_set_padding_mode failed"); ++ SSH_LOG(SSH_LOG_TRACE, "mbedtls_cipher_set_padding_mode failed"); + goto error; + } + + mbedtls_cipher_reset(&cipher->decrypt_ctx); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed"); ++ SSH_LOG(SSH_LOG_TRACE, "mbedtls_cipher_reset failed"); + goto error; + } + +@@ -658,7 +658,7 @@ static void cipher_encrypt(struct ssh_cipher_struct *cipher, + int rc = 0; + rc = mbedtls_cipher_update(&cipher->encrypt_ctx, in, len, out, &outlen); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update failed during encryption"); ++ SSH_LOG(SSH_LOG_TRACE, "mbedtls_cipher_update failed during encryption"); + return; + } + +@@ -674,12 +674,12 @@ static void cipher_encrypt(struct ssh_cipher_struct *cipher, + total_len += outlen; + + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_finish failed during encryption"); ++ SSH_LOG(SSH_LOG_TRACE, "mbedtls_cipher_finish failed during encryption"); + return; + } + + if (total_len != len) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update: output size %zu for %zu", ++ SSH_LOG(SSH_LOG_DEBUG, "mbedtls_cipher_update: output size %zu for %zu", + outlen, len); + return; + } +@@ -693,12 +693,12 @@ static void cipher_encrypt_cbc(struct ssh_cipher_struct *cipher, void *in, void + int rc = 0; + rc = mbedtls_cipher_update(&cipher->encrypt_ctx, in, len, out, &outlen); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update failed during encryption"); ++ SSH_LOG(SSH_LOG_TRACE, "mbedtls_cipher_update failed during encryption"); + return; + } + + if (outlen != len) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update: output size %zu for %zu", ++ SSH_LOG(SSH_LOG_DEBUG "mbedtls_cipher_update: output size %zu for %zu", + outlen, len); + return; + } +@@ -716,7 +716,7 @@ static void cipher_decrypt(struct ssh_cipher_struct *cipher, + + rc = mbedtls_cipher_update(&cipher->decrypt_ctx, in, len, out, &outlen); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update failed during decryption"); ++ SSH_LOG(SSH_LOG_TRACE, "mbedtls_cipher_update failed during decryption"); + return; + } + +@@ -730,14 +730,14 @@ static void cipher_decrypt(struct ssh_cipher_struct *cipher, + outlen, &outlen); + + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed during decryption"); ++ SSH_LOG(SSH_LOG_TRACE, "mbedtls_cipher_reset failed during decryption"); + return; + } + + total_len += outlen; + + if (total_len != len) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update: output size %zu for %zu", ++ SSH_LOG(SSH_LOG_DEBUG, "mbedtls_cipher_update: output size %zu for %zu", + outlen, len); + return; + } +@@ -751,7 +751,7 @@ static void cipher_decrypt_cbc(struct ssh_cipher_struct *cipher, void *in, void + int rc = 0; + rc = mbedtls_cipher_update(&cipher->decrypt_ctx, in, len, out, &outlen); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update failed during decryption"); ++ SSH_LOG(SSH_LOG_TRACE, "mbedtls_cipher_update failed during decryption"); + return; + } + +@@ -770,19 +770,19 @@ static void cipher_decrypt_cbc(struct ssh_cipher_struct *cipher, void *in, void + } + + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_finish failed during decryption"); ++ SSH_LOG(SSH_LOG_TRACE, "mbedtls_cipher_finish failed during decryption"); + return; + } + + rc = mbedtls_cipher_reset(&cipher->decrypt_ctx); + + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_reset failed during decryption"); ++ SSH_LOG(SSH_LOG_TRACE, "mbedtls_cipher_reset failed during decryption"); + return; + } + + if (outlen != len) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_cipher_update: output size %zu for %zu", ++ SSH_LOG(SSH_LOG_DEBUG, "mbedtls_cipher_update: output size %zu for %zu", + outlen, len); + return; + } +@@ -836,7 +836,7 @@ cipher_encrypt_gcm(struct ssh_cipher_struct *cipher, + authlen, + tag); /* tag */ + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_gcm_crypt_and_tag failed"); ++ SSH_LOG(SSH_LOG_TRACE, "mbedtls_gcm_crypt_and_tag failed"); + return; + } + +@@ -870,7 +870,7 @@ cipher_decrypt_gcm(struct ssh_cipher_struct *cipher, + (const uint8_t *)complete_packet + aadlen, /* input */ + (unsigned char *)out); /* output */ + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARNING, "mbedtls_gcm_auth_decrypt failed"); ++ SSH_LOG(SSH_LOG_TRACE, "mbedtls_gcm_auth_decrypt failed"); + return SSH_ERROR; + } + +diff --git a/src/messages.c b/src/messages.c +index a772d488..2f4f99f8 100644 +--- a/src/messages.c ++++ b/src/messages.c +@@ -160,7 +160,7 @@ static int ssh_execute_server_request(ssh_session session, ssh_message msg) + if (channel != NULL) { + rc = ssh_message_channel_request_open_reply_accept_channel(msg, channel); + if (rc != SSH_OK) { +- SSH_LOG(SSH_LOG_WARNING, ++ SSH_LOG(SSH_LOG_TRACE, + "Failed to send reply for accepting a channel " + "open"); + } +@@ -237,7 +237,7 @@ static int ssh_execute_server_request(ssh_session session, ssh_message msg) + msg->channel_request.pxwidth, + msg->channel_request.pxheight); + if (rc != SSH_OK) { +- SSH_LOG(SSH_LOG_WARNING, ++ SSH_LOG(SSH_LOG_TRACE, + "Failed to iterate callbacks for window change"); + } + return SSH_OK; +@@ -494,8 +494,11 @@ ssh_message ssh_message_pop_head(ssh_session session){ + static int ssh_message_termination(void *s){ + ssh_session session = s; + struct ssh_iterator *it; +- if(session->session_state == SSH_SESSION_STATE_ERROR) ++ if (session->session_state == SSH_SESSION_STATE_ERROR) { ++ // TODO not sure of this ++ SSH_LOG(SSH_LOG_WARN, "Error: %s", ssh_get_error(session)); + return 1; ++ } + it = ssh_list_get_iterator(session->ssh_message_list); + if(!it) + return 0; +@@ -774,7 +777,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request){ + + cmp = strcmp(service, "ssh-connection"); + if (cmp != 0) { +- SSH_LOG(SSH_LOG_WARNING, ++ SSH_LOG(SSH_LOG_TRACE, + "Invalid service request: %s", + service); + goto end; +@@ -1046,7 +1049,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){ + } + + if (session->kbdint == NULL) { +- SSH_LOG(SSH_LOG_PROTOCOL, "Warning: Got a keyboard-interactive " ++ SSH_LOG(SSH_LOG_DEBUG, "Warning: Got a keyboard-interactive " + "response but it seems we didn't send the request."); + + session->kbdint = ssh_kbdint_new(); +@@ -1080,7 +1083,7 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_info_response){ + + if(nanswers != session->kbdint->nprompts) { + /* warn but let the application handle this case */ +- SSH_LOG(SSH_LOG_PROTOCOL, "Warning: Number of prompts and answers" ++ SSH_LOG(SSH_LOG_DEBUG, "Warning: Number of prompts and answers" + " mismatch: p=%u a=%u", session->kbdint->nprompts, nanswers); + } + session->kbdint->nanswers = nanswers; +@@ -1487,7 +1490,7 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){ + (void)type; + (void)packet; + +- SSH_LOG(SSH_LOG_PROTOCOL,"Received SSH_MSG_GLOBAL_REQUEST packet"); ++ SSH_LOG(SSH_LOG_DEBUG,"Received SSH_MSG_GLOBAL_REQUEST packet"); + r = ssh_buffer_unpack(packet, "sb", + &request, + &want_reply); +@@ -1519,12 +1522,12 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){ + msg->global_request.type = SSH_GLOBAL_REQUEST_TCPIP_FORWARD; + msg->global_request.want_reply = want_reply; + +- SSH_LOG(SSH_LOG_PROTOCOL, "Received SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, ++ SSH_LOG(SSH_LOG_DEBUG, "Received SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, + msg->global_request.bind_address, + msg->global_request.bind_port); + + if(ssh_callbacks_exists(session->common.callbacks, global_request_function)) { +- SSH_LOG(SSH_LOG_PROTOCOL, "Calling callback for SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, ++ SSH_LOG(SSH_LOG_DEBUG, "Calling callback for SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, + want_reply, msg->global_request.bind_address, + msg->global_request.bind_port); + session->common.callbacks->global_request_function(session, msg, session->common.callbacks->userdata); +@@ -1549,7 +1552,7 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){ + msg->global_request.type = SSH_GLOBAL_REQUEST_CANCEL_TCPIP_FORWARD; + msg->global_request.want_reply = want_reply; + +- SSH_LOG(SSH_LOG_PROTOCOL, "Received SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, ++ SSH_LOG(SSH_LOG_DEBUG, "Received SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, + msg->global_request.bind_address, + msg->global_request.bind_port); + +@@ -1563,14 +1566,14 @@ SSH_PACKET_CALLBACK(ssh_packet_global_request){ + } else if(strcmp(request, "keepalive@openssh.com") == 0) { + msg->global_request.type = SSH_GLOBAL_REQUEST_KEEPALIVE; + msg->global_request.want_reply = want_reply; +- SSH_LOG(SSH_LOG_PROTOCOL, "Received keepalive@openssh.com %d", want_reply); ++ SSH_LOG(SSH_LOG_DEBUG, "Received keepalive@openssh.com %d", want_reply); + if(ssh_callbacks_exists(session->common.callbacks, global_request_function)) { + session->common.callbacks->global_request_function(session, msg, session->common.callbacks->userdata); + } else { + ssh_message_global_request_reply_success(msg, 0); + } + } else { +- SSH_LOG(SSH_LOG_PROTOCOL, "UNKNOWN SSH_MSG_GLOBAL_REQUEST %s, " ++ SSH_LOG(SSH_LOG_DEBUG, "UNKNOWN SSH_MSG_GLOBAL_REQUEST %s, " + "want_reply = %d", request, want_reply); + goto reply_with_failure; + } +@@ -1603,7 +1606,7 @@ reply_with_failure: + error: + SAFE_FREE(msg); + SAFE_FREE(request); +- SSH_LOG(SSH_LOG_WARNING, "Invalid SSH_MSG_GLOBAL_REQUEST packet"); ++ SSH_LOG(SSH_LOG_TRACE, "Invalid SSH_MSG_GLOBAL_REQUEST packet"); + return rc; + } + +diff --git a/src/misc.c b/src/misc.c +index 0f1a7d49..0429ffac 100644 +--- a/src/misc.c ++++ b/src/misc.c +@@ -622,7 +622,7 @@ void ssh_log_hexdump(const char *descr, const unsigned char *what, size_t len) + return; + + error: +- SSH_LOG(SSH_LOG_WARN, "Could not print to buffer"); ++ SSH_LOG(SSH_LOG_DEBUG, "Could not print to buffer"); + return; + } + +@@ -1249,7 +1249,7 @@ int ssh_analyze_banner(ssh_session session, int server) + return -1; + } + +- SSH_LOG(SSH_LOG_PROTOCOL, "Analyzing banner: %s", banner); ++ SSH_LOG(SSH_LOG_DEBUG, "Analyzing banner: %s", banner); + + switch (banner[4]) { + case '2': +@@ -1299,7 +1299,7 @@ int ssh_analyze_banner(ssh_session session, int server) + + session->openssh = SSH_VERSION_INT(((int) major), ((int) minor), 0); + +- SSH_LOG(SSH_LOG_PROTOCOL, ++ SSH_LOG(SSH_LOG_DEBUG, + "We are talking to an OpenSSH client version: %lu.%lu (%x)", + major, minor, session->openssh); + } +@@ -1393,7 +1393,7 @@ int ssh_timeout_elapsed(struct ssh_timestamp *ts, int timeout) { + * -2 means user-defined timeout as available in + * session->timeout, session->timeout_usec. + */ +- SSH_LOG(SSH_LOG_WARN, "ssh_timeout_elapsed called with -2. this needs to " ++ SSH_LOG(SSH_LOG_DEBUG, "ssh_timeout_elapsed called with -2. this needs to " + "be fixed. please set a breakpoint on misc.c:%d and " + "fix the caller\n", __LINE__); + return 0; +@@ -1546,20 +1546,20 @@ int ssh_quote_file_name(const char *file_name, char *buf, size_t buf_len) + enum ssh_quote_state_e state = NO_QUOTE; + + if (file_name == NULL || buf == NULL || buf_len == 0) { +- SSH_LOG(SSH_LOG_WARNING, "Invalid parameter"); ++ SSH_LOG(SSH_LOG_TRACE, "Invalid parameter"); + return SSH_ERROR; + } + + /* Only allow file names smaller than 32kb. */ + if (strlen(file_name) > 32 * 1024) { +- SSH_LOG(SSH_LOG_WARNING, "File name too long"); ++ SSH_LOG(SSH_LOG_TRACE, "File name too long"); + return SSH_ERROR; + } + + /* Paranoia check */ + required_buf_len = (size_t)3 * strlen(file_name) + 1; + if (required_buf_len > buf_len) { +- SSH_LOG(SSH_LOG_WARNING, "Buffer too small"); ++ SSH_LOG(SSH_LOG_TRACE, "Buffer too small"); + return SSH_ERROR; + } + +@@ -1717,7 +1717,7 @@ int ssh_newline_vis(const char *string, char *buf, size_t buf_len) + } + + if ((2 * strlen(string) + 1) > buf_len) { +- SSH_LOG(SSH_LOG_WARNING, "Buffer too small"); ++ SSH_LOG(SSH_LOG_TRACE, "Buffer too small"); + return SSH_ERROR; + } + +diff --git a/src/packet.c b/src/packet.c +index ec4a7203..c9555ba0 100644 +--- a/src/packet.c ++++ b/src/packet.c +@@ -1543,7 +1543,7 @@ SSH_PACKET_CALLBACK(ssh_packet_unimplemented){ + + rc = ssh_buffer_unpack(packet, "d", &seq); + if (rc != SSH_OK) { +- SSH_LOG(SSH_LOG_WARNING, ++ SSH_LOG(SSH_LOG_TRACE, + "Could not unpack SSH_MSG_UNIMPLEMENTED packet"); + } + +@@ -1864,7 +1864,7 @@ ssh_init_rekey_state(struct ssh_session_struct *session, + session->opts.rekey_data / cipher->blocksize); + } + +- SSH_LOG(SSH_LOG_PROTOCOL, ++ SSH_LOG(SSH_LOG_DEBUG, + "Set rekey after %" PRIu64 " blocks", + cipher->max_blocks); + } +@@ -1891,7 +1891,7 @@ ssh_packet_set_newkeys(ssh_session session, + session->next_crypto->used |= direction; + if (session->current_crypto != NULL) { + if (session->current_crypto->used & direction) { +- SSH_LOG(SSH_LOG_WARNING, "This direction isn't used anymore."); ++ SSH_LOG(SSH_LOG_TRACE, "This direction isn't used anymore."); + } + /* Mark the current requested direction unused */ + session->current_crypto->used &= ~direction; +@@ -1966,7 +1966,7 @@ ssh_packet_set_newkeys(ssh_session session, + session->next_crypto->in_cipher); + if (session->opts.rekey_time != 0) { + ssh_timestamp_init(&session->last_rekey_time); +- SSH_LOG(SSH_LOG_PROTOCOL, "Set rekey after %" PRIu32 " seconds", ++ SSH_LOG(SSH_LOG_DEBUG, "Set rekey after %" PRIu32 " seconds", + session->opts.rekey_time/1000); + } + +diff --git a/src/packet_cb.c b/src/packet_cb.c +index 39575b17..98d21b12 100644 +--- a/src/packet_cb.c ++++ b/src/packet_cb.c +@@ -87,7 +87,7 @@ SSH_PACKET_CALLBACK(ssh_packet_ignore_callback){ + (void)user; + (void)type; + (void)packet; +- SSH_LOG(SSH_LOG_PROTOCOL,"Received %s packet",type==SSH2_MSG_IGNORE ? "SSH_MSG_IGNORE" : "SSH_MSG_DEBUG"); ++ SSH_LOG(SSH_LOG_DEBUG,"Received %s packet",type==SSH2_MSG_IGNORE ? "SSH_MSG_IGNORE" : "SSH_MSG_DEBUG"); + /* TODO: handle a graceful disconnect */ + return SSH_PACKET_USED; + } +@@ -99,7 +99,7 @@ SSH_PACKET_CALLBACK(ssh_packet_newkeys){ + (void)packet; + (void)user; + (void)type; +- SSH_LOG(SSH_LOG_PROTOCOL, "Received SSH_MSG_NEWKEYS"); ++ SSH_LOG(SSH_LOG_DEBUG, "Received SSH_MSG_NEWKEYS"); + + if (session->session_state != SSH_SESSION_STATE_DH || + session->dh_handshake_state != DH_STATE_NEWKEYS_SENT) { +@@ -158,7 +158,7 @@ SSH_PACKET_CALLBACK(ssh_packet_newkeys){ + if (rc == SSH_ERROR) { + goto error; + } +- SSH_LOG(SSH_LOG_PROTOCOL,"Signature verified and valid"); ++ SSH_LOG(SSH_LOG_DEBUG,"Signature verified and valid"); + + /* When receiving this packet, we switch on the incomming crypto. */ + rc = ssh_packet_set_newkeys(session, SSH_DIRECTION_IN); +diff --git a/src/pki.c b/src/pki.c +index 932abf2c..db808355 100644 +--- a/src/pki.c ++++ b/src/pki.c +@@ -330,7 +330,7 @@ enum ssh_digest_e ssh_key_hash_from_name(const char *name) + return SSH_DIGEST_AUTO; + } + +- SSH_LOG(SSH_LOG_WARN, "Unknown signature name %s", name); ++ SSH_LOG(SSH_LOG_TRACE, "Unknown signature name %s", name); + + /* TODO we should rather fail */ + return SSH_DIGEST_AUTO; +@@ -362,13 +362,13 @@ int ssh_key_algorithm_allowed(ssh_session session, const char *type) + else if (session->server) { + allowed_list = session->opts.wanted_methods[SSH_HOSTKEYS]; + if (allowed_list == NULL) { +- SSH_LOG(SSH_LOG_WARN, "Session invalid: no host key available"); ++ SSH_LOG(SSH_LOG_TRACE, "Session invalid: no host key available"); + return 0; + } + } + #endif + else { +- SSH_LOG(SSH_LOG_WARN, "Session invalid: not set as client nor server"); ++ SSH_LOG(SSH_LOG_TRACE, "Session invalid: not set as client nor server"); + return 0; + } + +@@ -438,7 +438,7 @@ enum ssh_digest_e ssh_key_type_to_hash(ssh_session session, + case SSH_KEYTYPE_ECDSA: + case SSH_KEYTYPE_UNKNOWN: + default: +- SSH_LOG(SSH_LOG_WARN, "Digest algorithm to be used with key type %u " ++ SSH_LOG(SSH_LOG_TRACE, "Digest algorithm to be used with key type %u " + "is not defined", type); + } + +@@ -625,7 +625,7 @@ int ssh_key_cmp(const ssh_key k1, + } + + if (k1->type != k2->type) { +- SSH_LOG(SSH_LOG_WARN, "key types don't match!"); ++ SSH_LOG(SSH_LOG_DEBUG, "key types don't match!"); + return 1; + } + +@@ -744,7 +744,7 @@ int ssh_pki_import_privkey_base64(const char *b64_key, + return SSH_ERROR; + } + +- SSH_LOG(SSH_LOG_INFO, ++ SSH_LOG(SSH_LOG_DEBUG, + "Trying to decode privkey passphrase=%s", + passphrase ? "true" : "false"); + +@@ -864,7 +864,7 @@ int ssh_pki_import_privkey_file(const char *filename, + + file = fopen(filename, "rb"); + if (file == NULL) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Error opening %s: %s", + filename, + strerror(errno)); +@@ -874,7 +874,7 @@ int ssh_pki_import_privkey_file(const char *filename, + rc = fstat(fileno(file), &sb); + if (rc < 0) { + fclose(file); +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Error getting stat of %s: %s", + filename, + strerror(errno)); +@@ -888,7 +888,7 @@ int ssh_pki_import_privkey_file(const char *filename, + } + + if (sb.st_size > MAX_PRIVKEY_SIZE) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Private key is bigger than 4M."); + fclose(file); + return SSH_ERROR; +@@ -897,7 +897,7 @@ int ssh_pki_import_privkey_file(const char *filename, + key_buf = malloc(sb.st_size + 1); + if (key_buf == NULL) { + fclose(file); +- SSH_LOG(SSH_LOG_WARN, "Out of memory!"); ++ SSH_LOG(SSH_LOG_TRACE, "Out of memory!"); + return SSH_ERROR; + } + +@@ -906,7 +906,7 @@ int ssh_pki_import_privkey_file(const char *filename, + + if (size != sb.st_size) { + SAFE_FREE(key_buf); +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Error reading %s: %s", + filename, + strerror(errno)); +@@ -1068,7 +1068,7 @@ int pki_import_privkey_buffer(enum ssh_keytypes_e type, + rc = ssh_buffer_unpack(buffer, "SSSSS", &p, &q, &g, + &pubkey, &privkey); + if (rc != SSH_OK) { +- SSH_LOG(SSH_LOG_WARN, "Unpack error"); ++ SSH_LOG(SSH_LOG_TRACE, "Unpack error"); + goto fail; + } + +@@ -1109,7 +1109,7 @@ int pki_import_privkey_buffer(enum ssh_keytypes_e type, + rc = ssh_buffer_unpack(buffer, "SSSSSS", &n, &e, &d, + &iqmp, &p, &q); + if (rc != SSH_OK) { +- SSH_LOG(SSH_LOG_WARN, "Unpack error"); ++ SSH_LOG(SSH_LOG_TRACE, "Unpack error"); + goto fail; + } + +@@ -1136,7 +1136,7 @@ int pki_import_privkey_buffer(enum ssh_keytypes_e type, + ssh_string_burn(q); + SSH_STRING_FREE(q); + if (rc == SSH_ERROR) { +- SSH_LOG(SSH_LOG_WARN, "Failed to build RSA private key"); ++ SSH_LOG(SSH_LOG_TRACE, "Failed to build RSA private key"); + goto fail; + } + } +@@ -1153,7 +1153,7 @@ int pki_import_privkey_buffer(enum ssh_keytypes_e type, + + rc = ssh_buffer_unpack(buffer, "SSS", &i, &e, &exp); + if (rc != SSH_OK) { +- SSH_LOG(SSH_LOG_WARN, "Unpack error"); ++ SSH_LOG(SSH_LOG_TRACE, "Unpack error"); + goto fail; + } + +@@ -1173,7 +1173,7 @@ int pki_import_privkey_buffer(enum ssh_keytypes_e type, + ssh_string_burn(exp); + SSH_STRING_FREE(exp); + if (rc < 0) { +- SSH_LOG(SSH_LOG_WARN, "Failed to build ECDSA private key"); ++ SSH_LOG(SSH_LOG_TRACE, "Failed to build ECDSA private key"); + goto fail; + } + } +@@ -1185,7 +1185,7 @@ int pki_import_privkey_buffer(enum ssh_keytypes_e type, + + rc = ssh_buffer_unpack(buffer, "SS", &pubkey, &privkey); + if (rc != SSH_OK){ +- SSH_LOG(SSH_LOG_WARN, "Unpack error"); ++ SSH_LOG(SSH_LOG_TRACE, "Unpack error"); + goto fail; + } + +@@ -1194,7 +1194,7 @@ int pki_import_privkey_buffer(enum ssh_keytypes_e type, + SSH_STRING_FREE(privkey); + SSH_STRING_FREE(pubkey); + if (rc != SSH_OK) { +- SSH_LOG(SSH_LOG_WARN, "Failed to build ed25519 key"); ++ SSH_LOG(SSH_LOG_TRACE, "Failed to build ed25519 key"); + goto fail; + } + } +@@ -1208,7 +1208,7 @@ int pki_import_privkey_buffer(enum ssh_keytypes_e type, + case SSH_KEYTYPE_RSA1: + case SSH_KEYTYPE_UNKNOWN: + default: +- SSH_LOG(SSH_LOG_WARN, "Unknown private key type (%d)", type); ++ SSH_LOG(SSH_LOG_TRACE, "Unknown private key type (%d)", type); + goto fail; + } + +@@ -1245,7 +1245,7 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer, + + rc = ssh_buffer_unpack(buffer, "SSSS", &p, &q, &g, &pubkey); + if (rc != SSH_OK) { +- SSH_LOG(SSH_LOG_WARN, "Unpack error"); ++ SSH_LOG(SSH_LOG_TRACE, "Unpack error"); + goto fail; + } + +@@ -1264,7 +1264,7 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer, + ssh_string_burn(pubkey); + SSH_STRING_FREE(pubkey); + if (rc == SSH_ERROR) { +- SSH_LOG(SSH_LOG_WARN, "Failed to build DSA public key"); ++ SSH_LOG(SSH_LOG_TRACE, "Failed to build DSA public key"); + goto fail; + } + } +@@ -1276,7 +1276,7 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer, + + rc = ssh_buffer_unpack(buffer, "SS", &e, &n); + if (rc != SSH_OK) { +- SSH_LOG(SSH_LOG_WARN, "Unpack error"); ++ SSH_LOG(SSH_LOG_TRACE, "Unpack error"); + goto fail; + } + +@@ -1290,7 +1290,7 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer, + ssh_string_burn(n); + SSH_STRING_FREE(n); + if (rc == SSH_ERROR) { +- SSH_LOG(SSH_LOG_WARN, "Failed to build RSA public key"); ++ SSH_LOG(SSH_LOG_TRACE, "Failed to build RSA public key"); + goto fail; + } + } +@@ -1307,7 +1307,7 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer, + + rc = ssh_buffer_unpack(buffer, "SS", &i, &e); + if (rc != SSH_OK) { +- SSH_LOG(SSH_LOG_WARN, "Unpack error"); ++ SSH_LOG(SSH_LOG_TRACE, "Unpack error"); + goto fail; + } + +@@ -1321,7 +1321,7 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer, + ssh_string_burn(e); + SSH_STRING_FREE(e); + if (rc < 0) { +- SSH_LOG(SSH_LOG_WARN, "Failed to build ECDSA public key"); ++ SSH_LOG(SSH_LOG_TRACE, "Failed to build ECDSA public key"); + goto fail; + } + +@@ -1336,7 +1336,7 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer, + { + ssh_string pubkey = ssh_buffer_get_ssh_string(buffer); + if (ssh_string_len(pubkey) != ED25519_KEY_LEN) { +- SSH_LOG(SSH_LOG_WARN, "Invalid public key length"); ++ SSH_LOG(SSH_LOG_TRACE, "Invalid public key length"); + ssh_string_burn(pubkey); + SSH_STRING_FREE(pubkey); + goto fail; +@@ -1363,7 +1363,7 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer, + case SSH_KEYTYPE_RSA1: + case SSH_KEYTYPE_UNKNOWN: + default: +- SSH_LOG(SSH_LOG_WARN, "Unknown public key protocol %d", type); ++ SSH_LOG(SSH_LOG_TRACE, "Unknown public key protocol %d", type); + goto fail; + } + +@@ -1532,26 +1532,26 @@ int ssh_pki_import_pubkey_blob(const ssh_string key_blob, + + buffer = ssh_buffer_new(); + if (buffer == NULL) { +- SSH_LOG(SSH_LOG_WARN, "Out of memory!"); ++ SSH_LOG(SSH_LOG_TRACE, "Out of memory!"); + return SSH_ERROR; + } + + rc = ssh_buffer_add_data(buffer, ssh_string_data(key_blob), + ssh_string_len(key_blob)); + if (rc < 0) { +- SSH_LOG(SSH_LOG_WARN, "Out of memory!"); ++ SSH_LOG(SSH_LOG_TRACE, "Out of memory!"); + goto fail; + } + + type_s = ssh_buffer_get_ssh_string(buffer); + if (type_s == NULL) { +- SSH_LOG(SSH_LOG_WARN, "Out of memory!"); ++ SSH_LOG(SSH_LOG_TRACE, "Out of memory!"); + goto fail; + } + + type = ssh_key_type_from_name(ssh_string_get_char(type_s)); + if (type == SSH_KEYTYPE_UNKNOWN) { +- SSH_LOG(SSH_LOG_WARN, "Unknown key type found!"); ++ SSH_LOG(SSH_LOG_TRACE, "Unknown key type found!"); + goto fail; + } + SSH_STRING_FREE(type_s); +@@ -1602,7 +1602,7 @@ int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey) + + file = fopen(filename, "rb"); + if (file == NULL) { +- SSH_LOG(SSH_LOG_WARN, "Error opening %s: %s", ++ SSH_LOG(SSH_LOG_TRACE, "Error opening %s: %s", + filename, strerror(errno)); + return SSH_EOF; + } +@@ -1610,7 +1610,7 @@ int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey) + rc = fstat(fileno(file), &sb); + if (rc < 0) { + fclose(file); +- SSH_LOG(SSH_LOG_WARN, "Error gettint stat of %s: %s", ++ SSH_LOG(SSH_LOG_TRACE, "Error gettint stat of %s: %s", + filename, strerror(errno)); + switch (errno) { + case ENOENT: +@@ -1628,7 +1628,7 @@ int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey) + key_buf = malloc(sb.st_size + 1); + if (key_buf == NULL) { + fclose(file); +- SSH_LOG(SSH_LOG_WARN, "Out of memory!"); ++ SSH_LOG(SSH_LOG_TRACE, "Out of memory!"); + return SSH_ERROR; + } + +@@ -1637,7 +1637,7 @@ int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey) + + if (size != sb.st_size) { + SAFE_FREE(key_buf); +- SSH_LOG(SSH_LOG_WARN, "Error reading %s: %s", ++ SSH_LOG(SSH_LOG_TRACE, "Error reading %s: %s", + filename, strerror(errno)); + return SSH_ERROR; + } +@@ -1650,7 +1650,7 @@ int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey) + *pkey = ssh_pki_openssh_pubkey_import(key_buf); + SAFE_FREE(key_buf); + if (*pkey == NULL) { +- SSH_LOG(SSH_LOG_WARN, "Failed to import public key from OpenSSH" ++ SSH_LOG(SSH_LOG_TRACE, "Failed to import public key from OpenSSH" + " private key file"); + return SSH_ERROR; + } +@@ -2183,7 +2183,7 @@ int pki_key_check_hash_compatible(ssh_key key, + case SSH_KEYTYPE_DSS: + if (hash_type == SSH_DIGEST_SHA1) { + if (ssh_fips_mode()) { +- SSH_LOG(SSH_LOG_WARN, "SHA1 is not allowed in FIPS mode"); ++ SSH_LOG(SSH_LOG_TRACE, "SHA1 is not allowed in FIPS mode"); + return SSH_ERROR; + } else { + return SSH_OK; +@@ -2194,7 +2194,7 @@ int pki_key_check_hash_compatible(ssh_key key, + case SSH_KEYTYPE_RSA: + if (hash_type == SSH_DIGEST_SHA1) { + if (ssh_fips_mode()) { +- SSH_LOG(SSH_LOG_WARN, "SHA1 is not allowed in FIPS mode"); ++ SSH_LOG(SSH_LOG_TRACE, "SHA1 is not allowed in FIPS mode"); + return SSH_ERROR; + } else { + return SSH_OK; +@@ -2234,11 +2234,11 @@ int pki_key_check_hash_compatible(ssh_key key, + case SSH_KEYTYPE_RSA1: + case SSH_KEYTYPE_ECDSA: + case SSH_KEYTYPE_UNKNOWN: +- SSH_LOG(SSH_LOG_WARN, "Unknown key type %d", key->type); ++ SSH_LOG(SSH_LOG_TRACE, "Unknown key type %d", key->type); + return SSH_ERROR; + } + +- SSH_LOG(SSH_LOG_WARN, "Key type %d incompatible with hash type %d", ++ SSH_LOG(SSH_LOG_TRACE, "Key type %d incompatible with hash type %d", + key->type, hash_type); + + return SSH_ERROR; +@@ -2265,7 +2265,7 @@ int ssh_pki_signature_verify(ssh_session session, + sig->type_c); + + if (key_type != sig->type) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Can not verify %s signature with %s key", + sig->type_c, key->type_c); + return SSH_ERROR; +diff --git a/src/pki_container_openssh.c b/src/pki_container_openssh.c +index ecde4cdd..dadeefaa 100644 +--- a/src/pki_container_openssh.c ++++ b/src/pki_container_openssh.c +@@ -69,20 +69,20 @@ static int pki_openssh_import_privkey_blob(ssh_buffer key_blob_buffer, + + rc = ssh_buffer_unpack(key_blob_buffer, "s", &type_s); + if (rc == SSH_ERROR){ +- SSH_LOG(SSH_LOG_WARN, "Unpack error"); ++ SSH_LOG(SSH_LOG_TRACE, "Unpack error"); + return SSH_ERROR; + } + + type = ssh_key_type_from_name(type_s); + if (type == SSH_KEYTYPE_UNKNOWN) { +- SSH_LOG(SSH_LOG_WARN, "Unknown key type '%s' found!", type_s); ++ SSH_LOG(SSH_LOG_TRACE, "Unknown key type '%s' found!", type_s); + return SSH_ERROR; + } + SAFE_FREE(type_s); + + rc = pki_import_privkey_buffer(type, key_blob_buffer, &key); + if (rc != SSH_OK) { +- SSH_LOG(SSH_LOG_WARN, "Failed to read key in OpenSSH format"); ++ SSH_LOG(SSH_LOG_TRACE, "Failed to read key in OpenSSH format"); + goto fail; + } + +@@ -133,17 +133,17 @@ static int pki_private_key_decrypt(ssh_string blob, + } + + if (ciphers[i].name == NULL){ +- SSH_LOG(SSH_LOG_WARN, "Unsupported cipher %s", ciphername); ++ SSH_LOG(SSH_LOG_TRACE, "Unsupported cipher %s", ciphername); + return SSH_ERROR; + } + + cmp = strcmp(kdfname, "bcrypt"); + if (cmp != 0) { +- SSH_LOG(SSH_LOG_WARN, "Unsupported KDF %s", kdfname); ++ SSH_LOG(SSH_LOG_TRACE, "Unsupported KDF %s", kdfname); + return SSH_ERROR; + } + if (ssh_string_len(blob) % cipher.blocksize != 0) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Encrypted string not multiple of blocksize: %zu", + ssh_string_len(blob)); + return SSH_ERROR; +@@ -167,7 +167,7 @@ static int pki_private_key_decrypt(ssh_string blob, + /* We need material for key (keysize bits / 8) and IV (blocksize) */ + key_material_len = cipher.keysize/8 + cipher.blocksize; + if (key_material_len > sizeof(key_material)) { +- SSH_LOG(SSH_LOG_WARN, "Key material too big"); ++ SSH_LOG(SSH_LOG_TRACE, "Key material too big"); + return SSH_ERROR; + } + +@@ -181,7 +181,7 @@ static int pki_private_key_decrypt(ssh_string blob, + if (passphrase == NULL) { + if (auth_fn == NULL) { + SAFE_FREE(salt); +- SSH_LOG(SSH_LOG_WARN, "No passphrase provided"); ++ SSH_LOG(SSH_LOG_TRACE, "No passphrase provided"); + return SSH_ERROR; + } + rc = auth_fn("Passphrase", +@@ -251,7 +251,7 @@ ssh_pki_openssh_import(const char *text_key, + + cmp = strncmp(ptr, OPENSSH_HEADER_BEGIN, strlen(OPENSSH_HEADER_BEGIN)); + if (cmp != 0) { +- SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (no header)"); ++ SSH_LOG(SSH_LOG_TRACE, "Not an OpenSSH private key (no header)"); + goto out; + } + ptr += strlen(OPENSSH_HEADER_BEGIN); +@@ -260,7 +260,7 @@ ssh_pki_openssh_import(const char *text_key, + } + end = strstr(ptr, OPENSSH_HEADER_END); + if (end == NULL) { +- SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (no footer)"); ++ SSH_LOG(SSH_LOG_TRACE, "Not an OpenSSH private key (no footer)"); + goto out; + } + base64 = malloc(end - ptr + 1); +@@ -277,7 +277,7 @@ ssh_pki_openssh_import(const char *text_key, + buffer = base64_to_bin(base64); + SAFE_FREE(base64); + if (buffer == NULL) { +- SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (base64 error)"); ++ SSH_LOG(SSH_LOG_TRACE, "Not an OpenSSH private key (base64 error)"); + goto out; + } + rc = ssh_buffer_unpack(buffer, "PssSdSS", +@@ -290,21 +290,21 @@ ssh_pki_openssh_import(const char *text_key, + &pubkey0, + &privkeys); + if (rc == SSH_ERROR) { +- SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (unpack error)"); ++ SSH_LOG(SSH_LOG_TRACE, "Not an OpenSSH private key (unpack error)"); + goto out; + } + cmp = strncmp(magic, OPENSSH_AUTH_MAGIC, strlen(OPENSSH_AUTH_MAGIC)); + if (cmp != 0) { +- SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (bad magic)"); ++ SSH_LOG(SSH_LOG_TRACE, "Not an OpenSSH private key (bad magic)"); + goto out; + } +- SSH_LOG(SSH_LOG_INFO, ++ SSH_LOG(SSH_LOG_DEBUG, + "Opening OpenSSH private key: ciphername: %s, kdf: %s, nkeys: %d", + ciphername, + kdfname, + nkeys); + if (nkeys != 1) { +- SSH_LOG(SSH_LOG_WARN, "Opening OpenSSH private key: only 1 key supported (%d available)", nkeys); ++ SSH_LOG(SSH_LOG_TRACE, "Opening OpenSSH private key: only 1 key supported (%d available)", nkeys); + goto out; + } + +@@ -314,7 +314,7 @@ ssh_pki_openssh_import(const char *text_key, + if (!private) { + rc = ssh_pki_import_pubkey_blob(pubkey0, &key); + if (rc != SSH_OK) { +- SSH_LOG(SSH_LOG_WARN, "Failed to import public key blob"); ++ SSH_LOG(SSH_LOG_TRACE, "Failed to import public key blob"); + } + /* in either case we clean up here */ + goto out; +@@ -343,7 +343,7 @@ ssh_pki_openssh_import(const char *text_key, + + rc = ssh_buffer_unpack(privkey_buffer, "dd", &checkint1, &checkint2); + if (rc == SSH_ERROR || checkint1 != checkint2) { +- SSH_LOG(SSH_LOG_WARN, "OpenSSH private key unpack error (correct password?)"); ++ SSH_LOG(SSH_LOG_TRACE, "OpenSSH private key unpack error (correct password?)"); + goto out; + } + rc = pki_openssh_import_privkey_blob(privkey_buffer, &key); +@@ -358,7 +358,7 @@ ssh_pki_openssh_import(const char *text_key, + if (padding != i) { + ssh_key_free(key); + key = NULL; +- SSH_LOG(SSH_LOG_WARN, "Invalid padding"); ++ SSH_LOG(SSH_LOG_TRACE, "Invalid padding"); + goto out; + } + } +@@ -407,7 +407,7 @@ static int pki_openssh_export_privkey_blob(const ssh_key privkey, + int rc; + + if (privkey->type != SSH_KEYTYPE_ED25519) { +- SSH_LOG(SSH_LOG_WARN, "Type %s not supported", privkey->type_c); ++ SSH_LOG(SSH_LOG_TRACE, "Type %s not supported", privkey->type_c); + return SSH_ERROR; + } + if (privkey->ed25519_privkey == NULL || +@@ -462,29 +462,29 @@ static int pki_private_key_encrypt(ssh_buffer privkey_buffer, + } + + if (ciphers[i].name == NULL){ +- SSH_LOG(SSH_LOG_WARN, "Unsupported cipher %s", ciphername); ++ SSH_LOG(SSH_LOG_TRACE, "Unsupported cipher %s", ciphername); + return SSH_ERROR; + } + + cmp = strcmp(kdfname, "bcrypt"); + if (cmp != 0){ +- SSH_LOG(SSH_LOG_WARN, "Unsupported KDF %s", kdfname); ++ SSH_LOG(SSH_LOG_TRACE, "Unsupported KDF %s", kdfname); + return SSH_ERROR; + } + /* We need material for key (keysize bits / 8) and IV (blocksize) */ + key_material_len = cipher.keysize/8 + cipher.blocksize; + if (key_material_len > sizeof(key_material)){ +- SSH_LOG(SSH_LOG_WARN, "Key material too big"); ++ SSH_LOG(SSH_LOG_TRACE, "Key material too big"); + return SSH_ERROR; + } + +- SSH_LOG(SSH_LOG_WARN, "Encryption: %d key, %d IV, %d rounds, %zu bytes salt", ++ SSH_LOG(SSH_LOG_DEBUG, "Encryption: %d key, %d IV, %d rounds, %zu bytes salt", + cipher.keysize/8, + cipher.blocksize, rounds, ssh_string_len(salt)); + + if (passphrase == NULL){ + if (auth_fn == NULL){ +- SSH_LOG(SSH_LOG_WARN, "No passphrase provided"); ++ SSH_LOG(SSH_LOG_TRACE, "No passphrase provided"); + return SSH_ERROR; + } + rc = auth_fn("Passphrase", +@@ -555,11 +555,11 @@ ssh_string ssh_pki_openssh_privkey_export(const ssh_key privkey, + return NULL; + } + if (privkey->type != SSH_KEYTYPE_ED25519){ +- SSH_LOG(SSH_LOG_WARN, "Unsupported key type %s", privkey->type_c); ++ SSH_LOG(SSH_LOG_TRACE, "Unsupported key type %s", privkey->type_c); + return NULL; + } + if (passphrase != NULL || auth_fn != NULL){ +- SSH_LOG(SSH_LOG_INFO, "Enabling encryption for private key export"); ++ SSH_LOG(SSH_LOG_DEBUG, "Enabling encryption for private key export"); + to_encrypt = 1; + } + buffer = ssh_buffer_new(); +diff --git a/src/pki_crypto.c b/src/pki_crypto.c +index ec9cfa4b..e9fe32d3 100644 +--- a/src/pki_crypto.c ++++ b/src/pki_crypto.c +@@ -587,7 +587,7 @@ int pki_key_generate_ecdsa(ssh_key key, int parameter) { + key->type = SSH_KEYTYPE_ECDSA_P256; + break; + default: +- SSH_LOG(SSH_LOG_WARN, "Invalid parameter %d for ECDSA key " ++ SSH_LOG(SSH_LOG_TRACE, "Invalid parameter %d for ECDSA key " + "generation", parameter); + return SSH_ERROR; + } +@@ -779,7 +779,7 @@ ssh_string pki_private_key_to_pem(const ssh_key key, + rc = 1; + break; + #else +- SSH_LOG(SSH_LOG_WARN, "PEM output not supported for key type ssh-ed25519"); ++ SSH_LOG(SSH_LOG_TRACE, "PEM output not supported for key type ssh-ed25519"); + goto err; + #endif + case SSH_KEYTYPE_DSS_CERT01: +@@ -790,11 +790,11 @@ ssh_string pki_private_key_to_pem(const ssh_key key, + case SSH_KEYTYPE_ED25519_CERT01: + case SSH_KEYTYPE_UNKNOWN: + default: +- SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key type %d", key->type); ++ SSH_LOG(SSH_LOG_TRACE, "Unknown or invalid private key type %d", key->type); + goto err; + } + if (rc != 1) { +- SSH_LOG(SSH_LOG_WARN, "Failed to initialize EVP_PKEY structure"); ++ SSH_LOG(SSH_LOG_TRACE, "Failed to initialize EVP_PKEY structure"); + goto err; + } + +@@ -887,8 +887,8 @@ ssh_key pki_private_key_from_base64(const char *b64_key, + BIO_free(mem); + + if (pkey == NULL) { +- SSH_LOG(SSH_LOG_WARN, +- "Parsing private key: %s", ++ SSH_LOG(SSH_LOG_TRACE, ++ "Error parsing private key: %s", + ERR_error_string(ERR_get_error(), NULL)); + return NULL; + } +@@ -896,8 +896,8 @@ ssh_key pki_private_key_from_base64(const char *b64_key, + case EVP_PKEY_DSA: + dsa = EVP_PKEY_get1_DSA(pkey); + if (dsa == NULL) { +- SSH_LOG(SSH_LOG_WARN, +- "Parsing private key: %s", ++ SSH_LOG(SSH_LOG_TRACE, ++ "Error parsing private key: %s", + ERR_error_string(ERR_get_error(),NULL)); + goto fail; + } +@@ -906,8 +906,8 @@ ssh_key pki_private_key_from_base64(const char *b64_key, + case EVP_PKEY_RSA: + rsa = EVP_PKEY_get1_RSA(pkey); + if (rsa == NULL) { +- SSH_LOG(SSH_LOG_WARN, +- "Parsing private key: %s", ++ SSH_LOG(SSH_LOG_TRACE, ++ "Error parsing private key: %s", + ERR_error_string(ERR_get_error(),NULL)); + goto fail; + } +@@ -917,8 +917,8 @@ ssh_key pki_private_key_from_base64(const char *b64_key, + #ifdef HAVE_OPENSSL_ECC + ecdsa = EVP_PKEY_get1_EC_KEY(pkey); + if (ecdsa == NULL) { +- SSH_LOG(SSH_LOG_WARN, +- "Parsing private key: %s", ++ SSH_LOG(SSH_LOG_TRACE, ++ "Error parsing private key: %s", + ERR_error_string(ERR_get_error(), NULL)); + goto fail; + } +@@ -927,7 +927,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key, + * keys, so we need to figure out the correct type here */ + type = pki_key_ecdsa_to_key_type(ecdsa); + if (type == SSH_KEYTYPE_UNKNOWN) { +- SSH_LOG(SSH_LOG_WARN, "Invalid private key."); ++ SSH_LOG(SSH_LOG_TRACE, "Invalid private key."); + goto fail; + } + +@@ -954,7 +954,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key, + + ed25519 = malloc(key_len); + if (ed25519 == NULL) { +- SSH_LOG(SSH_LOG_WARN, "Out of memory"); ++ SSH_LOG(SSH_LOG_TRACE, "Out of memory"); + goto fail; + } + +@@ -972,7 +972,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key, + #endif + default: + EVP_PKEY_free(pkey); +- SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key type %d", ++ SSH_LOG(SSH_LOG_TRACE, "Unknown or invalid private key type %d", + EVP_PKEY_base_id(pkey)); + return NULL; + } +@@ -1571,7 +1571,7 @@ ssh_string pki_signature_to_blob(const ssh_signature sig) + #endif + default: + case SSH_KEYTYPE_UNKNOWN: +- SSH_LOG(SSH_LOG_WARN, "Unknown signature key type: %s", sig->type_c); ++ SSH_LOG(SSH_LOG_TRACE, "Unknown signature key type: %s", sig->type_c); + return NULL; + } + +@@ -1591,13 +1591,13 @@ static int pki_signature_from_rsa_blob(const ssh_key pubkey, + size_t len = ssh_string_len(sig_blob); + + if (pubkey->rsa == NULL) { +- SSH_LOG(SSH_LOG_WARN, "Pubkey RSA field NULL"); ++ SSH_LOG(SSH_LOG_TRACE, "Pubkey RSA field NULL"); + goto errout; + } + + rsalen = RSA_size(pubkey->rsa); + if (len > rsalen) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Signature is too big: %lu > %lu", + (unsigned long)len, + (unsigned long)rsalen); +@@ -1605,7 +1605,7 @@ static int pki_signature_from_rsa_blob(const ssh_key pubkey, + } + + #ifdef DEBUG_CRYPTO +- SSH_LOG(SSH_LOG_WARN, "RSA signature len: %lu", (unsigned long)len); ++ SSH_LOG(SSH_LOG_DEBUG, "RSA signature len: %lu", (unsigned long)len); + ssh_log_hexdump("RSA signature", ssh_string_data(sig_blob), len); + #endif + +@@ -1669,7 +1669,7 @@ static int pki_signature_from_dsa_blob(UNUSED_PARAM(const ssh_key pubkey), + + /* 40 is the dual signature blob len. */ + if (len != 40) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Signature has wrong size: %lu", + (unsigned long)len); + goto error; +@@ -1832,7 +1832,7 @@ static int pki_signature_from_ecdsa_blob(UNUSED_PARAM(const ssh_key pubkey), + if (rlen != 0) { + ssh_string_burn(s); + SSH_STRING_FREE(s); +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Signature has remaining bytes in inner " + "sigblob: %lu", + (unsigned long)rlen); +@@ -1921,7 +1921,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, + int rc; + + if (ssh_key_type_plain(pubkey->type) != type) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Incompatible public key provided (%d) expecting (%d)", + type, + pubkey->type); +@@ -1972,7 +1972,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, + #endif + default: + case SSH_KEYTYPE_UNKNOWN: +- SSH_LOG(SSH_LOG_WARN, "Unknown signature type"); ++ SSH_LOG(SSH_LOG_TRACE, "Unknown signature type"); + goto error; + } + +diff --git a/src/pki_ed25519_common.c b/src/pki_ed25519_common.c +index 7aa05269..15c9abef 100644 +--- a/src/pki_ed25519_common.c ++++ b/src/pki_ed25519_common.c +@@ -34,7 +34,7 @@ int pki_privkey_build_ed25519(ssh_key key, + if (ssh_string_len(pubkey) != ED25519_KEY_LEN || + ssh_string_len(privkey) != (2 * ED25519_KEY_LEN)) + { +- SSH_LOG(SSH_LOG_WARN, "Invalid ed25519 key len"); ++ SSH_LOG(SSH_LOG_TRACE, "Invalid ed25519 key len"); + return SSH_ERROR; + } + +@@ -266,7 +266,7 @@ int pki_signature_from_ed25519_blob(ssh_signature sig, ssh_string sig_blob) + + len = ssh_string_len(sig_blob); + if (len != ED25519_SIG_LEN){ +- SSH_LOG(SSH_LOG_WARN, "Invalid ssh-ed25519 signature len: %zu", len); ++ SSH_LOG(SSH_LOG_TRACE, "Invalid ssh-ed25519 signature len: %zu", len); + return SSH_ERROR; + } + +diff --git a/src/pki_gcrypt.c b/src/pki_gcrypt.c +index bf45351d..87cd91c8 100644 +--- a/src/pki_gcrypt.c ++++ b/src/pki_gcrypt.c +@@ -938,7 +938,7 @@ ssh_string pki_private_key_to_pem(const ssh_key key, + (void) auth_fn; + (void) auth_data; + +- SSH_LOG(SSH_LOG_WARN, "PEM export not supported by gcrypt backend!"); ++ SSH_LOG(SSH_LOG_TRACE, "PEM export not supported by gcrypt backend!"); + + return NULL; + } +@@ -957,7 +957,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key, + + type = pki_privatekey_type_from_string(b64_key); + if (type == SSH_KEYTYPE_UNKNOWN) { +- SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key."); ++ SSH_LOG(SSH_LOG_TRACE, "Unknown or invalid private key."); + return NULL; + } + +@@ -977,7 +977,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key, + } + + if (!valid) { +- SSH_LOG(SSH_LOG_WARN, "Parsing private key"); ++ SSH_LOG(SSH_LOG_TRACE, "Error parsing private key"); + goto fail; + } + break; +@@ -996,7 +996,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key, + } + + if (!valid) { +- SSH_LOG(SSH_LOG_WARN, "Parsing private key"); ++ SSH_LOG(SSH_LOG_TRACE, "Error parsing private key"); + goto fail; + } + break; +@@ -1027,7 +1027,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key, + } + + if (!valid) { +- SSH_LOG(SSH_LOG_WARN, "Parsing private key"); ++ SSH_LOG(SSH_LOG_TRACE, "Error parsing private key"); + goto fail; + } + +@@ -1035,7 +1035,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key, + * keys, so we need to figure out the correct type here */ + type = pki_key_ecdsa_to_key_type(ecdsa); + if (type == SSH_KEYTYPE_UNKNOWN) { +- SSH_LOG(SSH_LOG_WARN, "Invalid private key."); ++ SSH_LOG(SSH_LOG_TRACE, "Invalid private key."); + goto fail; + } + break; +@@ -1045,7 +1045,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key, + case SSH_KEYTYPE_RSA1: + case SSH_KEYTYPE_UNKNOWN: + default: +- SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key type %d", type); ++ SSH_LOG(SSH_LOG_TRACE, "Unknown or invalid private key type %d", type); + return NULL; + } + +@@ -1905,7 +1905,7 @@ ssh_string pki_signature_to_blob(const ssh_signature sig) + case SSH_KEYTYPE_RSA1: + case SSH_KEYTYPE_UNKNOWN: + default: +- SSH_LOG(SSH_LOG_WARN, "Unknown signature key type: %d", sig->type); ++ SSH_LOG(SSH_LOG_TRACE, "Unknown signature key type: %d", sig->type); + return NULL; + break; + } +@@ -1925,7 +1925,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, + int rc; + + if (ssh_key_type_plain(pubkey->type) != type) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Incompatible public key provided (%d) expecting (%d)", + type, + pubkey->type); +@@ -1947,7 +1947,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, + case SSH_KEYTYPE_DSS: + /* 40 is the dual signature blob len. */ + if (len != 40) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Signature has wrong size: %lu", + (unsigned long)len); + ssh_signature_free(sig); +@@ -1977,7 +1977,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, + rsalen = (gcry_pk_get_nbits(pubkey->rsa) + 7) / 8; + + if (len > rsalen) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Signature is to big size: %lu", + (unsigned long)len); + ssh_signature_free(sig); +@@ -2055,7 +2055,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, + } + + if (rlen != 0) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Signature has remaining bytes in inner " + "sigblob: %lu", + (unsigned long)rlen); +@@ -2093,7 +2093,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, + case SSH_KEYTYPE_RSA1: + case SSH_KEYTYPE_UNKNOWN: + default: +- SSH_LOG(SSH_LOG_WARN, "Unknown signature type"); ++ SSH_LOG(SSH_LOG_TRACE, "Unknown signature type"); + return NULL; + } + +@@ -2154,7 +2154,7 @@ ssh_signature pki_do_sign_hash(const ssh_key privkey, + break; + case SSH_DIGEST_AUTO: + default: +- SSH_LOG(SSH_LOG_WARN, "Incompatible key algorithm"); ++ SSH_LOG(SSH_LOG_TRACE, "Incompatible key algorithm"); + return NULL; + } + err = gcry_sexp_build(&sexp, +diff --git a/src/pki_mbedcrypto.c b/src/pki_mbedcrypto.c +index c33fb726..ca19a5fa 100644 +--- a/src/pki_mbedcrypto.c ++++ b/src/pki_mbedcrypto.c +@@ -95,7 +95,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key, const char *passphrase, + + type = pki_privatekey_type_from_string(b64_key); + if (type == SSH_KEYTYPE_UNKNOWN) { +- SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key."); ++ SSH_LOG(SSH_LOG_TRACE, "Unknown or invalid private key."); + return NULL; + } + +@@ -136,7 +136,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key, const char *passphrase, + if (valid != 0) { + char error_buf[100]; + mbedtls_strerror(valid, error_buf, 100); +- SSH_LOG(SSH_LOG_WARN,"Parsing private key %s", error_buf); ++ SSH_LOG(SSH_LOG_TRACE,"Parsing private key %s", error_buf); + goto fail; + } + break; +@@ -177,14 +177,14 @@ ssh_key pki_private_key_from_base64(const char *b64_key, const char *passphrase, + if (valid != 0) { + char error_buf[100]; + mbedtls_strerror(valid, error_buf, 100); +- SSH_LOG(SSH_LOG_WARN,"Parsing private key %s", error_buf); ++ SSH_LOG(SSH_LOG_TRACE,"Parsing private key %s", error_buf); + goto fail; + } + break; + case SSH_KEYTYPE_ED25519: + /* Cannot open ed25519 keys with libmbedcrypto */ + default: +- SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key type %d", ++ SSH_LOG(SSH_LOG_TRACE, "Unknown or invalid private key type %d", + type); + return NULL; + } +@@ -213,7 +213,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key, const char *passphrase, + * keys, so we need to figure out the correct type here */ + type = pki_key_ecdsa_to_key_type(key->ecdsa); + if (type == SSH_KEYTYPE_UNKNOWN) { +- SSH_LOG(SSH_LOG_WARN, "Invalid private key."); ++ SSH_LOG(SSH_LOG_TRACE, "Invalid private key."); + goto fail; + } + } else { +@@ -276,19 +276,19 @@ int pki_privkey_build_rsa(ssh_key key, + ssh_string_data(d), ssh_string_len(d), + ssh_string_data(e), ssh_string_len(e)); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARN, "Failed to import private RSA key"); ++ SSH_LOG(SSH_LOG_TRACE, "Failed to import private RSA key"); + goto fail; + } + + rc = mbedtls_rsa_complete(rsa); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARN, "Failed to complete private RSA key"); ++ SSH_LOG(SSH_LOG_TRACE, "Failed to complete private RSA key"); + goto fail; + } + + rc = mbedtls_rsa_check_privkey(rsa); + if (rc != 0) { +- SSH_LOG(SSH_LOG_WARN, "Inconsistent private RSA key"); ++ SSH_LOG(SSH_LOG_TRACE, "Inconsistent private RSA key"); + goto fail; + } + +@@ -845,7 +845,7 @@ ssh_string pki_signature_to_blob(const ssh_signature sig) + sig_blob = pki_ed25519_signature_to_blob(sig); + break; + default: +- SSH_LOG(SSH_LOG_WARN, "Unknown signature key type: %s", ++ SSH_LOG(SSH_LOG_TRACE, "Unknown signature key type: %s", + sig->type_c); + return NULL; + } +@@ -865,20 +865,20 @@ static ssh_signature pki_signature_from_rsa_blob(const ssh_key pubkey, const + size_t len = ssh_string_len(sig_blob); + + if (pubkey->rsa == NULL) { +- SSH_LOG(SSH_LOG_WARN, "Pubkey RSA field NULL"); ++ SSH_LOG(SSH_LOG_TRACE, "Pubkey RSA field NULL"); + goto errout; + } + + rsalen = mbedtls_pk_get_bitlen(pubkey->rsa) / 8; + if (len > rsalen) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Signature is too big: %lu > %lu", + (unsigned long) len, + (unsigned long) rsalen); + goto errout; + } + #ifdef DEBUG_CRYPTO +- SSH_LOG(SSH_LOG_WARN, "RSA signature len: %lu", (unsigned long)len); ++ SSH_LOG(SSH_LOG_TRACE, "RSA signature len: %lu", (unsigned long)len); + ssh_log_hexdump("RSA signature", ssh_string_data(sig_blob), len); + #endif + +@@ -919,7 +919,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, + int rc; + + if (ssh_key_type_plain(pubkey->type) != type) { +- SSH_LOG(SSH_LOG_WARN, ++ SSH_LOG(SSH_LOG_TRACE, + "Incompatible public key provided (%d) expecting (%d)", + type, + pubkey->type); +@@ -1003,7 +1003,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, + } + + if (rlen != 0) { +- SSH_LOG(SSH_LOG_WARN, "Signature has remaining bytes in inner " ++ SSH_LOG(SSH_LOG_TRACE, "Signature has remaining bytes in inner " + "sigblob: %lu", + (unsigned long)rlen); + ssh_signature_free(sig); +@@ -1020,7 +1020,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey, + } + break; + default: +- SSH_LOG(SSH_LOG_WARN, "Unknown signature type"); ++ SSH_LOG(SSH_LOG_TRACE, "Unknown signature type"); + return NULL; + } + +@@ -1050,7 +1050,7 @@ static ssh_string rsa_do_sign_hash(const unsigned char *digest, + break; + case SSH_DIGEST_AUTO: + default: +- SSH_LOG(SSH_LOG_WARN, "Incompatible key algorithm"); ++ SSH_LOG(SSH_LOG_TRACE, "Incompatible key algorithm"); + return NULL; + } + +diff --git a/src/scp.c b/src/scp.c +index 85d670a4..d3f9a831 100644 +--- a/src/scp.c ++++ b/src/scp.c +@@ -140,7 +140,7 @@ int ssh_scp_init(ssh_scp scp) + return SSH_ERROR; + } + +- SSH_LOG(SSH_LOG_PROTOCOL, "Initializing scp session %s %son location '%s'", ++ SSH_LOG(SSH_LOG_DEBUG, "Initializing scp session %s %son location '%s'", + scp->mode == SSH_SCP_WRITE?"write":"read", + scp->recursive ? "recursive " : "", + scp->location); +@@ -364,7 +364,7 @@ int ssh_scp_push_directory(ssh_scp scp, const char *dirname, int mode) + goto error; + } + +- SSH_LOG(SSH_LOG_PROTOCOL, ++ SSH_LOG(SSH_LOG_DEBUG, + "SCP pushing directory %s with permissions '%s'", + vis_encoded, perms); + +@@ -501,7 +501,7 @@ int ssh_scp_push_file64(ssh_scp scp, const char *filename, uint64_t size, + goto error; + } + +- SSH_LOG(SSH_LOG_PROTOCOL, ++ SSH_LOG(SSH_LOG_DEBUG, + "SCP pushing file %s, size %" PRIu64 " with permissions '%s'", + vis_encoded, size, perms); + +@@ -800,7 +800,7 @@ int ssh_scp_pull_request(ssh_scp scp) + *p = '\0'; + } + +- SSH_LOG(SSH_LOG_PROTOCOL, "Received SCP request: '%s'", buffer); ++ SSH_LOG(SSH_LOG_DEBUG, "Received SCP request: '%s'", buffer); + switch(buffer[0]) { + case 'C': + /* File */ +diff --git a/src/server.c b/src/server.c +index 841a1c42..acfbfffe 100644 +--- a/src/server.c ++++ b/src/server.c +@@ -348,7 +348,7 @@ static void ssh_server_connection_callback(ssh_session session){ + goto error; + } + set_status(session, 0.4f); +- SSH_LOG(SSH_LOG_PROTOCOL, ++ SSH_LOG(SSH_LOG_DEBUG, + "SSH client banner: %s", session->clientbanner); + + /* Here we analyze the different protocols the server allows. */ +@@ -884,7 +884,7 @@ int ssh_message_auth_interactive_request(ssh_message msg, const char *name, + + /* fill in the kbdint structure */ + if (msg->session->kbdint == NULL) { +- SSH_LOG(SSH_LOG_PROTOCOL, "Warning: Got a " ++ SSH_LOG(SSH_LOG_DEBUG, "Warning: Got a " + "keyboard-interactive response but it " + "seems we didn't send the request."); + +@@ -981,13 +981,13 @@ int ssh_auth_reply_success(ssh_session session, int partial) + + crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_OUT); + if (crypto != NULL && crypto->delayed_compress_out) { +- SSH_LOG(SSH_LOG_PROTOCOL, "Enabling delayed compression OUT"); ++ SSH_LOG(SSH_LOG_DEBUG, "Enabling delayed compression OUT"); + crypto->do_compress_out = 1; + } + + crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_IN); + if (crypto != NULL && crypto->delayed_compress_in) { +- SSH_LOG(SSH_LOG_PROTOCOL, "Enabling delayed compression IN"); ++ SSH_LOG(SSH_LOG_DEBUG, "Enabling delayed compression IN"); + crypto->do_compress_in = 1; + } + return r; +diff --git a/src/session.c b/src/session.c +index 3199096a..fe87cadd 100644 +--- a/src/session.c ++++ b/src/session.c +@@ -504,11 +504,14 @@ int ssh_is_blocking(ssh_session session) + /* Waits until the output socket is empty */ + static int ssh_flush_termination(void *c){ + ssh_session session = c; +- if (ssh_socket_buffered_write_bytes(session->socket) == 0 || +- session->session_state == SSH_SESSION_STATE_ERROR) ++ if (ssh_socket_buffered_write_bytes(session->socket) == 0) { + return 1; +- else ++ } else if (session->session_state == SSH_SESSION_STATE_ERROR) { ++ SSH_LOG(SSH_LOG_WARN, "Error: %s", ssh_get_error(session)); ++ return 1; ++ } else { + return 0; ++ } + } + + /** +@@ -1184,7 +1187,7 @@ int ssh_get_publickey_hash(const ssh_key key, + + /* In FIPS mode, we cannot use MD5 */ + if (ssh_fips_mode()) { +- SSH_LOG(SSH_LOG_WARN, "In FIPS mode MD5 is not allowed." ++ SSH_LOG(SSH_LOG_TRACE, "In FIPS mode MD5 is not allowed." + "Try using SSH_PUBLICKEY_HASH_SHA256"); + rc = SSH_ERROR; + goto out; +diff --git a/src/sftp.c b/src/sftp.c +index a8346040..e3a842d5 100644 +--- a/src/sftp.c ++++ b/src/sftp.c +@@ -316,7 +316,7 @@ int sftp_server_init(sftp_session sftp){ + } + SSH_BUFFER_FREE(reply); + +- SSH_LOG(SSH_LOG_PROTOCOL, "Server version sent"); ++ SSH_LOG(SSH_LOG_DEBUG, "Server version sent"); + + if (version > LIBSFTP_VERSION) { + sftp->version = LIBSFTP_VERSION; +@@ -707,7 +707,7 @@ int sftp_init(sftp_session sftp) { + sftp_set_error(sftp, SSH_FX_FAILURE); + return -1; + } +- SSH_LOG(SSH_LOG_PROTOCOL, ++ SSH_LOG(SSH_LOG_DEBUG, + "SFTP server version %d", + version); + rc = ssh_buffer_unpack(packet->payload, "s", &ext_name); +@@ -720,7 +720,7 @@ int sftp_init(sftp_session sftp) { + break; + } + +- SSH_LOG(SSH_LOG_PROTOCOL, ++ SSH_LOG(SSH_LOG_DEBUG, + "SFTP server extension: %s, version: %s", + ext_name, ext_data); + +@@ -1353,7 +1353,7 @@ static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf, + if (rc != SSH_OK){ + goto error; + } +- SSH_LOG(SSH_LOG_PROTOCOL, "Name: %s", attr->name); ++ SSH_LOG(SSH_LOG_DEBUG, "Name: %s", attr->name); + + /* Set owner and group if we talk to openssh and have the longname */ + if (ssh_get_openssh_version(sftp->session)) { +@@ -1373,7 +1373,7 @@ static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf, + if (rc != SSH_OK){ + goto error; + } +- SSH_LOG(SSH_LOG_PROTOCOL, ++ SSH_LOG(SSH_LOG_DEBUG, + "Flags: %.8"PRIx32"\n", (uint32_t) attr->flags); + + if (attr->flags & SSH_FILEXFER_ATTR_SIZE) { +@@ -1381,7 +1381,7 @@ static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf, + if(rc != SSH_OK) { + goto error; + } +- SSH_LOG(SSH_LOG_PROTOCOL, ++ SSH_LOG(SSH_LOG_DEBUG, + "Size: %"PRIu64"\n", + (uint64_t) attr->size); + } +@@ -1644,7 +1644,7 @@ sftp_attributes sftp_readdir(sftp_session sftp, sftp_dir dir) + return NULL; + } + +- SSH_LOG(SSH_LOG_PROTOCOL, "Count is %d", dir->count); ++ SSH_LOG(SSH_LOG_DEBUG, "Count is %d", dir->count); + + attr = sftp_parse_attr(sftp, dir->buffer, 1); + if (attr == NULL) { +diff --git a/src/socket.c b/src/socket.c +index 2fef8e7e..f470bb28 100644 +--- a/src/socket.c ++++ b/src/socket.c +@@ -473,12 +473,12 @@ void ssh_socket_close(ssh_socket s) + kill(pid, SIGTERM); + while (waitpid(pid, &status, 0) == -1) { + if (errno != EINTR) { +- SSH_LOG(SSH_LOG_WARN, "waitpid failed: %s", strerror(errno)); ++ SSH_LOG(SSH_LOG_TRACE, "waitpid failed: %s", strerror(errno)); + return; + } + } + if (!WIFEXITED(status)) { +- SSH_LOG(SSH_LOG_WARN, "Proxy command exitted abnormally"); ++ SSH_LOG(SSH_LOG_TRACE, "Proxy command exitted abnormally"); + return; + } + SSH_LOG(SSH_LOG_TRACE, "Proxy command returned %d", WEXITSTATUS(status)); +@@ -849,7 +849,7 @@ int ssh_socket_connect(ssh_socket s, + return SSH_ERROR; + } + fd = ssh_connect_host_nonblocking(s->session, host, bind_addr, port); +- SSH_LOG(SSH_LOG_PROTOCOL, "Nonblocking connection socket: %d", fd); ++ SSH_LOG(SSH_LOG_DEBUG, "Nonblocking connection socket: %d", fd); + if (fd == SSH_INVALID_SOCKET) { + return SSH_ERROR; + } +@@ -873,7 +873,7 @@ ssh_execute_command(const char *command, socket_t in, socket_t out) + /* Prepare /dev/null socket for the stderr redirection */ + int devnull = open("/dev/null", O_WRONLY); + if (devnull == -1) { +- SSH_LOG(SSH_LOG_WARNING, "Failed to open /dev/null"); ++ SSH_LOG(SSH_LOG_TRACE, "Failed to open /dev/null"); + exit(1); + } + +@@ -914,7 +914,7 @@ ssh_socket_connect_proxycommand(ssh_socket s, const char *command) + return SSH_ERROR; + } + +- SSH_LOG(SSH_LOG_PROTOCOL, "Executing proxycommand '%s'", command); ++ SSH_LOG(SSH_LOG_DEBUG, "Executing proxycommand '%s'", command); + pid = fork(); + if (pid == 0) { + ssh_execute_command(command, pair[0], pair[0]); +@@ -922,7 +922,7 @@ ssh_socket_connect_proxycommand(ssh_socket s, const char *command) + } + s->proxy_pid = pid; + close(pair[0]); +- SSH_LOG(SSH_LOG_PROTOCOL, "ProxyCommand connection pipe: [%d,%d]",pair[0],pair[1]); ++ SSH_LOG(SSH_LOG_DEBUG, "ProxyCommand connection pipe: [%d,%d]",pair[0],pair[1]); + ssh_socket_set_fd(s, pair[1]); + s->state=SSH_SOCKET_CONNECTED; + s->fd_is_socket=0; diff --git a/SOURCES/null_dereference_rekey.patch b/SOURCES/null_dereference_rekey.patch new file mode 100644 index 0000000..505240b --- /dev/null +++ b/SOURCES/null_dereference_rekey.patch @@ -0,0 +1,1845 @@ +diff --color -ru ../libssh-0.9.6/include/libssh/curve25519.h ./include/libssh/curve25519.h +--- ../libssh-0.9.6/include/libssh/curve25519.h 2021-03-15 08:11:33.000000000 +0100 ++++ ./include/libssh/curve25519.h 2023-04-27 12:21:30.257820636 +0200 +@@ -48,6 +48,7 @@ + + + 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 --color -ru ../libssh-0.9.6/include/libssh/dh-gex.h ./include/libssh/dh-gex.h +--- ../libssh-0.9.6/include/libssh/dh-gex.h 2021-03-15 08:11:33.000000000 +0100 ++++ ./include/libssh/dh-gex.h 2023-04-27 12:21:30.257820636 +0200 +@@ -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 --color -ru ../libssh-0.9.6/include/libssh/dh.h ./include/libssh/dh.h +--- ../libssh-0.9.6/include/libssh/dh.h 2021-03-15 08:11:33.000000000 +0100 ++++ ./include/libssh/dh.h 2023-04-27 12:21:30.257820636 +0200 +@@ -63,8 +63,10 @@ + 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); + #ifdef WITH_SERVER + void ssh_server_dh_init(ssh_session session); + #endif /* WITH_SERVER */ +diff --color -ru ../libssh-0.9.6/include/libssh/ecdh.h ./include/libssh/ecdh.h +--- ../libssh-0.9.6/include/libssh/ecdh.h 2021-03-15 08:11:33.000000000 +0100 ++++ ./include/libssh/ecdh.h 2023-04-27 12:21:30.257820636 +0200 +@@ -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 --color -ru ../libssh-0.9.6/include/libssh/kex.h ./include/libssh/kex.h +--- ../libssh-0.9.6/include/libssh/kex.h 2021-03-15 08:11:33.000000000 +0100 ++++ ./include/libssh/kex.h 2023-04-27 12:21:30.257820636 +0200 +@@ -33,7 +33,7 @@ + + 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 --color -ru ../libssh-0.9.6/include/libssh/session.h ./include/libssh/session.h +--- ../libssh-0.9.6/include/libssh/session.h 2021-08-26 14:27:42.000000000 +0200 ++++ ./include/libssh/session.h 2023-04-27 12:24:04.679475777 +0200 +@@ -75,6 +75,11 @@ + /* 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 +@@ -131,10 +136,8 @@ + /* Extensions negotiated using RFC 8308 */ + uint32_t extensions; + +- ssh_string banner; /* that's the issue banner from +- the server */ +- char *discon_msg; /* disconnect message from +- the remote host */ ++ ssh_string banner; /* that's the issue banner from the server */ ++ char *discon_msg; /* disconnect message from the remote host */ + ssh_buffer in_buffer; + PACKET in_packet; + ssh_buffer out_buffer; +@@ -158,25 +161,33 @@ + 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; + struct ssh_crypto_struct *current_crypto; +- struct ssh_crypto_struct *next_crypto; /* next_crypto is going to be used after a SSH2_MSG_NEWKEYS */ ++ /* next_crypto is going to be used after a SSH2_MSG_NEWKEYS */ ++ struct ssh_crypto_struct *next_crypto; + + struct ssh_list *channels; /* linked list of channels */ + int maxchannel; + ssh_agent agent; /* ssh agent */ + +-/* keyb interactive data */ ++ /* keyboard interactive data */ + struct ssh_kbdint_struct *kbdint; + struct ssh_gssapi_struct *gssapi; + +@@ -193,7 +204,8 @@ + + /* auths accepted by server */ + struct ssh_list *ssh_message_list; /* list of delayed SSH messages */ +- int (*ssh_message_callback)( struct ssh_session_struct *session, ssh_message msg, void *userdata); ++ int (*ssh_message_callback)(struct ssh_session_struct *session, ++ ssh_message msg, void *userdata); + void *ssh_message_callback_data; + ssh_server_callbacks server_callbacks; + void (*ssh_connection_callback)( struct ssh_session_struct *session); +diff --color -ru ../libssh-0.9.6/src/client.c ./src/client.c +--- ../libssh-0.9.6/src/client.c 2023-04-27 12:22:39.797925403 +0200 ++++ ./src/client.c 2023-04-27 12:24:04.680475778 +0200 +@@ -243,10 +243,13 @@ + * @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,96 +389,102 @@ + { + int rc; + +- switch(session->session_state) { +- case SSH_SESSION_STATE_NONE: +- case SSH_SESSION_STATE_CONNECTING: +- break; +- case SSH_SESSION_STATE_SOCKET_CONNECTED: +- ssh_set_fd_towrite(session); +- ssh_send_banner(session, 0); +- +- break; +- case SSH_SESSION_STATE_BANNER_RECEIVED: +- if (session->serverbanner == NULL) { +- goto error; +- } +- set_status(session, 0.4f); +- SSH_LOG(SSH_LOG_DEBUG, +- "SSH server banner: %s", session->serverbanner); ++ SSH_LOG(SSH_LOG_DEBUG, "session_state=%d", session->session_state); + +- /* Here we analyze the different protocols the server allows. */ +- rc = ssh_analyze_banner(session, 0); +- if (rc < 0) { +- ssh_set_error(session, SSH_FATAL, +- "No version of SSH protocol usable (banner: %s)", +- session->serverbanner); +- goto error; +- } ++ switch (session->session_state) { ++ case SSH_SESSION_STATE_NONE: ++ case SSH_SESSION_STATE_CONNECTING: ++ break; ++ case SSH_SESSION_STATE_SOCKET_CONNECTED: ++ ssh_set_fd_towrite(session); ++ ssh_send_banner(session, 0); ++ ++ break; ++ case SSH_SESSION_STATE_BANNER_RECEIVED: ++ if (session->serverbanner == NULL) { ++ goto error; ++ } ++ set_status(session, 0.4f); ++ SSH_LOG(SSH_LOG_DEBUG, ++ "SSH server banner: %s", session->serverbanner); ++ ++ /* Here we analyze the different protocols the server allows. */ ++ rc = ssh_analyze_banner(session, 0); ++ if (rc < 0) { ++ ssh_set_error(session, SSH_FATAL, ++ "No version of SSH protocol usable (banner: %s)", ++ session->serverbanner); ++ goto error; ++ } ++ ++ ssh_packet_register_socket_callback(session, session->socket); + +- ssh_packet_register_socket_callback(session, session->socket); ++ ssh_packet_set_default_callbacks(session); ++ session->session_state = SSH_SESSION_STATE_INITIAL_KEX; ++ rc = ssh_set_client_kex(session); ++ if (rc != SSH_OK) { ++ goto error; ++ } ++ rc = ssh_send_kex(session); ++ if (rc < 0) { ++ goto error; ++ } ++ set_status(session, 0.5f); + +- ssh_packet_set_default_callbacks(session); +- session->session_state = SSH_SESSION_STATE_INITIAL_KEX; ++ break; ++ case SSH_SESSION_STATE_INITIAL_KEX: ++ /* TODO: This state should disappear in favor of get_key handle */ ++ break; ++ case SSH_SESSION_STATE_KEXINIT_RECEIVED: ++ set_status(session, 0.6f); ++ ssh_list_kex(&session->next_crypto->server_kex); ++ if ((session->flags & SSH_SESSION_FLAG_KEXINIT_SENT) == 0) { ++ /* in rekeying state if next_crypto client_kex might be empty */ + rc = ssh_set_client_kex(session); + if (rc != SSH_OK) { + goto error; + } +- rc = ssh_send_kex(session, 0); ++ rc = ssh_send_kex(session); + if (rc < 0) { + goto error; + } +- set_status(session, 0.5f); ++ } ++ if (ssh_kex_select_methods(session) == SSH_ERROR) ++ goto error; ++ set_status(session, 0.8f); ++ session->session_state = SSH_SESSION_STATE_DH; + +- break; +- case SSH_SESSION_STATE_INITIAL_KEX: +- /* TODO: This state should disappear in favor of get_key handle */ +- break; +- 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) { +- /* in rekeying state if next_crypto client_kex is empty */ +- rc = ssh_set_client_kex(session); +- if (rc != SSH_OK) { +- goto error; +- } +- rc = ssh_send_kex(session, 0); +- if (rc < 0) { +- goto error; +- } +- } +- if (ssh_kex_select_methods(session) == SSH_ERROR) +- goto error; +- set_status(session,0.8f); +- session->session_state=SSH_SESSION_STATE_DH; +- if (dh_handshake(session) == SSH_ERROR) { +- goto error; +- } +- FALL_THROUGH; +- case SSH_SESSION_STATE_DH: +- if(session->dh_handshake_state==DH_STATE_FINISHED){ +- set_status(session,1.0f); +- session->connected = 1; +- if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) +- session->session_state = SSH_SESSION_STATE_AUTHENTICATED; +- else +- session->session_state=SSH_SESSION_STATE_AUTHENTICATING; +- } +- break; +- case SSH_SESSION_STATE_AUTHENTICATING: +- break; +- case SSH_SESSION_STATE_ERROR: ++ /* If the init packet was already sent in previous step, this will be no ++ * operation */ ++ if (dh_handshake(session) == SSH_ERROR) { + goto error; +- default: +- ssh_set_error(session,SSH_FATAL,"Invalid state %d",session->session_state); ++ } ++ FALL_THROUGH; ++ case SSH_SESSION_STATE_DH: ++ if (session->dh_handshake_state == DH_STATE_FINISHED) { ++ set_status(session, 1.0f); ++ session->connected = 1; ++ if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) ++ session->session_state = SSH_SESSION_STATE_AUTHENTICATED; ++ else ++ session->session_state=SSH_SESSION_STATE_AUTHENTICATING; ++ } ++ break; ++ case SSH_SESSION_STATE_AUTHENTICATING: ++ break; ++ case SSH_SESSION_STATE_ERROR: ++ goto error; ++ default: ++ ssh_set_error(session, SSH_FATAL, "Invalid state %d", ++ session->session_state); + } + + return; + error: + ssh_socket_close(session->socket); + session->alive = 0; +- session->session_state=SSH_SESSION_STATE_ERROR; +- SSH_LOG(SSH_LOG_WARN, "%s", ssh_get_error(session)); ++ session->session_state = SSH_SESSION_STATE_ERROR; ++ + } + + /** @internal +diff --color -ru ../libssh-0.9.6/src/curve25519.c ./src/curve25519.c +--- ../libssh-0.9.6/src/curve25519.c 2023-04-27 12:22:39.797925403 +0200 ++++ ./src/curve25519.c 2023-04-27 12:24:04.680475778 +0200 +@@ -172,6 +172,11 @@ + 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 @@ + (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 --color -ru ../libssh-0.9.6/src/dh.c ./src/dh.c +--- ../libssh-0.9.6/src/dh.c 2023-04-27 12:22:39.798925404 +0200 ++++ ./src/dh.c 2023-04-27 12:24:04.680475778 +0200 +@@ -342,6 +342,11 @@ + 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 @@ + (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 --color -ru ../libssh-0.9.6/src/dh-gex.c ./src/dh-gex.c +--- ../libssh-0.9.6/src/dh-gex.c 2023-04-27 12:22:39.797925403 +0200 ++++ ./src/dh-gex.c 2023-04-27 12:24:04.680475778 +0200 +@@ -238,6 +238,11 @@ + 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 @@ + (void)user; + SSH_LOG(SSH_LOG_DEBUG, "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 --color -ru ../libssh-0.9.6/src/ecdh.c ./src/ecdh.c +--- ../libssh-0.9.6/src/ecdh.c 2023-04-27 12:22:39.798925404 +0200 ++++ ./src/ecdh.c 2023-04-27 12:24:04.680475778 +0200 +@@ -43,6 +43,11 @@ + .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 @@ + (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 --color -ru ../libssh-0.9.6/src/gssapi.c ./src/gssapi.c +--- ../libssh-0.9.6/src/gssapi.c 2023-04-27 12:22:39.798925404 +0200 ++++ ./src/gssapi.c 2023-04-27 12:24:04.681475778 +0200 +@@ -223,6 +223,7 @@ + "indicate mechs", + maj_stat, + min_stat); ++ gss_release_oid_set(&min_stat, &both_supported); + return SSH_ERROR; + } + +@@ -259,8 +260,10 @@ + return SSH_OK; + } + /* from now we have room for context */ +- if (ssh_gssapi_init(session) == SSH_ERROR) ++ if (ssh_gssapi_init(session) == SSH_ERROR) { ++ gss_release_oid_set(&min_stat, &both_supported); + return SSH_ERROR; ++ } + + name_buf.value = service_name; + name_buf.length = strlen(name_buf.value) + 1; +@@ -272,6 +275,7 @@ + "importing name", + maj_stat, + min_stat); ++ gss_release_oid_set(&min_stat, &both_supported); + return -1; + } + +@@ -338,6 +342,7 @@ + min_stat); + ptr = malloc(buffer.length + 1); + if (ptr == NULL) { ++ gss_release_buffer(&min_stat, &buffer); + return NULL; + } + memcpy(ptr, buffer.value, buffer.length); +@@ -421,6 +426,7 @@ + "Gssapi error", + maj_stat, + min_stat); ++ gss_release_buffer(&min_stat, &output_token); + ssh_auth_reply_default(session,0); + ssh_gssapi_free(session); + session->gssapi=NULL; +@@ -438,6 +444,9 @@ + (size_t)output_token.length, output_token.value); + ssh_packet_send(session); + } ++ ++ gss_release_buffer(&min_stat, &output_token); ++ + if(maj_stat == GSS_S_COMPLETE){ + session->gssapi->state = SSH_GSSAPI_STATE_RCV_MIC; + } +@@ -638,7 +647,7 @@ + static int ssh_gssapi_match(ssh_session session, gss_OID_set *valid_oids) + { + OM_uint32 maj_stat, min_stat, lifetime; +- gss_OID_set actual_mechs; ++ gss_OID_set actual_mechs = GSS_C_NO_OID_SET; + gss_buffer_desc namebuf; + gss_name_t client_id = GSS_C_NO_NAME; + gss_OID oid; +@@ -700,6 +709,7 @@ + ret = SSH_OK; + + end: ++ gss_release_oid_set(&min_stat, &actual_mechs); + gss_release_name(&min_stat, &client_id); + return ret; + } +@@ -713,7 +723,7 @@ + */ + int ssh_gssapi_auth_mic(ssh_session session){ + size_t i; +- gss_OID_set selected; /* oid selected for authentication */ ++ gss_OID_set selected = GSS_C_NO_OID_SET; /* oid selected for authentication */ + ssh_string *oids = NULL; + int rc; + size_t n_oids = 0; +@@ -790,6 +800,8 @@ + SSH_STRING_FREE(oids[i]); + } + free(oids); ++ gss_release_oid_set(&min_stat, &selected); ++ + if (rc != SSH_ERROR) { + return SSH_AUTH_AGAIN; + } +@@ -893,6 +905,8 @@ + ssh_packet_send(session); + session->auth.state = SSH_AUTH_STATE_GSSAPI_TOKEN; + } ++ ++ gss_release_buffer(&min_stat, &output_token); + return SSH_PACKET_USED; + + error: +@@ -921,8 +935,10 @@ + + maj_stat = gss_get_mic(&min_stat,session->gssapi->ctx, GSS_C_QOP_DEFAULT, + &mic_buf, &mic_token_buf); ++ ++ SSH_BUFFER_FREE(mic_buffer); ++ + if (GSS_ERROR(maj_stat)){ +- SSH_BUFFER_FREE(mic_buffer); + ssh_gssapi_log_error(SSH_LOG_DEBUG, + "generating MIC", + maj_stat, +@@ -935,8 +951,10 @@ + SSH2_MSG_USERAUTH_GSSAPI_MIC, + mic_token_buf.length, + (size_t)mic_token_buf.length, mic_token_buf.value); ++ ++ gss_release_buffer(&min_stat, &mic_token_buf); ++ + if (rc != SSH_OK) { +- SSH_BUFFER_FREE(mic_buffer); + ssh_set_error_oom(session); + return SSH_ERROR; + } +@@ -1005,6 +1023,8 @@ + ssh_packet_send(session); + } + ++ gss_release_buffer(&min_stat, &output_token); ++ + if (maj_stat == GSS_S_COMPLETE) { + ssh_gssapi_send_mic(session); + session->auth.state = SSH_AUTH_STATE_GSSAPI_MIC_SENT; +diff --color -ru ../libssh-0.9.6/src/kex.c ./src/kex.c +--- ../libssh-0.9.6/src/kex.c 2023-04-27 12:22:39.798925404 +0200 ++++ ./src/kex.c 2023-04-27 12:24:08.450478574 +0200 +@@ -28,6 +28,7 @@ + #include + #include + ++#include "libssh/libssh.h" + #include "libssh/priv.h" + #include "libssh/buffer.h" + #include "libssh/dh.h" +@@ -305,6 +306,10 @@ + + int is_wrong = 1; + ++ if (client_str == NULL || server_str == NULL) { ++ return is_wrong; ++ } ++ + colon = strchr(client_str, ','); + if (colon == NULL) { + client_kex_len = strlen(client_str); +@@ -331,6 +336,7 @@ + SSH_PACKET_CALLBACK(ssh_packet_kexinit) + { + int i, ok; ++ struct ssh_crypto_struct *crypto = session->next_crypto; + int server_kex = session->server; + ssh_string str = NULL; + char *strings[SSH_KEX_METHODS] = {0}; +@@ -344,35 +350,67 @@ + (void)type; + (void)user; + ++ SSH_LOG(SSH_LOG_TRACE, "KEXINIT received"); ++ + if (session->session_state == SSH_SESSION_STATE_AUTHENTICATED) { +- SSH_LOG(SSH_LOG_DEBUG, "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->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; ++ } + } else if (session->session_state != SSH_SESSION_STATE_INITIAL_KEX) { +- ssh_set_error(session,SSH_FATAL,"SSH_KEXINIT received in wrong state"); ++ ssh_set_error(session, SSH_FATAL, ++ "SSH_KEXINIT received in wrong state"); + goto error; + } + + if (server_kex) { +- len = ssh_buffer_get_data(packet,session->next_crypto->client_kex.cookie, 16); ++#ifdef WITH_SERVER ++ len = ssh_buffer_get_data(packet, crypto->client_kex.cookie, 16); + if (len != 16) { +- ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: no cookie in packet"); ++ ssh_set_error(session, SSH_FATAL, ++ "ssh_packet_kexinit: no cookie in packet"); + goto error; + } + +- ok = ssh_hashbufin_add_cookie(session, session->next_crypto->client_kex.cookie); ++ ok = ssh_hashbufin_add_cookie(session, crypto->client_kex.cookie); + if (ok < 0) { +- ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: adding cookie failed"); ++ 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); ++ len = ssh_buffer_get_data(packet, crypto->server_kex.cookie, 16); + if (len != 16) { +- ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: no cookie in packet"); ++ ssh_set_error(session, SSH_FATAL, ++ "ssh_packet_kexinit: no cookie in packet"); + goto error; + } + +- ok = ssh_hashbufin_add_cookie(session, session->next_crypto->server_kex.cookie); ++ ok = ssh_hashbufin_add_cookie(session, crypto->server_kex.cookie); + if (ok < 0) { +- ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: adding cookie failed"); ++ 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; + } + } +@@ -385,7 +423,8 @@ + + rc = ssh_buffer_add_ssh_string(session->in_hashbuf, str); + if (rc < 0) { +- ssh_set_error(session, SSH_FATAL, "Error adding string in hash buffer"); ++ ssh_set_error(session, SSH_FATAL, ++ "Error adding string in hash buffer"); + goto error; + } + +@@ -398,14 +437,14 @@ + str = NULL; + } + +- /* copy the server kex info into an array of strings */ ++ /* copy the peer kex info into an array of strings */ + if (server_kex) { + for (i = 0; i < SSH_KEX_METHODS; i++) { +- session->next_crypto->client_kex.methods[i] = strings[i]; ++ crypto->client_kex.methods[i] = strings[i]; + } + } else { /* client */ + for (i = 0; i < SSH_KEX_METHODS; i++) { +- session->next_crypto->server_kex.methods[i] = strings[i]; ++ crypto->server_kex.methods[i] = strings[i]; + } + } + +@@ -419,30 +458,48 @@ + * 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 on the server side. ++ * Client needs to start the Key exchange over with the correct method ++ */ ++ if (first_kex_packet_follows || session->send_first_kex_follows) { ++ char **client_methods = crypto->client_kex.methods; ++ char **server_methods = 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]); ++ SSH_LOG(SSH_LOG_DEBUG, "The initial guess was %s.", ++ session->first_kex_follows_guess_wrong ? "wrong" : "right"); ++ } + ++ if (server_kex) { + /* + * If client sent a ext-info-c message in the kex list, it supports + * RFC 8308 extension negotiation. + */ +- ok = ssh_match_group(session->next_crypto->client_kex.methods[SSH_KEX], ++ ok = ssh_match_group(crypto->client_kex.methods[SSH_KEX], + KEX_EXTENSION_CLIENT); + if (ok) { +- const char *hostkeys = NULL; ++ const char *hostkeys = NULL, *wanted_hostkeys = NULL; + + /* The client supports extension negotiation */ + session->extensions |= SSH_EXT_NEGOTIATION; +@@ -452,14 +509,14 @@ + * by the client and enable the respective extensions to provide + * correct signature in the next packet if RSA is negotiated + */ +- hostkeys = session->next_crypto->client_kex.methods[SSH_HOSTKEYS]; ++ hostkeys = crypto->client_kex.methods[SSH_HOSTKEYS]; ++ wanted_hostkeys = session->opts.wanted_methods[SSH_HOSTKEYS]; + ok = ssh_match_group(hostkeys, "rsa-sha2-512"); + if (ok) { + /* Check if rsa-sha2-512 is allowed by config */ +- if (session->opts.wanted_methods[SSH_HOSTKEYS] != NULL) { +- char *is_allowed = +- ssh_find_matching(session->opts.wanted_methods[SSH_HOSTKEYS], +- "rsa-sha2-512"); ++ if (wanted_hostkeys != NULL) { ++ char *is_allowed = ssh_find_matching(wanted_hostkeys, ++ "rsa-sha2-512"); + if (is_allowed != NULL) { + session->extensions |= SSH_EXT_SIG_RSA_SHA512; + } +@@ -469,10 +526,9 @@ + ok = ssh_match_group(hostkeys, "rsa-sha2-256"); + if (ok) { + /* Check if rsa-sha2-256 is allowed by config */ +- if (session->opts.wanted_methods[SSH_HOSTKEYS] != NULL) { +- char *is_allowed = +- ssh_find_matching(session->opts.wanted_methods[SSH_HOSTKEYS], +- "rsa-sha2-256"); ++ if (wanted_hostkeys != NULL) { ++ char *is_allowed = ssh_find_matching(wanted_hostkeys, ++ "rsa-sha2-256"); + if (is_allowed != NULL) { + session->extensions |= SSH_EXT_SIG_RSA_SHA256; + } +@@ -488,7 +544,7 @@ + (session->extensions & SSH_EXT_SIG_RSA_SHA512)) { + session->extensions &= ~(SSH_EXT_SIG_RSA_SHA256 | SSH_EXT_SIG_RSA_SHA512); + rsa_sig_ext = ssh_find_matching("rsa-sha2-512,rsa-sha2-256", +- session->next_crypto->client_kex.methods[SSH_HOSTKEYS]); ++ hostkeys); + if (rsa_sig_ext == NULL) { + goto error; /* should never happen */ + } else if (strcmp(rsa_sig_ext, "rsa-sha2-512") == 0) { +@@ -507,24 +563,16 @@ + 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 */ + 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; + +@@ -672,14 +720,18 @@ + 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++) { +@@ -749,15 +801,89 @@ + return NULL; + } + ++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; ++} ++ ++ ++/** @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. + */ + 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; ++ struct ssh_crypto_struct *crypto = session->next_crypto; ++ struct ssh_kex_struct *server = &crypto->server_kex; ++ struct ssh_kex_struct *client = &crypto->client_kex; + char *ext_start = NULL; + const char *aead_hmac = 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. +@@ -768,52 +894,41 @@ + } + + for (i = 0; i < SSH_KEX_METHODS; i++) { +- session->next_crypto->kex_methods[i]=ssh_find_matching(server->methods[i],client->methods[i]); ++ crypto->kex_methods[i] = ssh_find_matching(server->methods[i], ++ client->methods[i]); + + if (i == SSH_MAC_C_S || i == SSH_MAC_S_C) { +- aead_hmac = ssh_find_aead_hmac(session->next_crypto->kex_methods[i-2]); ++ aead_hmac = ssh_find_aead_hmac(crypto->kex_methods[i - 2]); + if (aead_hmac) { +- free(session->next_crypto->kex_methods[i]); +- session->next_crypto->kex_methods[i] = strdup(aead_hmac); ++ free(crypto->kex_methods[i]); ++ crypto->kex_methods[i] = strdup(aead_hmac); + } + } +- if (session->next_crypto->kex_methods[i] == NULL && i < SSH_LANG_C_S){ +- ssh_set_error(session,SSH_FATAL,"kex error : no match for method %s: server [%s], client [%s]", +- ssh_kex_descriptions[i],server->methods[i],client->methods[i]); ++ if (crypto->kex_methods[i] == NULL && i < SSH_LANG_C_S) { ++ ssh_set_error(session, SSH_FATAL, ++ "kex error : no match for method %s: server [%s], " ++ "client [%s]", ssh_kex_descriptions[i], ++ server->methods[i], client->methods[i]); + return SSH_ERROR; +- } else if ((i >= SSH_LANG_C_S) && (session->next_crypto->kex_methods[i] == NULL)) { ++ } else if ((i >= SSH_LANG_C_S) && (crypto->kex_methods[i] == NULL)) { + /* we can safely do that for languages */ +- session->next_crypto->kex_methods[i] = strdup(""); ++ 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; ++ ++ /* 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(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; + } +- SSH_LOG(SSH_LOG_DEBUG, "Negotiated %s,%s,%s,%s,%s,%s,%s,%s,%s,%s", ++ crypto->kex_type = kex_type; ++ ++ SSH_LOG(SSH_LOG_DEBUG, "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], + session->next_crypto->kex_methods[SSH_CRYPT_C_S], +@@ -830,63 +945,116 @@ + + + /* this function only sends the predefined set of kex methods */ +-int ssh_send_kex(ssh_session session, int server_kex) ++int ssh_send_kex(ssh_session session) + { +- struct ssh_kex_struct *kex = (server_kex ? &session->next_crypto->server_kex : +- &session->next_crypto->client_kex); +- ssh_string str = NULL; +- int i; +- int rc; +- +- rc = ssh_buffer_pack(session->out_buffer, +- "bP", +- SSH2_MSG_KEXINIT, +- 16, +- kex->cookie); /* cookie */ +- if (rc != SSH_OK) +- goto error; +- if (ssh_hashbufout_add_cookie(session) < 0) { +- goto error; +- } ++ struct ssh_kex_struct *kex = (session->server ? ++ &session->next_crypto->server_kex : ++ &session->next_crypto->client_kex); ++ 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", ++ SSH2_MSG_KEXINIT, ++ 16, ++ kex->cookie); /* cookie */ ++ if (rc != SSH_OK) ++ goto error; ++ if (ssh_hashbufout_add_cookie(session) < 0) { ++ goto error; ++ } ++ ++ ssh_list_kex(kex); + +- ssh_list_kex(kex); ++ for (i = 0; i < SSH_KEX_METHODS; i++) { ++ str = ssh_string_from_char(kex->methods[i]); ++ if (str == NULL) { ++ goto error; ++ } ++ ++ rc = ssh_buffer_add_ssh_string(session->out_hashbuf, str); ++ if (rc < 0) { ++ goto error; ++ } ++ rc = ssh_buffer_add_ssh_string(session->out_buffer, str); ++ if (rc < 0) { ++ goto error; ++ } ++ SSH_STRING_FREE(str); ++ str = NULL; ++ } + +- for (i = 0; i < SSH_KEX_METHODS; i++) { +- str = ssh_string_from_char(kex->methods[i]); +- if (str == NULL) { +- goto error; ++ rc = ssh_buffer_pack(session->out_buffer, ++ "bd", ++ first_kex_packet_follows, ++ 0); ++ if (rc != SSH_OK) { ++ goto error; + } + +- if (ssh_buffer_add_ssh_string(session->out_hashbuf, str) < 0) { +- goto error; ++ /* Prepare also the first_kex_packet_follows and reserved to 0 */ ++ rc = ssh_buffer_add_u8(session->out_hashbuf, first_kex_packet_follows); ++ if (rc < 0) { ++ goto error; + } +- if (ssh_buffer_add_ssh_string(session->out_buffer, str) < 0) { +- goto error; ++ rc = ssh_buffer_add_u32(session->out_hashbuf, 0); ++ if (rc < 0) { ++ goto error; + } +- SSH_STRING_FREE(str); +- str = NULL; +- } + +- rc = ssh_buffer_pack(session->out_buffer, +- "bd", +- 0, +- 0); +- if (rc != SSH_OK) { +- goto error; +- } ++ rc = ssh_packet_send(session); ++ if (rc == SSH_ERROR) { ++ return -1; ++ } + +- 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"); ++ ++ /* 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; + +- SSH_LOG(SSH_LOG_PACKET, "SSH_MSG_KEXINIT sent"); +- return 0; + error: +- ssh_buffer_reinit(session->out_buffer); +- ssh_buffer_reinit(session->out_hashbuf); +- SSH_STRING_FREE(str); ++ ssh_buffer_reinit(session->out_buffer); ++ ssh_buffer_reinit(session->out_hashbuf); ++ SSH_STRING_FREE(str); + +- return -1; ++ return -1; + } + + /* +@@ -929,7 +1097,7 @@ + } + + 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; +@@ -1006,33 +1174,6 @@ + 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 --color -ru ../libssh-0.9.6/src/packet.c ./src/packet.c +--- ../libssh-0.9.6/src/packet.c 2023-04-27 12:22:39.811925413 +0200 ++++ ./src/packet.c 2023-04-27 12:24:04.682475779 +0200 +@@ -366,6 +366,11 @@ + * - 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; +@@ -1410,18 +1415,23 @@ + } + } + +-void ssh_packet_register_socket_callback(ssh_session session, ssh_socket s){ +- session->socket_callbacks.data=ssh_packet_socket_callback; +- session->socket_callbacks.connected=NULL; +- session->socket_callbacks.controlflow = ssh_packet_socket_controlflow_callback; +- session->socket_callbacks.userdata=session; +- ssh_socket_set_callbacks(s,&session->socket_callbacks); ++void ssh_packet_register_socket_callback(ssh_session session, ssh_socket s) ++{ ++ struct ssh_socket_callbacks_struct *callbacks = &session->socket_callbacks; ++ ++ callbacks->data = ssh_packet_socket_callback; ++ callbacks->connected = NULL; ++ callbacks->controlflow = ssh_packet_socket_controlflow_callback; ++ callbacks->userdata = session; ++ ssh_socket_set_callbacks(s, callbacks); + } + + /** @internal + * @brief sets the callbacks for the packet layer + */ +-void ssh_packet_set_callbacks(ssh_session session, ssh_packet_callbacks callbacks){ ++void ++ssh_packet_set_callbacks(ssh_session session, ssh_packet_callbacks callbacks) ++{ + if (session->packet_callbacks == NULL) { + session->packet_callbacks = ssh_list_new(); + if (session->packet_callbacks == NULL) { +@@ -1435,8 +1445,11 @@ + /** @internal + * @brief remove the callbacks from the packet layer + */ +-void ssh_packet_remove_callbacks(ssh_session session, ssh_packet_callbacks callbacks){ ++void ++ssh_packet_remove_callbacks(ssh_session session, ssh_packet_callbacks callbacks) ++{ + struct ssh_iterator *it = NULL; ++ + it = ssh_list_find(session->packet_callbacks, callbacks); + if (it != NULL) { + ssh_list_remove(session->packet_callbacks, it); +@@ -1446,12 +1459,15 @@ + /** @internal + * @brief sets the default packet handlers + */ +-void ssh_packet_set_default_callbacks(ssh_session session){ +- session->default_packet_callbacks.start=1; +- session->default_packet_callbacks.n_callbacks=sizeof(default_packet_handlers)/sizeof(ssh_packet_callback); +- session->default_packet_callbacks.user=session; +- session->default_packet_callbacks.callbacks=default_packet_handlers; +- ssh_packet_set_callbacks(session, &session->default_packet_callbacks); ++void ssh_packet_set_default_callbacks(ssh_session session) ++{ ++ struct ssh_packet_callbacks_struct *c = &session->default_packet_callbacks; ++ ++ c->start = 1; ++ c->n_callbacks = sizeof(default_packet_handlers) / sizeof(ssh_packet_callback); ++ c->user = session; ++ c->callbacks = default_packet_handlers; ++ ssh_packet_set_callbacks(session, c); + } + + /** @internal +@@ -1928,7 +1944,7 @@ + memcpy(session->next_crypto->session_id, + session->current_crypto->session_id, + session_id_len); +- session->next_crypto->session_id_len = session_id_len; ++ session->next_crypto->session_id_len = session_id_len; + + return SSH_OK; + } +diff --color -ru ../libssh-0.9.6/src/packet_cb.c ./src/packet_cb.c +--- ../libssh-0.9.6/src/packet_cb.c 2023-04-27 12:22:39.799925404 +0200 ++++ ./src/packet_cb.c 2023-04-27 12:24:04.682475779 +0200 +@@ -156,6 +156,9 @@ + session->next_crypto->digest_len); + 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_DEBUG,"Signature verified and valid"); +diff --color -ru ../libssh-0.9.6/src/server.c ./src/server.c +--- ../libssh-0.9.6/src/server.c 2023-04-27 12:22:39.800925405 +0200 ++++ ./src/server.c 2023-04-27 12:24:04.683475780 +0200 +@@ -92,7 +92,11 @@ + 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) { +@@ -335,117 +339,121 @@ + * @brief A function to be called each time a step has been done in the + * connection. + */ +-static void ssh_server_connection_callback(ssh_session session){ ++static void ssh_server_connection_callback(ssh_session session) ++{ + int rc; + +- switch(session->session_state){ +- case SSH_SESSION_STATE_NONE: +- case SSH_SESSION_STATE_CONNECTING: +- case SSH_SESSION_STATE_SOCKET_CONNECTED: +- break; +- case SSH_SESSION_STATE_BANNER_RECEIVED: +- if (session->clientbanner == NULL) { ++ switch (session->session_state) { ++ case SSH_SESSION_STATE_NONE: ++ case SSH_SESSION_STATE_CONNECTING: ++ case SSH_SESSION_STATE_SOCKET_CONNECTED: ++ break; ++ case SSH_SESSION_STATE_BANNER_RECEIVED: ++ if (session->clientbanner == NULL) { ++ goto error; ++ } ++ set_status(session, 0.4f); ++ SSH_LOG(SSH_LOG_DEBUG, ++ "SSH client banner: %s", session->clientbanner); ++ ++ /* Here we analyze the different protocols the server allows. */ ++ rc = ssh_analyze_banner(session, 1); ++ if (rc < 0) { ++ ssh_set_error(session, SSH_FATAL, ++ "No version of SSH protocol usable (banner: %s)", ++ session->clientbanner); ++ goto error; ++ } ++ ++ /* from now, the packet layer is handling incoming packets */ ++ session->socket_callbacks.data = ssh_packet_socket_callback; ++ ssh_packet_register_socket_callback(session, session->socket); ++ ++ ssh_packet_set_default_callbacks(session); ++ set_status(session, 0.5f); ++ session->session_state = SSH_SESSION_STATE_INITIAL_KEX; ++ if (ssh_send_kex(session) < 0) { ++ goto error; ++ } ++ break; ++ case SSH_SESSION_STATE_INITIAL_KEX: ++ /* TODO: This state should disappear in favor of get_key handle */ ++ break; ++ case SSH_SESSION_STATE_KEXINIT_RECEIVED: ++ set_status(session, 0.6f); ++ if ((session->flags & SSH_SESSION_FLAG_KEXINIT_SENT) == 0) { ++ if (server_set_kex(session) == SSH_ERROR) + goto error; +- } +- set_status(session, 0.4f); +- SSH_LOG(SSH_LOG_DEBUG, +- "SSH client banner: %s", session->clientbanner); +- +- /* Here we analyze the different protocols the server allows. */ +- rc = ssh_analyze_banner(session, 1); +- if (rc < 0) { +- ssh_set_error(session, SSH_FATAL, +- "No version of SSH protocol usable (banner: %s)", +- session->clientbanner); ++ /* We are in a rekeying, so we need to send the server kex */ ++ if (ssh_send_kex(session) < 0) + goto error; +- } ++ } ++ ssh_list_kex(&session->next_crypto->client_kex); // log client kex ++ if (ssh_kex_select_methods(session) < 0) { ++ goto error; ++ } ++ if (crypt_set_algorithms_server(session) == SSH_ERROR) ++ goto error; ++ set_status(session, 0.8f); ++ session->session_state = SSH_SESSION_STATE_DH; ++ break; ++ case SSH_SESSION_STATE_DH: ++ if (session->dh_handshake_state == DH_STATE_FINISHED) { + +- /* from now, the packet layer is handling incoming packets */ +- session->socket_callbacks.data=ssh_packet_socket_callback; +- ssh_packet_register_socket_callback(session, session->socket); +- +- 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) { +- goto error; +- } +- break; +- case SSH_SESSION_STATE_INITIAL_KEX: +- /* TODO: This state should disappear in favor of get_key handle */ +- break; +- case SSH_SESSION_STATE_KEXINIT_RECEIVED: +- set_status(session,0.6f); +- if(session->next_crypto->server_kex.methods[0]==NULL){ +- 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) +- goto error; +- } +- ssh_list_kex(&session->next_crypto->client_kex); // log client kex +- if (ssh_kex_select_methods(session) < 0) { ++ rc = ssh_packet_set_newkeys(session, SSH_DIRECTION_IN); ++ if (rc != SSH_OK) { + goto error; + } +- if (crypt_set_algorithms_server(session) == SSH_ERROR) +- goto error; +- set_status(session,0.8f); +- session->session_state=SSH_SESSION_STATE_DH; +- break; +- case SSH_SESSION_STATE_DH: +- if(session->dh_handshake_state==DH_STATE_FINISHED){ +- +- rc = ssh_packet_set_newkeys(session, SSH_DIRECTION_IN); +- if (rc != SSH_OK) { +- goto error; +- } ++ ++ /* ++ * If the client supports extension negotiation, we will send ++ * our supported extensions now. This is the first message after ++ * sending NEWKEYS message and after turning on crypto. ++ */ ++ if (session->extensions & SSH_EXT_NEGOTIATION && ++ session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { + + /* +- * If the client supports extension negotiation, we will send +- * our supported extensions now. This is the first message after +- * sending NEWKEYS message and after turning on crypto. ++ * Only send an SSH_MSG_EXT_INFO message the first time the ++ * client undergoes NEWKEYS. It is unexpected for this message ++ * to be sent upon rekey, and may cause clients to log error ++ * messages. ++ * ++ * The session_state can not be used for this purpose because it ++ * is re-set to SSH_SESSION_STATE_KEXINIT_RECEIVED during rekey. ++ * So, use the connected flag which transitions from non-zero ++ * below. ++ * ++ * See also: ++ * - https://bugzilla.mindrot.org/show_bug.cgi?id=2929 + */ +- if (session->extensions & SSH_EXT_NEGOTIATION && +- session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { +- +- /* +- * Only send an SSH_MSG_EXT_INFO message the first time the client +- * undergoes NEWKEYS. It is unexpected for this message to be sent +- * upon rekey, and may cause clients to log error messages. +- * +- * The session_state can not be used for this purpose because it is +- * re-set to SSH_SESSION_STATE_KEXINIT_RECEIVED during rekey. So, +- * use the connected flag which transitions from non-zero below. +- * +- * See also: +- * - https://bugzilla.mindrot.org/show_bug.cgi?id=2929 +- */ +- if (session->connected == 0) { +- ssh_server_send_extensions(session); +- } ++ if (session->connected == 0) { ++ ssh_server_send_extensions(session); + } ++ } + +- set_status(session,1.0f); +- session->connected = 1; +- session->session_state=SSH_SESSION_STATE_AUTHENTICATING; +- if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) +- session->session_state = SSH_SESSION_STATE_AUTHENTICATED; ++ set_status(session, 1.0f); ++ session->connected = 1; ++ session->session_state = SSH_SESSION_STATE_AUTHENTICATING; ++ if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) ++ session->session_state = SSH_SESSION_STATE_AUTHENTICATED; + +- } +- break; +- case SSH_SESSION_STATE_AUTHENTICATING: +- break; +- case SSH_SESSION_STATE_ERROR: +- goto error; +- default: +- ssh_set_error(session,SSH_FATAL,"Invalid state %d",session->session_state); ++ } ++ break; ++ case SSH_SESSION_STATE_AUTHENTICATING: ++ break; ++ case SSH_SESSION_STATE_ERROR: ++ goto error; ++ default: ++ ssh_set_error(session, SSH_FATAL, "Invalid state %d", ++ session->session_state); + } + + return; + error: + ssh_socket_close(session->socket); + session->alive = 0; +- session->session_state=SSH_SESSION_STATE_ERROR; ++ session->session_state = SSH_SESSION_STATE_ERROR; + } + + /** +@@ -459,16 +467,17 @@ + * @param user is a pointer to session + * @returns Number of bytes processed, or zero if the banner is not complete. + */ +-static int callback_receive_banner(const void *data, size_t len, void *user) { +- char *buffer = (char *) data; +- ssh_session session = (ssh_session) user; ++static int callback_receive_banner(const void *data, size_t len, void *user) ++{ ++ char *buffer = (char *)data; ++ ssh_session session = (ssh_session)user; + char *str = NULL; + size_t i; + int ret=0; + + for (i = 0; i < len; i++) { + #ifdef WITH_PCAP +- if(session->pcap_ctx && buffer[i] == '\n') { ++ if (session->pcap_ctx && buffer[i] == '\n') { + ssh_pcap_context_write(session->pcap_ctx, + SSH_PCAP_DIR_IN, + buffer, +@@ -477,11 +486,11 @@ + } + #endif + if (buffer[i] == '\r') { +- buffer[i]='\0'; ++ buffer[i] = '\0'; + } + + if (buffer[i] == '\n') { +- buffer[i]='\0'; ++ buffer[i] = '\0'; + + str = strdup(buffer); + /* number of bytes read */ +@@ -494,10 +503,11 @@ + return ret; + } + +- if(i > 127) { ++ if (i > 127) { + /* Too big banner */ + session->session_state = SSH_SESSION_STATE_ERROR; +- ssh_set_error(session, SSH_FATAL, "Receiving banner: too large banner"); ++ ssh_set_error(session, SSH_FATAL, ++ "Receiving banner: too large banner"); + + return 0; + } +@@ -525,10 +535,14 @@ + } + + /* Do the banner and key exchange */ +-int ssh_handle_key_exchange(ssh_session session) { ++int ssh_handle_key_exchange(ssh_session session) ++{ + int rc; +- if (session->session_state != SSH_SESSION_STATE_NONE) +- goto pending; ++ ++ if (session->session_state != SSH_SESSION_STATE_NONE) { ++ goto pending; ++ } ++ + rc = ssh_send_banner(session, 1); + if (rc < 0) { + return SSH_ERROR; +@@ -539,27 +553,28 @@ + session->ssh_connection_callback = ssh_server_connection_callback; + session->session_state = SSH_SESSION_STATE_SOCKET_CONNECTED; + ssh_socket_set_callbacks(session->socket,&session->socket_callbacks); +- session->socket_callbacks.data=callback_receive_banner; +- session->socket_callbacks.exception=ssh_socket_exception_callback; +- session->socket_callbacks.userdata=session; ++ session->socket_callbacks.data = callback_receive_banner; ++ session->socket_callbacks.exception = ssh_socket_exception_callback; ++ session->socket_callbacks.userdata = session; + + rc = server_set_kex(session); + if (rc < 0) { + return SSH_ERROR; + } +- pending: ++pending: + rc = ssh_handle_packets_termination(session, SSH_TIMEOUT_USER, +- ssh_server_kex_termination,session); ++ ssh_server_kex_termination,session); + SSH_LOG(SSH_LOG_PACKET, "ssh_handle_key_exchange: current state : %d", +- session->session_state); +- if (rc != SSH_OK) +- return rc; ++ session->session_state); ++ if (rc != SSH_OK) { ++ return rc; ++ } + if (session->session_state == SSH_SESSION_STATE_ERROR || + session->session_state == SSH_SESSION_STATE_DISCONNECTED) { +- return SSH_ERROR; ++ return SSH_ERROR; + } + +- return SSH_OK; ++ return SSH_OK; + } + + /* messages */ +diff --color -ru ../libssh-0.9.6/src/token.c ./src/token.c +--- ../libssh-0.9.6/src/token.c 2021-03-15 08:11:33.000000000 +0100 ++++ ./src/token.c 2023-04-27 12:21:30.260820657 +0200 +@@ -87,7 +87,7 @@ + return NULL; + } + +- tokens->buffer= strdup(chain); ++ tokens->buffer = strdup(chain); + if (tokens->buffer == NULL) { + goto error; + } +diff --color -ru ../libssh-0.9.6/src/wrapper.c ./src/wrapper.c +--- ../libssh-0.9.6/src/wrapper.c 2021-08-26 14:27:44.000000000 +0200 ++++ ./src/wrapper.c 2023-04-27 12:21:30.260820657 +0200 +@@ -147,15 +147,16 @@ + SAFE_FREE(cipher); + } + +-struct ssh_crypto_struct *crypto_new(void) { +- struct ssh_crypto_struct *crypto; ++struct ssh_crypto_struct *crypto_new(void) ++{ ++ struct ssh_crypto_struct *crypto; + +- crypto = malloc(sizeof(struct ssh_crypto_struct)); +- if (crypto == NULL) { +- return NULL; +- } +- ZERO_STRUCTP(crypto); +- return crypto; ++ crypto = malloc(sizeof(struct ssh_crypto_struct)); ++ if (crypto == NULL) { ++ return NULL; ++ } ++ ZERO_STRUCTP(crypto); ++ return crypto; + } + + void crypto_free(struct ssh_crypto_struct *crypto) +diff --color -ru ../libssh-0.9.6/tests/client/torture_rekey.c ./tests/client/torture_rekey.c +--- ../libssh-0.9.6/tests/client/torture_rekey.c 2021-08-26 14:27:44.000000000 +0200 ++++ ./tests/client/torture_rekey.c 2023-04-27 12:24:04.684475780 +0200 +@@ -651,6 +651,92 @@ + #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; + struct CMUnitTest tests[] = { +@@ -671,19 +757,34 @@ + cmocka_unit_test_setup_teardown(torture_rekey_different_kex, + 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), +-#endif /* WITH_SFTP */ +- cmocka_unit_test_setup_teardown(torture_rekey_server_different_kex, ++ cmocka_unit_test_setup_teardown(torture_rekey_guess_recv, + session_setup, + session_teardown), +- /* TODO verify the two rekey are possible and the states are not broken after rekey */ ++ cmocka_unit_test_setup_teardown(torture_rekey_guess_wrong_recv, ++ session_setup, ++ session_teardown), ++#endif /* WITH_SFTP */ + }; + + ssh_init(); diff --git a/SOURCES/s390x_fix.patch b/SOURCES/s390x_fix.patch new file mode 100644 index 0000000..d06e348 --- /dev/null +++ b/SOURCES/s390x_fix.patch @@ -0,0 +1,19 @@ +diff --git a/src/packet.c b/src/packet.c +index ec4a7203..a81eb8e3 100644 +--- a/src/packet.c ++++ b/src/packet.c +@@ -1752,10 +1752,12 @@ static bool + ssh_packet_in_rekey(ssh_session session) + { + /* We know we are rekeying if we are authenticated and the DH +- * status is not finished ++ * status is not finished, but we only queue packets until we've ++ * sent our NEWKEYS. + */ + return (session->flags & SSH_SESSION_FLAG_AUTHENTICATED) && +- (session->dh_handshake_state != DH_STATE_FINISHED); ++ (session->dh_handshake_state != DH_STATE_FINISHED) && ++ (session->dh_handshake_state != DH_STATE_NEWKEYS_SENT); + } + + int ssh_packet_send(ssh_session session) diff --git a/SPECS/libssh.spec b/SPECS/libssh.spec new file mode 100644 index 0000000..c669efb --- /dev/null +++ b/SPECS/libssh.spec @@ -0,0 +1,516 @@ +Name: libssh +Version: 0.9.6 +Release: 14%{?dist} +Summary: A library implementing the SSH protocol +License: LGPLv2+ +URL: http://www.libssh.org + +Source0: https://www.libssh.org/files/0.9/%{name}-%{version}.tar.xz +Source1: https://www.libssh.org/files/0.9/%{name}-%{version}.tar.xz.asc +Source2: https://cryptomilk.org/gpgkey-8DFF53E18F2ABC8D8F3C92237EE0FC4DCC014E3D.gpg#/%{name}.keyring +Source3: libssh_client.config +Source4: libssh_server.config + +Patch0: loglevel.patch +Patch1: s390x_fix.patch +Patch2: null_dereference_rekey.patch +Patch3: auth_bypass.patch +Patch4: fix_tests.patch +Patch5: covscan23.patch +Patch6: CVE-2023-48795.patch +Patch7: CVE-2023-6004.patch +Patch8: CVE-2023-6918.patch + +BuildRequires: cmake +BuildRequires: doxygen +BuildRequires: gcc-c++ +BuildRequires: gnupg2 +BuildRequires: openssl-devel +BuildRequires: pkgconfig +BuildRequires: zlib-devel +BuildRequires: krb5-devel +BuildRequires: libcmocka-devel +BuildRequires: openssh-clients +BuildRequires: openssh-server +BuildRequires: pam_wrapper +BuildRequires: socket_wrapper +BuildRequires: nss_wrapper +BuildRequires: uid_wrapper +BuildRequires: nmap-ncat + +Requires: crypto-policies +Requires: %{name}-config = %{version}-%{release} + +%ifarch aarch64 ppc64 ppc64le s390x x86_64 +Provides: libssh_threads.so()(64bit) +Provides: libssh_threads.so.4()(64bit) +%else +Provides: libssh_threads.so +Provides: libssh_threads.so.4 +%endif + +%description +The ssh library was designed to be used by programmers needing a working SSH +implementation by the mean of a library. The complete control of the client is +made by the programmer. With libssh, you can remotely execute programs, transfer +files, use a secure and transparent tunnel for your remote programs. With its +Secure FTP implementation, you can play with remote files easily, without +third-party programs others than libcrypto (from openssl). + +%package devel +Summary: Development files for %{name} +Requires: %{name}%{?_isa} = %{version}-%{release} + +%description devel +The %{name}-devel package contains libraries and header files for developing +applications that use %{name}. + +%package config +Summary: Configuration files for %{name} +BuildArch: noarch +Obsoletes: %{name} < 0.9.0-1 + +%description config +The %{name}-config package provides the default configuration files for %{name}. + +%prep +gpgv2 --quiet --keyring %{SOURCE2} %{SOURCE1} %{SOURCE0} +%autosetup -p1 + +%build +if test ! -e "obj"; then + mkdir obj +fi +pushd obj + +%cmake .. \ + -DUNIT_TESTING=ON \ + -DCLIENT_TESTING=ON \ + -DSERVER_TESTING=ON \ + -DGLOBAL_CLIENT_CONFIG="%{_sysconfdir}/libssh/libssh_client.config" \ + -DGLOBAL_BIND_CONFIG="%{_sysconfdir}/libssh/libssh_server.config" + + +%make_build VERBOSE=1 +make docs + +popd + +%install +make DESTDIR=%{buildroot} install/fast -C obj +install -d -m755 %{buildroot}%{_sysconfdir}/libssh +install -m644 %{SOURCE3} %{buildroot}%{_sysconfdir}/libssh/libssh_client.config +install -m644 %{SOURCE4} %{buildroot}%{_sysconfdir}/libssh/libssh_server.config + +# +# Workaround for the removal of libssh_threads.so +# +# This will allow libraries which link against libssh_threads.so or packages +# requiring it to continue working. +# +pushd %{buildroot}%{_libdir} +for i in libssh.so.4*; +do + _target="${i}" + _link_name="${i%libssh*}libssh_threads${i##*libssh}" + if [ -L "${i}" ]; then + _target="$(readlink ${i})" + fi + ln -s "${_target}" "${_link_name}" +done; +popd + +%ldconfig_scriptlets + +%check +pushd obj +ctest --output-on-failure +popd + +%files +%doc AUTHORS BSD ChangeLog README +%license COPYING +%{_libdir}/libssh.so.4* +%{_libdir}/libssh_threads.so.4* + +%files devel +%doc obj/doc/html +%{_includedir}/libssh/ +# own this to avoid dep on cmake -- rex +%dir %{_libdir}/cmake/ +%{_libdir}/cmake/libssh/ +%{_libdir}/pkgconfig/libssh.pc +%{_libdir}/libssh.so + +%files config +%attr(0755,root,root) %dir %{_sysconfdir}/libssh +%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/libssh/libssh_client.config +%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/libssh/libssh_server.config + +%changelog +* Fri Mar 29 2024 MSVSphere Packaging Team - 0.9.6-14 +- Rebuilt for MSVSphere 8.10 beta + +* Mon Feb 26 2024 Sahana Prasad - 0.9.6-14 +- Fix CVE-2023-48795 Prefix truncation attack on Binary Packet Protocol (BPP) +- Fix CVE-2023-6918 Missing checks for return values for digests +- Fix CVE-2023-6004 ProxyCommand/ProxyJump features allow injection + of malicious code through hostname +- Note: version is bumped from 12 to 14 directly, as the z-stream + version in 8.9 also has 13. So bumping it to 14, will prevent + upgrade conflicts. +- Resolves:RHEL-19690, RHEL-17244, RHEL-19312 + +* Mon May 15 2023 Norbert Pocs - 0.9.6-12 +- Fix loglevel regression +- Related: rhbz#2182251, rhbz#2189742 + +* Thu May 04 2023 Norbert Pocs - 0.9.6-11 +- .fmf/version is needed to run the tests +- Related: rhbz#2182251, rhbz#2189742 + +* Wed May 03 2023 Norbert Pocs - 0.9.6-10 +- Add missing ci.fmf file +- Related: rhbz#2182251, rhbz#2189742 + +* Wed May 03 2023 Norbert Pocs - 0.9.6-9 +- Fix covscan errors found at gating +- Related: rhbz#2182251, rhbz#2189742 + +* Tue May 02 2023 Norbert Pocs - 0.9.6-8 +- Backport test fixing commits to make the build pass +- Related: rhbz#2182251, rhbz#2189742 + +* Thu Apr 27 2023 Norbert Pocs - 0.9.6-7 +- Fix NULL dereference during rekeying with algorithm guessing + GHSL-2023-032 / CVE-2023-1667 +- Fix possible authentication bypass + GHSL 2023-085 / CVE-2023-2283 +- Resolves: rhbz#2182251, rhbz#2189742 + +* Fri Jan 06 2023 Norbert Pocs - 0.9.6-6 +- Enable client and server testing build time +- Fix failing rekey test on arch s390x +- Resolves: rhbz#2126342 + +* Mon Dec 05 2022 Stanislav Zidek - 0.9.6-5 +- Fix CI configuration for new TMT +- Resolves: rhbz#2149910 + +* Mon Nov 28 2022 Norbert Pocs - 0.9.6-4 +- Make VERBOSE and lower log levels less verbose +- Resolves: rhbz#2091512 + +* Fri Nov 05 2021 Norbert Pocs - 0.9.6-3 +- Remove STI tests + +* Thu Oct 21 2021 Norbert Pocs - 0.9.6-2 +- Remove bad patch causing errors +- Adding BuildRequires for openssh (SSHD support) + +* Thu Oct 14 2021 Norbert Pocs - 0.9.6-1 +- Fix CVE-2021-3634: Fix possible heap-buffer overflow when + rekeying with different key exchange mechanism +- Rebase to version 0.9.6 +- Rename SSHD_EXECUTABLE to SSH_EXECUTABLE in tests/torture.c +- Resolves: rhbz#1896651, rhbz#1994600 + +* Thu Oct 14 2021 Sahana Prasad - 0.9.4-4 +- Revert previous commit as it is incorrect. + +* Thu Oct 14 2021 Norbert Pocs - 0.9.6-1 +- Fix CVE-2021-3634: Fix possible heap-buffer overflow when + rekeying with different key exchange mechanism (#1978810) + +* Wed Apr 21 2021 Sahana Prasad - 0.9.4-3 +- Fix CVE-2020-16135 NULL pointer dereference in sftpserver.c if + ssh_buffer_new returns NULL (#1862646) + +* Wed Jun 24 2020 Anderson Sasaki - 0.9.4-2 +- Do not return error when server properly closed the channel (#1849071) +- Add a test for CVE-2019-14889 +- Do not parse configuration file in torture_knownhosts test + +* Tue May 26 2020 Anderson Sasaki - 0.9.4-1 +- Update to version 0.9.4 + https://www.libssh.org/2020/04/09/libssh-0-9-4-and-libssh-0-8-9-security-release/ +- Fixed CVE-2019-14889 (#1781782) +- Fixed CVE-2020-1730 (#1802422) +- Create missing directories in the path provided for known_hosts files (#1733914) +- Removed inclusion of OpenSSH server configuration file from + libssh_server.config (#1821339) + +* Mon Aug 05 2019 Anderson Sasaki - 0.9.0-4 +- Skip 1024 bits RSA key generation test in FIPS mode (#1734485) + +* Thu Jul 11 2019 Anderson Sasaki - 0.9.0-3 +- Add Obsoletes in libssh-config to avoid conflict with old libssh which + installed the configuration files. + +* Wed Jul 10 2019 Anderson Sasaki - 0.9.0-2 +- Eliminate circular dependency with libssh-config subpackage + +* Wed Jul 10 2019 Anderson Sasaki - 0.9.0-1 +- Update to version 0.9.0 + https://www.libssh.org/2019/06/28/libssh-0-9-0/ +- Added explicit Requires for crypto-policies +- Do not ignore known_hosts keys when SSH_OPTIONS_HOSTKEYS is set +- Provide the configuration files in a separate libssh-config subpackage + +* Mon Jun 17 2019 Anderson Sasaki - 0.8.91-0.1 +- Update to 0.9.0 pre release version (0.8.91) +- Added default configuration files for client and server +- Removed unused patch files left behind +- Fixed issues found to run upstream test suite with SELinux + +* Fri Dec 14 2018 Anderson Sasaki - 0.8.5-2 +- Fix more regressions introduced by the fixes for CVE-2018-10933 + +* Thu Nov 29 2018 Anderson Sasaki - 0.8.5-1 +- Update to version 0.8.5 + * Fixed an issue where global known_hosts file was ignored (#1649321) + * Fixed ssh_get_fd() to return writable file descriptor (#1649319) + * Fixed regression introduced in known_hosts parsing (#1649315) + * Fixed a regression which caused only the first algorithm in known_hosts to + be considered (#1638790) + +* Thu Nov 08 2018 Anderson Sasaki - 0.8.3-5 +- Fix regressions introduced by the fixes for CVE-2018-10933 + +* Wed Oct 17 2018 Nikos Mavrogiannopoulos - 0.8.3-4 +- Fix for authentication bypass issue in server implementation (#1639926) + +* Tue Oct 02 2018 Anderson Sasaki - 0.8.3-3 +- Fixed errors found by static code analysis (#1602594) + +* Fri Sep 21 2018 Anderson Sasaki - 0.8.3-1 +- Update to version 0.8.3 + * Added support for rsa-sha2 (#1610882) + * Added support to parse private keys in openssh container format (other than + ed25519) (#1622983) + * Added support for diffie-hellman-group18-sha512 and + diffie-hellman-group16-sha512 (#1610885) + * Added ssh_get_fingerprint_hash() + * Added ssh_pki_export_privkey_base64() + * Added support for Match keyword in config file + * Improved performance and reduced memory footprint for sftp + * Fixed ecdsa publickey auth + * Fixed reading a closed channel + * Added support to announce posix-rename@openssh.com and hardlink@openssh.com + in the sftp server + * Use -fstack-protector-strong if possible (#1624135) + +* Wed Aug 15 2018 Anderson Sasaki - 0.8.1-4 +- Fix the creation of symbolic links for libssh_threads.so.4 + +* Wed Aug 15 2018 Anderson Sasaki - 0.8.1-3 +- Add missing Provides for libssh_threads.so.4 + +* Tue Aug 14 2018 Anderson Sasaki - 0.8.1-2 +- Add Provides for libssh_threads.so to unbreak applications +- Fix ABIMap detection to not depend on python to build + +* Mon Aug 13 2018 Andreas Schneider - 0.8.1-1 +- Update to version 0.8.1 + https://www.libssh.org/2018/08/13/libssh-0-8-1/ + +* Fri Aug 10 2018 Andreas Schneider - 0.8.0-1 +- Update to version 0.8.0 + https://www.libssh.org/2018/08/10/libssh-0-8-0/ + +* Fri Jul 13 2018 Fedora Release Engineering - 0.7.5-9 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild + +* Wed Mar 07 2018 Rex Dieter - 0.7.5-8 +- BR: gcc-c++, use %%make_build + +* Wed Feb 07 2018 Fedora Release Engineering - 0.7.5-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild +- Related: bug#1614611 + +* Thu Feb 01 2018 Andreas Schneider - 0.7.5-6 +- resolves: #1540021 - Build against OpenSSL 1.1 + +* Wed Jan 31 2018 Igor Gnatenko - 0.7.5-5 +- Switch to %%ldconfig_scriptlets + +* Fri Dec 29 2017 Andreas Schneider - 0.7.5-4 +- Fix parsing ssh_config + +* Thu Aug 03 2017 Fedora Release Engineering - 0.7.5-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Wed Jul 26 2017 Fedora Release Engineering - 0.7.5-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Wed Apr 26 2017 Peter Robinson 0.7.5-1 +- Update to version 0.7.5 + +* Sat Mar 11 2017 Rex Dieter - 0.7.4-2 +- BR: compat-openssl10-devel (f26+, #1423088) +- use %%license +- -devel: drop hardcoded pkgconfig dep (let autodeps handle it) +- %%files: track library sonames, simplify -devel +- %%install: use 'install/fast' target +- .spec cosmetics, drop deprecated %%clean section + +* Wed Feb 08 2017 Andreas Schneider - 0.7.4-1 +- Update to version 0.7.4 + * Added id_ed25519 to the default identity list + * Fixed sftp EOF packet handling + * Fixed ssh_send_banner() to confirm with RFC 4253 + * Fixed some memory leaks +- resolves: #1419007 + +* Wed Feb 24 2016 Andreas Schneider - 0.7.3-1 +- resolves: #1311259 - Fix CVE-2016-0739 +- resolves: #1311332 - Update to version 0.7.3 + * Fixed CVE-2016-0739 + * Fixed ssh-agent on big endian + * Fixed some documentation issues +- Enabled GSSAPI support + +* Thu Feb 04 2016 Fedora Release Engineering - 0.7.2-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Thu Oct 22 2015 Andreas Schneider - 0.7.2-2 +- resolves: #1271230 - Fix ssh-agent support on big endian + +* Wed Sep 30 2015 Andreas Schneider - 0.7.2-1 +- Update to version 0.7.2 + * Fixed OpenSSL detection on Windows + * Fixed return status for ssh_userauth_agent() + * Fixed KEX to prefer hmac-sha2-256 + * Fixed sftp packet handling + * Fixed return values of ssh_key_is_(public|private) + * Fixed bug in global success reply +- resolves: #1267346 + +* Tue Jun 30 2015 Andreas Schneider - 0.7.1-1 +- Update to version 0.7.1 + * Fixed SSH_AUTH_PARTIAL auth with auto public key + * Fixed memory leak in session options + * Fixed allocation of ed25519 public keys + * Fixed channel exit-status and exit-signal + * Reintroduce ssh_forward_listen() + +* Wed Jun 17 2015 Fedora Release Engineering - 0.7.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Thu May 21 2015 Orion Poplawski - 0.7.0-2 +- Add patch to fix undefined symbol: ssh_forward_listen (bug #1221310) + +* Mon May 11 2015 Andreas Schneider - 0.7.0-1 +- Update to version 0.7.0 + * Added support for ed25519 keys + * Added SHA2 algorithms for HMAC + * Added improved and more secure buffer handling code + * Added callback for auth_none_function + * Added support for ECDSA private key signing + * Added more tests + * Fixed a lot of bugs + * Improved API documentation + +* Thu Apr 30 2015 Andreas Schneider - 0.6.5-1 +- resolves: #1213775 - Security fix for CVE-2015-3146 +- resolves: #1218076 - Security fix for CVE-2015-3146 + +* Fri Dec 19 2014 - Andreas Schneider - 0.6.4-1 +- Security fix for CVE-2014-8132. + +* Sun Aug 17 2014 Fedora Release Engineering - 0.6.3-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Sat Jun 07 2014 Fedora Release Engineering - 0.6.3-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Tue Mar 04 2014 - Andreas Schneider - 0.6.3-1 +- Fix CVE-2014-0017. + +* Mon Feb 10 2014 - Andreas Schneider - 0.6.1-1 +- Update to version 0.6.1. +- resolves: #1056757 - Fix scp mode. +- resolves: #1053305 - Fix known_hosts heuristic. + +* Wed Jan 08 2014 - Andreas Schneider - 0.6.0-1 +- Update to 0.6.0 + +* Fri Jul 26 2013 - Andreas Schneider - 0.5.5-1 +- Update to 0.5.5. +- Clenup the spec file. + +* Thu Jul 18 2013 Simone Caronni - 0.5.4-5 +- Add EPEL 5 support. +- Add Debian patches to enable Doxygen documentation. + +* Tue Jul 16 2013 Simone Caronni - 0.5.4-4 +- Add patch for #982685. + +* Mon Jun 10 2013 Simone Caronni - 0.5.4-3 +- Clean up SPEC file and fix rpmlint complaints. + +* Thu Feb 14 2013 Fedora Release Engineering - 0.5.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Wed Jan 23 2013 Petr Lautrbach 0.5.4-1 +- update to security 0.5.4 release +- CVE-2013-0176 (#894407) + +* Tue Nov 20 2012 Petr Lautrbach 0.5.3-1 +- update to security 0.5.3 release (#878465) + +* Thu Jul 19 2012 Fedora Release Engineering - 0.5.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Thu Feb 02 2012 Petr Lautrbach 0.5.2-1 +- update to 0.5.2 version (#730270) + +* Fri Jan 13 2012 Fedora Release Engineering - 0.5.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Wed Jun 1 2011 Jan F. Chadima - 0.5.0-1 +- bounce versionn to 0.5.0 (#709785) +- the support for protocol v1 is disabled + +* Tue Feb 08 2011 Fedora Release Engineering - 0.4.8-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Wed Jan 19 2011 Jan F. Chadima - 0.4.8-1 +- bounce versionn to 0.4.8 (#670456) + +* Mon Sep 6 2010 Jan F. Chadima - 0.4.6-1 +- bounce versionn to 0.4.6 (#630602) + +* Thu Jun 3 2010 Jan F. Chadima - 0.4.4-1 +- bounce versionn to 0.4.4 (#598592) + +* Wed May 19 2010 Jan F. Chadima - 0.4.3-1 +- bounce versionn to 0.4.3 (#593288) + +* Tue Mar 16 2010 Jan F. Chadima - 0.4.2-1 +- bounce versionn to 0.4.2 (#573972) + +* Tue Feb 16 2010 Jan F. Chadima - 0.4.1-1 +- bounce versionn to 0.4.1 (#565870) + +* Fri Dec 11 2009 Jan F. Chadima - 0.4.0-1 +- bounce versionn to 0.4.0 (#541010) + +* Thu Nov 26 2009 Jan F. Chadima - 0.3.92-2 +- typo in spec file + +* Thu Nov 26 2009 Jan F. Chadima - 0.3.92-1 +- bounce versionn to 0.3.92 (0.4 beta2) (#541010) + +* Fri Aug 21 2009 Tomas Mraz - 0.2-4 +- rebuilt with new openssl + +* Sat Jul 25 2009 Fedora Release Engineering - 0.2-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Tue Jun 02 2009 Jan F. Chadima - 0.2-2 +- Small changes during review + +* Mon Jun 01 2009 Jan F. Chadima - 0.2-1 +- Initial build +