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;
}