diff --git a/pgadmin/include/utils/sshTunnel.h b/pgadmin/include/utils/sshTunnel.h index 18e7a48..616b7e7 100644 --- a/pgadmin/include/utils/sshTunnel.h +++ b/pgadmin/include/utils/sshTunnel.h @@ -77,6 +77,7 @@ private: bool resolveDNS(const char *host, wxArrayString &arrIPAddress); static void keyboard_interactive(const char *name, int name_len, const char *instr, int instr_len, int num_prompts, const struct _LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE *res, void **abstract); + bool IsHostKeyVerified(const wxString& newHostKey); int m_listensock, m_sock; struct sockaddr_in m_sin; diff --git a/pgadmin/utils/sshTunnel.cpp b/pgadmin/utils/sshTunnel.cpp index ca32bd1..f6c933f 100644 --- a/pgadmin/utils/sshTunnel.cpp +++ b/pgadmin/utils/sshTunnel.cpp @@ -141,6 +141,18 @@ bool CSSHTunnelThread::Initialize() * user, that's your call */ fingerprint = libssh2_hostkey_hash(m_session, LIBSSH2_HOSTKEY_HASH_SHA1); + wxString newHostKey = wxEmptyString; + for(int i = 0; i < 20; i++) { + newHostKey += wxString::Format(wxT("%02X "), (unsigned char)fingerprint[i]); + } + + // Check for the SSH Host Key is verified + if(!IsHostKeyVerified(newHostKey)) + { + Cleanup(); + return false; + } + /* check what authentication methods are available */ userauthlist = libssh2_userauth_list(m_session, m_username.mb_str(), strlen(m_username.mb_str())); @@ -407,6 +419,46 @@ void CSSHTunnelThread::keyboard_interactive(const char *name, int name_len, cons } } +bool CSSHTunnelThread::IsHostKeyVerified(const wxString& newHostKey) +{ + bool bIsVerified = false; + wxString cachedHostKey = settings->Read(m_tunnelhost, wxEmptyString); + + // If cached host key is empty then ask user to accept or reject + if(cachedHostKey == wxEmptyString) + { + //Prompt User to accept or reject + wxString msg = wxString::Format(wxT("Host key received for the SSH server \"%s\" is \"%s\" \n\nWould you like to accept it and continue with the connection?"), m_tunnelhost.c_str(), newHostKey.c_str()); + int answer = wxMessageBox(msg, wxT("Host key verification?"), wxYES_NO | wxNO_DEFAULT); + if (answer == wxYES) + { + // Write the host key with respect to tunnel host + settings->Write(m_tunnelhost, newHostKey); + bIsVerified = true; + } + } + else + { + // Compare the cached host key with the new key + if(cachedHostKey.compare(newHostKey) == 0) + bIsVerified = true; + else + { + //Prompt user to accept or reject the new host key received for the tunnel host + wxString msg = wxString::Format(wxT("WARNING :\n\nThe host key received from the server \"%s\" is %s, but the stored key is %s. This may indicate that this is not the same server that was previously used.\n\nDo you wish to accept and store the new key, and continue with the connection?"), m_tunnelhost.c_str(), newHostKey.c_str(), cachedHostKey.c_str()); + int answer = wxMessageBox(msg, wxT("Host key verification?"), wxYES_NO | wxNO_DEFAULT); + if (answer == wxYES) + { + // Write the host key with respect to tunnel host + settings->Write(m_tunnelhost, newHostKey); + bIsVerified = true; + } + } + } + + return bIsVerified; +} + CSubThread::CSubThread(const struct sockaddr_in sin, const wxString remote_desthost, const unsigned int remote_destport, LIBSSH2_SESSION *session, int forwardsock) : m_sin(sin), m_remote_desthost(remote_desthost), m_remote_destport(remote_destport),