Merge branch 'L1' into L2-Win32Posix-Prototype

This commit is contained in:
Manoj Ampalam 2016-01-18 22:37:55 -08:00
commit 888020265b
38 changed files with 2261 additions and 1056 deletions

1
.gitignore vendored
View File

@ -276,3 +276,4 @@ Makefile.in
#temp key files #temp key files
d2utmpa* d2utmpa*
configure configure
contrib/win32/openssh/Win32-OpenSSH.VC.opendb

View File

@ -114,6 +114,14 @@ ssh_get_authentication_socket(int *fdp)
errno = oerrno; errno = oerrno;
return SSH_ERR_SYSTEM_ERROR; return SSH_ERR_SYSTEM_ERROR;
} }
#else
if (
connect(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
oerrno = errno;
close(sock);
errno = oerrno;
return SSH_ERR_SYSTEM_ERROR;
}
#endif /* #ifndef WIN32_FIXME */ #endif /* #ifndef WIN32_FIXME */
if (fdp != NULL) if (fdp != NULL)

View File

@ -103,6 +103,12 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssh-lsa", "ssh-lsa.vcxproj", "{02FB3D98-6516-42C6-9762-98811A99960F}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssh-lsa", "ssh-lsa.vcxproj", "{02FB3D98-6516-42C6-9762-98811A99960F}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scp", "scp.vcxproj", "{29B98ADF-1285-49CE-BF6C-AA92C5D2FB24}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scp", "scp.vcxproj", "{29B98ADF-1285-49CE-BF6C-AA92C5D2FB24}"
ProjectSection(ProjectDependencies) = postProject
{05E1115F-8529-46D0-AAAF-52A404CE79A7} = {05E1115F-8529-46D0-AAAF-52A404CE79A7}
{8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} = {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4}
{DD483F7D-C553-4740-BC1A-903805AD0174} = {DD483F7D-C553-4740-BC1A-903805AD0174}
{8660C2FE-9874-432D-B047-E042BB41DBE0} = {8660C2FE-9874-432D-B047-E042BB41DBE0}
EndProjectSection
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution

View File

@ -258,6 +258,13 @@
<ClCompile Include="$(OpenSSH-Src-Path)uuencode.c" /> <ClCompile Include="$(OpenSSH-Src-Path)uuencode.c" />
<ClCompile Include="$(OpenSSH-Src-Path)verify.c" /> <ClCompile Include="$(OpenSSH-Src-Path)verify.c" />
<ClCompile Include="$(OpenSSH-Src-Path)xmalloc.c" /> <ClCompile Include="$(OpenSSH-Src-Path)xmalloc.c" />
<ClCompile Include="$(OpenSSH-Src-Path)openssl-bn.c" />
<ClCompile Include="$(OpenSSH-Src-Path)openssl-dh.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(OpenSSH-Src-Path)crypto-wrap.h" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">

View File

@ -288,5 +288,16 @@
<ClCompile Include="$(OpenSSH-Src-Path)xmalloc.c"> <ClCompile Include="$(OpenSSH-Src-Path)xmalloc.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\..\openssl-dh.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\openssl-bn.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\crypto-wrap.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -114,6 +114,9 @@
<AdditionalLibraryDirectories>$(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Debug-Path)lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Debug-Path)lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;win32compat.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;win32compat.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
<Manifest>
<AdditionalManifestFiles>targetos.manifest</AdditionalManifestFiles>
</Manifest>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile> <ClCompile>
@ -133,6 +136,9 @@
<AdditionalLibraryDirectories>$(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Debug-Path)lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Debug-Path)lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;win32compat.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;win32compat.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
<Manifest>
<AdditionalManifestFiles>targetos.manifest</AdditionalManifestFiles>
</Manifest>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile> <ClCompile>
@ -154,6 +160,9 @@
<AdditionalLibraryDirectories>$(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Release-Path)lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Release-Path)lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;win32compat.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;win32compat.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
<Manifest>
<AdditionalManifestFiles>targetos.manifest</AdditionalManifestFiles>
</Manifest>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile> <ClCompile>
@ -176,6 +185,9 @@
<AdditionalLibraryDirectories>$(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Release-Path)lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Release-Path)lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;win32compat.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>bcrypt.lib;Userenv.lib;Ws2_32.lib;Secur32.lib;Shlwapi.lib;openbsd_compat.lib;libssh.lib;win32compat.lib;libeay32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
<Manifest>
<AdditionalManifestFiles>targetos.manifest</AdditionalManifestFiles>
</Manifest>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="$(OpenSSH-Src-Path)acss.h" /> <ClInclude Include="$(OpenSSH-Src-Path)acss.h" />

View File

@ -110,6 +110,9 @@
<AdditionalLibraryDirectories>$(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Debug-Path)lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Debug-Path)lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ForceFileOutput>MultiplyDefinedSymbolOnly</ForceFileOutput> <ForceFileOutput>MultiplyDefinedSymbolOnly</ForceFileOutput>
</Link> </Link>
<Manifest>
<AdditionalManifestFiles>targetos.manifest</AdditionalManifestFiles>
</Manifest>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile> <ClCompile>
@ -130,6 +133,9 @@
<AdditionalLibraryDirectories>$(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Debug-Path)lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Debug-Path)lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ForceFileOutput>MultiplyDefinedSymbolOnly</ForceFileOutput> <ForceFileOutput>MultiplyDefinedSymbolOnly</ForceFileOutput>
</Link> </Link>
<Manifest>
<AdditionalManifestFiles>targetos.manifest</AdditionalManifestFiles>
</Manifest>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile> <ClCompile>
@ -153,6 +159,9 @@
<AdditionalLibraryDirectories>$(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Release-Path)lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Release-Path)lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ForceFileOutput>MultiplyDefinedSymbolOnly</ForceFileOutput> <ForceFileOutput>MultiplyDefinedSymbolOnly</ForceFileOutput>
</Link> </Link>
<Manifest>
<AdditionalManifestFiles>targetos.manifest</AdditionalManifestFiles>
</Manifest>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile> <ClCompile>
@ -177,6 +186,9 @@
<AdditionalLibraryDirectories>$(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Release-Path)lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>$(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Release-Path)lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<ForceFileOutput>MultiplyDefinedSymbolOnly</ForceFileOutput> <ForceFileOutput>MultiplyDefinedSymbolOnly</ForceFileOutput>
</Link> </Link>
<Manifest>
<AdditionalManifestFiles>targetos.manifest</AdditionalManifestFiles>
</Manifest>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="$(OpenSSH-Src-Path)audit-bsm.c" /> <ClCompile Include="$(OpenSSH-Src-Path)audit-bsm.c" />

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
* <!-- Windows 8.1 -->
* <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
</application>
</compatibility>
</assembly>

View File

@ -159,6 +159,13 @@
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\tncon.c" /> <ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\tncon.c" />
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\tnnet.c" /> <ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\tnnet.c" />
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\win32auth.c" /> <ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\win32auth.c" />
<ClCompile Include="..\win32compat\cng_dh.c">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\cng_openssl_dh.c" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\ansiprsr.h" /> <ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\ansiprsr.h" />
@ -175,6 +182,7 @@
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\tncon.h" /> <ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\tncon.h" />
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\tnnet.h" /> <ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\tnnet.h" />
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\win32auth.h" /> <ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\win32auth.h" />
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\cng_kex.h" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">

View File

@ -81,6 +81,12 @@
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\win32auth.c"> <ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\win32auth.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\cng_kex.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\win32compat\cng_openssl_dh.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\ansiprsr.h"> <ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\ansiprsr.h">
@ -125,5 +131,11 @@
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\win32auth.h"> <ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\win32auth.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\cng_kex.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\win32compat\cng-wrap.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,324 @@
#include <windows.h>
#include <bcrypt.h>
#include <openssl/bn.h>
#include <VersionHelpers.h>
#include <dh.h>
#include "crypto-wrap.h"
// CNG Diffie-hellman Kex context
typedef struct cng_dh_ctx {
int size;
PBYTE g;
PBYTE p;
PBYTE pub;
BCRYPT_KEY_HANDLE hPrivate;
BCRYPT_ALG_HANDLE hAlg;
} CNG_DH_CTX;
struct sshdh {
CNG_DH_CTX *dh;
};
//function to reverse the order of a byte array
static void
cng_dh_swap_bytes(void *pv, size_t n)
{
char *p = (char*)pv;
size_t lo, hi;
for (lo = 0, hi = n - 1; hi>lo; lo++, hi--)
{
char tmp = p[lo];
p[lo] = p[hi];
p[hi] = tmp;
}
}
/* DH wrappers */
struct sshdh *
sshdh_new(void)
{
return (struct sshdh *)(malloc(sizeof(struct sshdh)));
}
void
sshdh_free(struct sshdh *dh)
{
if (dh != NULL) {
if (dh->dh != NULL)
{
CNG_DH_CTX * pCtx = (CNG_DH_CTX*)dh->dh;
if (pCtx->hAlg)
BCryptCloseAlgorithmProvider(pCtx->hAlg, 0);
if (pCtx->hPrivate)
BCryptDestroyKey(pCtx->hPrivate);
ZeroMemory(pCtx, sizeof(*pCtx));
free(pCtx);
}
free(dh);
}
}
struct sshbn *
sshdh_pubkey(struct sshdh *dh)
{
CNG_DH_CTX *pCtx = dh->dh;
struct sshbn * bn = NULL;
sshbn_from(pCtx->pub, pCtx->size, &bn);
return bn;
}
struct sshbn *
sshdh_p(struct sshdh *dh)
{
CNG_DH_CTX *pCtx = dh->dh;
struct sshbn * bn = NULL;
sshbn_from(pCtx->p, pCtx->size, &bn);
return bn;
}
struct sshbn *
sshdh_g(struct sshdh *dh)
{
CNG_DH_CTX *pCtx = dh->dh;
struct sshbn * bn = NULL;
sshbn_from(pCtx->g, pCtx->size, &bn);
return bn;
}
void
sshdh_dump(struct sshdh *dh)
{
return;
}
// XXX needed?
size_t
sshdh_shared_key_size(struct sshdh *dh)
{
int sz;
CNG_DH_CTX *pCtx = dh->dh;
if (dh == NULL || dh->dh == NULL || (sz = pCtx->size) < 0)
return 0;
return (size_t)sz;
}
// import a bignum public key
static BCRYPT_KEY_HANDLE
cng_dh_set_remote_pub_key2(struct sshdh *dh, struct sshbn *b)
{
BCRYPT_KEY_HANDLE hPub = NULL;
CNG_DH_CTX *pCtx = dh->dh;
if (sshbn_bytes(b) > pCtx->size)
return NULL;
DWORD cbBlob = sizeof(BCRYPT_DH_KEY_BLOB) + (pCtx->size * 3);
PBYTE pBlob = (PBYTE)malloc(cbBlob);
BCRYPT_DH_KEY_BLOB *pKeyBlob = (BCRYPT_DH_KEY_BLOB *)pBlob;
pKeyBlob->cbKey = pCtx->size;
pKeyBlob->dwMagic = BCRYPT_DH_PUBLIC_MAGIC;
PBYTE pModulus = pBlob + sizeof(BCRYPT_DH_KEY_BLOB);
PBYTE pGenerator = pModulus + pKeyBlob->cbKey;
PBYTE pPublic = pGenerator + pKeyBlob->cbKey;
memcpy(pModulus, pCtx->p, pCtx->size);
memcpy(pGenerator, pCtx->g, pCtx->size);
memset(pPublic, 0, pCtx->size);
sshbn_to(b, pPublic + pCtx->size - (sshbn_bytes(b)));
HRESULT Status = 0;
if (S_OK != (Status = BCryptImportKeyPair(pCtx->hAlg, NULL, BCRYPT_DH_PUBLIC_BLOB, &hPub, pBlob, cbBlob, 0)))
goto cleanup;
cleanup:
if (pBlob) free(pBlob);
return hPub;
}
int sshdh_compute_key(struct sshdh *dh, struct sshbn *pubkey,
struct sshbn **shared_secretp)
{
HRESULT hr = S_OK;
CNG_DH_CTX *pCtx = dh->dh;
PBYTE pSecret = (PBYTE)malloc(pCtx->size);
DWORD pSecret_len = pCtx->size;
DWORD size = pCtx->size;
struct sshbn * bn = NULL;
BCRYPT_SECRET_HANDLE hSecret;
BCRYPT_KEY_HANDLE hRemotePub = cng_dh_set_remote_pub_key2(dh, pubkey);
if (hRemotePub != NULL)
{
if (S_OK == (hr = BCryptSecretAgreement(pCtx->hPrivate, hRemotePub, &hSecret, 0)))
{
hr = BCryptDeriveKey(hSecret, L"TRUNCATE", NULL, pSecret, pSecret_len, &size, 0);
if (S_OK == hr)
{
cng_dh_swap_bytes(pSecret, size);
sshbn_from(pSecret, size, &bn);
memset(pSecret, 0, size);
free(pSecret);
*shared_secretp = bn;
}
BCryptDestroySecret(hSecret);
}
}
return S_OK==hr?0:-1;
}
int
sshdh_generate(struct sshdh *dh, size_t len)
{
HRESULT Status;
BCRYPT_DH_PARAMETER_HEADER *DhParamHdrPointer = NULL;
DWORD DhParamBlobLength = 0;
PBYTE DhParamBlob = NULL;
BCRYPT_ALG_HANDLE hAlg = NULL;
PBYTE pBlob = NULL;
BCRYPT_KEY_HANDLE hPriv = NULL;
CNG_DH_CTX *pCtx = dh->dh;
DWORD cbBlob = 0;
DhParamBlobLength = sizeof(BCRYPT_DH_PARAMETER_HEADER) + (pCtx->size * 2);
if (NULL == (DhParamBlob = (PBYTE)malloc(DhParamBlobLength)))
return -1;
DhParamHdrPointer = (BCRYPT_DH_PARAMETER_HEADER *)DhParamBlob;
DhParamHdrPointer->cbLength = DhParamBlobLength;
DhParamHdrPointer->cbKeyLength = pCtx->size;
DhParamHdrPointer->dwMagic = BCRYPT_DH_PARAMETERS_MAGIC;
memcpy(DhParamBlob + sizeof(BCRYPT_DH_PARAMETER_HEADER), pCtx->p, pCtx->size);
memcpy(DhParamBlob + sizeof(BCRYPT_DH_PARAMETER_HEADER) + pCtx->size, pCtx->g, pCtx->size);
if (S_OK != (Status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_DH_ALGORITHM, NULL, 0)))
goto error;
if (S_OK != (Status = BCryptGenerateKeyPair(hAlg, &hPriv, pCtx->size*8, 0)))
goto error;
if (S_OK != (Status = BCryptSetProperty(hPriv, BCRYPT_DH_PARAMETERS, DhParamBlob, DhParamBlobLength, 0)))
goto error;
if (S_OK != (Status = BCryptFinalizeKeyPair(hPriv, 0)))
goto error;
if (S_OK != (Status = BCryptExportKey(hPriv, NULL, BCRYPT_DH_PUBLIC_BLOB, NULL, 0, &cbBlob, 0)))
goto error;
if (NULL == (pBlob = (PBYTE)malloc(cbBlob)))
{
Status = STATUS_NO_MEMORY;
goto error;
}
if (S_OK != (Status = BCryptExportKey(hPriv, NULL, BCRYPT_DH_PUBLIC_BLOB, pBlob, cbBlob, &cbBlob, 0)))
goto error;
BCRYPT_DH_KEY_BLOB *pKeyBlob = (BCRYPT_DH_KEY_BLOB *)pBlob;
PBYTE pModulus = pBlob + sizeof(BCRYPT_DH_KEY_BLOB);
PBYTE pGenerator = pModulus + pKeyBlob->cbKey;
PBYTE pPublic = pGenerator + pKeyBlob->cbKey;
pCtx->hAlg = hAlg;
pCtx->hPrivate = hPriv;
memcpy(pCtx->pub, pPublic, pCtx->size);
return 0;
error:
return -1;
}
int
sshdh_new_group_hex(const char *gen, const char *modulus, struct sshdh **dhp)
{
struct sshdh *ret;
struct sshbn * g = NULL;
struct sshbn * p = NULL;
sshbn_from_hex(gen, &g);
sshbn_from_hex(modulus, &p);
*dhp = NULL;
ret = sshdh_new_group(g, p);
if (g != NULL)
sshbn_free(g);
if (p != NULL)
sshbn_free(p);
*dhp = ret;
return 0;
}
/* XXX transfers ownership of gen, modulus */
struct sshdh *
sshdh_new_group(struct sshbn *gen, struct sshbn *modulus)
{
struct sshdh *dh;
PBYTE pBlob = NULL;
DWORD keysize = sshbn_bytes(modulus);
DWORD cbBlob = 0;
dh = sshdh_new();
pBlob = (PBYTE)malloc(sizeof(CNG_DH_CTX) + (3 * keysize));
memset(pBlob, 0, sizeof(CNG_DH_CTX) + (3 * keysize));
CNG_DH_CTX * pCtx = (CNG_DH_CTX *)pBlob;
pCtx->size = keysize;
pCtx->p = pBlob + sizeof(CNG_DH_CTX);
pCtx->g = pCtx->p + keysize;
pCtx->pub = pCtx->g + keysize;
sshbn_to(gen, pCtx->g + keysize - sshbn_bytes(gen));
sshbn_to(modulus, pCtx->p + keysize - sshbn_bytes(modulus));
dh->dh = pCtx;
return dh;
}

