mirror of
https://github.com/curl/curl.git
synced 2026-08-24 16:33:33 +03:00
libssh2: add CURLOPT_SSH_HOSTKEYFUNCTION
The callback set by CURLOPT_SSH_HOSTKEYFUNCTION is called to check wether or not the connection should continue. The host key is passed in argument with a custom handle for the application. It overrides CURLOPT_SSH_KNOWNHOSTS Closes #7959
This commit is contained in:
parent
267d560b5a
commit
1544513958
11 changed files with 263 additions and 20 deletions
|
|
@ -437,9 +437,45 @@ static int sshkeycallback(struct Curl_easy *easy,
|
|||
#else
|
||||
#define session_startup(x,y) libssh2_session_startup(x, (int)y)
|
||||
#endif
|
||||
static int convert_ssh2_keytype(int sshkeytype)
|
||||
{
|
||||
int keytype = CURLKHTYPE_UNKNOWN;
|
||||
switch(sshkeytype) {
|
||||
case LIBSSH2_HOSTKEY_TYPE_RSA:
|
||||
keytype = CURLKHTYPE_RSA;
|
||||
break;
|
||||
case LIBSSH2_HOSTKEY_TYPE_DSS:
|
||||
keytype = CURLKHTYPE_DSS;
|
||||
break;
|
||||
#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_256
|
||||
case LIBSSH2_HOSTKEY_TYPE_ECDSA_256:
|
||||
keytype = CURLKHTYPE_ECDSA;
|
||||
break;
|
||||
#endif
|
||||
#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_384
|
||||
case LIBSSH2_HOSTKEY_TYPE_ECDSA_384:
|
||||
keytype = CURLKHTYPE_ECDSA;
|
||||
break;
|
||||
#endif
|
||||
#ifdef LIBSSH2_HOSTKEY_TYPE_ECDSA_521
|
||||
case LIBSSH2_HOSTKEY_TYPE_ECDSA_521:
|
||||
keytype = CURLKHTYPE_ECDSA;
|
||||
break;
|
||||
#endif
|
||||
#ifdef LIBSSH2_HOSTKEY_TYPE_ED25519
|
||||
case LIBSSH2_HOSTKEY_TYPE_ED25519:
|
||||
keytype = CURLKHTYPE_ED25519;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
return keytype;
|
||||
}
|
||||
|
||||
static CURLcode ssh_knownhost(struct Curl_easy *data)
|
||||
{
|
||||
int sshkeytype = 0;
|
||||
size_t keylen = 0;
|
||||
int rc = 0;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
#ifdef HAVE_LIBSSH2_KNOWNHOST_API
|
||||
|
|
@ -448,11 +484,8 @@ static CURLcode ssh_knownhost(struct Curl_easy *data)
|
|||
struct connectdata *conn = data->conn;
|
||||
struct ssh_conn *sshc = &conn->proto.sshc;
|
||||
struct libssh2_knownhost *host = NULL;
|
||||
int rc;
|
||||
int keytype;
|
||||
size_t keylen;
|
||||
const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
|
||||
&keylen, &keytype);
|
||||
&keylen, &sshkeytype);
|
||||
int keycheck = LIBSSH2_KNOWNHOST_CHECK_FAILURE;
|
||||
int keybit = 0;
|
||||
|
||||
|
|
@ -464,12 +497,12 @@ static CURLcode ssh_knownhost(struct Curl_easy *data)
|
|||
*/
|
||||
enum curl_khmatch keymatch;
|
||||
curl_sshkeycallback func =
|
||||
data->set.ssh_keyfunc?data->set.ssh_keyfunc:sshkeycallback;
|
||||
data->set.ssh_keyfunc ? data->set.ssh_keyfunc : sshkeycallback;
|
||||
struct curl_khkey knownkey;
|
||||
struct curl_khkey *knownkeyp = NULL;
|
||||
struct curl_khkey foundkey;
|
||||
|
||||
switch(keytype) {
|
||||
switch(sshkeytype) {
|
||||
case LIBSSH2_HOSTKEY_TYPE_RSA:
|
||||
keybit = LIBSSH2_KNOWNHOST_KEY_SSHRSA;
|
||||
break;
|
||||
|
|
@ -533,16 +566,14 @@ static CURLcode ssh_knownhost(struct Curl_easy *data)
|
|||
if(keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH) {
|
||||
knownkey.key = host->key;
|
||||
knownkey.len = 0;
|
||||
knownkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
|
||||
CURLKHTYPE_RSA : CURLKHTYPE_DSS;
|
||||
knownkey.keytype = convert_ssh2_keytype(sshkeytype);
|
||||
knownkeyp = &knownkey;
|
||||
}
|
||||
|
||||
/* setup 'foundkey' */
|
||||
foundkey.key = remotekey;
|
||||
foundkey.len = keylen;
|
||||
foundkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
|
||||
CURLKHTYPE_RSA : CURLKHTYPE_DSS;
|
||||
foundkey.keytype = convert_ssh2_keytype(sshkeytype);
|
||||
|
||||
/*
|
||||
* if any of the LIBSSH2_KNOWNHOST_CHECK_* defines and the
|
||||
|
|
@ -639,7 +670,7 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
|
|||
#ifdef LIBSSH2_HOSTKEY_HASH_SHA256
|
||||
/* The fingerprint points to static storage (!), don't free() it. */
|
||||
fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
|
||||
LIBSSH2_HOSTKEY_HASH_SHA256);
|
||||
LIBSSH2_HOSTKEY_HASH_SHA256);
|
||||
#else
|
||||
const char *hostkey;
|
||||
size_t len = 0;
|
||||
|
|
@ -654,8 +685,8 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
|
|||
|
||||
if(!fingerprint) {
|
||||
failf(data,
|
||||
"Denied establishing ssh session: sha256 fingerprint "
|
||||
"not available");
|
||||
"Denied establishing ssh session: sha256 fingerprint "
|
||||
"not available");
|
||||
state(data, SSH_SESSION_FREE);
|
||||
sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
|
||||
return sshc->actualcode;
|
||||
|
|
@ -715,7 +746,7 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
|
|||
const char *fingerprint = NULL;
|
||||
|
||||
fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
|
||||
LIBSSH2_HOSTKEY_HASH_MD5);
|
||||
LIBSSH2_HOSTKEY_HASH_MD5);
|
||||
|
||||
if(fingerprint) {
|
||||
/* The fingerprint points to static storage (!), don't free() it. */
|
||||
|
|
@ -748,7 +779,31 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
|
|||
}
|
||||
|
||||
if(!pubkey_md5 && !pubkey_sha256) {
|
||||
return ssh_knownhost(data);
|
||||
if(data->set.ssh_hostkeyfunc) {
|
||||
size_t keylen = 0;
|
||||
int sshkeytype = 0;
|
||||
int rc = 0;
|
||||
/* we handle the process to the callback*/
|
||||
const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
|
||||
&keylen, &sshkeytype);
|
||||
if(remotekey) {
|
||||
int keytype = convert_ssh2_keytype(sshkeytype);
|
||||
Curl_set_in_callback(data, true);
|
||||
rc = data->set.ssh_hostkeyfunc(data->set.ssh_hostkeyfunc_userp,
|
||||
keytype, remotekey, keylen);
|
||||
Curl_set_in_callback(data, false);
|
||||
if(rc!= CURLKHMATCH_OK) {
|
||||
state(data, SSH_SESSION_FREE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
state(data, SSH_SESSION_FREE);
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
else {
|
||||
return ssh_knownhost(data);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* as we already matched, we skip the check for known hosts */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue