Revision: 8081 https://osdn.net/projects/ttssh2/scm/svn/commits/8081 Author: yutakapon Date: 2019-09-07 17:18:20 +0900 (Sat, 07 Sep 2019) Log Message: ----------- known_hostsダイアログが表示されている状態で、サーバから切断を行うと、 TTXCloseTCPが呼び出され、TTSSHのリソースが解放されてしまう。 SSHハンドラの延長でknown_hostsダイアログを出して止まっているため、 ダイアログを閉じて、処理再開すると、SSHの内部情報が壊れる。 その状態で再度SSH接続しようとすると100%アプリが落ちる。 上記問題に対して、SSH2 に対応した。 パケット受信時のSSHハンドラのコンテキストで known_hosts ダイアログを表示 させていたが、TTXCloseTCPの非同期呼び出しに対処できないため、 TTSSH1で使われていたknown_hosts ダイアログの非同期呼び出しに 実装を変更した。 これにより、比較的大きくロジックの修正を行っている。 Modified Paths: -------------- branches/ttssh_improved/ttssh2/ttxssh/hosts.c branches/ttssh_improved/ttssh2/ttxssh/ssh.c branches/ttssh_improved/ttssh2/ttxssh/ssh.h branches/ttssh_improved/ttssh2/ttxssh/ttxssh.c branches/ttssh_improved/ttssh2/ttxssh/ttxssh.h -------------- next part -------------- Modified: branches/ttssh_improved/ttssh2/ttxssh/hosts.c =================================================================== --- branches/ttssh_improved/ttssh2/ttxssh/hosts.c 2019-09-07 03:34:48 UTC (rev 8080) +++ branches/ttssh_improved/ttssh2/ttxssh/hosts.c 2019-09-07 08:18:20 UTC (rev 8081) @@ -66,6 +66,10 @@ static char base64[] ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +BOOL HOSTS_resume_session_after_known_hosts(PTInstVar pvar); +void HOSTS_cancel_session_after_known_hosts(PTInstVar pvar); + + static char **parse_multi_path(char *buf) { int i; @@ -1811,11 +1815,11 @@ add_host_key(pvar); } - if (SSHv1(pvar)) { - SSH_notify_host_OK(pvar); - } else { // SSH2 - // SSH2\x82ł͂\xA0\x82Ƃ\xC5 SSH_notify_host_OK() \x82\xF0\x8CĂԁB - } + /* + * known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82̂\xBD\x82߂Ɉꎞ\x92\xE2\x8E~\x82\xB5\x82Ă\xA2\x82\xBD + * SSH\x83T\x81[\x83o\x82Ƃ̃l\x83S\x83V\x83G\x81[\x83V\x83\x87\x83\x93\x82\xF0\x8DĊJ\x82\xB3\x82\xB9\x82\xE9\x81B + */ + HOSTS_resume_session_after_known_hosts(pvar); pvar->hosts_state.hosts_dialog = NULL; @@ -1824,6 +1828,11 @@ case IDCANCEL: /* kill the connection */ canceled: + /* + * known_hosts\x82\xF0\x83L\x83\x83\x83\x93\x83Z\x83\x8B\x82\xB7\x82邽\x82߁A\x8DĊJ\x97p\x82̃\x8A\x83\\x81[\x83X\x82\xF0\x94j\x8A\xFC\x82\xB5\x82Ă\xA8\x82\xAD\x81B + */ + HOSTS_cancel_session_after_known_hosts(pvar); + pvar->hosts_state.hosts_dialog = NULL; notify_closed_connection(pvar, "authentication cancelled"); EndDialog(dlg, 0); @@ -1830,7 +1839,12 @@ return TRUE; case IDCLOSE: - // \x94F\x8Fؒ\x86\x82Ƀl\x83b\x83g\x83\x8F\x81[\x83N\x90ؒf\x82\xB3\x82ꂽ\x8Fꍇ\x81A\x93\x96\x8AY\x83\x81\x83b\x83Z\x81[\x83W\x82Ń_\x83C\x83A\x83\x8D\x83O\x82\xF0\x95\xB6\x82\xE9\x81B + /* + * known_hosts\x92\x86\x82ɃT\x81[\x83o\x91\xA4\x82\xA9\x82\xE7\x83l\x83b\x83g\x83\x8F\x81[\x83N\x90ؒf\x82\xB3\x82ꂽ\x8Fꍇ\x81A + * \x83_\x83C\x83A\x83\x8D\x83O\x82݂̂\xF0\x95\xB6\x82\xE9\x81B + */ + HOSTS_cancel_session_after_known_hosts(pvar); + pvar->hosts_state.hosts_dialog = NULL; EndDialog(dlg, 0); return TRUE; @@ -1970,11 +1984,11 @@ delete_different_key(pvar); } - if (SSHv1(pvar)) { - SSH_notify_host_OK(pvar); - } else { // SSH2 - // SSH2\x82ł͂\xA0\x82Ƃ\xC5 SSH_notify_host_OK() \x82\xF0\x8CĂԁB - } + /* + * known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82̂\xBD\x82߂Ɉꎞ\x92\xE2\x8E~\x82\xB5\x82Ă\xA2\x82\xBD + * SSH\x83T\x81[\x83o\x82Ƃ̃l\x83S\x83V\x83G\x81[\x83V\x83\x87\x83\x93\x82\xF0\x8DĊJ\x82\xB3\x82\xB9\x82\xE9\x81B + */ + HOSTS_resume_session_after_known_hosts(pvar); pvar->hosts_state.hosts_dialog = NULL; @@ -1983,6 +1997,11 @@ case IDCANCEL: /* kill the connection */ canceled: + /* + * known_hosts\x82\xF0\x83L\x83\x83\x83\x93\x83Z\x83\x8B\x82\xB7\x82邽\x82߁A\x8DĊJ\x97p\x82̃\x8A\x83\\x81[\x83X\x82\xF0\x94j\x8A\xFC\x82\xB5\x82Ă\xA8\x82\xAD\x81B + */ + HOSTS_cancel_session_after_known_hosts(pvar); + pvar->hosts_state.hosts_dialog = NULL; notify_closed_connection(pvar, "authentication cancelled"); EndDialog(dlg, 0); @@ -1989,7 +2008,12 @@ return TRUE; case IDCLOSE: - // \x94F\x8Fؒ\x86\x82Ƀl\x83b\x83g\x83\x8F\x81[\x83N\x90ؒf\x82\xB3\x82ꂽ\x8Fꍇ\x81A\x93\x96\x8AY\x83\x81\x83b\x83Z\x81[\x83W\x82Ń_\x83C\x83A\x83\x8D\x83O\x82\xF0\x95\xB6\x82\xE9\x81B + /* + * known_hosts\x92\x86\x82ɃT\x81[\x83o\x91\xA4\x82\xA9\x82\xE7\x83l\x83b\x83g\x83\x8F\x81[\x83N\x90ؒf\x82\xB3\x82ꂽ\x8Fꍇ\x81A + * \x83_\x83C\x83A\x83\x8D\x83O\x82݂̂\xF0\x95\xB6\x82\xE9\x81B + */ + HOSTS_cancel_session_after_known_hosts(pvar); + pvar->hosts_state.hosts_dialog = NULL; EndDialog(dlg, 0); return TRUE; @@ -2130,11 +2154,11 @@ add_host_key(pvar); } - if (SSHv1(pvar)) { - SSH_notify_host_OK(pvar); - } else { // SSH2 - // SSH2\x82ł͂\xA0\x82Ƃ\xC5 SSH_notify_host_OK() \x82\xF0\x8CĂԁB - } + /* + * known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82̂\xBD\x82߂Ɉꎞ\x92\xE2\x8E~\x82\xB5\x82Ă\xA2\x82\xBD + * SSH\x83T\x81[\x83o\x82Ƃ̃l\x83S\x83V\x83G\x81[\x83V\x83\x87\x83\x93\x82\xF0\x8DĊJ\x82\xB3\x82\xB9\x82\xE9\x81B + */ + HOSTS_resume_session_after_known_hosts(pvar); pvar->hosts_state.hosts_dialog = NULL; @@ -2143,6 +2167,11 @@ case IDCANCEL: /* kill the connection */ canceled: + /* + * known_hosts\x82\xF0\x83L\x83\x83\x83\x93\x83Z\x83\x8B\x82\xB7\x82邽\x82߁A\x8DĊJ\x97p\x82̃\x8A\x83\\x81[\x83X\x82\xF0\x94j\x8A\xFC\x82\xB5\x82Ă\xA8\x82\xAD\x81B + */ + HOSTS_cancel_session_after_known_hosts(pvar); + pvar->hosts_state.hosts_dialog = NULL; notify_closed_connection(pvar, "authentication cancelled"); EndDialog(dlg, 0); @@ -2149,7 +2178,12 @@ return TRUE; case IDCLOSE: - // \x94F\x8Fؒ\x86\x82Ƀl\x83b\x83g\x83\x8F\x81[\x83N\x90ؒf\x82\xB3\x82ꂽ\x8Fꍇ\x81A\x93\x96\x8AY\x83\x81\x83b\x83Z\x81[\x83W\x82Ń_\x83C\x83A\x83\x8D\x83O\x82\xF0\x95\xB6\x82\xE9\x81B + /* + * known_hosts\x92\x86\x82ɃT\x81[\x83o\x91\xA4\x82\xA9\x82\xE7\x83l\x83b\x83g\x83\x8F\x81[\x83N\x90ؒf\x82\xB3\x82ꂽ\x8Fꍇ\x81A + * \x83_\x83C\x83A\x83\x8D\x83O\x82݂̂\xF0\x95\xB6\x82\xE9\x81B + */ + HOSTS_cancel_session_after_known_hosts(pvar); + pvar->hosts_state.hosts_dialog = NULL; EndDialog(dlg, 0); return TRUE; @@ -2194,7 +2228,15 @@ void HOSTS_do_unknown_host_dialog(HWND wnd, PTInstVar pvar) { if (pvar->hosts_state.hosts_dialog == NULL) { - HWND cur_active = GetActiveWindow(); + /* known_hosts\x82̓ǂݍ\x9E\x82ݎ\x9E\x81AID_SSHASYNCMESSAGEBOX \x82\xF0\x8Eg\x82\xC1\x82\xBD + * MessageBox \x82\xAA\x95\\x8E\xA6\x82\xB3\x82\xEA\x82\xE9\x8Fꍇ\x81A\x83I\x81[\x83i\x81[\x82Ȃ\xB5(no owner)\x82ɂȂ邽\x82߁A + * MessageBox \x82\xAATera Term\x82̗\xA0\x82ɉB\x82\xEA\x82邱\x82Ƃ\xAA\x82\xA0\x82\xE9\x81B + * \x82\xBB\x82̏\xF3\x91Ԃ\xC5 GetActiveWindow() \x82\xF0\x8CĂяo\x82\xB7\x82ƁAknown_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82\xCC + * \x83I\x81[\x83i\x81[\x82\xAA MessageBox \x82ƂȂ\xC1\x82āATera Term\x82̗\xA0\x82ɉB\x82\xEA\x82Ă\xB5\x82܂\xA4\x81B + * \x82\xBB\x82\xB1\x82ŁAknown_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82̃I\x81[\x83i\x81[\x82͏\xED\x82\xC9 Tera Term \x82\xF0\x8Ew\x82\xB5\x8E\xA6\x82\xB7 + * \x82悤\x82ɂ\xB7\x82\xE9\x81B + */ + HWND cur_active = NULL; DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHUNKNOWNHOST), cur_active != NULL ? cur_active : wnd, @@ -2205,7 +2247,15 @@ void HOSTS_do_different_key_dialog(HWND wnd, PTInstVar pvar) { if (pvar->hosts_state.hosts_dialog == NULL) { - HWND cur_active = GetActiveWindow(); + /* known_hosts\x82̓ǂݍ\x9E\x82ݎ\x9E\x81AID_SSHASYNCMESSAGEBOX \x82\xF0\x8Eg\x82\xC1\x82\xBD + * MessageBox \x82\xAA\x95\\x8E\xA6\x82\xB3\x82\xEA\x82\xE9\x8Fꍇ\x81A\x83I\x81[\x83i\x81[\x82Ȃ\xB5(no owner)\x82ɂȂ邽\x82߁A + * MessageBox \x82\xAATera Term\x82̗\xA0\x82ɉB\x82\xEA\x82邱\x82Ƃ\xAA\x82\xA0\x82\xE9\x81B + * \x82\xBB\x82̏\xF3\x91Ԃ\xC5 GetActiveWindow() \x82\xF0\x8CĂяo\x82\xB7\x82ƁAknown_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82\xCC + * \x83I\x81[\x83i\x81[\x82\xAA MessageBox \x82ƂȂ\xC1\x82āATera Term\x82̗\xA0\x82ɉB\x82\xEA\x82Ă\xB5\x82܂\xA4\x81B + * \x82\xBB\x82\xB1\x82ŁAknown_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82̃I\x81[\x83i\x81[\x82͏\xED\x82\xC9 Tera Term \x82\xF0\x8Ew\x82\xB5\x8E\xA6\x82\xB7 + * \x82悤\x82ɂ\xB7\x82\xE9\x81B + */ + HWND cur_active = NULL; DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHDIFFERENTKEY), cur_active != NULL ? cur_active : wnd, @@ -2216,7 +2266,15 @@ void HOSTS_do_different_type_key_dialog(HWND wnd, PTInstVar pvar) { if (pvar->hosts_state.hosts_dialog == NULL) { - HWND cur_active = GetActiveWindow(); + /* known_hosts\x82̓ǂݍ\x9E\x82ݎ\x9E\x81AID_SSHASYNCMESSAGEBOX \x82\xF0\x8Eg\x82\xC1\x82\xBD + * MessageBox \x82\xAA\x95\\x8E\xA6\x82\xB3\x82\xEA\x82\xE9\x8Fꍇ\x81A\x83I\x81[\x83i\x81[\x82Ȃ\xB5(no owner)\x82ɂȂ邽\x82߁A + * MessageBox \x82\xAATera Term\x82̗\xA0\x82ɉB\x82\xEA\x82邱\x82Ƃ\xAA\x82\xA0\x82\xE9\x81B + * \x82\xBB\x82̏\xF3\x91Ԃ\xC5 GetActiveWindow() \x82\xF0\x8CĂяo\x82\xB7\x82ƁAknown_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82\xCC + * \x83I\x81[\x83i\x81[\x82\xAA MessageBox \x82ƂȂ\xC1\x82āATera Term\x82̗\xA0\x82ɉB\x82\xEA\x82Ă\xB5\x82܂\xA4\x81B + * \x82\xBB\x82\xB1\x82ŁAknown_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82̃I\x81[\x83i\x81[\x82͏\xED\x82\xC9 Tera Term \x82\xF0\x8Ew\x82\xB5\x8E\xA6\x82\xB7 + * \x82悤\x82ɂ\xB7\x82\xE9\x81B + */ + HWND cur_active = NULL; DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHDIFFERENTTYPEKEY), cur_active != NULL ? cur_active : wnd, @@ -2224,16 +2282,24 @@ } } -// -// \x83T\x81[\x83o\x82\xA9\x82瑗\x82\xE7\x82\xEA\x82Ă\xAB\x82\xBD\x83z\x83X\x83g\x8C\xF6\x8AJ\x8C\xAE\x82̑Ó\x96\x90\xAB\x82\xF0\x83`\x83F\x83b\x83N\x82\xB7\x82\xE9 -// key: \x83T\x81[\x83o\x82\xA9\x82\xE7\x82̌\xF6\x8AJ\x8C\xAE -// -// SSH2\x91Ή\x9E\x82\xF0\x92lj\xC1 (2006.3.24 yutaka) -// +/* + * \x83T\x81[\x83o\x82\xA9\x82瑗\x82\xE7\x82\xEA\x82Ă\xAB\x82\xBD\x83z\x83X\x83g\x8C\xF6\x8AJ\x8C\xAE\x82̑Ó\x96\x90\xAB\x82\xF0\x83`\x83F\x83b\x83N\x82\xB5\x81A + * \x95K\x97v\x82ɉ\x9E\x82\xB6\x82\xC4 known_hosts \x83_\x83C\x83A\x83\x8D\x83O\x82\xF0\x8CĂяo\x82\xB7\x81B + * + * hostname: \x90ڑ\xB1\x90\xE6\x82̃z\x83X\x83g\x96\xBC + * tcpport: \x90ڑ\xB1\x90\xE6\x83|\x81[\x83g\x94ԍ\x86 + * key: \x83T\x81[\x83o\x82\xA9\x82\xE7\x82̌\xF6\x8AJ\x8C\xAE + * + * return: + * TRUE: known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82̌Ăяo\x82\xB5\x82͕s\x97v + * FALSE: known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82\xF0\x8CĂяo\x82\xB5\x82\xBD + * + */ BOOL HOSTS_check_host_key(PTInstVar pvar, char *hostname, unsigned short tcpport, Key *key) { int found_different_key = 0, found_different_type_key = 0; Key key2; // known_hosts\x82ɓo\x98^\x82\xB3\x82\xEA\x82Ă\xA2\x82錮 + DWORD id; pvar->dns_key_check = DNS_VERIFY_NONE; @@ -2242,12 +2308,8 @@ && _stricmp(pvar->hosts_state.prefetched_hostname, hostname) == 0 && HOSTS_compare_public_key(&pvar->hosts_state.hostkey, key) == 1) { - if (SSHv1(pvar)) { - SSH_notify_host_OK(pvar); - } else { - // SSH2\x82ł͂\xA0\x82Ƃ\xC5 SSH_notify_host_OK() \x82\xF0\x8CĂԁB - } - return TRUE; + // \x89\xBD\x82\xE0\x82\xB9\x82\xB8\x82ɖ߂\xE9\x81B + return TRUE; } // \x90\xE6\x93ǂ݂\xB3\x82\xEA\x82Ă\xA2\x82Ȃ\xA2\x8Fꍇ\x82́A\x82\xB1\x82̎\x9E\x93_\x82Ńt\x83@\x83C\x83\x8B\x82\xA9\x82\xE7\x93ǂݍ\x9E\x82\xDE @@ -2263,13 +2325,6 @@ if (match == 1) { finish_read_host_files(pvar, 0); // \x82\xB7\x82ׂẴG\x83\x93\x83g\x83\x8A\x82\xF0\x8EQ\x8FƂ\xB5\x82āA\x8D\x87\x92v\x82\xB7\x82\xE9\x83L\x81[\x82\xAA\x8C\xA9\x82\xA9\x82\xC1\x82\xBD\x82\xE7\x96߂\xE9\x81B - // SSH2\x82̏ꍇ\x82͂\xB1\x82\xB1\x82ł͉\xBD\x82\xE0\x82\xB5\x82Ȃ\xA2\x81B(2006.3.29 yutaka) - if (SSHv1(pvar)) { - SSH_notify_host_OK(pvar); - } else { - // SSH2\x82ł͂\xA0\x82Ƃ\xC5 SSH_notify_host_OK() \x82\xF0\x8CĂԁB - } - // About TTSSH \x83_\x83C\x83A\x83\x8D\x83O\x82ł̕\\x8E\xA6\x82̂\xBD\x82߂ɁA\x82\xB1\x82\xB1\x82ŕۑ\xB6\x82\xB5\x82Ă\xA8\x82\xAD\x81B key_copy(&pvar->hosts_state.hostkey, key); @@ -2298,6 +2353,7 @@ // "/nosecuritywarning"\x82\xAA\x8Ew\x92肳\x82\xEA\x82Ă\xA2\x82\xE9\x8Fꍇ\x81A\x83_\x83C\x83A\x83\x8D\x83O\x82\xF0\x95\\x8E\xA6\x82\xB3\x82\xB9\x82\xB8\x82\xC9 return success \x82\xB7\x82\xE9\x81B if (pvar->nocheck_known_hosts == TRUE) { + // \x89\xBD\x82\xE0\x82\xB9\x82\xB8\x82ɖ߂\xE9\x81B return TRUE; } @@ -2318,25 +2374,70 @@ * (2019.9.3 yutaka) */ if (found_different_key) { - HOSTS_do_different_key_dialog(pvar->NotificationWindow, pvar); - //PostMessage(pvar->NotificationWindow, WM_COMMAND, ID_SSHDIFFERENTKEY, 0); + // TTXProcessCommand \x82\xA9\x82\xE7 HOSTS_do_different_key_dialog() \x82\xF0\x8CĂяo\x82\xB7\x81B + id = ID_SSHDIFFERENTKEY; } else if (found_different_type_key) { - HOSTS_do_different_type_key_dialog(pvar->NotificationWindow, pvar); - //PostMessage(pvar->NotificationWindow, WM_COMMAND, ID_SSHDIFFERENT_TYPE_KEY, 0); + // TTXProcessCommand \x82\xA9\x82\xE7 HOSTS_do_different_type_key_dialog() \x82\xF0\x8CĂяo\x82\xB7\x81B + id = ID_SSHDIFFERENT_TYPE_KEY; } else { - // \x82܂\xB8\x82\xCDSSH1\x82̂ݏ\x88\x92u\x81B - if (SSHv1(pvar)) { - PostMessage(pvar->NotificationWindow, WM_COMMAND, ID_SSHUNKNOWNHOST, 0); - } else { - HOSTS_do_unknown_host_dialog(pvar->NotificationWindow, pvar); - } + // TTXProcessCommand \x82\xA9\x82\xE7 HOSTS_do_unknown_host_dialog() \x82\xF0\x8CĂяo\x82\xB7\x81B + id = ID_SSHUNKNOWNHOST; } - return TRUE; + PostMessage(pvar->NotificationWindow, WM_COMMAND, id, 0); + + logprintf(LOG_LEVEL_INFO, "Calling known_hosts dialog...(%s)", + id == ID_SSHDIFFERENTKEY ? "SSHDIFFERENTKEY" : + id == ID_SSHDIFFERENT_TYPE_KEY ? "SSHDIFFERENT_TYPE_KEY" : "SSHUNKNOWNHOST" + ); + + return FALSE; } +/* + * known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82Ń\x86\x81[\x83U\x8F\xB3\x94F\x8C\xE3\x81ASSH\x83T\x81[\x83o\x82Ƃ̃l\x83S\x83V\x83G\x81[\x83V\x83\x87\x83\x93\x82\xF0\x8DĊJ\x82\xB7\x82\xE9\x81B + */ +BOOL HOSTS_resume_session_after_known_hosts(PTInstVar pvar) +{ + enum ssh_kex_known_hosts type; + int ret = FALSE; + + type = pvar->contents_after_known_hosts.kex_type; + if (type == SSH1_PUBLIC_KEY_KNOWN_HOSTS) { + ret = handle_server_public_key_after_known_hosts(pvar); + + } else if (type == SSH2_DH_KEX_REPLY_KNOWN_HOSTS) { + ret = handle_SSH2_dh_kex_reply_after_known_hosts(pvar); + + } else if (type == SSH2_DH_GEX_REPLY_KNOWN_HOSTS) { + ret = handle_SSH2_dh_gex_reply_after_known_hosts(pvar); + + } else if (type == SSH2_ECDH_KEX_REPLY_KNOWN_HOSTS) { + ret = handle_SSH2_ecdh_kex_reply_after_known_hosts(pvar); + + } + + return (ret); +} + +/* + * known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82\xCCSSH\x82\xB2\x82Ƃ̃L\x83\x83\x83\x93\x83Z\x83\x8B\x8F\x88\x97\x9D + */ +void HOSTS_cancel_session_after_known_hosts(PTInstVar pvar) +{ + enum ssh_kex_known_hosts type; + + type = pvar->contents_after_known_hosts.kex_type; + if (type != NONE_KNOWN_HOSTS) { + handle_SSH2_canel_reply_after_known_hosts(pvar); + } + + return; +} + + void HOSTS_notify_disconnecting(PTInstVar pvar) { if (pvar->hosts_state.hosts_dialog != NULL) { Modified: branches/ttssh_improved/ttssh2/ttxssh/ssh.c =================================================================== --- branches/ttssh_improved/ttssh2/ttxssh/ssh.c 2019-09-07 03:34:48 UTC (rev 8080) +++ branches/ttssh_improved/ttssh2/ttxssh/ssh.c 2019-09-07 08:18:20 UTC (rev 8081) @@ -139,6 +139,7 @@ static void ssh2_scp_get_packetlist(Channel_t *c, unsigned char **buf, unsigned int *buflen); static void ssh2_scp_free_packetlist(Channel_t *c); static void get_window_pixel_size(PTInstVar pvar, int *x, int *y); +static BOOL store_contents_for_known_hosts(PTInstVar pvar, enum ssh_kex_known_hosts kex_type, UINT_PTR offset); // \x83}\x83N\x83\x8D #define remained_payload(pvar) ((pvar)->ssh_state.payload + payload_current_offset(pvar)) @@ -1666,6 +1667,9 @@ return FALSE; } +/* + * SSH1\x83T\x81[\x83o\x82\xA9\x82瑗\x82\xE7\x82\xEA\x82Ă\xAB\x82\xBD\x8C\xAE\x82\xF0\x83`\x83F\x83b\x83N\x82\xB5\x82āA\x8DŌ\xE3\x82\xC9known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82\xF0\x95\\x8E\xA6\x82\xB7\x82\xE9\x81B + */ static BOOL handle_server_public_key(PTInstVar pvar) { int server_key_public_exponent_len; @@ -1680,6 +1684,7 @@ char *inmsg; Key hostkey; int supported_types; + int ret; logputs(LOG_LEVEL_VERBOSE, "SSH_SMSG_PUBLIC_KEY was received."); @@ -1744,6 +1749,10 @@ supported_types)) return FALSE; + // \x8C㔼\x8F\x88\x97\x9D\x97p\x82̃f\x81[\x83^\x82\xF0\x91ޔ\xF0\x82\xB5\x82Ă\xA8\x82\xAD + if (store_contents_for_known_hosts(pvar, SSH1_PUBLIC_KEY_KNOWN_HOSTS, 0) == FALSE) + return FALSE; + /* this must be the LAST THING in this function, since it can cause host_is_OK to be called. */ hostkey.type = KEY_RSA1; @@ -1750,11 +1759,31 @@ hostkey.bits = get_uint32(inmsg + host_key_bits_pos); hostkey.exp = inmsg + host_key_bits_pos + 4; hostkey.mod = inmsg + host_key_public_modulus_pos; - HOSTS_check_host_key(pvar, pvar->ssh_state.hostname, pvar->ssh_state.tcpport, &hostkey); + ret = HOSTS_check_host_key(pvar, pvar->ssh_state.hostname, pvar->ssh_state.tcpport, &hostkey); + if (ret == TRUE) { + /* known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82̌Ăяo\x82\xB5\x82͕s\x97v\x82Ȃ̂ŁA + * \x91\xB1\x82\xAB\x82̏\x88\x97\x9D\x82\xF0\x8E\xC0\x8Ds\x82\xB7\x82\xE9\x81B + */ + ret = handle_server_public_key_after_known_hosts(pvar); + + } else { + /* known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82̌Ăяo\x82\xB5\x82\xBD\x82̂ŁA + * \x88ȍ~\x81A\x89\xBD\x82\xE0\x82\xB5\x82Ȃ\xA2\x81B + */ + + } + return FALSE; } +BOOL handle_server_public_key_after_known_hosts(PTInstVar pvar) +{ + SSH_notify_host_OK(pvar); + + return TRUE; +} + /* The ID must have already been found to start with "SSH-". It must be null-terminated. @@ -5833,33 +5862,64 @@ return TRUE; } -// -// Diffie-Hellman Key Exchange Reply(SSH2_MSG_KEXDH_REPLY:31) -// +static BOOL store_contents_for_known_hosts(PTInstVar pvar, enum ssh_kex_known_hosts kex_type, UINT_PTR offset) +{ + pvar->contents_after_known_hosts.payload = malloc(pvar->ssh_state.payloadlen); + if (pvar->contents_after_known_hosts.payload == NULL) + return FALSE; + memcpy(pvar->contents_after_known_hosts.payload, pvar->ssh_state.payload, pvar->ssh_state.payloadlen); + pvar->contents_after_known_hosts.payload_len = pvar->ssh_state.payloadlen; + pvar->contents_after_known_hosts.payload_offset = offset; + + pvar->contents_after_known_hosts.SSH2_MSG_NEWKEYS_received = FALSE; + + // \x8F\xEE\x95Z\x83b\x83g\x82\xB3\x82\xEA\x82Ă\xA2\x82邩\x82ǂ\xA4\x82\xA9\x82̔\xBB\x92\xE8\x82Ɏg\x82\xA4\x82\xBD\x82߁A\x8DŌ\xE3\x82ɐݒ肷\x82\xE9\x81B + pvar->contents_after_known_hosts.kex_type = kex_type; + + return TRUE; +} + +static void clear_contents_for_known_hosts(PTInstVar pvar) +{ + pvar->contents_after_known_hosts.kex_type = NONE_KNOWN_HOSTS; + if (pvar->contents_after_known_hosts.payload) { + free(pvar->contents_after_known_hosts.payload); + pvar->contents_after_known_hosts.payload = NULL; + } + pvar->contents_after_known_hosts.payload_len = 0; + pvar->contents_after_known_hosts.payload_offset = 0; + + /* \x82\xB1\x82\xB1\x82ł͈Ӑ}\x93I\x82ɃN\x83\x8A\x83A\x82\xB5\x82Ȃ\xA2\x81B + * pvar->contents_after_known_hosts.SSH2_MSG_NEWKEYS_received = FALSE; + */ +} + +/* + * Diffie-Hellman Key Exchange Reply(SSH2_MSG_KEXDH_REPLY:31) + * + * known_hosts\x8F\x88\x97\x9D\x82̑O\x94\xBC\x81F + * known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82\xF0\x95\\x8E\xA6\x82\xB7\x82\xE9\x82Ƃ\xB1\x82\xEB\x82܂ŁB + * known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82ł̏\xB3\x94F\x8C\xE3\x82̏\x88\x97\x9D\x82͌㔼\x82ցB + * + * return TRUE: \x90\xAC\x8C\xF7 + * FALSE: \x8E\xB8\x94s + */ static BOOL handle_SSH2_dh_kex_reply(PTInstVar pvar) { char *data; int len; - int offset = 0; char *server_host_key_blob; - int bloblen, siglen; - BIGNUM *server_public = NULL; - char *signature; - int dh_len, share_len; + int bloblen; char *dh_buf = NULL; - BIGNUM *share_key = NULL; - char *hash; char *emsg = NULL, emsg_tmp[1024]; // error message - int hashlen; Key *hostkey = NULL; // hostkey BOOL result = FALSE; + int ret; logputs(LOG_LEVEL_VERBOSE, "SSH2_MSG_KEXDH_REPLY was received."); memset(&hostkey, 0, sizeof(hostkey)); - // TODO: buffer overrun check - // \x83\x81\x83b\x83Z\x81[\x83W\x83^\x83C\x83v\x82̌\xE3\x82ɑ\xB1\x82\xAD\x83y\x83C\x83\x8D\x81[\x83h\x82̐擪 data = pvar->ssh_state.payload; // \x83y\x83C\x83\x8D\x81[\x83h\x82̒\xB7\x82\xB3; \x83\x81\x83b\x83Z\x81[\x83W\x83^\x83C\x83v\x95\xAA\x82\xCC 1 \x83o\x83C\x83g\x82\xF0\x8C\xB8\x82炷 @@ -5891,14 +5951,108 @@ emsg = emsg_tmp; goto error; } - HOSTS_check_host_key(pvar, pvar->ssh_state.hostname, pvar->ssh_state.tcpport, hostkey); - if (pvar->socket == INVALID_SOCKET) { + + // \x8C㔼\x8F\x88\x97\x9D\x97p\x82̃f\x81[\x83^\x82\xF0\x91ޔ\xF0\x82\xB5\x82Ă\xA8\x82\xAD + if (store_contents_for_known_hosts(pvar, SSH2_DH_KEX_REPLY_KNOWN_HOSTS, + (unsigned char *)data - pvar->ssh_state.payload) == FALSE) + goto error; + + /* + * Tera Term(SSH\x83N\x83\x89\x83C\x83A\x83\x93\x83g)\x91\xA4\x82͂\xB1\x82ꂩ\x82\xE7 known_hosts \x82ŃT\x81[\x83o\x82Ƃ̐ڑ\xB1\x82\xF0 + * \x8E\xFC\x82\xEA\x82\xE9\x82̂\xA9\x82\xF0\x8C\x88\x82߂邪\x81ASSH\x83T\x81[\x83o\x91\xA4\x82͂\xB7\x82łɌ\xAE\x82̏\x80\x94\x{142A82}ł\xAB\x82Ă\xA2\x82\xE9\x89\\x90\xAB\x82\xAA\x82\xA0\x82\xE8\x81A + * SSH2_MSG_NEWKEYS \x83\x81\x83b\x83Z\x81[\x83W\x82\xAA\x82\xA2\x82\x97\x82\xE7\x82\xEA\x82Ă\xAD\x82邩\x95\xAA\x82\xA9\x82\xE7\x82Ȃ\xA2\x81B + * known_hosts \x83_\x83C\x83A\x83\x8D\x83O\x95\\x8E\xA6\x92\x86\x82ɂ\xA8\x82\xA2\x82āA\x93\x96\x8AY\x83\x81\x83b\x83Z\x81[\x83W\x82\xF0\x8Et\x82\xAF\x82\xE7\x82\xEA\x82\xE9\x82悤\x82\xC9 + * \x82\xB5\x82Ă\xA8\x82\xAD\x95K\x97v\x82\xAA\x82\xA0\x82\xE9\x81B + */ + SSH2_dispatch_init(3); + SSH2_dispatch_add_message(SSH2_MSG_NEWKEYS); + + /* + * \x82\xB1\x82̂\xA0\x82\xC6 known_hosts \x83_\x83C\x83A\x83\x8D\x83O\x82\xF0\x94\xFA\x82ŌĂяo\x82\xB5\x81A\x82\xA2\x82\xC1\x82\xBD\x82\xF1SSH\x83T\x81[\x83o\x82Ƃ\xCC + * \x83l\x83S\x83V\x83G\x81[\x83V\x83\x87\x83\x93\x82\xF0\x88ꎞ\x92\xE2\x8E~\x82\xB3\x82\xB9\x82\xE9\x81B + */ + ret = HOSTS_check_host_key(pvar, pvar->ssh_state.hostname, pvar->ssh_state.tcpport, hostkey); + if (ret == TRUE) { + /* known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82̌Ăяo\x82\xB5\x82͕s\x97v\x82Ȃ̂ŁA + * \x91\xB1\x82\xAB\x82̏\x88\x97\x9D\x82\xF0\x8E\xC0\x8Ds\x82\xB7\x82\xE9\x81B + */ + ret = handle_SSH2_dh_kex_reply_after_known_hosts(pvar); + + } else { + /* known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82̌Ăяo\x82\xB5\x82\xBD\x82̂ŁA + * \x88ȍ~\x81A\x89\xBD\x82\xE0\x82\xB5\x82Ȃ\xA2\x81B + */ + + } + + result = TRUE; + +error: + key_free(hostkey); + + if (emsg) + notify_fatal_error(pvar, emsg, TRUE); + + return result; +} + +/* + * Diffie-Hellman Key Exchange Reply(SSH2_MSG_KEXDH_REPLY:31) + * + * known_hosts\x8F\x88\x97\x9D\x82̌㔼\x81F + * known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82\xA9\x82\xE7\x8CĂяo\x82\xB3\x82\xEA\x81ASSH\x83T\x81[\x83o\x82ɃL\x81[\x8F\xEE\x95\xF1\x82𑗐M\x82\xB7\x82\xE9\x81B + * + * return TRUE: \x90\xAC\x8C\xF7 + * FALSE: \x8E\xB8\x94s + */ +BOOL handle_SSH2_dh_kex_reply_after_known_hosts(PTInstVar pvar) +{ + char *data; + int len; + int offset = 0; + char *server_host_key_blob; + int bloblen, siglen; + BIGNUM *server_public = NULL; + char *signature; + int dh_len, share_len; + char *dh_buf = NULL; + BIGNUM *share_key = NULL; + char *hash; + char *emsg = NULL, emsg_tmp[1024]; // error message + int hashlen; + Key *hostkey = NULL; // hostkey + BOOL result = FALSE; + + logputs(LOG_LEVEL_VERBOSE, "SSH2_MSG_KEXDH_REPLY is continued after known_hosts."); + + memset(&hostkey, 0, sizeof(hostkey)); + + // \x83\x81\x83b\x83Z\x81[\x83W\x83^\x83C\x83v\x82̌\xE3\x82ɑ\xB1\x82\xAD\x83y\x83C\x83\x8D\x81[\x83h\x82̐擪 + data = pvar->contents_after_known_hosts.payload; + // \x83y\x83C\x83\x8D\x81[\x83h\x82̒\xB7\x82\xB3; \x83\x81\x83b\x83Z\x81[\x83W\x83^\x83C\x83v\x95\xAA\x82\xCC 1 \x83o\x83C\x83g\x82\xF0\x8C\xB8\x82炷 + len = pvar->contents_after_known_hosts.payload_len - 1; + + bloblen = get_uint32_MSBfirst(data); + data += 4; + server_host_key_blob = data; // for hash + + hostkey = key_from_blob(data, bloblen); + if (hostkey == NULL) { _snprintf_s(emsg_tmp, sizeof(emsg_tmp), _TRUNCATE, - "%s: Server disconnected", __FUNCTION__); + "%s: key_from_blob error", __FUNCTION__); emsg = emsg_tmp; goto error; } + data += bloblen; + if (hostkey->type != pvar->hostkey_type) { // \x83z\x83X\x83g\x83L\x81[\x82̎\xED\x95ʔ\xE4\x8Ar + _snprintf_s(emsg_tmp, sizeof(emsg_tmp), _TRUNCATE, + "%s: type mismatch for decoded server_host_key_blob (kex:%s blob:%s)", /*__FUNCTION__*/"handle_SSH2_dh_kex_reply", + get_ssh_keytype_name(pvar->hostkey_type), get_ssh_keytype_name(hostkey->type)); + emsg = emsg_tmp; + goto error; + } + server_public = BN_new(); if (server_public == NULL) { _snprintf_s(emsg_tmp, sizeof(emsg_tmp), _TRUNCATE, @@ -5984,17 +6138,139 @@ if (emsg) notify_fatal_error(pvar, emsg, TRUE); + clear_contents_for_known_hosts(pvar); + + /* + * SSH2_MSG_NEWKEYS \x82\xF0\x8E\xF3\x90M\x82\xB5\x82Ă\xA2\x82\xBD\x82\xE7\x81A\x8E\xA9\x95\xAA\x82ŏ\x88\x97\x9D\x82\xF0\x8CĂяo\x82\xB7\x81B + */ + if (pvar->contents_after_known_hosts.SSH2_MSG_NEWKEYS_received) { + pvar->contents_after_known_hosts.SSH2_MSG_NEWKEYS_received = FALSE; + handle_SSH2_newkeys(pvar); + } + return result; } +void handle_SSH2_canel_reply_after_known_hosts(PTInstVar pvar) +{ + clear_contents_for_known_hosts(pvar); +} -// -// Diffie-Hellman Group and Key Exchange Reply(SSH2_MSG_KEX_DH_GEX_REPLY:33) -// +/* + * Diffie-Hellman Group and Key Exchange Reply(SSH2_MSG_KEX_DH_GEX_REPLY:33) + * + * known_hosts\x8F\x88\x97\x9D\x82̑O\x94\xBC\x81F + * known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82\xF0\x95\\x8E\xA6\x82\xB7\x82\xE9\x82Ƃ\xB1\x82\xEB\x82܂ŁB + * known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82ł̏\xB3\x94F\x8C\xE3\x82̏\x88\x97\x9D\x82͌㔼\x82ցB + * + * return TRUE: \x90\xAC\x8C\xF7 + * FALSE: \x8E\xB8\x94s + */ static BOOL handle_SSH2_dh_gex_reply(PTInstVar pvar) { char *data; int len; + char *server_host_key_blob; + int bloblen; + char *dh_buf = NULL; + char *emsg = NULL, emsg_tmp[1024]; // error message + Key *hostkey = NULL; // hostkey + BOOL result = FALSE; + int ret; + + logputs(LOG_LEVEL_VERBOSE, "SSH2_MSG_KEX_DH_GEX_REPLY was received."); + + memset(&hostkey, 0, sizeof(hostkey)); + + // \x83\x81\x83b\x83Z\x81[\x83W\x83^\x83C\x83v\x82̌\xE3\x82ɑ\xB1\x82\xAD\x83y\x83C\x83\x8D\x81[\x83h\x82̐擪 + data = pvar->ssh_state.payload; + // \x83y\x83C\x83\x8D\x81[\x83h\x82̒\xB7\x82\xB3; \x83\x81\x83b\x83Z\x81[\x83W\x83^\x83C\x83v\x95\xAA\x82\xCC 1 \x83o\x83C\x83g\x82\xF0\x8C\xB8\x82炷 + len = pvar->ssh_state.payloadlen - 1; + + // for debug + push_memdump("DH_GEX_REPLY", "key exchange: receiving", data, len); + + bloblen = get_uint32_MSBfirst(data); + data += 4; + server_host_key_blob = data; // for hash + + push_memdump("DH_GEX_REPLY", "server_host_key_blob", server_host_key_blob, bloblen); + + hostkey = key_from_blob(data, bloblen); + if (hostkey == NULL) { + _snprintf_s(emsg_tmp, sizeof(emsg_tmp), _TRUNCATE, + "%s: key_from_blob error", __FUNCTION__); + emsg = emsg_tmp; + goto error; + } + data += bloblen; + + // known_hosts\x91Ή\x9E (2006.3.20 yutaka) + if (hostkey->type != pvar->hostkey_type) { // \x83z\x83X\x83g\x83L\x81[\x82̎\xED\x95ʔ\xE4\x8Ar + _snprintf_s(emsg_tmp, sizeof(emsg_tmp), _TRUNCATE, + "%s: type mismatch for decoded server_host_key_blob (kex:%s blob:%s)", /*__FUNCTION__*/"handle_SSH2_dh_gex_reply", + get_ssh_keytype_name(pvar->hostkey_type), get_ssh_keytype_name(hostkey->type)); + emsg = emsg_tmp; + goto error; + } + + // \x8C㔼\x8F\x88\x97\x9D\x97p\x82̃f\x81[\x83^\x82\xF0\x91ޔ\xF0\x82\xB5\x82Ă\xA8\x82\xAD + if (store_contents_for_known_hosts(pvar, SSH2_DH_GEX_REPLY_KNOWN_HOSTS, + (unsigned char *)data - pvar->ssh_state.payload) == FALSE) + goto error; + + /* + * Tera Term(SSH\x83N\x83\x89\x83C\x83A\x83\x93\x83g)\x91\xA4\x82͂\xB1\x82ꂩ\x82\xE7 known_hosts \x82ŃT\x81[\x83o\x82Ƃ̐ڑ\xB1\x82\xF0 + * \x8E\xFC\x82\xEA\x82\xE9\x82̂\xA9\x82\xF0\x8C\x88\x82߂邪\x81ASSH\x83T\x81[\x83o\x91\xA4\x82͂\xB7\x82łɌ\xAE\x82̏\x80\x94\x{142A82}ł\xAB\x82Ă\xA2\x82\xE9\x89\\x90\xAB\x82\xAA\x82\xA0\x82\xE8\x81A + * SSH2_MSG_NEWKEYS \x83\x81\x83b\x83Z\x81[\x83W\x82\xAA\x82\xA2\x82\x97\x82\xE7\x82\xEA\x82Ă\xAD\x82邩\x95\xAA\x82\xA9\x82\xE7\x82Ȃ\xA2\x81B + * known_hosts \x83_\x83C\x83A\x83\x8D\x83O\x95\\x8E\xA6\x92\x86\x82ɂ\xA8\x82\xA2\x82āA\x93\x96\x8AY\x83\x81\x83b\x83Z\x81[\x83W\x82\xF0\x8Et\x82\xAF\x82\xE7\x82\xEA\x82\xE9\x82悤\x82\xC9 + * \x82\xB5\x82Ă\xA8\x82\xAD\x95K\x97v\x82\xAA\x82\xA0\x82\xE9\x81B + */ + SSH2_dispatch_init(3); + SSH2_dispatch_add_message(SSH2_MSG_NEWKEYS); + + /* + * \x82\xB1\x82̂\xA0\x82\xC6 known_hosts \x83_\x83C\x83A\x83\x8D\x83O\x82\xF0\x94\xFA\x82ŌĂяo\x82\xB5\x81A\x82\xA2\x82\xC1\x82\xBD\x82\xF1SSH\x83T\x81[\x83o\x82Ƃ\xCC + * \x83l\x83S\x83V\x83G\x81[\x83V\x83\x87\x83\x93\x82\xF0\x88ꎞ\x92\xE2\x8E~\x82\xB3\x82\xB9\x82\xE9\x81B + */ + ret = HOSTS_check_host_key(pvar, pvar->ssh_state.hostname, pvar->ssh_state.tcpport, hostkey); + if (ret == TRUE) { + /* known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82̌Ăяo\x82\xB5\x82͕s\x97v\x82Ȃ̂ŁA + * \x91\xB1\x82\xAB\x82̏\x88\x97\x9D\x82\xF0\x8E\xC0\x8Ds\x82\xB7\x82\xE9\x81B + */ + ret = handle_SSH2_dh_gex_reply_after_known_hosts(pvar); + + } else { + /* known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82̌Ăяo\x82\xB5\x82\xBD\x82̂ŁA + * \x88ȍ~\x81A\x89\xBD\x82\xE0\x82\xB5\x82Ȃ\xA2\x81B + */ + + } + + result = TRUE; + +error: + key_free(hostkey); + + if (emsg) + notify_fatal_error(pvar, emsg, TRUE); + + return result; +} + +/* + * Diffie-Hellman Group and Key Exchange Reply(SSH2_MSG_KEX_DH_GEX_REPLY:33) + * + * known_hosts\x8F\x88\x97\x9D\x82̌㔼\x81F + * known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82\xA9\x82\xE7\x8CĂяo\x82\xB3\x82\xEA\x81ASSH\x83T\x81[\x83o\x82ɃL\x81[\x8F\xEE\x95\xF1\x82𑗐M\x82\xB7\x82\xE9\x81B + * + * return TRUE: \x90\xAC\x8C\xF7 + * FALSE: \x8E\xB8\x94s + */ +BOOL handle_SSH2_dh_gex_reply_after_known_hosts(PTInstVar pvar) +{ + char *data; + int len; int offset = 0; char *server_host_key_blob; int bloblen, siglen; @@ -6009,16 +6285,14 @@ Key *hostkey = NULL; // hostkey BOOL result = FALSE; - logputs(LOG_LEVEL_VERBOSE, "SSH2_MSG_KEX_DH_GEX_REPLY was received."); + logputs(LOG_LEVEL_VERBOSE, "SSH2_MSG_KEX_DH_GEX_REPLY is continued after known_hosts."); memset(&hostkey, 0, sizeof(hostkey)); - // TODO: buffer overrun check - // \x83\x81\x83b\x83Z\x81[\x83W\x83^\x83C\x83v\x82̌\xE3\x82ɑ\xB1\x82\xAD\x83y\x83C\x83\x8D\x81[\x83h\x82̐擪 - data = pvar->ssh_state.payload; + data = pvar->contents_after_known_hosts.payload; // \x83y\x83C\x83\x8D\x81[\x83h\x82̒\xB7\x82\xB3; \x83\x81\x83b\x83Z\x81[\x83W\x83^\x83C\x83v\x95\xAA\x82\xCC 1 \x83o\x83C\x83g\x82\xF0\x8C\xB8\x82炷 - len = pvar->ssh_state.payloadlen - 1; + len = pvar->contents_after_known_hosts.payload_len - 1; // for debug push_memdump("DH_GEX_REPLY", "key exchange: receiving", data, len); @@ -6046,13 +6320,6 @@ emsg = emsg_tmp; goto error; } - HOSTS_check_host_key(pvar, pvar->ssh_state.hostname, pvar->ssh_state.tcpport, hostkey); - if (pvar->socket == INVALID_SOCKET) { - _snprintf_s(emsg_tmp, sizeof(emsg_tmp), _TRUNCATE, - "%s: Server disconnected", __FUNCTION__); - emsg = emsg_tmp; - goto error; - } server_public = BN_new(); if (server_public == NULL) { @@ -6144,17 +6411,134 @@ if (emsg) notify_fatal_error(pvar, emsg, TRUE); + clear_contents_for_known_hosts(pvar); + + /* + * SSH2_MSG_NEWKEYS \x82\xF0\x8E\xF3\x90M\x82\xB5\x82Ă\xA2\x82\xBD\x82\xE7\x81A\x8E\xA9\x95\xAA\x82ŏ\x88\x97\x9D\x82\xF0\x8CĂяo\x82\xB7\x81B + */ + if (pvar->contents_after_known_hosts.SSH2_MSG_NEWKEYS_received) { + pvar->contents_after_known_hosts.SSH2_MSG_NEWKEYS_received = FALSE; + handle_SSH2_newkeys(pvar); + } + return result; } -// -// Elliptic Curve Diffie-Hellman Key Exchange Reply(SSH2_MSG_KEX_ECDH_REPLY:31) -// +/* + * Elliptic Curve Diffie-Hellman Key Exchange Reply(SSH2_MSG_KEX_ECDH_REPLY:31) + * + * known_hosts\x8F\x88\x97\x9D\x82̑O\x94\xBC\x81F + * known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82\xF0\x95\\x8E\xA6\x82\xB7\x82\xE9\x82Ƃ\xB1\x82\xEB\x82܂ŁB + * known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82ł̏\xB3\x94F\x8C\xE3\x82̏\x88\x97\x9D\x82͌㔼\x82ցB + * + * return TRUE: \x90\xAC\x8C\xF7 + * FALSE: \x8E\xB8\x94s + */ static BOOL handle_SSH2_ecdh_kex_reply(PTInstVar pvar) { char *data; int len; + char *server_host_key_blob; + int bloblen; + char *emsg = NULL, emsg_tmp[1024]; // error message + Key *hostkey = NULL; // hostkey + BOOL result = FALSE; + int ret; + + logputs(LOG_LEVEL_VERBOSE, "SSH2_MSG_KEX_ECDH_REPLY was received."); + + memset(&hostkey, 0, sizeof(hostkey)); + + // \x83\x81\x83b\x83Z\x81[\x83W\x83^\x83C\x83v\x82̌\xE3\x82ɑ\xB1\x82\xAD\x83y\x83C\x83\x8D\x81[\x83h\x82̐擪 + data = pvar->ssh_state.payload; + // \x83y\x83C\x83\x8D\x81[\x83h\x82̒\xB7\x82\xB3; \x83\x81\x83b\x83Z\x81[\x83W\x83^\x83C\x83v\x95\xAA\x82\xCC 1 \x83o\x83C\x83g\x82\xF0\x8C\xB8\x82炷 + len = pvar->ssh_state.payloadlen - 1; + + // for debug + push_memdump("KEX_ECDH_REPLY", "key exchange: receiving", data, len); + + bloblen = get_uint32_MSBfirst(data); + data += 4; + server_host_key_blob = data; // for hash + + push_memdump("KEX_ECDH_REPLY", "server_host_key_blob", server_host_key_blob, bloblen); + + hostkey = key_from_blob(data, bloblen); + if (hostkey == NULL) { + _snprintf_s(emsg_tmp, sizeof(emsg_tmp), _TRUNCATE, + "%s: key_from_blob error", __FUNCTION__); + emsg = emsg_tmp; + goto error; + } + data += bloblen; + + // known_hosts\x91Ή\x9E (2006.3.20 yutaka) + if (hostkey->type != pvar->hostkey_type) { // \x83z\x83X\x83g\x83L\x81[\x82̎\xED\x95ʔ\xE4\x8Ar + _snprintf_s(emsg_tmp, sizeof(emsg_tmp), _TRUNCATE, + "%s: type mismatch for decoded server_host_key_blob (kex:%s blob:%s)", /*__FUNCTION__*/"handle_SSH2_ecdh_kex_reply", + get_ssh_keytype_name(pvar->hostkey_type), get_ssh_keytype_name(hostkey->type)); + emsg = emsg_tmp; + goto error; + } + + // \x8C㔼\x8F\x88\x97\x9D\x97p\x82̃f\x81[\x83^\x82\xF0\x91ޔ\xF0\x82\xB5\x82Ă\xA8\x82\xAD + if (store_contents_for_known_hosts(pvar, SSH2_ECDH_KEX_REPLY_KNOWN_HOSTS, + (unsigned char *)data - pvar->ssh_state.payload) == FALSE) + goto error; + + /* + * Tera Term(SSH\x83N\x83\x89\x83C\x83A\x83\x93\x83g)\x91\xA4\x82͂\xB1\x82ꂩ\x82\xE7 known_hosts \x82ŃT\x81[\x83o\x82Ƃ̐ڑ\xB1\x82\xF0 + * \x8E\xFC\x82\xEA\x82\xE9\x82̂\xA9\x82\xF0\x8C\x88\x82߂邪\x81ASSH\x83T\x81[\x83o\x91\xA4\x82͂\xB7\x82łɌ\xAE\x82̏\x80\x94\x{142A82}ł\xAB\x82Ă\xA2\x82\xE9\x89\\x90\xAB\x82\xAA\x82\xA0\x82\xE8\x81A + * SSH2_MSG_NEWKEYS \x83\x81\x83b\x83Z\x81[\x83W\x82\xAA\x82\xA2\x82\x97\x82\xE7\x82\xEA\x82Ă\xAD\x82邩\x95\xAA\x82\xA9\x82\xE7\x82Ȃ\xA2\x81B + * known_hosts \x83_\x83C\x83A\x83\x8D\x83O\x95\\x8E\xA6\x92\x86\x82ɂ\xA8\x82\xA2\x82āA\x93\x96\x8AY\x83\x81\x83b\x83Z\x81[\x83W\x82\xF0\x8Et\x82\xAF\x82\xE7\x82\xEA\x82\xE9\x82悤\x82\xC9 + * \x82\xB5\x82Ă\xA8\x82\xAD\x95K\x97v\x82\xAA\x82\xA0\x82\xE9\x81B + */ + SSH2_dispatch_init(3); + SSH2_dispatch_add_message(SSH2_MSG_NEWKEYS); + + /* + * \x82\xB1\x82̂\xA0\x82\xC6 known_hosts \x83_\x83C\x83A\x83\x8D\x83O\x82\xF0\x94\xFA\x82ŌĂяo\x82\xB5\x81A\x82\xA2\x82\xC1\x82\xBD\x82\xF1SSH\x83T\x81[\x83o\x82Ƃ\xCC + * \x83l\x83S\x83V\x83G\x81[\x83V\x83\x87\x83\x93\x82\xF0\x88ꎞ\x92\xE2\x8E~\x82\xB3\x82\xB9\x82\xE9\x81B + */ + ret = HOSTS_check_host_key(pvar, pvar->ssh_state.hostname, pvar->ssh_state.tcpport, hostkey); + if (ret == TRUE) { + /* known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82̌Ăяo\x82\xB5\x82͕s\x97v\x82Ȃ̂ŁA + * \x91\xB1\x82\xAB\x82̏\x88\x97\x9D\x82\xF0\x8E\xC0\x8Ds\x82\xB7\x82\xE9\x81B + */ + ret = handle_SSH2_ecdh_kex_reply_after_known_hosts(pvar); + + } else { + /* known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82̌Ăяo\x82\xB5\x82\xBD\x82̂ŁA + * \x88ȍ~\x81A\x89\xBD\x82\xE0\x82\xB5\x82Ȃ\xA2\x81B + */ + + } + + result = TRUE; + +error: + key_free(hostkey); + + if (emsg) + notify_fatal_error(pvar, emsg, TRUE); + + return result; +} + +/* + * Elliptic Curve Diffie-Hellman Key Exchange Reply(SSH2_MSG_KEX_ECDH_REPLY:31) + * + * known_hosts\x8F\x88\x97\x9D\x82̌㔼\x81F + * known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82\xA9\x82\xE7\x8CĂяo\x82\xB3\x82\xEA\x81ASSH\x83T\x81[\x83o\x82ɃL\x81[\x8F\xEE\x95\xF1\x82𑗐M\x82\xB7\x82\xE9\x81B + * + * return TRUE: \x90\xAC\x8C\xF7 + * FALSE: \x8E\xB8\x94s + */ +BOOL handle_SSH2_ecdh_kex_reply_after_known_hosts(PTInstVar pvar) +{ + char *data; + int len; int offset = 0; char *server_host_key_blob; int bloblen, siglen; @@ -6170,16 +6554,14 @@ Key *hostkey = NULL; // hostkey BOOL result = FALSE; - logputs(LOG_LEVEL_VERBOSE, "SSH2_MSG_KEX_ECDH_REPLY was received."); + logputs(LOG_LEVEL_VERBOSE, "SSH2_MSG_KEX_ECDH_REPLY is continued after known_hosts."); memset(&hostkey, 0, sizeof(hostkey)); - // TODO: buffer overrun check - // \x83\x81\x83b\x83Z\x81[\x83W\x83^\x83C\x83v\x82̌\xE3\x82ɑ\xB1\x82\xAD\x83y\x83C\x83\x8D\x81[\x83h\x82̐擪 - data = pvar->ssh_state.payload; + data = pvar->contents_after_known_hosts.payload; // \x83y\x83C\x83\x8D\x81[\x83h\x82̒\xB7\x82\xB3; \x83\x81\x83b\x83Z\x81[\x83W\x83^\x83C\x83v\x95\xAA\x82\xCC 1 \x83o\x83C\x83g\x82\xF0\x8C\xB8\x82炷 - len = pvar->ssh_state.payloadlen - 1; + len = pvar->contents_after_known_hosts.payload_len - 1; // for debug push_memdump("KEX_ECDH_REPLY", "key exchange: receiving", data, len); @@ -6207,13 +6589,6 @@ emsg = emsg_tmp; goto error; } - HOSTS_check_host_key(pvar, pvar->ssh_state.hostname, pvar->ssh_state.tcpport, hostkey); - if (pvar->socket == INVALID_SOCKET) { - _snprintf_s(emsg_tmp, sizeof(emsg_tmp), _TRUNCATE, - "%s: Server disconnected", __FUNCTION__); - emsg = emsg_tmp; - goto error; - } /* Q_S, server public key */ group = EC_KEY_get0_group(pvar->ecdh_client_key); @@ -6323,10 +6698,21 @@ if (emsg) notify_fatal_error(pvar, emsg, TRUE); + clear_contents_for_known_hosts(pvar); + + /* + * SSH2_MSG_NEWKEYS \x82\xF0\x8E\xF3\x90M\x82\xB5\x82Ă\xA2\x82\xBD\x82\xE7\x81A\x8E\xA9\x95\xAA\x82ŏ\x88\x97\x9D\x82\xF0\x8CĂяo\x82\xB7\x81B + */ + if (pvar->contents_after_known_hosts.SSH2_MSG_NEWKEYS_received) { + pvar->contents_after_known_hosts.SSH2_MSG_NEWKEYS_received = FALSE; + handle_SSH2_newkeys(pvar); + } + return result; } + // KEX\x82ɂ\xA8\x82\xA2\x82ăT\x81[\x83o\x82\xA9\x82\xE7\x95Ԃ\xC1\x82Ă\xAD\x82\xE9 31 \x94ԃ\x81\x83b\x83Z\x81[\x83W\x82ɑ\xB7\x82\xE9\x83n\x83\x93\x83h\x83\x89 static BOOL handle_SSH2_dh_common_reply(PTInstVar pvar) { @@ -6396,6 +6782,17 @@ int type = (1 << SSH_AUTH_PASSWORD) | (1 << SSH_AUTH_RSA) | (1 << SSH_AUTH_TIS) | (1 << SSH_AUTH_PAGEANT); + + /* + * known_hosts\x83_\x83C\x83A\x83\x8D\x83O\x95\\x8E\xA6\x92\x86\x82\xC9 SSH2_MSG_NEWKEYS \x82\xF0\x8E\xE6\x82\xC1\x82\xBD\x8Fꍇ\x82\xCD + * \x8F\x88\x97\x9D\x82\xF0\x89\x84\x8A\x{20B30B9}\x82\xE9\x81B + */ + if (pvar->contents_after_known_hosts.kex_type != NONE_KNOWN_HOSTS) { + pvar->contents_after_known_hosts.SSH2_MSG_NEWKEYS_received = TRUE; + logputs(LOG_LEVEL_VERBOSE, "SSH2_MSG_NEWKEYS was postponed while known_hosts dialog is running."); + return TRUE; + } + logputs(LOG_LEVEL_VERBOSE, "SSH2_MSG_NEWKEYS was received(DH key generation is completed)."); // \x83\x8D\x83O\x8D̎\xE6\x82̏I\x97\xB9 (2005.3.7 yutaka) Modified: branches/ttssh_improved/ttssh2/ttxssh/ssh.h =================================================================== --- branches/ttssh_improved/ttssh2/ttxssh/ssh.h 2019-09-07 03:34:48 UTC (rev 8080) +++ branches/ttssh_improved/ttssh2/ttxssh/ssh.h 2019-09-07 08:18:20 UTC (rev 8081) @@ -915,4 +915,32 @@ int ref_count; }; +/* + * SSH bottom half after known_hosts + */ +enum ssh_kex_known_hosts { + NONE_KNOWN_HOSTS = 0, + SSH1_PUBLIC_KEY_KNOWN_HOSTS, + SSH2_DH_KEX_REPLY_KNOWN_HOSTS, + SSH2_DH_GEX_REPLY_KNOWN_HOSTS, + SSH2_ECDH_KEX_REPLY_KNOWN_HOSTS, +}; + +typedef struct bottom_half_known_hosts { + enum ssh_kex_known_hosts kex_type; + + unsigned char *payload; + int payload_len; + UINT_PTR payload_offset; + + BOOL SSH2_MSG_NEWKEYS_received; +} bottom_half_known_hosts_t; + +void handle_SSH2_canel_reply_after_known_hosts(PTInstVar pvar); + +BOOL handle_server_public_key_after_known_hosts(PTInstVar pvar); +BOOL handle_SSH2_dh_kex_reply_after_known_hosts(PTInstVar pvar); +BOOL handle_SSH2_dh_gex_reply_after_known_hosts(PTInstVar pvar); +BOOL handle_SSH2_ecdh_kex_reply_after_known_hosts(PTInstVar pvar); + #endif Modified: branches/ttssh_improved/ttssh2/ttxssh/ttxssh.c =================================================================== --- branches/ttssh_improved/ttssh2/ttxssh/ttxssh.c 2019-09-07 03:34:48 UTC (rev 8080) +++ branches/ttssh_improved/ttssh2/ttxssh/ttxssh.c 2019-09-07 08:18:20 UTC (rev 8081) @@ -136,6 +136,14 @@ pvar->protocol_major = 0; pvar->protocol_minor = 0; + /* + * pvar->contents_after_known_hosts \x82͈Ӑ}\x93I\x82\xC9 + * init_TTSSH()\x82\xE2uninit_TTSSH()\x82ł͏\x89\x8A\xFA\x89\xBB\x82\xE2\x89\xF0\x95\xFA\x82\xF0\x82\xB5\x82Ȃ\xA2\x81B + * \x82Ȃ\xBA\x82Ȃ\xE7\x82Aknown_hosts\x83_\x83C\x83A\x83\x8D\x83O\x82Ŏg\x97p\x82\xB7\x82邽\x82߂ł\xA0\x82\xE8\x81A + * \x83_\x83C\x83A\x83\x8D\x83O\x82̕\\x8E\xA6\x92\x86\x82\xC9 TTXCloseTCP() \x82\xAA\x8CĂяo\x82\xB3\x82\xEA\x82邱\x82Ƃɂ\xE6\x82\xE8\x81A + * pvar->contents_after_known_hosts \x82\xAA\x8F\x89\x8A\xFA\x89\xBB\x82\xE2\x89\xF0\x95\xFA\x82\xB3\x82\xEA\x82Ă͍\xA2\x82邩\x82\xE7\x82ł\xA0\x82\xE9\x81B + */ + PKT_init(pvar); SSH_init(pvar); CRYPT_init(pvar); Modified: branches/ttssh_improved/ttssh2/ttxssh/ttxssh.h =================================================================== --- branches/ttssh_improved/ttssh2/ttxssh/ttxssh.h 2019-09-07 03:34:48 UTC (rev 8080) +++ branches/ttssh_improved/ttssh2/ttxssh/ttxssh.h 2019-09-07 08:18:20 UTC (rev 8081) @@ -343,6 +343,8 @@ // dialog resource HFONT hFontFixed; // hosts.c\x93\xE0\x82̃_\x83C\x83A\x83\x8D\x83O\x97p + bottom_half_known_hosts_t contents_after_known_hosts; + } TInstVar; // \x83o\x81[\x83W\x83\x87\x83\x93\x82ɍ\x87\x82킹\x82Ď\xA9\x93\xAE\x95ύX\x82\xB3\x82\xEA\x82\xE9\x81B \x97\xE1: TTSSH_2-81_TS_data