Note

Access to this page requires authorization. You can try signing in or .

Access to this page requires authorization. You can try .

Example C Program: Making a Certificate Request

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

This example illustrates the following CryptoAPI functions:

This example also uses the functions ByteToStr and MyHandleError. Code for these functions is included with the sample. General Purpose Functions lists code for these and other auxiliary functions.

//-------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// This example demonstrates how to create and encode a 
// certificate request. 
#pragma comment(lib, "crypt32.lib")

#include <stdio.h>
#include <windows.h>
#include <Wincrypt.h>
#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
void MyHandleError(char *s);

//-------------------------------------------------------------------
// This program use this additional #define statement. 

#define CERT_SUBJECT_NAME "This certificate user"

//-------------------------------------------------------------------
// This program uses the function ByteToStr to convert an array
// of BYTEs to a char string. 

void ByteToStr(
 DWORD cb, 
 void* pv, 
 LPSTR sz)
//-------------------------------------------------------------------
// Parameters passed are:
// pv is the array of BYTEs to be converted.
// cb is the number of BYTEs in the array.
// sz is a pointer to the string to be returned.

{
//-------------------------------------------------------------------
// Declare and initialize local variables.

BYTE* pb = (BYTE*) pv; // local pointer to a BYTE in the BYTE array
DWORD i; // local loop counter
int b; // local variable

//-------------------------------------------------------------------
// Begin processing loop.

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

void main(void)
{
//-------------------------------------------------------------------
// Declare and initialize variables 

// 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

//-------------------------------------------------------------------
// Declare and initialize 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

//-------------------------------------------------------------------
// Declare and initialize a CERT_NAME_INFO structure.

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

//-------------------------------------------------------------------
// Declare and initialize all other variables and structures.

CERT_REQUEST_INFO CertReqInfo;
CERT_NAME_BLOB SubjNameBlob;
DWORD cbNameEncoded;
BYTE* pbNameEncoded;
HCRYPTPROV hCryptProv;
DWORD cbPublicKeyInfo;
CERT_PUBLIC_KEY_INFO* pbPublicKeyInfo;
DWORD cbEncodedCertReqSize;
CRYPT_OBJID_BLOB Parameters;
CRYPT_ALGORITHM_IDENTIFIER SigAlg;
BYTE* pbSignedEncodedCertReq;
char* pSignedEncodedCertReqBlob;

//-------------------------------------------------------------------
// Begin processing.

if(CryptEncodeObject(
 MY_ENCODING_TYPE, // Encoding type
 X509_NAME, // Structure type
 &Name, // Address of CERT_NAME_INFO structure
 NULL, // pbEncoded
 &cbNameEncoded)) // pbEncoded size
{
 printf("The first call to CryptEncodeObject succeeded. \n");
}
else
{
 MyHandleError("The first call to CryptEncodeObject failed. \n" 
 "A public/private key pair may not exit in the container. \n");
}
//-------------------------------------------------------------------
// Allocate memory for the encoded name.

if(!(pbNameEncoded = (BYTE*)malloc(cbNameEncoded)))
 MyHandleError("The pbNamencoded malloc operation failed. \n");

//-------------------------------------------------------------------
// Call CryptEncodeObject to do the actual encoding of the name.

if(CryptEncodeObject(
 MY_ENCODING_TYPE, // Encoding type
 X509_NAME, // Structure type
 &Name, // Address of CERT_NAME_INFO structure
 pbNameEncoded, // pbEncoded
 &cbNameEncoded)) // pbEncoded size
{
 printf("The object is encoded. \n");
}
else
{
 free(pbNameEncoded);
 MyHandleError("The second call to CryptEncodeObject failed. \n");
}
//-------------------------------------------------------------------
// Set the subject member of CertReqInfo to point to 
// a CERT_NAME_INFO structure that 
// has been initialized with the data from cbNameEncoded
// and pbNameEncoded.

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.
// First, 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 both encrypt and sign.
 NULL)) // No flags needed.
{
 printf("A cryptographic provider has been acquired. \n");
}
else
{
 free(pbNameEncoded);
 MyHandleError("CryptAcquireContext failed. \n");
}
//-------------------------------------------------------------------
// 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("The keyinfo structure is %d bytes. \n",cbPublicKeyInfo);
}
else
{
 free(pbNameEncoded);
 MyHandleError("The first call to CryptExportPublickKeyInfo failed. \n"
 "The probable cause is that \n"
 "there is no key pair in the key container. \n");
}
//-------------------------------------------------------------------
// Allocate the necessary memory.

