[Ttssh2-commit] [4531] RFC 4255 "Using DNS to Securely Publish Secure Shell (SSH) Key Fingerprints" 対応の準備

アーカイブの一覧に戻る

svnno****@sourc***** svnno****@sourc*****
2011年 7月 26日 (火) 17:50:11 JST


Revision: 4531
          http://sourceforge.jp/projects/ttssh2/svn/view?view=rev&revision=4531
Author:   doda
Date:     2011-07-26 17:50:11 +0900 (Tue, 26 Jul 2011)

Log Message:
-----------
RFC 4255 "Using DNS to Securely Publish Secure Shell (SSH) Key Fingerprints" 対応の準備
http://tools.ietf.org/html/rfc4255

VerifyHostKeyDNS = 1 にすると、ホスト鍵の検証を行う。
検証するだけで検証結果は使ってないけれど。

DNSSEC 未対応の問題が有るので、その部分について検討中。
解決する目途が立っていないので、もしかするとお蔵入りするかも。

Windows95/98/Me/NT4 では動かないかも。

Modified Paths:
--------------
    trunk/ttssh2/ttxssh/hosts.c
    trunk/ttssh2/ttxssh/key.c
    trunk/ttssh2/ttxssh/key.h
    trunk/ttssh2/ttxssh/ssh.h
    trunk/ttssh2/ttxssh/ttxssh.c
    trunk/ttssh2/ttxssh/ttxssh.h
    trunk/ttssh2/ttxssh/ttxssh.vcproj


-------------- next part --------------
Modified: trunk/ttssh2/ttxssh/hosts.c
===================================================================
--- trunk/ttssh2/ttxssh/hosts.c	2011-07-26 08:18:19 UTC (rev 4530)
+++ trunk/ttssh2/ttxssh/hosts.c	2011-07-26 08:50:11 UTC (rev 4531)
@@ -49,7 +49,10 @@
 #include <errno.h>
 #include <sys/stat.h>
 #include <direct.h>
+#include <memory.h>
 
+#include <windns.h>
+
 static HFONT DlgHostsAddFont;
 static HFONT DlgHostsReplaceFont;
 
@@ -128,12 +131,7 @@
 void HOSTS_init(PTInstVar pvar)
 {
 	pvar->hosts_state.prefetched_hostname = NULL;
-#if 0
-	pvar->hosts_state.key_exp = NULL;
-	pvar->hosts_state.key_mod = NULL;
-#else
 	init_hostkey(&pvar->hosts_state.hostkey);
-#endif
 	pvar->hosts_state.hosts_dialog = NULL;
 	pvar->hosts_state.file_names = NULL;
 }
@@ -693,16 +691,8 @@
 		return 0;
 	}
 
-#if 0
-	pvar->hosts_state.key_bits = 0;
-	free(pvar->hosts_state.key_exp);
-	pvar->hosts_state.key_exp = NULL;
-	free(pvar->hosts_state.key_mod);
-	pvar->hosts_state.key_mod = NULL;
-#else
 	// hostkey type is KEY_UNSPEC.
 	init_hostkey(&pvar->hosts_state.hostkey);
-#endif
 
 	do {
 		if (pvar->hosts_state.file_data == NULL
@@ -1631,6 +1621,107 @@
 	}
 }
 
