libssh2: add SHA256 fingerprint support

Added support for SHA256 fingerprint in command line curl and in
libcurl.

Closes #7646
This commit is contained in:
Mats Lindestam 2021-09-26 23:20:53 +02:00 committed by Daniel Stenberg
parent 1ca62bb5ce
commit d1e7d9197b
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
27 changed files with 360 additions and 38 deletions

View File

@ -138,7 +138,6 @@
17. SSH protocols
17.1 Multiplexing
17.2 Handle growing SFTP files
17.3 Support better than MD5 hostkey hash
17.4 Support CURLOPT_PREQUOTE
17.5 SSH over HTTPS proxy with more backends
@ -930,15 +929,6 @@
https://github.com/curl/curl/issues/4344
17.3 Support better than MD5 hostkey hash
libcurl offers the CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 option for verifying the
server's key. MD5 is generally being deprecated so we should implement
support for stronger hashing algorithms. libssh2 itself is what provides this
underlying functionality and it supports at least SHA-1 as an alternative.
SHA-1 is also being deprecated these days so we should consider working with
libssh2 to instead offer support for SHA-256 or similar.
17.4 Support CURLOPT_PREQUOTE
The two other QUOTE options are supported for SFTP, but this was left out for

View File

@ -96,6 +96,7 @@ DPAGES = \
header.d \
help.d \
hostpubmd5.d \
hostpubsha256.d \
hsts.d \
http0.9.d \
http1.0.d \

View File

@ -0,0 +1,11 @@
Long: hostpubsha256
Arg: <sha256>
Help: Acceptable SHA256 hash of the host public key
Protocols: SFTP SCP
Added: 7.80.0
Category: sftp scp
Example: --hostpubsha256 NDVkMTQxMGQ1ODdmMjQ3MjczYjAyOTY5MmRkMjVmNDQ= sftp://example.com/
---
Pass a string containing a Base64-encoded SHA256 hash of the remote
host's public key. Curl will refuse the connection with the host
unless the hashes match.

View File

@ -642,6 +642,8 @@ SSH authentication types. See \fICURLOPT_SSH_AUTH_TYPES(3)\fP
Enable SSH compression. See \fICURLOPT_SSH_COMPRESSION(3)\fP
.IP CURLOPT_SSH_HOST_PUBLIC_KEY_MD5
MD5 of host's public key. See \fICURLOPT_SSH_HOST_PUBLIC_KEY_MD5(3)\fP
.IP CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256
SHA256 of host's public key. See \fICURLOPT_SSH_HOST_PUBLIC_KEY_SHA256(3)\fP
.IP CURLOPT_SSH_PUBLIC_KEYFILE
File name of public key. See \fICURLOPT_SSH_PUBLIC_KEYFILE(3)\fP
.IP CURLOPT_SSH_PRIVATE_KEYFILE

View File

@ -0,0 +1,60 @@
.\" **************************************************************************
.\" * _ _ ____ _
.\" * Project ___| | | | _ \| |
.\" * / __| | | | |_) | |
.\" * | (__| |_| | _ <| |___
.\" * \___|\___/|_| \_\_____|
.\" *
.\" * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
.\" *
.\" * This software is licensed as described in the file COPYING, which
.\" * you should have received as part of this distribution. The terms
.\" * are also available at https://curl.se/docs/copyright.html.
.\" *
.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell
.\" * copies of the Software, and permit persons to whom the Software is
.\" * furnished to do so, under the terms of the COPYING file.
.\" *
.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
.\" * KIND, either express or implied.
.\" *
.\" **************************************************************************
.\"
.TH CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 3 "27 Aug 2021" "libcurl 7.80.0" "curl_easy_setopt options"
.SH NAME
CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 \- SHA256 hash of SSH server public key
.SH SYNOPSIS
.nf
#include <curl/curl.h>
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256,
char *sha256);
.SH DESCRIPTION
Pass a char * pointing to a string containing a Base64-encoded SHA256
hash of the remote host's public key.
The transfer will fail if the given hash doesn't match the hash the
remote host provides.
.SH DEFAULT
NULL
.SH PROTOCOLS
SCP and SFTP
.SH EXAMPLE
.nf
CURL *curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "sftp://example.com/file");
curl_easy_setopt(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256,
"NDVkMTQxMGQ1ODdmMjQ3MjczYjAyOTY5MmRkMjVmNDQ=");
ret = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
.fi
.SH AVAILABILITY
Added in 7.80.0
Requires the libssh2 back-end.
.SH RETURN VALUE
Returns CURLE_OK if the option is supported, CURLE_UNKNOWN_OPTION if not, or
CURLE_OUT_OF_MEMORY if there was insufficient heap space.
.SH "SEE ALSO"
.BR CURLOPT_SSH_PUBLIC_KEYFILE "(3), " CURLOPT_SSH_AUTH_TYPES "(3), "

