WinHttpReceiveResponse function return an error - c++

Can someone tell me what is wrong in the code below?
void Mess(LPCWSTR Str)
{
MessageBox(0, Str, L"Hi", 0);
}
int main()
{
// HttpOpen
HINTERNET hHttp = NULL;
LPCWSTR lpcwAgent = L"UserAgent";
DWORD dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
LPCWSTR lpcwProxyName = WINHTTP_NO_PROXY_NAME;
LPCWSTR lpcwProxyByPass = WINHTTP_NO_PROXY_BYPASS;
DWORD dwFlag = 0;
// HttpConnect
HINTERNET hConnect = NULL;
LPCWSTR lpcwServerName = L"localhost";
INTERNET_PORT Port = INTERNET_DEFAULT_HTTP_PORT;
DWORD dwReserved = 0; //must be 0
// HttpOpenRequest
HINTERNET hRequest = NULL;
LPCWSTR lpcwVerb = L"GET"; // or POST, PUT
LPCWSTR lpcwObjectName = L"/index.php";
LPCWSTR lpcwVersion = NULL; //NULL == HTTP/1.1
LPCWSTR lpcwReferrer = WINHTTP_NO_REFERER; // It mean there's no referrer
LPCWSTR* plpcwAccept = WINHTTP_DEFAULT_ACCEPT_TYPES; // For more information: Media types (http://www.iana.org/assi gnments/medi a-types)
DWORD dwRequestFlag = 0;
// HttpSendRequest
bool bSendRequest = false;
LPCWSTR lpcwHeaders = WINHTTP_NO_ADDITIONAL_HEADERS; // Additional headers to append to the request
DWORD dwHeaderLength = 0;
LPVOID lpvOptional = WINHTTP_NO_REQUEST_DATA; //The data which is used for POST or PUT
DWORD dwOptionalLength = 0;
DWORD dwTotalLength = 0;
DWORD_PTR pdwContext = NULL;
// HttpReceiveResponse
bool bReceiveResponse = false;
HINTERNET _hRequest = NULL; // Will be set again after HttpOpenRequest are completed
LPVOID lpvReserved = NULL;
hHttp = WinHttpOpen(lpcwAgent, dwAccessType, lpcwProxyName, lpcwProxyByPass, dwFlag);
if ( hHttp == NULL )
{
Mess(L"Unable to open a connection");
}
else
{
hConnect = WinHttpConnect(hHttp, lpcwServerName, Port, dwReserved);
if ( hConnect == NULL )
{
Mess(L"Unable to Connecting");
}
else
{
hRequest = WinHttpOpenRequest(hConnect, lpcwVerb, lpcwObjectName, lpcwVersion, lpcwReferrer, plpcwAccept, dwRequestFlag);
if ( hRequest == NULL )
{
Mess(L"Unable to open the request");
}
else
{
bSendRequest = WinHttpSendRequest(hRequest, lpcwHeaders, dwHeaderLength, lpvOptional, dwOptionalLength, dwTotalLength, pdwContext);
if ( !bSendRequest )
{
Mess(L"Failed to send the request");
}
else
{
bReceiveResponse = WinHttpReceiveResponse(_hRequest, lpvReserved);
if ( !bReceiveResponse )
{
Mess(L"Unable to receive the response");
}
else
{
Mess(L"Ok");
}
}
}
}
}
if ( hRequest != NULL )
WinHttpCloseHandle(hRequest);
if ( hConnect != NULL )
WinHttpCloseHandle(hConnect);
if ( hHttp != NULL )
WinHttpCloseHandle(hHttp);
return 0;
}
I don't understand WINHTTP much but I'm trying.
When I excute the program, I get
Unable to receive the response
then, I use GetLastError() to get the code of the error that always is 6. I can't find anything about code 6?

