aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelen <jjelen@redhat.com>2023-03-17 14:05:01 +0100
committerAndreas Schneider <asn@cryptomilk.org>2023-05-04 11:52:17 +0200
commitb759ae557d611ba347392c051504de474a8d9b60 (patch)
tree404006b6a3440e3300e1a2d0ed6be55206fad2d4
parent6df2daea040c47daff0a861a30761092886fe748 (diff)
downloadlibssh-b759ae557d611ba347392c051504de474a8d9b60.tar.gz
libssh-b759ae557d611ba347392c051504de474a8d9b60.tar.xz
libssh-b759ae557d611ba347392c051504de474a8d9b60.zip
CVE-2023-1667:dh: Expose the callback cleanup functions
These will be helpful when we already sent the first key exchange packet, but we found out that our guess was wrong and we need to initiate different key exchange method with different callbacks. Signed-off-by: Jakub Jelen <jjelen@redhat.com> Reviewed-by: Norbert Pocs <npocs@redhat.com> Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
-rw-r--r--include/libssh/curve25519.h1
-rw-r--r--include/libssh/dh-gex.h1
-rw-r--r--include/libssh/dh.h1
-rw-r--r--include/libssh/ecdh.h1
-rw-r--r--src/curve25519.c7
-rw-r--r--src/dh-gex.c7
-rw-r--r--src/dh.c7
-rw-r--r--src/ecdh.c7
-rw-r--r--src/kex.c38
9 files changed, 66 insertions, 4 deletions
diff --git a/include/libssh/curve25519.h b/include/libssh/curve25519.h
index 8c89267c..a55f52c7 100644
--- a/include/libssh/curve25519.h
+++ b/include/libssh/curve25519.h
@@ -52,6 +52,7 @@ typedef unsigned char ssh_curve25519_privkey[CURVE25519_PRIVKEY_SIZE];
int ssh_client_curve25519_init(ssh_session session);
+void ssh_client_curve25519_remove_callbacks(ssh_session session);
#ifdef WITH_SERVER
void ssh_server_curve25519_init(ssh_session session);
diff --git a/include/libssh/dh-gex.h b/include/libssh/dh-gex.h
index d12f9b8f..0f547e37 100644
--- a/include/libssh/dh-gex.h
+++ b/include/libssh/dh-gex.h
@@ -28,6 +28,7 @@ extern "C" {
#endif
int ssh_client_dhgex_init(ssh_session session);
+void ssh_client_dhgex_remove_callbacks(ssh_session session);
#ifdef WITH_SERVER
void ssh_server_dhgex_init(ssh_session session);
diff --git a/include/libssh/dh.h b/include/libssh/dh.h
index e7a9e68d..8824cfc4 100644
--- a/include/libssh/dh.h
+++ b/include/libssh/dh.h
@@ -79,6 +79,7 @@ int ssh_dh_get_next_server_publickey_blob(ssh_session session,
ssh_string *pubkey_blob);
int ssh_client_dh_init(ssh_session session);
+void ssh_client_dh_remove_callbacks(ssh_session session);
#ifdef WITH_SERVER
void ssh_server_dh_init(ssh_session session);
#endif /* WITH_SERVER */
diff --git a/include/libssh/ecdh.h b/include/libssh/ecdh.h
index e6907c0b..4c4c54eb 100644
--- a/include/libssh/ecdh.h
+++ b/include/libssh/ecdh.h
@@ -49,6 +49,7 @@ extern "C" {
extern struct ssh_packet_callbacks_struct ssh_ecdh_client_callbacks;
/* Backend-specific functions. */
int ssh_client_ecdh_init(ssh_session session);
+void ssh_client_ecdh_remove_callbacks(ssh_session session);
int ecdh_build_k(ssh_session session);
#ifdef WITH_SERVER
diff --git a/src/curve25519.c b/src/curve25519.c
index 7a8b9719..66291b5f 100644
--- a/src/curve25519.c
+++ b/src/curve25519.c
@@ -172,6 +172,11 @@ int ssh_client_curve25519_init(ssh_session session)
return rc;
}
+void ssh_client_curve25519_remove_callbacks(ssh_session session)
+{
+ ssh_packet_remove_callbacks(session, &ssh_curve25519_client_callbacks);
+}
+
static int ssh_curve25519_build_k(ssh_session session)
{
ssh_curve25519_pubkey k;
@@ -285,7 +290,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_client_curve25519_reply){
(void)type;
(void)user;
- ssh_packet_remove_callbacks(session, &ssh_curve25519_client_callbacks);
+ ssh_client_curve25519_remove_callbacks(session);
pubkey_blob = ssh_buffer_get_ssh_string(packet);
if (pubkey_blob == NULL) {
diff --git a/src/dh-gex.c b/src/dh-gex.c
index ffc145f6..91617081 100644
--- a/src/dh-gex.c
+++ b/src/dh-gex.c
@@ -248,6 +248,11 @@ error:
return SSH_PACKET_USED;
}
+void ssh_client_dhgex_remove_callbacks(ssh_session session)
+{
+ ssh_packet_remove_callbacks(session, &ssh_dhgex_client_callbacks);
+}
+
static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_reply)
{
struct ssh_crypto_struct *crypto=session->next_crypto;
@@ -258,7 +263,7 @@ static SSH_PACKET_CALLBACK(ssh_packet_client_dhgex_reply)
(void)user;
SSH_LOG(SSH_LOG_PROTOCOL, "SSH_MSG_KEX_DH_GEX_REPLY received");
- ssh_packet_remove_callbacks(session, &ssh_dhgex_client_callbacks);
+ ssh_client_dhgex_remove_callbacks(session);
rc = ssh_buffer_unpack(packet,
"SBS",
&pubkey_blob, &server_pubkey,
diff --git a/src/dh.c b/src/dh.c
index 77f2f7a4..011d97b3 100644
--- a/src/dh.c
+++ b/src/dh.c
@@ -354,6 +354,11 @@ error:
return SSH_ERROR;
}
+void ssh_client_dh_remove_callbacks(ssh_session session)
+{
+ ssh_packet_remove_callbacks(session, &ssh_dh_client_callbacks);
+}
+
SSH_PACKET_CALLBACK(ssh_packet_client_dh_reply){
struct ssh_crypto_struct *crypto=session->next_crypto;
ssh_string pubkey_blob = NULL;
@@ -363,7 +368,7 @@ SSH_PACKET_CALLBACK(ssh_packet_client_dh_reply){
(void)type;
(void)user;
- ssh_packet_remove_callbacks(session, &ssh_dh_client_callbacks);
+ ssh_client_dh_remove_callbacks(session);
rc = ssh_buffer_unpack(packet, "SBS", &pubkey_blob, &server_pubkey,
&crypto->dh_server_signature);
diff --git a/src/ecdh.c b/src/ecdh.c
index a4c07ccb..e5b11ba9 100644
--- a/src/ecdh.c
+++ b/src/ecdh.c
@@ -43,6 +43,11 @@ struct ssh_packet_callbacks_struct ssh_ecdh_client_callbacks = {
.user = NULL
};
+void ssh_client_ecdh_remove_callbacks(ssh_session session)
+{
+ ssh_packet_remove_callbacks(session, &ssh_ecdh_client_callbacks);
+}
+
/** @internal
* @brief parses a SSH_MSG_KEX_ECDH_REPLY packet and sends back
* a SSH_MSG_NEWKEYS
@@ -55,7 +60,7 @@ SSH_PACKET_CALLBACK(ssh_packet_client_ecdh_reply){
(void)type;
(void)user;
- ssh_packet_remove_callbacks(session, &ssh_ecdh_client_callbacks);
+ ssh_client_ecdh_remove_callbacks(session);
pubkey_blob = ssh_buffer_get_ssh_string(packet);
if (pubkey_blob == NULL) {
ssh_set_error(session,SSH_FATAL, "No public key in packet");
diff --git a/src/kex.c b/src/kex.c
index 426a606c..991ccbc8 100644
--- a/src/kex.c
+++ b/src/kex.c
@@ -818,6 +818,44 @@ kex_select_kex_type(const char *kex)
return 0;
}
+
+/** @internal
+ * @brief Reverts guessed callbacks set during the dh_handshake()
+ * @param session session handle
+ * @returns void
+ */
+static void revert_kex_callbacks(ssh_session session)
+{
+ switch (session->next_crypto->kex_type) {
+ case SSH_KEX_DH_GROUP1_SHA1:
+ case SSH_KEX_DH_GROUP14_SHA1:
+ case SSH_KEX_DH_GROUP14_SHA256:
+ case SSH_KEX_DH_GROUP16_SHA512:
+ case SSH_KEX_DH_GROUP18_SHA512:
+ ssh_client_dh_remove_callbacks(session);
+ break;
+#ifdef WITH_GEX
+ case SSH_KEX_DH_GEX_SHA1:
+ case SSH_KEX_DH_GEX_SHA256:
+ ssh_client_dhgex_remove_callbacks(session);
+ break;
+#endif /* WITH_GEX */
+#ifdef HAVE_ECDH
+ case SSH_KEX_ECDH_SHA2_NISTP256:
+ case SSH_KEX_ECDH_SHA2_NISTP384:
+ case SSH_KEX_ECDH_SHA2_NISTP521:
+ ssh_client_ecdh_remove_callbacks(session);
+ break;
+#endif
+#ifdef HAVE_CURVE25519
+ case SSH_KEX_CURVE25519_SHA256:
+ case SSH_KEX_CURVE25519_SHA256_LIBSSH_ORG:
+ ssh_client_curve25519_remove_callbacks(session);
+ break;
+#endif
+ }
+}
+
/** @brief Select the different methods on basis of client's and
* server's kex messages, and watches out if a match is possible.
*/