Retired Microsoft Blog disclaimer

This directory is a mirror of retired "Decrypt My World" MSDN blog and is provided as is. All posting authorship and copyrights belong to respective authors.

Posts on this page:

Original URL: https://blogs.msdn.microsoft.com/alejacma/2009/12/13/x64-version-of-signtool/
Post name: x64 version of SignTool?
Original author: Alejandro Campos Magencio
Posting date: 2009-12-13T23:57:00+00:00


Hi all,

I was asked the other day ifwe had an x64 version of SignTool.exe. Up to date, the answer is NO. If you download the tool with Microsoft Windows SDK, you will only get the x86 version. This tool has dependencies on some x86 authenticode plug-ins, and as you sure know, you cannot load x86 dlls in x64 processes.

I hope this helps.

Regards,

Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2009/12/13/x64-version-of-capicom/
Post name: x64 version of CAPICOM?
Original author: Alejandro Campos Magencio
Posting date: 2009-12-13T23:37:00+00:00


Hi all,

Now that we are progressively moving to x64 systems, many people ask me if there is an x64 version of CAPICOM available. The answer is no, there is not. And because CAPICOM is already deprecated (CAPICOM support on Windows 7), there won't ever be any. So if you are using a version of x64 Windows older than Windows 7/Server 2008 R2, you will have to use x86 version (which will only work with x86 apps), or move to i.e. .NET and forget about CAPICOM.

I hope this helps.

Regards,

Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2009/12/04/2-1-0-3-a-new-capicom-version/
Post name: 2.1.0.3, a new CAPICOM version?
Original author: Alejandro Campos Magencio
Posting date: 2009-12-04T05:44:00+00:00


Hi all,

The other day I got surprised when a customer of mine told me that they had seen a new CAPICOM version being installed by Office 2007 SP2: 2.1.0.3. I've been dealing with many CAPICOM issues in the past, and I had no news of such a version. Is it a new version? Can it be used? Can it be redistributed?

To my knowledge, version 2.1.0.2 was thelastest version available. Additionally, it was the only supported version on Vista/Server 2008(CAPICOM support on Windows Vista, CAPICOM support on Windows Server 2008).Note that this is not the case on Windows7/2008 R2(CAPICOM support on Windows 7). CAPICOM has been deprecated, and you should seriously think about migrating to a .NET solution, for example.

Anyway, after some research I was told that the code of2.1.0.3 is exactly the sameas 2.1.0.2, and only the version number is different. Office 2007 had to modify the version number of their copy of CAPICOM to work around some issue on their setup logic in SP2.

So summing up, just forget about that dll that Office uses. Stick to the official version,2.1.0.2, that is available here: Security Update for CAPICOM (KB931906).

I hope this helps.

Regards,

Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2009/12/02/httpwebclientprotocol-clientcertificates-and-pfx-files/
Post name: HttpWebClientProtocol.ClientCertificates and PFX files
Original author: Alejandro Campos Magencio
Posting date: 2009-12-02T00:29:00+00:00


Hi all,

Imagine you want to call a webservice through SSL in a client application. You want to provide a client certificate to the SSL connection and you have a PFX file with that client certificate plus the CA certificate plus the root certificate. None of those certificates are installed in the system.

