HOWTO: Read SPC Files Dumped by Certificate Enrollment Control
ID: Q193076
|
The information in this article applies to:
-
Microsoft Win32 Application Programming Interface (API), used with:
-
Microsoft Windows NT 4.0
-
Microsoft Windows 2000
SUMMARY
You can get information for an issued certificate without implementing a
custom exit module. The Certificate Enrollment Control object has a
property called SPCFileName. By setting SPCFileName, you tell the object to
dump the base64 encoded PKCS #7 certificate to a file in binary PKCS #7
format. You can decode this file by using CryptoAPI to obtain information
about the certificate.
NOTE: This information is only relevant to Certificate Server 1.0.
MORE INFORMATION
The following sample code demonstrates how to get a CERT_CONTEXT structure
from the SPC file. You can use the CryptoAPI Certificate Helper Functions
to retrieve the certificate information.
Sample Code
// Decode SPC.exe.
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
#include <tchar.h>
#define MY_ENCODE_TYPE (CRYPT_ASN_ENCODING | PKCS7_ASN_ENCODING)
#define BUFFERSIZE 40
void _cdecl _tmain(int argc, TCHAR *argv[])
{
HCRYPTMSG hCryptMsg = NULL;
PCCERT_CONTEXT pCertContext = NULL;
BYTE *bPKCS7 = NULL;
BYTE *pbCertificate = NULL;
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD CertCount, dwIndex, dwResult;
DWORD dwNumRead;
BOOL bResult;
if (argc != 2)
{
_tprintf(TEXT("Usage: DecodeSPC <SPC file>\n"));
return;
}
__try {
// Open SPC file.
hFile = CreateFile(argv[1], GENERIC_READ, 0,
NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
_tprintf(TEXT("CreateFile failed with %d\n"), GetLastError());
__leave;
}
// Get file size.
dwResult = GetFileSize(hFile, NULL);
if (dwResult == 0xFFFFFFFF)
{
_tprintf(TEXT("GetFileSize failed with %d\n"), GetLastError());
__leave;
}
// Allocate PKCS7 buffer.
bPKCS7 = (BYTE *)HeapAlloc(GetProcessHeap(), 0, dwResult);
if (bPKCS7 == NULL)
{
_tprintf(TEXT("HeapAlloc failed to allocate PKCS7 buffer\n"));
__leave;
}
// Read SPC file.
bResult = ReadFile(hFile, bPKCS7, dwResult, &dwNumRead, NULL);
if (!bResult)
{
_tprintf(TEXT("ReadFile failed with %d\n"), GetLastError());
__leave;
}
// Open message for decoding.
hCryptMsg = CryptMsgOpenToDecode(MY_ENCODE_TYPE, 0, 0,
0, NULL, NULL);
if (hCryptMsg == NULL)
{
_tprintf(TEXT("CryptMsgOpenToDecode failed with %x\n"),
GetLastError());
__leave;
}
// Update the contents of the message.
bResult = CryptMsgUpdate(hCryptMsg, bPKCS7, dwResult, TRUE);
if (!bResult)
{
_tprintf(TEXT("CryptMsgUpdate failed with %x\n"),
GetLastError());
__leave;
}
// Get Number of Certificates in message.
// There should be two certificates:
// the first certificate is the issuer certificate,
// and the second is the subject certificate.
dwNumRead = sizeof(DWORD);
bResult = CryptMsgGetParam(hCryptMsg, CMSG_CERT_COUNT_PARAM , 0,
&CertCount, &dwNumRead);
if (!bResult)
{
_tprintf(TEXT("CryptMsgGetParam failed with %x\n"),
GetLastError());
__leave;
}
_tprintf(TEXT("Certificate Count : %d\n"), CertCount);
// Enumerate through certificates.
for (dwIndex = 0; dwIndex < CertCount; dwIndex++)
{
_tprintf(TEXT("\n\nCertificate #%d\n"), dwIndex+1);
// Get encoded certificate length.
dwNumRead = 0;
bResult = CryptMsgGetParam(hCryptMsg, CMSG_CERT_PARAM, dwIndex,
NULL, &dwNumRead);
if (!bResult)
{
_tprintf(TEXT("CryptMsgGetParam with %x\n"),
GetLastError());
__leave;
}
// Allocate buffer for encoded certificate.
pbCertificate = (BYTE *)HeapAlloc(GetProcessHeap(), 0,
dwNumRead);
if (pbCertificate == NULL)
{
_tprintf(
TEXT("Failed to allocate memory for certificate\n"));
__leave
}
// Get encoded certificate.
bResult = CryptMsgGetParam(hCryptMsg, CMSG_CERT_PARAM,
dwIndex, pbCertificate, &dwNumRead);
if (!bResult)
{
_tprintf(TEXT("CryptMsgGetParam failed with %x\n"),
GetLastError());
__leave;
}
// Create certificate context from encoded certificate bytes.
pCertContext = CertCreateCertificateContext(
X509_ASN_ENCODING,
pbCertificate, dwNumRead);
if (pCertContext == NULL)
{
_tprintf(
TEXT("CertCreateCertificateContext failed with %x\n"),
GetLastError());
__leave;
}
//
// Get certificate information from pCertContext.
//
// Free memory for next iteration.
CertFreeCertificateContext(pCertContext);
pCertContext = NULL;
HeapFree(GetProcessHeap, 0, pbCertificate);
pbCertificate = NULL;
}
}
__finally {
// Clean up.
if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
if (bPKCS7 != NULL) HeapFree(GetProcessHeap(), 0, bPKCS7);
if (hCryptMsg != NULL) CryptMsgClose(hCryptMsg);
if (pbCertificate != NULL) LocalFree(GetProcessHeap(),
0, pbCertificate);
if (pCertContext != NULL)
CertFreeCertificateContext(pCertContext);
}
}
REFERENCES
Platform SDK documentation: Certificate Helper Functions.
Additional query words:
Keywords : kbAPI kbCrypt kbKernBase kbNTOS400 kbWinOS2000 kbSDKPlatform kbDSupport kbCodeSam kbGrpKernBase
Version : winnt:4.0
Platform : winnt
Issue type : kbhowto