mirror of https://github.com/moparisthebest/curl
SSH: move knownhost logic to separate function
This commit is contained in:
parent
b903186fa0
commit
9869668884
192
lib/ssh.c
192
lib/ssh.c
|
@ -504,100 +504,16 @@ static int sshkeycallback(CURL *easy,
|
||||||
#define libssh2_session_startup(x,y) libssh2_session_handshake(x,y)
|
#define libssh2_session_startup(x,y) libssh2_session_handshake(x,y)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
static CURLcode ssh_knownhost(struct connectdata *conn)
|
||||||
* ssh_statemach_act() runs the SSH state machine as far as it can without
|
|
||||||
* blocking and without reaching the end. The data the pointer 'block' points
|
|
||||||
* to will be set to TRUE if the libssh2 function returns LIBSSH2_ERROR_EAGAIN
|
|
||||||
* meaning it wants to be called again when the socket is ready
|
|
||||||
*/
|
|
||||||
|
|
||||||
static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
|
||||||
{
|
{
|
||||||
CURLcode result = CURLE_OK;
|
|
||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
struct SSHPROTO *sftp_scp = data->state.proto.ssh;
|
CURLcode result = CURLE_OK;
|
||||||
struct ssh_conn *sshc = &conn->proto.sshc;
|
|
||||||
curl_socket_t sock = conn->sock[FIRSTSOCKET];
|
|
||||||
#ifdef CURL_LIBSSH2_DEBUG
|
|
||||||
const char *fingerprint;
|
|
||||||
#endif /* CURL_LIBSSH2_DEBUG */
|
|
||||||
const char *host_public_key_md5;
|
|
||||||
int rc = LIBSSH2_ERROR_NONE, i;
|
|
||||||
int err;
|
|
||||||
int seekerr = CURL_SEEKFUNC_OK;
|
|
||||||
*block = 0; /* we're not blocking by default */
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
switch(sshc->state) {
|
|
||||||
case SSH_S_STARTUP:
|
|
||||||
sshc->secondCreateDirs = 0;
|
|
||||||
sshc->nextstate = SSH_NO_STATE;
|
|
||||||
sshc->actualcode = CURLE_OK;
|
|
||||||
|
|
||||||
rc = libssh2_session_startup(sshc->ssh_session, sock);
|
|
||||||
if(rc == LIBSSH2_ERROR_EAGAIN) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if(rc) {
|
|
||||||
failf(data, "Failure establishing ssh session");
|
|
||||||
state(conn, SSH_SESSION_FREE);
|
|
||||||
sshc->actualcode = CURLE_FAILED_INIT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set libssh2 to non-blocking, since everything internally is
|
|
||||||
non-blocking */
|
|
||||||
libssh2_session_set_blocking(sshc->ssh_session, 0);
|
|
||||||
|
|
||||||
state(conn, SSH_HOSTKEY);
|
|
||||||
|
|
||||||
/* fall-through */
|
|
||||||
case SSH_HOSTKEY:
|
|
||||||
|
|
||||||
#ifdef CURL_LIBSSH2_DEBUG
|
|
||||||
/*
|
|
||||||
* Before we authenticate we should check the hostkey's fingerprint
|
|
||||||
* against our known hosts. How that is handled (reading from file,
|
|
||||||
* whatever) is up to us. As for know not much is implemented, besides
|
|
||||||
* showing how to get the fingerprint.
|
|
||||||
*/
|
|
||||||
fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
|
|
||||||
LIBSSH2_HOSTKEY_HASH_MD5);
|
|
||||||
|
|
||||||
/* The fingerprint points to static storage (!), don't free() it. */
|
|
||||||
infof(data, "Fingerprint: ");
|
|
||||||
for(rc = 0; rc < 16; rc++)
|
|
||||||
infof(data, "%02X ", (unsigned char) fingerprint[rc]);
|
|
||||||
infof(data, "\n");
|
|
||||||
#endif /* CURL_LIBSSH2_DEBUG */
|
|
||||||
|
|
||||||
/* Before we authenticate we check the hostkey's MD5 fingerprint
|
|
||||||
* against a known fingerprint, if available. This implementation pulls
|
|
||||||
* it from the curl option.
|
|
||||||
*/
|
|
||||||
if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] &&
|
|
||||||
strlen(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) == 32) {
|
|
||||||
char buf[33];
|
|
||||||
host_public_key_md5 = libssh2_hostkey_hash(sshc->ssh_session,
|
|
||||||
LIBSSH2_HOSTKEY_HASH_MD5);
|
|
||||||
for(i = 0; i < 16; i++)
|
|
||||||
snprintf(&buf[i*2], 3, "%02x",
|
|
||||||
(unsigned char) host_public_key_md5[i]);
|
|
||||||
if(!strequal(buf, data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5])) {
|
|
||||||
failf(data,
|
|
||||||
"Denied establishing ssh session: mismatch md5 fingerprint. "
|
|
||||||
"Remote %s is not equal to %s",
|
|
||||||
buf, data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]);
|
|
||||||
state(conn, SSH_SESSION_FREE);
|
|
||||||
sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_LIBSSH2_KNOWNHOST_API
|
#ifdef HAVE_LIBSSH2_KNOWNHOST_API
|
||||||
if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
|
if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
|
||||||
/* we're asked to verify the host against a file */
|
/* we're asked to verify the host against a file */
|
||||||
|
struct ssh_conn *sshc = &conn->proto.sshc;
|
||||||
|
int rc;
|
||||||
int keytype;
|
int keytype;
|
||||||
size_t keylen;
|
size_t keylen;
|
||||||
const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
|
const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
|
||||||
|
@ -704,8 +620,106 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* HAVE_LIBSSH2_KNOWNHOST_API */
|
#else /* HAVE_LIBSSH2_KNOWNHOST_API */
|
||||||
|
(void)conn;
|
||||||
|
#endif
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ssh_statemach_act() runs the SSH state machine as far as it can without
|
||||||
|
* blocking and without reaching the end. The data the pointer 'block' points
|
||||||
|
* to will be set to TRUE if the libssh2 function returns LIBSSH2_ERROR_EAGAIN
|
||||||
|
* meaning it wants to be called again when the socket is ready
|
||||||
|
*/
|
||||||
|
|
||||||
|
static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||||
|
{
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
struct SSHPROTO *sftp_scp = data->state.proto.ssh;
|
||||||
|
struct ssh_conn *sshc = &conn->proto.sshc;
|
||||||
|
curl_socket_t sock = conn->sock[FIRSTSOCKET];
|
||||||
|
#ifdef CURL_LIBSSH2_DEBUG
|
||||||
|
const char *fingerprint;
|
||||||
|
#endif /* CURL_LIBSSH2_DEBUG */
|
||||||
|
const char *host_public_key_md5;
|
||||||
|
int rc = LIBSSH2_ERROR_NONE, i;
|
||||||
|
int err;
|
||||||
|
int seekerr = CURL_SEEKFUNC_OK;
|
||||||
|
*block = 0; /* we're not blocking by default */
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
|
switch(sshc->state) {
|
||||||
|
case SSH_S_STARTUP:
|
||||||
|
sshc->secondCreateDirs = 0;
|
||||||
|
sshc->nextstate = SSH_NO_STATE;
|
||||||
|
sshc->actualcode = CURLE_OK;
|
||||||
|
|
||||||
|
rc = libssh2_session_startup(sshc->ssh_session, sock);
|
||||||
|
if(rc == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if(rc) {
|
||||||
|
failf(data, "Failure establishing ssh session");
|
||||||
|
state(conn, SSH_SESSION_FREE);
|
||||||
|
sshc->actualcode = CURLE_FAILED_INIT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set libssh2 to non-blocking, since everything internally is
|
||||||
|
non-blocking */
|
||||||
|
libssh2_session_set_blocking(sshc->ssh_session, 0);
|
||||||
|
|
||||||
|
state(conn, SSH_HOSTKEY);
|
||||||
|
|
||||||
|
/* fall-through */
|
||||||
|
case SSH_HOSTKEY:
|
||||||
|
|
||||||
|
#ifdef CURL_LIBSSH2_DEBUG
|
||||||
|
/*
|
||||||
|
* Before we authenticate we should check the hostkey's fingerprint
|
||||||
|
* against our known hosts. How that is handled (reading from file,
|
||||||
|
* whatever) is up to us. As for know not much is implemented, besides
|
||||||
|
* showing how to get the fingerprint.
|
||||||
|
*/
|
||||||
|
fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
|
||||||
|
LIBSSH2_HOSTKEY_HASH_MD5);
|
||||||
|
|
||||||
|
/* The fingerprint points to static storage (!), don't free() it. */
|
||||||
|
infof(data, "Fingerprint: ");
|
||||||
|
for(rc = 0; rc < 16; rc++)
|
||||||
|
infof(data, "%02X ", (unsigned char) fingerprint[rc]);
|
||||||
|
infof(data, "\n");
|
||||||
|
#endif /* CURL_LIBSSH2_DEBUG */
|
||||||
|
|
||||||
|
/* Before we authenticate we check the hostkey's MD5 fingerprint
|
||||||
|
* against a known fingerprint, if available. This implementation pulls
|
||||||
|
* it from the curl option.
|
||||||
|
*/
|
||||||
|
if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] &&
|
||||||
|
strlen(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) == 32) {
|
||||||
|
char buf[33];
|
||||||
|
host_public_key_md5 = libssh2_hostkey_hash(sshc->ssh_session,
|
||||||
|
LIBSSH2_HOSTKEY_HASH_MD5);
|
||||||
|
for(i = 0; i < 16; i++)
|
||||||
|
snprintf(&buf[i*2], 3, "%02x",
|
||||||
|
(unsigned char) host_public_key_md5[i]);
|
||||||
|
if(!strequal(buf, data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5])) {
|
||||||
|
failf(data,
|
||||||
|
"Denied establishing ssh session: mismatch md5 fingerprint. "
|
||||||
|
"Remote %s is not equal to %s",
|
||||||
|
buf, data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]);
|
||||||
|
state(conn, SSH_SESSION_FREE);
|
||||||
|
sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = ssh_knownhost(conn);
|
||||||
|
if(!result)
|
||||||
state(conn, SSH_AUTHLIST);
|
state(conn, SSH_AUTHLIST);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue