예제 C 프로그램: 인증서 요청 만들기
다음 예제에서는 이전 섹션에 설명된 절차를 보여 줍니다. 이 예제에서는 하나의 서명자, 단일 RDN(상대 고유 이름) 특성 및 일반 특성이 없는 간단한 인증서 요청을 만듭니다.
이 예제에서는 다음 CryptoAPI 함수를 보여 줍니다.
이 예제에서는 ByteToStr 및 MyHandleError 함수도 사용합니다. 이러한 함수에 대한 코드는 샘플에 포함되어 있습니다. 범용 함수는 이러한 함수 및 기타 보조 함수에 대한 코드를 나열합니다.
//-------------------------------------------------------------------
// 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