View File

@ -326,6 +326,7 @@ man_MANS = \
CURLOPT_SSH_AUTH_TYPES.3 \
CURLOPT_SSH_COMPRESSION.3 \
CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.3 \
CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256.3 \
CURLOPT_SSH_KEYDATA.3 \
CURLOPT_SSH_KEYFUNCTION.3 \
CURLOPT_SSH_KNOWNHOSTS.3 \

View File

@ -613,6 +613,7 @@ CURLOPT_SOURCE_USERPWD 7.12.1 - 7.15.5
CURLOPT_SSH_AUTH_TYPES 7.16.1
CURLOPT_SSH_COMPRESSION 7.56.0
CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 7.17.1
CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 7.80.0
CURLOPT_SSH_KEYDATA 7.19.6
CURLOPT_SSH_KEYFUNCTION 7.19.6
CURLOPT_SSH_KNOWNHOSTS 7.19.6

View File

@ -84,6 +84,7 @@
--header (-H) 5.0
--help (-h) 4.0
--hostpubmd5 7.17.1
--hostpubsha256 7.80.0
--hsts 7.74.0
--http0.9 7.64.0
--http1.0 (-0) 7.9.1

View File

@ -2102,6 +2102,9 @@ typedef enum {
this option is used only if PROXY_SSL_VERIFYPEER is true */
CURLOPT(CURLOPT_PROXY_CAINFO_BLOB, CURLOPTTYPE_BLOB, 310),
/* used by scp/sftp to verify the host's public key */
CURLOPT(CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256, CURLOPTTYPE_STRINGPOINT, 311),
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;

View File

@ -317,6 +317,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
(option) == CURLOPT_SERVICE_NAME || \
(option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \
(option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \
(option) == CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 || \
(option) == CURLOPT_SSH_KNOWNHOSTS || \
(option) == CURLOPT_SSH_PRIVATE_KEYFILE || \
(option) == CURLOPT_SSH_PUBLIC_KEYFILE || \

View File

@ -271,6 +271,8 @@ struct curl_easyoption Curl_easyopts[] = {
{"SSH_COMPRESSION", CURLOPT_SSH_COMPRESSION, CURLOT_LONG, 0},
{"SSH_HOST_PUBLIC_KEY_MD5", CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
CURLOT_STRING, 0},
{"SSH_HOST_PUBLIC_KEY_SHA256", CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256,
CURLOT_STRING, 0},
{"SSH_KEYDATA", CURLOPT_SSH_KEYDATA, CURLOT_CBPTR, 0},
{"SSH_KEYFUNCTION", CURLOPT_SSH_KEYFUNCTION, CURLOT_FUNCTION, 0},
{"SSH_KNOWNHOSTS", CURLOPT_SSH_KNOWNHOSTS, CURLOT_STRING, 0},
@ -354,6 +356,6 @@ struct curl_easyoption Curl_easyopts[] = {
*/
int Curl_easyopts_check(void)
{
return ((CURLOPT_LASTENTRY%10000) != (310 + 1));
return ((CURLOPT_LASTENTRY%10000) != (311 + 1));
}
#endif

View File

@ -2477,6 +2477,15 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
va_arg(param, char *));
break;
case CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256:
/*
* Option to allow for the SHA256 of the host public key to be checked
* for validation purposes.
*/
result = Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256],
va_arg(param, char *));
break;
case CURLOPT_SSH_KNOWNHOSTS:
/*
* Store the file name to read known hosts from.

View File

@ -1554,6 +1554,7 @@ enum dupstring {
STRING_SSH_PRIVATE_KEY, /* path to the private key file for auth */
STRING_SSH_PUBLIC_KEY, /* path to the public key file for auth */
STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */
STRING_SSH_HOST_PUBLIC_KEY_SHA256, /* sha256 of host public key in base64 */
STRING_SSH_KNOWNHOSTS, /* file name of knownhosts file */
STRING_PROXY_SERVICE_NAME, /* Proxy service name */
STRING_SERVICE_NAME, /* Service name */

View File

@ -81,6 +81,11 @@
#include "select.h"
#include "warnless.h"
#include "curl_path.h"
#include "strcase.h"
#include <curl_base64.h> /* for base64 encoding/decoding */
#include <curl_sha256.h>
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@ -615,40 +620,142 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
struct connectdata *conn = data->conn;
struct ssh_conn *sshc = &conn->proto.sshc;
const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
char md5buffer[33];
const char *pubkey_sha256 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256];
const char *fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
LIBSSH2_HOSTKEY_HASH_MD5);
infof(data, "SSH MD5 public key: %s",
pubkey_md5 != NULL ? pubkey_md5 : "NULL");
infof(data, "SSH SHA256 public key: %s",
pubkey_sha256 != NULL ? pubkey_sha256 : "NULL");
if(fingerprint) {
if(pubkey_sha256) {
const char *fingerprint = NULL;
char *fingerprint_b64 = NULL;
size_t fingerprint_b64_len;
size_t pub_pos = 0;
size_t b64_pos = 0;
#ifdef LIBSSH2_HOSTKEY_HASH_SHA256
/* The fingerprint points to static storage (!), don't free() it. */
int i;
for(i = 0; i < 16; i++)
msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]);
infof(data, "SSH MD5 fingerprint: %s", md5buffer);
}
fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
LIBSSH2_HOSTKEY_HASH_SHA256);
#else
const char *hostkey;
size_t len = 0;
unsigned char hash[32];
/* Before we authenticate we check the hostkey's MD5 fingerprint
* against a known fingerprint, if available.
*/
if(pubkey_md5 && strlen(pubkey_md5) == 32) {
if(!fingerprint || !strcasecompare(md5buffer, pubkey_md5)) {
if(fingerprint)
failf(data,
"Denied establishing ssh session: mismatch md5 fingerprint. "
"Remote %s is not equal to %s", md5buffer, pubkey_md5);
else
failf(data,
"Denied establishing ssh session: md5 fingerprint not available");
hostkey = libssh2_session_hostkey(sshc->ssh_session, &len, NULL);
if(hostkey) {
Curl_sha256it(hash, (const unsigned char *) hostkey, len);
fingerprint = (char *) hash;
}
#endif
if(!fingerprint) {
failf(data,
"Denied establishing ssh session: sha256 fingerprint "
"not available");
state(data, SSH_SESSION_FREE);
sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
return sshc->actualcode;
}
infof(data, "MD5 checksum match!");
/* The length of fingerprint is 32 bytes for SHA256.
* See libssh2_hostkey_hash documentation. */
if(Curl_base64_encode (data, fingerprint, 32, &fingerprint_b64,
&fingerprint_b64_len) != CURLE_OK) {
state(data, SSH_SESSION_FREE);
sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
return sshc->actualcode;
}
if(!fingerprint_b64) {
failf(data,
"sha256 fingerprint could not be encoded");
state(data, SSH_SESSION_FREE);
sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
return sshc->actualcode;
}
infof(data, "SSH SHA256 fingerprint: %s", fingerprint_b64);
/* Find the position of any = padding characters in the public key */
while((pubkey_sha256[pub_pos] != '=') && pubkey_sha256[pub_pos]) {
pub_pos++;
}
/* Find the position of any = padding characters in the base64 coded
* hostkey fingerprint */
while((fingerprint_b64[b64_pos] != '=') && fingerprint_b64[b64_pos]) {
b64_pos++;
}
/* Before we authenticate we check the hostkey's sha256 fingerprint
* against a known fingerprint, if available.
*/
if((pub_pos != b64_pos) ||
Curl_strncasecompare(fingerprint_b64, pubkey_sha256, pub_pos) != 1) {
free(fingerprint_b64);
failf(data,
"Denied establishing ssh session: mismatch sha256 fingerprint. "
"Remote %s is not equal to %s", fingerprint, pubkey_sha256);
state(data, SSH_SESSION_FREE);
sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
return sshc->actualcode;
}
free(fingerprint_b64);
infof(data, "SHA256 checksum match!");
}
if(pubkey_md5) {
char md5buffer[33];
const char *fingerprint = NULL;
fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
LIBSSH2_HOSTKEY_HASH_MD5);
if(fingerprint) {
/* The fingerprint points to static storage (!), don't free() it. */
int i;
for(i = 0; i < 16; i++) {
msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]);
}
infof(data, "SSH MD5 fingerprint: %s", md5buffer);
}
/* Before we authenticate we check the hostkey's MD5 fingerprint
* against a known fingerprint, if available.
*/
if(pubkey_md5 && strlen(pubkey_md5) == 32) {
if(!fingerprint || !strcasecompare(md5buffer, pubkey_md5)) {
if(fingerprint) {
failf(data,
"Denied establishing ssh session: mismatch md5 fingerprint. "
"Remote %s is not equal to %s", md5buffer, pubkey_md5);
}
else {
failf(data,
"Denied establishing ssh session: md5 fingerprint "
"not available");
}
state(data, SSH_SESSION_FREE);
sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
return sshc->actualcode;
}
infof(data, "MD5 checksum match!");
}
}
if(!pubkey_md5 && !pubkey_sha256) {
return ssh_knownhost(data);
}
else {
/* as we already matched, we skip the check for known hosts */
return CURLE_OK;
}
return ssh_knownhost(data);
}
/*

View File

@ -131,6 +131,7 @@ static void free_config_fields(struct OperationConfig *config)
Curl_safefree(config->proxy_key_passwd);
Curl_safefree(config->pubkey);
Curl_safefree(config->hostpubmd5);
Curl_safefree(config->hostpubsha256);
Curl_safefree(config->engine);
Curl_safefree(config->etag_save_file);
Curl_safefree(config->etag_compare_file);

View File

@ -158,6 +158,7 @@ struct OperationConfig {
char *proxy_key_passwd;
char *pubkey;
char *hostpubmd5;
char *hostpubsha256;
char *engine;
char *etag_save_file;
char *etag_compare_file;

View File

@ -241,6 +241,7 @@ static const struct LongShort aliases[]= {
{"Eg", "capath", ARG_FILENAME},
{"Eh", "pubkey", ARG_STRING},
{"Ei", "hostpubmd5", ARG_STRING},
{"EF", "hostpubsha256", ARG_STRING},
{"Ej", "crlfile", ARG_FILENAME},
{"Ek", "tlsuser", ARG_STRING},
{"El", "tlspassword", ARG_STRING},
@ -1602,6 +1603,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
if(!config->hostpubmd5 || strlen(config->hostpubmd5) != 32)
return PARAM_BAD_USE;
break;
case 'F': /* --hostpubsha256 sha256 of the host public key */
GetStr(&config->hostpubsha256, nextarg);
break;
case 'j': /* CRL file */
GetStr(&config->crlfile, nextarg);
break;