View File

@ -0,0 +1,487 @@
#include <includes.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <openssl/dh.h>
#include <openssl/evp.h>
#include <openssl/bn.h>
#include "sshbuf.h"
#include "packet.h"
#include "ssherr.h"
#include <bcrypt.h>
#include "crypto-wrap.h"
#include <VersionHelpers.h>
// CNG Diffie-hellman Kex context
typedef struct cng_dh_ctx {
int size;
PBYTE g;
PBYTE p;
PBYTE pub;
BCRYPT_KEY_HANDLE hPrivate;
BCRYPT_ALG_HANDLE hAlg;
} CNG_DH_CTX;
struct sshdh {
void *dh;
};
struct sshbn {
BIGNUM *bn;
};
int cng_supported(void)
{
return (IsWindows8Point1OrGreater());
}
//function to reverse the order of a byte array
static void
cng_dh_swap_bytes(void *pv, size_t n)
{
char *p = (char*)pv;
size_t lo, hi;
for (lo = 0, hi = n - 1; hi>lo; lo++, hi--)
{
char tmp = p[lo];
p[lo] = p[hi];
p[hi] = tmp;
}
}
static struct sshbn *
bnwrap(BIGNUM *bn)
{
struct sshbn *ret;
if (bn == NULL)
return NULL;
if ((ret = calloc(1, sizeof(*ret))) == NULL)
return NULL;
if ((ret->bn = BN_dup(bn)) == NULL) {
free(ret);
return NULL;
}
return ret;
}
/* DH wrappers */
struct sshdh *
sshdh_new(void)
{
if (!cng_supported())
{
struct sshdh *ret;
if ((ret = calloc(1, sizeof(*ret))) == NULL)
return NULL;
if ((ret->dh = DH_new()) == NULL) {
free(ret);
return NULL;
}
return ret;
}
return (struct sshdh *)(malloc(sizeof(struct sshdh)));
}
void
sshdh_free(struct sshdh *dh)
{
if (!cng_supported())
{
if (dh != NULL) {
if (dh->dh != NULL)
DH_free(dh->dh);
explicit_bzero(dh, sizeof(*dh));
free(dh);
}
return;
}
if (dh != NULL) {
if (dh->dh != NULL)
{
CNG_DH_CTX * pCtx = (CNG_DH_CTX*)dh->dh;
if (pCtx->hAlg)
BCryptCloseAlgorithmProvider(pCtx->hAlg, 0);
if (pCtx->hPrivate)
BCryptDestroyKey(pCtx->hPrivate);
ZeroMemory(pCtx, sizeof(*pCtx));
free(pCtx);
}
free(dh);
}
}
struct sshbn *
sshdh_pubkey(struct sshdh *dh)
{
if (!cng_supported())
{
return bnwrap(((DH *)(dh->dh))->pub_key);
}
CNG_DH_CTX *pCtx = (CNG_DH_CTX*)dh->dh;
struct sshbn * bn = NULL;
sshbn_from(pCtx->pub, pCtx->size, &bn);
return bn;
}
struct sshbn *
sshdh_p(struct sshdh *dh)
{
if (!cng_supported())
{
return bnwrap(((DH *)(dh->dh))->p);
}
CNG_DH_CTX *pCtx = (CNG_DH_CTX*)dh->dh;
struct sshbn * bn = NULL;
sshbn_from(pCtx->p, pCtx->size, &bn);
return bn;
}
struct sshbn *
sshdh_g(struct sshdh *dh)
{
if (!cng_supported())
{
return bnwrap(((DH *)(dh->dh))->g);
}
CNG_DH_CTX *pCtx = (CNG_DH_CTX*)dh->dh;
struct sshbn * bn = NULL;
sshbn_from(pCtx->g, pCtx->size, &bn);
return bn;
}
void
sshdh_dump(struct sshdh *dh)
{
if (!cng_supported())
{
DHparams_print_fp(stderr, dh->dh);
fprintf(stderr, "pub= ");
BN_print_fp(stderr, ((DH*)(dh->dh))->pub_key);
fprintf(stderr, "\n");
}
return;
}
// XXX needed?
size_t
sshdh_shared_key_size(struct sshdh *dh)
{
if (!cng_supported())
{
int sz;
if (dh == NULL || dh->dh == NULL || (sz = DH_size(dh->dh)) < 0)
return 0;
return (size_t)sz;
}
int sz;
CNG_DH_CTX *pCtx = (CNG_DH_CTX*)dh->dh;
if (dh == NULL || dh->dh == NULL || (sz = pCtx->size) < 0)
return 0;
return (size_t)sz;
}
// import a bignum public key
static BCRYPT_KEY_HANDLE
cng_dh_set_remote_pub_key2(struct sshdh *dh, struct sshbn *b)
{
BCRYPT_KEY_HANDLE hPub = NULL;
CNG_DH_CTX *pCtx = (CNG_DH_CTX*)dh->dh;
if (sshbn_bytes(b) > pCtx->size)
return NULL;
DWORD cbBlob = sizeof(BCRYPT_DH_KEY_BLOB) + (pCtx->size * 3);
PBYTE pBlob = (PBYTE)malloc(cbBlob);
BCRYPT_DH_KEY_BLOB *pKeyBlob = (BCRYPT_DH_KEY_BLOB *)pBlob;
pKeyBlob->cbKey = pCtx->size;
pKeyBlob->dwMagic = BCRYPT_DH_PUBLIC_MAGIC;
PBYTE pModulus = pBlob + sizeof(BCRYPT_DH_KEY_BLOB);
PBYTE pGenerator = pModulus + pKeyBlob->cbKey;
PBYTE pPublic = pGenerator + pKeyBlob->cbKey;
memcpy(pModulus, pCtx->p, pCtx->size);
memcpy(pGenerator, pCtx->g, pCtx->size);
memset(pPublic, 0, pCtx->size);
sshbn_to(b, pPublic + pCtx->size - (sshbn_bytes(b)));
HRESULT Status = 0;
if (S_OK != (Status = BCryptImportKeyPair(pCtx->hAlg, NULL, BCRYPT_DH_PUBLIC_BLOB, &hPub, pBlob, cbBlob, 0)))
goto cleanup;
cleanup:
if (pBlob) free(pBlob);
return hPub;
}
int sshdh_compute_key(struct sshdh *dh, struct sshbn *pubkey,
struct sshbn **shared_secretp)
{
if (!cng_supported())
{
u_char *sbuf;
int r, slen;
*shared_secretp = NULL;
if ((slen = DH_size(dh->dh)) <= 0)
return SSH_ERR_INVALID_ARGUMENT;
if ((sbuf = calloc(1, slen)) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = DH_compute_key(sbuf, pubkey->bn, dh->dh)) < 0 ||
r != slen) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
if ((r = sshbn_from(sbuf, slen, shared_secretp)) != 0)
goto out;
/* success */
r = 0;
out:
explicit_bzero(sbuf, slen);
free(sbuf);
return r;
}
HRESULT hr = S_OK;
CNG_DH_CTX *pCtx = (CNG_DH_CTX*)dh->dh;
PBYTE pSecret = (PBYTE)malloc(pCtx->size);
DWORD pSecret_len = pCtx->size;
DWORD size = pCtx->size;
struct sshbn * bn = NULL;
BCRYPT_SECRET_HANDLE hSecret;
BCRYPT_KEY_HANDLE hRemotePub = cng_dh_set_remote_pub_key2(dh, pubkey);
if (hRemotePub != NULL)
{
if (S_OK == (hr = BCryptSecretAgreement(pCtx->hPrivate, hRemotePub, &hSecret, 0)))
{
hr = BCryptDeriveKey(hSecret, L"TRUNCATE", NULL, pSecret, pSecret_len, &size, 0);
if (S_OK == hr)
{
cng_dh_swap_bytes(pSecret, size);
sshbn_from(pSecret, size, &bn);
memset(pSecret, 0, size);
free(pSecret);
*shared_secretp = bn;
}
BCryptDestroySecret(hSecret);
}
}
return S_OK == hr ? 0 : -1;
}
int
sshdh_generate(struct sshdh *dh, size_t len)
{
if (!cng_supported())
{
if (len > INT_MAX)
return SSH_ERR_INVALID_ARGUMENT;
if (len != 0)
((DH*)(dh->dh))->length = (int)len;
if (DH_generate_key(dh->dh) != 1)
return SSH_ERR_LIBCRYPTO_ERROR;
return 0;
}
HRESULT Status;
BCRYPT_DH_PARAMETER_HEADER *DhParamHdrPointer = NULL;
DWORD DhParamBlobLength = 0;
PBYTE DhParamBlob = NULL;
BCRYPT_ALG_HANDLE hAlg = NULL;
PBYTE pBlob = NULL;
BCRYPT_KEY_HANDLE hPriv = NULL;
CNG_DH_CTX *pCtx = (CNG_DH_CTX*)dh->dh;
DWORD cbBlob = 0;
DhParamBlobLength = sizeof(BCRYPT_DH_PARAMETER_HEADER) + (pCtx->size * 2);
if (NULL == (DhParamBlob = (PBYTE)malloc(DhParamBlobLength)))
return -1;
DhParamHdrPointer = (BCRYPT_DH_PARAMETER_HEADER *)DhParamBlob;
DhParamHdrPointer->cbLength = DhParamBlobLength;
DhParamHdrPointer->cbKeyLength = pCtx->size;
DhParamHdrPointer->dwMagic = BCRYPT_DH_PARAMETERS_MAGIC;
memcpy(DhParamBlob + sizeof(BCRYPT_DH_PARAMETER_HEADER), pCtx->p, pCtx->size);
memcpy(DhParamBlob + sizeof(BCRYPT_DH_PARAMETER_HEADER) + pCtx->size, pCtx->g, pCtx->size);
if (S_OK != (Status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_DH_ALGORITHM, NULL, 0)))
goto error;
if (S_OK != (Status = BCryptGenerateKeyPair(hAlg, &hPriv, pCtx->size * 8, 0)))
goto error;
if (S_OK != (Status = BCryptSetProperty(hPriv, BCRYPT_DH_PARAMETERS, DhParamBlob, DhParamBlobLength, 0)))
goto error;
if (S_OK != (Status = BCryptFinalizeKeyPair(hPriv, 0)))
goto error;
if (S_OK != (Status = BCryptExportKey(hPriv, NULL, BCRYPT_DH_PUBLIC_BLOB, NULL, 0, &cbBlob, 0)))
goto error;
if (NULL == (pBlob = (PBYTE)malloc(cbBlob)))
{
Status = STATUS_NO_MEMORY;
goto error;
}
if (S_OK != (Status = BCryptExportKey(hPriv, NULL, BCRYPT_DH_PUBLIC_BLOB, pBlob, cbBlob, &cbBlob, 0)))
goto error;
BCRYPT_DH_KEY_BLOB *pKeyBlob = (BCRYPT_DH_KEY_BLOB *)pBlob;
PBYTE pModulus = pBlob + sizeof(BCRYPT_DH_KEY_BLOB);
PBYTE pGenerator = pModulus + pKeyBlob->cbKey;
PBYTE pPublic = pGenerator + pKeyBlob->cbKey;
pCtx->hAlg = hAlg;
pCtx->hPrivate = hPriv;
memcpy(pCtx->pub, pPublic, pCtx->size);
return 0;
error:
return -1;
}
int
sshdh_new_group_hex(const char *gen, const char *modulus, struct sshdh **dhp)
{
if (!cng_supported())
{
struct sshdh *ret;
*dhp = NULL;
if ((ret = sshdh_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if (BN_hex2bn(&(((DH*)(ret->dh))->p), modulus) == 0 ||
BN_hex2bn(&(((DH*)(ret->dh))->g), gen) == 0) {
sshdh_free(ret);
return SSH_ERR_LIBCRYPTO_ERROR;
}
*dhp = ret;
return 0;
}
struct sshdh *ret;
struct sshbn * g = NULL;
struct sshbn * p = NULL;
sshbn_from_hex(gen, &g);
sshbn_from_hex(modulus, &p);
*dhp = NULL;
ret = sshdh_new_group(g, p);
if (g != NULL)
sshbn_free(g);
if (p != NULL)
sshbn_free(p);
*dhp = ret;
return 0;
}
/* XXX transfers ownership of gen, modulus */
struct sshdh *
sshdh_new_group(struct sshbn *gen, struct sshbn *modulus)
{
if (!cng_supported())
{
struct sshdh *dh;
if ((dh = sshdh_new()) == NULL)
return NULL;
((DH*)(dh->dh))->p = modulus->bn;
((DH*)(dh->dh))->g = gen->bn;
modulus->bn = gen->bn = NULL;
sshbn_free(gen);
sshbn_free(modulus);
return (dh);
}
struct sshdh *dh;
PBYTE pBlob = NULL;
DWORD keysize = sshbn_bytes(modulus);
DWORD cbBlob = 0;
dh = sshdh_new();
pBlob = (PBYTE)malloc(sizeof(CNG_DH_CTX) + (3 * keysize));
memset(pBlob, 0, sizeof(CNG_DH_CTX) + (3 * keysize));
CNG_DH_CTX * pCtx = (CNG_DH_CTX *)pBlob;
pCtx->size = keysize;
pCtx->p = pBlob + sizeof(CNG_DH_CTX);
pCtx->g = pCtx->p + keysize;
pCtx->pub = pCtx->g + keysize;
sshbn_to(gen, pCtx->g + keysize - sshbn_bytes(gen));
sshbn_to(modulus, pCtx->p + keysize - sshbn_bytes(modulus));
dh->dh = (void *)pCtx;
return dh;
}

View File

@ -2013,9 +2013,10 @@ int cleanSelectThread(int thread_no)
if(thread_data_set[thread_no] != NULL) if(thread_data_set[thread_no] != NULL)
{ {
HeapFree(GetProcessHeap(), 0, thread_data_set[thread_no]); thread_data_p ap = thread_data_set[thread_no];
thread_data_set[thread_no] = NULL; thread_data_set[thread_no] = NULL;
HeapFree(GetProcessHeap(), 0, ap);
} }
DBG_MSG("<- cleanSelectThread()...\n"); DBG_MSG("<- cleanSelectThread()...\n");

51
crypto-wrap.h Normal file
View File

@ -0,0 +1,51 @@
#ifndef _OPENSSL_WRAP_H
#define _OPENSSL_WRAP_H
struct sshdh;
struct sshbn;
struct sshbuf;
struct ssh;
struct sshdh *sshdh_new(void);
void sshdh_free(struct sshdh *dh);
struct sshbn *sshdh_pubkey(struct sshdh *dh);
struct sshbn *sshdh_p(struct sshdh *dh);
struct sshbn *sshdh_g(struct sshdh *dh);
void sshdh_dump(struct sshdh *dh);
size_t sshdh_shared_key_size(struct sshdh *dh);
int sshdh_compute_key(struct sshdh *dh, struct sshbn *pubkey,
struct sshbn **shared_secretp);
int sshdh_generate(struct sshdh *dh, size_t len);
int sshdh_new_group_hex(const char *gen, const char *modulus,
struct sshdh **dhp);
struct sshdh *sshdh_new_group(struct sshbn *gen, struct sshbn *modulus);
struct sshbn *sshbn_new(void);
void sshbn_free(struct sshbn *bn);
int sshbn_from(const void *d, size_t l, struct sshbn **retp);
int sshbn_from_hex(const char *hex, struct sshbn **retp);
size_t sshbn_bits(const struct sshbn *bn);
const struct sshbn *sshbn_value_0(void);
const struct sshbn *sshbn_value_1(void);
int sshbn_cmp(const struct sshbn *a, const struct sshbn *b);
int sshbn_sub(struct sshbn *r, const struct sshbn *a, const struct sshbn *b);
int sshbn_is_bit_set(const struct sshbn *bn, size_t i);
int sshbn_to(const struct sshbn *a, unsigned char *to);
size_t sshbn_bytes(const struct sshbn *bn);
/* XXX move to sshbuf.h; rename s/_wrap$// */
int sshbuf_get_bignum2_wrap(struct sshbuf *buf, struct sshbn *bn);
int sshbuf_get_bignum1_wrap(struct sshbuf *buf, struct sshbn *bn);
int sshbuf_put_bignum2_wrap(struct sshbuf *buf, const struct sshbn *bn);
int sshbuf_put_bignum1_wrap(struct sshbuf *buf, const struct sshbn *bn);
int sshpkt_get_bignum2_wrap(struct ssh *ssh, struct sshbn *bn);
int sshpkt_put_bignum2_wrap(struct ssh *ssh, const struct sshbn *bn);
/* bridge to unwrapped OpenSSL APIs; XXX remove later */
struct sshbn *sshbn_from_bignum(BIGNUM *bn);
BIGNUM *sshbn_bignum(struct sshbn *bn);
DH *sshdh_dh(struct sshdh *dh);
#endif /* _OPENSSL_WRAP_H */

224
dh.c
View File

@ -41,6 +41,7 @@
#include "log.h" #include "log.h"
#include "misc.h" #include "misc.h"
#include "ssherr.h" #include "ssherr.h"
#include "crypto-wrap.h"
static int static int
parse_prime(int linenum, char *line, struct dhgroup *dhg) parse_prime(int linenum, char *line, struct dhgroup *dhg)
@ -49,6 +50,7 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg)
char *strsize, *gen, *prime; char *strsize, *gen, *prime;
const char *errstr = NULL; const char *errstr = NULL;
long long n; long long n;
int r;
dhg->p = dhg->g = NULL; dhg->p = dhg->g = NULL;
cp = line; cp = line;
@ -109,53 +111,45 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg)
goto fail; goto fail;
} }
if ((dhg->g = BN_new()) == NULL || if ((r = sshbn_from_hex(gen, &dhg->g)) != 0 ||
(dhg->p = BN_new()) == NULL) { (r = sshbn_from_hex(prime, &dhg->p)) != 0)
error("parse_prime: BN_new failed"); {
goto fail; goto fail;
} }
if (BN_hex2bn(&dhg->g, gen) == 0) { if (sshbn_bits(dhg->p) != dhg->size) {
error("moduli:%d: could not parse generator value", linenum); error("moduli:%d: prime has wrong size: actual %zu listed %zu",
linenum, sshbn_bits(dhg->p), dhg->size - 1);
goto fail; goto fail;
} }
if (BN_hex2bn(&dhg->p, prime) == 0) {
error("moduli:%d: could not parse prime value", linenum); if (sshbn_cmp(dhg->g, sshbn_value_1()) <= 0) {
goto fail;
}
if (BN_num_bits(dhg->p) != dhg->size) {
error("moduli:%d: prime has wrong size: actual %d listed %d",
linenum, BN_num_bits(dhg->p), dhg->size - 1);
goto fail;
}
if (BN_cmp(dhg->g, BN_value_one()) <= 0) {
error("moduli:%d: generator is invalid", linenum); error("moduli:%d: generator is invalid", linenum);
goto fail; goto fail;
} }
return 1; return 1;
fail: fail:
if (dhg->g != NULL) sshbn_free(dhg->g);
BN_clear_free(dhg->g); sshbn_free(dhg->p);
if (dhg->p != NULL)
BN_clear_free(dhg->p);
dhg->g = dhg->p = NULL; dhg->g = dhg->p = NULL;
return 0; return 0;
} }
DH * struct sshdh *
choose_dh(int min, int wantbits, int max) choose_dh(u_int min, u_int wantbits, u_int max)
{ {
FILE *f; FILE *f;
char line[4096]; char line[4096];
int best, bestcount, which; u_int best, bestcount, which, linenum;
int linenum; int r;
struct dhgroup dhg; struct dhgroup dhg;
struct sshdh *dh = NULL;
if ((f = fopen(_PATH_DH_MODULI, "r")) == NULL && if ((f = fopen(_PATH_DH_MODULI, "r")) == NULL &&
(f = fopen(_PATH_DH_PRIMES, "r")) == NULL) { (f = fopen(_PATH_DH_PRIMES, "r")) == NULL) {
logit("WARNING: %s does not exist, using fixed modulus", logit("WARNING: %s does not exist, using fixed modulus",
_PATH_DH_MODULI); _PATH_DH_MODULI);
return (dh_new_group_fallback(max)); goto fallback;
} }
linenum = 0; linenum = 0;
@ -164,8 +158,8 @@ choose_dh(int min, int wantbits, int max)
linenum++; linenum++;
if (!parse_prime(linenum, line, &dhg)) if (!parse_prime(linenum, line, &dhg))
continue; continue;
BN_clear_free(dhg.g); sshbn_free(dhg.g);
BN_clear_free(dhg.p); sshbn_free(dhg.p);
if (dhg.size > max || dhg.size < min) if (dhg.size > max || dhg.size < min)
continue; continue;
@ -183,7 +177,7 @@ choose_dh(int min, int wantbits, int max)
if (bestcount == 0) { if (bestcount == 0) {
fclose(f); fclose(f);
logit("WARNING: no suitable primes in %s", _PATH_DH_PRIMES); logit("WARNING: no suitable primes in %s", _PATH_DH_PRIMES);
return (dh_new_group_fallback(max)); goto fallback;
} }
linenum = 0; linenum = 0;
@ -194,8 +188,8 @@ choose_dh(int min, int wantbits, int max)
if ((dhg.size > max || dhg.size < min) || if ((dhg.size > max || dhg.size < min) ||
dhg.size != best || dhg.size != best ||
linenum++ != which) { linenum++ != which) {
BN_clear_free(dhg.g); sshbn_free(dhg.g);
BN_clear_free(dhg.p); sshbn_free(dhg.p);
continue; continue;
} }
break; break;
@ -204,109 +198,104 @@ choose_dh(int min, int wantbits, int max)
if (linenum != which+1) { if (linenum != which+1) {
logit("WARNING: line %d disappeared in %s, giving up", logit("WARNING: line %d disappeared in %s, giving up",
which, _PATH_DH_PRIMES); which, _PATH_DH_PRIMES);
return (dh_new_group_fallback(max)); fallback:
if ((r = dh_new_group_fallback(max, &dh)) != 0)
fatal("%s: dh_new_group_fallback: %s",
__func__, ssh_err(r));
return dh;
} }
return (dh_new_group(dhg.g, dhg.p)); return (sshdh_new_group(dhg.g, dhg.p));
} }
/* diffie-hellman-groupN-sha1 */ /* diffie-hellman-groupN-sha1 */
int int
dh_pub_is_valid(DH *dh, BIGNUM *dh_pub) dh_pub_is_valid(struct sshdh *dh, struct sshbn *dh_pub)
{ {
int i; size_t i;
int n = BN_num_bits(dh_pub); size_t n;
int bits_set = 0; int r, freeme = 0, bits_set = 0;
BIGNUM *tmp; struct sshbn *dh_p = NULL, *tmp = NULL;
if (dh_pub->neg) { if (dh_pub == NULL) {
logit("invalid public DH value: negative"); if ((dh_pub = sshdh_pubkey(dh)) == NULL)
return 0; return SSH_ERR_ALLOC_FAIL;
freeme = 1;
} }
if (BN_cmp(dh_pub, BN_value_one()) != 1) { /* pub_exp <= 1 */ n = sshbn_bits(dh_pub);
if (sshbn_cmp(dh_pub, sshbn_value_1()) != 1) { /* pub_exp <= 1 */
logit("invalid public DH value: <= 1"); logit("invalid public DH value: <= 1");
return 0; r = SSH_ERR_INVALID_FORMAT;
goto out;
} }
if ((dh_p = sshdh_p(dh)) == NULL) {
if ((tmp = BN_new()) == NULL) { error("%s: sshdh_p failed", __func__);
error("%s: BN_new failed", __func__); r = SSH_ERR_ALLOC_FAIL;
return 0; goto out;
} }
if (!BN_sub(tmp, dh->p, BN_value_one()) || if ((tmp = sshbn_new()) == NULL) {
BN_cmp(dh_pub, tmp) != -1) { /* pub_exp > p-2 */ error("%s: sshbn_new failed", __func__);
BN_clear_free(tmp); r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshbn_sub(tmp, dh_p, sshbn_value_1())) != 0) {
error("%s: sshbn_sub: %s", __func__, ssh_err(r));
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
if ((r = sshbn_cmp(dh_pub, tmp)) != -1) { /* pub_exp > p-2 */
logit("invalid public DH value: >= p-1"); logit("invalid public DH value: >= p-1");
return 0; r = SSH_ERR_INVALID_FORMAT;
goto out;
} }
BN_clear_free(tmp);
for (i = 0; i <= n; i++) for (i = 0; i <= n; i++)
if (BN_is_bit_set(dh_pub, i)) if (sshbn_is_bit_set(dh_pub, i))
bits_set++; bits_set++;
debug2("bits set: %d/%d", bits_set, BN_num_bits(dh->p)); debug2("bits set: %d/%zu", bits_set, sshbn_bits(dh_p));
/* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */ /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
if (bits_set > 1) if (bits_set <= 1) {
return 1; logit("invalid public DH value (%d/%zu)",
bits_set, sshbn_bits(dh_p));
r = SSH_ERR_INVALID_FORMAT;
goto out;
}
logit("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p)); /* success */
r = 0;
out:
sshbn_free(dh_p);
sshbn_free(tmp);
if (freeme)
sshbn_free(dh_pub);
return r;
}
int
dh_gen_key(struct sshdh *dh, u_int need)
{
size_t pbits;
struct sshbn *dh_p;
int r;
if ((dh_p = sshdh_p(dh)) == NULL) {
error("%s: sshdh_p failed", __func__);
return 0;
}
if (need == 0 ||
(pbits = sshbn_bits(dh_p)) == 0 ||
need > INT_MAX / 2 || 2 * need > pbits) {
sshbn_free(dh_p);
return SSH_ERR_INVALID_ARGUMENT;
}
if ((r = sshdh_generate(dh, MIN(need * 2, pbits - 1))) != 0 ||
(r = dh_pub_is_valid(dh, NULL)) != 0)
return r;
return 0; return 0;
} }
int int
dh_gen_key(DH *dh, int need) dh_new_group1(struct sshdh **dhp)
{
int pbits;
if (need < 0 || dh->p == NULL ||
(pbits = BN_num_bits(dh->p)) <= 0 ||
need > INT_MAX / 2 || 2 * need > pbits)
return SSH_ERR_INVALID_ARGUMENT;
dh->length = MIN(need * 2, pbits - 1);
if (DH_generate_key(dh) == 0 ||
!dh_pub_is_valid(dh, dh->pub_key)) {
BN_clear_free(dh->priv_key);
return SSH_ERR_LIBCRYPTO_ERROR;
}
return 0;
}
DH *
dh_new_group_asc(const char *gen, const char *modulus)
{
DH *dh;
if ((dh = DH_new()) == NULL)
return NULL;
if (BN_hex2bn(&dh->p, modulus) == 0 ||
BN_hex2bn(&dh->g, gen) == 0) {
DH_free(dh);
return NULL;
}
return (dh);
}
/*
* This just returns the group, we still need to generate the exchange
* value.
*/
DH *
dh_new_group(BIGNUM *gen, BIGNUM *modulus)
{
DH *dh;
if ((dh = DH_new()) == NULL)
return NULL;
dh->p = modulus;
dh->g = gen;
return (dh);
}
DH *
dh_new_group1(void)
{ {
static char *gen = "2", *group1 = static char *gen = "2", *group1 =
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
@ -316,11 +305,11 @@ dh_new_group1(void)
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381" "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
"FFFFFFFF" "FFFFFFFF"; "FFFFFFFF" "FFFFFFFF";
return (dh_new_group_asc(gen, group1)); return sshdh_new_group_hex(gen, group1, dhp);
} }
DH * int
dh_new_group14(void) dh_new_group14(struct sshdh **dhp)
{ {
static char *gen = "2", *group14 = static char *gen = "2", *group14 =
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
@ -335,15 +324,15 @@ dh_new_group14(void)
"DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510" "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
"15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF"; "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF";
return (dh_new_group_asc(gen, group14)); return sshdh_new_group_hex(gen, group14, dhp);
} }
/* /*
* 4k bit fallback group used by DH-GEX if moduli file cannot be read. * 4k bit fallback group used by DH-GEX if moduli file cannot be read.
* Source: MODP group 16 from RFC3526. * Source: MODP group 16 from RFC3526.
*/ */
DH * int
dh_new_group_fallback(int max) dh_new_group_fallback(int max, struct sshdh **dhp)
{ {
static char *gen = "2", *group16 = static char *gen = "2", *group16 =
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1" "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
@ -371,10 +360,10 @@ dh_new_group_fallback(int max)
if (max < 4096) { if (max < 4096) {
debug3("requested max size %d, using 2k bit group 14", max); debug3("requested max size %d, using 2k bit group 14", max);
return dh_new_group14(); return dh_new_group14(dhp);
} }
debug3("using 4k bit group 16"); debug3("using 4k bit group 16");
return (dh_new_group_asc(gen, group16)); return sshdh_new_group_hex(gen, group16, dhp);
} }
/* /*
@ -384,7 +373,6 @@ dh_new_group_fallback(int max)
* Management Part 1 (rev 3) limited by the recommended maximum value * Management Part 1 (rev 3) limited by the recommended maximum value
* from RFC4419 section 3. * from RFC4419 section 3.
*/ */
u_int u_int
dh_estimate(int bits) dh_estimate(int bits)
{ {

30
dh.h
View File

@ -26,26 +26,29 @@
#ifndef DH_H #ifndef DH_H
#define DH_H #define DH_H
#include <crypto-wrap.h>
struct dhgroup { struct dhgroup {
int size; size_t size;
BIGNUM *g; struct sshbn *g;
BIGNUM *p; struct sshbn *p;
}; };
DH *choose_dh(int, int, int); struct sshdh *choose_dh(u_int, u_int, u_int);
DH *dh_new_group_asc(const char *, const char *); int dh_new_group1(struct sshdh **dhp);
DH *dh_new_group(BIGNUM *, BIGNUM *); int dh_new_group14(struct sshdh **dhp);
DH *dh_new_group1(void); int dh_new_group_fallback(int, struct sshdh **dhp);
DH *dh_new_group14(void);
DH *dh_new_group_fallback(int);
int dh_gen_key(DH *, int); int dh_gen_key(struct sshdh *dh, u_int);
int dh_pub_is_valid(DH *, BIGNUM *); int dh_pub_is_valid(struct sshdh *dh, struct sshbn *dh_pub);
u_int dh_estimate(int); u_int dh_estimate(int);
/* Min and max values from RFC4419. */ /*
#define DH_GRP_MIN 1024 * Max value from RFC4419.
* Miniumum increased in light of DH precomputation attacks.
*/
#define DH_GRP_MIN 2048
#define DH_GRP_MAX 8192 #define DH_GRP_MAX 8192
/* /*
@ -71,5 +74,4 @@ u_int dh_estimate(int);
#define MODULI_TESTS_JACOBI (0x08) #define MODULI_TESTS_JACOBI (0x08)
#define MODULI_TESTS_ELLIPTIC (0x10) #define MODULI_TESTS_ELLIPTIC (0x10)
#endif #endif

107
kex.c
View File

@ -55,18 +55,23 @@
#include "sshbuf.h" #include "sshbuf.h"
#include "digest.h" #include "digest.h"
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
# if defined(HAVE_EVP_SHA256)
# define evp_ssh_sha256 EVP_sha256
# else
extern const EVP_MD *evp_ssh_sha256(void);
# endif
#endif
/* prototype */ /* prototype */
static int kex_choose_conf(struct ssh *); static int kex_choose_conf(struct ssh *);
static int kex_input_newkeys(int, u_int32_t, void *); static int kex_input_newkeys(int, u_int32_t, void *);
static const char *proposal_names[PROPOSAL_MAX] = {
"KEX algorithms",
"host key algorithms",
"ciphers ctos",
"ciphers stoc",
"MACs ctos",
"MACs stoc",
"compression ctos",
"compression stoc",
"languages ctos",
"languages stoc",
};
struct kexalg { struct kexalg {
char *name; char *name;
u_int type; u_int type;
@ -78,23 +83,15 @@ static const struct kexalg kexalgs[] = {
{ KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
{ KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, { KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },
{ KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 },
#ifdef HAVE_EVP_SHA256
{ KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 }, { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 },
#endif /* HAVE_EVP_SHA256 */
#ifdef OPENSSL_HAS_ECC
{ KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2,
NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, NID_X9_62_prime256v1, SSH_DIGEST_SHA256 },
{ KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1,
SSH_DIGEST_SHA384 }, SSH_DIGEST_SHA384 },
# ifdef OPENSSL_HAS_NISTP521
{ KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1,
SSH_DIGEST_SHA512 }, SSH_DIGEST_SHA512 },
# endif /* OPENSSL_HAS_NISTP521 */ #endif
#endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
#if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL)
{ KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
#endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */
{ NULL, -1, -1, -1 }, { NULL, -1, -1, -1 },
}; };
@ -267,7 +264,7 @@ kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp)
for (i = 0; i < PROPOSAL_MAX; i++) { for (i = 0; i < PROPOSAL_MAX; i++) {
if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0)
goto out; goto out;
debug2("kex_parse_kexinit: %s", proposal[i]); debug2("%s: %s", proposal_names[i], proposal[i]);
} }
/* first kex follows / reserved */ /* first kex follows / reserved */
if ((r = sshbuf_get_u8(b, &v)) != 0 || if ((r = sshbuf_get_u8(b, &v)) != 0 ||
@ -275,8 +272,8 @@ kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp)
goto out; goto out;
if (first_kex_follows != NULL) if (first_kex_follows != NULL)
*first_kex_follows = i; *first_kex_follows = i;
debug2("kex_parse_kexinit: first_kex_follows %d ", v); debug2("first_kex_follows %d ", v);
debug2("kex_parse_kexinit: reserved %u ", i); debug2("reserved %u ", i);
r = 0; r = 0;
*propp = proposal; *propp = proposal;
out: out:
@ -302,7 +299,14 @@ kex_prop_free(char **proposal)
static int static int
kex_protocol_error(int type, u_int32_t seq, void *ctxt) kex_protocol_error(int type, u_int32_t seq, void *ctxt)
{ {
error("Hm, kex protocol error: type %d seq %u", type, seq); struct ssh *ssh = active_state; /* XXX */
int r;
error("kex protocol error: type %d seq %u", type, seq);
if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 ||
(r = sshpkt_put_u32(ssh, seq)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
return r;
return 0; return 0;
} }
@ -468,7 +472,7 @@ kex_free_newkeys(struct newkeys *newkeys)
newkeys->enc.key = NULL; newkeys->enc.key = NULL;
} }
if (newkeys->enc.iv) { if (newkeys->enc.iv) {
explicit_bzero(newkeys->enc.iv, newkeys->enc.block_size); explicit_bzero(newkeys->enc.iv, newkeys->enc.iv_len);
free(newkeys->enc.iv); free(newkeys->enc.iv);
newkeys->enc.iv = NULL; newkeys->enc.iv = NULL;
} }
@ -494,13 +498,10 @@ kex_free(struct kex *kex)
u_int mode; u_int mode;
#ifdef WITH_OPENSSL #ifdef WITH_OPENSSL
if (kex->dh) sshdh_free(kex->dh);
DH_free(kex->dh);
#ifdef OPENSSL_HAS_ECC
if (kex->ec_client_key) if (kex->ec_client_key)
EC_KEY_free(kex->ec_client_key); EC_KEY_free(kex->ec_client_key);
#endif /* OPENSSL_HAS_ECC */ #endif
#endif /* WITH_OPENSSL */
for (mode = 0; mode < MODE_MAX; mode++) { for (mode = 0; mode < MODE_MAX; mode++) {
kex_free_newkeys(kex->newkeys[mode]); kex_free_newkeys(kex->newkeys[mode]);
kex->newkeys[mode] = NULL; kex->newkeys[mode] = NULL;
@ -575,11 +576,14 @@ choose_comp(struct sshcomp *comp, char *client, char *server)
return SSH_ERR_NO_COMPRESS_ALG_MATCH; return SSH_ERR_NO_COMPRESS_ALG_MATCH;
if (strcmp(name, "zlib@openssh.com") == 0) { if (strcmp(name, "zlib@openssh.com") == 0) {
comp->type = COMP_DELAYED; comp->type = COMP_DELAYED;
} else if (strcmp(name, "zlib") == 0) { }
else if (strcmp(name, "zlib") == 0) {
comp->type = COMP_ZLIB; comp->type = COMP_ZLIB;
} else if (strcmp(name, "none") == 0) { }
else if (strcmp(name, "none") == 0) {
comp->type = COMP_NONE; comp->type = COMP_NONE;
} else { }
else {
return SSH_ERR_INTERNAL_ERROR; return SSH_ERR_INTERNAL_ERROR;
} }
comp->name = name; comp->name = name;
@ -593,6 +597,7 @@ choose_kex(struct kex *k, char *client, char *server)
k->name = match_list(client, server, NULL); k->name = match_list(client, server, NULL);
debug("kex: algorithm: %s", k->name ? k->name : "(no match)");
if (k->name == NULL) if (k->name == NULL)
return SSH_ERR_NO_KEX_ALG_MATCH; return SSH_ERR_NO_KEX_ALG_MATCH;
if ((kexalg = kex_alg_by_name(k->name)) == NULL) if ((kexalg = kex_alg_by_name(k->name)) == NULL)
@ -608,6 +613,8 @@ choose_hostkeyalg(struct kex *k, char *client, char *server)
{ {
char *hostkeyalg = match_list(client, server, NULL); char *hostkeyalg = match_list(client, server, NULL);
debug("kex: host key algorithm: %s",
hostkeyalg ? hostkeyalg : "(no match)");
if (hostkeyalg == NULL) if (hostkeyalg == NULL)
return SSH_ERR_NO_HOSTKEY_ALG_MATCH; return SSH_ERR_NO_HOSTKEY_ALG_MATCH;
k->hostkey_type = sshkey_type_from_name(hostkeyalg); k->hostkey_type = sshkey_type_from_name(hostkeyalg);
@ -653,14 +660,18 @@ kex_choose_conf(struct ssh *ssh)
u_int mode, ctos, need, dh_need, authlen; u_int mode, ctos, need, dh_need, authlen;
int r, first_kex_follows; int r, first_kex_follows;
if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0 || debug2("local %s KEXINIT proposal", kex->server ? "server" : "client");
(r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0) if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0)
goto out;
debug2("peer %s KEXINIT proposal", kex->server ? "client" : "server");
if ((r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0)
goto out; goto out;
if (kex->server) { if (kex->server) {
cprop = peer; cprop = peer;
sprop = my; sprop = my;
} else { }
else {
cprop = my; cprop = my;
sprop = peer; sprop = peer;
} }
@ -677,6 +688,18 @@ kex_choose_conf(struct ssh *ssh)
} }
/* Algorithm Negotiation */ /* Algorithm Negotiation */
if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS],
sprop[PROPOSAL_KEX_ALGS])) != 0) {
kex->failed_choice = peer[PROPOSAL_KEX_ALGS];
peer[PROPOSAL_KEX_ALGS] = NULL;
goto out;
}
if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) {
kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS];
peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL;
goto out;
}
for (mode = 0; mode < MODE_MAX; mode++) { for (mode = 0; mode < MODE_MAX; mode++) {
if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) { if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) {
r = SSH_ERR_ALLOC_FAIL; r = SSH_ERR_ALLOC_FAIL;
@ -709,24 +732,12 @@ kex_choose_conf(struct ssh *ssh)
peer[ncomp] = NULL; peer[ncomp] = NULL;
goto out; goto out;
} }
debug("kex: %s %s %s %s", debug("kex: %s cipher: %s MAC: %s compression: %s",
ctos ? "client->server" : "server->client", ctos ? "client->server" : "server->client",
newkeys->enc.name, newkeys->enc.name,
authlen == 0 ? newkeys->mac.name : "<implicit>", authlen == 0 ? newkeys->mac.name : "<implicit>",
newkeys->comp.name); newkeys->comp.name);
} }
if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS],
sprop[PROPOSAL_KEX_ALGS])) != 0) {
kex->failed_choice = peer[PROPOSAL_KEX_ALGS];
peer[PROPOSAL_KEX_ALGS] = NULL;
goto out;
}
if ((r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) {
kex->failed_choice = peer[PROPOSAL_SERVER_HOST_KEY_ALGS];
peer[PROPOSAL_SERVER_HOST_KEY_ALGS] = NULL;
goto out;
}
need = dh_need = 0; need = dh_need = 0;
for (mode = 0; mode < MODE_MAX; mode++) { for (mode = 0; mode < MODE_MAX; mode++) {
newkeys = kex->newkeys[mode]; newkeys = kex->newkeys[mode];
@ -849,14 +860,14 @@ kex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen,
#ifdef WITH_OPENSSL #ifdef WITH_OPENSSL
int int
kex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen, kex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen,
const BIGNUM *secret) const struct sshbn *secret)
{ {
struct sshbuf *shared_secret; struct sshbuf *shared_secret;
int r; int r;
if ((shared_secret = sshbuf_new()) == NULL) if ((shared_secret = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL; return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_put_bignum2(shared_secret, secret)) == 0) if ((r = sshbuf_put_bignum2_wrap(shared_secret, secret)) == 0)
r = kex_derive_keys(ssh, hash, hashlen, shared_secret); r = kex_derive_keys(ssh, hash, hashlen, shared_secret);
sshbuf_free(shared_secret); sshbuf_free(shared_secret);
return r; return r;

32
kex.h
View File

@ -34,20 +34,6 @@
#include "leakmalloc.h" #include "leakmalloc.h"
#endif #endif
#ifdef WITH_OPENSSL
# ifdef OPENSSL_HAS_ECC
# include <openssl/ec.h>
# else /* OPENSSL_HAS_ECC */
# define EC_KEY void
# define EC_GROUP void
# define EC_POINT void
# endif /* OPENSSL_HAS_ECC */
#else /* WITH_OPENSSL */
# define EC_KEY void
# define EC_GROUP void
# define EC_POINT void
#endif /* WITH_OPENSSL */
#define KEX_COOKIE_LEN 16 #define KEX_COOKIE_LEN 16
#define KEX_DH1 "diffie-hellman-group1-sha1" #define KEX_DH1 "diffie-hellman-group1-sha1"
@ -150,7 +136,7 @@ struct kex {
u_char **, size_t *, const u_char *, size_t, u_int); u_char **, size_t *, const u_char *, size_t, u_int);
int(*kex[KEX_MAX])(struct ssh *); int(*kex[KEX_MAX])(struct ssh *);
/* kex specific state */ /* kex specific state */
DH *dh; /* DH */ struct sshdh *dh; /* DH */
u_int min, max, nbits; /* GEX */ u_int min, max, nbits; /* GEX */
EC_KEY *ec_client_key; /* ECDH */ EC_KEY *ec_client_key; /* ECDH */
const EC_GROUP *ec_group; /* ECDH */ const EC_GROUP *ec_group; /* ECDH */
@ -175,7 +161,8 @@ void kex_prop_free(char **);
int kex_send_kexinit(struct ssh *); int kex_send_kexinit(struct ssh *);
int kex_input_kexinit(int, u_int32_t, void *); int kex_input_kexinit(int, u_int32_t, void *);
int kex_derive_keys(struct ssh *, u_char *, u_int, const struct sshbuf *); int kex_derive_keys(struct ssh *, u_char *, u_int, const struct sshbuf *);
int kex_derive_keys_bn(struct ssh *, u_char *, u_int, const BIGNUM *); int kex_derive_keys_bn(struct ssh *, u_char *, u_int,
const struct sshbn *);
int kex_send_newkeys(struct ssh *); int kex_send_newkeys(struct ssh *);
int kexdh_client(struct ssh *); int kexdh_client(struct ssh *);
@ -189,13 +176,14 @@ int kexc25519_server(struct ssh *);
int kex_dh_hash(const char *, const char *, int kex_dh_hash(const char *, const char *,
const u_char *, size_t, const u_char *, size_t, const u_char *, size_t, const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
const BIGNUM *, const BIGNUM *, const BIGNUM *, u_char *, size_t *); const struct sshbn *, const struct sshbn *,
const struct sshbn *, u_char *, size_t *);
int kexgex_hash(int, const char *, const char *, int kexgex_hash(int, const char *, const char *,
const u_char *, size_t, const u_char *, size_t, const u_char *, size_t, const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
int, int, int, int, int, int,
const BIGNUM *, const BIGNUM *, const BIGNUM *, const struct sshbn *, const struct sshbn *, const struct sshbn *,
const BIGNUM *, const BIGNUM *, const struct sshbn *, const struct sshbn *,
u_char *, size_t *); u_char *, size_t *);
int kex_ecdh_hash(int, const EC_GROUP *, const char *, const char *, int kex_ecdh_hash(int, const EC_GROUP *, const char *, const char *,
@ -221,10 +209,4 @@ derive_ssh1_session_id(BIGNUM *, BIGNUM *, u_int8_t[8], u_int8_t[16]);
void dump_digest(char *, u_char *, int); void dump_digest(char *, u_char *, int);
#endif #endif
#if !defined(WITH_OPENSSL) || !defined(OPENSSL_HAS_ECC)
# undef EC_KEY
# undef EC_GROUP
# undef EC_POINT
#endif
#endif #endif

14
kexdh.c
View File

@ -25,7 +25,6 @@
#include "includes.h" #include "includes.h"
#ifdef WITH_OPENSSL
#include <sys/types.h> #include <sys/types.h>
@ -48,9 +47,9 @@ kex_dh_hash(
const u_char *ckexinit, size_t ckexinitlen, const u_char *ckexinit, size_t ckexinitlen,
const u_char *skexinit, size_t skexinitlen, const u_char *skexinit, size_t skexinitlen,
const u_char *serverhostkeyblob, size_t sbloblen, const u_char *serverhostkeyblob, size_t sbloblen,
const BIGNUM *client_dh_pub, const struct sshbn *client_dh_pub,
const BIGNUM *server_dh_pub, const struct sshbn *server_dh_pub,
const BIGNUM *shared_secret, const struct sshbn *shared_secret,
u_char *hash, size_t *hashlen) u_char *hash, size_t *hashlen)
{ {
struct sshbuf *b; struct sshbuf *b;
@ -70,9 +69,9 @@ kex_dh_hash(
(r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 || (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
(r = sshbuf_put(b, skexinit, skexinitlen)) != 0 || (r = sshbuf_put(b, skexinit, skexinitlen)) != 0 ||
(r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 || (r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 ||
(r = sshbuf_put_bignum2(b, client_dh_pub)) != 0 || (r = sshbuf_put_bignum2_wrap(b, client_dh_pub)) != 0 ||
(r = sshbuf_put_bignum2(b, server_dh_pub)) != 0 || (r = sshbuf_put_bignum2_wrap(b, server_dh_pub)) != 0 ||
(r = sshbuf_put_bignum2(b, shared_secret)) != 0) { (r = sshbuf_put_bignum2_wrap(b, shared_secret)) != 0) {
sshbuf_free(b); sshbuf_free(b);
return r; return r;
} }
@ -90,4 +89,3 @@ kex_dh_hash(
#endif #endif
return 0; return 0;
} }
#endif /* WITH_OPENSSL */

View File

@ -25,7 +25,6 @@
#include "includes.h" #include "includes.h"
#ifdef WITH_OPENSSL
#include <sys/types.h> #include <sys/types.h>
@ -55,15 +54,18 @@ int
kexdh_client(struct ssh *ssh) kexdh_client(struct ssh *ssh)
{ {
struct kex *kex = ssh->kex; struct kex *kex = ssh->kex;
struct sshbn *dh_client_pub = NULL;
int r; int r;
/* generate and send 'e', client DH public key */ /* generate and send 'e', client DH public key */
switch (kex->kex_type) { switch (kex->kex_type) {
case KEX_DH_GRP1_SHA1: case KEX_DH_GRP1_SHA1:
kex->dh = dh_new_group1(); if ((r = dh_new_group1(&kex->dh)) != 0)
return r;
break; break;
case KEX_DH_GRP14_SHA1: case KEX_DH_GRP14_SHA1:
kex->dh = dh_new_group14(); if ((r = dh_new_group14(&kex->dh)) != 0)
return r;
break; break;
default: default:
r = SSH_ERR_INVALID_ARGUMENT; r = SSH_ERR_INVALID_ARGUMENT;
@ -73,22 +75,25 @@ kexdh_client(struct ssh *ssh)
r = SSH_ERR_ALLOC_FAIL; r = SSH_ERR_ALLOC_FAIL;
goto out; goto out;
} }
if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0)
goto out;
if ((dh_client_pub = sshdh_pubkey(kex->dh)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
debug("sending SSH2_MSG_KEXDH_INIT"); debug("sending SSH2_MSG_KEXDH_INIT");
if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0 || if ((r = sshpkt_start(ssh, SSH2_MSG_KEXDH_INIT)) != 0 ||
(r = sshpkt_start(ssh, SSH2_MSG_KEXDH_INIT)) != 0 || (r = sshpkt_put_bignum2_wrap(ssh, dh_client_pub)) != 0 ||
(r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 ||
(r = sshpkt_send(ssh)) != 0) (r = sshpkt_send(ssh)) != 0)
goto out; goto out;
#ifdef DEBUG_KEXDH #ifdef DEBUG_KEXDH
DHparams_print_fp(stderr, kex->dh); sshdh_dump(kex->dh);
fprintf(stderr, "pub= ");
BN_print_fp(stderr, kex->dh->pub_key);
fprintf(stderr, "\n");
#endif #endif
debug("expecting SSH2_MSG_KEXDH_REPLY"); debug("expecting SSH2_MSG_KEXDH_REPLY");
ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_REPLY, &input_kex_dh); ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_REPLY, &input_kex_dh);
r = 0; r = 0;
out: out:
sshbn_free(dh_client_pub);
return r; return r;
} }
@ -97,12 +102,14 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
{ {
struct ssh *ssh = ctxt; struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex; struct kex *kex = ssh->kex;
BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; struct sshbn *dh_client_pub = NULL;
struct sshbn *dh_server_pub = NULL;
struct sshbn *shared_secret = NULL;
struct sshkey *server_host_key = NULL; struct sshkey *server_host_key = NULL;
u_char *kbuf = NULL, *server_host_key_blob = NULL, *signature = NULL; u_char *server_host_key_blob = NULL, *signature = NULL;
u_char hash[SSH_DIGEST_MAX_LENGTH]; u_char hash[SSH_DIGEST_MAX_LENGTH];
size_t klen = 0, slen, sbloblen, hashlen; size_t slen, sbloblen, hashlen;
int kout, r; int r;
if (kex->verify_host_key == NULL) { if (kex->verify_host_key == NULL) {
r = SSH_ERR_INVALID_ARGUMENT; r = SSH_ERR_INVALID_ARGUMENT;
@ -125,12 +132,12 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
goto out; goto out;
} }
/* DH parameter f, server public DH key */ /* DH parameter f, server public DH key */
if ((dh_server_pub = BN_new()) == NULL) { if ((dh_server_pub = sshbn_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL; r = SSH_ERR_ALLOC_FAIL;
goto out; goto out;
} }
/* signed H */ /* signed H */
if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 || if ((r = sshpkt_get_bignum2_wrap(ssh, dh_server_pub)) != 0 ||
(r = sshpkt_get_string(ssh, &signature, &slen)) != 0 || (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0) (r = sshpkt_get_end(ssh)) != 0)
goto out; goto out;
@ -140,23 +147,17 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
fprintf(stderr, "\n"); fprintf(stderr, "\n");
debug("bits %d", BN_num_bits(dh_server_pub)); debug("bits %d", BN_num_bits(dh_server_pub));
#endif #endif
if (!dh_pub_is_valid(kex->dh, dh_server_pub)) { if ((r = dh_pub_is_valid(kex->dh, dh_server_pub)) != 0) {
sshpkt_disconnect(ssh, "bad server public DH value"); sshpkt_disconnect(ssh, "bad server public DH value");
r = SSH_ERR_MESSAGE_INCOMPLETE;
goto out; goto out;
} }
if ((dh_client_pub = sshdh_pubkey(kex->dh)) == NULL) {
klen = DH_size(kex->dh); r = SSH_ERR_INTERNAL_ERROR;
if ((kbuf = malloc(klen)) == NULL ||
(shared_secret = BN_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out; goto out;
} }
if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 || if ((r = sshdh_compute_key(kex->dh, dh_server_pub,
BN_bin2bn(kbuf, kout, shared_secret) == NULL) { &shared_secret)) != 0)
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out; goto out;
}
#ifdef DEBUG_KEXDH #ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout); dump_digest("shared secret", kbuf, kout);
#endif #endif
@ -169,7 +170,7 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
sshbuf_ptr(kex->my), sshbuf_len(kex->my), sshbuf_ptr(kex->my), sshbuf_len(kex->my),
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
server_host_key_blob, sbloblen, server_host_key_blob, sbloblen,
kex->dh->pub_key, dh_client_pub,
dh_server_pub, dh_server_pub,
shared_secret, shared_secret,
hash, &hashlen)) != 0) hash, &hashlen)) != 0)
@ -194,19 +195,13 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
r = kex_send_newkeys(ssh); r = kex_send_newkeys(ssh);
out: out:
explicit_bzero(hash, sizeof(hash)); explicit_bzero(hash, sizeof(hash));
DH_free(kex->dh);
kex->dh = NULL;
if (dh_server_pub)
BN_clear_free(dh_server_pub);
if (kbuf) {
explicit_bzero(kbuf, klen);
free(kbuf);
}
if (shared_secret)
BN_clear_free(shared_secret);
sshkey_free(server_host_key); sshkey_free(server_host_key);
sshbn_free(shared_secret);
sshbn_free(dh_server_pub);
sshbn_free(dh_client_pub);
sshdh_free(kex->dh);
kex->dh = NULL;
free(server_host_key_blob); free(server_host_key_blob);
free(signature); free(signature);
return r; return r;
} }
#endif /* WITH_OPENSSL */

View File

@ -34,7 +34,6 @@
#undef KRB5 #undef KRB5
#endif #endif
#ifdef WITH_OPENSSL
#include <sys/types.h> #include <sys/types.h>
@ -69,27 +68,24 @@ kexdh_server(struct ssh *ssh)
/* generate server DH public key */ /* generate server DH public key */
switch (kex->kex_type) { switch (kex->kex_type) {
case KEX_DH_GRP1_SHA1: case KEX_DH_GRP1_SHA1:
kex->dh = dh_new_group1(); if ((r = dh_new_group1(&kex->dh)) != 0)
return r;
break; break;
case KEX_DH_GRP14_SHA1: case KEX_DH_GRP14_SHA1:
kex->dh = dh_new_group14(); if ((r = dh_new_group14(&kex->dh)) != 0)
return r;
break; break;
default: default:
r = SSH_ERR_INVALID_ARGUMENT; return SSH_ERR_INVALID_ARGUMENT;
goto out;
}
if (kex->dh == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
} }
if (kex->dh == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0) if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0)
goto out; return r;
debug("expecting SSH2_MSG_KEXDH_INIT"); debug("expecting SSH2_MSG_KEXDH_INIT");
ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_INIT, &input_kex_dh_init); ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_INIT, &input_kex_dh_init);
r = 0; return 0;
out:
return r;
} }
int int
@ -97,13 +93,15 @@ input_kex_dh_init(int type, u_int32_t seq, void *ctxt)
{ {
struct ssh *ssh = ctxt; struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex; struct kex *kex = ssh->kex;
BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; struct sshbn *dh_client_pub = NULL;
struct sshbn *dh_server_pub = NULL;
struct sshbn *shared_secret = NULL;
struct sshkey *server_host_public, *server_host_private; struct sshkey *server_host_public, *server_host_private;
u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL; u_char *signature = NULL, *server_host_key_blob = NULL;
u_char hash[SSH_DIGEST_MAX_LENGTH]; u_char hash[SSH_DIGEST_MAX_LENGTH];
size_t sbloblen, slen; size_t sbloblen, slen;
size_t klen = 0, hashlen; size_t hashlen;
int kout, r; int r;
if (kex->load_host_public_key == NULL || if (kex->load_host_public_key == NULL ||
kex->load_host_private_key == NULL) { kex->load_host_private_key == NULL) {
@ -120,11 +118,11 @@ input_kex_dh_init(int type, u_int32_t seq, void *ctxt)
} }
/* key, cert */ /* key, cert */
if ((dh_client_pub = BN_new()) == NULL) { if ((dh_client_pub = sshbn_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL; r = SSH_ERR_ALLOC_FAIL;
goto out; goto out;
} }
if ((r = sshpkt_get_bignum2(ssh, dh_client_pub)) != 0 || if ((r = sshpkt_get_bignum2_wrap(ssh, dh_client_pub)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0) (r = sshpkt_get_end(ssh)) != 0)
goto out; goto out;
@ -136,30 +134,21 @@ input_kex_dh_init(int type, u_int32_t seq, void *ctxt)
#endif #endif
#ifdef DEBUG_KEXDH #ifdef DEBUG_KEXDH
DHparams_print_fp(stderr, kex->dh); sshdh_dump(kex->dh);
fprintf(stderr, "pub= ");
BN_print_fp(stderr, kex->dh->pub_key);
fprintf(stderr, "\n");
#endif #endif
if (!dh_pub_is_valid(kex->dh, dh_client_pub)) { if ((r = dh_pub_is_valid(kex->dh, dh_client_pub)) != 0) {
sshpkt_disconnect(ssh, "bad client public DH value"); sshpkt_disconnect(ssh, "bad client public DH value");
r = SSH_ERR_MESSAGE_INCOMPLETE;
goto out; goto out;
} }
if ((dh_server_pub = sshdh_pubkey(kex->dh)) == NULL) {
klen = DH_size(kex->dh); r = SSH_ERR_INTERNAL_ERROR;
if ((kbuf = malloc(klen)) == NULL ||
(shared_secret = BN_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out; goto out;
} }
if ((kout = DH_compute_key(kbuf, dh_client_pub, kex->dh)) < 0 || if ((r = sshdh_compute_key(kex->dh, dh_client_pub,
BN_bin2bn(kbuf, kout, shared_secret) == NULL) { &shared_secret)) != 0)
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out; goto out;
}
#ifdef DEBUG_KEXDH #ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout); dump_digest("shared secret", kbuf, klen);
#endif #endif
if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob, if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob,
&sbloblen)) != 0) &sbloblen)) != 0)
@ -173,7 +162,7 @@ input_kex_dh_init(int type, u_int32_t seq, void *ctxt)
sshbuf_ptr(kex->my), sshbuf_len(kex->my), sshbuf_ptr(kex->my), sshbuf_len(kex->my),
server_host_key_blob, sbloblen, server_host_key_blob, sbloblen,
dh_client_pub, dh_client_pub,
kex->dh->pub_key, dh_server_pub,
shared_secret, shared_secret,
hash, &hashlen)) != 0) hash, &hashlen)) != 0)
goto out; goto out;
@ -199,7 +188,7 @@ input_kex_dh_init(int type, u_int32_t seq, void *ctxt)
/* send server hostkey, DH pubkey 'f' and singed H */ /* send server hostkey, DH pubkey 'f' and singed H */
if ((r = sshpkt_start(ssh, SSH2_MSG_KEXDH_REPLY)) != 0 || if ((r = sshpkt_start(ssh, SSH2_MSG_KEXDH_REPLY)) != 0 ||
(r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 || (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
(r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || /* f */ (r = sshpkt_put_bignum2_wrap(ssh, dh_server_pub)) != 0 || /* f */
(r = sshpkt_put_string(ssh, signature, slen)) != 0 || (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
(r = sshpkt_send(ssh)) != 0) (r = sshpkt_send(ssh)) != 0)
goto out; goto out;
@ -208,18 +197,12 @@ input_kex_dh_init(int type, u_int32_t seq, void *ctxt)
r = kex_send_newkeys(ssh); r = kex_send_newkeys(ssh);
out: out:
explicit_bzero(hash, sizeof(hash)); explicit_bzero(hash, sizeof(hash));
DH_free(kex->dh); sshbn_free(shared_secret);
sshbn_free(dh_client_pub);
sshbn_free(dh_server_pub);
sshdh_free(kex->dh);
kex->dh = NULL; kex->dh = NULL;
if (dh_client_pub)
BN_clear_free(dh_client_pub);
if (kbuf) {
explicit_bzero(kbuf, klen);
free(kbuf);
}
if (shared_secret)
BN_clear_free(shared_secret);
free(server_host_key_blob); free(server_host_key_blob);
free(signature); free(signature);
return r; return r;
} }
#endif /* WITH_OPENSSL */

View File

@ -26,8 +26,6 @@
#include "includes.h" #include "includes.h"
#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
#include <sys/types.h> #include <sys/types.h>
#include <stdio.h> #include <stdio.h>
@ -103,6 +101,7 @@ input_kex_ecdh_reply(int type, u_int32_t seq, void *ctxt)
EC_POINT *server_public = NULL; EC_POINT *server_public = NULL;
EC_KEY *client_key; EC_KEY *client_key;
BIGNUM *shared_secret = NULL; BIGNUM *shared_secret = NULL;
struct sshbn *xxx_shared_secret = NULL;
struct sshkey *server_host_key = NULL; struct sshkey *server_host_key = NULL;
u_char *server_host_key_blob = NULL, *signature = NULL; u_char *server_host_key_blob = NULL, *signature = NULL;
u_char *kbuf = NULL; u_char *kbuf = NULL;
@ -203,7 +202,13 @@ input_kex_ecdh_reply(int type, u_int32_t seq, void *ctxt)
memcpy(kex->session_id, hash, kex->session_id_len); memcpy(kex->session_id, hash, kex->session_id_len);
} }
if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) /* XXX */
if ((xxx_shared_secret = sshbn_from_bignum(shared_secret)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = kex_derive_keys_bn(ssh, hash, hashlen,
xxx_shared_secret)) == 0)
r = kex_send_newkeys(ssh); r = kex_send_newkeys(ssh);
out: out:
explicit_bzero(hash, sizeof(hash)); explicit_bzero(hash, sizeof(hash));
@ -219,10 +224,9 @@ input_kex_ecdh_reply(int type, u_int32_t seq, void *ctxt)
} }
if (shared_secret) if (shared_secret)
BN_clear_free(shared_secret); BN_clear_free(shared_secret);
sshbn_free(xxx_shared_secret);
sshkey_free(server_host_key); sshkey_free(server_host_key);
free(server_host_key_blob); free(server_host_key_blob);
free(signature); free(signature);
return r; return r;
} }
#endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */

View File

@ -26,7 +26,7 @@
#include "includes.h" #include "includes.h"
#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
#include <sys/types.h> #include <sys/types.h>
#include <string.h> #include <string.h>
@ -67,6 +67,7 @@ input_kex_ecdh_init(int type, u_int32_t seq, void *ctxt)
const EC_GROUP *group; const EC_GROUP *group;
const EC_POINT *public_key; const EC_POINT *public_key;
BIGNUM *shared_secret = NULL; BIGNUM *shared_secret = NULL;
struct sshbn *xxx_shared_secret = NULL;
struct sshkey *server_host_private, *server_host_public; struct sshkey *server_host_private, *server_host_public;
u_char *server_host_key_blob = NULL, *signature = NULL; u_char *server_host_key_blob = NULL, *signature = NULL;
u_char *kbuf = NULL; u_char *kbuf = NULL;
@ -183,8 +184,13 @@ input_kex_ecdh_init(int type, u_int32_t seq, void *ctxt)
(r = sshpkt_put_string(ssh, signature, slen)) != 0 || (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
(r = sshpkt_send(ssh)) != 0) (r = sshpkt_send(ssh)) != 0)
goto out; goto out;
/* XXX */
if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) if ((xxx_shared_secret = sshbn_from_bignum(shared_secret)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = kex_derive_keys_bn(ssh, hash, hashlen,
xxx_shared_secret)) == 0)
r = kex_send_newkeys(ssh); r = kex_send_newkeys(ssh);
out: out:
explicit_bzero(hash, sizeof(hash)); explicit_bzero(hash, sizeof(hash));
@ -200,9 +206,8 @@ input_kex_ecdh_init(int type, u_int32_t seq, void *ctxt)
} }
if (shared_secret) if (shared_secret)
BN_clear_free(shared_secret); BN_clear_free(shared_secret);
sshbn_free(xxx_shared_secret);
free(server_host_key_blob); free(server_host_key_blob);
free(signature); free(signature);
return r; return r;
} }
#endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */

View File

@ -35,8 +35,6 @@
#undef KRB5 #undef KRB5
#endif #endif
#ifdef WITH_OPENSSL
#include <sys/types.h> #include <sys/types.h>
#include <openssl/evp.h> #include <openssl/evp.h>
@ -49,9 +47,70 @@
#include "ssherr.h" #include "ssherr.h"
#include "sshbuf.h" #include "sshbuf.h"
#include "digest.h" #include "digest.h"
#include "crypto-wrap.h"
int int
kexgex_hash( kexgex_hash(
int hash_alg,
const char *client_version_string,
const char *server_version_string,
const u_char *ckexinit, size_t ckexinitlen,
const u_char *skexinit, size_t skexinitlen,
const u_char *serverhostkeyblob, size_t sbloblen,
int min, int wantbits, int max,
const struct sshbn *prime,
const struct sshbn *gen,
const struct sshbn *client_dh_pub,
const struct sshbn *server_dh_pub,
const struct sshbn *shared_secret,
u_char *hash, size_t *hashlen)
{
struct sshbuf *b;
int r;
if (*hashlen < ssh_digest_bytes(SSH_DIGEST_SHA1))
return SSH_ERR_INVALID_ARGUMENT;
if ((b = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshbuf_put_cstring(b, client_version_string)) != 0 ||
(r = sshbuf_put_cstring(b, server_version_string)) != 0 ||
/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
(r = sshbuf_put_u32(b, ckexinitlen + 1)) != 0 ||
(r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
(r = sshbuf_put(b, ckexinit, ckexinitlen)) != 0 ||
(r = sshbuf_put_u32(b, skexinitlen + 1)) != 0 ||
(r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
(r = sshbuf_put(b, skexinit, skexinitlen)) != 0 ||
(r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 ||
(min != -1 && (r = sshbuf_put_u32(b, min)) != 0) ||
(r = sshbuf_put_u32(b, wantbits)) != 0 ||
(max != -1 && (r = sshbuf_put_u32(b, max)) != 0) ||
(r = sshbuf_put_bignum2_wrap(b, prime)) != 0 ||
(r = sshbuf_put_bignum2_wrap(b, gen)) != 0 ||
(r = sshbuf_put_bignum2_wrap(b, client_dh_pub)) != 0 ||
(r = sshbuf_put_bignum2_wrap(b, server_dh_pub)) != 0 ||
(r = sshbuf_put_bignum2_wrap(b, shared_secret)) != 0) {
sshbuf_free(b);
return r;
}
#ifdef DEBUG_KEXDH
sshbuf_dump(b, stderr);
#endif
if (ssh_digest_buffer(hash_alg, b, hash, *hashlen) != 0) {
sshbuf_free(b);
return SSH_ERR_LIBCRYPTO_ERROR;
}
sshbuf_free(b);
*hashlen = ssh_digest_bytes(hash_alg);
#ifdef DEBUG_KEXDH
dump_digest("hash", hash, *hashlen);
#endif
return 0;
}
int
kexgex_hash_old(
int hash_alg, int hash_alg,
const char *client_version_string, const char *client_version_string,
const char *server_version_string, const char *server_version_string,
@ -108,4 +167,3 @@ kexgex_hash(
#endif #endif
return 0; return 0;
} }
#endif /* WITH_OPENSSL */

119
kexgexc.c
View File

@ -26,14 +26,11 @@
#include "includes.h" #include "includes.h"
#ifdef WITH_OPENSSL
#include <sys/param.h> #include <sys/param.h>
#include <sys/types.h> #include <sys/types.h>
#include <openssl/dh.h> #include <openssl/dh.h>
#include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <signal.h> #include <signal.h>
@ -54,6 +51,23 @@
static int input_kex_dh_gex_group(int, u_int32_t, void *); static int input_kex_dh_gex_group(int, u_int32_t, void *);
static int input_kex_dh_gex_reply(int, u_int32_t, void *); static int input_kex_dh_gex_reply(int, u_int32_t, void *);
int
kexgex_hash_old(
int hash_alg,
const char *client_version_string,
const char *server_version_string,
const u_char *ckexinit, size_t ckexinitlen,
const u_char *skexinit, size_t skexinitlen,
const u_char *serverhostkeyblob, size_t sbloblen,
int min, int wantbits, int max,
const BIGNUM *prime,
const BIGNUM *gen,
const BIGNUM *client_dh_pub,
const BIGNUM *server_dh_pub,
const BIGNUM *shared_secret,
u_char *hash, size_t *hashlen);
int int
kexgex_client(struct ssh *ssh) kexgex_client(struct ssh *ssh)
{ {
@ -93,52 +107,55 @@ input_kex_dh_gex_group(int type, u_int32_t seq, void *ctxt)
{ {
struct ssh *ssh = ctxt; struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex; struct kex *kex = ssh->kex;
BIGNUM *p = NULL, *g = NULL; struct sshbn *dh_client_pub = NULL;
int r, bits; struct sshbn *dh_g = NULL, *dh_p = NULL;
int r;
size_t bits;
debug("got SSH2_MSG_KEX_DH_GEX_GROUP"); debug("got SSH2_MSG_KEX_DH_GEX_GROUP");
if ((p = BN_new()) == NULL || if ((dh_p = sshbn_new()) == NULL ||
(g = BN_new()) == NULL) { (dh_g = sshbn_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL; r = SSH_ERR_ALLOC_FAIL;
goto out; goto out;
} }
if ((r = sshpkt_get_bignum2(ssh, p)) != 0 || if ((r = sshpkt_get_bignum2_wrap(ssh, dh_p)) != 0 ||
(r = sshpkt_get_bignum2(ssh, g)) != 0 || (r = sshpkt_get_bignum2_wrap(ssh, dh_g)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0) (r = sshpkt_get_end(ssh)) != 0)
goto out; goto out;
if ((bits = BN_num_bits(p)) < 0 || if ((bits = sshbn_bits(dh_p)) == 0 ||
(u_int)bits < kex->min || (u_int)bits > kex->max) { bits < kex->min || bits > kex->max) {
r = SSH_ERR_DH_GEX_OUT_OF_RANGE; r = SSH_ERR_DH_GEX_OUT_OF_RANGE;
goto out; goto out;
} }
if ((kex->dh = dh_new_group(g, p)) == NULL) { if ((kex->dh = sshdh_new_group(dh_g, dh_p)) == NULL) {
r = SSH_ERR_ALLOC_FAIL; r = SSH_ERR_ALLOC_FAIL;
goto out; goto out;
} }
p = g = NULL; /* belong to kex->dh now */ dh_p = dh_g = NULL; /* belong to kex->dh now */
/* generate and send 'e', client DH public key */ /* generate and send 'e', client DH public key */
if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0 || if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0)
(r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_INIT)) != 0 || goto out;
(r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || if ((dh_client_pub = sshdh_pubkey(kex->dh)) == NULL) {
r = SSH_ERR_INTERNAL_ERROR;
goto out;
}
if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_INIT)) != 0 ||
(r = sshpkt_put_bignum2_wrap(ssh, dh_client_pub)) != 0 ||
(r = sshpkt_send(ssh)) != 0) (r = sshpkt_send(ssh)) != 0)
goto out; goto out;
debug("SSH2_MSG_KEX_DH_GEX_INIT sent"); debug("SSH2_MSG_KEX_DH_GEX_INIT sent");
#ifdef DEBUG_KEXDH #ifdef DEBUG_KEXDH
DHparams_print_fp(stderr, kex->dh); sshdh_dump(kex->dh);
fprintf(stderr, "pub= ");
BN_print_fp(stderr, kex->dh->pub_key);
fprintf(stderr, "\n");
#endif #endif
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP, NULL); ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP, NULL);
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REPLY, &input_kex_dh_gex_reply); ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REPLY, &input_kex_dh_gex_reply);
r = 0; r = 0;
out: out:
if (p) sshbn_free(dh_p);
BN_clear_free(p); sshbn_free(dh_g);
if (g) sshbn_free(dh_client_pub);
BN_clear_free(g);
return r; return r;
} }
@ -147,12 +164,15 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
{ {
struct ssh *ssh = ctxt; struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex; struct kex *kex = ssh->kex;
BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; struct sshbn *dh_g = NULL, *dh_p = NULL;
struct sshbn *dh_client_pub = NULL;
struct sshbn *dh_server_pub = NULL;
struct sshbn *shared_secret = NULL;
struct sshkey *server_host_key = NULL; struct sshkey *server_host_key = NULL;
u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL; u_char *signature = NULL, *server_host_key_blob = NULL;
u_char hash[SSH_DIGEST_MAX_LENGTH]; u_char hash[SSH_DIGEST_MAX_LENGTH];
size_t klen = 0, slen, sbloblen, hashlen; size_t slen, sbloblen, hashlen;
int kout, r; int r;
debug("got SSH2_MSG_KEX_DH_GEX_REPLY"); debug("got SSH2_MSG_KEX_DH_GEX_REPLY");
if (kex->verify_host_key == NULL) { if (kex->verify_host_key == NULL) {
@ -180,12 +200,12 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
goto out; goto out;
} }
/* DH parameter f, server public DH key */ /* DH parameter f, server public DH key */
if ((dh_server_pub = BN_new()) == NULL) { if ((dh_server_pub = sshbn_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL; r = SSH_ERR_ALLOC_FAIL;
goto out; goto out;
} }
/* signed H */ /* signed H */
if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 || if ((r = sshpkt_get_bignum2_wrap(ssh, dh_server_pub)) != 0 ||
(r = sshpkt_get_string(ssh, &signature, &slen)) != 0 || (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0) (r = sshpkt_get_end(ssh)) != 0)
goto out; goto out;
@ -195,23 +215,19 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
fprintf(stderr, "\n"); fprintf(stderr, "\n");
debug("bits %d", BN_num_bits(dh_server_pub)); debug("bits %d", BN_num_bits(dh_server_pub));
#endif #endif
if (!dh_pub_is_valid(kex->dh, dh_server_pub)) { if ((r = dh_pub_is_valid(kex->dh, dh_server_pub)) != 0) {
sshpkt_disconnect(ssh, "bad server public DH value"); sshpkt_disconnect(ssh, "bad server public DH value");
r = SSH_ERR_MESSAGE_INCOMPLETE;
goto out; goto out;
} }
if ((dh_client_pub = sshdh_pubkey(kex->dh)) == NULL ||
klen = DH_size(kex->dh); (dh_p = sshdh_p(kex->dh)) == NULL ||
if ((kbuf = malloc(klen)) == NULL || (dh_g = sshdh_g(kex->dh)) == NULL) {
(shared_secret = BN_new()) == NULL) { r = SSH_ERR_INTERNAL_ERROR;
r = SSH_ERR_ALLOC_FAIL;
goto out; goto out;
} }
if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 || if ((r = sshdh_compute_key(kex->dh, dh_server_pub,
BN_bin2bn(kbuf, kout, shared_secret) == NULL) { &shared_secret)) != 0)
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out; goto out;
}
#ifdef DEBUG_KEXDH #ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout); dump_digest("shared secret", kbuf, kout);
#endif #endif
@ -228,8 +244,8 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
server_host_key_blob, sbloblen, server_host_key_blob, sbloblen,
kex->min, kex->nbits, kex->max, kex->min, kex->nbits, kex->max,
kex->dh->p, kex->dh->g, dh_p, dh_g,
kex->dh->pub_key, dh_client_pub,
dh_server_pub, dh_server_pub,
shared_secret, shared_secret,
hash, &hashlen)) != 0) hash, &hashlen)) != 0)
@ -254,19 +270,14 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
r = kex_send_newkeys(ssh); r = kex_send_newkeys(ssh);
out: out:
explicit_bzero(hash, sizeof(hash)); explicit_bzero(hash, sizeof(hash));
DH_free(kex->dh); sshbn_free(dh_p);
sshbn_free(dh_g);
sshbn_free(shared_secret);
sshbn_free(dh_client_pub);
sshbn_free(dh_server_pub);
sshdh_free(kex->dh);
kex->dh = NULL; kex->dh = NULL;
if (dh_server_pub)
BN_clear_free(dh_server_pub);
if (kbuf) {
explicit_bzero(kbuf, klen);
free(kbuf);
}
if (shared_secret)
BN_clear_free(shared_secret);
sshkey_free(server_host_key);
free(server_host_key_blob); free(server_host_key_blob);
free(signature); free(signature);
return r; return r;
} }
#endif /* WITH_OPENSSL */

