📄 emptypacketschecker.cpp
字号:
SecBuffer Buffers[4];
BufferDesc.cBuffers = _countof(Buffers);
BufferDesc.pBuffers = Buffers;
BufferDesc.ulVersion = SECBUFFER_VERSION;
Buffers[0].BufferType = SECBUFFER_STREAM_HEADER;
Buffers[0].pvBuffer = pCompositeInBuffer;
Buffers[0].cbBuffer = Sizes.cbHeader;
Buffers[1].BufferType = SECBUFFER_DATA;
Buffers[1].pvBuffer = pCompositeInBuffer + Sizes.cbHeader;
Buffers[1].cbBuffer = cbData;
Buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
Buffers[2].pvBuffer = pCompositeInBuffer + Sizes.cbHeader + cbData;
Buffers[2].cbBuffer = Sizes.cbTrailer;
Buffers[3].BufferType = SECBUFFER_EMPTY;
// Encrypt the message.
scRet = EncryptMessage(phContext, 0, &BufferDesc, 0);
if (scRet != SEC_E_OK)
{
error("failure encrypting message: 0x%x\n", scRet);
goto cleanup;
}
ULONG cbEncryptedData = Buffers[0].cbBuffer + Buffers[1].cbBuffer + Buffers[2].cbBuffer;
verbose("%5d raw bytes being sent on socket.\n", cbData);
cbData = send(s, pCompositeInBuffer, cbEncryptedData, 0);
if(cbData == SOCKET_ERROR || cbData == 0)
{
error("failure sending data: 0x%x\n", WSAGetLastError());
goto cleanup;
}
result = true;
cleanup:
if (pCompositeInBuffer) LocalFree(pCompositeInBuffer);
return result;
}
int DecryptingRecv(SOCKET s, PCtxtHandle phContext, char * pBuffer, int cbBufferSize, char * pExtraData, int cbExtraDataSize, int * pcbExtraData, bool * pbEmptyPacketsDetected)
{
int result = 0;
SECURITY_STATUS scRet;
// Find certain important buffer sizes
SecPkgContext_StreamSizes Sizes;
scRet = QueryContextAttributes(phContext, SECPKG_ATTR_STREAM_SIZES, &Sizes);
if(scRet != SEC_E_OK)
{
error("0x%x reading SECPKG_ATTR_STREAM_SIZES\n", scRet);
goto cleanup;
}
ULONG nMaxPacketTotalSize = Sizes.cbHeader + Sizes.cbMaximumMessage + Sizes.cbTrailer;
ULONG cbMessageSize = nMaxPacketTotalSize;
char* pMessage = (char*)LocalAlloc(LMEM_FIXED, cbMessageSize);
if (pMessage == NULL)
{
oom;
goto cleanup;
}
// Initialize security buffers
SecBufferDesc BufferDesc;
SecBuffer Buffers[4];
BufferDesc.cBuffers = _countof(Buffers);
BufferDesc.pBuffers = Buffers;
BufferDesc.ulVersion = SECBUFFER_VERSION;
SecBuffer * pDataBuffer;
SecBuffer * pExtraBuffer;
// Mark the position of where the actual data buffer will go, and fill up any extra data from earlier.
memcpy_s(pMessage, cbMessageSize, pExtraData, *pcbExtraData);
ULONG cbMessage = *pcbExtraData;
do
{
do
{
Buffers[0].BufferType = SECBUFFER_DATA;
Buffers[0].pvBuffer = pMessage;
Buffers[0].cbBuffer = 0;
Buffers[1].BufferType = SECBUFFER_EMPTY;
Buffers[2].BufferType = SECBUFFER_EMPTY;
Buffers[3].BufferType = SECBUFFER_EMPTY;
if (cbMessage > 0)
{
Buffers[0].cbBuffer = cbMessage;
scRet = DecryptMessage(phContext, &BufferDesc, 0, NULL);
}
if (cbMessage == 0 || scRet == SEC_E_INCOMPLETE_MESSAGE)
{
if (scRet == SEC_E_INCOMPLETE_MESSAGE)
{
verbose("incomplete message received, calling recv again.\n");
}
int bytes_read = recv(s, pMessage + cbMessage, cbMessageSize - cbMessage, 0);
if (bytes_read == 0 || bytes_read == SOCKET_ERROR)
{
error("socket unexpectedly closed.\n");
goto cleanup;
}
else
{
verbose("%5d raw bytes received from socket.\n", bytes_read);
}
cbMessage += bytes_read;
scRet = SEC_E_INCOMPLETE_MESSAGE;
}
} while (scRet == SEC_E_INCOMPLETE_MESSAGE);
if (scRet != SEC_E_OK && scRet != SEC_I_CONTEXT_EXPIRED)
{
error("DecryptMessage failed with error code 0x%x\n", scRet);
result = SOCKET_ERROR;
goto cleanup;
}
pDataBuffer = NULL;
pExtraBuffer = NULL;
for (ULONG i = 0; i < BufferDesc.cBuffers; i++)
{
switch(BufferDesc.pBuffers[i].BufferType)
{
case SECBUFFER_DATA:
pDataBuffer = &BufferDesc.pBuffers[i];
break;
case SECBUFFER_EXTRA:
pExtraBuffer = &BufferDesc.pBuffers[i];
break;
}
}
// If we decrypted an "empty" packet, prepare to decrypt another one so we get something useful.
if (pDataBuffer->cbBuffer == 0)
{
*pbEmptyPacketsDetected = true;
if (pExtraBuffer)
{
verbose("%5d bytes in decrypted packet (EMPTY). But some more data is waiting for decryption.\n", 0);
// move the extra buffer into the data buffer in preparation to try decrypting again.
memmove_s(pMessage, cbMessageSize, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer);
cbMessage = pExtraBuffer->cbBuffer;
}
else
{
verbose("%5d bytes in decrypted packet (EMPTY). No extra data. Waiting for more...\n", 0);
// No extra buffer, but set to an empty state and listen for more.
cbMessage = 0;
}
}
} while (pDataBuffer->cbBuffer == 0); // loop until we get a non-empty encrypted packet.
if (scRet == SEC_I_CONTEXT_EXPIRED)
{
verbose("The server closed the security context.\n");
result = 0;
*pcbExtraData = 0;
}
else
{
verbose("%5d bytes in decrypted packet.\n", pDataBuffer->cbBuffer);
// copy decrypted buffer into caller's buffer
memcpy_s(pBuffer, cbBufferSize, pDataBuffer->pvBuffer, pDataBuffer->cbBuffer);
result = pDataBuffer->cbBuffer;
// Copy the extra bytes buffer into the caller's extra bytes buffer
if (pExtraBuffer)
{
memcpy_s(pExtraData, cbExtraDataSize, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer);
*pcbExtraData = pExtraBuffer->cbBuffer;
}
else
{
*pcbExtraData = 0;
}
}
cleanup:
if (pMessage) LocalFree(pMessage);
return result;
}
bool ReceiveResponse(SOCKET s, PCtxtHandle phContext, bool * pbEmptyPacketsDetected)
{
bool result = false;
*pbEmptyPacketsDetected = false;
char * pExtraData = NULL;
char* pMessage = NULL;
SECURITY_STATUS scRet;
// Find certain important buffer sizes
SecPkgContext_StreamSizes Sizes;
scRet = QueryContextAttributes(phContext, SECPKG_ATTR_STREAM_SIZES, &Sizes);
if(scRet != SEC_E_OK)
{
error("0x%x reading SECPKG_ATTR_STREAM_SIZES\n", scRet);
goto cleanup;
}
ULONG nMaxPacketTotalSize = Sizes.cbHeader + Sizes.cbMaximumMessage + Sizes.cbTrailer;
ULONG cbMessageSize = max(nMaxPacketTotalSize, 1024*1024);
pMessage = (char*)LocalAlloc(LMEM_FIXED, cbMessageSize);
if (pMessage == NULL)
{
oom;
goto cleanup;
}
int cbExtraData = 0; // number of valid characters in the buffer
ULONG cbExtraDataSize = nMaxPacketTotalSize; // size of allocated buffer
pExtraData = (char*)LocalAlloc(LMEM_FIXED, cbExtraDataSize);
if (pExtraData == NULL)
{
oom;
goto cleanup;
}
ULONG cbTotalRead = 0;
ULONG cbExpectedContentLength = 1;
BOOL bContentLengthParsed = false;
ULONG cbHeadersLength = 0;
BOOL bHeadersEndFound = false;
BOOL bStreaming = false;
while (cbTotalRead - cbHeadersLength < cbExpectedContentLength)
{
ULONG cbMessage = DecryptingRecv(
s, phContext,
pMessage + cbTotalRead, cbMessageSize - cbTotalRead,
pExtraData, cbExtraDataSize, &cbExtraData,
pbEmptyPacketsDetected);
if (cbMessage == SOCKET_ERROR || cbMessage == 0)
{
if (bStreaming && cbMessage == 0)
{
verbose("Streaming end of data found.\n");
break;
}
else
{
error("failed read operation.\n");
return false;
}
}
cbTotalRead += cbMessage;
pMessage[cbTotalRead] = 0; // add null terminator since HTTP doesn't do that for us
if (bStreaming)
{
cbExpectedContentLength = cbTotalRead - cbHeadersLength + 1;
}
// Look for the content length header if we haven't found it yet.
if (!bContentLengthParsed && !bStreaming)
{
char* pszContentLengthHeader = strstr(pMessage, CONTENT_LENGTH_HEADER);
if (pszContentLengthHeader)
{
cbExpectedContentLength = atol(pszContentLengthHeader + strlen(CONTENT_LENGTH_HEADER));
bContentLengthParsed = true;
verbose("Found %s%d\n", CONTENT_LENGTH_HEADER, cbExpectedContentLength);
}
else
{
cbExpectedContentLength = cbTotalRead - cbHeadersLength + 1; // keep looking
}
}
if (!bHeadersEndFound)
{
char* pszEndHeaderIndex = strstr(pMessage, "\r\n\r\n");
if (pszEndHeaderIndex)
{
bHeadersEndFound = true;
cbHeadersLength = pszEndHeaderIndex + 4 - pMessage;
bStreaming = !bContentLengthParsed;
}
}
if (!bHeadersEndFound)
{
cbHeadersLength = cbTotalRead;
}
}
verbose("%5d bytes in decrypted packet.\n", cbTotalRead/*, pMessage*/);
result = true;
cleanup:
if (pMessage) LocalFree(pMessage);
if (pExtraData) LocalFree(pExtraData);
return result;
}
int _tmain(int argc, wchar_t* argv[])
{
CredHandle hCredential;
CtxtHandle hContext;
SOCKET socket = INVALID_SOCKET;
SecInvalidateHandle(&hCredential);
SecInvalidateHandle(&hContext);
wchar_t* pwzHost = NULL;
u_short nPort;
wchar_t* pwzRequestUrl = NULL;
bool bEmptyPacketsDetected;
int nReturnCode = RETURN_CODE_ERROR;
if (argc != 2)
{
printf("USAGE: %S https://<urltotest>\n", argv[0]);
nReturnCode = RETURN_CODE_USAGE;
goto cleanup;
}
if (!ParseCommandLine(argv[1], &pwzHost, &nPort, &pwzRequestUrl))
{
nReturnCode = RETURN_CODE_USAGE_ERROR;
goto cleanup;
}
if (!InitializeCredential(&hCredential)) goto cleanup;
if (!InitializeSockets()) goto cleanup;
if (!ConnectSocket(socket, pwzHost, nPort)) goto cleanup;
if (!Handshake(socket, pwzHost, &hCredential, &hContext)) goto cleanup;
if (!SendRequest(socket, pwzHost, pwzRequestUrl, &hContext)) goto cleanup;
if (!ReceiveResponse(socket, &hContext, &bEmptyPacketsDetected)) goto cleanup;
printf("--------\nTest completed: empty encryption packets %s detected.\n",
bEmptyPacketsDetected ? "WERE" : "WERE NOT");
if (bEmptyPacketsDetected)
{
printf("This may cause compatibility issues with .NET Compact Framework versions\n2.0 SP2 (and earlier) and 3.5 RTM.\n");
}
cleanup:
if (SecIsValidHandle(&hContext))
{
DeleteSecurityContext(&hContext);
SecInvalidateHandle(&hContext);
}
if (socket != INVALID_SOCKET)
{
closesocket(socket);
}
WSACleanup();
if (SecIsValidHandle(&hCredential))
{
FreeCredentialsHandle(&hCredential);
SecInvalidateHandle(&hCredential);
}
if (pwzHost) delete pwzHost;
if (pwzRequestUrl) delete pwzRequestUrl;
return nReturnCode;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -