DirSync Page Size option - c

In my app i need to do a DirSync with the active directory. However, in my search preferences when i try to give the search preference parameter for page size, it shoots me an error (0x80005008, ADS_BAD_PARAMETER). If i dont give that, it works fine. I am giving the code snippet below:
HRESULT DoDirSyncSearch(
LPWSTR pszSearchFilter, // Search filter.
LPWSTR *pAttributeNames, // Attributes to retrieve.
DWORD dwAttributes, // Number of attributes.
PUCHAR *ppCookie, // Pointer to previous cookie.
PULONG pulCookieLength, // Length of previous cookie.
LPWSTR szDC) // Name of DC to bind to.
{
IADs *pRootDSE = NULL;
IDirectorySearch *pSearch = NULL;
ADS_SEARCH_HANDLE hSearch = NULL;
ADS_SEARCHPREF_INFO arSearchPrefs[4];
ADS_PROV_SPECIFIC dirsync;
ADS_SEARCH_COLUMN col;
HRESULT hr = S_OK;
VARIANT var;
BOOL bUpdate = FALSE;
DWORD dwCount = 0;
BOOL noMoreData = false;
DWORD dwError = ERROR_SUCCESS;
WCHAR szError[512];
WCHAR szProvider[512];
// Validate input parameters.
if (!pulCookieLength || !ppCookie || !szDC)
{
wprintf(L"Invalid parameter.\n");
return E_FAIL;
}
LPOLESTR szDSPath = new OLECHAR[MAX_PATH];
LPOLESTR szServerPath = new OLECHAR[MAX_PATH];
VariantInit(&var);
// If cookie is non-NULL, this is an update. Otherwise, it is a full-read.
if (*ppCookie)
bUpdate = TRUE;
CoInitialize(NULL);
// If there is a DC name from the previous USN sync,
// include it in the binding string.
if (szDC[0])
{
wcsncpy_s(szServerPath,MAX_PATH,L"LDAP://",MAX_PATH);
wcsncat_s(szServerPath, MAX_PATH,szDC,MAX_PATH-wcslen(szServerPath));
wcsncat_s(szServerPath, MAX_PATH,L"/",MAX_PATH-wcslen(szServerPath));
}
else
wcsncpy_s(szServerPath, MAX_PATH,L"LDAP://",MAX_PATH);
// Bind to root DSE.
wcsncpy_s(szDSPath,MAX_PATH,szServerPath,MAX_PATH);
wcsncat_s(szDSPath, MAX_PATH,L"rootDSE",MAX_PATH-wcslen(szDSPath));
wprintf(L"RootDSE binding string: %s\n", szDSPath);
hr = ADsGetObject(szDSPath,
IID_IADs,
(void**)&pRootDSE);
if (FAILED(hr))
{
wprintf(L"failed to bind to rootDSE: 0x%x\n", hr);
goto cleanup;
}
// Save the name of the DC connected to in order to connect to
// the same DC on the next dirsync operation.
if (! szDC[0])
{
hr = pRootDSE->Get(CComBSTR("DnsHostName"), &var);
wcsncpy_s(szServerPath,MAX_PATH,L"LDAP://",MAX_PATH);
wcsncat_s(szServerPath, MAX_PATH,var.bstrVal, MAX_PATH-wcslen(szServerPath));
wcsncat_s(szServerPath, MAX_PATH,L"/", MAX_PATH-wcslen(szServerPath));
}
// Get an IDirectorySearch pointer to the root of the domain partition.
hr = pRootDSE->Get(CComBSTR("defaultNamingContext"), &var);
wcsncpy_s(szDSPath,MAX_PATH,szServerPath,MAX_PATH);
wcsncat_s(szDSPath, MAX_PATH,var.bstrVal, MAX_PATH - wcslen(szDSPath));
hr = ADsGetObject(szDSPath, IID_IDirectorySearch, (void**) &pSearch);
if (FAILED(hr))
{
wprintf(L"failed to get IDirectorySearch: 0x%x\n", hr);
goto cleanup;
}
while(noMoreData == false) {
// Initialize the structure to pass in the cookie.
// On the first call, the cookie is NULL and the length is zero.
// On later calls, the cookie and length are the values returned by
// the previous call.
dirsync.dwLength = *pulCookieLength;
dirsync.lpValue = *ppCookie;
arSearchPrefs[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
arSearchPrefs[0].vValue.dwType = ADSTYPE_INTEGER;
arSearchPrefs[0].vValue.Integer = ADS_SCOPE_SUBTREE;
arSearchPrefs[1].dwSearchPref = ADS_SEARCHPREF_DIRSYNC;
arSearchPrefs[1].vValue.dwType = ADSTYPE_PROV_SPECIFIC;
arSearchPrefs[1].vValue.ProviderSpecific = dirsync;
arSearchPrefs[2].dwSearchPref = ADS_SEARCHPREF_PAGESIZE;
arSearchPrefs[2].vValue.dwType = ADSTYPE_INTEGER;
arSearchPrefs[2].vValue.Integer = 100;
hr = pSearch->SetSearchPreference(arSearchPrefs, 3); // this is where error is happening
if (FAILED(hr))
{
wprintf(L"failed to set search prefs: 0x%x\n", hr);
goto cleanup;
}
// Search for the objects indicated by the search filter.
hr = pSearch->ExecuteSearch(pszSearchFilter,
pAttributeNames, dwAttributes, &hSearch );
if (FAILED(hr))
{
wprintf(L"failed to set execute search: 0x%x\n", hr);
goto cleanup;
}
// Loop through the rows of the search result
// Each row is an object that has changed since the previous call.
hr = pSearch->GetNextRow(hSearch);
while ( SUCCEEDED(hr) && hr != S_ADS_NOMORE_ROWS )
{
hr = pSearch->GetColumn( hSearch, L"distinguishedName", &col );
if ( SUCCEEDED(hr) )
{
wprintf(L"Distinguished Name: %s\n",col.pADsValues->CaseIgnoreString);
pSearch->FreeColumn( &col );
}
dwCount++;
hr = pSearch->GetNextRow( hSearch);
}
ADsGetLastError(&dwError, szError, 512, szProvider, 512);
if(ERROR_MORE_DATA == dwError)
{
noMoreData = false;
wprintf(L"Trying to get cookie...\n");
wprintf(L"Page ends here...\n");
hr = pSearch->GetColumn( hSearch, ADS_DIRSYNC_COOKIE, &col );
if ( SUCCEEDED(hr) ) {
if (col.dwADsType == ADSTYPE_PROV_SPECIFIC && col.pADsValues)
{
wprintf(L"Got cookie\n");
*pulCookieLength = col.pADsValues->ProviderSpecific.dwLength;
*ppCookie = (PUCHAR) AllocADsMem (*pulCookieLength);
memcpy(*ppCookie, col.pADsValues->ProviderSpecific.lpValue,
*pulCookieLength);
}
pSearch->FreeColumn( &col );
} else {
wprintf(L"no cookie: 0x%x\n", hr);
wprintf(L"Error!! More data available but could not continue because of error in cookie retrieval...\n");
noMoreData = true;
}
}
else
noMoreData = true;
}
wprintf(L"dwCount: %d\n", dwCount);
// After looping through the results, get the cookie.
if (hr == S_ADS_NOMORE_ROWS )
{
if (ppCookie != NULL)
{
// Free the existing heap allocation
GlobalFree (*ppCookie);
}
wprintf(L"Trying to get cookie...\n");
hr = pSearch->GetColumn( hSearch, ADS_DIRSYNC_COOKIE, &col );
if ( SUCCEEDED(hr) ) {
if (col.dwADsType == ADSTYPE_PROV_SPECIFIC && col.pADsValues)
{
wprintf(L"Got cookie\n");
*pulCookieLength = col.pADsValues->ProviderSpecific.dwLength;
*ppCookie = (PUCHAR) AllocADsMem (*pulCookieLength);
memcpy(*ppCookie, col.pADsValues->ProviderSpecific.lpValue,
*pulCookieLength);
}
pSearch->FreeColumn( &col );
} else
wprintf(L"no cookie: 0x%x\n", hr);
}
cleanup:
if (pRootDSE)
pRootDSE->Release();
if (hSearch)
pSearch->CloseSearchHandle(hSearch);
if (pSearch)
pSearch->Release();
VariantClear(&var);
CoUninitialize();
delete [] szServerPath;
delete [] szDSPath;
return hr;
}
if i give only 2 first preferences, i.e. Scope and DIRSYNC, then the line
hr = pSearch->SetSearchPreference(arSearchPrefs, 2);
does not give any error.
Can anyone please help me why it is happening. I have checked the way the option for paging is to be specified from msdn : http://msdn.microsoft.com/en-us/library/windows/desktop/aa746414(v=vs.85).aspx
Thanks in advance!

From MSDN link:
ADS_SEARCHPREF_DIRSYNC
Specifies a directory synchronization (DirSync)
search, which returns all changes since a specified state. In the
ADSVALUE structure, set the dwType member to ADS_PROV_SPECIFIC. The
ProviderSpecific member is an ADS_PROV_SPECIFIC structure whose
lpValue member specifies a cookie that indicates the state from which
changes are retrieved. The first time you use the DirSync control, set
the dwLength and lpValue members of the ADS_PROV_SPECIFIC structure to
zero and NULL respectively. After reading the results set returned by
the search until IDirectorySearch::GetNextRow returns
S_ADS_NOMORE_ROWS, call IDirectorySearch::GetColumn to retrieve the
ADS_DIRSYNC_COOKIE attribute which contains a cookie to use in the
next DirSync search. For more information, see Polling for Changes
Using the DirSync Control and LDAP_SERVER_DIRSYNC_OID. This flag
cannot be combined with ADS_SEARCHPREF_PAGESIZE. The caller must have
the SE_SYNC_AGENT_NAME privilege.

Related

Failed to send Http request based on MFC

I'm new to HTTP and MFC. I suppose to upload a binary file to a given URL, by sending PUT request. I'm sure the requesting URL and the header are well formed and the file works well, because I tried them by Postman then get a SUCCESS returned.
But when I try to do this by the following MFC code, it always returns a 403 error. Please help me.
bool UploadFile(LPCTSTR strUrl, LPCTSTR filenameFullpath, CString header)
{
BOOL bResult = FALSE;
DWORD dwType = 0;
CString strServer;
CString strObject;
INTERNET_PORT wPort = 0;
DWORD dwFileLength = 0;
BYTE * pFileBuff = NULL;
CHttpConnection * pHC = NULL;
CHttpFile * pHF = NULL;
CInternetSession cis;
bResult = AfxParseURL(strUrl, dwType, strServer, strObject, wPort);
if (!bResult)
return FALSE;
CFile file;
try
{
// Read the file
if (!file.Open(filenameFullpath, CFile::shareDenyNone | CFile::modeRead))
return FALSE;
dwFileLength = file.GetLength();
if (dwFileLength <= 0)
return FALSE;
pFileBuff = new BYTE[dwFileLength];
memset(pFileBuff, 0, sizeof(BYTE) * dwFileLength);
file.Read(pFileBuff, dwFileLength);
// Set up internet connection
const int nTimeOut = 5000;
cis.SetOption(INTERNET_OPTION_CONNECT_TIMEOUT, nTimeOut);
cis.SetOption(INTERNET_OPTION_CONNECT_RETRIES, 2); // Retry once if failed
pHC = cis.GetHttpConnection(strServer, dwType == AFX_INET_SERVICE_HTTP ? NORMAL_CONNECT : SECURE_CONNECT, wPort); // Get a HTTP connection
pHF = pHC->OpenRequest(CHttpConnection::HTTP_VERB_PUT, strObject);//strObject
pHF->AddRequestHeaders(header , HTTP_ADDREQ_FLAG_ADD_IF_NEW);
// I set the header separately instead of passing it as the first parameter of the next call.
// If I don't do so, another error occurs
if (!pHF->SendRequest(NULL, 0, pFileBuff, dwFileLength))
{
delete[]pFileBuff;
pFileBuff = NULL;
pHF->Close();
pHC->Close();
cis.Close();
return FALSE;
}
DWORD dwStateCode = 0;
pHF->QueryInfoStatusCode(dwStateCode);
if (dwStateCode == HTTP_STATUS_OK)
bResult = TRUE;
}
catch (CInternetException * pEx)
{
char sz[256] = "";
pEx->GetErrorMessage(sz, 25);
CString str;
str.Format("InternetException occur!\r\n%s", sz);
AfxMessageBox(str);
}
delete[]pFileBuff;
pFileBuff = NULL;
file.Close();
pHF->Close();
pHC->Close();
cis.Close();
return bResult;
}
And the calling of this function is just something like this:
CHttpClient hc;
hc.UploadFile(csUrl, "E:\\blah blah blah\\blah.tma", csUploadHeader);
while csUrl and csUploadHeader are well formed CString;
I got it! I should give pHF the header items (the key-value pairs) one by one, by calling the AddRequestHeaders() method several times, instead of wrapping and passing them together to pHF.
Then the following codes works very well:
CString sHeader1, sHeader2, sHeader3;
sHeader1.Format(_T("%s : %s"), sKey1, sValue1); // sKey_, sValue_ are strings
sHeader2.Format(_T("%s : %s"), sKey2, sValue2);
sHeader3.Format(_T("%s : %s"), sKey3, sValue3);
pHF->AddRequestHeaders(sHeader1, HTTP_ADDREQ_FLAG_ADD_IF_NEW); // Keep the second paeramter as these
pHF->AddRequestHeaders(sHeader2, HTTP_ADDREQ_FLAG_COALESCE);
pHF->AddRequestHeaders(sHeader3, HTTP_ADDREQ_FLAG_COALESCE);
And a very important notification: the string we pass to AddRequestHeaders() should not have the quotation("") around either the key or the value. In other words, string like "MyKey":"MyValue" have to be modified as MyKey:MyValue before giving to AddRequestHeaders();

Simulating a broken sqlite3 server in c

I have made an sqlite3 database that saves entries that sensors create. I am checking on leaks with valgrind, now I was wondering how to 'simulate' a broken SQL server. I am using this function:
rc = sqlite3_prepare_v2(conn, sql, -1, &res, 0);
This function works correctly, is there a way to simulate it failing? Setting rc to another value manually is an option, but doesn't make sense since a database does get created while the program thinks it doesn't.
I will add the code bellow, although I don't think this is necessary for this question.
This is the insert function that inserts a sensor into the database. This is where I want to test what happens when the prepare function fails.
void *insert_sensor(void *argument) {
storagemgr_insert_argument_t *storagemgr_insert_argument = (storagemgr_insert_argument_t *) argument;
DBCONN *conn = storagemgr_insert_argument->db_connection;
sqlite3_stmt *res = NULL;
uint16_t sensor_id_read;
double temperature_value_read;
time_t timestamp_read;
sensor_data_t data;
int buffer_working_check;
data.id = 0;
data.value = 0;
data.ts = 0;
buffer_working_check = 1;
while (connmgr_loopt_bool == 1 || buffer_working_check == 0) { //connmgr aan -> moet blijven lopen, connmgr uit maar nog data beschikbaar -> moet blijven lopen
pthread_mutex_lock(&lock);
// printf("gelockt in storagemgr\n");
buffer_working_check = sbuffer_read(shared_buffer, &data, 0, 1);
pthread_mutex_unlock(&lock);
int failed_tries = 0;
if (data.id != 0 && buffer_working_check != -1 && buffer_working_check != 1) {
res = NULL;
sensor_id_read = data.id;
temperature_value_read = data.value;
timestamp_read = data.ts;
while(failed_tries<3) {
char *sql = "INSERT INTO "TO_STRING(TABLE_NAME)" (sensor_id, sensor_value, timestamp) VALUES (#sensor_id, #sensor_value, #timestamp)";
rc = sqlite3_prepare_v2(conn, sql, -1, &res, 0);
if (rc == SQLITE_OK) {
int idx1 = sqlite3_bind_parameter_index(res, "#sensor_id");
sqlite3_bind_int(res, idx1, sensor_id_read);
int idx2 = sqlite3_bind_parameter_index(res, "#sensor_value");
sqlite3_bind_double(res, idx2, temperature_value_read);
int idx = sqlite3_bind_parameter_index(res, "#timestamp");
sqlite3_bind_int(res, idx, timestamp_read);
break;
}
else {
write_to_fifo("Insert to the SQL server failed, trying again. ", 4);
failed_tries++;
// char *err_msg = 0;
//
// fprintf(stderr, "Failed to execute statement: %s\n", sqlite3_errmsg(conn));
// sqlite3_free(err_msg);
// sqlite3_close(conn);
// return NULL;
}
sleep(2);
}
}
if (0<failed_tries && failed_tries <= 2) { //het mag =2, want als het =2 en de db faalt dan wordt het eerst geincrementeert naar 3
write_to_fifo("Connection to SQL server re-established. ", 5);
}
if(failed_tries>2) {
db_connection_failed_bool = 1;
sqlite3_close(conn);
write_to_fifo("Connection to SQL server lost. ", 6);
break;
}
if (res != NULL) {
sqlite3_step(res);
sqlite3_finalize(res);
res = NULL;
}
}
return NULL;
}
If you want to keep the code pure, you could always pass the insert function an invalid file path or invalid file name. If you are trying to test the recovery loop, and still want it to remain pure, you can pass the invalid file path and have the recovery loop try to build the path. SQLite won’t build a database in a folder that doesn’t exist when using sqlite3_prepare_v2.

Sign a string using PFX/P12 certificate in Windows using C

I currently have a project that already sign the string that I need in C#, using the PFX certificate, but, now, I'm having to convert parts of that project to C to make it compatible with other projects...
I found this article in MSDN https://learn.microsoft.com/en-us/windows/win32/seccrypto/example-c-program-signing-a-message-and-verifying-a-message-signature which shows how to encrypt and sign the string by loading the certificate from windows store....
But the result of this example is not as expected, because in my case I just need to sign the string and not encrypt and sign, I checked if there was any function to sign only, but I didn't find...
Another point, how do I load a .PFX / .P12 file, and use it with windows functions, instead of having to install the certificate on the computer ...
My method for signing the string in C# is this:
public byte[] SignString(string mensagem)
{
var certificado = SearchCertificate();
CmsSigner signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber, certificado);
signer.DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1"); //SHA256
ContentInfo content = new ContentInfo(new Oid(Configuration.ContentOid), new System.Text.UTF8Encoding().GetBytes(mensagem));
SignedCms signedCms = new SignedCms(content, false);
signedCms.ComputeSignature(signer, false);
var signedStringBytes = signedCms.Encode();
return signedStringBytes;
}
The Encode function of the SignedCms class uses the wincrypt.h library internally and calls the methods CryptMsgOpenToEncode, CryptMsgUpdate and CryptMsgGetParam.
The Microsoft documentation also contains a full example
#pragma comment(lib, "crypt32.lib")
#include <stdio.h>
#include <windows.h>
#include <Wincrypt.h>
#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
void MyHandleError(char *s);
void main(void)
{
//-------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Declare and initialize variables.
BYTE* pbContent = (BYTE*) "Security is our only business.";
// a byte pointer
DWORD cbContent = strlen((char *) pbContent)+1;
// the size of the message
HCERTSTORE hStoreHandle;
HCRYPTPROV hCryptProv;
PCCERT_CONTEXT pSignerCert; // signer's certificate
PCCERT_CONTEXT pRecipCert; // receiver's certificate
LPWSTR pswzRecipientName = L"Hortense";
LPWSTR pswzCertSubject = L"Full Test Cert";
PCERT_INFO RecipCertArray[1];
DWORD ContentEncryptAlgSize;
CRYPT_ALGORITHM_IDENTIFIER ContentEncryptAlgorithm;
CMSG_ENVELOPED_ENCODE_INFO EnvelopedEncodeInfo;
DWORD cbEncodedBlob;
BYTE *pbEncodedBlob;
DWORD cbSignedBlob;
BYTE *pbSignedBlob;
HCRYPTMSG hMsg;
DWORD HashAlgSize;
CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
CMSG_SIGNER_ENCODE_INFO SignerEncodeInfo;
CERT_BLOB SignerCertBlob;
CERT_BLOB SignerCertBlobArray[1];
CMSG_SIGNER_ENCODE_INFO SignerEncodeInfoArray[1];
CMSG_SIGNED_ENCODE_INFO SignedMsgEncodeInfo;
//-------------------------------------------------------------------
// Begin processing. Display the original message.
printf("The original message => %s\n",pbContent);
//-------------------------------------------------------------------
// Acquire a cryptographic provider.
if(CryptAcquireContext(
&hCryptProv, // address for handle to be returned
NULL, // use the current user's logon name
NULL, // use the default provider
PROV_RSA_FULL, // provider type
0)) // zero allows access to private keys
{
printf("Context CSP acquired. \n");
}
else
{
if ( GetLastError() == NTE_BAD_KEYSET)
{
printf("A Usable private key was not found \n");
printf("in the default key container. Either a \n");
printf("private key must be generated in that container \n");
printf("or CryptAquireCertificatePrivateKey can be used \n");
printf("to gain access to the needed private key.");
}
MyHandleError("CryptAcquireContext failed.");
}
//-------------------------------------------------------------------
// Open the My system certificate store.
if(hStoreHandle = CertOpenStore(
CERT_STORE_PROV_SYSTEM,
0,
NULL,
CERT_SYSTEM_STORE_CURRENT_USER,
L"MY"))
{
printf("The MY system store is open. \n");
}
else
{
MyHandleError( "Error getting store handle.");
}
//-------------------------------------------------------------------
// Get the signer's certificate. This certificate must be in the
// My store, and its private key must be available.
if(pSignerCert = CertFindCertificateInStore(
hStoreHandle,
MY_ENCODING_TYPE,
0,
CERT_FIND_SUBJECT_STR,
pswzCertSubject,
NULL))
{
printf("Found certificate for %S.\n",pswzCertSubject);
}
else
{
MyHandleError("Signer certificate not found.");
}
//-------------------------------------------------------------------
// Initialize the algorithm identifier structure.
HashAlgSize = sizeof(HashAlgorithm);
memset(&HashAlgorithm, 0, HashAlgSize); // initialize to zero
HashAlgorithm.pszObjId = szOID_RSA_MD5; // initialize the
// necessary member
//-------------------------------------------------------------------
// Initialize the CMSG_SIGNER_ENCODE_INFO structure.
memset(&SignerEncodeInfo, 0, sizeof(CMSG_SIGNER_ENCODE_INFO));
SignerEncodeInfo.cbSize = sizeof(CMSG_SIGNER_ENCODE_INFO);
SignerEncodeInfo.pCertInfo = pSignerCert->pCertInfo;
SignerEncodeInfo.hCryptProv = hCryptProv;
SignerEncodeInfo.dwKeySpec = AT_KEYEXCHANGE;
SignerEncodeInfo.HashAlgorithm = HashAlgorithm;
SignerEncodeInfo.pvHashAuxInfo = NULL;
//-------------------------------------------------------------------
// Create an array of one.
// Note: The current program is set up for only a single signer.
SignerEncodeInfoArray[0] = SignerEncodeInfo;
//-------------------------------------------------------------------
// Initialize the CMSG_SIGNED_ENCODE_INFO structure.
SignerCertBlob.cbData = pSignerCert->cbCertEncoded;
SignerCertBlob.pbData = pSignerCert->pbCertEncoded;
//-------------------------------------------------------------------
// Initialize the array of one CertBlob.
SignerCertBlobArray[0] = SignerCertBlob;
memset(&SignedMsgEncodeInfo, 0, sizeof(CMSG_SIGNED_ENCODE_INFO));
SignedMsgEncodeInfo.cbSize = sizeof(CMSG_SIGNED_ENCODE_INFO);
SignedMsgEncodeInfo.cSigners = 1;
SignedMsgEncodeInfo.rgSigners = SignerEncodeInfoArray;
SignedMsgEncodeInfo.cCertEncoded = 1;
SignedMsgEncodeInfo.rgCertEncoded = SignerCertBlobArray;
SignedMsgEncodeInfo.rgCrlEncoded = NULL;
//-------------------------------------------------------------------
// Get the size of the encoded, signed message BLOB.
if(cbSignedBlob = CryptMsgCalculateEncodedLength(
MY_ENCODING_TYPE, // message encoding type
0, // flags
CMSG_SIGNED, // message type
&SignedMsgEncodeInfo, // pointer to structure
NULL, // inner content OID
cbContent)) // size of content
{
printf("%d, the length of data calculated. \n",cbSignedBlob);
}
else
{
if ( GetLastError() == NTE_BAD_KEYSET)
{
printf("A Usable private key was not found \n");
printf("in the default key container. Either a \n");
printf("private key must be generated in that container \n");
printf("or CryptAquireCertificatePRivateKey can be used \n");
printf("to gain access to the needed private key.");
}
MyHandleError("Getting cbSignedBlob length failed.");
}
//-------------------------------------------------------------------
// Allocate memory for the encoded BLOB.
if(pbSignedBlob = (BYTE *) malloc(cbSignedBlob))
{
printf("Memory has been allocated for the signed message. \n");
}
else
{
MyHandleError("Memory allocation failed.");
}
//-------------------------------------------------------------------
// Open a message to encode.
if(hMsg = CryptMsgOpenToEncode(
MY_ENCODING_TYPE, // encoding type
0, // flags
CMSG_SIGNED, // message type
&SignedMsgEncodeInfo, // pointer to structure
NULL, // inner content OID
NULL)) // stream information (not used)
{
printf("The message to be encoded has been opened. \n");
}
else
{
MyHandleError("OpenToEncode failed.");
}
//-------------------------------------------------------------------
// Update the message with the data.
if(CryptMsgUpdate(
hMsg, // handle to the message
pbContent, // pointer to the content
cbContent, // size of the content
TRUE)) // last call
{
printf("Content has been added to the encoded message. \n");
}
else
{
MyHandleError("MsgUpdate failed.");
}
//-------------------------------------------------------------------
// Get the resulting message.
if(CryptMsgGetParam(
hMsg, // handle to the message
CMSG_CONTENT_PARAM, // parameter type
0, // index
pbSignedBlob, // pointer to the BLOB
&cbSignedBlob)) // size of the BLOB
{
printf("Message encoded successfully. \n");
}
else
{
MyHandleError("MsgGetParam failed.");
}
//-------------------------------------------------------------------
// pbSignedBlob now points to the encoded, signed content.
//-------------------------------------------------------------------
// Get a pointer to the recipient certificate.
// For this program, the recipient's certificate must also be in the
// My store. At this point, only the recipient's public key is needed.
// To open the enveloped message, however, the recipient's
// private key must also be available.
if(pRecipCert=CertFindCertificateInStore(
hStoreHandle,
MY_ENCODING_TYPE, // use X509_ASN_ENCODING
0, // no dwFlags needed
CERT_FIND_SUBJECT_STR, // find a certificate with a
// subject that matches the
// string in the next parameter
pswzRecipientName, // the Unicode string to be found
// in a certificate's subject
NULL)) // NULL for the first call to the
// function
// in all subsequent
// calls, it is the last pointer
// returned by the function
{
printf("Certificate for %S found. \n", pswzRecipientName);
}
else
{
MyHandleError("Could not find the countersigner's "
"certificate.");
}
//-------------------------------------------------------------------
// Initialize the first element of the array of CERT_INFOs.
// In this example, there is only a single recipient.
RecipCertArray[0] = pRecipCert->pCertInfo;
//-------------------------------------------------------------------
// Initialize the symmetric-encryption algorithm identifier
// structure.
ContentEncryptAlgSize = sizeof(ContentEncryptAlgorithm);
memset(&ContentEncryptAlgorithm,
0,
ContentEncryptAlgSize); // initialize to zero
//-------------------------------------------------------------------
// Initialize the necessary members. This particular OID does not
// need any parameters. Some OIDs, however, will require that
// the other members be initialized.
ContentEncryptAlgorithm.pszObjId = szOID_RSA_RC4;
//-------------------------------------------------------------------
// Initialize the CMSG_ENVELOPED_ENCODE_INFO structure.
memset(&EnvelopedEncodeInfo,
0,
sizeof(CMSG_ENVELOPED_ENCODE_INFO));
EnvelopedEncodeInfo.cbSize = sizeof(CMSG_ENVELOPED_ENCODE_INFO);
EnvelopedEncodeInfo.hCryptProv = hCryptProv;
EnvelopedEncodeInfo.ContentEncryptionAlgorithm =
ContentEncryptAlgorithm;
EnvelopedEncodeInfo.pvEncryptionAuxInfo = NULL;
EnvelopedEncodeInfo.cRecipients = 1;
EnvelopedEncodeInfo.rgpRecipients = RecipCertArray;
//-------------------------------------------------------------------
// Get the size of the encoded message BLOB.
if(cbEncodedBlob = CryptMsgCalculateEncodedLength(
MY_ENCODING_TYPE, // message encoding type
0, // flags
CMSG_ENVELOPED, // message type
&EnvelopedEncodeInfo, // pointer to structure
szOID_RSA_signedData, // inner content OID
cbSignedBlob)) // size of content
{
printf("Length of the encoded BLOB will be %d.\n",cbEncodedBlob);
}
else
{
MyHandleError("Getting enveloped cbEncodedBlob length failed.");
}
//--------------------------------------------------------------------
// Allocate memory for the encoded BLOB.
if(pbEncodedBlob = (BYTE *) malloc(cbEncodedBlob))
{
printf("Memory has been allocated for the BLOB. \n");
}
else
{
MyHandleError("Enveloped malloc operation failed.");
}
//-------------------------------------------------------------------
// Open a message to encode.
if(hMsg = CryptMsgOpenToEncode(
MY_ENCODING_TYPE, // encoding type
0, // flags
CMSG_ENVELOPED, // message type
&EnvelopedEncodeInfo, // pointer to structure
szOID_RSA_signedData, // inner content OID
NULL)) // stream information (not used)
{
printf("The message to encode is open. \n");
}
else
{
MyHandleError("Enveloped OpenToEncode failed.");
}
//-------------------------------------------------------------------
// Update the message with the data.
if(CryptMsgUpdate(
hMsg, // handle to the message
pbSignedBlob, // pointer to the signed data BLOB
cbSignedBlob, // size of the data BLOB
TRUE)) // last call
{
printf("The signed BLOB has been added to the message. \n");
}
else
{
MyHandleError("Enveloped MsgUpdate failed.");
}
//-------------------------------------------------------------------
// Get the resulting message.
if(CryptMsgGetParam(
hMsg, // handle to the message
CMSG_CONTENT_PARAM, // parameter type
0, // index
pbEncodedBlob, // pointer to the enveloped,
// signed data BLOB
&cbEncodedBlob)) // size of the BLOB
{
printf("Enveloped message encoded successfully. \n");
}
else
{
MyHandleError("Enveloped MsgGetParam failed.");
}
//-------------------------------------------------------------------
// Clean up.
CertFreeCertificateContext(pRecipCert);
if(CertCloseStore(
hStoreHandle,
CERT_CLOSE_STORE_CHECK_FLAG))
{
printf("The certificate store closed without a certificate "
"left open. \n");
}
else
{
printf("The store closed but a certificate was still open. \n");
}
if(hMsg)
CryptMsgClose(hMsg);
if(hCryptProv)
CryptReleaseContext(hCryptProv,0);
} // end main
//-------------------------------------------------------------------
// This example uses the function MyHandleError, a simple error
// handling function to print an error message and exit
// the program.
// For most applications, replace this function with one
// that does more extensive error reporting.
void MyHandleError(char *s)
{
fprintf(stderr,"An error occurred in running the program. \n");
fprintf(stderr,"%s\n",s);
fprintf(stderr, "Error number %x.\n", GetLastError());
fprintf(stderr, "Program terminating. \n");
exit(1);
} // end MyHandleError

