libssh2: add SHA256 fingerprint support
Added support for SHA256 fingerprint in command line curl and in libcurl. Closes #7646
This commit is contained in:
parent
1ca62bb5ce
commit
d1e7d9197b
10
docs/TODO
10
docs/TODO
@ -138,7 +138,6 @@
|
|||||||
17. SSH protocols
|
17. SSH protocols
|
||||||
17.1 Multiplexing
|
17.1 Multiplexing
|
||||||
17.2 Handle growing SFTP files
|
17.2 Handle growing SFTP files
|
||||||
17.3 Support better than MD5 hostkey hash
|
|
||||||
17.4 Support CURLOPT_PREQUOTE
|
17.4 Support CURLOPT_PREQUOTE
|
||||||
17.5 SSH over HTTPS proxy with more backends
|
17.5 SSH over HTTPS proxy with more backends
|
||||||
|
|
||||||
@ -930,15 +929,6 @@
|
|||||||
|
|
||||||
https://github.com/curl/curl/issues/4344
|
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
|
17.4 Support CURLOPT_PREQUOTE
|
||||||
|
|
||||||
The two other QUOTE options are supported for SFTP, but this was left out for
|
The two other QUOTE options are supported for SFTP, but this was left out for
|
||||||
|
|||||||
@ -96,6 +96,7 @@ DPAGES = \
|
|||||||
header.d \
|
header.d \
|
||||||
help.d \
|
help.d \
|
||||||
hostpubmd5.d \
|
hostpubmd5.d \
|
||||||
|
hostpubsha256.d \
|
||||||
hsts.d \
|
hsts.d \
|
||||||
http0.9.d \
|
http0.9.d \
|
||||||
http1.0.d \
|
http1.0.d \
|
||||||
|
|||||||
11
docs/cmdline-opts/hostpubsha256.d
Normal file
11
docs/cmdline-opts/hostpubsha256.d
Normal 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.
|
||||||
@ -642,6 +642,8 @@ SSH authentication types. See \fICURLOPT_SSH_AUTH_TYPES(3)\fP
|
|||||||
Enable SSH compression. See \fICURLOPT_SSH_COMPRESSION(3)\fP
|
Enable SSH compression. See \fICURLOPT_SSH_COMPRESSION(3)\fP
|
||||||
.IP CURLOPT_SSH_HOST_PUBLIC_KEY_MD5
|
.IP CURLOPT_SSH_HOST_PUBLIC_KEY_MD5
|
||||||
MD5 of host's public key. See \fICURLOPT_SSH_HOST_PUBLIC_KEY_MD5(3)\fP
|
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
|
.IP CURLOPT_SSH_PUBLIC_KEYFILE
|
||||||
File name of public key. See \fICURLOPT_SSH_PUBLIC_KEYFILE(3)\fP
|
File name of public key. See \fICURLOPT_SSH_PUBLIC_KEYFILE(3)\fP
|
||||||
.IP CURLOPT_SSH_PRIVATE_KEYFILE
|
.IP CURLOPT_SSH_PRIVATE_KEYFILE
|
||||||
|
|||||||
60
docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256.3
Normal file
60
docs/libcurl/opts/CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256.3
Normal 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), "
|
||||||
@ -326,6 +326,7 @@ man_MANS = \
|
|||||||
CURLOPT_SSH_AUTH_TYPES.3 \
|
CURLOPT_SSH_AUTH_TYPES.3 \
|
||||||
CURLOPT_SSH_COMPRESSION.3 \
|
CURLOPT_SSH_COMPRESSION.3 \
|
||||||
CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.3 \
|
CURLOPT_SSH_HOST_PUBLIC_KEY_MD5.3 \
|
||||||
|
CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256.3 \
|
||||||
CURLOPT_SSH_KEYDATA.3 \
|
CURLOPT_SSH_KEYDATA.3 \
|
||||||
CURLOPT_SSH_KEYFUNCTION.3 \
|
CURLOPT_SSH_KEYFUNCTION.3 \
|
||||||
CURLOPT_SSH_KNOWNHOSTS.3 \
|
CURLOPT_SSH_KNOWNHOSTS.3 \
|
||||||
|
|||||||
@ -613,6 +613,7 @@ CURLOPT_SOURCE_USERPWD 7.12.1 - 7.15.5
|
|||||||
CURLOPT_SSH_AUTH_TYPES 7.16.1
|
CURLOPT_SSH_AUTH_TYPES 7.16.1
|
||||||
CURLOPT_SSH_COMPRESSION 7.56.0
|
CURLOPT_SSH_COMPRESSION 7.56.0
|
||||||
CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 7.17.1
|
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_KEYDATA 7.19.6
|
||||||
CURLOPT_SSH_KEYFUNCTION 7.19.6
|
CURLOPT_SSH_KEYFUNCTION 7.19.6
|
||||||
CURLOPT_SSH_KNOWNHOSTS 7.19.6
|
CURLOPT_SSH_KNOWNHOSTS 7.19.6
|
||||||
|
|||||||
@ -84,6 +84,7 @@
|
|||||||
--header (-H) 5.0
|
--header (-H) 5.0
|
||||||
--help (-h) 4.0
|
--help (-h) 4.0
|
||||||
--hostpubmd5 7.17.1
|
--hostpubmd5 7.17.1
|
||||||
|
--hostpubsha256 7.80.0
|
||||||
--hsts 7.74.0
|
--hsts 7.74.0
|
||||||
--http0.9 7.64.0
|
--http0.9 7.64.0
|
||||||
--http1.0 (-0) 7.9.1
|
--http1.0 (-0) 7.9.1
|
||||||
|
|||||||
@ -2102,6 +2102,9 @@ typedef enum {
|
|||||||
this option is used only if PROXY_SSL_VERIFYPEER is true */
|
this option is used only if PROXY_SSL_VERIFYPEER is true */
|
||||||
CURLOPT(CURLOPT_PROXY_CAINFO_BLOB, CURLOPTTYPE_BLOB, 310),
|
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 */
|
CURLOPT_LASTENTRY /* the last unused */
|
||||||
} CURLoption;
|
} CURLoption;
|
||||||
|
|
||||||
|
|||||||
@ -317,6 +317,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
|
|||||||
(option) == CURLOPT_SERVICE_NAME || \
|
(option) == CURLOPT_SERVICE_NAME || \
|
||||||
(option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \
|
(option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \
|
||||||
(option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \
|
(option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \
|
||||||
|
(option) == CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 || \
|
||||||
(option) == CURLOPT_SSH_KNOWNHOSTS || \
|
(option) == CURLOPT_SSH_KNOWNHOSTS || \
|
||||||
(option) == CURLOPT_SSH_PRIVATE_KEYFILE || \
|
(option) == CURLOPT_SSH_PRIVATE_KEYFILE || \
|
||||||
(option) == CURLOPT_SSH_PUBLIC_KEYFILE || \
|
(option) == CURLOPT_SSH_PUBLIC_KEYFILE || \
|
||||||
|
|||||||
@ -271,6 +271,8 @@ struct curl_easyoption Curl_easyopts[] = {
|
|||||||
{"SSH_COMPRESSION", CURLOPT_SSH_COMPRESSION, CURLOT_LONG, 0},
|
{"SSH_COMPRESSION", CURLOPT_SSH_COMPRESSION, CURLOT_LONG, 0},
|
||||||
{"SSH_HOST_PUBLIC_KEY_MD5", CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
|
{"SSH_HOST_PUBLIC_KEY_MD5", CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
|
||||||
CURLOT_STRING, 0},
|
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_KEYDATA", CURLOPT_SSH_KEYDATA, CURLOT_CBPTR, 0},
|
||||||
{"SSH_KEYFUNCTION", CURLOPT_SSH_KEYFUNCTION, CURLOT_FUNCTION, 0},
|
{"SSH_KEYFUNCTION", CURLOPT_SSH_KEYFUNCTION, CURLOT_FUNCTION, 0},
|
||||||
{"SSH_KNOWNHOSTS", CURLOPT_SSH_KNOWNHOSTS, CURLOT_STRING, 0},
|
{"SSH_KNOWNHOSTS", CURLOPT_SSH_KNOWNHOSTS, CURLOT_STRING, 0},
|
||||||
@ -354,6 +356,6 @@ struct curl_easyoption Curl_easyopts[] = {
|
|||||||
*/
|
*/
|
||||||
int Curl_easyopts_check(void)
|
int Curl_easyopts_check(void)
|
||||||
{
|
{
|
||||||
return ((CURLOPT_LASTENTRY%10000) != (310 + 1));
|
return ((CURLOPT_LASTENTRY%10000) != (311 + 1));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -2477,6 +2477,15 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
|
|||||||
va_arg(param, char *));
|
va_arg(param, char *));
|
||||||
break;
|
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:
|
case CURLOPT_SSH_KNOWNHOSTS:
|
||||||
/*
|
/*
|
||||||
* Store the file name to read known hosts from.
|
* Store the file name to read known hosts from.
|
||||||
|
|||||||
@ -1554,6 +1554,7 @@ enum dupstring {
|
|||||||
STRING_SSH_PRIVATE_KEY, /* path to the private key file for auth */
|
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_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_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_SSH_KNOWNHOSTS, /* file name of knownhosts file */
|
||||||
STRING_PROXY_SERVICE_NAME, /* Proxy service name */
|
STRING_PROXY_SERVICE_NAME, /* Proxy service name */
|
||||||
STRING_SERVICE_NAME, /* Service name */
|
STRING_SERVICE_NAME, /* Service name */
|
||||||
|
|||||||
@ -81,6 +81,11 @@
|
|||||||
#include "select.h"
|
#include "select.h"
|
||||||
#include "warnless.h"
|
#include "warnless.h"
|
||||||
#include "curl_path.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 */
|
/* The last 3 #include files should be in this order */
|
||||||
#include "curl_printf.h"
|
#include "curl_printf.h"
|
||||||
@ -615,40 +620,142 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
|
|||||||
struct connectdata *conn = data->conn;
|
struct connectdata *conn = data->conn;
|
||||||
struct ssh_conn *sshc = &conn->proto.sshc;
|
struct ssh_conn *sshc = &conn->proto.sshc;
|
||||||
const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
|
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,
|
infof(data, "SSH MD5 public key: %s",
|
||||||
LIBSSH2_HOSTKEY_HASH_MD5);
|
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. */
|
/* The fingerprint points to static storage (!), don't free() it. */
|
||||||
int i;
|
fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
|
||||||
for(i = 0; i < 16; i++)
|
LIBSSH2_HOSTKEY_HASH_SHA256);
|
||||||
msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]);
|
#else
|
||||||
infof(data, "SSH MD5 fingerprint: %s", md5buffer);
|
const char *hostkey;
|
||||||
}
|
size_t len = 0;
|
||||||
|
unsigned char hash[32];
|
||||||
|
|
||||||
/* Before we authenticate we check the hostkey's MD5 fingerprint
|
hostkey = libssh2_session_hostkey(sshc->ssh_session, &len, NULL);
|
||||||
* against a known fingerprint, if available.
|
if(hostkey) {
|
||||||
*/
|
Curl_sha256it(hash, (const unsigned char *) hostkey, len);
|
||||||
if(pubkey_md5 && strlen(pubkey_md5) == 32) {
|
fingerprint = (char *) hash;
|
||||||
if(!fingerprint || !strcasecompare(md5buffer, pubkey_md5)) {
|
}
|
||||||
if(fingerprint)
|
#endif
|
||||||
failf(data,
|
|
||||||
"Denied establishing ssh session: mismatch md5 fingerprint. "
|
if(!fingerprint) {
|
||||||
"Remote %s is not equal to %s", md5buffer, pubkey_md5);
|
failf(data,
|
||||||
else
|
"Denied establishing ssh session: sha256 fingerprint "
|
||||||
failf(data,
|
"not available");
|
||||||
"Denied establishing ssh session: md5 fingerprint not available");
|
|
||||||
state(data, SSH_SESSION_FREE);
|
state(data, SSH_SESSION_FREE);
|
||||||
sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
|
sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
|
||||||
return sshc->actualcode;
|
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 */
|
/* as we already matched, we skip the check for known hosts */
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
return ssh_knownhost(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -131,6 +131,7 @@ static void free_config_fields(struct OperationConfig *config)
|
|||||||
Curl_safefree(config->proxy_key_passwd);
|
Curl_safefree(config->proxy_key_passwd);
|
||||||
Curl_safefree(config->pubkey);
|
Curl_safefree(config->pubkey);
|
||||||
Curl_safefree(config->hostpubmd5);
|
Curl_safefree(config->hostpubmd5);
|
||||||
|
Curl_safefree(config->hostpubsha256);
|
||||||
Curl_safefree(config->engine);
|
Curl_safefree(config->engine);
|
||||||
Curl_safefree(config->etag_save_file);
|
Curl_safefree(config->etag_save_file);
|
||||||
Curl_safefree(config->etag_compare_file);
|
Curl_safefree(config->etag_compare_file);
|
||||||
|
|||||||
@ -158,6 +158,7 @@ struct OperationConfig {
|
|||||||
char *proxy_key_passwd;
|
char *proxy_key_passwd;
|
||||||
char *pubkey;
|
char *pubkey;
|
||||||
char *hostpubmd5;
|
char *hostpubmd5;
|
||||||
|
char *hostpubsha256;
|
||||||
char *engine;
|
char *engine;
|
||||||
char *etag_save_file;
|
char *etag_save_file;
|
||||||
char *etag_compare_file;
|
char *etag_compare_file;
|
||||||
|
|||||||
@ -241,6 +241,7 @@ static const struct LongShort aliases[]= {
|
|||||||
{"Eg", "capath", ARG_FILENAME},
|
{"Eg", "capath", ARG_FILENAME},
|
||||||
{"Eh", "pubkey", ARG_STRING},
|
{"Eh", "pubkey", ARG_STRING},
|
||||||
{"Ei", "hostpubmd5", ARG_STRING},
|
{"Ei", "hostpubmd5", ARG_STRING},
|
||||||
|
{"EF", "hostpubsha256", ARG_STRING},
|
||||||
{"Ej", "crlfile", ARG_FILENAME},
|
{"Ej", "crlfile", ARG_FILENAME},
|
||||||
{"Ek", "tlsuser", ARG_STRING},
|
{"Ek", "tlsuser", ARG_STRING},
|
||||||
{"El", "tlspassword", 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)
|
if(!config->hostpubmd5 || strlen(config->hostpubmd5) != 32)
|
||||||
return PARAM_BAD_USE;
|
return PARAM_BAD_USE;
|
||||||
break;
|
break;
|
||||||
|
case 'F': /* --hostpubsha256 sha256 of the host public key */
|
||||||
|
GetStr(&config->hostpubsha256, nextarg);
|
||||||
|
break;
|
||||||
case 'j': /* CRL file */
|
case 'j': /* CRL file */
|
||||||
GetStr(&config->crlfile, nextarg);
|
GetStr(&config->crlfile, nextarg);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -346,6 +346,9 @@ static const struct helptxt helptext[] = {
|
|||||||
{" --hostpubmd5 <md5>",
|
{" --hostpubmd5 <md5>",
|
||||||
"Acceptable MD5 hash of the host public key",
|
"Acceptable MD5 hash of the host public key",
|
||||||
CURLHELP_SFTP | CURLHELP_SCP},
|
CURLHELP_SFTP | CURLHELP_SCP},
|
||||||
|
{" --hostpubsha256 <sha256>",
|
||||||
|
"Acceptable SHA256 hash of the host public key",
|
||||||
|
CURLHELP_SFTP | CURLHELP_SCP},
|
||||||
{" --hsts <file name>",
|
{" --hsts <file name>",
|
||||||
"Enable HSTS with this cache file",
|
"Enable HSTS with this cache file",
|
||||||
CURLHELP_HTTP},
|
CURLHELP_HTTP},
|
||||||
|
|||||||
@ -1408,6 +1408,11 @@ static CURLcode single_transfer(struct GlobalConfig *global,
|
|||||||
my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
|
my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
|
||||||
config->hostpubmd5);
|
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 */
|
/* new in libcurl 7.56.0 */
|
||||||
if(config->ssh_compression)
|
if(config->ssh_compression)
|
||||||
my_setopt(curl, CURLOPT_SSH_COMPRESSION, 1L);
|
my_setopt(curl, CURLOPT_SSH_COMPRESSION, 1L);
|
||||||
|
|||||||
1
tests/.gitignore
vendored
1
tests/.gitignore
vendored
@ -7,6 +7,7 @@ curl_client_knownhosts
|
|||||||
curl_host_rsa_key
|
curl_host_rsa_key
|
||||||
curl_host_rsa_key.pub
|
curl_host_rsa_key.pub
|
||||||
curl_host_rsa_key.pub_md5
|
curl_host_rsa_key.pub_md5
|
||||||
|
curl_host_rsa_key.pub_sha256
|
||||||
curl_sftp_cmds
|
curl_sftp_cmds
|
||||||
curl_sftp_config
|
curl_sftp_config
|
||||||
curl_ssh_config
|
curl_ssh_config
|
||||||
|
|||||||
@ -148,6 +148,7 @@ Available substitute variables include:
|
|||||||
- `%SRCDIR` - Full path to the source dir
|
- `%SRCDIR` - Full path to the source dir
|
||||||
- `%SSHPORT` - Port number of the SCP/SFTP server
|
- `%SSHPORT` - Port number of the SCP/SFTP server
|
||||||
- `%SSHSRVMD5` - MD5 of SSH server's public key
|
- `%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
|
- `%SSH_PWD` - Current directory friendly for the SSH server
|
||||||
- `%TESTNUMBER` - Number of the test case
|
- `%TESTNUMBER` - Number of the test case
|
||||||
- `%TFTP6PORT` - IPv6 port number of the TFTP server
|
- `%TFTP6PORT` - IPv6 port number of the TFTP server
|
||||||
|
|||||||
@ -237,4 +237,4 @@ test2200 test2201 test2202 test2203 test2204 test2205 \
|
|||||||
\
|
\
|
||||||
test3000 test3001 test3002 test3003 test3004 test3005 test3006 test3007 \
|
test3000 test3001 test3002 test3003 test3004 test3005 test3006 test3007 \
|
||||||
test3008 test3009 test3010 test3011 test3012 test3013 test3014 test3015 \
|
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
44
tests/data/test3021
Normal 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
44
tests/data/test3022
Normal 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>
|
||||||
@ -168,6 +168,7 @@ my $proxy_address;
|
|||||||
my %custom_skip_reasons;
|
my %custom_skip_reasons;
|
||||||
|
|
||||||
my $SSHSRVMD5 = "[uninitialized]"; # MD5 of ssh server public key
|
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 $VERSION=""; # curl's reported version number
|
||||||
|
|
||||||
my $srcdir = $ENV{'srcdir'} || '.';
|
my $srcdir = $ENV{'srcdir'} || '.';
|
||||||
@ -2287,6 +2288,17 @@ sub runsshserver {
|
|||||||
die $msg;
|
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);
|
logmsg "RUN: $srvrname on PID $pid2 port $wport\n" if($verbose);
|
||||||
|
|
||||||
return ($pid2, $sshpid, $wport);
|
return ($pid2, $sshpid, $wport);
|
||||||
@ -3374,6 +3386,7 @@ sub subVariables {
|
|||||||
$$thing =~ s/${prefix}USER/$USER/g;
|
$$thing =~ s/${prefix}USER/$USER/g;
|
||||||
|
|
||||||
$$thing =~ s/${prefix}SSHSRVMD5/$SSHSRVMD5/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
|
# 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
|
# used for time-out tests and that would work on most hosts as these
|
||||||
|
|||||||
@ -51,6 +51,7 @@ use vars qw(
|
|||||||
$hstprvkeyf
|
$hstprvkeyf
|
||||||
$hstpubkeyf
|
$hstpubkeyf
|
||||||
$hstpubmd5f
|
$hstpubmd5f
|
||||||
|
$hstpubsha256f
|
||||||
$cliprvkeyf
|
$cliprvkeyf
|
||||||
$clipubkeyf
|
$clipubkeyf
|
||||||
@sftppath
|
@sftppath
|
||||||
@ -84,6 +85,7 @@ use vars qw(
|
|||||||
$hstprvkeyf
|
$hstprvkeyf
|
||||||
$hstpubkeyf
|
$hstpubkeyf
|
||||||
$hstpubmd5f
|
$hstpubmd5f
|
||||||
|
$hstpubsha256f
|
||||||
$cliprvkeyf
|
$cliprvkeyf
|
||||||
$clipubkeyf
|
$clipubkeyf
|
||||||
display_sshdconfig
|
display_sshdconfig
|
||||||
@ -125,6 +127,7 @@ $knownhosts = 'curl_client_knownhosts'; # ssh knownhosts file
|
|||||||
$hstprvkeyf = 'curl_host_rsa_key'; # host private key file
|
$hstprvkeyf = 'curl_host_rsa_key'; # host private key file
|
||||||
$hstpubkeyf = 'curl_host_rsa_key.pub'; # host public 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
|
$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
|
$cliprvkeyf = 'curl_client_key'; # client private key file
|
||||||
$clipubkeyf = 'curl_client_key.pub'; # client public key file
|
$clipubkeyf = 'curl_client_key.pub'; # client public key file
|
||||||
|
|
||||||
|
|||||||
@ -30,6 +30,8 @@ use Cwd;
|
|||||||
use Cwd 'abs_path';
|
use Cwd 'abs_path';
|
||||||
use Digest::MD5;
|
use Digest::MD5;
|
||||||
use Digest::MD5 'md5_hex';
|
use Digest::MD5 'md5_hex';
|
||||||
|
use Digest::SHA;
|
||||||
|
use Digest::SHA 'sha256_base64';
|
||||||
use MIME::Base64;
|
use MIME::Base64;
|
||||||
|
|
||||||
#***************************************************************************
|
#***************************************************************************
|
||||||
@ -52,6 +54,7 @@ use sshhelp qw(
|
|||||||
$hstprvkeyf
|
$hstprvkeyf
|
||||||
$hstpubkeyf
|
$hstpubkeyf
|
||||||
$hstpubmd5f
|
$hstpubmd5f
|
||||||
|
$hstpubsha256f
|
||||||
$cliprvkeyf
|
$cliprvkeyf
|
||||||
$clipubkeyf
|
$clipubkeyf
|
||||||
display_sshdconfig
|
display_sshdconfig
|
||||||
@ -362,10 +365,12 @@ if((($sshid =~ /OpenSSH/) && ($sshvernum < 299)) ||
|
|||||||
if((! -e $hstprvkeyf) || (! -s $hstprvkeyf) ||
|
if((! -e $hstprvkeyf) || (! -s $hstprvkeyf) ||
|
||||||
(! -e $hstpubkeyf) || (! -s $hstpubkeyf) ||
|
(! -e $hstpubkeyf) || (! -s $hstpubkeyf) ||
|
||||||
(! -e $hstpubmd5f) || (! -s $hstpubmd5f) ||
|
(! -e $hstpubmd5f) || (! -s $hstpubmd5f) ||
|
||||||
|
(! -e $hstpubsha256f) || (! -s $hstpubsha256f) ||
|
||||||
(! -e $cliprvkeyf) || (! -s $cliprvkeyf) ||
|
(! -e $cliprvkeyf) || (! -s $cliprvkeyf) ||
|
||||||
(! -e $clipubkeyf) || (! -s $clipubkeyf)) {
|
(! -e $clipubkeyf) || (! -s $clipubkeyf)) {
|
||||||
# Make sure all files are gone so ssh-keygen doesn't complain
|
# 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);
|
logmsg 'generating host keys...' if($verbose);
|
||||||
if(system "\"$sshkeygen\" -q -t rsa -f $hstprvkeyf -C 'curl test server' -N ''") {
|
if(system "\"$sshkeygen\" -q -t rsa -f $hstprvkeyf -C 'curl test server' -N ''") {
|
||||||
logmsg 'Could not generate host key';
|
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
|
# Make sure that permissions are restricted so openssh doesn't complain
|
||||||
system "chmod 600 $hstprvkeyf";
|
system "chmod 600 $hstprvkeyf";
|
||||||
system "chmod 600 $cliprvkeyf";
|
system "chmod 600 $cliprvkeyf";
|
||||||
# Save md5 hash of public host key
|
# Save md5 and sha256 hashes of public host key
|
||||||
open(RSAKEYFILE, "<$hstpubkeyf");
|
open(RSAKEYFILE, "<$hstpubkeyf");
|
||||||
my @rsahostkey = do { local $/ = ' '; <RSAKEYFILE> };
|
my @rsahostkey = do { local $/ = ' '; <RSAKEYFILE> };
|
||||||
close(RSAKEYFILE);
|
close(RSAKEYFILE);
|
||||||
@ -394,6 +399,13 @@ if((! -e $hstprvkeyf) || (! -s $hstprvkeyf) ||
|
|||||||
logmsg 'Failed writing md5 hash of RSA host key';
|
logmsg 'Failed writing md5 hash of RSA host key';
|
||||||
exit 1;
|
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
|
# Clean up once the server has stopped
|
||||||
#
|
#
|
||||||
unlink($hstprvkeyf, $hstpubkeyf, $hstpubmd5f,
|
unlink($hstprvkeyf, $hstpubkeyf, $hstpubmd5f, $hstpubsha256f,
|
||||||
$cliprvkeyf, $clipubkeyf, $knownhosts,
|
$cliprvkeyf, $clipubkeyf, $knownhosts,
|
||||||
$sshdconfig, $sshconfig, $sftpconfig);
|
$sshdconfig, $sshconfig, $sftpconfig);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user