Certificate Request Example Code

The following example code demonstrates the procedure outlined in the previous section. This example code creates a simple certificate request with one signer, a single RDN attribute, and no general attributes.

// This example code demonstrates how to create and encode a 
// certificate request. 

#include <stdio.h>
#include <windows.h>
#include "wincrypt.h"
#define CERT_SUBJECT_NAME "Elizabeth Jackson"
#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
void BytesToStr(DWORD cb, void* pv, LPSTR sz);
void main(void)
{
// Declare and initialize  

// A CERT_RDN_ATTR array.
// In this code, only one array element is used.

  CERT_RDN_ATTR rgNameAttr[] = {"2.5.4.3",  // pszObjId 
  CERT_RDN_PRINTABLE_STRING,                // dwValueType
    strlen(CERT_SUBJECT_NAME),              // value.cbData
    (BYTE*)CERT_SUBJECT_NAME};              // value.pbData

// A CERT_RDN array.
// In this code, only one array element is used.

CERT_RDN rgRDN[] = {
    1,                 // rgRDN[0].cRDNAttr
    &rgNameAttr[0]};   // rgRDN[0].rgRDNAttr

// A CERT_NAME_INFO structure.

CERT_NAME_INFO Name = {
       1,                  // Name.cRDN
       rgRDN};             // Name.rgRDN

// Other variables and structures.

CERT_REQUEST_INFO    CertReqInfo;
CERT_NAME_BLOB       SubjNameBlob;
DWORD cbNameEncoded = 0;
BYTE* pbNameEncoded;
HCRYPTPROV hCryptProv = NULL; // Handle returned here
DWORD    cbPublicKeyInfo;
CERT_PUBLIC_KEY_INFO* pbPublicKeyInfo;
DWORD    cbEncodedCertReqSize;
CRYPT_OBJID_BLOB Parameters;
CRYPT_ALGORITHM_IDENTIFIER SigAlg;
BYTE* pbSignedEncodedCertReq;
char*    pSignedEncodedCertReqBlob;
BOOL fReturn = FALSE;

CryptEncodeObject(
    MY_ENCODING_TYPE,     // Encoding type
    X509_NAME,            // Struct type
    &Name,                // Address of CERT_NAME_INFO struct.
    NULL,                 // pbEncoded
    &cbNameEncoded);      // pbEncoded size

if(cbNameEncoded<1)
{
    printf("First call to CryptEncodeObject Failed\n");
    goto handle_error;
}

if(!(pbNameEncoded = (BYTE*)malloc(cbNameEncoded)))
{
    printf("pbNamencoded Malloc Failed\n");
    goto handle_error;
}

if(!CryptEncodeObject(
        MY_ENCODING_TYPE,    // Encoding type
        X509_NAME,           // Struct type
        &Name,               // Address of CERT_NAME_INFO struct.
        pbNameEncoded,       // pbEncoded
        &cbNameEncoded))     // pbEncoded size
{
    printf("Second call to CryptEncodeObject Failed\n");
    free(pbNameEncoded);
    goto handle_error;
}

// Set the Subject member of CertReqInfo to point to 
// a CERT_NAME_INFO structure that 
// has been initialized with the data from step 5.

SubjNameBlob.cbData = cbNameEncoded;
SubjNameBlob.pbData = pbNameEncoded;
CertReqInfo.Subject = SubjNameBlob;

// Generate custom information.  This step is not
// implemented in this code.

CertReqInfo.cAttribute = 0;
CertReqInfo.rgAttribute = NULL;
CertReqInfo.dwVersion = CERT_REQUEST_V1;

// Call CryptExportPublicKeyInfo to return an initialized
// CERT_PUBLIC_KEY_INFO structure.
// #1  Get 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,      // Need to do both encrypt & sign.
    NULL)))             // No flags needed.
{
    printf("Call to CryptAcquireContextFailed\n");
    free(pbNameEncoded);
    goto handle_error;
}

// Call CryptExportPublicKeyInfo to get the size of the returned
// information.

if(!(CryptExportPublicKeyInfo(
          hCryptProv,            // Provider handle
          AT_SIGNATURE,          // Key spec
          MY_ENCODING_TYPE,      // Encoding type
          NULL,                  // pbPublicKeyInfo
          &cbPublicKeyInfo)))     // Size of PublicKeyInfo
{
    printf("First call to CryptExportPublicKeyInfo failed\n");
    free(pbNameEncoded);
    goto handle_error;
}

// Allocate the necessary memory.
if(!(pbPublicKeyInfo = 
   (CERT_PUBLIC_KEY_INFO*)malloc(cbPublicKeyInfo)))
{
    printf("pbPublicKeyInfo Malloc Failed.\n");
    free(pbNameEncoded);
    goto handle_error;
}