So you create an X509Certificate object from that PFX file and add it to the HttpWebClientProtocol.ClientCertificates property, but it won't work. Only if you install all the certificates in the certificate store ofi.e. the user's profile (so you don't need an admin user to install them) you will be able to connect to the webservice successfully.

The reason is that the info in ClientCertificates is just used to be able to find the relevant client certificates in the certificate store. So the certificates in the PFX must be installed in the store (user's or machine's profile) first, to be able to find them and use them.

When we use ClientCertificates property, it is enough just by adding an X509Certificate objectcreated from a CER file. That CER file just contains the client certificate without private key, and of course no CA or root certs. And it is enough because the certs in ClientCertificates just identify the client cert that we can find in the store, where the private key and the other CA and root certs can be found (to build the certificate chain to verify trust, for instance).

I hope this helps.

Regards,

Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2009/11/12/how-to-manipulate-reg_multi_sz-values-from-the-registry-c/
Post name: How to manipulate REG_MULTI_SZ values from the registry (C++)
Original author: Alejandro Campos Magencio
Posting date: 2009-11-12T07:48:00+00:00


Hi all,


The other day I had to develop a small C++ sample which shows how to readthe list of values of a REG_MULTI_SZ from the registry, and add a new value just after one of the values of the list. Additionally,I used methods and constants from tchar.h extensively, so it didn't matter if I compiled the code as UNICODE or ANSI. Here is the code:


#include "windows.h"
#include "tchar.h"
#include "conio.h"
#include "stdio.h"

#define MY_KEY _T("PathToMyRegistryKey\\MyRegistryKey") // Registry key
#define MY_VALUES _T("NameOfTheREG_MULTI_SZListOfValues") // Registry values
#define NEW_VALUE _T("MyNewValue") // New value
#define FIND_VALUE _T("AnExistingValue") // We will insert the new value after this one

int _tmain(int argc, _TCHAR* argv[])
{
LONG lResult = 0;
HKEY hKey = NULL;
LPTSTR lpValues = NULL;
LPTSTR lpValue = NULL;
LPTSTR lpNewValues = NULL;
LPTSTR lpNewValue = NULL;
DWORD cbValues = 0;
DWORD cbNewValues = 0;
DWORD cbNewValue = 0;
BOOL bFound = FALSE;

__try
{
// OPEN THE REGISTRY KEY
//
_tprintf(_T("RegOpenKeyEx..."));
lResult = RegOpenKeyEx(
HKEY_LOCAL_MACHINE,
MY_KEY,
0,
KEY_ALL_ACCESS,
&hKey
);
if (ERROR_SUCCESS != lResult) { _tprintf(_T("ERROR 0x%x\n"), lResult); return 1; }
_tprintf(_T("SUCCESS\n"));

// READ THE REG_MULTI_SZ VALUES
//
// Get size of the buffer for the values
_tprintf(_T("RegQueryValueEx..."));
lResult = RegQueryValueEx(
hKey,
MY_VALUES,
NULL,
NULL,
NULL,
&cbValues
);
if (ERROR_SUCCESS != lResult) { _tprintf(_T("ERROR 0x%x\n"), lResult); return 1; }
_tprintf(_T("SUCCESS\n"));

// Allocate the buffer
_tprintf(_T("malloc..."));
lpValues = (LPTSTR)malloc(cbValues);
if (NULL == lpValues) { _tprintf(_T("ERROR 0x%x\n"), GetLastError()); return 1; }
_tprintf(_T("SUCCESS\n"));

// Get the values
_tprintf(_T("RegQueryValueEx..."));
lResult = RegQueryValueEx(
hKey,
MY_VALUES,
NULL,
NULL,
(LPBYTE)lpValues,
&cbValues
);
if (ERROR_SUCCESS != lResult) { _tprintf(_T("ERROR 0x%x\n"), lResult); return 1; }
_tprintf(_T("SUCCESS\n"));

// SHOW THE VALUES
//
_tprintf(_T("\n**************************\n"));
_tprintf(_T("OLD VALUES\n"));
_tprintf(_T("**************************\n\n"));
lpValue = lpValues;
for (; '\0' != *lpValue; lpValue += _tcslen(lpValue) + 1)
{
// Show one value
_tprintf(_T("%s\n"), lpValue);
}
_tprintf(_T("\n**************************\n\n"));

// INSERT A NEW VALUE AFTER A SPECIFIC VALUE IN THE LIST OF VALUES
//
// Allocate a new buffer for the old values plus the new one
_tprintf(_T("malloc..."));
cbNewValue = (_tcslen(NEW_VALUE) + 1) * sizeof(TCHAR);
cbNewValues = cbValues + cbNewValue;
lpNewValues = (LPTSTR)malloc(cbNewValues);
if (NULL == lpNewValues) { _tprintf(_T("ERROR 0x%x\n"), GetLastError()); return 1; }
_tprintf(_T("SUCCESS\n"));

// Find the value after which we will insert the new one
lpValue = lpValues;
lpNewValue = lpNewValues;
bFound = FALSE;
for (; '\0' != *lpValue; lpValue += _tcslen(lpValue) + 1)
{
// Copy the current value to the target buffer
memcpy(lpNewValue, lpValue, (_tcslen(lpValue) + 1) * sizeof(TCHAR));

if (0 == _tcscmp(lpValue, FIND_VALUE))
{
// The current value is the one we wanted to find
bFound = TRUE;

// Copy the new value to the target buffer
lpNewValue += _tcslen(lpValue) + 1;
memcpy(lpNewValue, NEW_VALUE, (_tcslen(NEW_VALUE) + 1) * sizeof(TCHAR));
lpNewValue += _tcslen(NEW_VALUE) + 1;
}
else
{
// This is not the value we want, continue to the next one
lpNewValue += _tcslen(lpValue) + 1;
}
}
if (!bFound)
{
// We didn't find the value we wanted. Insert the new value at the end
memcpy(lpNewValue, NEW_VALUE, (_tcslen(NEW_VALUE) + 1) * sizeof(TCHAR));
lpNewValue += _tcslen(NEW_VALUE) + 1;
}
*lpNewValue = *lpValue;

// SHOW THE NEW VALUES
//
_tprintf(_T("\n**************************\n"));
_tprintf(_T("NEW VALUES\n"));
_tprintf(_T("**************************\n\n"));
lpNewValue = lpNewValues;
for (; '\0' != *lpNewValue; lpNewValue += _tcslen(lpNewValue) + 1)
{
// Show one value
_tprintf(_T("%s\n"), lpNewValue);
}
_tprintf(_T("\n**************************\n\n"));

// WRITE THE NEW VALUES BACK TO THE KEY
//
_tprintf(_T("RegSetValueEx..."));
lResult = RegSetValueEx(
hKey,
MY_VALUES,
NULL,
REG_MULTI_SZ,
(LPBYTE)lpNewValues,
cbNewValues
);
if (ERROR_SUCCESS != lResult) { _tprintf(_T("ERROR 0x%x\n"), lResult); return 1; }
_tprintf(_T("SUCCESS\n"));
}
__finally
{
// Clean up
//
if (NULL != lpValues) { free(lpValues); }
if (NULL != lpNewValues) { free(lpNewValues); }
if (NULL != hKey) { RegCloseKey(hKey); }

//_tprintf(_T("\n<<PRESS ANY KEY>>\n"));
//_getch();
}

return 0;
}


Regards,



Alex (Alejandro Campos Magencio)