[ttssh2-commit] [10695] 新実装のsshagent通信追加

Back to archive index
scmno****@osdn***** scmno****@osdn*****
2023年 5月 2日 (火) 22:27:52 JST


Revision: 10695
          https://osdn.net/projects/ttssh2/scm/svn/commits/10695
Author:   zmatsuo
Date:     2023-05-02 22:27:52 +0900 (Tue, 02 May 2023)
Log Message:
-----------
新実装のsshagent通信追加

- 通信できる agent
  - pageant (共有メモリ)
  - pageant (NamedPipe)
  - Microsoft SSH agent (NamedPipe)
- sha256 は opensslIF版とbcrypt版の2つを準備

ticket #45653

Ticket Links:
------------
    https://osdn.net/projects/ttssh2/tracker/detail/45653

Modified Paths:
--------------
    trunk/ttssh2/libsshagentc/CMakeLists.txt
    trunk/ttssh2/libsshagentc/README.md

Added Paths:
-----------
    trunk/ttssh2/libsshagentc/sshagentc/
    trunk/ttssh2/libsshagentc/sshagentc/CMakeLists.txt
    trunk/ttssh2/libsshagentc/sshagentc/README.md
    trunk/ttssh2/libsshagentc/sshagentc/agentc.cpp
    trunk/ttssh2/libsshagentc/sshagentc/sha256.h
    trunk/ttssh2/libsshagentc/sshagentc/sha256_bcrypt.cpp
    trunk/ttssh2/libsshagentc/sshagentc/sha256_openssl.cpp

-------------- next part --------------
Modified: trunk/ttssh2/libsshagentc/CMakeLists.txt
===================================================================
--- trunk/ttssh2/libsshagentc/CMakeLists.txt	2023-05-02 13:27:42 UTC (rev 10694)
+++ trunk/ttssh2/libsshagentc/CMakeLists.txt	2023-05-02 13:27:52 UTC (rev 10695)
@@ -1,9 +1,16 @@
 cmake_minimum_required(VERSION 3.11)
 project(libsshagentc)
 
+# どの libsshagentc を使用するか
+#  すべて OFF の時、従来と同じ putty を使用する
 option(SSHAGENTC_SKELTON "use skelton" OFF)
+option(SSHAGENTC_NEXT "use next sshagent" OFF)
 
-if(SSHAGENTC_SKELTON)
+option(SSHAGENTC_TOOL "sshagentc test/debug tool" OFF)
+
+if(SSHAGENTC_NEXT)
+  add_subdirectory(sshagentc)
+elseif(SSHAGENTC_SKELTON)
   add_subdirectory(skelton)
 else()
   add_subdirectory(putty)
@@ -10,4 +17,6 @@
 endif()
 
 # for debug/test
-#add_subdirectory(sshagentc_tool)
+if(SSHAGENTC_TOOL)
+  add_subdirectory(sshagentc_tool)
+endif()

Modified: trunk/ttssh2/libsshagentc/README.md
===================================================================
--- trunk/ttssh2/libsshagentc/README.md	2023-05-02 13:27:42 UTC (rev 10694)
+++ trunk/ttssh2/libsshagentc/README.md	2023-05-02 13:27:52 UTC (rev 10695)
@@ -1,6 +1,7 @@
 # libsshagentc
 
-- ssh-agent と通信するためのライブラリ
+ssh-agent と通信するためのライブラリ。
+Tera Term 以外でも使えるよう考慮。
 
 ファイル/フォルダ
 
@@ -11,6 +12,8 @@
 - skelton/
   - クライアントスケルトン
   - 何も行わない
+- sshagentc/
+  - 作成中
 
 # 資料
 

Added: trunk/ttssh2/libsshagentc/sshagentc/CMakeLists.txt
===================================================================
--- trunk/ttssh2/libsshagentc/sshagentc/CMakeLists.txt	                        (rev 0)
+++ trunk/ttssh2/libsshagentc/sshagentc/CMakeLists.txt	2023-05-02 13:27:52 UTC (rev 10695)
@@ -0,0 +1,54 @@
+set(PACKAGE_NAME "libsshagentc")
+
+project(${PACKAGE_NAME})
+
+add_library(
+  ${PACKAGE_NAME}
+  ../libputty.h
+  agentc.cpp
+  sha256.h
+)
+
+if(1)
+  target_sources(
+    ${PACKAGE_NAME}
+    PRIVATE
+    sha256.h
+    sha256_bcrypt.cpp
+  )
+endif()
+
+if(0)
+  target_sources(
+    ${PACKAGE_NAME}
+    PRIVATE
+    sha256.h
+    sha256_openssl.cpp
+  )
+endif()
+
+if(MSVC)
+  target_compile_options(
+    ${PACKAGE_NAME}
+    PRIVATE
+    -W4
+  )
+else()
+  target_compile_options(
+    ${PACKAGE_NAME}
+    PRIVATE
+    -Wall -Wextra
+  )
+endif()
+
+target_include_directories(
+  ${PACKAGE_NAME}
+  PRIVATE
+  ${CMAKE_CURRENT_LIST_DIR}/..
+)
+
+target_link_libraries(
+  ${PACKAGE_NAME}
+  PRIVATE
+  crypt32
+)

Added: trunk/ttssh2/libsshagentc/sshagentc/README.md
===================================================================
--- trunk/ttssh2/libsshagentc/sshagentc/README.md	                        (rev 0)
+++ trunk/ttssh2/libsshagentc/sshagentc/README.md	2023-05-02 13:27:52 UTC (rev 10695)
@@ -0,0 +1,16 @@
+# ssh agent client
+
+ssh ageant と通信するライブラリ
+
+## 通信できる agent
+
+- pageant (共有メモリ)
+- pageant (NamedPipe)
+- Microsoft SSH ageant (NamedPipe)
+
+## 参考にしたプロジェクト
+
+- PuTTY
+  - https://www.chiark.greenend.org.uk/~sgtatham/putty/
+- RLogin
+  - http://nanno.bf1.jp/softlib/man/rlogin/