if(pbPublicKeyInfo = 
 (CERT_PUBLIC_KEY_INFO*)malloc(cbPublicKeyInfo))
{
 printf("Memory is allocated for the public key structure. \n");
}
else
{
 free(pbNameEncoded);
 MyHandleError("Memory allocation failed. \n");
}
//-------------------------------------------------------------------
// 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("The key has been exported. \n");
}
else
{
 free(pbNameEncoded);
 free(pbPublicKeyInfo);
 MyHandleError("The second call to CryptExportPublicKeyInfo failed. \n");
}
//-------------------------------------------------------------------
// Set the SubjectPublicKeyInfo member of the 
// CERT_REQUEST_INFO structure to point to the CERT_PUBLIC_KEY_INFO 
// structure created.

CertReqInfo.SubjectPublicKeyInfo = *pbPublicKeyInfo;

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

//-------------------------------------------------------------------
// Call CryptSignAndEncodeCertificate to get the size of the
// returned BLOB. The dwKeySpec argument should match the KeySpec
// (AT_SIGNATURE or AT_KEYEXCHANGE) used to create the private
// key. Here, AT_KEYEXCHANGE is assumed.

if(CryptSignAndEncodeCertificate(
 hCryptProv, // Crypto provider
 AT_KEYEXCHANGE, // Key spec
 MY_ENCODING_TYPE, // Encoding type
 X509_CERT_REQUEST_TO_BE_SIGNED, // Structure type
 &CertReqInfo, // Structure information
 &SigAlg, // Signature algorithm
 NULL, // Not used
 NULL, // pbSignedEncodedCertReq
 &cbEncodedCertReqSize)) // Size of certificate 
 // required
{
 printf("The size of the encoded certificate is set. \n");
}
else
{
 free(pbNameEncoded);
 free(pbPublicKeyInfo);
 MyHandleError("First call to CryptSignandEncode failed. \n");
}
//-------------------------------------------------------------------
// Allocate memory for the encoded certificate request.

if(pbSignedEncodedCertReq = (BYTE*)malloc(cbEncodedCertReqSize))
{
 printf("Memory has been allocated.\n");
}
else
{
 free(pbNameEncoded);
 free(pbPublicKeyInfo);
 MyHandleError("The malloc operation failed. \n");
}
//-------------------------------------------------------------------
// Call CryptSignAndEncodeCertificate to get the 
// returned BLOB.

if(CryptSignAndEncodeCertificate(
 hCryptProv, // Crypto provider
 AT_KEYEXCHANGE, // 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)) // Length of the message
{
 printf("The message is encoded and signed. \n");
}
else
{
 free(pbNameEncoded);
 free(pbPublicKeyInfo);
 free(pbSignedEncodedCertReq);
 MyHandleError("The second call to CryptSignAndEncode failed. \n");
}
//-------------------------------------------------------------------
// View the signed and encoded certificate request BLOB.

pSignedEncodedCertReqBlob = 
 new char[(cbEncodedCertReqSize *2) +1];

//-------------------------------------------------------------------
// Call ByteToStr, one of the general purpose functions, to convert 
// the byte BLOB to ASCII hexadecimal format. 

ByteToStr(cbEncodedCertReqSize,
 pbSignedEncodedCertReq,
 pSignedEncodedCertReqBlob);

//-------------------------------------------------------------------
// Print the string.
printf("The string created is: \n");
printf("%s\n",pSignedEncodedCertReqBlob);

//-------------------------------------------------------------------
// Free memory.

free(pbNameEncoded);
free(pbPublicKeyInfo);
free(pbSignedEncodedCertReq);
CryptReleaseContext(hCryptProv,0);

printf("\nMemory freed. Program ran without error. \n");
} // End of main

//-------------------------------------------------------------------
// This example uses the function MyHandleError, a simple error
// handling function, to print an error message to 
// the standard error (stderr) file and exit the program. 
// For most applications, replace this function with one 
// that does more extensive error reporting.

void MyHandleError(char *s)
{
 fprintf(stderr,"An error occurred in running the program. \n");
 fprintf(stderr,"%s\n",s);
 fprintf(stderr, "Error number %x.\n", GetLastError());
 fprintf(stderr, "Program terminating. \n");
 exit(1);
} // End of MyHandleError

Feedback

Was this page helpful?

Additional resources