Should I IUnknown::Release interfaces created with DllGetClassObject

I'm trying to debug some code that uses COM, which I am a beginner at.
The two calls to IUnknown::Release at the end have got me worried.
The interfaces were created with DllGetClassObject and IClassFactory::CreateInstance.
I have seen other similar code that does not call IUnknown::Release on these - which is correct?
int OpenMixer_Win_DirectSound(px_mixer *Px, int index)
{
DSPROPERTY_DIRECTSOUNDDEVICE_DESCRIPTION_DATA desc;
HMODULE hDsound = INVALID_HANDLE_VALUE;
GCO DllGetClassObject;
IClassFactory *pcf = NULL;
IKsPropertySet *pps = NULL;
HRESULT hr;
ULONG bytes;
LPGUID guidIn;
LPGUID guidOut;
UINT deviceIn = -1;
UINT deviceOut = -1;
int ret = FALSE;
guidIn = PaWinDS_GetStreamInputGUID(Px->pa_stream);
guidOut = PaWinDS_GetStreamOutputGUID(Px->pa_stream);
do {
hDsound = LoadLibraryA("dsound.dll");
if (hDsound == NULL) {
break;
}
DllGetClassObject = (GCO) GetProcAddress(hDsound, "DllGetClassObject");
if (DllGetClassObject == NULL) {
break;
}
hr = DllGetClassObject(&CLSID_DirectSoundPrivate,
&IID_IClassFactory,
(void **)(&pcf));
if (hr || pcf == NULL) {
break;
}
hr = IClassFactory_CreateInstance(pcf,
NULL,
&IID_IKsPropertySet,
(void **)(&pps));
if (hr || pps == NULL) {
break;
}
/* Do stuff with the interfaces */
} while( FALSE );
if (pps) {
IUnknown_Release(pps);
}
if (pcf) {
IUnknown_Release(pcf);
}
// Free the library. Note that portaudio also opens dsound.dll
// so this probably doesn't do anything until Pa_Terminate is called.
if (hDsound != INVALID_HANDLE_VALUE) {
FreeLibrary(hDsound);
}
}
Absolutely. Both functions create a new interface pointer, they will have a reference count of 1, the AddRef() function was already called. When you're done with it then you have to call Release(). You'll leak memory if you don't. Every interface in COM works this way.
Yes. As seen in DllGetClassObject sample, the return ppvObj will have a refcount.
Yes, DllGetClassObject() will create an object and pass ownership of that object to your code. Your code will now own the object and be responsible for releasing it by calling IUnknown::Release().