+int is_numeric_hostname(const char *hostname)
+{
+	struct addrinfo hints, *ai;
+
+	if (hostname == NULL) {
+		return -1;
+	}
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_socktype = SOCK_DGRAM;
+	hints.ai_flags = AI_NUMERICHOST;
+
+	if (getaddrinfo(hostname, NULL, &hints, &ai) == 0) {
+		freeaddrinfo(ai);
+		return 1;
+	}
+
+	return 0;
+}
+
+#define DNS_TYPE_SSHFP	44
+typedef struct {
+	BYTE Algorithm;
+	BYTE DigestType;
+	BYTE Digest[1];
+} DNS_SSHFP_DATA, *PDNS_SSHFP_DATA;
+enum verifydns_result {
+	DNS_VERIFY_NONE,
+	DNS_VERIFY_MATCH,
+	DNS_VERIFY_MISMATCH,
+	DNS_VERIFY_DIFFERENTTYPE,
+	DNS_VERIFY_AUTH_MATCH,
+	DNS_VERIFY_AUTH_MISMATCH,
+	DNS_VERIFY_AUTH_DIFFERENTTYPE
+};
+
+int verify_hostkey_dns(char FAR *hostname, Key *key)
+{
+	DNS_STATUS status;
+	PDNS_RECORD rec, p;
+	PDNS_SSHFP_DATA t;
+	int hostkey_alg, hostkey_dtype, hostkey_dlen;
+	BYTE *hostkey_digest;
+	int found = DNS_VERIFY_NONE;
+	char buff[1024];
+
+	switch (key->type) {
+	case KEY_RSA:
+		hostkey_alg = SSHFP_KEY_RSA;
+		break;
+	case KEY_DSA:
+		hostkey_alg = SSHFP_KEY_DSA;
+		break;
+	// XXX KEY_ECDSA
+	default: // Un-supported algorighm
+		hostkey_alg = SSHFP_KEY_RESERVED;
+	}
+
+	if (hostkey_alg) {
+		hostkey_dtype = SSHFP_HASH_SHA1;
+		hostkey_digest = key_fingerprint_raw(key, SSH_FP_SHA1, &hostkey_dlen);
+	}
+	else {
+		hostkey_dtype = SSHFP_HASH_RESERVED;
+		hostkey_digest = NULL;
+	}
+
+	status = DnsQuery(hostname, DNS_TYPE_SSHFP, DNS_QUERY_STANDARD, NULL, &rec, NULL);
+
+	if (status == 0) {
+		for (p=rec; p!=NULL; p=p->pNext) {
+			if (p->wType == DNS_TYPE_SSHFP) {
+				t = (PDNS_SSHFP_DATA)&(p->Data.Null);
+				if (t->Algorithm == hostkey_alg && t->DigestType == hostkey_dtype) {
+					if (hostkey_dlen == p->wDataLength-2 && memcmp(hostkey_digest, t->Digest, hostkey_dlen) == 0) {
+						found = DNS_VERIFY_MATCH;
+						_snprintf_s(buff, sizeof(buff), _TRUNCATE, "Match: alg=%d, dgst=%d, flags=%d (%x)",
+							t->Algorithm, t->DigestType, p->Flags);
+						MessageBox(NULL, buff, "DNS Verify Match", MB_OK);
+						break;
+					}
+					else {
+						found = DNS_VERIFY_MISMATCH;
+						_snprintf_s(buff, sizeof(buff), _TRUNCATE, "Missmatch: alg=%d, dgst=%d, flags=%d (%x)",
+							t->Algorithm, t->DigestType, p->Flags);
+						MessageBox(NULL, buff, "DNS Verify Missmatch", MB_OK);
+						break;
+					}
+				}
+				else {
+					found = DNS_VERIFY_DIFFERENTTYPE;
+				}
+			}
+		}
+	}
+
+	free(hostkey_digest);
+	DnsRecordListFree(rec, DnsFreeRecordList);
+	return found;
+}
+
 //
 // ƒT[ƒo‚©‚ç‘—‚ç‚ê‚Ä‚«‚½ƒzƒXƒgŒöŠJŒ®‚̑Ó–«‚ðƒ`ƒFƒbƒN‚·‚é
 //
