mirror of
https://github.com/PowerShell/Win32-OpenSSH.git
synced 2025-07-23 14:04:59 +02:00
Merge branch 'L1' into L2-Win32Posix-Prototype
This commit is contained in:
commit
888020265b
3
.gitignore
vendored
3
.gitignore
vendored
@ -275,4 +275,5 @@ Makefile.in
|
||||
|
||||
#temp key files
|
||||
d2utmpa*
|
||||
configure
|
||||
configure
|
||||
contrib/win32/openssh/Win32-OpenSSH.VC.opendb
|
8
authfd.c
8
authfd.c
@ -114,6 +114,14 @@ ssh_get_authentication_socket(int *fdp)
|
||||
errno = oerrno;
|
||||
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 */
|
||||
|
||||
if (fdp != NULL)
|
||||
|
@ -103,6 +103,12 @@ EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssh-lsa", "ssh-lsa.vcxproj", "{02FB3D98-6516-42C6-9762-98811A99960F}"
|
||||
EndProject
|
||||
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
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
@ -258,6 +258,13 @@
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)uuencode.c" />
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)verify.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>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
@ -288,5 +288,16 @@
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)xmalloc.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</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>
|
||||
</Project>
|
@ -114,6 +114,9 @@
|
||||
<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>
|
||||
</Link>
|
||||
<Manifest>
|
||||
<AdditionalManifestFiles>targetos.manifest</AdditionalManifestFiles>
|
||||
</Manifest>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
@ -133,6 +136,9 @@
|
||||
<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>
|
||||
</Link>
|
||||
<Manifest>
|
||||
<AdditionalManifestFiles>targetos.manifest</AdditionalManifestFiles>
|
||||
</Manifest>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
@ -154,6 +160,9 @@
|
||||
<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>
|
||||
</Link>
|
||||
<Manifest>
|
||||
<AdditionalManifestFiles>targetos.manifest</AdditionalManifestFiles>
|
||||
</Manifest>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
@ -176,6 +185,9 @@
|
||||
<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>
|
||||
</Link>
|
||||
<Manifest>
|
||||
<AdditionalManifestFiles>targetos.manifest</AdditionalManifestFiles>
|
||||
</Manifest>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="$(OpenSSH-Src-Path)acss.h" />
|
||||
|
@ -110,6 +110,9 @@
|
||||
<AdditionalLibraryDirectories>$(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Debug-Path)lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<ForceFileOutput>MultiplyDefinedSymbolOnly</ForceFileOutput>
|
||||
</Link>
|
||||
<Manifest>
|
||||
<AdditionalManifestFiles>targetos.manifest</AdditionalManifestFiles>
|
||||
</Manifest>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
@ -130,6 +133,9 @@
|
||||
<AdditionalLibraryDirectories>$(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Debug-Path)lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<ForceFileOutput>MultiplyDefinedSymbolOnly</ForceFileOutput>
|
||||
</Link>
|
||||
<Manifest>
|
||||
<AdditionalManifestFiles>targetos.manifest</AdditionalManifestFiles>
|
||||
</Manifest>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
@ -153,6 +159,9 @@
|
||||
<AdditionalLibraryDirectories>$(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Release-Path)lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<ForceFileOutput>MultiplyDefinedSymbolOnly</ForceFileOutput>
|
||||
</Link>
|
||||
<Manifest>
|
||||
<AdditionalManifestFiles>targetos.manifest</AdditionalManifestFiles>
|
||||
</Manifest>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
@ -177,6 +186,9 @@
|
||||
<AdditionalLibraryDirectories>$(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Release-Path)lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<ForceFileOutput>MultiplyDefinedSymbolOnly</ForceFileOutput>
|
||||
</Link>
|
||||
<Manifest>
|
||||
<AdditionalManifestFiles>targetos.manifest</AdditionalManifestFiles>
|
||||
</Manifest>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)audit-bsm.c" />
|
||||
|
17
contrib/win32/openssh/targetos.manifest
Normal file
17
contrib/win32/openssh/targetos.manifest
Normal 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>
|
@ -159,6 +159,13 @@
|
||||
<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\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>
|
||||
<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\tnnet.h" />
|
||||
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\win32auth.h" />
|
||||
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\cng_kex.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
@ -81,6 +81,12 @@
|
||||
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\win32auth.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</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>
|
||||
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\ansiprsr.h">
|
||||
@ -125,5 +131,11 @@
|
||||
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\win32auth.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</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>
|
||||
</Project>
|
324
contrib/win32/win32compat/cng_dh.c
Normal file
324
contrib/win32/win32compat/cng_dh.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
487
contrib/win32/win32compat/cng_openssl_dh.c
Normal file
487
contrib/win32/win32compat/cng_openssl_dh.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -2013,9 +2013,10 @@ int cleanSelectThread(int thread_no)
|
||||
|
||||
if(thread_data_set[thread_no] != NULL)
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, thread_data_set[thread_no]);
|
||||
|
||||
thread_data_set[thread_no] = NULL;
|
||||
thread_data_p ap = thread_data_set[thread_no];
|
||||
thread_data_set[thread_no] = NULL;
|
||||
HeapFree(GetProcessHeap(), 0, ap);
|
||||
|
||||
}
|
||||
|
||||
DBG_MSG("<- cleanSelectThread()...\n");
|
||||
|
51
crypto-wrap.h
Normal file
51
crypto-wrap.h
Normal 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 */
|
320
dh.c
320
dh.c
@ -41,6 +41,7 @@
|
||||
#include "log.h"
|
||||
#include "misc.h"
|
||||
#include "ssherr.h"
|
||||
#include "crypto-wrap.h"
|
||||
|
||||
static int
|
||||
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;
|
||||
const char *errstr = NULL;
|
||||
long long n;
|
||||
int r;
|
||||
|
||||
dhg->p = dhg->g = NULL;
|
||||
cp = line;
|
||||
@ -109,53 +111,45 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((dhg->g = BN_new()) == NULL ||
|
||||
(dhg->p = BN_new()) == NULL) {
|
||||
error("parse_prime: BN_new failed");
|
||||
if ((r = sshbn_from_hex(gen, &dhg->g)) != 0 ||
|
||||
(r = sshbn_from_hex(prime, &dhg->p)) != 0)
|
||||
{
|
||||
goto fail;
|
||||
}
|
||||
if (BN_hex2bn(&dhg->g, gen) == 0) {
|
||||
error("moduli:%d: could not parse generator value", linenum);
|
||||
if (sshbn_bits(dhg->p) != dhg->size) {
|
||||
error("moduli:%d: prime has wrong size: actual %zu listed %zu",
|
||||
linenum, sshbn_bits(dhg->p), dhg->size - 1);
|
||||
goto fail;
|
||||
}
|
||||
if (BN_hex2bn(&dhg->p, prime) == 0) {
|
||||
error("moduli:%d: could not parse prime value", linenum);
|
||||
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) {
|
||||
|
||||
if (sshbn_cmp(dhg->g, sshbn_value_1()) <= 0) {
|
||||
error("moduli:%d: generator is invalid", linenum);
|
||||
goto fail;
|
||||
}
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
if (dhg->g != NULL)
|
||||
BN_clear_free(dhg->g);
|
||||
if (dhg->p != NULL)
|
||||
BN_clear_free(dhg->p);
|
||||
sshbn_free(dhg->g);
|
||||
sshbn_free(dhg->p);
|
||||
dhg->g = dhg->p = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DH *
|
||||
choose_dh(int min, int wantbits, int max)
|
||||
struct sshdh *
|
||||
choose_dh(u_int min, u_int wantbits, u_int max)
|
||||
{
|
||||
FILE *f;
|
||||
char line[4096];
|
||||
int best, bestcount, which;
|
||||
int linenum;
|
||||
u_int best, bestcount, which, linenum;
|
||||
int r;
|
||||
struct dhgroup dhg;
|
||||
struct sshdh *dh = NULL;
|
||||
|
||||
if ((f = fopen(_PATH_DH_MODULI, "r")) == NULL &&
|
||||
(f = fopen(_PATH_DH_PRIMES, "r")) == NULL) {
|
||||
logit("WARNING: %s does not exist, using fixed modulus",
|
||||
_PATH_DH_MODULI);
|
||||
return (dh_new_group_fallback(max));
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
linenum = 0;
|
||||
@ -164,8 +158,8 @@ choose_dh(int min, int wantbits, int max)
|
||||
linenum++;
|
||||
if (!parse_prime(linenum, line, &dhg))
|
||||
continue;
|
||||
BN_clear_free(dhg.g);
|
||||
BN_clear_free(dhg.p);
|
||||
sshbn_free(dhg.g);
|
||||
sshbn_free(dhg.p);
|
||||
|
||||
if (dhg.size > max || dhg.size < min)
|
||||
continue;
|
||||
@ -183,7 +177,7 @@ choose_dh(int min, int wantbits, int max)
|
||||
if (bestcount == 0) {
|
||||
fclose(f);
|
||||
logit("WARNING: no suitable primes in %s", _PATH_DH_PRIMES);
|
||||
return (dh_new_group_fallback(max));
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
linenum = 0;
|
||||
@ -194,8 +188,8 @@ choose_dh(int min, int wantbits, int max)
|
||||
if ((dhg.size > max || dhg.size < min) ||
|
||||
dhg.size != best ||
|
||||
linenum++ != which) {
|
||||
BN_clear_free(dhg.g);
|
||||
BN_clear_free(dhg.p);
|
||||
sshbn_free(dhg.g);
|
||||
sshbn_free(dhg.p);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@ -204,187 +198,181 @@ choose_dh(int min, int wantbits, int max)
|
||||
if (linenum != which+1) {
|
||||
logit("WARNING: line %d disappeared in %s, giving up",
|
||||
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 */
|
||||
|
||||
int
|
||||
dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
|
||||
dh_pub_is_valid(struct sshdh *dh, struct sshbn *dh_pub)
|
||||
{
|
||||
int i;
|
||||
int n = BN_num_bits(dh_pub);
|
||||
int bits_set = 0;
|
||||
BIGNUM *tmp;
|
||||
size_t i;
|
||||
size_t n;
|
||||
int r, freeme = 0, bits_set = 0;
|
||||
struct sshbn *dh_p = NULL, *tmp = NULL;
|
||||
|
||||
if (dh_pub->neg) {
|
||||
logit("invalid public DH value: negative");
|
||||
return 0;
|
||||
if (dh_pub == NULL) {
|
||||
if ((dh_pub = sshdh_pubkey(dh)) == NULL)
|
||||
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");
|
||||
return 0;
|
||||
r = SSH_ERR_INVALID_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((tmp = BN_new()) == NULL) {
|
||||
error("%s: BN_new failed", __func__);
|
||||
return 0;
|
||||
if ((dh_p = sshdh_p(dh)) == NULL) {
|
||||
error("%s: sshdh_p failed", __func__);
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
if (!BN_sub(tmp, dh->p, BN_value_one()) ||
|
||||
BN_cmp(dh_pub, tmp) != -1) { /* pub_exp > p-2 */
|
||||
BN_clear_free(tmp);
|
||||
if ((tmp = sshbn_new()) == NULL) {
|
||||
error("%s: sshbn_new failed", __func__);
|
||||
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");
|
||||
return 0;
|
||||
r = SSH_ERR_INVALID_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
BN_clear_free(tmp);
|
||||
|
||||
for (i = 0; i <= n; i++)
|
||||
if (BN_is_bit_set(dh_pub, i))
|
||||
if (sshbn_is_bit_set(dh_pub, i))
|
||||
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 (bits_set > 1)
|
||||
return 1;
|
||||
if (bits_set <= 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;
|
||||
}
|
||||
|
||||
int
|
||||
dh_gen_key(DH *dh, int need)
|
||||
{
|
||||
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)
|
||||
dh_new_group1(struct sshdh **dhp)
|
||||
{
|
||||
static char *gen = "2", *group1 =
|
||||
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
|
||||
"29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
|
||||
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
|
||||
"E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
|
||||
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
|
||||
"FFFFFFFF" "FFFFFFFF";
|
||||
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
|
||||
"29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
|
||||
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
|
||||
"E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
|
||||
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
|
||||
"FFFFFFFF" "FFFFFFFF";
|
||||
|
||||
return (dh_new_group_asc(gen, group1));
|
||||
return sshdh_new_group_hex(gen, group1, dhp);
|
||||
}
|
||||
|
||||
DH *
|
||||
dh_new_group14(void)
|
||||
int
|
||||
dh_new_group14(struct sshdh **dhp)
|
||||
{
|
||||
static char *gen = "2", *group14 =
|
||||
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
|
||||
"29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
|
||||
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
|
||||
"E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
|
||||
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
|
||||
"C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
|
||||
"83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
|
||||
"670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
|
||||
"E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
|
||||
"DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
|
||||
"15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF";
|
||||
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
|
||||
"29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
|
||||
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
|
||||
"E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
|
||||
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
|
||||
"C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
|
||||
"83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
|
||||
"670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
|
||||
"E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
|
||||
"DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
|
||||
"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.
|
||||
* Source: MODP group 16 from RFC3526.
|
||||
*/
|
||||
DH *
|
||||
dh_new_group_fallback(int max)
|
||||
* 4k bit fallback group used by DH-GEX if moduli file cannot be read.
|
||||
* Source: MODP group 16 from RFC3526.
|
||||
*/
|
||||
int
|
||||
dh_new_group_fallback(int max, struct sshdh **dhp)
|
||||
{
|
||||
static char *gen = "2", *group16 =
|
||||
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
|
||||
"29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
|
||||
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
|
||||
"E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
|
||||
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
|
||||
"C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
|
||||
"83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
|
||||
"670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
|
||||
"E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
|
||||
"DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
|
||||
"15728E5A" "8AAAC42D" "AD33170D" "04507A33" "A85521AB" "DF1CBA64"
|
||||
"ECFB8504" "58DBEF0A" "8AEA7157" "5D060C7D" "B3970F85" "A6E1E4C7"
|
||||
"ABF5AE8C" "DB0933D7" "1E8C94E0" "4A25619D" "CEE3D226" "1AD2EE6B"
|
||||
"F12FFA06" "D98A0864" "D8760273" "3EC86A64" "521F2B18" "177B200C"
|
||||
"BBE11757" "7A615D6C" "770988C0" "BAD946E2" "08E24FA0" "74E5AB31"
|
||||
"43DB5BFC" "E0FD108E" "4B82D120" "A9210801" "1A723C12" "A787E6D7"
|
||||
"88719A10" "BDBA5B26" "99C32718" "6AF4E23C" "1A946834" "B6150BDA"
|
||||
"2583E9CA" "2AD44CE8" "DBBBC2DB" "04DE8EF9" "2E8EFC14" "1FBECAA6"
|
||||
"287C5947" "4E6BC05D" "99B2964F" "A090C3A2" "233BA186" "515BE7ED"
|
||||
"1F612970" "CEE2D7AF" "B81BDD76" "2170481C" "D0069127" "D5B05AA9"
|
||||
"93B4EA98" "8D8FDDC1" "86FFB7DC" "90A6C08F" "4DF435C9" "34063199"
|
||||
"FFFFFFFF" "FFFFFFFF";
|
||||
"FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
|
||||
"29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
|
||||
"EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
|
||||
"E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
|
||||
"EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
|
||||
"C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
|
||||
"83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
|
||||
"670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
|
||||
"E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
|
||||
"DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
|
||||
"15728E5A" "8AAAC42D" "AD33170D" "04507A33" "A85521AB" "DF1CBA64"
|
||||
"ECFB8504" "58DBEF0A" "8AEA7157" "5D060C7D" "B3970F85" "A6E1E4C7"
|
||||
"ABF5AE8C" "DB0933D7" "1E8C94E0" "4A25619D" "CEE3D226" "1AD2EE6B"
|
||||
"F12FFA06" "D98A0864" "D8760273" "3EC86A64" "521F2B18" "177B200C"
|
||||
"BBE11757" "7A615D6C" "770988C0" "BAD946E2" "08E24FA0" "74E5AB31"
|
||||
"43DB5BFC" "E0FD108E" "4B82D120" "A9210801" "1A723C12" "A787E6D7"
|
||||
"88719A10" "BDBA5B26" "99C32718" "6AF4E23C" "1A946834" "B6150BDA"
|
||||
"2583E9CA" "2AD44CE8" "DBBBC2DB" "04DE8EF9" "2E8EFC14" "1FBECAA6"
|
||||
"287C5947" "4E6BC05D" "99B2964F" "A090C3A2" "233BA186" "515BE7ED"
|
||||
"1F612970" "CEE2D7AF" "B81BDD76" "2170481C" "D0069127" "D5B05AA9"
|
||||
"93B4EA98" "8D8FDDC1" "86FFB7DC" "90A6C08F" "4DF435C9" "34063199"
|
||||
"FFFFFFFF" "FFFFFFFF";
|
||||
|
||||
if (max < 4096) {
|
||||
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");
|
||||
return (dh_new_group_asc(gen, group16));
|
||||
return sshdh_new_group_hex(gen, group16, dhp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Estimates the group order for a Diffie-Hellman group that has an
|
||||
* attack complexity approximately the same as O(2**bits).
|
||||
* Values from NIST Special Publication 800-57: Recommendation for Key
|
||||
* Management Part 1 (rev 3) limited by the recommended maximum value
|
||||
* from RFC4419 section 3.
|
||||
*/
|
||||
|
||||
* Estimates the group order for a Diffie-Hellman group that has an
|
||||
* attack complexity approximately the same as O(2**bits).
|
||||
* Values from NIST Special Publication 800-57: Recommendation for Key
|
||||
* Management Part 1 (rev 3) limited by the recommended maximum value
|
||||
* from RFC4419 section 3.
|
||||
*/
|
||||
u_int
|
||||
dh_estimate(int bits)
|
||||
{
|
||||
|
44
dh.h
44
dh.h
@ -26,32 +26,35 @@
|
||||
#ifndef DH_H
|
||||
#define DH_H
|
||||
|
||||
#include <crypto-wrap.h>
|
||||
|
||||
struct dhgroup {
|
||||
int size;
|
||||
BIGNUM *g;
|
||||
BIGNUM *p;
|
||||
size_t size;
|
||||
struct sshbn *g;
|
||||
struct sshbn *p;
|
||||
};
|
||||
|
||||
DH *choose_dh(int, int, int);
|
||||
DH *dh_new_group_asc(const char *, const char *);
|
||||
DH *dh_new_group(BIGNUM *, BIGNUM *);
|
||||
DH *dh_new_group1(void);
|
||||
DH *dh_new_group14(void);
|
||||
DH *dh_new_group_fallback(int);
|
||||
struct sshdh *choose_dh(u_int, u_int, u_int);
|
||||
int dh_new_group1(struct sshdh **dhp);
|
||||
int dh_new_group14(struct sshdh **dhp);
|
||||
int dh_new_group_fallback(int, struct sshdh **dhp);
|
||||
|
||||
int dh_gen_key(DH *, int);
|
||||
int dh_pub_is_valid(DH *, BIGNUM *);
|
||||
int dh_gen_key(struct sshdh *dh, u_int);
|
||||
int dh_pub_is_valid(struct sshdh *dh, struct sshbn *dh_pub);
|
||||
|
||||
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
|
||||
|
||||
/*
|
||||
* Values for "type" field of moduli(5)
|
||||
* Specifies the internal structure of the prime modulus.
|
||||
*/
|
||||
* Values for "type" field of moduli(5)
|
||||
* Specifies the internal structure of the prime modulus.
|
||||
*/
|
||||
#define MODULI_TYPE_UNKNOWN (0)
|
||||
#define MODULI_TYPE_UNSTRUCTURED (1)
|
||||
#define MODULI_TYPE_SAFE (2)
|
||||
@ -60,10 +63,10 @@ u_int dh_estimate(int);
|
||||
#define MODULI_TYPE_STRONG (5)
|
||||
|
||||
/*
|
||||
* Values for "tests" field of moduli(5)
|
||||
* Specifies the methods used in checking for primality.
|
||||
* Usually, more than one test is used.
|
||||
*/
|
||||
* Values for "tests" field of moduli(5)
|
||||
* Specifies the methods used in checking for primality.
|
||||
* Usually, more than one test is used.
|
||||
*/
|
||||
#define MODULI_TESTS_UNTESTED (0x00)
|
||||
#define MODULI_TESTS_COMPOSITE (0x01)
|
||||
#define MODULI_TESTS_SIEVE (0x02)
|
||||
@ -71,5 +74,4 @@ u_int dh_estimate(int);
|
||||
#define MODULI_TESTS_JACOBI (0x08)
|
||||
#define MODULI_TESTS_ELLIPTIC (0x10)
|
||||
|
||||
|
||||
#endif
|
||||
|
297
kex.c
297
kex.c
@ -55,18 +55,23 @@
|
||||
#include "sshbuf.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_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 {
|
||||
char *name;
|
||||
u_int type;
|
||||
@ -75,27 +80,19 @@ struct kexalg {
|
||||
};
|
||||
static const struct kexalg kexalgs[] = {
|
||||
#ifdef WITH_OPENSSL
|
||||
{ KEX_DH1, KEX_DH_GRP1_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 },
|
||||
#ifdef HAVE_EVP_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,
|
||||
NID_X9_62_prime256v1, SSH_DIGEST_SHA256 },
|
||||
{ KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1,
|
||||
SSH_DIGEST_SHA384 },
|
||||
# ifdef OPENSSL_HAS_NISTP521
|
||||
{ KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1,
|
||||
SSH_DIGEST_SHA512 },
|
||||
# endif /* OPENSSL_HAS_NISTP521 */
|
||||
#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 },
|
||||
#endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */
|
||||
{ NULL, -1, -1, -1},
|
||||
{ KEX_DH1, KEX_DH_GRP1_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_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 },
|
||||
{ KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2,
|
||||
NID_X9_62_prime256v1, SSH_DIGEST_SHA256 },
|
||||
{ KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1,
|
||||
SSH_DIGEST_SHA384 },
|
||||
{ KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1,
|
||||
SSH_DIGEST_SHA512 },
|
||||
#endif
|
||||
{ KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
|
||||
{ NULL, -1, -1, -1 },
|
||||
};
|
||||
|
||||
char *
|
||||
@ -143,7 +140,7 @@ kex_names_valid(const char *names)
|
||||
if ((s = cp = strdup(names)) == NULL)
|
||||
return 0;
|
||||
for ((p = strsep(&cp, ",")); p && *p != '\0';
|
||||
(p = strsep(&cp, ","))) {
|
||||
(p = strsep(&cp, ","))) {
|
||||
if (kex_alg_by_name(p) == NULL) {
|
||||
error("Unsupported KEX algorithm \"%.100s\"", p);
|
||||
free(s);
|
||||
@ -156,9 +153,9 @@ kex_names_valid(const char *names)
|
||||
}
|
||||
|
||||
/*
|
||||
* Concatenate algorithm names, avoiding duplicates in the process.
|
||||
* Caller must free returned string.
|
||||
*/
|
||||
* Concatenate algorithm names, avoiding duplicates in the process.
|
||||
* Caller must free returned string.
|
||||
*/
|
||||
char *
|
||||
kex_names_cat(const char *a, const char *b)
|
||||
{
|
||||
@ -169,11 +166,11 @@ kex_names_cat(const char *a, const char *b)
|
||||
return NULL;
|
||||
if (b == NULL || *b == '\0')
|
||||
return strdup(a);
|
||||
if (strlen(b) > 1024*1024)
|
||||
if (strlen(b) > 1024 * 1024)
|
||||
return NULL;
|
||||
len = strlen(a) + strlen(b) + 2;
|
||||
if ((tmp = cp = strdup(b)) == NULL ||
|
||||
(ret = calloc(1, len)) == NULL) {
|
||||
(ret = calloc(1, len)) == NULL) {
|
||||
free(tmp);
|
||||
return NULL;
|
||||
}
|
||||
@ -182,7 +179,7 @@ kex_names_cat(const char *a, const char *b)
|
||||
if (match_list(ret, p, NULL) != NULL)
|
||||
continue; /* Algorithm already present */
|
||||
if (strlcat(ret, ",", len) >= len ||
|
||||
strlcat(ret, p, len) >= len) {
|
||||
strlcat(ret, p, len) >= len) {
|
||||
free(tmp);
|
||||
free(ret);
|
||||
return NULL; /* Shouldn't happen */
|
||||
@ -193,10 +190,10 @@ kex_names_cat(const char *a, const char *b)
|
||||
}
|
||||
|
||||
/*
|
||||
* Assemble a list of algorithms from a default list and a string from a
|
||||
* configuration file. The user-provided string may begin with '+' to
|
||||
* indicate that it should be appended to the default.
|
||||
*/
|
||||
* Assemble a list of algorithms from a default list and a string from a
|
||||
* configuration file. The user-provided string may begin with '+' to
|
||||
* indicate that it should be appended to the default.
|
||||
*/
|
||||
int
|
||||
kex_assemble_names(const char *def, char **list)
|
||||
{
|
||||
@ -227,9 +224,9 @@ kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX])
|
||||
sshbuf_reset(b);
|
||||
|
||||
/*
|
||||
* add a dummy cookie, the cookie will be overwritten by
|
||||
* kex_send_kexinit(), each time a kexinit is set
|
||||
*/
|
||||
* add a dummy cookie, the cookie will be overwritten by
|
||||
* kex_send_kexinit(), each time a kexinit is set
|
||||
*/
|
||||
for (i = 0; i < KEX_COOKIE_LEN; i++) {
|
||||
if ((r = sshbuf_put_u8(b, 0)) != 0)
|
||||
return r;
|
||||
@ -239,7 +236,7 @@ kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX])
|
||||
return r;
|
||||
}
|
||||
if ((r = sshbuf_put_u8(b, 0)) != 0 || /* first_kex_packet_follows */
|
||||
(r = sshbuf_put_u32(b, 0)) != 0) /* uint32 reserved */
|
||||
(r = sshbuf_put_u32(b, 0)) != 0) /* uint32 reserved */
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
@ -267,19 +264,19 @@ kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp)
|
||||
for (i = 0; i < PROPOSAL_MAX; i++) {
|
||||
if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0)
|
||||
goto out;
|
||||
debug2("kex_parse_kexinit: %s", proposal[i]);
|
||||
debug2("%s: %s", proposal_names[i], proposal[i]);
|
||||
}
|
||||
/* first kex follows / reserved */
|
||||
if ((r = sshbuf_get_u8(b, &v)) != 0 ||
|
||||
(r = sshbuf_get_u32(b, &i)) != 0)
|
||||
(r = sshbuf_get_u32(b, &i)) != 0)
|
||||
goto out;
|
||||
if (first_kex_follows != NULL)
|
||||
*first_kex_follows = i;
|
||||
debug2("kex_parse_kexinit: first_kex_follows %d ", v);
|
||||
debug2("kex_parse_kexinit: reserved %u ", i);
|
||||
debug2("first_kex_follows %d ", v);
|
||||
debug2("reserved %u ", i);
|
||||
r = 0;
|
||||
*propp = proposal;
|
||||
out:
|
||||
out:
|
||||
if (r != 0 && proposal != NULL)
|
||||
kex_prop_free(proposal);
|
||||
sshbuf_free(b);
|
||||
@ -302,7 +299,14 @@ kex_prop_free(char **proposal)
|
||||
static int
|
||||
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;
|
||||
}
|
||||
|
||||
@ -310,7 +314,7 @@ static void
|
||||
kex_reset_dispatch(struct ssh *ssh)
|
||||
{
|
||||
ssh_dispatch_range(ssh, SSH2_MSG_TRANSPORT_MIN,
|
||||
SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error);
|
||||
SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error);
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit);
|
||||
}
|
||||
|
||||
@ -321,7 +325,7 @@ kex_send_newkeys(struct ssh *ssh)
|
||||
|
||||
kex_reset_dispatch(ssh);
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_NEWKEYS)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
return r;
|
||||
debug("SSH2_MSG_NEWKEYS sent");
|
||||
debug("expecting SSH2_MSG_NEWKEYS");
|
||||
@ -370,8 +374,8 @@ kex_send_kexinit(struct ssh *ssh)
|
||||
arc4random_buf(cookie, KEX_COOKIE_LEN);
|
||||
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 ||
|
||||
(r = sshpkt_putb(ssh, kex->my)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
(r = sshpkt_putb(ssh, kex->my)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
return r;
|
||||
debug("SSH2_MSG_KEXINIT sent");
|
||||
kex->flags |= KEX_INIT_SENT;
|
||||
@ -405,19 +409,19 @@ kex_input_kexinit(int type, u_int32_t seq, void *ctxt)
|
||||
if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0)
|
||||
return r;
|
||||
/*
|
||||
* XXX RFC4253 sec 7: "each side MAY guess" - currently no supported
|
||||
* KEX method has the server move first, but a server might be using
|
||||
* a custom method or one that we otherwise don't support. We should
|
||||
* be prepared to remember first_kex_follows here so we can eat a
|
||||
* packet later.
|
||||
* XXX2 - RFC4253 is kind of ambiguous on what first_kex_follows means
|
||||
* for cases where the server *doesn't* go first. I guess we should
|
||||
* ignore it when it is set for these cases, which is what we do now.
|
||||
*/
|
||||
* XXX RFC4253 sec 7: "each side MAY guess" - currently no supported
|
||||
* KEX method has the server move first, but a server might be using
|
||||
* a custom method or one that we otherwise don't support. We should
|
||||
* be prepared to remember first_kex_follows here so we can eat a
|
||||
* packet later.
|
||||
* XXX2 - RFC4253 is kind of ambiguous on what first_kex_follows means
|
||||
* for cases where the server *doesn't* go first. I guess we should
|
||||
* ignore it when it is set for these cases, which is what we do now.
|
||||
*/
|
||||
if ((r = sshpkt_get_u8(ssh, NULL)) != 0 || /* first_kex_follows */
|
||||
(r = sshpkt_get_u32(ssh, NULL)) != 0 || /* reserved */
|
||||
(r = sshpkt_get_end(ssh)) != 0)
|
||||
return r;
|
||||
(r = sshpkt_get_u32(ssh, NULL)) != 0 || /* reserved */
|
||||
(r = sshpkt_get_end(ssh)) != 0)
|
||||
return r;
|
||||
|
||||
if (!(kex->flags & KEX_INIT_SENT))
|
||||
if ((r = kex_send_kexinit(ssh)) != 0)
|
||||
@ -441,7 +445,7 @@ kex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp)
|
||||
if ((kex = calloc(1, sizeof(*kex))) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
if ((kex->peer = sshbuf_new()) == NULL ||
|
||||
(kex->my = sshbuf_new()) == NULL) {
|
||||
(kex->my = sshbuf_new()) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
@ -451,7 +455,7 @@ kex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp)
|
||||
kex_reset_dispatch(ssh);
|
||||
r = 0;
|
||||
*kexp = kex;
|
||||
out:
|
||||
out:
|
||||
if (r != 0)
|
||||
kex_free(kex);
|
||||
return r;
|
||||
@ -468,7 +472,7 @@ kex_free_newkeys(struct newkeys *newkeys)
|
||||
newkeys->enc.key = NULL;
|
||||
}
|
||||
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);
|
||||
newkeys->enc.iv = NULL;
|
||||
}
|
||||
@ -494,13 +498,10 @@ kex_free(struct kex *kex)
|
||||
u_int mode;
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
if (kex->dh)
|
||||
DH_free(kex->dh);
|
||||
#ifdef OPENSSL_HAS_ECC
|
||||
sshdh_free(kex->dh);
|
||||
if (kex->ec_client_key)
|
||||
EC_KEY_free(kex->ec_client_key);
|
||||
#endif /* OPENSSL_HAS_ECC */
|
||||
#endif /* WITH_OPENSSL */
|
||||
#endif
|
||||
for (mode = 0; mode < MODE_MAX; mode++) {
|
||||
kex_free_newkeys(kex->newkeys[mode]);
|
||||
kex->newkeys[mode] = NULL;
|
||||
@ -575,11 +576,14 @@ choose_comp(struct sshcomp *comp, char *client, char *server)
|
||||
return SSH_ERR_NO_COMPRESS_ALG_MATCH;
|
||||
if (strcmp(name, "zlib@openssh.com") == 0) {
|
||||
comp->type = COMP_DELAYED;
|
||||
} else if (strcmp(name, "zlib") == 0) {
|
||||
}
|
||||
else if (strcmp(name, "zlib") == 0) {
|
||||
comp->type = COMP_ZLIB;
|
||||
} else if (strcmp(name, "none") == 0) {
|
||||
}
|
||||
else if (strcmp(name, "none") == 0) {
|
||||
comp->type = COMP_NONE;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return SSH_ERR_INTERNAL_ERROR;
|
||||
}
|
||||
comp->name = name;
|
||||
@ -593,6 +597,7 @@ choose_kex(struct kex *k, char *client, char *server)
|
||||
|
||||
k->name = match_list(client, server, NULL);
|
||||
|
||||
debug("kex: algorithm: %s", k->name ? k->name : "(no match)");
|
||||
if (k->name == NULL)
|
||||
return SSH_ERR_NO_KEX_ALG_MATCH;
|
||||
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);
|
||||
|
||||
debug("kex: host key algorithm: %s",
|
||||
hostkeyalg ? hostkeyalg : "(no match)");
|
||||
if (hostkeyalg == NULL)
|
||||
return SSH_ERR_NO_HOSTKEY_ALG_MATCH;
|
||||
k->hostkey_type = sshkey_type_from_name(hostkeyalg);
|
||||
@ -634,7 +641,7 @@ proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX])
|
||||
*p = '\0';
|
||||
if (strcmp(my[*idx], peer[*idx]) != 0) {
|
||||
debug2("proposal mismatch: my %s peer %s",
|
||||
my[*idx], peer[*idx]);
|
||||
my[*idx], peer[*idx]);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
@ -653,22 +660,26 @@ kex_choose_conf(struct ssh *ssh)
|
||||
u_int mode, ctos, need, dh_need, authlen;
|
||||
int r, first_kex_follows;
|
||||
|
||||
if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0 ||
|
||||
(r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0)
|
||||
debug2("local %s KEXINIT proposal", kex->server ? "server" : "client");
|
||||
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;
|
||||
|
||||
if (kex->server) {
|
||||
cprop=peer;
|
||||
sprop=my;
|
||||
} else {
|
||||
cprop=my;
|
||||
sprop=peer;
|
||||
cprop = peer;
|
||||
sprop = my;
|
||||
}
|
||||
else {
|
||||
cprop = my;
|
||||
sprop = peer;
|
||||
}
|
||||
|
||||
/* Check whether server offers roaming */
|
||||
if (!kex->server) {
|
||||
char *roaming = match_list(KEX_RESUME,
|
||||
peer[PROPOSAL_KEX_ALGS], NULL);
|
||||
peer[PROPOSAL_KEX_ALGS], NULL);
|
||||
|
||||
if (roaming) {
|
||||
kex->roaming = 1;
|
||||
@ -677,6 +688,18 @@ kex_choose_conf(struct ssh *ssh)
|
||||
}
|
||||
|
||||
/* 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++) {
|
||||
if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
@ -684,12 +707,12 @@ kex_choose_conf(struct ssh *ssh)
|
||||
}
|
||||
kex->newkeys[mode] = newkeys;
|
||||
ctos = (!kex->server && mode == MODE_OUT) ||
|
||||
(kex->server && mode == MODE_IN);
|
||||
nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
|
||||
nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
|
||||
(kex->server && mode == MODE_IN);
|
||||
nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
|
||||
nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
|
||||
ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
|
||||
if ((r = choose_enc(&newkeys->enc, cprop[nenc],
|
||||
sprop[nenc])) != 0) {
|
||||
sprop[nenc])) != 0) {
|
||||
kex->failed_choice = peer[nenc];
|
||||
peer[nenc] = NULL;
|
||||
goto out;
|
||||
@ -697,35 +720,23 @@ kex_choose_conf(struct ssh *ssh)
|
||||
authlen = cipher_authlen(newkeys->enc.cipher);
|
||||
/* ignore mac for authenticated encryption */
|
||||
if (authlen == 0 &&
|
||||
(r = choose_mac(ssh, &newkeys->mac, cprop[nmac],
|
||||
sprop[nmac])) != 0) {
|
||||
(r = choose_mac(ssh, &newkeys->mac, cprop[nmac],
|
||||
sprop[nmac])) != 0) {
|
||||
kex->failed_choice = peer[nmac];
|
||||
peer[nmac] = NULL;
|
||||
goto out;
|
||||
}
|
||||
if ((r = choose_comp(&newkeys->comp, cprop[ncomp],
|
||||
sprop[ncomp])) != 0) {
|
||||
sprop[ncomp])) != 0) {
|
||||
kex->failed_choice = peer[ncomp];
|
||||
peer[ncomp] = NULL;
|
||||
goto out;
|
||||
}
|
||||
debug("kex: %s %s %s %s",
|
||||
ctos ? "client->server" : "server->client",
|
||||
newkeys->enc.name,
|
||||
authlen == 0 ? newkeys->mac.name : "<implicit>",
|
||||
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;
|
||||
debug("kex: %s cipher: %s MAC: %s compression: %s",
|
||||
ctos ? "client->server" : "server->client",
|
||||
newkeys->enc.name,
|
||||
authlen == 0 ? newkeys->mac.name : "<implicit>",
|
||||
newkeys->comp.name);
|
||||
}
|
||||
need = dh_need = 0;
|
||||
for (mode = 0; mode < MODE_MAX; mode++) {
|
||||
@ -745,10 +756,10 @@ kex_choose_conf(struct ssh *ssh)
|
||||
|
||||
/* ignore the next message if the proposals do not match */
|
||||
if (first_kex_follows && !proposals_match(my, peer) &&
|
||||
!(ssh->compat & SSH_BUG_FIRSTKEX))
|
||||
!(ssh->compat & SSH_BUG_FIRSTKEX))
|
||||
ssh->dispatch_skip_packets = 1;
|
||||
r = 0;
|
||||
out:
|
||||
out:
|
||||
kex_prop_free(my);
|
||||
kex_prop_free(peer);
|
||||
return r;
|
||||
@ -756,7 +767,7 @@ kex_choose_conf(struct ssh *ssh)
|
||||
|
||||
static int
|
||||
derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
|
||||
const struct sshbuf *shared_secret, u_char **keyp)
|
||||
const struct sshbuf *shared_secret, u_char **keyp)
|
||||
{
|
||||
struct kex *kex = ssh->kex;
|
||||
struct ssh_digest_ctx *hashctx = NULL;
|
||||
@ -775,12 +786,12 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
|
||||
|
||||
/* K1 = HASH(K || H || "A" || session_id) */
|
||||
if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL ||
|
||||
ssh_digest_update_buffer(hashctx, shared_secret) != 0 ||
|
||||
ssh_digest_update(hashctx, hash, hashlen) != 0 ||
|
||||
ssh_digest_update(hashctx, &c, 1) != 0 ||
|
||||
ssh_digest_update(hashctx, kex->session_id,
|
||||
kex->session_id_len) != 0 ||
|
||||
ssh_digest_final(hashctx, digest, mdsz) != 0) {
|
||||
ssh_digest_update_buffer(hashctx, shared_secret) != 0 ||
|
||||
ssh_digest_update(hashctx, hash, hashlen) != 0 ||
|
||||
ssh_digest_update(hashctx, &c, 1) != 0 ||
|
||||
ssh_digest_update(hashctx, kex->session_id,
|
||||
kex->session_id_len) != 0 ||
|
||||
ssh_digest_final(hashctx, digest, mdsz) != 0) {
|
||||
r = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
goto out;
|
||||
}
|
||||
@ -788,16 +799,16 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
|
||||
hashctx = NULL;
|
||||
|
||||
/*
|
||||
* expand key:
|
||||
* Kn = HASH(K || H || K1 || K2 || ... || Kn-1)
|
||||
* Key = K1 || K2 || ... || Kn
|
||||
*/
|
||||
* expand key:
|
||||
* Kn = HASH(K || H || K1 || K2 || ... || Kn-1)
|
||||
* Key = K1 || K2 || ... || Kn
|
||||
*/
|
||||
for (have = mdsz; need > have; have += mdsz) {
|
||||
if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL ||
|
||||
ssh_digest_update_buffer(hashctx, shared_secret) != 0 ||
|
||||
ssh_digest_update(hashctx, hash, hashlen) != 0 ||
|
||||
ssh_digest_update(hashctx, digest, have) != 0 ||
|
||||
ssh_digest_final(hashctx, digest + have, mdsz) != 0) {
|
||||
ssh_digest_update_buffer(hashctx, shared_secret) != 0 ||
|
||||
ssh_digest_update(hashctx, hash, hashlen) != 0 ||
|
||||
ssh_digest_update(hashctx, digest, have) != 0 ||
|
||||
ssh_digest_final(hashctx, digest + have, mdsz) != 0) {
|
||||
r = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
goto out;
|
||||
}
|
||||
@ -811,7 +822,7 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
|
||||
*keyp = digest;
|
||||
digest = NULL;
|
||||
r = 0;
|
||||
out:
|
||||
out:
|
||||
if (digest)
|
||||
free(digest);
|
||||
ssh_digest_free(hashctx);
|
||||
@ -821,7 +832,7 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
|
||||
#define NKEYS 6
|
||||
int
|
||||
kex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen,
|
||||
const struct sshbuf *shared_secret)
|
||||
const struct sshbuf *shared_secret)
|
||||
{
|
||||
struct kex *kex = ssh->kex;
|
||||
u_char *keys[NKEYS];
|
||||
@ -829,8 +840,8 @@ kex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen,
|
||||
int r;
|
||||
|
||||
for (i = 0; i < NKEYS; i++) {
|
||||
if ((r = derive_key(ssh, 'A'+i, kex->we_need, hash, hashlen,
|
||||
shared_secret, &keys[i])) != 0) {
|
||||
if ((r = derive_key(ssh, 'A' + i, kex->we_need, hash, hashlen,
|
||||
shared_secret, &keys[i])) != 0) {
|
||||
for (j = 0; j < i; j++)
|
||||
free(keys[j]);
|
||||
return r;
|
||||
@ -838,8 +849,8 @@ kex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen,
|
||||
}
|
||||
for (mode = 0; mode < MODE_MAX; mode++) {
|
||||
ctos = (!kex->server && mode == MODE_OUT) ||
|
||||
(kex->server && mode == MODE_IN);
|
||||
kex->newkeys[mode]->enc.iv = keys[ctos ? 0 : 1];
|
||||
(kex->server && mode == MODE_IN);
|
||||
kex->newkeys[mode]->enc.iv = keys[ctos ? 0 : 1];
|
||||
kex->newkeys[mode]->enc.key = keys[ctos ? 2 : 3];
|
||||
kex->newkeys[mode]->mac.key = keys[ctos ? 4 : 5];
|
||||
}
|
||||
@ -849,14 +860,14 @@ kex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen,
|
||||
#ifdef WITH_OPENSSL
|
||||
int
|
||||
kex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen,
|
||||
const BIGNUM *secret)
|
||||
const struct sshbn *secret)
|
||||
{
|
||||
struct sshbuf *shared_secret;
|
||||
int r;
|
||||
|
||||
if ((shared_secret = sshbuf_new()) == NULL)
|
||||
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);
|
||||
sshbuf_free(shared_secret);
|
||||
return r;
|
||||
@ -866,7 +877,7 @@ kex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen,
|
||||
#ifdef WITH_SSH1
|
||||
int
|
||||
derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus,
|
||||
u_int8_t cookie[8], u_int8_t id[16])
|
||||
u_int8_t cookie[8], u_int8_t id[16])
|
||||
{
|
||||
u_int8_t hbuf[2048], sbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH];
|
||||
struct ssh_digest_ctx *hashctx = NULL;
|
||||
@ -876,10 +887,10 @@ derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus,
|
||||
hlen = BN_num_bytes(host_modulus);
|
||||
slen = BN_num_bytes(server_modulus);
|
||||
if (hlen < (512 / 8) || (u_int)hlen > sizeof(hbuf) ||
|
||||
slen < (512 / 8) || (u_int)slen > sizeof(sbuf))
|
||||
slen < (512 / 8) || (u_int)slen > sizeof(sbuf))
|
||||
return SSH_ERR_KEY_BITS_MISMATCH;
|
||||
if (BN_bn2bin(host_modulus, hbuf) <= 0 ||
|
||||
BN_bn2bin(server_modulus, sbuf) <= 0) {
|
||||
BN_bn2bin(server_modulus, sbuf) <= 0) {
|
||||
r = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
goto out;
|
||||
}
|
||||
@ -888,15 +899,15 @@ derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus,
|
||||
goto out;
|
||||
}
|
||||
if (ssh_digest_update(hashctx, hbuf, hlen) != 0 ||
|
||||
ssh_digest_update(hashctx, sbuf, slen) != 0 ||
|
||||
ssh_digest_update(hashctx, cookie, 8) != 0 ||
|
||||
ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) {
|
||||
ssh_digest_update(hashctx, sbuf, slen) != 0 ||
|
||||
ssh_digest_update(hashctx, cookie, 8) != 0 ||
|
||||
ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) {
|
||||
r = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
goto out;
|
||||
}
|
||||
memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5));
|
||||
r = 0;
|
||||
out:
|
||||
out:
|
||||
ssh_digest_free(hashctx);
|
||||
explicit_bzero(hbuf, sizeof(hbuf));
|
||||
explicit_bzero(sbuf, sizeof(sbuf));
|
||||
|
64
kex.h
64
kex.h
@ -34,20 +34,6 @@
|
||||
#include "leakmalloc.h"
|
||||
#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_DH1 "diffie-hellman-group1-sha1"
|
||||
@ -142,15 +128,15 @@ struct kex {
|
||||
char *client_version_string;
|
||||
char *server_version_string;
|
||||
char *failed_choice;
|
||||
int (*verify_host_key)(struct sshkey *, struct ssh *);
|
||||
int(*verify_host_key)(struct sshkey *, struct ssh *);
|
||||
struct sshkey *(*load_host_public_key)(int, int, struct ssh *);
|
||||
struct sshkey *(*load_host_private_key)(int, int, struct ssh *);
|
||||
int (*host_key_index)(struct sshkey *, int, struct ssh *);
|
||||
int (*sign)(struct sshkey *, struct sshkey *,
|
||||
u_char **, size_t *, const u_char *, size_t, u_int);
|
||||
int (*kex[KEX_MAX])(struct ssh *);
|
||||
int(*host_key_index)(struct sshkey *, int, struct ssh *);
|
||||
int(*sign)(struct sshkey *, struct sshkey *,
|
||||
u_char **, size_t *, const u_char *, size_t, u_int);
|
||||
int(*kex[KEX_MAX])(struct ssh *);
|
||||
/* kex specific state */
|
||||
DH *dh; /* DH */
|
||||
struct sshdh *dh; /* DH */
|
||||
u_int min, max, nbits; /* GEX */
|
||||
EC_KEY *ec_client_key; /* ECDH */
|
||||
const EC_GROUP *ec_group; /* ECDH */
|
||||
@ -175,7 +161,8 @@ void kex_prop_free(char **);
|
||||
int kex_send_kexinit(struct ssh *);
|
||||
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_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 kexdh_client(struct ssh *);
|
||||
@ -188,29 +175,30 @@ int kexc25519_client(struct ssh *);
|
||||
int kexc25519_server(struct ssh *);
|
||||
|
||||
int kex_dh_hash(const char *, const char *,
|
||||
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 u_char *, size_t, const u_char *, size_t, const 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 *,
|
||||
const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
|
||||
int, int, int,
|
||||
const BIGNUM *, const BIGNUM *, const BIGNUM *,
|
||||
const BIGNUM *, const BIGNUM *,
|
||||
u_char *, size_t *);
|
||||
const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
|
||||
int, int, int,
|
||||
const struct sshbn *, const struct sshbn *, const struct sshbn *,
|
||||
const struct sshbn *, const struct sshbn *,
|
||||
u_char *, size_t *);
|
||||
|
||||
int kex_ecdh_hash(int, const EC_GROUP *, const char *, const char *,
|
||||
const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
|
||||
const EC_POINT *, const EC_POINT *, const BIGNUM *, u_char *, size_t *);
|
||||
const u_char *, size_t, const u_char *, size_t, const u_char *, size_t,
|
||||
const EC_POINT *, const EC_POINT *, const BIGNUM *, u_char *, size_t *);
|
||||
|
||||
int kex_c25519_hash(int, const char *, const char *, const char *, size_t,
|
||||
const char *, size_t, const u_char *, size_t, const u_char *, const u_char *,
|
||||
const u_char *, size_t, u_char *, size_t *);
|
||||
const char *, size_t, const u_char *, size_t, const u_char *, const u_char *,
|
||||
const u_char *, size_t, u_char *, size_t *);
|
||||
|
||||
void kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE])
|
||||
__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
|
||||
__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)));
|
||||
__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
|
||||
__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)));
|
||||
int kexc25519_shared_key(const u_char key[CURVE25519_SIZE],
|
||||
const u_char pub[CURVE25519_SIZE], struct sshbuf *out)
|
||||
const u_char pub[CURVE25519_SIZE], struct sshbuf *out)
|
||||
__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
|
||||
__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)));
|
||||
|
||||
@ -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);
|
||||
#endif
|
||||
|
||||
#if !defined(WITH_OPENSSL) || !defined(OPENSSL_HAS_ECC)
|
||||
# undef EC_KEY
|
||||
# undef EC_GROUP
|
||||
# undef EC_POINT
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
44
kexdh.c
44
kexdh.c
@ -25,7 +25,6 @@
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
@ -43,15 +42,15 @@
|
||||
|
||||
int
|
||||
kex_dh_hash(
|
||||
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,
|
||||
const BIGNUM *client_dh_pub,
|
||||
const BIGNUM *server_dh_pub,
|
||||
const BIGNUM *shared_secret,
|
||||
u_char *hash, size_t *hashlen)
|
||||
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,
|
||||
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;
|
||||
@ -61,18 +60,18 @@ kex_dh_hash(
|
||||
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 ||
|
||||
(r = sshbuf_put_bignum2(b, client_dh_pub)) != 0 ||
|
||||
(r = sshbuf_put_bignum2(b, server_dh_pub)) != 0 ||
|
||||
(r = sshbuf_put_bignum2(b, shared_secret)) != 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 ||
|
||||
(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;
|
||||
}
|
||||
@ -90,4 +89,3 @@ kex_dh_hash(
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif /* WITH_OPENSSL */
|
||||
|
111
kexdhc.c
111
kexdhc.c
@ -25,7 +25,6 @@
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
@ -55,15 +54,18 @@ int
|
||||
kexdh_client(struct ssh *ssh)
|
||||
{
|
||||
struct kex *kex = ssh->kex;
|
||||
struct sshbn *dh_client_pub = NULL;
|
||||
int r;
|
||||
|
||||
/* generate and send 'e', client DH public key */
|
||||
switch (kex->kex_type) {
|
||||
case KEX_DH_GRP1_SHA1:
|
||||
kex->dh = dh_new_group1();
|
||||
if ((r = dh_new_group1(&kex->dh)) != 0)
|
||||
return r;
|
||||
break;
|
||||
case KEX_DH_GRP14_SHA1:
|
||||
kex->dh = dh_new_group14();
|
||||
if ((r = dh_new_group14(&kex->dh)) != 0)
|
||||
return r;
|
||||
break;
|
||||
default:
|
||||
r = SSH_ERR_INVALID_ARGUMENT;
|
||||
@ -73,22 +75,25 @@ kexdh_client(struct ssh *ssh)
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
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");
|
||||
if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0 ||
|
||||
(r = sshpkt_start(ssh, SSH2_MSG_KEXDH_INIT)) != 0 ||
|
||||
(r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_KEXDH_INIT)) != 0 ||
|
||||
(r = sshpkt_put_bignum2_wrap(ssh, dh_client_pub)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
goto out;
|
||||
#ifdef DEBUG_KEXDH
|
||||
DHparams_print_fp(stderr, kex->dh);
|
||||
fprintf(stderr, "pub= ");
|
||||
BN_print_fp(stderr, kex->dh->pub_key);
|
||||
fprintf(stderr, "\n");
|
||||
sshdh_dump(kex->dh);
|
||||
#endif
|
||||
debug("expecting SSH2_MSG_KEXDH_REPLY");
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_REPLY, &input_kex_dh);
|
||||
r = 0;
|
||||
out:
|
||||
out:
|
||||
sshbn_free(dh_client_pub);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -97,12 +102,14 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
|
||||
{
|
||||
struct ssh *ssh = ctxt;
|
||||
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;
|
||||
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];
|
||||
size_t klen = 0, slen, sbloblen, hashlen;
|
||||
int kout, r;
|
||||
size_t slen, sbloblen, hashlen;
|
||||
int r;
|
||||
|
||||
if (kex->verify_host_key == NULL) {
|
||||
r = SSH_ERR_INVALID_ARGUMENT;
|
||||
@ -110,13 +117,13 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
|
||||
}
|
||||
/* key, cert */
|
||||
if ((r = sshpkt_get_string(ssh, &server_host_key_blob,
|
||||
&sbloblen)) != 0 ||
|
||||
(r = sshkey_from_blob(server_host_key_blob, sbloblen,
|
||||
&server_host_key)) != 0)
|
||||
&sbloblen)) != 0 ||
|
||||
(r = sshkey_from_blob(server_host_key_blob, sbloblen,
|
||||
&server_host_key)) != 0)
|
||||
goto out;
|
||||
if (server_host_key->type != kex->hostkey_type ||
|
||||
(kex->hostkey_type == KEY_ECDSA &&
|
||||
server_host_key->ecdsa_nid != kex->hostkey_nid)) {
|
||||
(kex->hostkey_type == KEY_ECDSA &&
|
||||
server_host_key->ecdsa_nid != kex->hostkey_nid)) {
|
||||
r = SSH_ERR_KEY_TYPE_MISMATCH;
|
||||
goto out;
|
||||
}
|
||||
@ -125,14 +132,14 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
|
||||
goto out;
|
||||
}
|
||||
/* 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;
|
||||
goto out;
|
||||
}
|
||||
/* signed H */
|
||||
if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 ||
|
||||
(r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
|
||||
(r = sshpkt_get_end(ssh)) != 0)
|
||||
if ((r = sshpkt_get_bignum2_wrap(ssh, dh_server_pub)) != 0 ||
|
||||
(r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
|
||||
(r = sshpkt_get_end(ssh)) != 0)
|
||||
goto out;
|
||||
#ifdef DEBUG_KEXDH
|
||||
fprintf(stderr, "dh_server_pub= ");
|
||||
@ -140,23 +147,17 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
|
||||
fprintf(stderr, "\n");
|
||||
debug("bits %d", BN_num_bits(dh_server_pub));
|
||||
#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");
|
||||
r = SSH_ERR_MESSAGE_INCOMPLETE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
klen = DH_size(kex->dh);
|
||||
if ((kbuf = malloc(klen)) == NULL ||
|
||||
(shared_secret = BN_new()) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
if ((dh_client_pub = sshdh_pubkey(kex->dh)) == NULL) {
|
||||
r = SSH_ERR_INTERNAL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 ||
|
||||
BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
|
||||
r = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
if ((r = sshdh_compute_key(kex->dh, dh_server_pub,
|
||||
&shared_secret)) != 0)
|
||||
goto out;
|
||||
}
|
||||
#ifdef DEBUG_KEXDH
|
||||
dump_digest("shared secret", kbuf, kout);
|
||||
#endif
|
||||
@ -164,19 +165,19 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
|
||||
/* calc and verify H */
|
||||
hashlen = sizeof(hash);
|
||||
if ((r = kex_dh_hash(
|
||||
kex->client_version_string,
|
||||
kex->server_version_string,
|
||||
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
|
||||
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
|
||||
server_host_key_blob, sbloblen,
|
||||
kex->dh->pub_key,
|
||||
dh_server_pub,
|
||||
shared_secret,
|
||||
hash, &hashlen)) != 0)
|
||||
kex->client_version_string,
|
||||
kex->server_version_string,
|
||||
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
|
||||
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
|
||||
server_host_key_blob, sbloblen,
|
||||
dh_client_pub,
|
||||
dh_server_pub,
|
||||
shared_secret,
|
||||
hash, &hashlen)) != 0)
|
||||
goto out;
|
||||
|
||||
if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen,
|
||||
ssh->compat)) != 0)
|
||||
ssh->compat)) != 0)
|
||||
goto out;
|
||||
|
||||
/* save session id */
|
||||
@ -192,21 +193,15 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
|
||||
|
||||
if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
|
||||
r = kex_send_newkeys(ssh);
|
||||
out:
|
||||
out:
|
||||
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);
|
||||
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(signature);
|
||||
return r;
|
||||
}
|
||||
#endif /* WITH_OPENSSL */
|
||||
|
113
kexdhs.c
113
kexdhs.c
@ -34,7 +34,6 @@
|
||||
#undef KRB5
|
||||
#endif
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
@ -69,27 +68,24 @@ kexdh_server(struct ssh *ssh)
|
||||
/* generate server DH public key */
|
||||
switch (kex->kex_type) {
|
||||
case KEX_DH_GRP1_SHA1:
|
||||
kex->dh = dh_new_group1();
|
||||
if ((r = dh_new_group1(&kex->dh)) != 0)
|
||||
return r;
|
||||
break;
|
||||
case KEX_DH_GRP14_SHA1:
|
||||
kex->dh = dh_new_group14();
|
||||
if ((r = dh_new_group14(&kex->dh)) != 0)
|
||||
return r;
|
||||
break;
|
||||
default:
|
||||
r = SSH_ERR_INVALID_ARGUMENT;
|
||||
goto out;
|
||||
}
|
||||
if (kex->dh == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
if (kex->dh == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0)
|
||||
goto out;
|
||||
return r;
|
||||
|
||||
debug("expecting SSH2_MSG_KEXDH_INIT");
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_INIT, &input_kex_dh_init);
|
||||
r = 0;
|
||||
out:
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
@ -97,35 +93,37 @@ input_kex_dh_init(int type, u_int32_t seq, void *ctxt)
|
||||
{
|
||||
struct ssh *ssh = ctxt;
|
||||
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;
|
||||
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];
|
||||
size_t sbloblen, slen;
|
||||
size_t klen = 0, hashlen;
|
||||
int kout, r;
|
||||
size_t hashlen;
|
||||
int r;
|
||||
|
||||
if (kex->load_host_public_key == NULL ||
|
||||
kex->load_host_private_key == NULL) {
|
||||
kex->load_host_private_key == NULL) {
|
||||
r = SSH_ERR_INVALID_ARGUMENT;
|
||||
goto out;
|
||||
}
|
||||
server_host_public = kex->load_host_public_key(kex->hostkey_type,
|
||||
kex->hostkey_nid, ssh);
|
||||
kex->hostkey_nid, ssh);
|
||||
server_host_private = kex->load_host_private_key(kex->hostkey_type,
|
||||
kex->hostkey_nid, ssh);
|
||||
kex->hostkey_nid, ssh);
|
||||
if (server_host_public == NULL) {
|
||||
r = SSH_ERR_NO_HOSTKEY_LOADED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* key, cert */
|
||||
if ((dh_client_pub = BN_new()) == NULL) {
|
||||
if ((dh_client_pub = sshbn_new()) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
if ((r = sshpkt_get_bignum2(ssh, dh_client_pub)) != 0 ||
|
||||
(r = sshpkt_get_end(ssh)) != 0)
|
||||
if ((r = sshpkt_get_bignum2_wrap(ssh, dh_client_pub)) != 0 ||
|
||||
(r = sshpkt_get_end(ssh)) != 0)
|
||||
goto out;
|
||||
|
||||
#ifdef DEBUG_KEXDH
|
||||
@ -136,46 +134,37 @@ input_kex_dh_init(int type, u_int32_t seq, void *ctxt)
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_KEXDH
|
||||
DHparams_print_fp(stderr, kex->dh);
|
||||
fprintf(stderr, "pub= ");
|
||||
BN_print_fp(stderr, kex->dh->pub_key);
|
||||
fprintf(stderr, "\n");
|
||||
sshdh_dump(kex->dh);
|
||||
#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");
|
||||
r = SSH_ERR_MESSAGE_INCOMPLETE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
klen = DH_size(kex->dh);
|
||||
if ((kbuf = malloc(klen)) == NULL ||
|
||||
(shared_secret = BN_new()) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
if ((dh_server_pub = sshdh_pubkey(kex->dh)) == NULL) {
|
||||
r = SSH_ERR_INTERNAL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
if ((kout = DH_compute_key(kbuf, dh_client_pub, kex->dh)) < 0 ||
|
||||
BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
|
||||
r = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
if ((r = sshdh_compute_key(kex->dh, dh_client_pub,
|
||||
&shared_secret)) != 0)
|
||||
goto out;
|
||||
}
|
||||
#ifdef DEBUG_KEXDH
|
||||
dump_digest("shared secret", kbuf, kout);
|
||||
dump_digest("shared secret", kbuf, klen);
|
||||
#endif
|
||||
if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob,
|
||||
&sbloblen)) != 0)
|
||||
&sbloblen)) != 0)
|
||||
goto out;
|
||||
/* calc H */
|
||||
hashlen = sizeof(hash);
|
||||
if ((r = kex_dh_hash(
|
||||
kex->client_version_string,
|
||||
kex->server_version_string,
|
||||
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
|
||||
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
|
||||
server_host_key_blob, sbloblen,
|
||||
dh_client_pub,
|
||||
kex->dh->pub_key,
|
||||
shared_secret,
|
||||
hash, &hashlen)) != 0)
|
||||
kex->client_version_string,
|
||||
kex->server_version_string,
|
||||
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
|
||||
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
|
||||
server_host_key_blob, sbloblen,
|
||||
dh_client_pub,
|
||||
dh_server_pub,
|
||||
shared_secret,
|
||||
hash, &hashlen)) != 0)
|
||||
goto out;
|
||||
|
||||
/* save session id := H */
|
||||
@ -191,35 +180,29 @@ input_kex_dh_init(int type, u_int32_t seq, void *ctxt)
|
||||
|
||||
/* sign H */
|
||||
if ((r = kex->sign(server_host_private, server_host_public,
|
||||
&signature, &slen, hash, hashlen, ssh->compat)) < 0)
|
||||
&signature, &slen, hash, hashlen, ssh->compat)) < 0)
|
||||
goto out;
|
||||
|
||||
/* destroy_sensitive_data(); */
|
||||
|
||||
/* send server hostkey, DH pubkey 'f' and singed H */
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_KEXDH_REPLY)) != 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_string(ssh, signature, slen)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
(r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
|
||||
(r = sshpkt_put_bignum2_wrap(ssh, dh_server_pub)) != 0 || /* f */
|
||||
(r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
goto out;
|
||||
|
||||
if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
|
||||
r = kex_send_newkeys(ssh);
|
||||
out:
|
||||
out:
|
||||
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;
|
||||
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(signature);
|
||||
return r;
|
||||
}
|
||||
#endif /* WITH_OPENSSL */
|
||||
|
66
kexecdhc.c
66
kexecdhc.c
@ -26,8 +26,6 @@
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdio.h>
|
||||
@ -72,8 +70,8 @@ kexecdh_client(struct ssh *ssh)
|
||||
public_key = EC_KEY_get0_public_key(client_key);
|
||||
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_INIT)) != 0 ||
|
||||
(r = sshpkt_put_ec(ssh, public_key, group)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
(r = sshpkt_put_ec(ssh, public_key, group)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
goto out;
|
||||
debug("sending SSH2_MSG_KEX_ECDH_INIT");
|
||||
|
||||
@ -88,7 +86,7 @@ kexecdh_client(struct ssh *ssh)
|
||||
debug("expecting SSH2_MSG_KEX_ECDH_REPLY");
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &input_kex_ecdh_reply);
|
||||
r = 0;
|
||||
out:
|
||||
out:
|
||||
if (client_key)
|
||||
EC_KEY_free(client_key);
|
||||
return r;
|
||||
@ -103,6 +101,7 @@ input_kex_ecdh_reply(int type, u_int32_t seq, void *ctxt)
|
||||
EC_POINT *server_public = NULL;
|
||||
EC_KEY *client_key;
|
||||
BIGNUM *shared_secret = NULL;
|
||||
struct sshbn *xxx_shared_secret = NULL;
|
||||
struct sshkey *server_host_key = NULL;
|
||||
u_char *server_host_key_blob = NULL, *signature = NULL;
|
||||
u_char *kbuf = NULL;
|
||||
@ -120,13 +119,13 @@ input_kex_ecdh_reply(int type, u_int32_t seq, void *ctxt)
|
||||
|
||||
/* hostkey */
|
||||
if ((r = sshpkt_get_string(ssh, &server_host_key_blob,
|
||||
&sbloblen)) != 0 ||
|
||||
(r = sshkey_from_blob(server_host_key_blob, sbloblen,
|
||||
&server_host_key)) != 0)
|
||||
&sbloblen)) != 0 ||
|
||||
(r = sshkey_from_blob(server_host_key_blob, sbloblen,
|
||||
&server_host_key)) != 0)
|
||||
goto out;
|
||||
if (server_host_key->type != kex->hostkey_type ||
|
||||
(kex->hostkey_type == KEY_ECDSA &&
|
||||
server_host_key->ecdsa_nid != kex->hostkey_nid)) {
|
||||
(kex->hostkey_type == KEY_ECDSA &&
|
||||
server_host_key->ecdsa_nid != kex->hostkey_nid)) {
|
||||
r = SSH_ERR_KEY_TYPE_MISMATCH;
|
||||
goto out;
|
||||
}
|
||||
@ -142,8 +141,8 @@ input_kex_ecdh_reply(int type, u_int32_t seq, void *ctxt)
|
||||
goto out;
|
||||
}
|
||||
if ((r = sshpkt_get_ec(ssh, server_public, group)) != 0 ||
|
||||
(r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
|
||||
(r = sshpkt_get_end(ssh)) != 0)
|
||||
(r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
|
||||
(r = sshpkt_get_end(ssh)) != 0)
|
||||
goto out;
|
||||
|
||||
#ifdef DEBUG_KEXECDH
|
||||
@ -158,13 +157,13 @@ input_kex_ecdh_reply(int type, u_int32_t seq, void *ctxt)
|
||||
|
||||
klen = (EC_GROUP_get_degree(group) + 7) / 8;
|
||||
if ((kbuf = malloc(klen)) == NULL ||
|
||||
(shared_secret = BN_new()) == NULL) {
|
||||
(shared_secret = BN_new()) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
if (ECDH_compute_key(kbuf, klen, server_public,
|
||||
client_key, NULL) != (int)klen ||
|
||||
BN_bin2bn(kbuf, klen, shared_secret) == NULL) {
|
||||
client_key, NULL) != (int)klen ||
|
||||
BN_bin2bn(kbuf, klen, shared_secret) == NULL) {
|
||||
r = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
goto out;
|
||||
}
|
||||
@ -175,21 +174,21 @@ input_kex_ecdh_reply(int type, u_int32_t seq, void *ctxt)
|
||||
/* calc and verify H */
|
||||
hashlen = sizeof(hash);
|
||||
if ((r = kex_ecdh_hash(
|
||||
kex->hash_alg,
|
||||
group,
|
||||
kex->client_version_string,
|
||||
kex->server_version_string,
|
||||
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
|
||||
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
|
||||
server_host_key_blob, sbloblen,
|
||||
EC_KEY_get0_public_key(client_key),
|
||||
server_public,
|
||||
shared_secret,
|
||||
hash, &hashlen)) != 0)
|
||||
kex->hash_alg,
|
||||
group,
|
||||
kex->client_version_string,
|
||||
kex->server_version_string,
|
||||
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
|
||||
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
|
||||
server_host_key_blob, sbloblen,
|
||||
EC_KEY_get0_public_key(client_key),
|
||||
server_public,
|
||||
shared_secret,
|
||||
hash, &hashlen)) != 0)
|
||||
goto out;
|
||||
|
||||
if ((r = sshkey_verify(server_host_key, signature, slen, hash,
|
||||
hashlen, ssh->compat)) != 0)
|
||||
hashlen, ssh->compat)) != 0)
|
||||
goto out;
|
||||
|
||||
/* save session id */
|
||||
@ -203,9 +202,15 @@ input_kex_ecdh_reply(int type, u_int32_t seq, void *ctxt)
|
||||
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);
|
||||
out:
|
||||
out:
|
||||
explicit_bzero(hash, sizeof(hash));
|
||||
if (kex->ec_client_key) {
|
||||
EC_KEY_free(kex->ec_client_key);
|
||||
@ -219,10 +224,9 @@ input_kex_ecdh_reply(int type, u_int32_t seq, void *ctxt)
|
||||
}
|
||||
if (shared_secret)
|
||||
BN_clear_free(shared_secret);
|
||||
sshbn_free(xxx_shared_secret);
|
||||
sshkey_free(server_host_key);
|
||||
free(server_host_key_blob);
|
||||
free(signature);
|
||||
return r;
|
||||
}
|
||||
#endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */
|
||||
|
||||
|
65
kexecdhs.c
65
kexecdhs.c
@ -26,7 +26,7 @@
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC)
|
||||
|
||||
|
||||
#include <sys/types.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_POINT *public_key;
|
||||
BIGNUM *shared_secret = NULL;
|
||||
struct sshbn *xxx_shared_secret = NULL;
|
||||
struct sshkey *server_host_private, *server_host_public;
|
||||
u_char *server_host_key_blob = NULL, *signature = NULL;
|
||||
u_char *kbuf = NULL;
|
||||
@ -91,14 +92,14 @@ input_kex_ecdh_init(int type, u_int32_t seq, void *ctxt)
|
||||
#endif
|
||||
|
||||
if (kex->load_host_public_key == NULL ||
|
||||
kex->load_host_private_key == NULL) {
|
||||
kex->load_host_private_key == NULL) {
|
||||
r = SSH_ERR_INVALID_ARGUMENT;
|
||||
goto out;
|
||||
}
|
||||
server_host_public = kex->load_host_public_key(kex->hostkey_type,
|
||||
kex->hostkey_nid, ssh);
|
||||
kex->hostkey_nid, ssh);
|
||||
server_host_private = kex->load_host_private_key(kex->hostkey_type,
|
||||
kex->hostkey_nid, ssh);
|
||||
kex->hostkey_nid, ssh);
|
||||
if (server_host_public == NULL) {
|
||||
r = SSH_ERR_NO_HOSTKEY_LOADED;
|
||||
goto out;
|
||||
@ -108,7 +109,7 @@ input_kex_ecdh_init(int type, u_int32_t seq, void *ctxt)
|
||||
goto out;
|
||||
}
|
||||
if ((r = sshpkt_get_ec(ssh, client_public, group)) != 0 ||
|
||||
(r = sshpkt_get_end(ssh)) != 0)
|
||||
(r = sshpkt_get_end(ssh)) != 0)
|
||||
goto out;
|
||||
|
||||
#ifdef DEBUG_KEXECDH
|
||||
@ -124,13 +125,13 @@ input_kex_ecdh_init(int type, u_int32_t seq, void *ctxt)
|
||||
/* Calculate shared_secret */
|
||||
klen = (EC_GROUP_get_degree(group) + 7) / 8;
|
||||
if ((kbuf = malloc(klen)) == NULL ||
|
||||
(shared_secret = BN_new()) == NULL) {
|
||||
(shared_secret = BN_new()) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
if (ECDH_compute_key(kbuf, klen, client_public,
|
||||
server_key, NULL) != (int)klen ||
|
||||
BN_bin2bn(kbuf, klen, shared_secret) == NULL) {
|
||||
server_key, NULL) != (int)klen ||
|
||||
BN_bin2bn(kbuf, klen, shared_secret) == NULL) {
|
||||
r = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
goto out;
|
||||
}
|
||||
@ -140,21 +141,21 @@ input_kex_ecdh_init(int type, u_int32_t seq, void *ctxt)
|
||||
#endif
|
||||
/* calc H */
|
||||
if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob,
|
||||
&sbloblen)) != 0)
|
||||
&sbloblen)) != 0)
|
||||
goto out;
|
||||
hashlen = sizeof(hash);
|
||||
if ((r = kex_ecdh_hash(
|
||||
kex->hash_alg,
|
||||
group,
|
||||
kex->client_version_string,
|
||||
kex->server_version_string,
|
||||
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
|
||||
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
|
||||
server_host_key_blob, sbloblen,
|
||||
client_public,
|
||||
EC_KEY_get0_public_key(server_key),
|
||||
shared_secret,
|
||||
hash, &hashlen)) != 0)
|
||||
kex->hash_alg,
|
||||
group,
|
||||
kex->client_version_string,
|
||||
kex->server_version_string,
|
||||
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
|
||||
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
|
||||
server_host_key_blob, sbloblen,
|
||||
client_public,
|
||||
EC_KEY_get0_public_key(server_key),
|
||||
shared_secret,
|
||||
hash, &hashlen)) != 0)
|
||||
goto out;
|
||||
|
||||
/* save session id := H */
|
||||
@ -170,7 +171,7 @@ input_kex_ecdh_init(int type, u_int32_t seq, void *ctxt)
|
||||
|
||||
/* sign H */
|
||||
if ((r = kex->sign(server_host_private, server_host_public,
|
||||
&signature, &slen, hash, hashlen, ssh->compat)) < 0)
|
||||
&signature, &slen, hash, hashlen, ssh->compat)) < 0)
|
||||
goto out;
|
||||
|
||||
/* destroy_sensitive_data(); */
|
||||
@ -178,15 +179,20 @@ input_kex_ecdh_init(int type, u_int32_t seq, void *ctxt)
|
||||
public_key = EC_KEY_get0_public_key(server_key);
|
||||
/* send server hostkey, ECDH pubkey 'Q_S' and signed H */
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_REPLY)) != 0 ||
|
||||
(r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
|
||||
(r = sshpkt_put_ec(ssh, public_key, group)) != 0 ||
|
||||
(r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
(r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
|
||||
(r = sshpkt_put_ec(ssh, public_key, group)) != 0 ||
|
||||
(r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
goto out;
|
||||
|
||||
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);
|
||||
out:
|
||||
out:
|
||||
explicit_bzero(hash, sizeof(hash));
|
||||
if (kex->ec_client_key) {
|
||||
EC_KEY_free(kex->ec_client_key);
|
||||
@ -200,9 +206,8 @@ input_kex_ecdh_init(int type, u_int32_t seq, void *ctxt)
|
||||
}
|
||||
if (shared_secret)
|
||||
BN_clear_free(shared_secret);
|
||||
sshbn_free(xxx_shared_secret);
|
||||
free(server_host_key_blob);
|
||||
free(signature);
|
||||
return r;
|
||||
}
|
||||
#endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */
|
||||
|
||||
|
124
kexgex.c
124
kexgex.c
@ -35,8 +35,6 @@
|
||||
#undef KRB5
|
||||
#endif
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
@ -49,22 +47,23 @@
|
||||
#include "ssherr.h"
|
||||
#include "sshbuf.h"
|
||||
#include "digest.h"
|
||||
#include "crypto-wrap.h"
|
||||
|
||||
int
|
||||
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 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 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;
|
||||
@ -74,23 +73,23 @@ kexgex_hash(
|
||||
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(b, prime)) != 0 ||
|
||||
(r = sshbuf_put_bignum2(b, gen)) != 0 ||
|
||||
(r = sshbuf_put_bignum2(b, client_dh_pub)) != 0 ||
|
||||
(r = sshbuf_put_bignum2(b, server_dh_pub)) != 0 ||
|
||||
(r = sshbuf_put_bignum2(b, shared_secret)) != 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;
|
||||
}
|
||||
@ -108,4 +107,63 @@ kexgex_hash(
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif /* WITH_OPENSSL */
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
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(b, prime)) != 0 ||
|
||||
(r = sshbuf_put_bignum2(b, gen)) != 0 ||
|
||||
(r = sshbuf_put_bignum2(b, client_dh_pub)) != 0 ||
|
||||
(r = sshbuf_put_bignum2(b, server_dh_pub)) != 0 ||
|
||||
(r = sshbuf_put_bignum2(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;
|
||||
}
|
179
kexgexc.c
179
kexgexc.c
@ -26,14 +26,11 @@
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <openssl/dh.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.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_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
|
||||
kexgex_client(struct ssh *ssh)
|
||||
{
|
||||
@ -70,21 +84,21 @@ kexgex_client(struct ssh *ssh)
|
||||
kex->nbits = MIN(kex->nbits, 4096);
|
||||
/* New GEX request */
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST)) != 0 ||
|
||||
(r = sshpkt_put_u32(ssh, kex->min)) != 0 ||
|
||||
(r = sshpkt_put_u32(ssh, kex->nbits)) != 0 ||
|
||||
(r = sshpkt_put_u32(ssh, kex->max)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
(r = sshpkt_put_u32(ssh, kex->min)) != 0 ||
|
||||
(r = sshpkt_put_u32(ssh, kex->nbits)) != 0 ||
|
||||
(r = sshpkt_put_u32(ssh, kex->max)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
goto out;
|
||||
debug("SSH2_MSG_KEX_DH_GEX_REQUEST(%u<%u<%u) sent",
|
||||
kex->min, kex->nbits, kex->max);
|
||||
kex->min, kex->nbits, kex->max);
|
||||
#ifdef DEBUG_KEXDH
|
||||
fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n",
|
||||
kex->min, kex->nbits, kex->max);
|
||||
kex->min, kex->nbits, kex->max);
|
||||
#endif
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP,
|
||||
&input_kex_dh_gex_group);
|
||||
&input_kex_dh_gex_group);
|
||||
r = 0;
|
||||
out:
|
||||
out:
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -93,52 +107,55 @@ input_kex_dh_gex_group(int type, u_int32_t seq, void *ctxt)
|
||||
{
|
||||
struct ssh *ssh = ctxt;
|
||||
struct kex *kex = ssh->kex;
|
||||
BIGNUM *p = NULL, *g = NULL;
|
||||
int r, bits;
|
||||
struct sshbn *dh_client_pub = NULL;
|
||||
struct sshbn *dh_g = NULL, *dh_p = NULL;
|
||||
int r;
|
||||
size_t bits;
|
||||
|
||||
debug("got SSH2_MSG_KEX_DH_GEX_GROUP");
|
||||
|
||||
if ((p = BN_new()) == NULL ||
|
||||
(g = BN_new()) == NULL) {
|
||||
if ((dh_p = sshbn_new()) == NULL ||
|
||||
(dh_g = sshbn_new()) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
if ((r = sshpkt_get_bignum2(ssh, p)) != 0 ||
|
||||
(r = sshpkt_get_bignum2(ssh, g)) != 0 ||
|
||||
(r = sshpkt_get_end(ssh)) != 0)
|
||||
if ((r = sshpkt_get_bignum2_wrap(ssh, dh_p)) != 0 ||
|
||||
(r = sshpkt_get_bignum2_wrap(ssh, dh_g)) != 0 ||
|
||||
(r = sshpkt_get_end(ssh)) != 0)
|
||||
goto out;
|
||||
if ((bits = BN_num_bits(p)) < 0 ||
|
||||
(u_int)bits < kex->min || (u_int)bits > kex->max) {
|
||||
if ((bits = sshbn_bits(dh_p)) == 0 ||
|
||||
bits < kex->min || bits > kex->max) {
|
||||
r = SSH_ERR_DH_GEX_OUT_OF_RANGE;
|
||||
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;
|
||||
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 */
|
||||
if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0 ||
|
||||
(r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_INIT)) != 0 ||
|
||||
(r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
/* generate and send 'e', client DH public key */
|
||||
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_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)
|
||||
goto out;
|
||||
debug("SSH2_MSG_KEX_DH_GEX_INIT sent");
|
||||
#ifdef DEBUG_KEXDH
|
||||
DHparams_print_fp(stderr, kex->dh);
|
||||
fprintf(stderr, "pub= ");
|
||||
BN_print_fp(stderr, kex->dh->pub_key);
|
||||
fprintf(stderr, "\n");
|
||||
sshdh_dump(kex->dh);
|
||||
#endif
|
||||
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);
|
||||
r = 0;
|
||||
out:
|
||||
if (p)
|
||||
BN_clear_free(p);
|
||||
if (g)
|
||||
BN_clear_free(g);
|
||||
sshbn_free(dh_p);
|
||||
sshbn_free(dh_g);
|
||||
sshbn_free(dh_client_pub);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -147,12 +164,15 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
|
||||
{
|
||||
struct ssh *ssh = ctxt;
|
||||
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;
|
||||
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];
|
||||
size_t klen = 0, slen, sbloblen, hashlen;
|
||||
int kout, r;
|
||||
size_t slen, sbloblen, hashlen;
|
||||
int r;
|
||||
|
||||
debug("got SSH2_MSG_KEX_DH_GEX_REPLY");
|
||||
if (kex->verify_host_key == NULL) {
|
||||
@ -161,17 +181,17 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
|
||||
}
|
||||
/* key, cert */
|
||||
if ((r = sshpkt_get_string(ssh, &server_host_key_blob,
|
||||
&sbloblen)) != 0 ||
|
||||
(r = sshkey_from_blob(server_host_key_blob, sbloblen,
|
||||
&server_host_key)) != 0)
|
||||
&sbloblen)) != 0 ||
|
||||
(r = sshkey_from_blob(server_host_key_blob, sbloblen,
|
||||
&server_host_key)) != 0)
|
||||
goto out;
|
||||
if (server_host_key->type != kex->hostkey_type) {
|
||||
r = SSH_ERR_KEY_TYPE_MISMATCH;
|
||||
goto out;
|
||||
}
|
||||
if (server_host_key->type != kex->hostkey_type ||
|
||||
(kex->hostkey_type == KEY_ECDSA &&
|
||||
server_host_key->ecdsa_nid != kex->hostkey_nid)) {
|
||||
(kex->hostkey_type == KEY_ECDSA &&
|
||||
server_host_key->ecdsa_nid != kex->hostkey_nid)) {
|
||||
r = SSH_ERR_KEY_TYPE_MISMATCH;
|
||||
goto out;
|
||||
}
|
||||
@ -180,14 +200,14 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
|
||||
goto out;
|
||||
}
|
||||
/* 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;
|
||||
goto out;
|
||||
}
|
||||
/* signed H */
|
||||
if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 ||
|
||||
(r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
|
||||
(r = sshpkt_get_end(ssh)) != 0)
|
||||
if ((r = sshpkt_get_bignum2_wrap(ssh, dh_server_pub)) != 0 ||
|
||||
(r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
|
||||
(r = sshpkt_get_end(ssh)) != 0)
|
||||
goto out;
|
||||
#ifdef DEBUG_KEXDH
|
||||
fprintf(stderr, "dh_server_pub= ");
|
||||
@ -195,23 +215,19 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
|
||||
fprintf(stderr, "\n");
|
||||
debug("bits %d", BN_num_bits(dh_server_pub));
|
||||
#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");
|
||||
r = SSH_ERR_MESSAGE_INCOMPLETE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
klen = DH_size(kex->dh);
|
||||
if ((kbuf = malloc(klen)) == NULL ||
|
||||
(shared_secret = BN_new()) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
if ((dh_client_pub = sshdh_pubkey(kex->dh)) == NULL ||
|
||||
(dh_p = sshdh_p(kex->dh)) == NULL ||
|
||||
(dh_g = sshdh_g(kex->dh)) == NULL) {
|
||||
r = SSH_ERR_INTERNAL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 ||
|
||||
BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
|
||||
r = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
if ((r = sshdh_compute_key(kex->dh, dh_server_pub,
|
||||
&shared_secret)) != 0)
|
||||
goto out;
|
||||
}
|
||||
#ifdef DEBUG_KEXDH
|
||||
dump_digest("shared secret", kbuf, kout);
|
||||
#endif
|
||||
@ -221,22 +237,22 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
|
||||
/* calc and verify H */
|
||||
hashlen = sizeof(hash);
|
||||
if ((r = kexgex_hash(
|
||||
kex->hash_alg,
|
||||
kex->client_version_string,
|
||||
kex->server_version_string,
|
||||
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
|
||||
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
|
||||
server_host_key_blob, sbloblen,
|
||||
kex->min, kex->nbits, kex->max,
|
||||
kex->dh->p, kex->dh->g,
|
||||
kex->dh->pub_key,
|
||||
dh_server_pub,
|
||||
shared_secret,
|
||||
hash, &hashlen)) != 0)
|
||||
kex->hash_alg,
|
||||
kex->client_version_string,
|
||||
kex->server_version_string,
|
||||
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
|
||||
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
|
||||
server_host_key_blob, sbloblen,
|
||||
kex->min, kex->nbits, kex->max,
|
||||
dh_p, dh_g,
|
||||
dh_client_pub,
|
||||
dh_server_pub,
|
||||
shared_secret,
|
||||
hash, &hashlen)) != 0)
|
||||
goto out;
|
||||
|
||||
if ((r = sshkey_verify(server_host_key, signature, slen, hash,
|
||||
hashlen, ssh->compat)) != 0)
|
||||
hashlen, ssh->compat)) != 0)
|
||||
goto out;
|
||||
|
||||
/* save session id */
|
||||
@ -252,21 +268,16 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
|
||||
|
||||
if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
|
||||
r = kex_send_newkeys(ssh);
|
||||
out:
|
||||
out:
|
||||
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;
|
||||
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(signature);
|
||||
return r;
|
||||
}
|
||||
#endif /* WITH_OPENSSL */
|
||||
|
131
kexgexs.c
131
kexgexs.c
@ -30,16 +30,8 @@
|
||||
* 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 <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
@ -70,7 +62,7 @@ int
|
||||
kexgex_server(struct ssh *ssh)
|
||||
{
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST,
|
||||
&input_kex_dh_gex_request);
|
||||
&input_kex_dh_gex_request);
|
||||
debug("expecting SSH2_MSG_KEX_DH_GEX_REQUEST");
|
||||
return 0;
|
||||
}
|
||||
@ -80,14 +72,15 @@ input_kex_dh_gex_request(int type, u_int32_t seq, void *ctxt)
|
||||
{
|
||||
struct ssh *ssh = ctxt;
|
||||
struct kex *kex = ssh->kex;
|
||||
struct sshbn *dh_g = NULL, *dh_p = NULL;
|
||||
int r;
|
||||
u_int min = 0, max = 0, nbits = 0;
|
||||
|
||||
debug("SSH2_MSG_KEX_DH_GEX_REQUEST received");
|
||||
if ((r = sshpkt_get_u32(ssh, &min)) != 0 ||
|
||||
(r = sshpkt_get_u32(ssh, &nbits)) != 0 ||
|
||||
(r = sshpkt_get_u32(ssh, &max)) != 0 ||
|
||||
(r = sshpkt_get_end(ssh)) != 0)
|
||||
(r = sshpkt_get_u32(ssh, &nbits)) != 0 ||
|
||||
(r = sshpkt_get_u32(ssh, &max)) != 0 ||
|
||||
(r = sshpkt_get_end(ssh)) != 0)
|
||||
goto out;
|
||||
kex->nbits = nbits;
|
||||
kex->min = min;
|
||||
@ -98,7 +91,7 @@ input_kex_dh_gex_request(int type, u_int32_t seq, void *ctxt)
|
||||
nbits = MIN(DH_GRP_MAX, nbits);
|
||||
|
||||
if (kex->max < kex->min || kex->nbits < kex->min ||
|
||||
kex->max < kex->nbits) {
|
||||
kex->max < kex->nbits) {
|
||||
r = SSH_ERR_DH_GEX_OUT_OF_RANGE;
|
||||
goto out;
|
||||
}
|
||||
@ -110,11 +103,16 @@ input_kex_dh_gex_request(int type, u_int32_t seq, void *ctxt)
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
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");
|
||||
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(ssh, kex->dh->g)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
(r = sshpkt_put_bignum2_wrap(ssh, dh_p)) != 0 ||
|
||||
(r = sshpkt_put_bignum2_wrap(ssh, dh_g)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
goto out;
|
||||
|
||||
/* Compute our exchange value in parallel with the client */
|
||||
@ -124,7 +122,9 @@ input_kex_dh_gex_request(int type, u_int32_t seq, void *ctxt)
|
||||
debug("expecting SSH2_MSG_KEX_DH_GEX_INIT");
|
||||
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_INIT, &input_kex_dh_gex_init);
|
||||
r = 0;
|
||||
out:
|
||||
out:
|
||||
sshbn_free(dh_g);
|
||||
sshbn_free(dh_p);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -133,35 +133,37 @@ input_kex_dh_gex_init(int type, u_int32_t seq, void *ctxt)
|
||||
{
|
||||
struct ssh *ssh = ctxt;
|
||||
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;
|
||||
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];
|
||||
size_t sbloblen, slen;
|
||||
size_t klen = 0, hashlen;
|
||||
int kout, r;
|
||||
size_t sbloblen, slen, hashlen;
|
||||
int r;
|
||||
|
||||
if (kex->load_host_public_key == NULL ||
|
||||
kex->load_host_private_key == NULL) {
|
||||
kex->load_host_private_key == NULL) {
|
||||
r = SSH_ERR_INVALID_ARGUMENT;
|
||||
goto out;
|
||||
}
|
||||
server_host_public = kex->load_host_public_key(kex->hostkey_type,
|
||||
kex->hostkey_nid, ssh);
|
||||
kex->hostkey_nid, ssh);
|
||||
server_host_private = kex->load_host_private_key(kex->hostkey_type,
|
||||
kex->hostkey_nid, ssh);
|
||||
kex->hostkey_nid, ssh);
|
||||
if (server_host_public == NULL) {
|
||||
r = SSH_ERR_NO_HOSTKEY_LOADED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* key, cert */
|
||||
if ((dh_client_pub = BN_new()) == NULL) {
|
||||
if ((dh_client_pub = sshbn_new()) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
if ((r = sshpkt_get_bignum2(ssh, dh_client_pub)) != 0 ||
|
||||
(r = sshpkt_get_end(ssh)) != 0)
|
||||
if ((r = sshpkt_get_bignum2_wrap(ssh, dh_client_pub)) != 0 ||
|
||||
(r = sshpkt_get_end(ssh)) != 0)
|
||||
goto out;
|
||||
|
||||
#ifdef DEBUG_KEXDH
|
||||
@ -177,44 +179,40 @@ input_kex_dh_gex_init(int type, u_int32_t seq, void *ctxt)
|
||||
BN_print_fp(stderr, kex->dh->pub_key);
|
||||
fprintf(stderr, "\n");
|
||||
#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");
|
||||
r = SSH_ERR_MESSAGE_INCOMPLETE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
klen = DH_size(kex->dh);
|
||||
if ((kbuf = malloc(klen)) == NULL ||
|
||||
(shared_secret = BN_new()) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
if ((dh_server_pub = sshdh_pubkey(kex->dh)) == NULL ||
|
||||
(dh_p = sshdh_p(kex->dh)) == NULL ||
|
||||
(dh_g = sshdh_g(kex->dh)) == NULL) {
|
||||
r = SSH_ERR_INTERNAL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
if ((kout = DH_compute_key(kbuf, dh_client_pub, kex->dh)) < 0 ||
|
||||
BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
|
||||
r = SSH_ERR_LIBCRYPTO_ERROR;
|
||||
if ((r = sshdh_compute_key(kex->dh, dh_client_pub,
|
||||
&shared_secret)) != 0)
|
||||
goto out;
|
||||
}
|
||||
#ifdef DEBUG_KEXDH
|
||||
dump_digest("shared secret", kbuf, kout);
|
||||
#endif
|
||||
if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob,
|
||||
&sbloblen)) != 0)
|
||||
&sbloblen)) != 0)
|
||||
goto out;
|
||||
/* calc H */
|
||||
hashlen = sizeof(hash);
|
||||
if ((r = kexgex_hash(
|
||||
kex->hash_alg,
|
||||
kex->client_version_string,
|
||||
kex->server_version_string,
|
||||
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
|
||||
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
|
||||
server_host_key_blob, sbloblen,
|
||||
kex->min, kex->nbits, kex->max,
|
||||
kex->dh->p, kex->dh->g,
|
||||
dh_client_pub,
|
||||
kex->dh->pub_key,
|
||||
shared_secret,
|
||||
hash, &hashlen)) != 0)
|
||||
kex->hash_alg,
|
||||
kex->client_version_string,
|
||||
kex->server_version_string,
|
||||
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
|
||||
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
|
||||
server_host_key_blob, sbloblen,
|
||||
kex->min, kex->nbits, kex->max,
|
||||
dh_p, dh_g,
|
||||
dh_client_pub,
|
||||
dh_server_pub,
|
||||
shared_secret,
|
||||
hash, &hashlen)) != 0)
|
||||
goto out;
|
||||
|
||||
/* save session id := H */
|
||||
@ -230,34 +228,31 @@ input_kex_dh_gex_init(int type, u_int32_t seq, void *ctxt)
|
||||
|
||||
/* sign H */
|
||||
if ((r = kex->sign(server_host_private, server_host_public,
|
||||
&signature, &slen, hash, hashlen, ssh->compat)) < 0)
|
||||
&signature, &slen, hash, hashlen, ssh->compat)) < 0)
|
||||
goto out;
|
||||
|
||||
/* destroy_sensitive_data(); */
|
||||
|
||||
/* send server hostkey, DH pubkey 'f' and singed H */
|
||||
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_bignum2(ssh, kex->dh->pub_key)) != 0 || /* f */
|
||||
(r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
(r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
|
||||
(r = sshpkt_put_bignum2_wrap(ssh, dh_server_pub)) != 0 || /* f */
|
||||
(r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
goto out;
|
||||
|
||||
if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0)
|
||||
r = kex_send_newkeys(ssh);
|
||||
out:
|
||||
DH_free(kex->dh);
|
||||
out:
|
||||
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;
|
||||
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(signature);
|
||||
return r;
|
||||
}
|
||||
#endif /* WITH_OPENSSL */
|
||||
|
24
monitor.c
24
monitor.c
@ -664,8 +664,11 @@ monitor_reset_key_state(void)
|
||||
int
|
||||
mm_answer_moduli(int sock, Buffer *m)
|
||||
{
|
||||
DH *dh;
|
||||
struct sshdh *dh;
|
||||
int min, want, max;
|
||||
struct sshbn * dh_p = NULL;
|
||||
struct sshbn * dh_g = NULL;
|
||||
int ret = 0;
|
||||
|
||||
min = buffer_get_int(m);
|
||||
want = buffer_get_int(m);
|
||||
@ -681,18 +684,25 @@ mm_answer_moduli(int sock, Buffer *m)
|
||||
buffer_clear(m);
|
||||
|
||||
dh = choose_dh(min, want, max);
|
||||
|
||||
|
||||
if (dh == NULL) {
|
||||
buffer_put_char(m, 0);
|
||||
return (0);
|
||||
} else {
|
||||
/* Send first bignum */
|
||||
buffer_put_char(m, 1);
|
||||
buffer_put_bignum2(m, dh->p);
|
||||
buffer_put_bignum2(m, dh->g);
|
||||
if ((dh_p = sshdh_p(dh)) != NULL &&
|
||||
(dh_g = sshdh_g(dh)) != NULL) {
|
||||
|
||||
DH_free(dh);
|
||||
/* Send first bignum */
|
||||
buffer_put_char(m, 1);
|
||||
sshbuf_put_bignum2_wrap(m, dh_p);
|
||||
sshbuf_put_bignum2_wrap(m, dh_g);
|
||||
mm_request_send(sock, MONITOR_ANS_MODULI, m);
|
||||
}
|
||||
sshdh_free(dh);
|
||||
sshbn_free(dh_p);
|
||||
sshbn_free(dh_g);
|
||||
}
|
||||
mm_request_send(sock, MONITOR_ANS_MODULI, m);
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
319
monitor_wrap.c
319
monitor_wrap.c
@ -94,6 +94,7 @@
|
||||
#include "roaming.h"
|
||||
|
||||
#include "ssherr.h"
|
||||
#include "crypto-wrap.h"
|
||||
|
||||
/* Imports */
|
||||
extern int compat20;
|
||||
@ -116,17 +117,17 @@ mm_log_handler(LogLevel level, const char *msg, void *ctx)
|
||||
|
||||
buffer_init(&log_msg);
|
||||
/*
|
||||
* Placeholder for packet length. Will be filled in with the actual
|
||||
* packet length once the packet has been constucted. This saves
|
||||
* fragile math.
|
||||
*/
|
||||
* Placeholder for packet length. Will be filled in with the actual
|
||||
* packet length once the packet has been constucted. This saves
|
||||
* fragile math.
|
||||
*/
|
||||
buffer_put_int(&log_msg, 0);
|
||||
|
||||
buffer_put_int(&log_msg, level);
|
||||
buffer_put_cstring(&log_msg, msg);
|
||||
put_u32(buffer_ptr(&log_msg), buffer_len(&log_msg) - 4);
|
||||
if (atomicio(vwrite, mon->m_log_sendfd, buffer_ptr(&log_msg),
|
||||
buffer_len(&log_msg)) != buffer_len(&log_msg))
|
||||
buffer_len(&log_msg)) != buffer_len(&log_msg))
|
||||
fatal("%s: write: %s", __func__, strerror(errno));
|
||||
buffer_free(&log_msg);
|
||||
}
|
||||
@ -135,9 +136,9 @@ int
|
||||
mm_is_monitor(void)
|
||||
{
|
||||
/*
|
||||
* m_pid is only set in the privileged part, and
|
||||
* points to the unprivileged child.
|
||||
*/
|
||||
* m_pid is only set in the privileged part, and
|
||||
* points to the unprivileged child.
|
||||
*/
|
||||
return (pmonitor && pmonitor->m_pid > 0);
|
||||
}
|
||||
|
||||
@ -150,7 +151,7 @@ mm_request_send(int sock, enum monitor_reqtype type, Buffer *m)
|
||||
debug3("%s entering: type %d", __func__, type);
|
||||
|
||||
put_u32(buf, mlen + 1);
|
||||
buf[4] = (u_char) type; /* 1st byte of payload is mesg-type */
|
||||
buf[4] = (u_char)type; /* 1st byte of payload is mesg-type */
|
||||
if (atomicio(vwrite, sock, buf, sizeof(buf)) != sizeof(buf))
|
||||
fatal("%s: write: %s", __func__, strerror(errno));
|
||||
if (atomicio(vwrite, sock, buffer_ptr(m), mlen) != mlen)
|
||||
@ -190,15 +191,15 @@ mm_request_receive_expect(int sock, enum monitor_reqtype type, Buffer *m)
|
||||
rtype = buffer_get_char(m);
|
||||
if (rtype != type)
|
||||
fatal("%s: read: rtype %d != type %d", __func__,
|
||||
rtype, type);
|
||||
rtype, type);
|
||||
}
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
DH *
|
||||
mm_choose_dh(int min, int nbits, int max)
|
||||
struct sshdh *
|
||||
mm_choose_dh(int min, int nbits, int max)
|
||||
{
|
||||
BIGNUM *p, *g;
|
||||
int success = 0;
|
||||
struct sshbn *p, *g;
|
||||
int r, success = 0;
|
||||
Buffer m;
|
||||
|
||||
buffer_init(&m);
|
||||
@ -215,23 +216,22 @@ mm_choose_dh(int min, int nbits, int max)
|
||||
if (success == 0)
|
||||
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__);
|
||||
if ((g = BN_new()) == NULL)
|
||||
fatal("%s: BN_new failed", __func__);
|
||||
buffer_get_bignum2(&m, p);
|
||||
buffer_get_bignum2(&m, g);
|
||||
if ((r = sshbuf_get_bignum2_wrap(&m, p)) != 0 ||
|
||||
(r = sshbuf_get_bignum2_wrap(&m, g)) != 0)
|
||||
fatal("%s: sshbuf_get_bignum2_wrap: %s", __func__, ssh_err(r));
|
||||
|
||||
debug3("%s: remaining %d", __func__, buffer_len(&m));
|
||||
buffer_free(&m);
|
||||
|
||||
return (dh_new_group(g, p));
|
||||
return (sshdh_new_group(g, p));
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
mm_key_sign(Key *key, u_char **sigp, u_int *lenp,
|
||||
const u_char *data, u_int datalen)
|
||||
const u_char *data, u_int datalen)
|
||||
{
|
||||
struct kex *kex = *pmonitor->m_pkex;
|
||||
Buffer m;
|
||||
@ -246,14 +246,14 @@ mm_key_sign(Key *key, u_char **sigp, u_int *lenp,
|
||||
|
||||
debug3("%s: waiting for MONITOR_ANS_SIGN", __func__);
|
||||
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_SIGN, &m);
|
||||
*sigp = buffer_get_string(&m, lenp);
|
||||
*sigp = buffer_get_string(&m, lenp);
|
||||
buffer_free(&m);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
struct passwd *
|
||||
mm_getpwnamallow(const char *username)
|
||||
mm_getpwnamallow(const char *username)
|
||||
{
|
||||
Buffer m;
|
||||
struct passwd *pw;
|
||||
@ -279,12 +279,8 @@ mm_getpwnamallow(const char *username)
|
||||
fatal("%s: struct passwd size mismatch", __func__);
|
||||
pw->pw_name = 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);
|
||||
#endif
|
||||
#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
|
||||
pw->pw_class = buffer_get_string(&m, NULL);
|
||||
#endif
|
||||
// pw->pw_class = buffer_get_string(&m, NULL);
|
||||
pw->pw_dir = buffer_get_string(&m, NULL);
|
||||
pw->pw_shell = buffer_get_string(&m, NULL);
|
||||
|
||||
@ -328,7 +324,7 @@ mm_auth2_read_banner(void)
|
||||
buffer_clear(&m);
|
||||
|
||||
mm_request_receive_expect(pmonitor->m_recvfd,
|
||||
MONITOR_ANS_AUTH2_READ_BANNER, &m);
|
||||
MONITOR_ANS_AUTH2_READ_BANNER, &m);
|
||||
banner = buffer_get_string(&m, NULL);
|
||||
buffer_free(&m);
|
||||
|
||||
@ -379,7 +375,7 @@ mm_auth_password(Authctxt *authctxt, char *password)
|
||||
buffer_free(&m);
|
||||
|
||||
debug3("%s: user %sauthenticated",
|
||||
__func__, authenticated ? "" : "not ");
|
||||
__func__, authenticated ? "" : "not ");
|
||||
return (authenticated);
|
||||
}
|
||||
|
||||
@ -387,19 +383,19 @@ int
|
||||
mm_user_key_allowed(struct passwd *pw, Key *key, int pubkey_auth_attempt)
|
||||
{
|
||||
return (mm_key_allowed(MM_USERKEY, NULL, NULL, key,
|
||||
pubkey_auth_attempt));
|
||||
pubkey_auth_attempt));
|
||||
}
|
||||
|
||||
int
|
||||
mm_hostbased_key_allowed(struct passwd *pw, char *user, char *host,
|
||||
Key *key)
|
||||
Key *key)
|
||||
{
|
||||
return (mm_key_allowed(MM_HOSTKEY, user, host, key, 0));
|
||||
}
|
||||
|
||||
int
|
||||
mm_auth_rhosts_rsa_key_allowed(struct passwd *pw, char *user,
|
||||
char *host, Key *key)
|
||||
char *host, Key *key)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -411,7 +407,7 @@ mm_auth_rhosts_rsa_key_allowed(struct passwd *pw, char *user,
|
||||
|
||||
int
|
||||
mm_key_allowed(enum mm_keytype type, char *user, char *host, Key *key,
|
||||
int pubkey_auth_attempt)
|
||||
int pubkey_auth_attempt)
|
||||
{
|
||||
Buffer m;
|
||||
u_char *blob;
|
||||
@ -450,10 +446,10 @@ mm_key_allowed(enum mm_keytype type, char *user, char *host, Key *key,
|
||||
}
|
||||
|
||||
/*
|
||||
* This key verify needs to send the key type along, because the
|
||||
* privileged parent makes the decision if the key is allowed
|
||||
* for authentication.
|
||||
*/
|
||||
* This key verify needs to send the key type along, because the
|
||||
* privileged parent makes the decision if the key is allowed
|
||||
* for authentication.
|
||||
*/
|
||||
|
||||
int
|
||||
mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen)
|
||||
@ -498,7 +494,7 @@ mm_send_keystate(struct monitor *monitor)
|
||||
fatal("%s: sshbuf_new failed", __func__);
|
||||
if ((r = ssh_packet_get_state(ssh, m)) != 0)
|
||||
fatal("%s: get_state failed: %s",
|
||||
__func__, ssh_err(r));
|
||||
__func__, ssh_err(r));
|
||||
mm_request_send(monitor->m_recvfd, MONITOR_REQ_KEYEXPORT, m);
|
||||
debug3("%s: Finished sending state", __func__);
|
||||
sshbuf_free(m);
|
||||
@ -513,7 +509,7 @@ mm_pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen)
|
||||
|
||||
/* Kludge: ensure there are fds free to receive the pty/tty */
|
||||
if ((tmp1 = dup(pmonitor->m_recvfd)) == -1 ||
|
||||
(tmp2 = dup(pmonitor->m_recvfd)) == -1) {
|
||||
(tmp2 = dup(pmonitor->m_recvfd)) == -1) {
|
||||
error("%s: cannot allocate fds for pty", __func__);
|
||||
if (tmp1 > 0)
|
||||
close(tmp1);
|
||||
@ -547,7 +543,7 @@ mm_pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen)
|
||||
free(msg);
|
||||
|
||||
if ((*ptyfd = mm_receive_fd(pmonitor->m_recvfd)) == -1 ||
|
||||
(*ttyfd = mm_receive_fd(pmonitor->m_recvfd)) == -1)
|
||||
(*ttyfd = mm_receive_fd(pmonitor->m_recvfd)) == -1)
|
||||
fatal("%s: receive fds failed", __func__);
|
||||
|
||||
/* Success */
|
||||
@ -569,143 +565,12 @@ mm_session_pty_cleanup2(Session *s)
|
||||
/* closed dup'ed master */
|
||||
if (s->ptymaster != -1 && close(s->ptymaster) < 0)
|
||||
error("close(s->ptymaster/%d): %s",
|
||||
s->ptymaster, strerror(errno));
|
||||
s->ptymaster, strerror(errno));
|
||||
|
||||
/* unlink pty from session */
|
||||
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 */
|
||||
|
||||
void
|
||||
@ -742,7 +607,7 @@ mm_ssh1_session_key(BIGNUM *num)
|
||||
|
||||
static void
|
||||
mm_chall_setup(char **name, char **infotxt, u_int *numprompts,
|
||||
char ***prompts, u_int **echo_on)
|
||||
char ***prompts, u_int **echo_on)
|
||||
{
|
||||
*name = xstrdup("");
|
||||
*infotxt = xstrdup("");
|
||||
@ -754,7 +619,7 @@ mm_chall_setup(char **name, char **infotxt, u_int *numprompts,
|
||||
|
||||
int
|
||||
mm_bsdauth_query(void *ctx, char **name, char **infotxt,
|
||||
u_int *numprompts, char ***prompts, u_int **echo_on)
|
||||
u_int *numprompts, char ***prompts, u_int **echo_on)
|
||||
{
|
||||
Buffer m;
|
||||
u_int success;
|
||||
@ -766,7 +631,7 @@ mm_bsdauth_query(void *ctx, char **name, char **infotxt,
|
||||
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_BSDAUTHQUERY, &m);
|
||||
|
||||
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_BSDAUTHQUERY,
|
||||
&m);
|
||||
&m);
|
||||
success = buffer_get_int(&m);
|
||||
if (success == 0) {
|
||||
debug3("%s: no challenge", __func__);
|
||||
@ -775,7 +640,7 @@ mm_bsdauth_query(void *ctx, char **name, char **infotxt,
|
||||
}
|
||||
|
||||
/* Get the challenge, and format the response */
|
||||
challenge = buffer_get_string(&m, NULL);
|
||||
challenge = buffer_get_string(&m, NULL);
|
||||
buffer_free(&m);
|
||||
|
||||
mm_chall_setup(name, infotxt, numprompts, prompts, echo_on);
|
||||
@ -801,7 +666,7 @@ mm_bsdauth_respond(void *ctx, u_int numresponses, char **responses)
|
||||
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_BSDAUTHRESPOND, &m);
|
||||
|
||||
mm_request_receive_expect(pmonitor->m_recvfd,
|
||||
MONITOR_ANS_BSDAUTHRESPOND, &m);
|
||||
MONITOR_ANS_BSDAUTHRESPOND, &m);
|
||||
|
||||
authok = buffer_get_int(&m);
|
||||
buffer_free(&m);
|
||||
@ -809,66 +674,6 @@ mm_bsdauth_respond(void *ctx, u_int numresponses, char **responses)
|
||||
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
|
||||
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
|
||||
|
||||
#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
|
||||
OM_uint32
|
||||
mm_ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID goid)
|
||||
@ -1038,7 +813,7 @@ mm_ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID goid)
|
||||
|
||||
OM_uint32
|
||||
mm_ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_desc *in,
|
||||
gss_buffer_desc *out, OM_uint32 *flags)
|
||||
gss_buffer_desc *out, OM_uint32 *flags)
|
||||
{
|
||||
Buffer m;
|
||||
OM_uint32 major;
|
||||
@ -1073,7 +848,7 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
|
||||
|
||||
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSCHECKMIC, &m);
|
||||
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSCHECKMIC,
|
||||
&m);
|
||||
&m);
|
||||
|
||||
major = buffer_get_int(&m);
|
||||
buffer_free(&m);
|
||||
@ -1090,12 +865,12 @@ mm_ssh_gssapi_userok(char *user)
|
||||
|
||||
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, &m);
|
||||
mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUSEROK,
|
||||
&m);
|
||||
&m);
|
||||
|
||||
authenticated = buffer_get_int(&m);
|
||||
|
||||
buffer_free(&m);
|
||||
debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
|
||||
debug3("%s: user %sauthenticated", __func__, authenticated ? "" : "not ");
|
||||
return (authenticated);
|
||||
}
|
||||
#endif /* GSSAPI */
|
||||
|
@ -39,7 +39,7 @@ struct Authctxt;
|
||||
|
||||
void mm_log_handler(LogLevel, const char *, 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);
|
||||
void mm_inform_authserv(char *, char *);
|
||||
struct passwd *mm_getpwnamallow(const char *);
|
||||
|
@ -203,6 +203,8 @@ realpath(const char *path, char resolved[PATH_MAX])
|
||||
|
||||
#else
|
||||
|
||||
#include <Shlwapi.h>
|
||||
|
||||
void backslashconvert(char *str)
|
||||
{
|
||||
while (*str) {
|
||||
|
214
openssl-bn.c
Normal file
214
openssl-bn.c
Normal 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
199
openssl-dh.c
Normal 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;
|
||||
}
|
@ -1723,7 +1723,7 @@ initialize_options(Options * options)
|
||||
options->tun_remote = -1;
|
||||
options->local_command = NULL;
|
||||
options->permit_local_command = -1;
|
||||
options->use_roaming = -1;
|
||||
options->use_roaming = 0;
|
||||
options->visual_host_key = -1;
|
||||
options->ip_qos_interactive = -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;
|
||||
if (options->permit_local_command == -1)
|
||||
options->permit_local_command = 0;
|
||||
if (options->use_roaming == -1)
|
||||
options->use_roaming = 1;
|
||||
options->use_roaming = 0;
|
||||
if (options->visual_host_key == -1)
|
||||
options->visual_host_key = 0;
|
||||
if (options->ip_qos_interactive == -1)
|
||||
|
@ -520,6 +520,11 @@ main(int argc, char **argv)
|
||||
fprintf(stderr, "Could not open a connection to your "
|
||||
"authentication agent.\n");
|
||||
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:
|
||||
fprintf(stderr, "Error connecting to agent: %s\n", ssh_err(r));
|
||||
exit(2);
|
||||
|
@ -1734,7 +1734,9 @@ main(int ac, char **av)
|
||||
cleanup_exit(1);
|
||||
}
|
||||
if (pid != 0) { /* Parent - execute the given command. */
|
||||
#ifndef WIN32_FIXME
|
||||
close(sock);
|
||||
#endif
|
||||
snprintf(pidstrbuf, sizeof pidstrbuf, "%ld", (long)pid);
|
||||
if (ac == 0) {
|
||||
#ifdef WIN32_FIXME
|
||||
@ -1748,6 +1750,11 @@ main(int ac, char **av)
|
||||
printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
|
||||
SSH_AGENTPID_ENV_NAME);
|
||||
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);
|
||||
}
|
||||
if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 ||
|
||||
|
2
ssh.c
2
ssh.c
@ -2163,8 +2163,6 @@ ssh_session2(void)
|
||||
fork_postauth();
|
||||
}
|
||||
|
||||
if (options.use_roaming)
|
||||
request_roaming();
|
||||
|
||||
return client_loop(tty_flag, tty_flag ?
|
||||
options.escape_char : SSH_ESCAPECHAR_NONE, id);
|
||||
|
@ -76,6 +76,8 @@
|
||||
#include "ssh-gss.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* import */
|
||||
extern char *client_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)
|
||||
fatal("kex_setup: %s", ssh_err(r));
|
||||
kex = active_state->kex;
|
||||
#ifdef WITH_OPENSSL
|
||||
|
||||
kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
|
||||
kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client;
|
||||
kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
|
||||
kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
|
||||
|
||||
# ifdef OPENSSL_HAS_ECC
|
||||
kex->kex[KEX_ECDH_SHA2] = kexecdh_client;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
kex->kex[KEX_C25519_SHA256] = kexc25519_client;
|
||||
kex->client_version_string=client_version_string;
|
||||
kex->server_version_string=server_version_string;
|
||||
|
8
sshd.c
8
sshd.c
@ -145,6 +145,8 @@
|
||||
#define O_NOCTTY 0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Re-exec fds */
|
||||
#define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1)
|
||||
#define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2)
|
||||
@ -3378,15 +3380,17 @@ do_ssh2_kex(void)
|
||||
if ((r = kex_setup(active_state, myproposal)) != 0)
|
||||
fatal("kex_setup: %s", ssh_err(r));
|
||||
kex = active_state->kex;
|
||||
#ifdef WITH_OPENSSL
|
||||
|
||||
|
||||
kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
|
||||
kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
|
||||
kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
|
||||
kex->kex[KEX_DH_GEX_SHA256] = kexgex_server;
|
||||
|
||||
# ifdef OPENSSL_HAS_ECC
|
||||
kex->kex[KEX_ECDH_SHA2] = kexecdh_server;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
kex->kex[KEX_C25519_SHA256] = kexc25519_server;
|
||||
kex->server = 1;
|
||||
kex->client_version_string=client_version_string;
|
||||
|
Loading…
x
Reference in New Issue
Block a user