Microsoft KB Archive/193076

{|
 * width="100%"|

HOWTO: Read SPC Files Dumped by Certificate Enrollment Control

 * }

Q193076

-

The information in this article applies to:


 * Microsoft Win32 Application Programming Interface (API), used with:
 * the operating system: Microsoft Windows NT 4.0
 * the operating system: 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   #include    #include    #include 

#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 \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); }  }