@@ -1638,7 +1729,7 @@
 //
 BOOL HOSTS_check_host_key(PTInstVar pvar, char FAR * hostname, unsigned short tcpport, Key *key)
 {
-	int found_different_key = 0, found_different_type_key = 0;
+	int found_different_key = 0, found_different_type_key = 0, dns_sshfp_check = 0;
 
 	// ‚·‚Å‚É known_hosts ƒtƒ@ƒCƒ‹‚©‚çƒzƒXƒgŒöŠJŒ®‚ð“ǂݍž‚ñ‚Å‚¢‚é‚È‚çA‚»‚ê‚Æ”äŠr‚·‚éB
 	if (pvar->hosts_state.prefetched_hostname != NULL
@@ -1687,6 +1778,11 @@
 		finish_read_host_files(pvar, 0);
 	}
 
+	if (pvar->settings.VerifyHostKeyDNS) {
+		if (!is_numeric_hostname(hostname)) {
+			dns_sshfp_check = verify_hostkey_dns(hostname, key);
+		}
+	}
 
 	// known_hosts ‚É‘¶Ý‚µ‚È‚¢ƒL[‚Í‚ ‚ƂŃtƒ@ƒCƒ‹‚֏‘‚«ž‚Þ‚½‚߂ɁA‚±‚±‚Å•Û‘¶‚µ‚Ä‚¨‚­B
 	pvar->hosts_state.hostkey.type = key->type;
@@ -1721,24 +1817,13 @@
 	// ‚±‚ê‚É‚æ‚èknown_hosts‚ÌŠm”F‚ð‘Ò‚½‚¸‚ɁAƒT[ƒo‚Öƒ†[ƒUî•ñ‚ð‘—‚Á‚Ä‚µ‚Ü‚¤–â‘è‚ð‰ñ”ð‚·‚éB
 	// (2007.10.1 yutaka)
 	if (found_different_key) {
-#if 0
-		PostMessage(pvar->NotificationWindow, WM_COMMAND,
-		            ID_SSHDIFFERENTKEY, 0);
-#else
 		HOSTS_do_different_key_dialog(pvar->NotificationWindow, pvar);
-#endif
 	}
 	else if (found_different_type_key) {
 		HOSTS_do_different_type_key_dialog(pvar->NotificationWindow, pvar);
 	}
 	else {
-#if 0
-		PostMessage(pvar->NotificationWindow, WM_COMMAND,
-		            ID_SSHUNKNOWNHOST, 0);
-#else
 		HOSTS_do_unknown_host_dialog(pvar->NotificationWindow, pvar);
-#endif
-
 	}
 
 	return TRUE;
@@ -1747,8 +1832,7 @@
 void HOSTS_notify_disconnecting(PTInstVar pvar)
 {
 	if (pvar->hosts_state.hosts_dialog != NULL) {
-		PostMessage(pvar->hosts_state.hosts_dialog, WM_COMMAND, IDCANCEL,
-		            0);
+		PostMessage(pvar->hosts_state.hosts_dialog, WM_COMMAND, IDCANCEL, 0);
 		/* the main window might not go away if it's not enabled. (see vtwin.cpp) */
 		EnableWindow(pvar->NotificationWindow, TRUE);
 	}
@@ -1759,12 +1843,7 @@
 	int i;
 
 	free(pvar->hosts_state.prefetched_hostname);
-#if 0
-	free(pvar->hosts_state.key_exp);
-	free(pvar->hosts_state.key_mod);
-#else
 	init_hostkey(&pvar->hosts_state.hostkey);
-#endif
 
 	if (pvar->hosts_state.file_names != NULL) {
 		for (i = 0; pvar->hosts_state.file_names[i] != NULL; i++) {

Modified: trunk/ttssh2/ttxssh/key.c
===================================================================
--- trunk/ttssh2/ttxssh/key.c	2011-07-26 08:18:19 UTC (rev 4530)
+++ trunk/ttssh2/ttxssh/key.c	2011-07-26 08:50:11 UTC (rev 4531)
@@ -435,7 +435,7 @@
 }
 
 
-char* key_fingerprint_raw(Key *k, int *dgst_raw_length)
+char* key_fingerprint_raw(Key *k, enum fp_type dgst_type, int *dgst_raw_length)
 {
 	const EVP_MD *md = NULL;
 	EVP_MD_CTX ctx;
@@ -447,8 +447,16 @@
 
 	*dgst_raw_length = 0;
 
-	// MD5ƒAƒ‹ƒSƒŠƒYƒ€‚ðŽg—p‚·‚é
-	md = EVP_md5();
+	switch (dgst_type) {
+	case SSH_FP_MD5:
+		md = EVP_md5();
+		break;
+	case SSH_FP_SHA1:
+		md = EVP_sha1();
+		break;
+	default:
+		md = EVP_md5();
+	}
 
 	switch (k->type) {
 	case KEY_RSA1:
@@ -633,7 +641,7 @@
 	int i, retval_len;
 
 	// fingerprint‚̃nƒbƒVƒ…’liƒoƒCƒiƒŠj‚ð‹‚ß‚é
-	dgst_raw = key_fingerprint_raw(key, &dgst_raw_len);
+	dgst_raw = key_fingerprint_raw(key, SSH_FP_MD5, &dgst_raw_len);
 
 	if (dgst_rep == SSH_FP_HEX) {
 		// 16i•\‹L‚Ö•ÏŠ·‚·‚é

Modified: trunk/ttssh2/ttxssh/key.h
===================================================================
--- trunk/ttssh2/ttxssh/key.h	2011-07-26 08:18:19 UTC (rev 4530)
+++ trunk/ttssh2/ttxssh/key.h	2011-07-26 08:50:11 UTC (rev 4531)
@@ -34,7 +34,7 @@
 RSA *duplicate_RSA(RSA *src);
 DSA *duplicate_DSA(DSA *src);
 
-char* key_fingerprint_raw(Key *k, int *dgst_raw_length);
+char *key_fingerprint_raw(Key *k, enum fp_type dgst_type, int *dgst_raw_length);
 char *key_fingerprint(Key *key, enum fp_rep dgst_rep);
 
 const char *key_type(const Key *k);

Modified: trunk/ttssh2/ttxssh/ssh.h
===================================================================
--- trunk/ttssh2/ttxssh/ssh.h	2011-07-26 08:18:19 UTC (rev 4530)
+++ trunk/ttssh2/ttxssh/ssh.h	2011-07-26 08:50:11 UTC (rev 4531)
@@ -473,6 +473,22 @@
 	SSH_FP_RANDOMART
 };
 
+enum fp_type {
+	SSH_FP_SHA1,
+	SSH_FP_MD5
+};
+
+enum sshfp_types {
+	SSHFP_KEY_RESERVED,
+	SSHFP_KEY_RSA,
+	SSHFP_KEY_DSA
+};
+
+enum sshfp_hashes {
+	SSHFP_HASH_RESERVED,
+	SSHFP_HASH_SHA1
+};
+
 enum scp_dir {
 	TOREMOTE, FROMREMOTE,
 };

Modified: trunk/ttssh2/ttxssh/ttxssh.c
===================================================================
--- trunk/ttssh2/ttxssh/ttxssh.c	2011-07-26 08:18:19 UTC (rev 4530)
+++ trunk/ttssh2/ttxssh/ttxssh.c	2011-07-26 08:50:11 UTC (rev 4531)
@@ -465,6 +465,9 @@
 	// agent forward Šm”F‚ð—LŒø‚É‚·‚é
 	settings->ForwardAgentConfirm = read_BOOL_option(fileName, "ForwardAgentConfirm", TRUE);
 
+	// ƒzƒXƒgŒ®‚Ì DNS ‚ł̃`ƒFƒbƒN (RFC 4255)
+	settings->VerifyHostKeyDNS = read_BOOL_option(fileName, "VerifyHostKeyDNS", FALSE);
+
 	clear_local_settings(pvar);
 }
 
@@ -557,6 +560,12 @@
 	// agent forward Šm”F‚ð—LŒø‚É‚·‚é
 	WritePrivateProfileString("TTSSH", "ForwardAgentConfirm",
 	                          settings->ForwardAgentConfirm ? "1" : "0", fileName);
+
+/*
+	// ƒzƒXƒgŒ®‚Ì DNS ‚ł̃`ƒFƒbƒN (RFC 4255)
+	WritePrivateProfileString("TTSSH", "VerifyHostKeyDNS",
+	                          settings->VerifyHostKeyDNS ? "1" : "0", fileName);
+ */
 }
 
 

Modified: trunk/ttssh2/ttxssh/ttxssh.h
===================================================================
--- trunk/ttssh2/ttxssh/ttxssh.h	2011-07-26 08:18:19 UTC (rev 4530)
+++ trunk/ttssh2/ttxssh/ttxssh.h	2011-07-26 08:50:11 UTC (rev 4531)
@@ -145,6 +145,8 @@
 	char HostKeyOrder[KEY_MAX+1];
 	char MacOrder[HMAC_MAX+1];
 	char CompOrder[COMP_MAX+1];
+
+	BOOL VerifyHostKeyDNS;
 } TS_SSH;
 
 typedef struct _TInstVar {

Modified: trunk/ttssh2/ttxssh/ttxssh.vcproj
===================================================================
--- trunk/ttssh2/ttxssh/ttxssh.vcproj	2011-07-26 08:18:19 UTC (rev 4530)
+++ trunk/ttssh2/ttxssh/ttxssh.vcproj	2011-07-26 08:50:11 UTC (rev 4531)
@@ -78,11 +78,12 @@
 			<Tool
 				Name="VCLinkerTool"
 				AdditionalOptions="Version.lib &#x0D;&#x0A;&#x0D;&#x0A;"
-				AdditionalDependencies="odbc32.lib odbccp32.lib ws2_32.lib libeay32.lib zlibd.lib ttpcmn.lib"
+				AdditionalDependencies="odbc32.lib odbccp32.lib ws2_32.lib libeay32.lib zlibd.lib ttpcmn.lib dnsapi.lib"
 				OutputFile=".\Debug/ttxssh.dll"
 				LinkIncremental="2"
 				SuppressStartupBanner="true"
 				AdditionalLibraryDirectories="..\..\libs\openssl\out32.dbg;..\..\libs\zlib;..\..\teraterm\Debug"
+				DelayLoadDLLs="dnsapi.dll"
 				ModuleDefinitionFile="ttxssh.def"
 				GenerateDebugInformation="true"
 				ProgramDatabaseFile=".\Debug/ttxssh.pdb"
@@ -182,11 +183,12 @@
 			<Tool
 				Name="VCLinkerTool"
 				AdditionalOptions="Version.lib &#x0D;&#x0A;"
-				AdditionalDependencies="odbc32.lib odbccp32.lib ws2_32.lib libeay32.lib zlib.lib ttpcmn.lib"
+				AdditionalDependencies="odbc32.lib odbccp32.lib ws2_32.lib libeay32.lib zlib.lib ttpcmn.lib dnsapi.lib"
 				OutputFile=".\Release/ttxssh.dll"
 				LinkIncremental="1"
 				SuppressStartupBanner="true"
 				AdditionalLibraryDirectories="..\..\libs\openssl\out32;..\..\libs\zlib;..\..\teraterm\Release"
+				DelayLoadDLLs="dnsapi.dll"
 				ModuleDefinitionFile="ttxssh.def"
 				GenerateDebugInformation="true"
 				ProgramDatabaseFile=".\Release/ttxssh.pdb"



Ttssh2-commit メーリングリストの案内
アーカイブの一覧に戻る