Error code 6 is ERROR_INVALID_HANDLE "The handle is invalid."
The problem is that you use wrong variable for the request handle: _hRequest whereas you were to use hRequest instead.
WinHttpReceiveResponse(_hRequest, ...

Related

WinHttp websockets listener

I am trying to develop a WebSockets client in C++ using WinHttp. I am making very slow progress (I am .NET developer). I have my WS server developed in .NET 6 and now I am working on a C++ console app that connects to the server and listens for messages.
So far I successfully connect to the server and upgrade the connection to WS but struggle setting up the callback that triggers when a new message was sent from the server. I spent hours finding an example with no success.
Can someone please help me how to set the callback for the below code or provide me with a working example?
static void CALLBACK Callback(HINTERNET handle,
DWORD_PTR context,
DWORD code,
void* info,
DWORD length)
{
switch (code) {
case WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE:
{
int i = 0;
break;
}
case WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED:
{
int i = 0;
break;
}
case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:
{
int i = 0;
break;
}
default:
{
}
}
if (0 != context)
{
}
}
int main()
{
DWORD dwError = ERROR_SUCCESS;
BOOL fStatus = FALSE;
DWORD dwSize = 0;
DWORD dwDownloaded = 0;
LPSTR pszOutBuffer;
BOOL bResults = FALSE;
HINTERNET hSession = NULL, hConnect = NULL, hRequest = NULL, hWebSocket = NULL;
// Use WinHttpOpen to obtain a session handle.
hSession = WinHttpOpen(L"WinHTTP Example/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS,
0);
//WINHTTP_FLAG_ASYNC);
if (hSession == NULL)
{
dwError = GetLastError();
}
// Setup the status callback function.
WINHTTP_STATUS_CALLBACK isCallback = WinHttpSetStatusCallback(hSession,
(WINHTTP_STATUS_CALLBACK)Callback,
WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS,
NULL);
hConnect = WinHttpConnect(hSession, L"localhost", 5004, 0);
if (hConnect == NULL)
{
dwError = GetLastError();
}
// Create an HTTP request handle.
if (hConnect)
hRequest = WinHttpOpenRequest(hConnect,
L"GET",
L"/ws",
NULL,
WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
0);//WINHTTP_FLAG_SECURE); // flags
if (hRequest == NULL)
{
dwError = GetLastError();
}
//
// Request protocol upgrade from http to websocket.
//
#pragma prefast(suppress:6387, "WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET does not take any arguments.")
fStatus = WinHttpSetOption(hRequest,
WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET,
NULL,
0);
if (!fStatus)
{
dwError = GetLastError();
}
// Send a request.
if (hRequest)
fStatus = WinHttpSendRequest(hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS,
0,
WINHTTP_NO_REQUEST_DATA,
0, // request data length
0, // total length
0); // context
if (!fStatus)
{
dwError = GetLastError();
}
fStatus = WinHttpReceiveResponse(hRequest, 0);
if (!fStatus)
{
dwError = GetLastError();
}
//
// Application should check what is the HTTP status code returned by the server and behave accordingly.
// WinHttpWebSocketCompleteUpgrade will fail if the HTTP status code is different than 101.
//
hWebSocket = WinHttpWebSocketCompleteUpgrade(hRequest, NULL);
if (hWebSocket == NULL)
{
dwError = GetLastError();
}
//
// The request handle is not needed anymore. From now on we will use the websocket handle.
//
WinHttpCloseHandle(hRequest);
hRequest = NULL;
std::cout << "Connected to WS!\n";
}

Cant send a WinHTTP request in a DLL, but works in an EXE

Whenever I try to call the WinHttpSendRequest() function, it always returns null.
It is worth mentioning that the function works fine in a normal .exe, but doesn't work in a .dll.
I was trying to find a solution for a long time.
Here is the code:
bool c_lw_http::send_request(std::wstring s_url, std::vector<BYTE>& bt_reply, const PWCHAR psz_type, const LPVOID p_data, const DWORD dw_data_len)
{
bool b_result = false;
if (!m_h_session_) return b_result;
INTERNET_PORT w_srv_port = 0;
std::wstring s_server, s_object;
parse_url_a(s_url, s_server, s_object, w_srv_port);
const HINTERNET h_connect = WinHttpConnect((HINTERNET)m_h_session_, (LPCWSTR)s_server.c_str(), (INTERNET_PORT)w_srv_port, (DWORD)0);
if (!h_connect) return b_result;
LPCWSTR psz_accept_types[2];
psz_accept_types[0] = L"*/*";
psz_accept_types[1] = NULL;
const HINTERNET h_request = WinHttpOpenRequest(h_connect, psz_type,
s_object.c_str(), L"HTTP/1.1", m_psz_referer_, psz_accept_types,
w_srv_port == INTERNET_DEFAULT_HTTPS_PORT ? WINHTTP_FLAG_SECURE : 0);
if (!h_request) {
MessageBoxA(0, "h_request", 0, 0);
}
DWORD dwOptionValue = WINHTTP_DISABLE_REDIRECTS;
WinHttpSetOption(h_request, WINHTTP_OPTION_DISABLE_FEATURE, &dwOptionValue, sizeof(dwOptionValue));
// Custom Header: Content-Type
BOOL b_http_result = WinHttpAddRequestHeaders(h_request,
LWHTTP_CONT_TYPE, -1, WINHTTP_ADDREQ_FLAG_ADD);
if (!b_http_result) {
MessageBoxA(0, "b_http_result", 0, 0);
goto CleanUp;
}
b_http_result = WinHttpSendRequest((HINTERNET)h_request,(LPCWSTR)WINHTTP_NO_ADDITIONAL_HEADERS, (DWORD)0, (LPVOID)p_data, (DWORD)dw_data_len, (DWORD)dw_data_len, (DWORD_PTR)NULL);
if (!b_http_result) {
MessageBoxA(0, "b_http_result2", 0, 0);
goto CleanUp;
}
b_http_result = WinHttpReceiveResponse((HINTERNET)h_request, (LPVOID)NULL);
if (!b_http_result) {
MessageBoxA(0, "b_http_result3", 0, 0);
goto CleanUp;
}
if ((m_dw_last_reply_size_ = read_req_reply(h_request, bt_reply)))
b_result = true;
CleanUp:
if (h_request)
LI_FN(WinHttpCloseHandle).get()((HINTERNET)h_request);
if (h_connect)
LI_FN(WinHttpCloseHandle).get()((HINTERNET)h_connect);
return b_result;
}

How to get the SID and User Name of the user utilising my service in C++

I am attempting to create a service that will essentially act as a local web server. In theory users will use a REST API by visiting URIs through localhost in a browser i.e. http://localhost:2017/path/to/function/call will connect to the service and execute a function.
My question is how do I get the SID and User Name of the account that called the service?
I have implemented a couple of solutions but they return the SID and User Name of the service and not the user using it.
OJSon* UnifiedStreamingService::getUserDetails()
{
OJSon* result = OJSon::create();
if(result)
{
/*
HANDLE hToken = NULL;
ULONG id = WTSGetActiveConsoleSessionId();
BOOL bRet = WTSQueryUserToken(id, &hToken);
if (bRet == false)
{
DWORD error = GetLastError();
printf("ERROR: %d", error);
}
*/
HANDLE hToken = NULL;
if ( ! OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken ) )
{
//_tprintf( _T("OpenProcessToken failed. GetLastError returned: %d\n"), GetLastError());
return NULL;
}
// Get the size of the memory buffer needed for the SID
DWORD dwBufferSize = 0;
if ( ! GetTokenInformation( hToken, TokenUser, NULL, 0, &dwBufferSize ) && ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) )
{
//_tprintf( _T("GetTokenInformation failed. GetLastError returned: %d\n"), GetLastError());
// Cleanup
CloseHandle( hToken );
hToken = NULL;
return NULL;
}
// Allocate buffer for user token data
std::vector<BYTE> buffer;
buffer.resize( dwBufferSize );
PTOKEN_USER pTokenUser = reinterpret_cast<PTOKEN_USER>( &buffer[0] );
// Retrieve the token information in a TOKEN_USER structure
if ( ! GetTokenInformation(
hToken,
TokenUser,
pTokenUser,
dwBufferSize,
&dwBufferSize))
{
//_tprintf( _T("2 GetTokenInformation failed. GetLastError returned: %d\n"), GetLastError());
// Cleanup
CloseHandle( hToken );
hToken = NULL;
return NULL;
}
// Check if SID is valid
if ( ! IsValidSid( pTokenUser->User.Sid ) )
{
//_tprintf( _T("The owner SID is invalid.\n") );
// Cleanup
CloseHandle(hToken);
hToken = NULL;
return NULL;
}
// add the name
OString* name = lookupAccountSid(pTokenUser->User.Sid);
if(name)
{
result->setKey(&OString("name"), name);
SAFEDELETE(name);
}
// add the SID
OString* sid = convertSidToString(pTokenUser->User.Sid);
if(sid)
{
result->setKey(&OString("SID"), sid);
SAFEDELETE(sid);
}
// Cleanup
CloseHandle(hToken);
hToken = NULL;
}
return result;
}
OString* UnifiedStreamingService::convertSidToString(PSID pSID)
{
OString* result = NULL;
if(pSID)
{
// Get string corresponding to SID
LPTSTR pszSID = NULL;
if ( ! ConvertSidToStringSid( pSID, &pszSID ) )
{
return NULL;
}
result = new OString(pszSID);
// Release buffer allocated by ConvertSidToStringSid API
LocalFree( pszSID );
pszSID = NULL;
}
return result;
}
OString* UnifiedStreamingService::lookupAccountSid(PSID pSID)
{
DWORD dwSize = 256;
DWORD dwResult = 0;
SID_NAME_USE SidType;
LPTSTR lpName = new TCHAR[dwSize];
LPWSTR lpDomain = new TCHAR[dwSize];
OString* result = NULL;
if( !LookupAccountSid( NULL, pSID, lpName, &dwSize, lpDomain, &dwSize, &SidType ) )
{
dwResult = GetLastError();
return NULL;
}
OString* pDomain = new OString(lpDomain);
OString* pName = new OString(lpName);
if(pDomain && pName)
{
result = OString::createByFormat(&OString("%s\\%s"), pDomain, pName);
SAFEDELETE(pDomain);
SAFEDELETE(pName);
}
delete[] lpDomain;
delete[] lpName;
return result;
}
The task can be accomplished by using WTSGetActiveConsoleSessionId and WTSQueryUserToken to get user token and then getting SID with GetTokenInformation.
The additional requirement is the service is running under Local System account which grants SE_TCB_NAME privelege (== SeTcbPrivilege). SE_TCB_NAME required by WTSQueryUserToken. Note that the other accounts usually have no SE_TCB_NAME privelege!