View File

@ -346,6 +346,9 @@ static const struct helptxt helptext[] = {
{" --hostpubmd5 <md5>",
"Acceptable MD5 hash of the host public key",
CURLHELP_SFTP | CURLHELP_SCP},
{" --hostpubsha256 <sha256>",
"Acceptable SHA256 hash of the host public key",
CURLHELP_SFTP | CURLHELP_SCP},
{" --hsts <file name>",
"Enable HSTS with this cache file",
CURLHELP_HTTP},

View File

@ -1408,6 +1408,11 @@ static CURLcode single_transfer(struct GlobalConfig *global,
my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
config->hostpubmd5);
/* new in libcurl 7.80.0: SSH host key sha256 checking allows us
to fail if we are not talking to who we think we should */
my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256,
config->hostpubsha256);
/* new in libcurl 7.56.0 */
if(config->ssh_compression)
my_setopt(curl, CURLOPT_SSH_COMPRESSION, 1L);

1
tests/.gitignore vendored
View File

@ -7,6 +7,7 @@ curl_client_knownhosts
curl_host_rsa_key
curl_host_rsa_key.pub
curl_host_rsa_key.pub_md5
curl_host_rsa_key.pub_sha256
curl_sftp_cmds
curl_sftp_config
curl_ssh_config

View File

@ -148,6 +148,7 @@ Available substitute variables include:
- `%SRCDIR` - Full path to the source dir
- `%SSHPORT` - Port number of the SCP/SFTP server
- `%SSHSRVMD5` - MD5 of SSH server's public key
- `%SSHSRVSHA256` - SHA256 of SSH server's public key
- `%SSH_PWD` - Current directory friendly for the SSH server
- `%TESTNUMBER` - Number of the test case
- `%TFTP6PORT` - IPv6 port number of the TFTP server

View File

@ -237,4 +237,4 @@ test2200 test2201 test2202 test2203 test2204 test2205 \
\
test3000 test3001 test3002 test3003 test3004 test3005 test3006 test3007 \
test3008 test3009 test3010 test3011 test3012 test3013 test3014 test3015 \
test3016 test3017 test3018 test3019 test3020
test3016 test3017 test3018 test3019 test3020 test3021 test3022

44
tests/data/test3021 Normal file
View File

@ -0,0 +1,44 @@
<testcase>
<info>
<keywords>
SFTP
server sha256 key check
</keywords>
</info>
#
# Server-side
<reply>
<data>
test
</data>
</reply>
#
# Client-side
<client>
<server>
sftp
</server>
<name>
SFTP correct sha256 host key
</name>
<command>
--hostpubsha256 %SSHSRVSHA256 --key curl_client_key --pubkey curl_client_key.pub -u %USER: sftp://%HOSTIP:%SSHPORT%SSH_PWD/log/file%TESTNUMBER.txt
</command>
<file name="log/file%TESTNUMBER.txt">
test
</file>
</client>
#
# Verify data after the test has been "shot"
<verify>
<errorcode>
0
</errorcode>
<valgrind>
disable
</valgrind>
</verify>
</testcase>

