Programa C de ejemplo: Crear una cadena de certificados
En el ejemplo siguiente se crea e instala un motor de cadena de certificados no predeterminado. El motor se usa para crear cadenas de certificados para cada uno de los certificados de un almacén de certificados.
En este ejemplo se muestran las siguientes tareas y funciones CryptoAPI :
- Preparación para crear un motor de cadena de certificados no predeterminado declarando e inicializando una estructura de datos CERT_CHAIN_ENGINE_CONFIG .
- Creación del motor de búsqueda mediante CertCreateCertificateChainEngine.
- Usar CertOpenSystemStore para abrir el almacén Mi sistema.
- Recuperar todos los certificados del almacén abierto mediante CertEnumCertificatesInStore en un bucle.
- Para cada certificado del almacén abierto, recuperando el nombre del firmante del certificado mediante CertGetNameString.
- Creación de una cadena de certificados para cada certificado mediante CertGetCertificateChain.
- Creación de un duplicado de la cadena de certificados mediante CertDuplicateCertificateChain.
- Usar CertFreeCertificateChain para liberar cada cadena antes de que se compila la cadena siguiente.
#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