libssh: Fix matching user-specified MD5 hex key

Resolves: RHEL-94574
This commit is contained in:
Carlos Santos 2025-06-10 15:35:13 +02:00 committed by Jacek Migacz
parent 46bb6035af
commit d5e096563c
2 changed files with 346 additions and 1 deletions

338
0065-md5-hex-key.patch Normal file
View File

@ -0,0 +1,338 @@
From b1a049b4c024ea69ef571da8def3cc13889430f4 Mon Sep 17 00:00:00 2001
From: Jay Satiro <raysatiro@yahoo.com>
Date: Sun, 23 Feb 2020 18:37:09 -0500
Subject: [PATCH] libssh: Fix matching user-specified MD5 hex key
Prior to this change a match would never be successful because it
was mistakenly coded to compare binary data from libssh to a
user-specified hex string (ie CURLOPT_SSH_HOST_PUBLIC_KEY_MD5).
Reported-by: fds242@users.noreply.github.com
Fixes https://github.com/curl/curl/issues/4971
Closes https://github.com/curl/curl/pull/4974
(cherry picked from commit 09aa807240b9dcde78a919ff712316a1daf0655e)
---
lib/ssh-libssh.c | 20 ++++++++++++++++---
tests/FILEFORMAT | 1 +
tests/data/Makefile.inc | 1 +
tests/data/test664 | 44 +++++++++++++++++++++++++++++++++++++++++
tests/data/test665 | 44 +++++++++++++++++++++++++++++++++++++++++
tests/runtests.pl | 24 ++++++++++++++++++++++
tests/sshhelp.pm | 3 +++
tests/sshserver.pl | 31 +++++++++++++++++++++++++----
8 files changed, 161 insertions(+), 7 deletions(-)
create mode 100644 tests/data/test664
create mode 100644 tests/data/test665
diff --git a/lib/ssh-libssh.c b/lib/ssh-libssh.c
index 7d590891c..c203d6336 100644
--- a/lib/ssh-libssh.c
+++ b/lib/ssh-libssh.c
@@ -327,13 +327,27 @@ static int myssh_is_known(struct connectdata *conn)
return rc;
if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) {
+ int i;
+ char md5buffer[33];
+ const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
+
rc = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_MD5,
&hash, &hlen);
- if(rc != SSH_OK)
+ if(rc != SSH_OK || hlen != 16) {
+ failf(data,
+ "Denied establishing ssh session: md5 fingerprint not available");
goto cleanup;
+ }
+
+ for(i = 0; i < 16; i++)
+ snprintf(&md5buffer[i*2], 3, "%02x", (unsigned char)hash[i]);
+
+ infof(data, "SSH MD5 fingerprint: %s\n", md5buffer);
- if(hlen != strlen(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) ||
- memcmp(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5], hash, hlen)) {
+ if(!strcasecompare(md5buffer, pubkey_md5)) {
+ failf(data,
+ "Denied establishing ssh session: mismatch md5 fingerprint. "
+ "Remote %s is not equal to %s", md5buffer, pubkey_md5);
rc = SSH_ERROR;
goto cleanup;
}
diff --git a/tests/FILEFORMAT b/tests/FILEFORMAT
index 135ded6c1..6b79093ab 100644
--- a/tests/FILEFORMAT
+++ b/tests/FILEFORMAT
@@ -368,6 +368,7 @@ Available substitute variables include:
%PWD - Current directory
%RTSP6PORT - IPv6 port number of the RTSP server
%RTSPPORT - Port number of the RTSP server
+%SSHSRVMD5 - MD5 of SSH server's public key
%SMTP6PORT - IPv6 port number of the SMTP server
%SMTPPORT - Port number of the SMTP server
%SOCKSPORT - Port number of the SOCKS4/5 server
diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
index e0457486b..923b58a63 100644
--- a/tests/data/Makefile.inc
+++ b/tests/data/Makefile.inc
@@ -84,6 +84,7 @@ test626 test627 test628 test629 test630 test631 test632 test633 test634 \
test635 test636 test637 test638 test639 test640 test641 test642 \
test643 test644 test645 test646 test647 test648 test649 test650 test651 \
test652 test653 test654 test655 test656 \
+test664 test665 \
\
test700 test701 test702 test703 test704 test705 test706 test707 test708 \
test709 test710 test711 test712 test713 test714 test715 \
diff --git a/tests/data/test664 b/tests/data/test664
new file mode 100644
index 000000000..cb73b248b
--- /dev/null
+++ b/tests/data/test664
@@ -0,0 +1,44 @@
+<testcase>
+<info>
+<keywords>
+SFTP
+server key check
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<data>
+test
+</data>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+sftp
+</server>
+ <name>
+SFTP correct host key
+ </name>
+ <command>
+--hostpubmd5 %SSHSRVMD5 --key curl_client_key --pubkey curl_client_key.pub -u %USER: sftp://%HOSTIP:%SSHPORT%POSIX_PWD/log/file664.txt
+</command>
+<file name="log/file664.txt">
+test
+</file>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<errorcode>
+0
+</errorcode>
+<valgrind>
+disable
+</valgrind>
+</verify>
+</testcase>
diff --git a/tests/data/test665 b/tests/data/test665
new file mode 100644
index 000000000..830adb8f6
--- /dev/null
+++ b/tests/data/test665
@@ -0,0 +1,44 @@
+<testcase>
+<info>
+<keywords>
+SCP
+server key check
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<data>
+test
+</data>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+scp
+</server>
+ <name>
+SCP correct host key
+ </name>
+ <command>
+--hostpubmd5 %SSHSRVMD5 --key curl_client_key --pubkey curl_client_key.pub -u %USER: scp://%HOSTIP:%SSHPORT%POSIX_PWD/log/file665.txt
+</command>
+<file name="log/file665.txt">
+test
+</file>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<errorcode>
+0
+</errorcode>
+<valgrind>
+disable
+</valgrind>
+</verify>
+</testcase>
diff --git a/tests/runtests.pl b/tests/runtests.pl
index e12c1429a..4e2a19cf2 100755
--- a/tests/runtests.pl
+++ b/tests/runtests.pl
@@ -150,6 +150,8 @@ my $SMBPORT; # SMB server port
my $SMBSPORT; # SMBS server port
my $NEGTELNETPORT; # TELNET server port with negotiation
+my $SSHSRVMD5; # MD5 of ssh server public key
+
my $srcdir = $ENV{'srcdir'} || '.';
my $CURL="../src/curl".exe_ext(); # what curl executable to run on the tests
my $VCURL=$CURL; # what curl binary to use to verify the servers with
@@ -2181,6 +2183,18 @@ sub runsshserver {
return (0,0);
}
+ my $hstpubmd5f = "curl_host_rsa_key.pub_md5";
+ if(!open(PUBMD5FILE, "<", $hstpubmd5f) ||
+ (read(PUBMD5FILE, $SSHSRVMD5, 32) != 32) ||
+ !close(PUBMD5FILE) ||
+ ($SSHSRVMD5 !~ /^[a-f0-9]{32}$/i))
+ {
+ my $msg = "Fatal: $srvrname pubkey md5 missing : \"$hstpubmd5f\" : $!";
+ logmsg "$msg\n";
+ stopservers($verbose);
+ die $msg;
+ }
+
if($verbose) {
logmsg "RUN: $srvrname server is now running PID $pid2\n";
}
@@ -3205,6 +3219,16 @@ sub subVariables {
$$thing =~ s/%SRCDIR/$srcdir/g;
$$thing =~ s/%USER/$USER/g;
+ if($$thing =~ /%SSHSRVMD5/) {
+ if(!$SSHSRVMD5) {
+ my $msg = "Fatal: Missing SSH server pubkey MD5. Is server running?";
+ logmsg "$msg\n";
+ stopservers($verbose);
+ die $msg;
+ }
+ $$thing =~ s/%SSHSRVMD5/$SSHSRVMD5/g;
+ }
+
# The purpose of FTPTIME2 and FTPTIME3 is to provide times that can be
# used for time-out tests and that whould work on most hosts as these
# adjust for the startup/check time for this particular host. We needed
diff --git a/tests/sshhelp.pm b/tests/sshhelp.pm
index c5618a109..abdf9c458 100644
--- a/tests/sshhelp.pm
+++ b/tests/sshhelp.pm
@@ -50,6 +50,7 @@ use vars qw(
$sftpcmds
$hstprvkeyf
$hstpubkeyf
+ $hstpubmd5f
$cliprvkeyf
$clipubkeyf
@sftppath
@@ -82,6 +83,7 @@ use vars qw(
$sftpcmds
$hstprvkeyf
$hstpubkeyf
+ $hstpubmd5f
$cliprvkeyf
$clipubkeyf
display_sshdconfig
@@ -122,6 +124,7 @@ $sftpcmds = 'curl_sftp_cmds'; # sftp client commands batch file
$knownhosts = 'curl_client_knownhosts'; # ssh knownhosts file
$hstprvkeyf = 'curl_host_rsa_key'; # host private key file
$hstpubkeyf = 'curl_host_rsa_key.pub'; # host public key file
+$hstpubmd5f = 'curl_host_rsa_key.pub_md5'; # md5 hash of host public key
$cliprvkeyf = 'curl_client_key'; # client private key file
$clipubkeyf = 'curl_client_key.pub'; # client public key file
diff --git a/tests/sshserver.pl b/tests/sshserver.pl
index 9b3d122fd..cd92a62c5 100755
--- a/tests/sshserver.pl
+++ b/tests/sshserver.pl
@@ -28,6 +28,9 @@ use strict;
use warnings;
use Cwd;
use Cwd 'abs_path';
+use Digest::MD5;
+use Digest::MD5 'md5_hex';
+use MIME::Base64;
#***************************************************************************
# Variables and subs imported from sshhelp module
@@ -48,6 +51,7 @@ use sshhelp qw(
$sftpcmds
$hstprvkeyf
$hstpubkeyf
+ $hstpubmd5f
$cliprvkeyf
$clipubkeyf
display_sshdconfig
@@ -367,10 +371,11 @@ if((($sshid =~ /OpenSSH/) && ($sshvernum < 299)) ||
#
if((! -e $hstprvkeyf) || (! -s $hstprvkeyf) ||
(! -e $hstpubkeyf) || (! -s $hstpubkeyf) ||
+ (! -e $hstpubmd5f) || (! -s $hstpubmd5f) ||
(! -e $cliprvkeyf) || (! -s $cliprvkeyf) ||
(! -e $clipubkeyf) || (! -s $clipubkeyf)) {
# Make sure all files are gone so ssh-keygen doesn't complain
- unlink($hstprvkeyf, $hstpubkeyf, $cliprvkeyf, $clipubkeyf);
+ unlink($hstprvkeyf, $hstpubkeyf, $hstpubmd5f, $cliprvkeyf, $clipubkeyf);
logmsg 'generating host keys...' if($verbose);
if(system "\"$sshkeygen\" -q -t rsa -f $hstprvkeyf -C 'curl test server' -N ''") {
logmsg 'Could not generate host key';
@@ -381,6 +386,24 @@ if((! -e $hstprvkeyf) || (! -s $hstprvkeyf) ||
logmsg 'Could not generate client key';
exit 1;
}
+ # Make sure that permissions are restricted so openssh doesn't complain
+ system "chmod 600 $hstprvkeyf";
+ system "chmod 600 $cliprvkeyf";
+ # Save md5 hash of public host key
+ open(RSAKEYFILE, "<$hstpubkeyf");
+ my @rsahostkey = do { local $/ = ' '; <RSAKEYFILE> };
+ close(RSAKEYFILE);
+ if(!$rsahostkey[1]) {
+ logmsg 'Failed parsing base64 encoded RSA host key';
+ exit 1;
+ }
+ open(PUBMD5FILE, ">$hstpubmd5f");
+ print PUBMD5FILE md5_hex(decode_base64($rsahostkey[1]));
+ close(PUBMD5FILE);
+ if((! -e $hstpubmd5f) || (! -s $hstpubmd5f)) {
+ logmsg 'Failed writing md5 hash of RSA host key';
+ exit 1;
+ }
}
@@ -1073,8 +1096,8 @@ elsif($verbose && ($rc >> 8)) {
#***************************************************************************
# Clean up once the server has stopped
#
-unlink($hstprvkeyf, $hstpubkeyf, $cliprvkeyf, $clipubkeyf, $knownhosts);
-unlink($sshdconfig, $sshconfig, $sftpconfig);
-
+unlink($hstprvkeyf, $hstpubkeyf, $hstpubmd5f,
+ $cliprvkeyf, $clipubkeyf, $knownhosts,
+ $sshdconfig, $sshconfig, $sftpconfig);
exit 0;
--
2.47.1

View File

@ -1,7 +1,7 @@
Summary: A utility for getting files from remote servers (FTP, HTTP, and others)
Name: curl
Version: 7.61.1
Release: 34%{?dist}.5
Release: 34%{?dist}.6
License: MIT
Source: https://curl.haxx.se/download/%{name}-%{version}.tar.xz
@ -187,6 +187,9 @@ Patch63: 0063-curl-7.61.1-native-md5.patch
# asyn-thread: issue CURL_POLL_REMOVE before closing socket
Patch64: 0064-curl-7.61.1-EBADF.patch
# libssh: Fix matching user-specified MD5 hex key
Patch65: 0065-md5-hex-key.patch
# patch making libcurl multilib ready
Patch101: 0101-curl-7.32.0-multilib.patch
@ -424,6 +427,7 @@ git apply %{PATCH52}
%patch -P 62 -p1
%patch -P 63 -p1
%patch -P 64 -p1
%patch -P 65 -p1
# make tests/*.py use Python 3
sed -e '1 s|^#!/.*python|#!%{__python3}|' -i tests/*.py
@ -586,6 +590,9 @@ rm -f ${RPM_BUILD_ROOT}%{_libdir}/libcurl.la
%{_libdir}/libcurl.so.4.[0-9].[0-9].minimal
%changelog
* Thu May 29 2025 Carlos Santos <casantos@redhat.com> - 7.61.1-34.el8_10.6
- libssh: Fix matching user-specified MD5 hex key (RHEL-94574)
* Wed Jan 08 2025 Jacek Migacz <jmigacz@redhat.com> - 7.61.1-34.el8_10.5
- asyn-thread: fix EBADF regression (RHEL-85602)