44
tests/data/test3022 Normal file
View File

@ -0,0 +1,44 @@
<testcase>
<info>
<keywords>
SCP
server sha256 key check
</keywords>
</info>
#
# Server-side
<reply>
<data>
test
</data>
</reply>
#
# Client-side
<client>
<server>
scp
</server>
<name>
SCP correct sha256 host key
</name>
<command>
--hostpubsha256 %SSHSRVSHA256 --key curl_client_key --pubkey curl_client_key.pub -u %USER: scp://%HOSTIP:%SSHPORT%SSH_PWD/log/file%TESTNUMBER.txt
</command>
<file name="log/file%TESTNUMBER.txt">
test
</file>
</client>
#
# Verify data after the test has been "shot"
<verify>
<errorcode>
0
</errorcode>
<valgrind>
disable
</valgrind>
</verify>
</testcase>

View File

@ -168,6 +168,7 @@ my $proxy_address;
my %custom_skip_reasons;
my $SSHSRVMD5 = "[uninitialized]"; # MD5 of ssh server public key
my $SSHSRVSHA256 = "[uninitialized]"; # SHA256 of ssh server public key
my $VERSION=""; # curl's reported version number
my $srcdir = $ENV{'srcdir'} || '.';
@ -2287,6 +2288,17 @@ sub runsshserver {
die $msg;
}
my $hstpubsha256f = "curl_host_rsa_key.pub_sha256";
if(!open(PUBSHA256FILE, "<", $hstpubsha256f) ||
(read(PUBSHA256FILE, $SSHSRVSHA256, 48) == 0) ||
!close(PUBSHA256FILE))
{
my $msg = "Fatal: $srvrname pubkey sha256 missing : \"$hstpubsha256f\" : $!";
logmsg "$msg\n";
stopservers($verbose);
die $msg;
}
logmsg "RUN: $srvrname on PID $pid2 port $wport\n" if($verbose);
return ($pid2, $sshpid, $wport);
@ -3374,6 +3386,7 @@ sub subVariables {
$$thing =~ s/${prefix}USER/$USER/g;
$$thing =~ s/${prefix}SSHSRVMD5/$SSHSRVMD5/g;
$$thing =~ s/${prefix}SSHSRVSHA256/$SSHSRVSHA256/g;
# The purpose of FTPTIME2 and FTPTIME3 is to provide times that can be
# used for time-out tests and that would work on most hosts as these

View File

@ -51,6 +51,7 @@ use vars qw(
$hstprvkeyf
$hstpubkeyf
$hstpubmd5f
$hstpubsha256f
$cliprvkeyf
$clipubkeyf
@sftppath
@ -84,6 +85,7 @@ use vars qw(
$hstprvkeyf
$hstpubkeyf
$hstpubmd5f
$hstpubsha256f
$cliprvkeyf
$clipubkeyf
display_sshdconfig
@ -125,6 +127,7 @@ $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
$hstpubsha256f = 'curl_host_rsa_key.pub_sha256'; # sha256 hash of host public key
$cliprvkeyf = 'curl_client_key'; # client private key file
$clipubkeyf = 'curl_client_key.pub'; # client public key file

View File

@ -30,6 +30,8 @@ use Cwd;
use Cwd 'abs_path';
use Digest::MD5;
use Digest::MD5 'md5_hex';
use Digest::SHA;
use Digest::SHA 'sha256_base64';
use MIME::Base64;
#***************************************************************************
@ -52,6 +54,7 @@ use sshhelp qw(
$hstprvkeyf
$hstpubkeyf
$hstpubmd5f
$hstpubsha256f
$cliprvkeyf
$clipubkeyf
display_sshdconfig
@ -362,10 +365,12 @@ if((($sshid =~ /OpenSSH/) && ($sshvernum < 299)) ||
if((! -e $hstprvkeyf) || (! -s $hstprvkeyf) ||
(! -e $hstpubkeyf) || (! -s $hstpubkeyf) ||
(! -e $hstpubmd5f) || (! -s $hstpubmd5f) ||
(! -e $hstpubsha256f) || (! -s $hstpubsha256f) ||
(! -e $cliprvkeyf) || (! -s $cliprvkeyf) ||
(! -e $clipubkeyf) || (! -s $clipubkeyf)) {
# Make sure all files are gone so ssh-keygen doesn't complain
unlink($hstprvkeyf, $hstpubkeyf, $hstpubmd5f, $cliprvkeyf, $clipubkeyf);
unlink($hstprvkeyf, $hstpubkeyf, $hstpubmd5f, $hstpubsha256f,
$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';
@ -379,7 +384,7 @@ if((! -e $hstprvkeyf) || (! -s $hstprvkeyf) ||
# 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
# Save md5 and sha256 hashes of public host key
open(RSAKEYFILE, "<$hstpubkeyf");
my @rsahostkey = do { local $/ = ' '; <RSAKEYFILE> };
close(RSAKEYFILE);
@ -394,6 +399,13 @@ if((! -e $hstprvkeyf) || (! -s $hstprvkeyf) ||
logmsg 'Failed writing md5 hash of RSA host key';
exit 1;
}
open(PUBSHA256FILE, ">$hstpubsha256f");
print PUBSHA256FILE sha256_base64(decode_base64($rsahostkey[1]));
close(PUBSHA256FILE);
if((! -e $hstpubsha256f) || (! -s $hstpubsha256f)) {
logmsg 'Failed writing sha256 hash of RSA host key';
exit 1;
}
}
@ -1141,7 +1153,7 @@ elsif($verbose && ($rc >> 8)) {
#***************************************************************************
# Clean up once the server has stopped
#
unlink($hstprvkeyf, $hstpubkeyf, $hstpubmd5f,
unlink($hstprvkeyf, $hstpubkeyf, $hstpubmd5f, $hstpubsha256f,
$cliprvkeyf, $clipubkeyf, $knownhosts,
$sshdconfig, $sshconfig, $sftpconfig);