// Call CryptExportPublicKeyInfo to get pbPublicKeyInfo.
if(!(CryptExportPublicKeyInfo(
          hCryptProv,            // Provider handle
          AT_SIGNATURE,          // Key spec
          MY_ENCODING_TYPE,      // Encoding type
          pbPublicKeyInfo,       // pbPublicKeyInfo
          &cbPublicKeyInfo)))    // Size of PublicKeyInfo
{
    printf("Second call to CryptExportPublicKeyInfo failed.\n");
    free(pbNameEncoded);
    free(pbPublicKeyInfo);
    goto handle_error;
}
// Set the SubjectPublicKeyInfo member of the 
// CERT_REQUEST_INFO structure to point to the CERT_PUBLIC_KEY_INFO 
// structure created.

CertReqInfo.SubjectPublicKeyInfo = *pbPublicKeyInfo;

// Call CryptSignAndEncodeCertificate to encode, sign,
// and re-encode the CERT_REQUEST_INFO structure and the data 
// pointed to by it.
//---------------------------------------------------------------

memset(&Parameters, 0, sizeof(Parameters));
SigAlg.pszObjId = szOID_OIWSEC_sha1RSASign;
SigAlg.Parameters = Parameters;

// Call CryptSignAndEncodeCertificate to get the size of the
// returned blob.
if(!(CryptSignAndEncodeCertificate(
          hCryptProv,                      // Crypto provider
          AT_SIGNATURE,                    // Key spec.
          MY_ENCODING_TYPE,                // Encoding type
          X509_CERT_REQUEST_TO_BE_SIGNED,  // Struct type
          &CertReqInfo,                    // Struct info
          &SigAlg,                         // Signature algorithm
          NULL,                            // Not used
          NULL,                            // pbSignedEncodedCertReq
          &cbEncodedCertReqSize)))         // Size of cert req
{
    printf("First call to CryptSignAndEncodeCertificate\n ");
    printf("failed.\n");
    free(pbNameEncoded);
    free(pbPublicKeyInfo);
    goto handle_error;
}

// Malloc the necessary memory.
pbSignedEncodedCertReq = (BYTE*)malloc(cbEncodedCertReqSize);
if(!pbSignedEncodedCertReq)
{
    printf("pbSignedEncodedCertReq Malloc Failed\n");
    free(pbNameEncoded);
    free(pbPublicKeyInfo);
    goto handle_error;
}
// Call CryptSignAndEncodeCertificate to get the 
// returned blob.
if(!(CryptSignAndEncodeCertificate(
          hCryptProv,                     // Crypto provider
          AT_SIGNATURE,                   // Key spec.
          MY_ENCODING_TYPE,               // Encoding type
          X509_CERT_REQUEST_TO_BE_SIGNED, // Struct type
          &CertReqInfo,                   // Struct info        
          &SigAlg,                        // Signature algorithm
          NULL,                           // Not used
          pbSignedEncodedCertReq,         // Pointer
          &cbEncodedCertReqSize)))        // Sizeif(!fReturn)
{
    printf("Second call to CryptSignAndEncodeCertificate\n ");
    printf("failed.\n");
    free(pbNameEncoded);
    free(pbPublicKeyInfo);
    free(pbSignedEncodedCertReq);
    goto handle_error;
}
// View the signed and encoded certificate request blob.

pSignedEncodedCertReqBlob = 
                        new char[(cbEncodedCertReqSize *2) +1];
// Call routine to convert the byte blob to ASCII HEX. See the 
// subroutine that follows this code segment.
BytesToStr(cbEncodedCertReqSize,
            pbSignedEncodedCertReq,
            pSignedEncodedCertReqBlob);
// Show the unicode string.
printf("%S\n",pSignedEncodedCertReqBlob);

//---------------------------------------------------------------
// Free memory.
//---------------------------------------------------------------
free(pbNameEncoded);
free(pbPublicKeyInfo);
free(pbSignedEncodedCertReq);
handle_error:
printf("have reached the end.\n");
}


//************************************************************
// BytesToStr() - Converts the bytes into CHAR hex. Needs
// (cb * 2 + 1) * sizeof(CHAR) bytes of space in sz.
//************************************************************
void BytesToStr(DWORD cb, void* pv, LPSTR sz)
{
    
    BYTE* pb = (BYTE*) pv;
int b;
DWORD i;
    for (i = 0; i<cb; i++)
    {
     b = (*pb & 0xF0) >> 4;
        *sz++ = (b <= 9) ? b + '0' : (b - 10) + 'A';
        b = *pb & 0x0F;
        *sz++ = (b <= 9) ? b + '0' : (b - 10) + 'A';
        
        pb++;
    }
    *sz++ = 0;
}