summaryrefslogtreecommitdiffstats
path: root/Utilities/cmcurl/lib/vssh/libssh2.c
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmcurl/lib/vssh/libssh2.c')
-rw-r--r--Utilities/cmcurl/lib/vssh/libssh2.c161
1 files changed, 133 insertions, 28 deletions
diff --git a/Utilities/cmcurl/lib/vssh/libssh2.c b/Utilities/cmcurl/lib/vssh/libssh2.c
index a772f1f..d269263 100644
--- a/Utilities/cmcurl/lib/vssh/libssh2.c
+++ b/Utilities/cmcurl/lib/vssh/libssh2.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -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"
@@ -428,7 +433,9 @@ static int sshkeycallback(struct Curl_easy *easy,
* libssh2 1.2.8 fixed the problem with 32bit ints used for sockets on win64.
*/
#ifdef HAVE_LIBSSH2_SESSION_HANDSHAKE
-#define libssh2_session_startup(x,y) libssh2_session_handshake(x,y)
+#define session_startup(x,y) libssh2_session_handshake(x, y)
+#else
+#define session_startup(x,y) libssh2_session_startup(x, (int)y)
#endif
static CURLcode ssh_knownhost(struct Curl_easy *data)
@@ -490,7 +497,7 @@ static CURLcode ssh_knownhost(struct Curl_easy *data)
break;
#endif
default:
- infof(data, "unsupported key type, can't check knownhosts!");
+ infof(data, "unsupported key type, can't check knownhosts");
keybit = 0;
break;
}
@@ -585,7 +592,7 @@ static CURLcode ssh_knownhost(struct Curl_easy *data)
LIBSSH2_KNOWNHOST_KEYENC_RAW|
keybit, NULL);
if(addrc)
- infof(data, "Warning adding the known host %s failed!",
+ infof(data, "WARNING: adding the known host %s failed",
conn->host.name);
else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE ||
rc == CURLKHSTAT_FINE_REPLACE) {
@@ -596,7 +603,7 @@ static CURLcode ssh_knownhost(struct Curl_easy *data)
data->set.str[STRING_SSH_KNOWNHOSTS],
LIBSSH2_KNOWNHOST_FILE_OPENSSH);
if(wrc) {
- infof(data, "Warning, writing %s failed!",
+ infof(data, "WARNING: writing %s failed",
data->set.str[STRING_SSH_KNOWNHOSTS]);
}
}
@@ -615,40 +622,138 @@ 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];
+
+ hostkey = libssh2_session_hostkey(sshc->ssh_session, &len, NULL);
+ if(hostkey) {
+ if(!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;
+ }
+
+ /* The length of fingerprint is 32 bytes for SHA256.
+ * See libssh2_hostkey_hash documentation. */
+ if(Curl_base64_encode(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) ||
+ strncmp(fingerprint_b64, pubkey_sha256, pub_pos)) {
+ free(fingerprint_b64);
+
+ failf(data,
+ "Denied establishing ssh session: mismatch sha256 fingerprint. "
+ "Remote %s is not equal to %s", fingerprint_b64, pubkey_sha256);
+ state(data, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+ return sshc->actualcode;
+ }
+
+ free(fingerprint_b64);
+
+ infof(data, "SHA256 checksum match");
}
- /* Before we authenticate we check the hostkey's MD5 fingerprint
- * against a known fingerprint, if available.
- */
- if(pubkey_md5 && strlen(pubkey_md5) == 32) {
+ 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);
+ }
+
+ /* This does NOT verify the length of 'pubkey_md5' separately, which will
+ make the comparison below fail unless it is exactly 32 characters */
if(!fingerprint || !strcasecompare(md5buffer, pubkey_md5)) {
- if(fingerprint)
+ if(fingerprint) {
failf(data,
- "Denied establishing ssh session: mismatch md5 fingerprint. "
- "Remote %s is not equal to %s", md5buffer, pubkey_md5);
- else
+ "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");
+ "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!");
+ 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);
}
/*
@@ -826,7 +931,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
/* FALLTHROUGH */
case SSH_S_STARTUP:
- rc = libssh2_session_startup(sshc->ssh_session, (int)sock);
+ rc = session_startup(sshc->ssh_session, sock);
if(rc == LIBSSH2_ERROR_EAGAIN) {
break;
}
@@ -1362,7 +1467,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
*/
cp = strchr(cmd, ' ');
if(!cp) {
- failf(data, "Syntax error command '%s'. Missing parameter!",
+ failf(data, "Syntax error command '%s', missing parameter",
cmd);
state(data, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
@@ -3121,7 +3226,7 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
sshrecv.recvptr = ssh_tls_recv;
sshsend.sendptr = ssh_tls_send;
- infof(data, "Uses HTTPS proxy!");
+ infof(data, "Uses HTTPS proxy");
/*
Setup libssh2 callbacks to make it read/write TLS from the socket.
@@ -3610,7 +3715,7 @@ void Curl_ssh_cleanup(void)
void Curl_ssh_version(char *buffer, size_t buflen)
{
- (void)msnprintf(buffer, buflen, "libssh2/%s", LIBSSH2_VERSION);
+ (void)msnprintf(buffer, buflen, "libssh2/%s", CURL_LIBSSH2_VERSION);
}
/* The SSH session is associated with the *CONNECTION* but the callback user