View File

@ -30,16 +30,8 @@
* We support only client side kerberos on Windows. * We support only client side kerberos on Windows.
*/ */
#ifdef WIN32_FIXME
#undef GSSAPI
#undef KRB5
#endif
#ifdef WITH_OPENSSL
#include <sys/param.h> /* MIN MAX */ #include <sys/param.h> /* MIN MAX */
#include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <signal.h> #include <signal.h>
@ -80,6 +72,7 @@ input_kex_dh_gex_request(int type, u_int32_t seq, void *ctxt)
{ {
struct ssh *ssh = ctxt; struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex; struct kex *kex = ssh->kex;
struct sshbn *dh_g = NULL, *dh_p = NULL;
int r; int r;
u_int min = 0, max = 0, nbits = 0; u_int min = 0, max = 0, nbits = 0;
@ -110,10 +103,15 @@ input_kex_dh_gex_request(int type, u_int32_t seq, void *ctxt)
r = SSH_ERR_ALLOC_FAIL; r = SSH_ERR_ALLOC_FAIL;
goto out; goto out;
} }
if ((dh_p = sshdh_p(kex->dh)) == NULL ||
(dh_g = sshdh_g(kex->dh)) == NULL) {
r = SSH_ERR_INTERNAL_ERROR;
goto out;
}
debug("SSH2_MSG_KEX_DH_GEX_GROUP sent"); debug("SSH2_MSG_KEX_DH_GEX_GROUP sent");
if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_GROUP)) != 0 || if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_GROUP)) != 0 ||
(r = sshpkt_put_bignum2(ssh, kex->dh->p)) != 0 || (r = sshpkt_put_bignum2_wrap(ssh, dh_p)) != 0 ||
(r = sshpkt_put_bignum2(ssh, kex->dh->g)) != 0 || (r = sshpkt_put_bignum2_wrap(ssh, dh_g)) != 0 ||
(r = sshpkt_send(ssh)) != 0) (r = sshpkt_send(ssh)) != 0)
goto out; goto out;
@ -125,6 +123,8 @@ input_kex_dh_gex_request(int type, u_int32_t seq, void *ctxt)
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_INIT, &input_kex_dh_gex_init); ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_INIT, &input_kex_dh_gex_init);
r = 0; r = 0;
out: out:
sshbn_free(dh_g);
sshbn_free(dh_p);
return r; return r;
} }
@ -133,13 +133,15 @@ input_kex_dh_gex_init(int type, u_int32_t seq, void *ctxt)
{ {
struct ssh *ssh = ctxt; struct ssh *ssh = ctxt;
struct kex *kex = ssh->kex; struct kex *kex = ssh->kex;
BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; struct sshbn *dh_g = NULL, *dh_p = NULL;
struct sshbn *dh_client_pub = NULL;
struct sshbn *dh_server_pub = NULL;
struct sshbn *shared_secret = NULL;
struct sshkey *server_host_public, *server_host_private; struct sshkey *server_host_public, *server_host_private;
u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL; u_char *signature = NULL, *server_host_key_blob = NULL;
u_char hash[SSH_DIGEST_MAX_LENGTH]; u_char hash[SSH_DIGEST_MAX_LENGTH];
size_t sbloblen, slen; size_t sbloblen, slen, hashlen;
size_t klen = 0, hashlen; int r;
int kout, r;
if (kex->load_host_public_key == NULL || if (kex->load_host_public_key == NULL ||
kex->load_host_private_key == NULL) { kex->load_host_private_key == NULL) {
@ -156,11 +158,11 @@ input_kex_dh_gex_init(int type, u_int32_t seq, void *ctxt)
} }
/* key, cert */ /* key, cert */
if ((dh_client_pub = BN_new()) == NULL) { if ((dh_client_pub = sshbn_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL; r = SSH_ERR_ALLOC_FAIL;
goto out; goto out;
} }
if ((r = sshpkt_get_bignum2(ssh, dh_client_pub)) != 0 || if ((r = sshpkt_get_bignum2_wrap(ssh, dh_client_pub)) != 0 ||
(r = sshpkt_get_end(ssh)) != 0) (r = sshpkt_get_end(ssh)) != 0)
goto out; goto out;
@ -177,23 +179,19 @@ input_kex_dh_gex_init(int type, u_int32_t seq, void *ctxt)
BN_print_fp(stderr, kex->dh->pub_key); BN_print_fp(stderr, kex->dh->pub_key);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
#endif #endif
if (!dh_pub_is_valid(kex->dh, dh_client_pub)) { if ((r = dh_pub_is_valid(kex->dh, dh_client_pub)) != 0) {
sshpkt_disconnect(ssh, "bad client public DH value"); sshpkt_disconnect(ssh, "bad client public DH value");
r = SSH_ERR_MESSAGE_INCOMPLETE;
goto out; goto out;
} }
if ((dh_server_pub = sshdh_pubkey(kex->dh)) == NULL ||
klen = DH_size(kex->dh); (dh_p = sshdh_p(kex->dh)) == NULL ||
if ((kbuf = malloc(klen)) == NULL || (dh_g = sshdh_g(kex->dh)) == NULL) {
(shared_secret = BN_new()) == NULL) { r = SSH_ERR_INTERNAL_ERROR;
r = SSH_ERR_ALLOC_FAIL;
goto out; goto out;
} }
if ((kout = DH_compute_key(kbuf, dh_client_pub, kex->dh)) < 0 || if ((r = sshdh_compute_key(kex->dh, dh_client_pub,
BN_bin2bn(kbuf, kout, shared_secret) == NULL) { &shared_secret)) != 0)
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out; goto out;
}
#ifdef DEBUG_KEXDH #ifdef DEBUG_KEXDH
dump_digest("shared secret", kbuf, kout); dump_digest("shared secret", kbuf, kout);
#endif #endif
@ -210,9 +208,9 @@ input_kex_dh_gex_init(int type, u_int32_t seq, void *ctxt)
sshbuf_ptr(kex->my), sshbuf_len(kex->my), sshbuf_ptr(kex->my), sshbuf_len(kex->my),
server_host_key_blob, sbloblen, server_host_key_blob, sbloblen,
kex->min, kex->nbits, kex->max, kex->min, kex->nbits, kex->max,
kex->dh->p, kex->dh->g, dh_p, dh_g,
dh_client_pub, dh_client_pub,
kex->dh->pub_key, dh_server_pub,
shared_secret, shared_secret,
hash, &hashlen)) != 0) hash, &hashlen)) != 0)
goto out; goto out;
@ -238,7 +236,7 @@ input_kex_dh_gex_init(int type, u_int32_t seq, void *ctxt)
/* send server hostkey, DH pubkey 'f' and singed H */ /* send server hostkey, DH pubkey 'f' and singed H */
if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REPLY)) != 0 || if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REPLY)) != 0 ||
(r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 || (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
(r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || /* f */ (r = sshpkt_put_bignum2_wrap(ssh, dh_server_pub)) != 0 || /* f */
(r = sshpkt_put_string(ssh, signature, slen)) != 0 || (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
(r = sshpkt_send(ssh)) != 0) (r = sshpkt_send(ssh)) != 0)
goto out; goto out;
@ -246,18 +244,15 @@ input_kex_dh_gex_init(int type, u_int32_t seq, void *ctxt)
if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
r = kex_send_newkeys(ssh); r = kex_send_newkeys(ssh);
out: out:
DH_free(kex->dh); explicit_bzero(hash, sizeof(hash));
sshbn_free(dh_p);
sshbn_free(dh_g);
sshbn_free(shared_secret);
sshbn_free(dh_client_pub);
sshbn_free(dh_server_pub);
sshdh_free(kex->dh);
kex->dh = NULL; kex->dh = NULL;
if (dh_client_pub)
BN_clear_free(dh_client_pub);
if (kbuf) {
explicit_bzero(kbuf, klen);
free(kbuf);
}
if (shared_secret)
BN_clear_free(shared_secret);
free(server_host_key_blob); free(server_host_key_blob);
free(signature); free(signature);
return r; return r;
} }
#endif /* WITH_OPENSSL */

View File

@ -664,8 +664,11 @@ monitor_reset_key_state(void)
int int
mm_answer_moduli(int sock, Buffer *m) mm_answer_moduli(int sock, Buffer *m)
{ {
DH *dh; struct sshdh *dh;
int min, want, max; int min, want, max;
struct sshbn * dh_p = NULL;
struct sshbn * dh_g = NULL;
int ret = 0;
min = buffer_get_int(m); min = buffer_get_int(m);
want = buffer_get_int(m); want = buffer_get_int(m);
@ -681,18 +684,25 @@ mm_answer_moduli(int sock, Buffer *m)
buffer_clear(m); buffer_clear(m);
dh = choose_dh(min, want, max); dh = choose_dh(min, want, max);
if (dh == NULL) { if (dh == NULL) {
buffer_put_char(m, 0); buffer_put_char(m, 0);
return (0); return (0);
} else { } else {
if ((dh_p = sshdh_p(dh)) != NULL &&
(dh_g = sshdh_g(dh)) != NULL) {
/* Send first bignum */ /* Send first bignum */
buffer_put_char(m, 1); buffer_put_char(m, 1);
buffer_put_bignum2(m, dh->p); sshbuf_put_bignum2_wrap(m, dh_p);
buffer_put_bignum2(m, dh->g); sshbuf_put_bignum2_wrap(m, dh_g);
DH_free(dh);
}
mm_request_send(sock, MONITOR_ANS_MODULI, m); mm_request_send(sock, MONITOR_ANS_MODULI, m);
}
sshdh_free(dh);
sshbn_free(dh_p);
sshbn_free(dh_g);
}
return (0); return (0);
} }
#endif #endif

