1
0
mirror of https://github.com/moparisthebest/curl synced 2024-08-13 17:03:50 -04:00

libssh: improve known hosts handling

Previously, it was not possible to get a known hosts file entry due to
the lack of an API.  ssh_session_get_known_hosts_entry(), introduced in
libssh-0.9.0, allows libcurl to obtain such information and behave the
same as when compiled with libssh2.

This also tries to avoid the usage of deprecated functions when the
replacements are available.  The behaviour will not change if versions
older than libssh-0.8.0 are used.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>

Fixes #4953
Closes #4962
This commit is contained in:
Anderson Toshiyuki Sasaki 2020-02-21 11:09:26 +01:00 committed by Daniel Stenberg
parent 0922f76240
commit 507cf6a13d
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2

View File

@ -322,14 +322,25 @@ static int myssh_is_known(struct connectdata *conn)
ssh_key pubkey;
size_t hlen;
unsigned char *hash = NULL;
char *base64 = NULL;
char *found_base64 = NULL;
char *known_base64 = NULL;
int vstate;
enum curl_khmatch keymatch;
struct curl_khkey foundkey;
struct curl_khkey *knownkeyp = NULL;
curl_sshkeycallback func =
data->set.ssh_keyfunc;
#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
struct ssh_knownhosts_entry *knownhostsentry = NULL;
struct curl_khkey knownkey;
#endif
#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0)
rc = ssh_get_server_publickey(sshc->ssh_session, &pubkey);
#else
rc = ssh_get_publickey(sshc->ssh_session, &pubkey);
#endif
if(rc != SSH_OK)
return rc;
@ -354,6 +365,65 @@ static int myssh_is_known(struct connectdata *conn)
goto cleanup;
}
#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
/* Get the known_key from the known hosts file */
vstate = ssh_session_get_known_hosts_entry(sshc->ssh_session,
&knownhostsentry);
/* Case an entry was found in a known hosts file */
if(knownhostsentry) {
if(knownhostsentry->publickey) {
rc = ssh_pki_export_pubkey_base64(knownhostsentry->publickey,
&known_base64);
if(rc != SSH_OK) {
goto cleanup;
}
knownkey.key = known_base64;
knownkey.len = strlen(known_base64);
switch(ssh_key_type(knownhostsentry->publickey)) {
case SSH_KEYTYPE_RSA:
knownkey.keytype = CURLKHTYPE_RSA;
break;
case SSH_KEYTYPE_RSA1:
knownkey.keytype = CURLKHTYPE_RSA1;
break;
case SSH_KEYTYPE_ECDSA:
knownkey.keytype = CURLKHTYPE_ECDSA;
break;
case SSH_KEYTYPE_ED25519:
knownkey.keytype = CURLKHTYPE_ED25519;
break;
case SSH_KEYTYPE_DSS:
knownkey.keytype = CURLKHTYPE_DSS;
break;
default:
rc = SSH_ERROR;
goto cleanup;
}
knownkeyp = &knownkey;
}
}
switch(vstate) {
case SSH_KNOWN_HOSTS_OK:
keymatch = CURLKHMATCH_OK;
break;
case SSH_KNOWN_HOSTS_OTHER:
/* fallthrough */
case SSH_KNOWN_HOSTS_NOT_FOUND:
/* fallthrough */
case SSH_KNOWN_HOSTS_UNKNOWN:
/* fallthrough */
case SSH_KNOWN_HOSTS_ERROR:
keymatch = CURLKHMATCH_MISSING;
break;
default:
keymatch = CURLKHMATCH_MISMATCH;
break;
}
#else
vstate = ssh_is_server_known(sshc->ssh_session);
switch(vstate) {
case SSH_SERVER_KNOWN_OK:
@ -368,14 +438,15 @@ static int myssh_is_known(struct connectdata *conn)
keymatch = CURLKHMATCH_MISMATCH;
break;
}
#endif
if(func) { /* use callback to determine action */
rc = ssh_pki_export_pubkey_base64(pubkey, &base64);
rc = ssh_pki_export_pubkey_base64(pubkey, &found_base64);
if(rc != SSH_OK)
goto cleanup;
foundkey.key = base64;
foundkey.len = strlen(base64);
foundkey.key = found_base64;
foundkey.len = strlen(found_base64);
switch(ssh_key_type(pubkey)) {
case SSH_KEYTYPE_RSA:
@ -400,15 +471,19 @@ static int myssh_is_known(struct connectdata *conn)
goto cleanup;
}
/* we don't have anything equivalent to knownkey. Always NULL */
Curl_set_in_callback(data, true);
rc = func(data, NULL, &foundkey, /* from the remote host */
rc = func(data, knownkeyp, /* from the knownhosts file */
&foundkey, /* from the remote host */
keymatch, data->set.ssh_keyfunc_userp);
Curl_set_in_callback(data, false);
switch(rc) {
case CURLKHSTAT_FINE_ADD_TO_FILE:
#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0)
rc = ssh_session_update_known_hosts(sshc->ssh_session);
#else
rc = ssh_write_knownhost(sshc->ssh_session);
#endif
if(rc != SSH_OK) {
goto cleanup;
}
@ -429,9 +504,20 @@ static int myssh_is_known(struct connectdata *conn)
rc = SSH_OK;
cleanup:
if(found_base64) {
free(found_base64);
}
if(known_base64) {
free(known_base64);
}
if(hash)
ssh_clean_pubkey_hash(&hash);
ssh_key_free(pubkey);
#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
if(knownhostsentry) {
ssh_knownhosts_entry_free(knownhostsentry);
}
#endif
return rc;
}