How to retrieve information from multiple/dual code signatures on an executable file

I've been using the following code (taken from KB323809 article) to retrieve information about the code signature on the executable file. This works fine for a single digital signature.
But how to retrieve information for multiple code signatures?
In that case the Microsoft code below simply retrives info only for the first signature.
My thought was to call CryptMsgGetParam with CMSG_SIGNER_COUNT_PARAM to get the number of signatures and then pass each signature index to the subsequent call to CryptMsgGetParam with CMSG_SIGNER_INFO_PARAM (in the code below.) But this approach always returns 1 signature, even if I clearly have more, like 3 in this example:
#include <windows.h>
#include <wincrypt.h>
#include <wintrust.h>
#include <stdio.h>
#include <tchar.h>
#pragma comment(lib, "crypt32.lib")
#define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
typedef struct {
LPWSTR lpszProgramName;
LPWSTR lpszPublisherLink;
LPWSTR lpszMoreInfoLink;
} SPROG_PUBLISHERINFO, *PSPROG_PUBLISHERINFO;
BOOL GetProgAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo,
PSPROG_PUBLISHERINFO Info);
BOOL GetDateOfTimeStamp(PCMSG_SIGNER_INFO pSignerInfo, SYSTEMTIME *st);
BOOL PrintCertificateInfo(PCCERT_CONTEXT pCertContext);
BOOL GetTimeStampSignerInfo(PCMSG_SIGNER_INFO pSignerInfo,
PCMSG_SIGNER_INFO *pCounterSignerInfo);
int _tmain(int argc, TCHAR *argv[])
{
WCHAR szFileName[MAX_PATH];
HCERTSTORE hStore = NULL;
HCRYPTMSG hMsg = NULL;
PCCERT_CONTEXT pCertContext = NULL;
BOOL fResult;
DWORD dwEncoding, dwContentType, dwFormatType;
PCMSG_SIGNER_INFO pSignerInfo = NULL;
PCMSG_SIGNER_INFO pCounterSignerInfo = NULL;
DWORD dwSignerInfo;
CERT_INFO CertInfo;
SPROG_PUBLISHERINFO ProgPubInfo;
SYSTEMTIME st;
ZeroMemory(&ProgPubInfo, sizeof(ProgPubInfo));
__try
{
if (argc != 2)
{
_tprintf(_T("Usage: SignedFileInfo <filename>\n"));
return 0;
}
#ifdef UNICODE
lstrcpynW(szFileName, argv[1], MAX_PATH);
#else
if (mbstowcs(szFileName, argv[1], MAX_PATH) == -1)
{
printf("Unable to convert to unicode.\n");
__leave;
}
#endif
// Get message handle and store handle from the signed file.
fResult = CryptQueryObject(CERT_QUERY_OBJECT_FILE,
szFileName,
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
CERT_QUERY_FORMAT_FLAG_BINARY,
0,
&dwEncoding,
&dwContentType,
&dwFormatType,
&hStore,
&hMsg,
NULL);
if (!fResult)
{
_tprintf(_T("CryptQueryObject failed with %x\n"), GetLastError());
__leave;
}
// Get signer information size.
fResult = CryptMsgGetParam(hMsg,
CMSG_SIGNER_INFO_PARAM,
0,
NULL,
&dwSignerInfo);
if (!fResult)
{
_tprintf(_T("CryptMsgGetParam failed with %x\n"), GetLastError());
__leave;
}
// Allocate memory for signer information.
pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSignerInfo);
if (!pSignerInfo)
{
_tprintf(_T("Unable to allocate memory for Signer Info.\n"));
__leave;
}
// Get Signer Information.
fResult = CryptMsgGetParam(hMsg,
CMSG_SIGNER_INFO_PARAM,
0,
(PVOID)pSignerInfo,
&dwSignerInfo);
if (!fResult)
{
_tprintf(_T("CryptMsgGetParam failed with %x\n"), GetLastError());
__leave;
}
// Get program name and publisher information from
// signer info structure.
if (GetProgAndPublisherInfo(pSignerInfo, &ProgPubInfo))
{
if (ProgPubInfo.lpszProgramName != NULL)
{
wprintf(L"Program Name : %s\n",
ProgPubInfo.lpszProgramName);
}
if (ProgPubInfo.lpszPublisherLink != NULL)
{
wprintf(L"Publisher Link : %s\n",
ProgPubInfo.lpszPublisherLink);
}
if (ProgPubInfo.lpszMoreInfoLink != NULL)
{
wprintf(L"MoreInfo Link : %s\n",
ProgPubInfo.lpszMoreInfoLink);
}
}
_tprintf(_T("\n"));
// Search for the signer certificate in the temporary
// certificate store.
CertInfo.Issuer = pSignerInfo->Issuer;
CertInfo.SerialNumber = pSignerInfo->SerialNumber;
pCertContext = CertFindCertificateInStore(hStore,
ENCODING,
0,
CERT_FIND_SUBJECT_CERT,
(PVOID)&CertInfo,
NULL);
if (!pCertContext)
{
_tprintf(_T("CertFindCertificateInStore failed with %x\n"),
GetLastError());
__leave;
}
// Print Signer certificate information.
_tprintf(_T("Signer Certificate:\n\n"));
PrintCertificateInfo(pCertContext);
_tprintf(_T("\n"));
// Get the timestamp certificate signerinfo structure.
if (GetTimeStampSignerInfo(pSignerInfo, &pCounterSignerInfo))
{
// Search for Timestamp certificate in the temporary
// certificate store.
CertInfo.Issuer = pCounterSignerInfo->Issuer;
CertInfo.SerialNumber = pCounterSignerInfo->SerialNumber;
pCertContext = CertFindCertificateInStore(hStore,
ENCODING,
0,
CERT_FIND_SUBJECT_CERT,
(PVOID)&CertInfo,
NULL);
if (!pCertContext)
{
_tprintf(_T("CertFindCertificateInStore failed with %x\n"),
GetLastError());
__leave;
}
// Print timestamp certificate information.
_tprintf(_T("TimeStamp Certificate:\n\n"));
PrintCertificateInfo(pCertContext);
_tprintf(_T("\n"));
// Find Date of timestamp.
if (GetDateOfTimeStamp(pCounterSignerInfo, &st))
{
_tprintf(_T("Date of TimeStamp : %02d/%02d/%04d %02d:%02d\n"),
st.wMonth,
st.wDay,
st.wYear,
st.wHour,
st.wMinute);
}
_tprintf(_T("\n"));
}
}
__finally
{
// Clean up.
if (ProgPubInfo.lpszProgramName != NULL)
LocalFree(ProgPubInfo.lpszProgramName);
if (ProgPubInfo.lpszPublisherLink != NULL)
LocalFree(ProgPubInfo.lpszPublisherLink);
if (ProgPubInfo.lpszMoreInfoLink != NULL)
LocalFree(ProgPubInfo.lpszMoreInfoLink);
if (pSignerInfo != NULL) LocalFree(pSignerInfo);
if (pCounterSignerInfo != NULL) LocalFree(pCounterSignerInfo);
if (pCertContext != NULL) CertFreeCertificateContext(pCertContext);
if (hStore != NULL) CertCloseStore(hStore, 0);
if (hMsg != NULL) CryptMsgClose(hMsg);
}
return 0;
}
BOOL PrintCertificateInfo(PCCERT_CONTEXT pCertContext)
{
BOOL fReturn = FALSE;
LPTSTR szName = NULL;
DWORD dwData;
__try
{
// Print Serial Number.
_tprintf(_T("Serial Number: "));
dwData = pCertContext->pCertInfo->SerialNumber.cbData;
for (DWORD n = 0; n < dwData; n++)
{
_tprintf(_T("%02x "),
pCertContext->pCertInfo->SerialNumber.pbData[dwData - (n + 1)]);
}
_tprintf(_T("\n"));
// Get Issuer name size.
if (!(dwData = CertGetNameString(pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
CERT_NAME_ISSUER_FLAG,
NULL,
NULL,
0)))
{
_tprintf(_T("CertGetNameString failed.\n"));
__leave;
}
// Allocate memory for Issuer name.
szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
if (!szName)
{
_tprintf(_T("Unable to allocate memory for issuer name.\n"));
__leave;
}
// Get Issuer name.
if (!(CertGetNameString(pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
CERT_NAME_ISSUER_FLAG,
NULL,
szName,
dwData)))
{
_tprintf(_T("CertGetNameString failed.\n"));
__leave;
}
// print Issuer name.
_tprintf(_T("Issuer Name: %s\n"), szName);
LocalFree(szName);
szName = NULL;
// Get Subject name size.
if (!(dwData = CertGetNameString(pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
0,
NULL,
NULL,
0)))
{
_tprintf(_T("CertGetNameString failed.\n"));
__leave;
}
// Allocate memory for subject name.
szName = (LPTSTR)LocalAlloc(LPTR, dwData * sizeof(TCHAR));
if (!szName)
{
_tprintf(_T("Unable to allocate memory for subject name.\n"));
__leave;
}
// Get subject name.
if (!(CertGetNameString(pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
0,
NULL,
szName,
dwData)))
{
_tprintf(_T("CertGetNameString failed.\n"));
__leave;
}
// Print Subject Name.
_tprintf(_T("Subject Name: %s\n"), szName);
fReturn = TRUE;
}
__finally
{
if (szName != NULL) LocalFree(szName);
}
return fReturn;
}
LPWSTR AllocateAndCopyWideString(LPCWSTR inputString)
{
LPWSTR outputString = NULL;
outputString = (LPWSTR)LocalAlloc(LPTR,
(wcslen(inputString) + 1) * sizeof(WCHAR));
if (outputString != NULL)
{
lstrcpyW(outputString, inputString);
}
return outputString;
}
BOOL GetProgAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo,
PSPROG_PUBLISHERINFO Info)
{
BOOL fReturn = FALSE;
PSPC_SP_OPUS_INFO OpusInfo = NULL;
DWORD dwData;
BOOL fResult;
__try
{
// Loop through authenticated attributes and find
// SPC_SP_OPUS_INFO_OBJID OID.
for (DWORD n = 0; n < pSignerInfo->AuthAttrs.cAttr; n++)
{
if (lstrcmpA(SPC_SP_OPUS_INFO_OBJID,
pSignerInfo->AuthAttrs.rgAttr[n].pszObjId) == 0)
{
// Get Size of SPC_SP_OPUS_INFO structure.
fResult = CryptDecodeObject(ENCODING,
SPC_SP_OPUS_INFO_OBJID,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
0,
NULL,
&dwData);
if (!fResult)
{
_tprintf(_T("CryptDecodeObject failed with %x\n"),
GetLastError());
__leave;
}
// Allocate memory for SPC_SP_OPUS_INFO structure.
OpusInfo = (PSPC_SP_OPUS_INFO)LocalAlloc(LPTR, dwData);
if (!OpusInfo)
{
_tprintf(_T("Unable to allocate memory for Publisher Info.\n"));
__leave;
}
// Decode and get SPC_SP_OPUS_INFO structure.
fResult = CryptDecodeObject(ENCODING,
SPC_SP_OPUS_INFO_OBJID,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
0,
OpusInfo,
&dwData);
if (!fResult)
{
_tprintf(_T("CryptDecodeObject failed with %x\n"),
GetLastError());
__leave;
}
// Fill in Program Name if present.
if (OpusInfo->pwszProgramName)
{
Info->lpszProgramName =
AllocateAndCopyWideString(OpusInfo->pwszProgramName);
}
else
Info->lpszProgramName = NULL;
// Fill in Publisher Information if present.
if (OpusInfo->pPublisherInfo)
{
switch (OpusInfo->pPublisherInfo->dwLinkChoice)
{
case SPC_URL_LINK_CHOICE:
Info->lpszPublisherLink =
AllocateAndCopyWideString(OpusInfo->pPublisherInfo->pwszUrl);
break;
case SPC_FILE_LINK_CHOICE:
Info->lpszPublisherLink =
AllocateAndCopyWideString(OpusInfo->pPublisherInfo->pwszFile);
break;
default:
Info->lpszPublisherLink = NULL;
break;
}
}
else
{
Info->lpszPublisherLink = NULL;
}
// Fill in More Info if present.
if (OpusInfo->pMoreInfo)
{
switch (OpusInfo->pMoreInfo->dwLinkChoice)
{
case SPC_URL_LINK_CHOICE:
Info->lpszMoreInfoLink =
AllocateAndCopyWideString(OpusInfo->pMoreInfo->pwszUrl);
break;
case SPC_FILE_LINK_CHOICE:
Info->lpszMoreInfoLink =
AllocateAndCopyWideString(OpusInfo->pMoreInfo->pwszFile);
break;
default:
Info->lpszMoreInfoLink = NULL;
break;
}
}
else
{
Info->lpszMoreInfoLink = NULL;
}
fReturn = TRUE;
break; // Break from for loop.
} // lstrcmp SPC_SP_OPUS_INFO_OBJID
} // for
}
__finally
{
if (OpusInfo != NULL) LocalFree(OpusInfo);
}
return fReturn;
}
BOOL GetDateOfTimeStamp(PCMSG_SIGNER_INFO pSignerInfo, SYSTEMTIME *st)
{
BOOL fResult;
FILETIME lft, ft;
DWORD dwData;
BOOL fReturn = FALSE;
// Loop through authenticated attributes and find
// szOID_RSA_signingTime OID.
for (DWORD n = 0; n < pSignerInfo->AuthAttrs.cAttr; n++)
{
if (lstrcmpA(szOID_RSA_signingTime,
pSignerInfo->AuthAttrs.rgAttr[n].pszObjId) == 0)
{
// Decode and get FILETIME structure.
dwData = sizeof(ft);
fResult = CryptDecodeObject(ENCODING,
szOID_RSA_signingTime,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
0,
(PVOID)&ft,
&dwData);
if (!fResult)
{
_tprintf(_T("CryptDecodeObject failed with %x\n"),
GetLastError());
break;
}
// Convert to local time.
FileTimeToLocalFileTime(&ft, &lft);
FileTimeToSystemTime(&lft, st);
fReturn = TRUE;
break; // Break from for loop.
} //lstrcmp szOID_RSA_signingTime
} // for
return fReturn;
}
BOOL GetTimeStampSignerInfo(PCMSG_SIGNER_INFO pSignerInfo, PCMSG_SIGNER_INFO *pCounterSignerInfo)
{
PCCERT_CONTEXT pCertContext = NULL;
BOOL fReturn = FALSE;
BOOL fResult;
DWORD dwSize;
__try
{
*pCounterSignerInfo = NULL;
// Loop through unathenticated attributes for
// szOID_RSA_counterSign OID.
for (DWORD n = 0; n < pSignerInfo->UnauthAttrs.cAttr; n++)
{
if (lstrcmpA(pSignerInfo->UnauthAttrs.rgAttr[n].pszObjId,
szOID_RSA_counterSign) == 0)
{
// Get size of CMSG_SIGNER_INFO structure.
fResult = CryptDecodeObject(ENCODING,
PKCS7_SIGNER_INFO,
pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData,
0,
NULL,
&dwSize);
if (!fResult)
{
_tprintf(_T("CryptDecodeObject failed with %x\n"),
GetLastError());
__leave;
}
// Allocate memory for CMSG_SIGNER_INFO.
*pCounterSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc(LPTR, dwSize);
if (!*pCounterSignerInfo)
{
_tprintf(_T("Unable to allocate memory for timestamp info.\n"));
__leave;
}
// Decode and get CMSG_SIGNER_INFO structure
// for timestamp certificate.
fResult = CryptDecodeObject(ENCODING,
PKCS7_SIGNER_INFO,
pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->UnauthAttrs.rgAttr[n].rgValue[0].cbData,
0,
(PVOID)*pCounterSignerInfo,
&dwSize);
if (!fResult)
{
_tprintf(_T("CryptDecodeObject failed with %x\n"),
GetLastError());
__leave;
}
fReturn = TRUE;
break; // Break from for loop.
}
}
}
__finally
{
// Clean up.
if (pCertContext != NULL) CertFreeCertificateContext(pCertContext);
}
return fReturn;
}
In addition to the answer of Daniel Sie.
Found an attribute (szOID_NESTED_SIGNATURE) that would contain the CMSG_SIGNER_INFO that need to be decoded with following steps (this is Delphi code but sense is clear):
LNestedMsg := CryptMsgOpenToDecode(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, 0, 0, 0, nil, 0);
CryptMsgUpdate(LNestedMsg, LFindedAttr.rgValue.pbData, LFindedAttr.rgValue.cbData, True);
CryptMsgGetParam(LNestedMsg, CMSG_SIGNER_INFO_PARAM, 0, nil, #LSize);
CryptMsgGetParam(LNestedMsg, CMSG_SIGNER_INFO_PARAM, 0, LNestedSignerInfo, #LSize);
The acquired CMSG_SIGNER_INFO (LNestedSignerInfo) is the nested signature (in our case SHA2 signature).
To obtain the time-stamp information (RFC3161) of that signature - search the Unauthenticated attribute with pszObjId = szOID_RFC3161_counterSign (1.3.6.1.4.1.311.3.3.1).
Found attribute would contain the CMSG_SIGNER_INFO of the time-stamp counter signature, that also need to be decoded by previously described steps (CryptMsgOpenToDecode, CryptMsgUpdate, CryptMsgGetParam).
The CERT_CONTEXT of nested signature or timestamp counter signature is need to be searched in store with is obtained from corresponding HCRYPTMSG (result of CryptMsgOpenToDecode).
LNestedStore := CertOpenStore(CERT_STORE_PROV_MSG, PKCS_7_ASN_ENCODING or X509_ASN_ENCODING, 0, 0, LNestedMsg);
LTimeStampStore := CertOpenStore(CERT_STORE_PROV_MSG, PKCS_7_ASN_ENCODING or X509_ASN_ENCODING, 0, 0, LTimeStampMsg);
Example to decode szOID_RFC3161_counterSign attribute:
LNestedSignerAttr := LNestedSigner.UnauthAttrs.rgAttr;
for I := 0 to LNestedSigner.UnauthAttrs.cAttr - 1 do
begin
if SameText(string(LNestedSignerAttr.pszObjId), szOID_RFC3161_counterSign) then
begin
LNestedTimeStampMsg := CryptMsgOpenToDecode(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, 0, 0, 0, nil, nil);
if not Assigned(LNestedTimeStampMsg) then
RaiseLastOSError;
try
if not CryptMsgUpdate(LNestedTimeStampMsg, LNestedSignerAttr.rgValue.pbData, LNestedSignerAttr.rgValue.cbData, True) then
RaiseLastOSError;
if not CryptMsgGetParam(LNestedTimeStampMsg, CMSG_SIGNER_INFO_PARAM, 0, nil, #LSize) then
RaiseLastOSError;
GetMem(LTimeStampSigner, LSize);
try
if not CryptMsgGetParam(LNestedTimeStampMsg, CMSG_SIGNER_INFO_PARAM, 0, LTimeStampSigner, #LSize) then
RaiseLastOSError;
LAttr := LTimeStampSigner.AuthAttrs.rgAttr;
for J := 0 to LTimeStampSigner.AuthAttrs.cAttr - 1 do
begin
if SameText(string(LAttr.pszObjId), szOID_RSA_signingTime) then
begin
LSize := SizeOf(LFileTime);
if not CryptDecodeObject(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING,
szOID_RSA_signingTime, LAttr.rgValue.pbData, LAttr.rgValue.cbData, 0, #LFileTime, #LSize) then
RaiseLastOSError;
if FileTimeToLocalFileTime(#LFileTime, LLocalFileTime)
and FileTimeToSystemTime(#LLocalFileTime, LSystemTime) then
SHA2TimeStamp := SystemTimeToDateTime(LSystemTime)
else
SHA2TimeStamp := 0;
end;
Inc(LAttr);
end;
finally
FreeMem(LTimeStampSigner);
end;
finally
if not CryptMsgClose(LNestedTimeStampMsg) then
RaiseLastOSError;
end;
end;
Inc(LNestedSignerAttr);
end;
Authenticode stores secondary signatures in the UnauthenticatedAttributes of primary signer (index 0), instead of additional PKCS 7 signer.
From the primary signature, search the UnauthenticatedAttribue for below:
//Indicates the attribute is an octet encoded PKCS7
define szOID_NESTED_SIGNATURE "1.3.6.1.4.1.311.2.4.1"
The encoded object of this attribute is a full PKCS 7 signer.
Thanks.

HInternet works only one time

This code is in a C++ DLL injected in a game. (This is on a private server so it is legal). The code has to be executed multiple times. However, it works only the first time. It could be on the WCF end but I managed to send 2 and 5 successful requests from a .net dll loaded from the c++ dll before.
Since I didn't figure out why it was blocked after 2 and 5 requests, I decided to go all native but now I'm blocked after one request. I have a feeling it now has to do with the way I'm parsing the response.
The first execution gets a 200 code status and the second one gets a 0.
edit : my fire wall is turned off.
HINTERNET hInternet = InternetOpen(_T("MyApp"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
HINTERNET hConnect = InternetConnect(hInternet, _T("localhost"), INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
LPCSTR rgpszAcceptTypes[] = { _T("application/json"), NULL };
HINTERNET hRequest = HttpOpenRequest(hConnect, _T("POST"), _T("/xxxBackend/service1.svc/SaveDataVoid"), NULL, NULL, rgpszAcceptTypes, 0, 0);
HttpAddRequestHeaders(hRequest, _T("Content-Type: application/json\r\n"), -1, HTTP_ADDREQ_FLAG_ADD);
char *JsonData = "{\"data\":{\"AccountName\":\"\",\"CharName\":\"SilverDeth-IV\",\"GameDiff\":\"1\",\"CompressedData\":[8228138568842941382,8247906688399250381,8244242016143283142]}}";
HttpSendRequest(hRequest, NULL, 0, JsonData, strlen(JsonData));
DWORD StatusCode = 0;
DWORD StatusCodeLen = sizeof(StatusCode);
HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &StatusCode, &StatusCodeLen, NULL);
if (StatusCode == 200)
{
char *lpBuffer[2000];
DWORD lpdwNumberOfBytesRead = 0;
InternetQueryDataAvailable(hRequest, &StatusCodeLen, 0, 0);
bool bRetval = InternetReadFile(hRequest, lpBuffer, 2000, &lpdwNumberOfBytesRead);
}
InternetCloseHandle(hRequest);
InternetCloseHandle(hConnect);
InternetCloseHandle(hInternet);
The code you have shown is not doing ANY error handling at all. Add that in, and then see where the failure is really occurring. The fact that StatusCode is 0 means HttpQueryInfo() is failing, which could happen if you did not obtain a valid hRequest to begin with.
BTW, rgpszAcceptTypes needs to be declared as LPCTSTR instead of LPCSTR, and you should be using the TEXT() macro instead of the _T() macro. TEXT() belongs to the Win32 API, but _T() belongs to the C runtime library, which you are not using in this code.
Try this:
void InetError(LPCTSTR msg)
{
DWORD dwErr = GetLastError();
if (dwErr == ERROR_INTERNET_EXTENDED_ERROR)
{
DWORD dwInetErr = 0;
LPTSTR szResp = NULL;
DWORD dwLength = 0;
InternetGetLastResponseInfo(&dwInetErr, NULL, &dwLength);
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
szResp = new TCHAR[dwLength+1];
InternetGetLastResponseInfo(&dwInetErr, szResp, &dwLength);
}
// use msg, szResp, and dwInetErr as needed...
delete[] szResp;
}
else
{
// use msg and dwErr as needed...
}
}
...
HINTERNET hInternet = NULL;
HINTERNET hConnect = NULL;
HINTERNET hRequest = NULL;
hInternet = InternetOpen(TEXT("MyApp"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (!hInternet)
{
InetError(TEXT("InternetOpen failed"));
goto done;
}
hConnect = InternetConnect(hInternet, TEXT("localhost"), INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
if (!hConnect)
{
InetError(TEXT("InternetConnect failed"));
goto done;
}
LPCTSTR rgpszAcceptTypes[] = { TEXT("application/json"), NULL };
hRequest = HttpOpenRequest(hConnect, TEXT("POST"), TEXT("/xxxBackend/service1.svc/SaveDataVoid"), NULL, NULL, rgpszAcceptTypes, 0, 0);
if (!hRequest)
{
InetError(TEXT("HttpOpenRequest failed"));
goto done;
}
if (!HttpAddRequestHeaders(hRequest, TEXT("Content-Type: application/json\r\n"), -1, HTTP_ADDREQ_FLAG_ADD))
{
InetError(TEXT("HttpAddRequestHeaders failed"));
goto done;
}
char *JsonData = "{\"data\":{\"AccountName\":\"\",\"CharName\":\"SilverDeth-IV\",\"GameDiff\":\"1\",\"CompressedData\":[8228138568842941382,8247906688399250381,8244242016143283142]}}";
if (!HttpSendRequest(hRequest, NULL, 0, JsonData, strlen(JsonData)))
{
InetError(TEXT("HttpSendRequest failed"));
goto done;
}
DWORD StatusCode = 0;
DWORD StatusCodeLen = sizeof(StatusCode);
if (!HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &StatusCode, &StatusCodeLen, NULL))
{
InetError(TEXT("HttpQueryInfo failed"));
goto done;
}
if (StatusCode == 200)
{
BYTE Buffer[2000];
DWORD dwNumberOfBytes = 0;
DWORD dwNumberOfBytesRead = 0;
if (!InternetQueryDataAvailable(hRequest, &dwNumberOfBytes, 0, 0))
{
InetError(TEXT("InternetQueryDataAvailable failed"));
goto done;
}
if (!InternetReadFile(hRequest, Buffer, min(dwNumberOfBytes, sizeof(Buffer)), &dwNumberOfBytesRead))
{
InetError(TEXT("InternetReadFile failed"));
goto done;
}
//...
}
done:
if (hRequest) InternetCloseHandle(hRequest);
if (hConnect) InternetCloseHandle(hConnect);
if (hInternet) InternetCloseHandle(hInternet);