View File

@ -94,6 +94,7 @@
#include "roaming.h" #include "roaming.h"
#include "ssherr.h" #include "ssherr.h"
#include "crypto-wrap.h"
/* Imports */ /* Imports */
extern int compat20; extern int compat20;
@ -194,11 +195,11 @@ mm_request_receive_expect(int sock, enum monitor_reqtype type, Buffer *m)
} }
#ifdef WITH_OPENSSL #ifdef WITH_OPENSSL
DH * struct sshdh *
mm_choose_dh(int min, int nbits, int max) mm_choose_dh(int min, int nbits, int max)
{ {
BIGNUM *p, *g; struct sshbn *p, *g;
int success = 0; int r, success = 0;
Buffer m; Buffer m;
buffer_init(&m); buffer_init(&m);
@ -215,17 +216,16 @@ mm_choose_dh(int min, int nbits, int max)
if (success == 0) if (success == 0)
fatal("%s: MONITOR_ANS_MODULI failed", __func__); fatal("%s: MONITOR_ANS_MODULI failed", __func__);
if ((p = BN_new()) == NULL) if ((p = sshbn_new()) == NULL || (g = sshbn_new()) == NULL)
fatal("%s: BN_new failed", __func__); fatal("%s: BN_new failed", __func__);
if ((g = BN_new()) == NULL) if ((r = sshbuf_get_bignum2_wrap(&m, p)) != 0 ||
fatal("%s: BN_new failed", __func__); (r = sshbuf_get_bignum2_wrap(&m, g)) != 0)
buffer_get_bignum2(&m, p); fatal("%s: sshbuf_get_bignum2_wrap: %s", __func__, ssh_err(r));
buffer_get_bignum2(&m, g);
debug3("%s: remaining %d", __func__, buffer_len(&m)); debug3("%s: remaining %d", __func__, buffer_len(&m));
buffer_free(&m); buffer_free(&m);
return (dh_new_group(g, p)); return (sshdh_new_group(g, p));
} }
#endif #endif
@ -279,12 +279,8 @@ mm_getpwnamallow(const char *username)
fatal("%s: struct passwd size mismatch", __func__); fatal("%s: struct passwd size mismatch", __func__);
pw->pw_name = buffer_get_string(&m, NULL); pw->pw_name = buffer_get_string(&m, NULL);
pw->pw_passwd = buffer_get_string(&m, NULL); pw->pw_passwd = buffer_get_string(&m, NULL);
#ifdef HAVE_STRUCT_PASSWD_PW_GECOS
pw->pw_gecos = buffer_get_string(&m, NULL); pw->pw_gecos = buffer_get_string(&m, NULL);
#endif // pw->pw_class = buffer_get_string(&m, NULL);
#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
pw->pw_class = buffer_get_string(&m, NULL);
#endif
pw->pw_dir = buffer_get_string(&m, NULL); pw->pw_dir = buffer_get_string(&m, NULL);
pw->pw_shell = buffer_get_string(&m, NULL); pw->pw_shell = buffer_get_string(&m, NULL);
@ -575,137 +571,6 @@ mm_session_pty_cleanup2(Session *s)
s->ttyfd = -1; s->ttyfd = -1;
} }
#ifdef USE_PAM
void
mm_start_pam(Authctxt *authctxt)
{
Buffer m;
debug3("%s entering", __func__);
if (!options.use_pam)
fatal("UsePAM=no, but ended up in %s anyway", __func__);
buffer_init(&m);
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_START, &m);
buffer_free(&m);
}
u_int
mm_do_pam_account(void)
{
Buffer m;
u_int ret;
char *msg;
debug3("%s entering", __func__);
if (!options.use_pam)
fatal("UsePAM=no, but ended up in %s anyway", __func__);
buffer_init(&m);
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_ACCOUNT, &m);
mm_request_receive_expect(pmonitor->m_recvfd,
MONITOR_ANS_PAM_ACCOUNT, &m);
ret = buffer_get_int(&m);
msg = buffer_get_string(&m, NULL);
buffer_append(&loginmsg, msg, strlen(msg));
free(msg);
buffer_free(&m);
debug3("%s returning %d", __func__, ret);
return (ret);
}
void *
mm_sshpam_init_ctx(Authctxt *authctxt)
{
Buffer m;
int success;
debug3("%s", __func__);
buffer_init(&m);
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_INIT_CTX, &m);
debug3("%s: waiting for MONITOR_ANS_PAM_INIT_CTX", __func__);
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_INIT_CTX, &m);
success = buffer_get_int(&m);
if (success == 0) {
debug3("%s: pam_init_ctx failed", __func__);
buffer_free(&m);
return (NULL);
}
buffer_free(&m);
return (authctxt);
}
int
mm_sshpam_query(void *ctx, char **name, char **info,
u_int *num, char ***prompts, u_int **echo_on)
{
Buffer m;
u_int i;
int ret;
debug3("%s", __func__);
buffer_init(&m);
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_QUERY, &m);
debug3("%s: waiting for MONITOR_ANS_PAM_QUERY", __func__);
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_QUERY, &m);
ret = buffer_get_int(&m);
debug3("%s: pam_query returned %d", __func__, ret);
*name = buffer_get_string(&m, NULL);
*info = buffer_get_string(&m, NULL);
*num = buffer_get_int(&m);
if (*num > PAM_MAX_NUM_MSG)
fatal("%s: recieved %u PAM messages, expected <= %u",
__func__, *num, PAM_MAX_NUM_MSG);
*prompts = xcalloc((*num + 1), sizeof(char *));
*echo_on = xcalloc((*num + 1), sizeof(u_int));
for (i = 0; i < *num; ++i) {
(*prompts)[i] = buffer_get_string(&m, NULL);
(*echo_on)[i] = buffer_get_int(&m);
}
buffer_free(&m);
return (ret);
}
int
mm_sshpam_respond(void *ctx, u_int num, char **resp)
{
Buffer m;
u_int i;
int ret;
debug3("%s", __func__);
buffer_init(&m);
buffer_put_int(&m, num);
for (i = 0; i < num; ++i)
buffer_put_cstring(&m, resp[i]);
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_RESPOND, &m);
debug3("%s: waiting for MONITOR_ANS_PAM_RESPOND", __func__);
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_RESPOND, &m);
ret = buffer_get_int(&m);
debug3("%s: pam_respond returned %d", __func__, ret);
buffer_free(&m);
return (ret);
}
void
mm_sshpam_free_ctx(void *ctxtp)
{
Buffer m;
debug3("%s", __func__);
buffer_init(&m);
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PAM_FREE_CTX, &m);
debug3("%s: waiting for MONITOR_ANS_PAM_FREE_CTX", __func__);
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_PAM_FREE_CTX, &m);
buffer_free(&m);
}
#endif /* USE_PAM */
/* Request process termination */ /* Request process termination */
void void
@ -809,66 +674,6 @@ mm_bsdauth_respond(void *ctx, u_int numresponses, char **responses)
return ((authok == 0) ? -1 : 0); return ((authok == 0) ? -1 : 0);
} }
#ifdef SKEY
int
mm_skey_query(void *ctx, char **name, char **infotxt,
u_int *numprompts, char ***prompts, u_int **echo_on)
{
Buffer m;
u_int success;
char *challenge;
debug3("%s: entering", __func__);
buffer_init(&m);
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_SKEYQUERY, &m);
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_SKEYQUERY,
&m);
success = buffer_get_int(&m);
if (success == 0) {
debug3("%s: no challenge", __func__);
buffer_free(&m);
return (-1);
}
/* Get the challenge, and format the response */
challenge = buffer_get_string(&m, NULL);
buffer_free(&m);
debug3("%s: received challenge: %s", __func__, challenge);
mm_chall_setup(name, infotxt, numprompts, prompts, echo_on);
xasprintf(*prompts, "%s%s", challenge, SKEY_PROMPT);
free(challenge);
return (0);
}
int
mm_skey_respond(void *ctx, u_int numresponses, char **responses)
{
Buffer m;
int authok;
debug3("%s: entering", __func__);
if (numresponses != 1)
return (-1);
buffer_init(&m);
buffer_put_cstring(&m, responses[0]);
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_SKEYRESPOND, &m);
mm_request_receive_expect(pmonitor->m_recvfd,
MONITOR_ANS_SKEYRESPOND, &m);
authok = buffer_get_int(&m);
buffer_free(&m);
return ((authok == 0) ? -1 : 0);
}
#endif /* SKEY */
void void
mm_ssh1_session_id(u_char session_id[16]) mm_ssh1_session_id(u_char session_id[16])
@ -984,36 +789,6 @@ mm_auth_rsa_verify_response(Key *key, BIGNUM *p, u_char response[16])
} }
#endif #endif
#ifdef SSH_AUDIT_EVENTS
void
mm_audit_event(ssh_audit_event_t event)
{
Buffer m;
debug3("%s entering", __func__);
buffer_init(&m);
buffer_put_int(&m, event);
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_EVENT, &m);
buffer_free(&m);
}
void
mm_audit_run_command(const char *command)
{
Buffer m;
debug3("%s entering command %s", __func__, command);
buffer_init(&m);
buffer_put_cstring(&m, command);
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_COMMAND, &m);
buffer_free(&m);
}
#endif /* SSH_AUDIT_EVENTS */
#ifdef GSSAPI #ifdef GSSAPI
OM_uint32 OM_uint32
mm_ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID goid) mm_ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID goid)

View File

@ -39,7 +39,7 @@ struct Authctxt;
void mm_log_handler(LogLevel, const char *, void *); void mm_log_handler(LogLevel, const char *, void *);
int mm_is_monitor(void); int mm_is_monitor(void);
DH *mm_choose_dh(int, int, int); struct sshdh *mm_choose_dh(int, int, int);
int mm_key_sign(Key *, u_char **, u_int *, const u_char *, u_int); int mm_key_sign(Key *, u_char **, u_int *, const u_char *, u_int);
void mm_inform_authserv(char *, char *); void mm_inform_authserv(char *, char *);
struct passwd *mm_getpwnamallow(const char *); struct passwd *mm_getpwnamallow(const char *);

View File

@ -203,6 +203,8 @@ realpath(const char *path, char resolved[PATH_MAX])
#else #else
#include <Shlwapi.h>
void backslashconvert(char *str) void backslashconvert(char *str)
{ {
while (*str) { while (*str) {

214
openssl-bn.c Normal file
View File

@ -0,0 +1,214 @@
/*
* Copyright (c) 2015 Damien Miller <djm@mindrot.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <includes.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <openssl/bn.h>
#include "sshbuf.h"
#include "packet.h"
#include "ssherr.h"
#include "crypto-wrap.h"
struct sshbn {
BIGNUM *bn;
};
static struct sshbn *
bnwrap(BIGNUM *bn)
{
struct sshbn *ret;
if (bn == NULL)
return NULL;
if ((ret = calloc(1, sizeof(*ret))) == NULL)
return NULL;
if ((ret->bn = BN_dup(bn)) == NULL) {
free(ret);
return NULL;
}
return ret;
}
struct sshbn *
sshbn_new(void)
{
return bnwrap(BN_new());
}
void
sshbn_free(struct sshbn *bn)
{
if (bn != NULL) {
if (bn->bn != NULL)
BN_clear_free(bn->bn);
explicit_bzero(bn, sizeof(*bn));
free(bn);
}
}
int
sshbn_from(const void *d, size_t l, struct sshbn **retp)
{
struct sshbn *ret;
const u_char *dd = (const u_char *)d;
*retp = NULL;
if (l > INT_MAX)
return SSH_ERR_INVALID_ARGUMENT;
if ((ret = sshbn_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if (BN_bin2bn(dd, (int)l, ret->bn) == NULL) {
sshbn_free(ret);
return SSH_ERR_LIBCRYPTO_ERROR;
}
*retp = ret;
return 0;
}
int
sshbn_from_hex(const char *hex, struct sshbn **retp)
{
struct sshbn *ret;
*retp = NULL;
if ((ret = sshbn_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if (BN_hex2bn(&ret->bn, hex) <= 0) {
sshbn_free(ret);
return SSH_ERR_LIBCRYPTO_ERROR;
}
*retp = ret;
return 0;
}
int sshbn_to(const struct sshbn *a, unsigned char *to)
{
return BN_bn2bin(sshbn_bignum(a), to);
}
size_t
sshbn_bytes(const struct sshbn *bn)
{
int bytes = BN_num_bytes(bn->bn);
return bytes < 0 ? 0 : (size_t)bytes;
}
size_t
sshbn_bits(const struct sshbn *bn)
{
int bits = BN_num_bits(bn->bn);
return bits < 0 ? 0 : (size_t)bits;
}
const struct sshbn *
sshbn_value_0(void)
{
static struct sshbn *ret;
if (ret == NULL)
sshbn_from_hex("0", &ret);
return ret;
}
const struct sshbn *
sshbn_value_1(void)
{
static struct sshbn *ret;
if (ret == NULL)
sshbn_from_hex("1", &ret);
return ret;
}
int
sshbn_cmp(const struct sshbn *a, const struct sshbn *b)
{
return BN_cmp(a->bn, b->bn);
}
int
sshbn_sub(struct sshbn *r, const struct sshbn *a, const struct sshbn *b)
{
if (BN_sub(r->bn, a->bn, b->bn) != 1)
return SSH_ERR_LIBCRYPTO_ERROR;
return 0;
}
int
sshbn_is_bit_set(const struct sshbn *bn, size_t i)
{
if (i > INT_MAX)
return 0;
return BN_is_bit_set(bn->bn, (int)i);
}
/* XXX move to sshbuf.h */
int
sshbuf_get_bignum2_wrap(struct sshbuf *buf, struct sshbn *bn)
{
return sshbuf_get_bignum2(buf, bn->bn);
}
int
sshbuf_put_bignum2_wrap(struct sshbuf *buf, const struct sshbn *bn)
{
return sshbuf_put_bignum2(buf, bn->bn);
}
int
sshpkt_get_bignum2_wrap(struct ssh *ssh, struct sshbn *bn)
{
return sshpkt_get_bignum2(ssh, bn->bn);
}
int
sshpkt_put_bignum2_wrap(struct ssh *ssh, const struct sshbn *bn)
{
return sshpkt_put_bignum2(ssh, bn->bn);
}
/* bridge to unwrapped OpenSSL APIs; XXX remove later */
BIGNUM *
sshbn_bignum(struct sshbn *bn)
{
return bn->bn;
}
struct sshbn *
sshbn_from_bignum(BIGNUM *bn)
{
return bnwrap(bn);
}

199
openssl-dh.c Normal file
View File

@ -0,0 +1,199 @@
/*
* Copyright (c) 2015 Damien Miller <djm@mindrot.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <includes.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <openssl/dh.h>
#include <openssl/evp.h>
#include "sshbuf.h"
#include "packet.h"
#include "ssherr.h"
#include "crypto-wrap.h"
struct sshdh {
DH *dh;
};
struct sshbn {
BIGNUM *bn;
};
static struct sshbn *
bnwrap(BIGNUM *bn)
{
struct sshbn *ret;
if (bn == NULL)
return NULL;
if ((ret = calloc(1, sizeof(*ret))) == NULL)
return NULL;
if ((ret->bn = BN_dup(bn)) == NULL) {
free(ret);
return NULL;
}
return ret;
}
/* DH wrappers */
struct sshdh *
sshdh_new(void)
{
struct sshdh *ret;
if ((ret = calloc(1, sizeof(*ret))) == NULL)
return NULL;
if ((ret->dh = DH_new()) == NULL) {
free(ret);
return NULL;
}
return ret;
}
void
sshdh_free(struct sshdh *dh)
{
if (dh != NULL) {
if (dh->dh != NULL)
DH_free(dh->dh);
explicit_bzero(dh, sizeof(*dh));
free(dh);
}
}
struct sshbn *
sshdh_pubkey(struct sshdh *dh)
{
return bnwrap(dh->dh->pub_key);
}
struct sshbn *
sshdh_p(struct sshdh *dh)
{
return bnwrap(dh->dh->p);
}
struct sshbn *
sshdh_g(struct sshdh *dh)
{
return bnwrap(dh->dh->g);
}
void
sshdh_dump(struct sshdh *dh)
{
DHparams_print_fp(stderr, dh->dh);
fprintf(stderr, "pub= ");
BN_print_fp(stderr, dh->dh->pub_key);
fprintf(stderr, "\n");
}
// XXX needed?
size_t
sshdh_shared_key_size(struct sshdh *dh)
{
int sz;
if (dh == NULL || dh->dh == NULL || (sz = DH_size(dh->dh)) < 0)
return 0;
return (size_t)sz;
}
int sshdh_compute_key(struct sshdh *dh, struct sshbn *pubkey,
struct sshbn **shared_secretp)
{
u_char *sbuf;
int r, slen;
*shared_secretp = NULL;
if ((slen = DH_size(dh->dh)) <= 0)
return SSH_ERR_INVALID_ARGUMENT;
if ((sbuf = calloc(1, slen)) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = DH_compute_key(sbuf, pubkey->bn, dh->dh)) < 0 ||
r != slen) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
if ((r = sshbn_from(sbuf, slen, shared_secretp)) != 0)
goto out;
/* success */
r = 0;
out:
explicit_bzero(sbuf, slen);
free(sbuf);
return r;
}
int
sshdh_generate(struct sshdh *dh, size_t len)
{
if (len > INT_MAX)
return SSH_ERR_INVALID_ARGUMENT;
if (len != 0)
dh->dh->length = (int)len;
if (DH_generate_key(dh->dh) != 1)
return SSH_ERR_LIBCRYPTO_ERROR;
return 0;
}
int
sshdh_new_group_hex(const char *gen, const char *modulus, struct sshdh **dhp)
{
struct sshdh *ret;
*dhp = NULL;
if ((ret = sshdh_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if (BN_hex2bn(&ret->dh->p, modulus) == 0 ||
BN_hex2bn(&ret->dh->g, gen) == 0) {
sshdh_free(ret);
return SSH_ERR_LIBCRYPTO_ERROR;
}
*dhp = ret;
return 0;
}
/* XXX transfers ownership of gen, modulus */
struct sshdh *
sshdh_new_group(struct sshbn *gen, struct sshbn *modulus)
{
struct sshdh *dh;
if ((dh = sshdh_new()) == NULL)
return NULL;
dh->dh->p = modulus->bn;
dh->dh->g = gen->bn;
modulus->bn = gen->bn = NULL;
sshbn_free(gen);
sshbn_free(modulus);
return (dh);
}
DH *sshdh_dh(struct sshdh *dh)
{
return dh->dh;
}

View File

@ -1723,7 +1723,7 @@ initialize_options(Options * options)
options->tun_remote = -1; options->tun_remote = -1;
options->local_command = NULL; options->local_command = NULL;
options->permit_local_command = -1; options->permit_local_command = -1;
options->use_roaming = -1; options->use_roaming = 0;
options->visual_host_key = -1; options->visual_host_key = -1;
options->ip_qos_interactive = -1; options->ip_qos_interactive = -1;
options->ip_qos_bulk = -1; options->ip_qos_bulk = -1;
@ -1941,8 +1941,7 @@ void fill_default_options(Options * options, struct passwd *pw)
options->tun_remote = SSH_TUNID_ANY; options->tun_remote = SSH_TUNID_ANY;
if (options->permit_local_command == -1) if (options->permit_local_command == -1)
options->permit_local_command = 0; options->permit_local_command = 0;
if (options->use_roaming == -1) options->use_roaming = 0;
options->use_roaming = 1;
if (options->visual_host_key == -1) if (options->visual_host_key == -1)
options->visual_host_key = 0; options->visual_host_key = 0;
if (options->ip_qos_interactive == -1) if (options->ip_qos_interactive == -1)

View File

@ -520,6 +520,11 @@ main(int argc, char **argv)
fprintf(stderr, "Could not open a connection to your " fprintf(stderr, "Could not open a connection to your "
"authentication agent.\n"); "authentication agent.\n");
exit(2); exit(2);
#ifdef WIN32_FIXME
case SSH_ERR_SYSTEM_ERROR:
fprintf(stderr, "Error connecting to agent: ssh-agent.exe may not be running\n");
exit(2);
#endif
default: default:
fprintf(stderr, "Error connecting to agent: %s\n", ssh_err(r)); fprintf(stderr, "Error connecting to agent: %s\n", ssh_err(r));
exit(2); exit(2);

View File

@ -1734,7 +1734,9 @@ main(int ac, char **av)
cleanup_exit(1); cleanup_exit(1);
} }
if (pid != 0) { /* Parent - execute the given command. */ if (pid != 0) { /* Parent - execute the given command. */
#ifndef WIN32_FIXME
close(sock); close(sock);
#endif
snprintf(pidstrbuf, sizeof pidstrbuf, "%ld", (long)pid); snprintf(pidstrbuf, sizeof pidstrbuf, "%ld", (long)pid);
if (ac == 0) { if (ac == 0) {
#ifdef WIN32_FIXME #ifdef WIN32_FIXME
@ -1748,6 +1750,11 @@ main(int ac, char **av)
printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf, printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
SSH_AGENTPID_ENV_NAME); SSH_AGENTPID_ENV_NAME);
printf("echo Agent pid %ld;\n", (long)pid); printf("echo Agent pid %ld;\n", (long)pid);
#ifdef WIN32_FIXME
SetEnvironmentVariable(SSH_AUTHSOCKET_ENV_NAME, socket_name);
SetEnvironmentVariable(SSH_AGENTPID_ENV_NAME, pidstrbuf);
system("start cmd");
#endif
exit(0); exit(0);
} }
if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 || if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 ||

2
ssh.c
View File

@ -2163,8 +2163,6 @@ ssh_session2(void)
fork_postauth(); fork_postauth();
} }
if (options.use_roaming)
request_roaming();
return client_loop(tty_flag, tty_flag ? return client_loop(tty_flag, tty_flag ?
options.escape_char : SSH_ESCAPECHAR_NONE, id); options.escape_char : SSH_ESCAPECHAR_NONE, id);

View File

@ -76,6 +76,8 @@
#include "ssh-gss.h" #include "ssh-gss.h"
#endif #endif
/* import */ /* import */
extern char *client_version_string; extern char *client_version_string;
extern char *server_version_string; extern char *server_version_string;
@ -211,15 +213,16 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
if ((r = kex_setup(active_state, myproposal)) != 0) if ((r = kex_setup(active_state, myproposal)) != 0)
fatal("kex_setup: %s", ssh_err(r)); fatal("kex_setup: %s", ssh_err(r));
kex = active_state->kex; kex = active_state->kex;
#ifdef WITH_OPENSSL
kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client;
kex->kex[KEX_DH_GEX_SHA1] = kexgex_client; kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
kex->kex[KEX_DH_GEX_SHA256] = kexgex_client; kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
# ifdef OPENSSL_HAS_ECC # ifdef OPENSSL_HAS_ECC
kex->kex[KEX_ECDH_SHA2] = kexecdh_client; kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
# endif # endif
#endif
kex->kex[KEX_C25519_SHA256] = kexc25519_client; kex->kex[KEX_C25519_SHA256] = kexc25519_client;
kex->client_version_string=client_version_string; kex->client_version_string=client_version_string;
kex->server_version_string=server_version_string; kex->server_version_string=server_version_string;

8
sshd.c
View File

@ -145,6 +145,8 @@
#define O_NOCTTY 0 #define O_NOCTTY 0
#endif #endif
/* Re-exec fds */ /* Re-exec fds */
#define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1) #define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1)
#define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2) #define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2)
@ -3378,15 +3380,17 @@ do_ssh2_kex(void)
if ((r = kex_setup(active_state, myproposal)) != 0) if ((r = kex_setup(active_state, myproposal)) != 0)
fatal("kex_setup: %s", ssh_err(r)); fatal("kex_setup: %s", ssh_err(r));
kex = active_state->kex; kex = active_state->kex;
#ifdef WITH_OPENSSL
kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
# ifdef OPENSSL_HAS_ECC # ifdef OPENSSL_HAS_ECC
kex->kex[KEX_ECDH_SHA2] = kexecdh_server; kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
# endif # endif
#endif
kex->kex[KEX_C25519_SHA256] = kexc25519_server; kex->kex[KEX_C25519_SHA256] = kexc25519_server;
kex->server = 1; kex->server = 1;
kex->client_version_string=client_version_string; kex->client_version_string=client_version_string;