예제 C 프로그램: 인증서 체인 만들기
다음 예제에서는 기본이 아닌 인증서 체인 엔진을 만들고 설치합니다. 엔진은 인증서 저장소의 각 인증서에 대한 인증서 체인을 빌드하는 데 사용됩니다.
이 예제에서는 다음 작업 및 CryptoAPI 함수를 보여 줍니다.
- CERT_CHAIN_ENGINE_CONFIG 데이터 구조를 선언하고 초기화하여 기본이 아닌 인증서 체인 엔진 만들기 준비
- CertCreateCertificateChainEngine을 사용하여 검색 엔진을 만듭니다.
- CertOpenSystemStore를 사용하여 내 시스템 저장소를 엽니다.
- 루프에서 CertEnumCertificatesInStore 를 사용하여 열려 있는 저장소에서 모든 인증서를 검색합니다.
- 열려 있는 저장소의 각 인증서에 대해 CertGetNameString을 사용하여 인증서에서 주체 이름을 검색합니다.
- CertGetCertificateChain을 사용하여 각 인증서에 대한 인증서 체인을 빌드합니다.
- CertDuplicateCertificateChain을 사용하여 인증서 체인의 중복을 만듭니다.
- CertFreeCertificateChain을 사용하여 다음 체인이 빌드되기 전에 각 체인을 해제합니다.
#pragma comment(lib, "crypt32.lib")
#include <stdio.h>
#include <windows.h>
#include <Wincrypt.h>
void MyHandleError(char *s);
void main(void)
{
//---------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Declare and initialize variables.
HCERTCHAINENGINE hChainEngine;
CERT_CHAIN_ENGINE_CONFIG ChainConfig;
PCCERT_CHAIN_CONTEXT pChainContext;
PCCERT_CHAIN_CONTEXT pDupContext;
HCERTSTORE hCertStore;
PCCERT_CONTEXT pCertContext = NULL;
CERT_ENHKEY_USAGE EnhkeyUsage;
CERT_USAGE_MATCH CertUsage;
CERT_CHAIN_PARA ChainPara;
DWORD dwFlags=0;
LPWSTR pszNameString;
//---------------------------------------------------------
// Initialize data structures.
if(!(pszNameString=(LPWSTR)malloc(256)))
MyHandleError("Memory allocation failed.");
EnhkeyUsage.cUsageIdentifier = 0;
EnhkeyUsage.rgpszUsageIdentifier=NULL;
CertUsage.dwType = USAGE_MATCH_TYPE_AND;
CertUsage.Usage = EnhkeyUsage;
ChainPara.cbSize = sizeof(CERT_CHAIN_PARA);
ChainPara.RequestedUsage=CertUsage;
ChainConfig.cbSize = sizeof(CERT_CHAIN_ENGINE_CONFIG);
ChainConfig.hRestrictedRoot= NULL ;
ChainConfig.hRestrictedTrust= NULL ;
ChainConfig.hRestrictedOther= NULL ;
ChainConfig.cAdditionalStore=0 ;
ChainConfig.rghAdditionalStore = NULL ;
ChainConfig.dwFlags = CERT_CHAIN_CACHE_END_CERT;
ChainConfig.dwUrlRetrievalTimeout= 0 ;
ChainConfig.MaximumCachedCertificates=0 ;
ChainConfig.CycleDetectionModulus = 0;
//---------------------------------------------------------
// Create the nondefault certificate chain engine.
if(CertCreateCertificateChainEngine(
&ChainConfig,
&hChainEngine))
{
printf("A chain engine has been created.\n");
}
else
{
MyHandleError("The engine creation function failed.");
}
// Open the My system store.
if(hCertStore=CertOpenSystemStore(NULL,L"MY"))
{
printf("The MY Store is open.\n");
}
else
{
MyHandleError("The MY system store did not open.");
}
//-------------------------------------------------------
// Loop through the certificates in the store,
// and create a chain for each.
while(pCertContext = CertEnumCertificatesInStore(
hCertStore,
pCertContext))
{
//-------------------------------------------------------------------
// Get and display the name of subject of the certificate.
if(CertGetNameString(
pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
0,
NULL,
pszNameString,
128))
{
printf("\nCertificate for %s found.\n",pszNameString);
}
else
{
MyHandleError("CertGetName failed.");
}
//-------------------------------------------------------------------
// Build a chain using CertGetCertificateChain
// and the certificate retrieved.
if(CertGetCertificateChain(
NULL, // use the default chain engine
pCertContext, // pointer to the end certificate
NULL, // use the default time
NULL, // search no additional stores
&ChainPara, // use AND logic and enhanced key usage
// as indicated in the ChainPara
// data structure
dwFlags,
NULL, // currently reserved
&pChainContext)) // return a pointer to the chain created
{
printf("The chain has been created. \n");
}
else
{
MyHandleError("The chain could not be created.");
}
//---------------------------------------------------------------
// Display some of the contents of the chain.
printf("The size of the chain context "
"is %d. \n",pChainContext->cbSize);
printf("%d simple chains found.\n",pChainContext->cChain);
printf("\nError status for the chain:\n");
DWORD errorStatus = pChainContext->TrustStatus->dwErrorStatus;
if((errorStatus & CERT_TRUST_IS_NOT_TIME_VALID) != 0)
{
printf("This certificate or one of the certificates in the "
"certificate chain is not time-valid.\n");
}
if((errorStatus & CERT_TRUST_IS_REVOKED) != 0)
{
printf("Trust for this certificate or one of the certificates "
"in the certificate chain has been revoked.\n");
}
if((errorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID) != 0)
{
printf("The certificate or one of the certificates in the "
"certificate chain does not have a valid signature.\n");
}
if((errorStatus & CERT_TRUST_IS_NOT_VALID_FOR_USAGE) != 0)
{
printf("The certificate or certificate chain is not valid "
"in its proposed usage.\n");
}
if((errorStatus & CERT_TRUST_IS_UNTRUSTED_ROOT) != 0)
{
printf("The certificate or certificate chain is based "
"on an untrusted root.\n");
}
if((errorStatus & CERT_TRUST_REVOCATION_STATUS_UNKNOWN) != 0)
{
printf("The revocation status of the certificate or one of the"
"certificates in the certificate chain is unknown.\n");
}
if((errorStatus & CERT_TRUST_IS_CYCLIC) != 0)
{
printf("One of the certificates in the chain was issued by a "
"certification authority that the original certificate "
"had certified.\n");
}
if((errorStatus & CERT_TRUST_IS_PARTIAL_CHAIN) != 0)
{
printf("The certificate chain is not complete.\n");
}
if((errorStatus & CERT_TRUST_CTL_IS_NOT_TIME_VALID) != 0)
{
printf("A CTL used to create this chain was not time-valid.\n");
}
if((errorStatus & CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID) != 0)
{
printf("A CTL used to create this chain did not have a valid "
"signature.\n");
}
if((errorStatus & CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE) != 0)
{
printf("A CTL used to create this chain did not have a valid "
"signature.\n");
}
else // CERT_TRUST_NO_ERROR
{
printf("No error found for this certificate or chain.\n");
}
printf("\nInfo status for the chain:\n");
DWORD infoStatus = pChainContext->TrustStatus.dwInfoStatus;
if((infoStatus & CERT_TRUST_HAS_EXACT_MATCH_ISSUER) != 0)
{
printf("An exact match issuer certificate has been found for "
"this certificate.\n");
}
if((infoStatus & CERT_TRUST_HAS_KEY_MATCH_ISSUER) != 0)
{
printf("A key match issuer certificate has been found for this "
"certificate.\n");
}
if((infoStatus & CERT_TRUST_HAS_NAME_MATCH_ISSUER) != 0)
{
printf("A name match issuer certificate has been found for this "
"certificate.\n");
}
if((infoStatus & CERT_TRUST_IS_SELF_SIGNED) != 0)
{
printf("This certificate is self-signed.\n");
}
if((infoStatus & CERT_TRUST_IS_COMPLEX_CHAIN) != 0)
{
printf("The certificate chain created is a complex chain.\n");
}
else // No dwInfoStatus bits set
{
printf("No information status reported.\n");
}
//-------------------------------------------------------------------
// Duplicate the original chain.
if(pDupContext = CertDuplicateCertificateChain(
pChainContext ))
{
printf("Duplicated the chain.\n");
}
else
{
printf("Duplication failed.\n");
}
//-------------------------------------------------------------------
// Free both chains.
CertFreeCertificateChain(pDupContext);
printf("The duplicate chains is free.\n");
CertFreeCertificateChain(pChainContext);
printf("The Original chain is free.\n");
printf("\nPress Enter to continue.");
getchar();
} // end while loop
printf("\nThere are no more certificates in the store. \n");
//---------------------------------------------------------
// Free the chain engine.
CertFreeCertificateChainEngine(hChainEngine);
printf("The chain engine has been released.\n");
// Free memory for pszNameString.
if(pszNameString)
free(pszNameString);
printf("The demo program ran to completion without error.\n");
} // end main
//-------------------------------------------------------------------
// This example uses the function MyHandleError, a simple error
// handling function to print an error message 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 MyHandleError