WinVerifyTrust to check for a specific signature?

I'm implementing a process elevation helper for Windows. It's a program that will run in elevated mode and launch other programs with administrator privileges without displaying additional UAC prompts. For security reasons, I want to make sure only binaries that are digitally signed with my company's Authenticode key can be executed.
The WinVerifyTrust function gets me halfway there, but it only ensures that a binary is signed by some key that is part of Microsoft's chain of trust. Is there a relatively simple way to perform the Authenticode verification AND ensure that it is signed by our private key?
I believe what you're looking for is CryptQueryObject.
With it you should be able to pull the involved certificate out of a PE, and do any additional checks you want.
By way of example, this will get you to a HCRYPTMSG. From there you can use CryptMsgGetParam to pull out whatever you want. I'd hoped to make something more 'robust', but these APIs are pretty hairy insomuch as they require a lot of branching to handle all their return cases.
So, here's a p/invoke-rific c# example (I started in C, but that was basically unreadable):
static class Crypt32
{
//Omitting flag constants; you can look these up in WinCrypt.h
[DllImport("CRYPT32.DLL", EntryPoint = "CryptQueryObject", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptQueryObject(
int dwObjectType,
IntPtr pvObject,
int dwExpectedContentTypeFlags,
int dwExpectedFormatTypeFlags,
int dwFlags,
out int pdwMsgAndCertEncodingType,
out int pdwContentType,
out int pdwFormatType,
ref IntPtr phCertStore,
ref IntPtr phMsg,
ref IntPtr ppvContext);
}
class Program
{
static void Main(string[] args)
{
//Path to executable here
// I tested with MS-Office .exe's
string path = "";
int contentType;
int formatType;
int ignored;
IntPtr context = IntPtr.Zero;
IntPtr pIgnored = IntPtr.Zero;
IntPtr cryptMsg = IntPtr.Zero;
if (!Crypt32.CryptQueryObject(
Crypt32.CERT_QUERY_OBJECT_FILE,
Marshal.StringToHGlobalUni(path),
Crypt32.CERT_QUERY_CONTENT_FLAG_ALL,
Crypt32.CERT_QUERY_FORMAT_FLAG_ALL,
0,
out ignored,
out contentType,
out formatType,
ref pIgnored,
ref cryptMsg,
ref context))
{
int error = Marshal.GetLastWin32Error();
Console.WriteLine((new Win32Exception(error)).Message);
return;
}
//expecting '10'; CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED
Console.WriteLine("Context Type: " + contentType);
//Which implies this is set
Console.WriteLine("Crypt Msg: " + cryptMsg.ToInt32());
return;
}
To get the certificate information from signed code use this:
using System.Security.Cryptography.X509Certificates;
X509Certificate basicSigner = X509Certificate.CreateFromSignedFile(filename);
X509Certificate2 cert = new X509Certificate2(basicSigner);
Then you can get the cert details like this:
Console.WriteLine(cert.IssuerName.Name);
Console.WriteLine(cert.SubjectName.Name);
// etc
these are some of the nastiest APIs I've ever worked with
A word of warning: it's worse than you already thought.
At least since introducing SHA-256 signing (has this always been the case?), it's possible for Authenticode to have multiple signatures. They're not encoded as multiple signatures in the PKCS-7 signature message; instead, they're unauthenticated message attributes of type OID_NESTED_SIGNATURE, each containing another complete PKCS-7 signature message.
WinVerifyTrust will tell you the file is valid if any of the signatures are valid and come from a trusted certificate chain. However it won't tell you which of the signatures was valid. If you then use CryptQueryObject to read the full PKCS-7 message, and only look at the certificate for the primary signature (as in the code samples here and on MSDN), you're not necessarily looking at a verified certificate. The associated signature might not match the executable, and/or the certificate might not have a trusted CA chain.
If you're using the details of the primary signature to validate that the certificate is one your software trusts, you're vulnerable to a situation where WinVerifyTrust is trusting a secondary signature, but your code is checking the primary signature's certificate is what you expected, and you haven't noticed that the signature from the primary certificate is nonsense. An attacker could use your public certificate without owning its private key, combined with some other code-signing certificate issued to someone else, to bypass a publisher check this way.
From Win8 onwards, WinVerifyTrust can optionally validate specific signatures, so you should be able to iterate the signatures to find one that is valid and one that satisfies your requirements.
If you have to be Win7-compatible, though, as far as I know the best you can manage is MsiGetFileSignatureInformation. From experimentation (as for everything else here, the actual documentation is frustratingly woolly), it seems to return the trusted certificate when WinVerifyTrust trusts one. But if there isn't a trusted signature, it returns the primary signature's certificate anyway, so you still have to use WinVerifyTrust to check that first.
Of course there also plenty of possible time-of-check/time-of-use problems here.
found the solution here:
http://www.ucosoft.com/how-to-program-to-retrieve-the-authenticode-information.html
here it is with indentation:
#define _UNICODE 1
#define UNICODE 1
#include <windows.h>
#include <tchar.h>
#include <wincrypt.h>
#include <Softpub.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment (lib, "Crypt32")
// the Authenticode Signature is encode in PKCS7
#define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
// Information structure of authenticode sign
typedef struct
{
LPWSTR lpszProgramName;
LPWSTR lpszPublisherLink;
LPWSTR lpszMoreInfoLink;
DWORD cbSerialSize;
LPBYTE lpSerialNumber;
LPTSTR lpszIssuerName;
LPTSTR lpszSubjectName;
}
SPROG_SIGNATUREINFO, *PSPROG_SIGNATUREINFO;
VOID GetProgAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo, PSPROG_SIGNATUREINFO pInfo);
VOID GetCertificateInfo(HCERTSTORE hStore, PCMSG_SIGNER_INFO pSignerInfo, PSPROG_SIGNATUREINFO pInfo);
BOOL GetAuthenticodeInformation(LPCTSTR lpszFileName, PSPROG_SIGNATUREINFO pInfo)
{
HCERTSTORE hStore = NULL;
HCRYPTMSG hMsg = NULL;
PCMSG_SIGNER_INFO pSignerInfo = NULL;
DWORD dwSignerInfo;
BOOL bRet = FALSE;
__try
{
// as CryptQueryObject() only accept WCHAR file name, convert first
WCHAR wszFileName[MAX_PATH];
#ifdef UNICODE
if ( !lstrcpynW( wszFileName, lpszFileName, MAX_PATH))
__leave;
#else
if ( mbstowcs( wszFileName, lpszFileName, MAX_PATH) == -1)
__leave;
#endif
//Retrieve the Message Handle and Store Handle
DWORD dwEncoding, dwContentType, dwFormatType;
if ( !CryptQueryObject( CERT_QUERY_OBJECT_FILE, wszFileName,
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
CERT_QUERY_FORMAT_FLAG_BINARY, 0, &dwEncoding,
&dwContentType, &dwFormatType, &hStore,
&hMsg, NULL))
__leave;
//Get the length of SignerInfo
if ( !CryptMsgGetParam( hMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &dwSignerInfo))
__leave;
// allocate the memory for SignerInfo
if ( !(pSignerInfo = (PCMSG_SIGNER_INFO)LocalAlloc( LPTR, dwSignerInfo)))
__leave;
// get the SignerInfo
if ( !CryptMsgGetParam( hMsg, CMSG_SIGNER_INFO_PARAM, 0, (PVOID)pSignerInfo, &dwSignerInfo))
__leave;
//get the Publisher from SignerInfo
GetProgAndPublisherInfo( pSignerInfo, pInfo);
//get the Certificate from SignerInfo
GetCertificateInfo( hStore, pSignerInfo, pInfo);
bRet = TRUE;
}
__finally
{
// release the memory
if (pSignerInfo != NULL) LocalFree(pSignerInfo);
if (hStore != NULL) CertCloseStore(hStore, 0);
if (hMsg != NULL) CryptMsgClose(hMsg);
}
return bRet;
}
LPWSTR AllocateAndCopyWideString(LPCWSTR inputString)
{
LPWSTR outputString = NULL;
// allocate the memory
outputString = (LPWSTR)VirtualAlloc(NULL, (wcslen(inputString) + 1) * sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE);
// copy
if (outputString != NULL)
{
lstrcpyW(outputString, inputString);
}
return outputString;
}
VOID GetProgAndPublisherInfo(PCMSG_SIGNER_INFO pSignerInfo, PSPROG_SIGNATUREINFO pInfo)
{
PSPC_SP_OPUS_INFO OpusInfo = NULL;
DWORD dwData;
__try
{
// query SPC_SP_OPUS_INFO_OBJID OID in Authenticated Attributes
for (DWORD n = 0; n < pSignerInfo->AuthAttrs.cAttr; n++)
{
if (lstrcmpA(SPC_SP_OPUS_INFO_OBJID, pSignerInfo->AuthAttrs.rgAttr[n].pszObjId) == 0)
{
// get the length of SPC_SP_OPUS_INFO
if ( !CryptDecodeObject(ENCODING,
SPC_SP_OPUS_INFO_OBJID,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
0,
NULL,
&dwData))
__leave;
// allocate the memory for SPC_SP_OPUS_INFO
if ( !(OpusInfo = (PSPC_SP_OPUS_INFO)LocalAlloc(LPTR, dwData)))
__leave;
// get SPC_SP_OPUS_INFO structure
if ( !CryptDecodeObject(ENCODING,
SPC_SP_OPUS_INFO_OBJID,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].pbData,
pSignerInfo->AuthAttrs.rgAttr[n].rgValue[0].cbData,
0,
OpusInfo,
&dwData))
__leave;
// copy the Program Name of SPC_SP_OPUS_INFO to the return variable
if (OpusInfo->pwszProgramName)
{
pInfo->lpszProgramName = AllocateAndCopyWideString(OpusInfo->pwszProgramName);
}
else
pInfo->lpszProgramName = NULL;
// copy the Publisher Info of SPC_SP_OPUS_INFO to the return variable
if (OpusInfo->pPublisherInfo)
{
switch (OpusInfo->pPublisherInfo->dwLinkChoice)
{
case SPC_URL_LINK_CHOICE:
pInfo->lpszPublisherLink = AllocateAndCopyWideString(OpusInfo->pPublisherInfo->pwszUrl);
break;
case SPC_FILE_LINK_CHOICE:
pInfo->lpszPublisherLink = AllocateAndCopyWideString(OpusInfo->pPublisherInfo->pwszFile);
break;
default:
pInfo->lpszPublisherLink = NULL;
break;
}
}
else
{
pInfo->lpszPublisherLink = NULL;
}
// copy the More Info of SPC_SP_OPUS_INFO to the return variable
if (OpusInfo->pMoreInfo)
{
switch (OpusInfo->pMoreInfo->dwLinkChoice)
{
case SPC_URL_LINK_CHOICE:
pInfo->lpszMoreInfoLink = AllocateAndCopyWideString(OpusInfo->pMoreInfo->pwszUrl);
break;
case SPC_FILE_LINK_CHOICE:
pInfo->lpszMoreInfoLink = AllocateAndCopyWideString(OpusInfo->pMoreInfo->pwszFile);
break;
default:
pInfo->lpszMoreInfoLink = NULL;
break;
}
}
else
{
pInfo->lpszMoreInfoLink = NULL;
}
break; // we have got the information, break
}
}
}
__finally
{
if (OpusInfo != NULL) LocalFree(OpusInfo);
}
}
VOID GetCertificateInfo(HCERTSTORE hStore, PCMSG_SIGNER_INFO pSignerInfo, PSPROG_SIGNATUREINFO pInfo)
{
PCCERT_CONTEXT pCertContext = NULL;
__try
{
CERT_INFO CertInfo;
DWORD dwData;
// query Signer Certificate in Certificate Store
CertInfo.Issuer = pSignerInfo->Issuer;
CertInfo.SerialNumber = pSignerInfo->SerialNumber;
if ( !(pCertContext = CertFindCertificateInStore( hStore,
ENCODING, 0, CERT_FIND_SUBJECT_CERT,
(PVOID)&CertInfo, NULL)))
__leave;
dwData = pCertContext->pCertInfo->SerialNumber.cbData;
// SPROG_SIGNATUREINFO.cbSerialSize
pInfo->cbSerialSize = dwData;
// SPROG_SIGNATUREINFO.lpSerialNumber
pInfo->lpSerialNumber = (LPBYTE)VirtualAlloc(NULL, dwData, MEM_COMMIT, PAGE_READWRITE);
memcpy( pInfo->lpSerialNumber, pCertContext->pCertInfo->SerialNumber.pbData, dwData);
// SPROG_SIGNATUREINFO.lpszIssuerName
__try
{
// get the length of Issuer Name
if (!(dwData = CertGetNameString( pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
CERT_NAME_ISSUER_FLAG, NULL, NULL, 0)))
__leave;
// allocate the memory
if ( !(pInfo->lpszIssuerName = (LPTSTR)VirtualAlloc(NULL, dwData * sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE)))
__leave;
// get Issuer Name
if (!(CertGetNameString(pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
CERT_NAME_ISSUER_FLAG, NULL, pInfo->
lpszIssuerName, dwData)))
__leave;
}
__finally
{
}
// SPROG_SIGNATUREINFO.lpszSubjectName
__try
{
//get the length of Subject Name
if (!(dwData = CertGetNameString( pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, NULL, 0)))
__leave;
// allocate the memory
if ( !(pInfo->lpszSubjectName = (LPTSTR)VirtualAlloc(NULL, dwData * sizeof(TCHAR), MEM_COMMIT, PAGE_READWRITE)))
__leave;
// get Subject Name
if (!(CertGetNameString( pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, pInfo->lpszSubjectName, dwData)))
__leave;
}
__finally
{
}
}
__finally
{
if (pCertContext != NULL)
CertFreeCertificateContext(pCertContext);
}
}
int _tmain(int argc, TCHAR *argv[])
{
if (argc != 2)
{
_tprintf(_T("Usage: SignedFileInfo \n"));
return 0;
}
else
{
SPROG_SIGNATUREINFO SignInfo;
ZeroMemory(&SignInfo, sizeof(SignInfo));
GetAuthenticodeInformation( argv[1], &SignInfo);
wprintf(L"Program Name: %s\n", SignInfo.lpszProgramName);
wprintf(L"Publisher Link: %s\n", SignInfo.lpszPublisherLink);
wprintf(L"More Info Link: %s\n", SignInfo.lpszMoreInfoLink);
{
_tprintf(_T("Serial Number: "));
DWORD dwData = SignInfo.cbSerialSize;
for (DWORD n = 0; n < dwData; n++)
{
_tprintf(_T("%02x "),
SignInfo.lpSerialNumber[dwData - (n + 1)]);
}
_tprintf(_T("\n"));
}
_tprintf(_T("Issuer Name: %s\n"), SignInfo.lpszIssuerName);
_tprintf(_T("Subject Name: %s\n"), SignInfo.lpszSubjectName);
if ( SignInfo.lpszProgramName) VirtualFree(SignInfo.lpszProgramName, 0, MEM_RELEASE);
if ( SignInfo.lpszPublisherLink) VirtualFree(SignInfo.lpszPublisherLink, 0, MEM_RELEASE);
if ( SignInfo.lpszMoreInfoLink) VirtualFree(SignInfo.lpszMoreInfoLink, 0, MEM_RELEASE);
if ( SignInfo.lpSerialNumber) VirtualFree(SignInfo.lpSerialNumber, 0, MEM_RELEASE);
if ( SignInfo.lpszIssuerName) VirtualFree(SignInfo.lpszIssuerName, 0, MEM_RELEASE);
if ( SignInfo.lpszSubjectName) VirtualFree(SignInfo.lpszSubjectName, 0, MEM_RELEASE);
return 0;
}
}

Resources