Added: trunk/ttssh2/libsshagentc/sshagentc/agentc.cpp
===================================================================
--- trunk/ttssh2/libsshagentc/sshagentc/agentc.cpp	                        (rev 0)
+++ trunk/ttssh2/libsshagentc/sshagentc/agentc.cpp	2023-05-02 13:27:52 UTC (rev 10695)
@@ -0,0 +1,680 @@
+/*
+ * Copyright (C) 2023- TeraTerm Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+// PuTTY is copyright 1997-2023 Simon Tatham.
+// RLogin is copyright 1998-2023 Culti
+
+#include <stdio.h>
+#include <stdlib.h>
+#define _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#include <stdint.h>
+#include <assert.h>
+#include <vector>
+#include <windows.h>
+#include <Lmcons.h>	// for UNLEN
+#include "libputty.h"
+#include "sha256.h"
+
+#define PUTTY_SHM		1	// pageant shared memory
+#define PUTTY_NAMEDPIPE	1	// pageant named pipe
+#define MS_NAMEDPIPE	1	// Microsoft agent
+
+// SSH Agent
+//	Message numbers
+//	https://datatracker.ietf.org/doc/html/draft-miller-ssh-agent-04#section-5.1
+
+// requests from the client to the agent
+#define SSH_AGENTC_REQUEST_IDENTITIES			11
+#define SSH_AGENTC_SIGN_REQUEST					13
+#define SSH_AGENTC_ADD_IDENTITY					17
+#define SSH_AGENTC_REMOVE_IDENTITY				18
+#define SSH_AGENTC_REMOVE_ALL_IDENTITIES		19
+#define SSH_AGENTC_EXTENSION					27
+
+// replies from the agent to the client
+#define SSH_AGENT_FAILURE						5
+#define SSH_AGENT_SUCCESS						6
+#define SSH_AGENT_EXTENSION_FAILURE				28
+#define SSH_AGENT_IDENTITIES_ANSWER				12
+#define SSH_AGENT_SIGN_RESPONSE					14
+
+#if PUTTY_SHM
+static PSID usersid;
+#endif
+
+static uint32_t get_uint32(const uint8_t *p)
+{
+	return (((uint32_t)p[3]		 ) | ((uint32_t)p[2] <<	 8) |
+			((uint32_t)p[1] << 16) | ((uint32_t)p[0] << 24));
+}
+
+/**
+ *	pageant \x82\xCC named pipe\x96\xBC\x82̈ꕔ
+ *	from putty windows/utils/cryptapi.c
+ *
+ *	@param		realname	\x8C\xB3\x82ɂȂ镶\x8E\x9A\x97\xF1
+ *	@return		named pipe\x96\xBC\x82̈ꕔ
+ *				\x83T\x83C\x83\x93\x83C\x83\x93\x92\x86\x82͓\xAF\x88ꕶ\x8E\x9A\x97񂪕Ԃ\xE9
+ *				\x95s\x97v\x82ɂȂ\xC1\x82\xBD\x82\xE7 free()
+ *
+ *	TODO
+ *		CryptProtectMemory() API \x82͔\xE4\x8Ar\x93I\x90V\x82\xB5\x82\xA2 Windows \x82݂̂Ǝv\x82\xED\x82\xEA\x82\xE9
+ */
+static char *capi_obfuscate_string(const char *realname)
+{
+	char *cryptdata;
+	int cryptlen;
+	unsigned char digest[32];
+	char retbuf[65];
+	int i;
+
+	cryptlen = (int)(strlen(realname) + 1);
+	cryptlen += CRYPTPROTECTMEMORY_BLOCK_SIZE - 1;
+	cryptlen /= CRYPTPROTECTMEMORY_BLOCK_SIZE;
+	cryptlen *= CRYPTPROTECTMEMORY_BLOCK_SIZE;
+
+	cryptdata = (char *)malloc(cryptlen);
+	memset(cryptdata, 0, cryptlen);
+	memcpy(cryptdata, realname, strlen(realname));
+
+	/*
+	 * CRYPTPROTECTMEMORY_CROSS_PROCESS causes CryptProtectMemory to
+	 * use the same key in all processes with this user id, meaning
+	 * that the next PuTTY process calling this function with the same
+	 * input will get the same data.
+	 *
+	 * (Contrast with CryptProtectData, which invents a new session
+	 * key every time since its API permits returning more data than
+	 * was input, so calling _that_ and hashing the output would not
+	 * be stable.)
+	 *
+	 * We don't worry too much if this doesn't work for some reason.
+	 * Omitting this step still has _some_ privacy value (in that
+	 * another user can test-hash things to confirm guesses as to
+	 * where you might be connecting to, but cannot invert SHA-256 in
+	 * the absence of any plausible guess). So we don't abort if we
+	 * can't call CryptProtectMemory at all, or if it fails.
+	 */
+	CryptProtectMemory(cryptdata, cryptlen,
+					   CRYPTPROTECTMEMORY_CROSS_PROCESS);
+
+	/*
+	 * We don't want to give away the length of the hostname either,
+	 * so having got it back out of CryptProtectMemory we now hash it.
+	 */
+	assert(cryptlen == 16);
+	uint8_t buf[4+16] = {0};
+	buf[3] = 0x10;	// = 0x00000010
+	memcpy(&buf[4], cryptdata, cryptlen);
+	sha256(&buf[0], sizeof(buf), digest);
+	free(cryptdata);
+
+	/*
+	 * Finally, make printable.
+	 */
+	retbuf[0] = 0;
+	for (i = 0; i < 32; i++) {
+		char s[4];
+		sprintf_s(s, "%02x", digest[i]);
+		strcat_s(retbuf, s);
+	}
+
+	return _strdup(retbuf);
+}
+
+/**
+ *	pagent named pipe\x96\xBC
+ *	from putty windows/utils/agent_named_pipe_name.c
+ */
+static char *agent_named_pipe_name(void)
+{
+	char user_name[UNLEN+1];
+	DWORD len = _countof(user_name);
+	BOOL r = GetUserNameA(user_name, &len);
+	if (r == 0) {
+		return NULL;
+	}
+	char *suffix = capi_obfuscate_string("Pageant");
+	// asprintf(&pipename, "\\\\.\\pipe\\pageant.%s.%s", user_name, suffix);
+	const char *base = "\\\\.\\pipe\\pageant.";
+	size_t pipe_len = strlen(base) + 2 + strlen(user_name) + strlen(suffix);
+	char *pipename = (char *)malloc(pipe_len);
+	strcpy_s(pipename, pipe_len, base);
+	strcat_s(pipename, pipe_len, user_name);
+	strcat_s(pipename, pipe_len, ".");
+	strcat_s(pipename, pipe_len, suffix);
+	free(suffix);
+	return pipename;
+}
+
+/**
+ *	\x83o\x83b\x83t\x83@\x91\x80\x8D\xEC
+ */
+class Buffer {
+public:
+	virtual ~Buffer() {
+		clear();
+	}
+	size_t size() const
+	{
+		return buf_.size();
+	}
+	void clear()
+	{
+		const size_t size = buf_.size();
+		if (size > 0) {
+			SecureZeroMemory(&buf_[0], size);
+			buf_.clear();
+		}
+	}
+	void *get_ptr() const
+	{
+		if (buf_.size() == 0) {
+			return NULL;
+		}
+		return (void *)&buf_[0];
+	}
+	void append_array(const void *ptr, size_t len) {
+		const uint8_t *u8ptr = (uint8_t *)ptr;
+		buf_.insert(buf_.end(), &u8ptr[0], &u8ptr[len]);
+	}
+	void append_byte(uint8_t u8)
+	{
+		buf_.push_back(u8);
+	}
+	void append_uint32(uint32_t u32)
+	{
+		buf_.push_back((u32 >> (8*3)) & 0xff);
+		buf_.push_back((u32 >> (8*2)) & 0xff);
+		buf_.push_back((u32 >> (8*1)) & 0xff);
+		buf_.push_back((u32 >> (8*0)) & 0xff);
+	}
+	/**
+	 *	malloc\x82\xB5\x82\xBD\x97̈\xE6\x82ɓ\xE0\x97e\x82\xF0\x83R\x83s\x81[\x82\xB5\x82ĕԂ\xB7
+	 */
+	void *get_mallocdbuf(size_t *size)
+	{
+		size_t len = buf_.size();
+		*size = len;
+		void *p = NULL;
+		if (len > 0) {
+			p = malloc(len);
+			memcpy(p, &buf_[0], len);
+		}
+		return p;
+	}
+	/**
+	 *	\x83o\x83b\x83t\x83@\x82̐擪\x82ɒlj\xC1\x82\xB7\x82\xE9
+	 */
+	void prepend_uint32(uint32_t u32)
+	{
+		Buffer new_buf;
+		new_buf.append_uint32(u32);
+		new_buf.buf_.insert(new_buf.buf_.end(), buf_.begin(), buf_.end());
+		buf_.swap(new_buf.buf_);
+	}
+private:
+	std::vector<uint8_t> buf_;
+};
+
+/**
+ *	Microsoft named pipe \x96\xBC\x82\xF0\x8E擾
+ *
+ *	\x8A‹\xAB\x95ϐ\x94 SSH_AUTH_SOCK \x82\xAA\x90ݒ肳\x82\xEA\x82Ă\xA2\x82\xEA\x82΁A\x82\xBB\x82̒l\x82\xF0\x95Ԃ\xB7
+ *	\x90ݒ肳\x82\xEA\x82Ă\xA2\x82Ȃ\xAF\x82\xEA\x82΃f\x83t\x83H\x83\x8B\x83g\x82\xF0\x95Ԃ\xB7
+ *
+ *	@return	pipe name (\x95s\x97v\x82ɂȂ\xC1\x82\xBD\x82\xE7 free() \x82\xB7\x82邱\x82\xC6)
+ */
+#if MS_NAMEDPIPE
+static char *get_ms_namedpipe(void)
+{
+	static const char *var_name = "SSH_AUTH_SOCK";
+	static const char *pipename_default = "\\\\.\\pipe\\openssh-ssh-agent";
+	char *var_ptr = NULL;
+	size_t var_size = 0;
+	getenv_s(&var_size, NULL, 0, var_name);
+	if (var_size != 0) {
+		var_ptr = (char*)malloc(var_size);
+		getenv_s(&var_size, var_ptr, var_size, var_name);
+	}
+	if (var_ptr == NULL) {
+		var_ptr = strdup(pipename_default);
+	}
+	return var_ptr;
+}
+#endif
+
+/**
+ *	agent\x82ƒʐM,named pipe\x8Co\x97R
+ *	RLogin CMainFrame::WageantQuery() MainFrm.cpp \x82\xF0\x8EQ\x8Dl\x82ɂ\xB5\x82\xBD
+ */
+#if PUTTY_NAMEDPIPE || MS_NAMEDPIPE
+static BOOL query_namedpipe(const char *pipename, const Buffer &request, Buffer &reply)
+{
+	BOOL r = FALSE;
+	std::vector<BYTE> read_buffer(4096);
+	DWORD read_len = 0;
+
+	HANDLE hPipe = CreateFileA(pipename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+	if (hPipe == INVALID_HANDLE_VALUE) {
+		return FALSE;
+	}
+
+	// \x83\x8A\x83N\x83G\x83X\x83g\x91\x97\x90M
+	const BYTE *req_ptr = (BYTE *)request.get_ptr();
+	DWORD req_len = (DWORD)request.size();
+	while (req_len > 0) {
+		DWORD written;
+		if (!WriteFile(hPipe, req_ptr, req_len, &written, NULL)) {
+			// \x8F\x91\x82\xAB\x8D\x9E\x82݃G\x83\x89\x81[\x82\xAA\x8BN\x82\xAB\x82\xBD\x81A\x92ʐM\x92\x86\x82\xC9 agent \x82\xAA\x97\x8E\x82\xBF\x82\xBD?
+			goto finish;
+		}
+		req_ptr += written;
+		req_len -= written;
+	}
+
+	// \x83\x8A\x83v\x83\x89\x83C\x8E\xF3\x90M
+	reply.clear();
+	if (ReadFile(hPipe, &read_buffer[0], 4, &read_len, NULL) && read_len == 4) {
+		const uint32_t len = get_uint32(&read_buffer[0]);
+		if (len < AGENT_MAX_MSGLEN) {
+			uint32_t total_len;
+			reply.append_array(&read_buffer[0], 4);
+			for (total_len = 0; total_len < len;) {
+				if (!ReadFile(hPipe, &read_buffer[0], (DWORD)read_buffer.size(), &read_len, NULL)) {
+					reply.clear();
+					break;
+				}
+				reply.append_array(&read_buffer[0], read_len);
+				total_len += read_len;
+			}
+		}
+	}
+
+	if (reply.size() > 0)
+		r = TRUE;
+
+finish:
+	CloseHandle(hPipe);
+	SecureZeroMemory(&read_buffer[0], read_buffer.size());
+	return r;
+}
+#endif
+
+/**
+ *	sid\x82̎擾
+ *	PuTTY security.c get_user_sid()
+ */
+#if PUTTY_SHM
+static PSID get_user_sid(void)
+{
+    HANDLE proc = NULL, tok = NULL;
+    TOKEN_USER *user = NULL;
+    DWORD toklen, sidlen;
+    PSID sid = NULL, ret = NULL;
+
+    if (usersid)
+        return usersid;
+
+    if ((proc = OpenProcess(MAXIMUM_ALLOWED, false,
+                            GetCurrentProcessId())) == NULL)
+        goto cleanup;
+
+    if (!OpenProcessToken(proc, TOKEN_QUERY, &tok))
+        goto cleanup;
+
+    if (!GetTokenInformation(tok, TokenUser, NULL, 0, &toklen) &&
+        GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+        goto cleanup;
+
+    if ((user = (TOKEN_USER *)LocalAlloc(LPTR, toklen)) == NULL)
+        goto cleanup;
+
+    if (!GetTokenInformation(tok, TokenUser, user, toklen, &toklen))
+        goto cleanup;
+
+    sidlen = GetLengthSid(user->User.Sid);
+
+    sid = (PSID)malloc(sidlen);
+
+    if (!CopySid(sidlen, sid, user->User.Sid))
+        goto cleanup;
+
+    /* Success. Move sid into the return value slot, and null it out
+     * to stop the cleanup code freeing it. */
+    ret = usersid = sid;
+    sid = NULL;
+
+  cleanup:
+    if (proc != NULL)
+        CloseHandle(proc);
+    if (tok != NULL)
+        CloseHandle(tok);
+    if (user != NULL)
+        LocalFree(user);
+    if (sid != NULL)
+        free(sid);
+
+    return ret;
+}
+#endif
+
+/**
+ *	SECURITY_ATTRIBUTES \x82̎擾
+ *	PuTTY windows/agent-client.c wm_copydata_agent_query() \x82\xF0\x8EQ\x8Dl\x82ɂ\xB5\x82\xBD
+ *
+ *	@param	psa		SECURITY_ATTRIBUTES \x82ւ̃|\x83C\x83\x93\x83^
+ *					\x82\xB1\x82\xB1\x82Ɏ擾\x82\xB7\x82\xE9
+ *	@return	SECURITY_ATTRIBUTES\x82ւ̃|\x83C\x83\x93\x83^
+ *			\x95s\x97v\x82ɂȂ\xC1\x82\xBD\x82\xE7 psa->lpSecurityDescriptor \x82\xF0 LocalFree() \x82\xB7\x82邱\x82\xC6
+ *			\x8E擾\x82ł\xAB\x82Ȃ\xA9\x82\xC1\x82\xBD\x82Ƃ\xAB\x82\xCD NULL
+ */
+#if PUTTY_SHM
+static SECURITY_ATTRIBUTES *get_sa(SECURITY_ATTRIBUTES *psa)
+{
+	memset(psa, 0, sizeof(*psa));
+	usersid = get_user_sid();
+	if (!usersid) {
+		return NULL;
+	}
+	PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR)
+		LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
+	if (!psd) {
+		return NULL;
+	}
+
+	if (InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION) &&
+		SetSecurityDescriptorOwner(psd, usersid, false)) {
+		psa->nLength = sizeof(*psa);
+		psa->bInheritHandle = true;
+		psa->lpSecurityDescriptor = psd;	// LocalFree() \x82\xB7\x82邱\x82\xC6
+	} else {
+		LocalFree(psd);
+		psa = NULL;
+	}
+	return psa;
+}
+#endif
+
+/**
+ *	agent(pageant)\x82ƒʐM,\x8B\xA4\x97L\x83\x81\x83\x82\x83\x8A\x8Co\x97R
+ *
+ *	@retval	FALSE	\x83G\x83\x89\x81[
+ */
+#if PUTTY_SHM
+static BOOL query_SHM(const Buffer &request, Buffer &reply)
+{
+	HWND hwnd;
+	char mapname[25];
+	HANDLE fmap = NULL;
+	unsigned char *p = NULL;
+	unsigned long len;
+	BOOL ret = FALSE;
+	const uint8_t *in = (uint8_t *)request.get_ptr();
+	SECURITY_ATTRIBUTES *psa = NULL;
+
+	reply.clear();
+
+	if ((len = get_uint32(in)) > AGENT_MAX_MSGLEN) {
+		goto agent_error;
+	}
+
+	hwnd = FindWindowA("Pageant", "Pageant");
+	if (!hwnd) {
+		goto agent_error;
+	}
+
+	SECURITY_ATTRIBUTES sa;
+	psa = get_sa(&sa);
+	sprintf_s(mapname, "PageantRequest%08x", (unsigned)GetCurrentThreadId());
+	fmap = CreateFileMappingA(INVALID_HANDLE_VALUE, psa, PAGE_READWRITE,
+							  0, AGENT_MAX_MSGLEN, mapname);
+	if (!fmap) {
+		goto agent_error;
+	}
+
+	if ((p = (unsigned char *)MapViewOfFile(fmap, FILE_MAP_WRITE, 0, 0, 0)) == NULL) {
+		goto agent_error;
+	}
+
+	COPYDATASTRUCT cds;
+#define AGENT_COPYDATA_ID 0x804e50ba	// ?
+	cds.dwData = AGENT_COPYDATA_ID;
+	cds.cbData = (DWORD)(strlen(mapname) + 1);
+	cds.lpData = mapname;
+
+	memcpy(p, in, len + 4);
+	if (SendMessageA(hwnd, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&cds) > 0) {
+		// \x89\x9E\x93\x9A\x82\xAA\x82\xA0\x82\xC1\x82\xBD
+		len = get_uint32(p);
+		reply.append_array(p, len+4);
+		ret = TRUE;
+	}
+
+agent_error:
+	if (p) {
+		UnmapViewOfFile(p);
+	}
+	if (fmap) {
+		CloseHandle(fmap);
+	}
+	if (ret == 0) {
+		reply.append_uint32(5);
+		reply.append_byte(SSH_AGENT_FAILURE);
+		ret = FALSE;
+	}
+	if (psa != NULL) {
+		LocalFree(psa->lpSecurityDescriptor);
+	}
+	return ret;
+}
+#endif
+
+static BOOL query(const Buffer &request, Buffer &reply)
+{
+	BOOL r;
+
+	reply.clear();
+#if PUTTY_NAMEDPIPE
+	char *pname = agent_named_pipe_name();
+	if (pname != NULL) {
+		r = query_namedpipe(pname, request, reply);
+		free(pname);
+		if (r) {
+			goto finish;
+		}
+	}
+#endif
+#if PUTTY_SHM
+	r = query_SHM(request, reply);
+	if (r) {
+		goto finish;
+	}
+#endif
+#if MS_NAMEDPIPE
+	{
+		char *ms_namedpipe = get_ms_namedpipe();
+		r = query_namedpipe(ms_namedpipe, request, reply);
+		free(ms_namedpipe);
+		if (r) {
+			goto finish;
+		}
+	}
+#endif
+finish:
+	return r;
+}
+
+// https://datatracker.ietf.org/doc/html/draft-miller-ssh-agent-04#section-4.4
+int putty_get_ssh2_keylist(unsigned char **keylist)
+{
+	Buffer req;
+	req.append_uint32(1);
+	req.append_byte(SSH_AGENTC_REQUEST_IDENTITIES);
+
+	Buffer rep;
+	query(req, rep);
+
+	// check
+	const uint8_t *reply_ptr = (uint8_t *)rep.get_ptr();
+	uint32_t reply_len = get_uint32(reply_ptr);
+	if (rep.size() != reply_len + 4 || reply_ptr[4] != SSH_AGENT_IDENTITIES_ANSWER) {
+		*keylist = NULL;
+		return 0;
+	}
+
+	uint32_t key_blob_len = reply_len - (4+1);
+	uint8_t *key_blob_ptr = (uint8_t *)malloc(key_blob_len);
+	memcpy(key_blob_ptr, reply_ptr + (4+1), key_blob_len);
+
+	*keylist = key_blob_ptr;
+	return key_blob_len;
+}
+
+void *putty_sign_ssh2_key(unsigned char *pubkey,
+						  unsigned char *data,
+						  int datalen,
+						  int *outlen,
+						  int signflags)
+{
+	int pubkeylen = get_uint32(pubkey);
+
+	Buffer req;
+	req.append_byte(SSH_AGENTC_SIGN_REQUEST);
+	req.append_array(pubkey, 4 + pubkeylen);
+	req.append_uint32(datalen);
+	req.append_array(data, datalen);
+	req.append_uint32(signflags);
+	req.prepend_uint32((uint32_t)req.size());
+
+	Buffer rep;
+	query(req, rep);
+	const uint8_t *reply_ptr = (uint8_t *)rep.get_ptr();
+
+	if (rep.size() < 5 || reply_ptr[4] != SSH_AGENT_SIGN_RESPONSE) {
+		return NULL;
+	}
+
+	size_t signed_blob_len = rep.size() - (4+1);
+	void *signed_blob_ptr = malloc(signed_blob_len);
+	memcpy(signed_blob_ptr, reply_ptr + (4+1), signed_blob_len);
+	if (outlen)
+		*outlen = (int)signed_blob_len;
+	return signed_blob_ptr;
+}
+
+int putty_get_ssh1_keylist(unsigned char **keylist)
+{
+	(void)keylist;
+	return 0;
+}
+
+void *putty_hash_ssh1_challenge(unsigned char *pubkey,
+								int pubkeylen,
+								unsigned char *data,
+								int datalen,
+								unsigned char *session_id,
+								int *outlen)
+{
+	(void)pubkey;
+	(void)pubkeylen;
+	(void)data;
+	(void)datalen;
+	(void)session_id;
+	(void)outlen;
+	return NULL;
+}
+
+int putty_get_ssh1_keylen(unsigned char *key, int maxlen)
+{
+	(void)key;
+	(void)maxlen;
+	return 0;
+}
+
+const char *putty_get_version()
+{
+	return "libsshagent 0.1";
+}
+
+void putty_agent_query_synchronous(const void *req_ptr, int req_len, void **rep_ptr, int *rep_len)
+{
+	Buffer request;
+	request.append_array(req_ptr, req_len);
+	Buffer reply;
+	query(request, reply);
+	size_t len;
+	*rep_ptr = reply.get_mallocdbuf(&len);
+	*rep_len = (int)len;
+}
+
+#if PUTTY_NAMEDPIPE
+static BOOL check_puttyagent_namedpipe()
+{
+	char *pname = agent_named_pipe_name();
+	DWORD r = GetFileAttributesA(pname);
+	free(pname);
+	return r != INVALID_FILE_ATTRIBUTES ? TRUE : FALSE;
+}
+#endif
+
+#if MS_NAMEDPIPE
+static BOOL check_MSagent_namedpipe()
+{
+	char *ms_namedpipe = get_ms_namedpipe();
+	DWORD r = GetFileAttributesA(ms_namedpipe);
+	free(ms_namedpipe);
+	return r != INVALID_FILE_ATTRIBUTES ? TRUE : FALSE;
+}
+#endif
+
+BOOL putty_agent_exists()
+{
+#if PUTTY_NAMEDPIPE
+	if (check_puttyagent_namedpipe()) {
+		return TRUE;
+	}
+#endif
+#if PUTTY_SHM
+	HWND hwnd = FindWindowA("Pageant", "Pageant");
+	if (hwnd) {
+		return TRUE;
+	}
+#endif
+#if MS_NAMEDPIPE
+	if (check_MSagent_namedpipe()) {
+		return TRUE;
+	}
+#endif
+	return FALSE;
+}
+
+void safefree(void *p)
+{
+	free(p);
+}

