From 88e5188df90e68e8fb0e909211ee7adac799d970 Mon Sep 17 00:00:00 2001 From: jet2jet <34238471+jet2jet@users.noreply.github.com> Date: Sun, 4 Jan 2026 09:20:22 +0900 Subject: [PATCH 1/7] Update libssh2 with changing build step --- .github/lib-versions.env | 2 +- .github/workflows/build-libs.yml | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/lib-versions.env b/.github/lib-versions.env index bb2e64a..92416cc 100644 --- a/.github/lib-versions.env +++ b/.github/lib-versions.env @@ -1,2 +1,2 @@ OPENSSL_BRANCH=OpenSSL_1_1_1w -LIBSSH2_VERSION=1.9.0 +LIBSSH2_VERSION=1.11.1 diff --git a/.github/workflows/build-libs.yml b/.github/workflows/build-libs.yml index b63ff98..3b31eaf 100644 --- a/.github/workflows/build-libs.yml +++ b/.github/workflows/build-libs.yml @@ -6,7 +6,7 @@ on: env: OPENSSL_REPO: https://github.com/openssl/openssl.git - LIBSSH2_REPO: https://github.com/libssh2/libssh2.git + LIBSSH2_URL: https://github.com/libssh2/libssh2 jobs: build-libs: @@ -79,7 +79,9 @@ jobs: 2>&1 | Tee-Object "logs\openssl-$arch.log" # --- libssh2 --- - git clone --depth=1 --branch "libssh2-$($env:LIBSSH2_VERSION)" $env:LIBSSH2_REPO "libssh2-$arch" + curl.exe -LO "$($env:LIBSSH2_URL)/releases/download/libssh2-$($env:LIBSSH2_VERSION)/libssh2-$($env:LIBSSH2_VERSION).zip" + Expand-Archive ".\libssh2-$($env:LIBSSH2_VERSION).zip" -DestinationPath . + Rename-Item "libssh2-$($env:LIBSSH2_VERSION)" "libssh2-$arch" Push-Location "libssh2-$arch" $libssh2Prefix = "$env:GITHUB_WORKSPACE\deps\libssh2\$arch" From 1f2d416cfd73b80dd5efe46c28c6a4f03d8a07de Mon Sep 17 00:00:00 2001 From: jet2jet <34238471+jet2jet@users.noreply.github.com> Date: Sun, 4 Jan 2026 10:09:47 +0900 Subject: [PATCH 2/7] Add jom --- .github/workflows/build-libs.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-libs.yml b/.github/workflows/build-libs.yml index 3b31eaf..5b63224 100644 --- a/.github/workflows/build-libs.yml +++ b/.github/workflows/build-libs.yml @@ -5,6 +5,7 @@ on: workflow_dispatch: env: + JOM_DOWNLOAD_URL: http://download.qt.io/official_releases/jom/jom.zip OPENSSL_REPO: https://github.com/openssl/openssl.git LIBSSH2_URL: https://github.com/libssh2/libssh2 @@ -32,6 +33,15 @@ jobs: - name: Install NASM uses: ilammy/setup-nasm@v1 + - name: Install jom + shell: cmd + run: | + curl.exe -LO "%JOM_DOWNLOAD_URL%" + set "JOM_DIR=%HOMEDRIVE%%HOMEPATH%\jom" + md "%JOM_DIR%" 2>NUL || type NUL + tar.exe xz -C "%JOM_DIR%" -f jom.zip + echo %JOM_DIR%>>%GITHUB_PATH% + - name: Setup MSBuild uses: microsoft/setup-msbuild@v2 with: @@ -75,7 +85,7 @@ jobs: $opensslPrefix = "$env:GITHUB_WORKSPACE\deps\openssl\$arch" - cmd /c "`"$vcvars`" $vc && cd openssl-$arch && perl Configure $targetOpenSSL no-shared no-tests --prefix=$opensslPrefix && nmake && nmake install" ` + cmd /c "`"$vcvars`" $vc && cd openssl-$arch && perl Configure $targetOpenSSL no-shared no-tests --prefix=$opensslPrefix /FS && jom /J 8 && jom install" ` 2>&1 | Tee-Object "logs\openssl-$arch.log" # --- libssh2 --- From f4456aa34eec5fdbaa1d7d26408685d42bbf652a Mon Sep 17 00:00:00 2001 From: jet2jet <34238471+jet2jet@users.noreply.github.com> Date: Sun, 4 Jan 2026 10:15:54 +0900 Subject: [PATCH 3/7] Update OpenSSL to 3.6.0 --- .github/lib-versions.env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/lib-versions.env b/.github/lib-versions.env index 92416cc..150a02e 100644 --- a/.github/lib-versions.env +++ b/.github/lib-versions.env @@ -1,2 +1,2 @@ -OPENSSL_BRANCH=OpenSSL_1_1_1w +OPENSSL_BRANCH=openssl-3.6.0 LIBSSH2_VERSION=1.11.1 From a2b8d6d8c83a0eda73cf06323c1020da1d2df675 Mon Sep 17 00:00:00 2001 From: jet2jet <34238471+jet2jet@users.noreply.github.com> Date: Sun, 4 Jan 2026 15:55:10 +0900 Subject: [PATCH 4/7] Suppress logs for Expand-Archive --- .github/workflows/build-libs.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-libs.yml b/.github/workflows/build-libs.yml index 5b63224..c14a570 100644 --- a/.github/workflows/build-libs.yml +++ b/.github/workflows/build-libs.yml @@ -90,8 +90,10 @@ jobs: # --- libssh2 --- curl.exe -LO "$($env:LIBSSH2_URL)/releases/download/libssh2-$($env:LIBSSH2_VERSION)/libssh2-$($env:LIBSSH2_VERSION).zip" + Set-PSDebug -Off Expand-Archive ".\libssh2-$($env:LIBSSH2_VERSION).zip" -DestinationPath . Rename-Item "libssh2-$($env:LIBSSH2_VERSION)" "libssh2-$arch" + Set-PSDebug -Trace 1 Push-Location "libssh2-$arch" $libssh2Prefix = "$env:GITHUB_WORKSPACE\deps\libssh2\$arch" From c72b2cb72390c0e8d0f93c62062b1250493dd8d6 Mon Sep 17 00:00:00 2001 From: jet2jet <34238471+jet2jet@users.noreply.github.com> Date: Sun, 4 Jan 2026 16:11:19 +0900 Subject: [PATCH 5/7] Fix for migrating to libssh2 1.11.1 --- ShellDLL/Auth.cpp | 56 ++++++++++++++++++++++++++++++++++++------- ShellDLL/Auth.h | 2 ++ ShellDLL/SSHAgent.cpp | 4 ++-- ShellDLL/SSHAgent.h | 6 ++++- ShellDLL/stdafx.h | 2 ++ 5 files changed, 58 insertions(+), 12 deletions(-) diff --git a/ShellDLL/Auth.cpp b/ShellDLL/Auth.cpp index 4bfc7cd..9306f21 100644 --- a/ShellDLL/Auth.cpp +++ b/ShellDLL/Auth.cpp @@ -351,6 +351,10 @@ bool CAuthentication::CanRetry(IEasySFTPAuthentication* pAuth) if (!pAuthSession->lpPageantKeyList) return false; + + if (AssignAgentFlags(pAuthSession)) + return true; + pAuthSession->dwKeyIndex++; if (pAuthSession->dwKeyIndex >= pAuthSession->dwKeyCount) { @@ -363,6 +367,33 @@ bool CAuthentication::CanRetry(IEasySFTPAuthentication* pAuth) pAuthSession->lpCurrentKey += dw + 4; dw = ConvertEndian(*reinterpret_cast(pAuthSession->lpCurrentKey)); pAuthSession->lpCurrentKey += dw + 4; + pAuthSession->nPrevFlags = -1; + return AssignAgentFlags(pAuthSession); +} + +bool CAuthentication::AssignAgentFlags(CAuthSession* pAuthSession) +{ + if (pAuthSession->nPrevFlags == 0) + return false; + // get key type data (in the head of blob data) + DWORD dwKeyTypeLen = ConvertEndian(*((DWORD*)(pAuthSession->lpCurrentKey + 4))); + LPCSTR lpszKeyType = (LPCSTR)(pAuthSession->lpCurrentKey + 8); + + if ((dwKeyTypeLen == 7 && memcmp(lpszKeyType, "ssh-rsa", dwKeyTypeLen) == 0) || + (dwKeyTypeLen == 28 && memcmp(lpszKeyType, "ssh-rsa-cert-v01@openssh.com", dwKeyTypeLen) == 0)) + { + // both rsa-sha2-512 and rsa-sha2-256 are supported, so use rsa-sha2-512 + if (pAuthSession->nPrevFlags < 0) + pAuthSession->nPrevFlags = SSH_AGENT_RSA_SHA2_512; + else if (pAuthSession->nPrevFlags == SSH_AGENT_RSA_SHA2_512) + pAuthSession->nPrevFlags = SSH_AGENT_RSA_SHA2_256; + else + pAuthSession->nPrevFlags = 0; + } + else + { + pAuthSession->nPrevFlags = 0; + } return true; } @@ -403,47 +434,49 @@ AuthReturnType CAuthentication::SSHAuthenticateWithAgent(IEasySFTPAuthentication pAuthSession->dwKeyCount = ConvertEndian(*((DWORD*)lpKeyList)); pAuthSession->dwKeyIndex = 0; pAuthSession->lpCurrentKey = lpKeyList + 4; + pAuthSession->nPrevFlags = -1; if (FAILED(pAuth->put_AuthSession(reinterpret_cast<__int3264>(pAuthSession)))) { delete pAuthSession; return AuthReturnType::Error; } + AssignAgentFlags(pAuthSession); } LPBYTE p = pAuthSession->lpCurrentKey; - LPCSTR lpszKeyType; LPCBYTE pBlob; size_t nBlobLen; - // get key type data (in the head of blob data) - DWORD dwKeyTypeLen = ConvertEndian(*((DWORD*)(p + 4))); - lpszKeyType = (LPCSTR)(p + 8); - nBlobLen = (size_t)ConvertEndian(*((DWORD*)p)); pBlob = (p + 4); p += nBlobLen + 4; - // get the comment of key { + DWORD dwKeyTypeLen = ConvertEndian(*((DWORD*)(pBlob))); + LPCSTR lpszKeyType = (LPCSTR)(pBlob + 4); + + // get the comment of key DWORD dwCommentLen = ConvertEndian(*((DWORD*)p)); CMyStringW str; str.SetUTF8String((LPCBYTE)(p + 4), static_cast(dwCommentLen)); p += dwCommentLen + 4; - CMyStringW strType(lpszKeyType), strDebug; + CMyStringW strType, strDebug; + strType.SetString(lpszKeyType, dwKeyTypeLen); strDebug.Format(L"trying key '%s' (type: %s)", str.operator LPCWSTR(), strType.operator LPCWSTR()); theApp.Log(EasySFTPLogLevel::Debug, strDebug, S_OK); } void* abstract = pAuthSession; auto ret = libssh2_userauth_publickey(pSession, lpszUser, pBlob, nBlobLen, - [](LIBSSH2_SESSION*, LPBYTE* sig, size_t* sig_len, LPCBYTE data, size_t data_len, void** abstract) -> int + [](LIBSSH2_SESSION* session, LPBYTE* sig, size_t* sig_len, LPCBYTE data, size_t data_len, void** abstract) -> int { *sig = NULL; *sig_len = 0; CAuthSession* pAuthSession = static_cast(*abstract); LPBYTE lpCurrentKey = pAuthSession->lpCurrentKey; + size_t nSignedLen; - auto buff = pAuthSession->pAgent->SignSSH2Key(lpCurrentKey, data, data_len, &nSignedLen); + auto buff = pAuthSession->pAgent->SignSSH2Key(lpCurrentKey, pAuthSession->nPrevFlags, data, data_len, &nSignedLen); LPBYTE pSignedData = static_cast(buff); if (nSignedLen < 4 || !buff) { @@ -505,7 +538,12 @@ AuthReturnType CAuthentication::SSHAuthenticateWithAgent(IEasySFTPAuthentication return AuthReturnType::Again; if (ret != 0) + { + // trying any flags only needed when error is 'unverified' + if (ret != LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED) + pAuthSession->nPrevFlags = 0; return AuthReturnType::Error; + } delete pAuthSession; pAuth->put_AuthSession(reinterpret_cast<__int3264>(nullptr)); diff --git a/ShellDLL/Auth.h b/ShellDLL/Auth.h index 7153936..d407f37 100644 --- a/ShellDLL/Auth.h +++ b/ShellDLL/Auth.h @@ -37,6 +37,7 @@ struct CAuthSession LPBYTE lpCurrentKey; DWORD dwKeyCount; DWORD dwKeyIndex; + int nPrevFlags; ~CAuthSession(); }; @@ -69,6 +70,7 @@ class CAuthentication : public CDispatchImplT static bool CanRetry(IEasySFTPAuthentication* pAuth); private: + static bool AssignAgentFlags(CAuthSession* pAuthSession); static AuthReturnType SSHAuthenticateWithAgent(IEasySFTPAuthentication* pAuth, CMyStringW& strUserName, LIBSSH2_SESSION* pSession, LPCSTR lpszService, CSSHAgent* (* CreateAgent)()); public: diff --git a/ShellDLL/SSHAgent.cpp b/ShellDLL/SSHAgent.cpp index aeb4b55..b0fb923 100644 --- a/ShellDLL/SSHAgent.cpp +++ b/ShellDLL/SSHAgent.cpp @@ -62,7 +62,7 @@ int CSSHAgent::GetKeyList2(LPBYTE* ppKeyList) return static_cast(nResponseLen) - 5; } -void* CSSHAgent::SignSSH2Key(LPCBYTE pszPubKey, LPCBYTE pszData, size_t nDataLen, size_t* pnOutLen) +void* CSSHAgent::SignSSH2Key(LPCBYTE pszPubKey, int flags, LPCBYTE pszData, size_t nDataLen, size_t* pnOutLen) { void* ret; @@ -85,7 +85,7 @@ void* CSSHAgent::SignSSH2Key(LPCBYTE pszPubKey, LPCBYTE pszData, size_t nDataLen // sign data (length + data) request.AppendToBufferWithLenCE(pszData, nDataLen); // flags - request.AppendToBufferCE(static_cast(0)); + request.AppendToBufferCE(static_cast(flags)); retval = Query(request, nReqLen, (void**)&pResponse, &nResponseLen); if (!retval) diff --git a/ShellDLL/SSHAgent.h b/ShellDLL/SSHAgent.h index 44a71ed..cff8eb4 100644 --- a/ShellDLL/SSHAgent.h +++ b/ShellDLL/SSHAgent.h @@ -1,5 +1,9 @@ #pragma once +/* Signature request methods */ +#define SSH_AGENT_RSA_SHA2_256 2 +#define SSH_AGENT_RSA_SHA2_512 4 + class __declspec(novtable) CSSHAgent { public: @@ -8,6 +12,6 @@ class __declspec(novtable) CSSHAgent public: int GetKeyList2(LPBYTE* ppKeyList); - void* SignSSH2Key(LPCBYTE pszPubKey, LPCBYTE pszData, size_t nDataLen, size_t* pnOutLen); + void* SignSSH2Key(LPCBYTE pszPubKey, int flags, LPCBYTE pszData, size_t nDataLen, size_t* pnOutLen); void FreeKeyList(LPBYTE pKeyList); }; diff --git a/ShellDLL/stdafx.h b/ShellDLL/stdafx.h index 0f74d89..92ec8a3 100644 --- a/ShellDLL/stdafx.h +++ b/ShellDLL/stdafx.h @@ -74,6 +74,8 @@ typedef IDataObjectAsyncCapability IAsyncOperation; #include // libssh2 +// woraround definition (related: https://github.com/libssh2/libssh2/issues/1578 ) +#define LIBSSH2_API #include #include From 4c65005b84320d3a61e9a14a7fd903244c1d8f9a Mon Sep 17 00:00:00 2001 From: jet2jet <34238471+jet2jet@users.noreply.github.com> Date: Sun, 4 Jan 2026 16:15:50 +0900 Subject: [PATCH 6/7] Remove deprecated (non-necessary) function call --- ShellDLL/ShellDLL.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/ShellDLL/ShellDLL.cpp b/ShellDLL/ShellDLL.cpp index 48c1f37..f7cf2b0 100644 --- a/ShellDLL/ShellDLL.cpp +++ b/ShellDLL/ShellDLL.cpp @@ -1232,9 +1232,6 @@ bool CMainDLL::InitInstance() // for SSL library SSL_library_init(); - ERR_load_BIO_strings(); - ERR_load_CRYPTO_strings(); - ERR_load_SSL_strings(); ::srand((unsigned int) (time(NULL) * GetTickCount())); @@ -1661,13 +1658,9 @@ int CMainDLL::ExitInstance() ::DeleteCriticalSection(&m_csHosts); ::DeleteCriticalSection(&m_csRootRefs); - ::ERR_remove_state(0); //::ENGINE_cleanup(); //::CONF_modules_unload(); //::RAND_cleanup(); - ERR_free_strings(); - EVP_cleanup(); - CRYPTO_cleanup_all_ex_data(); libssh2_exit(); m_TimerThread.Finalize(); From f6d1d651bb184191012d8e92dd128c84a2603439 Mon Sep 17 00:00:00 2001 From: jet2jet <34238471+jet2jet@users.noreply.github.com> Date: Sun, 4 Jan 2026 16:34:41 +0900 Subject: [PATCH 7/7] Add workaround for x86 --- ShellDLL/ShellDLL.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ShellDLL/ShellDLL.cpp b/ShellDLL/ShellDLL.cpp index f7cf2b0..e85695a 100644 --- a/ShellDLL/ShellDLL.cpp +++ b/ShellDLL/ShellDLL.cpp @@ -53,6 +53,13 @@ ITypeInfo* GetTypeInfo(const GUID& guid) //////////////////////////////////////////////////////////////////////////////// +// workaround (related: https://github.com/openssl/openssl/issues/27701 ) +#if !defined(WIN64) +extern "C" unsigned _int64 _dtoul3_legacy(double v) { return (unsigned _int64)llround(v); } +#endif + +//////////////////////////////////////////////////////////////////////////////// + #if !defined(NTDDI_WIN7) || (NTDDI_VERSION < NTDDI_WIN7) #define INITGUID #include