[Ttssh2-commit] [8081] known_hostsダイアログが表示されている状態で、サーバから切断を行うと、

Back to archive index
scmno****@osdn***** scmno****@osdn*****
2019年 9月 7日 (土) 17:18:20 JST


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\x95񂪃Z\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\x8E󂯕t\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\x8E󂯕t\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\x8E󂯕t\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\x82΁Aknown_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


Ttssh2-commit メーリングリストの案内
Back to archive index