Added: trunk/ttssh2/libsshagentc/sshagentc/sha256.h
===================================================================
--- trunk/ttssh2/libsshagentc/sshagentc/sha256.h	                        (rev 0)
+++ trunk/ttssh2/libsshagentc/sshagentc/sha256.h	2023-05-02 13:27:52 UTC (rev 10695)
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023- TeraTerm Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <windows.h>	// for BOOL
+#include <stdlib.h>		// for size_t
+#include <stdint.h>		// for uint8_t
+
+BOOL sha256(const void *data_ptr, size_t data_size, uint8_t buf[32]);

Added: trunk/ttssh2/libsshagentc/sshagentc/sha256_bcrypt.cpp
===================================================================
--- trunk/ttssh2/libsshagentc/sshagentc/sha256_bcrypt.cpp	                        (rev 0)
+++ trunk/ttssh2/libsshagentc/sshagentc/sha256_bcrypt.cpp	2023-05-02 13:27:52 UTC (rev 10695)
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2023- TeraTerm Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <windows.h>
+
+#include "sha256.h"
+
+static BOOL CalcHash(const void *data_ptr, size_t data_size, ALG_ID alg, void **hash_value, size_t *hash_len)
+{
+	HCRYPTPROV hProv;
+	HCRYPTHASH hHash;
+	BOOL r;
+
+	*hash_value = 0;
+	*hash_len = 0;
+
+	//DWORD dwProvType = PROV_RSA_FULL;
+	DWORD dwProvType = PROV_RSA_AES;
+	r = CryptAcquireContextA(&hProv, NULL, NULL, dwProvType, CRYPT_VERIFYCONTEXT);
+	if (r == FALSE) {
+		return FALSE;
+	}
+
+	r = CryptCreateHash(hProv, alg, 0, 0, &hHash);
+	if (r == FALSE) {
+	error_release:
+		CryptReleaseContext(hProv, 0);
+		return FALSE;
+	}
+
+	r = CryptHashData(hHash, (BYTE *)data_ptr, (DWORD)data_size, 0);
+	if (r == FALSE) {
+		goto error_release;
+	}
+
+	DWORD len;
+	CryptGetHashParam(hHash, HP_HASHVAL, NULL, &len, 0);
+	BYTE *ptr = (BYTE *)malloc(len);
+	CryptGetHashParam(hHash, HP_HASHVAL, ptr, &len, 0);
+
+	*hash_value = ptr;
+	*hash_len = len;
+
+	CryptDestroyHash(hHash);
+	CryptReleaseContext(hProv, 0);
+
+	return TRUE;
+}
+
+BOOL sha256(const void *data_ptr, size_t data_size, uint8_t buf[32])
+{
+	const size_t sha256_len = 32;
+	void *hash_value;
+	size_t hash_len;
+	ALG_ID alg = CALG_SHA_256;
+	BOOL r = CalcHash(data_ptr, data_size, alg, &hash_value, &hash_len);
+	if (r == FALSE || hash_len != sha256_len) {
+		memset(buf, 0, sha256_len);
+		return FALSE;
+	}
+	memcpy(buf, hash_value, sha256_len);
+	free(hash_value);
+	return TRUE;
+}

Added: trunk/ttssh2/libsshagentc/sshagentc/sha256_openssl.cpp
===================================================================
--- trunk/ttssh2/libsshagentc/sshagentc/sha256_openssl.cpp	                        (rev 0)
+++ trunk/ttssh2/libsshagentc/sshagentc/sha256_openssl.cpp	2023-05-02 13:27:52 UTC (rev 10695)
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023- TeraTerm Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//#include <openssl/sha.h>
+extern "C" unsigned char *SHA256(const unsigned char *d, size_t n, unsigned char *md);
+
+#include "sha256.h"
+
+BOOL sha256(const void *data_ptr, size_t data_size, uint8_t buf[32])
+{
+	SHA256((unsigned char *)data_ptr, data_size, buf);
+	return TRUE;
+}


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