Important:
This is retired content. This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This content may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.
A version of this page is also available for
4/8/2010

This function builds a certificate chain context starting from an end certificate and going back, if possible, to a trusted root certificate. This is the primary API used to verify a certificate against a root store.

Syntax

BOOL WINAPI CertGetCertificateChain(
  HCERTCHAINENGINE 
hChainEngine, 
  PCCERT_CONTEXT 
pCertContext, 
  LPFILETIME 
pTime,
  HCERTSTORE 
hAdditionalStore,
  PCERT_CHAIN_PARA 
pChainPara,
  DWORD 
dwFlags,
  LPVOID 
pvReserved,
  PCCERT_CHAIN_CONTEXT* 
ppChainContext
);

Parameters

hChainEngine

[in] Optional. Handle to the chain engine, which includes name space and cache, to be used. If the value of this parameter is NULL, the default chain engine, HHCE_CURRENT_USER, is used. This parameter can be set to HCCE_LOCAL_MACHINE.

pCertContext

[in] Pointer to the CERT_CONTEXTstructure of the end certificate, the certificate for which a chain is being built. This certificate context will be the element with zero index in the first simple chain.

pTime

[in] Optional. Pointer to a FILETIME variable indicating the time for which the chain is to be validated. Note that the time does not affect root store checking. The current system time is used if NULL is passed to this parameter. Trust in a particular certificate being a trusted root is based on the current state of the root store and not the state of the root store at a time passed in by this parameter.

hAdditionalStore

[in] Handle to any additional store to search for supporting certificates. This parameter can be NULL if no additional store is to be searched.

pChainPara

[in] Pointer to a CERT_CHAIN_PARAstructure that includes chain-building parameters.

dwFlags

[in] Flag values indicating special processing. The CERT_CHAIN_CACHE_END_CERT flag can be used. When this flag is set, the end certificate is cached, which might speed up the chain-building process. By default, the end certificate is not cached and it would need to be verified each time a chain is built for it.

pvReserved

[in] Reserved parameter that must be set to NULL.

ppChainContext

[in] Pointer to a pointer to the chain context created.

Return Value

If the function succeeds, the return value is nonzero, or TRUE.

If the function fails, the return value is zero, or FALSE. For extended error information, call the GetLastErrorfunction.

Remarks

When an application requests a certificate chain, the structure returned is in the form of a CERT_CHAIN_CONTEXTstructure. This context contains an array of CERT_SIMPLE_CHAINstructures where each simple chain goes from an end certificate to a self-signed certificate. Because Windows Embedded CE does not support certificate trust lists, there is only one CERT_SIMPLE_CHAIN in the array. Each simple chain contains the chain of certificates, summary trust information about the chain, and trust information about each certificate element in the chain.

The desktop operating system supports the following dwFlagsflags that Windows Embedded CE does not support:

CERT_CHAIN_REVOCATION_CHECK_END_CERT

CERT_CHAIN_REVOCATION_CHECK_CHAIN

CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT

CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY.

Example Code

This example code demonstrates the use of CertGetCertificateChainto verify a certificate. In addition, it also shows how to verify that the DNS name in the certificate matches the name of the server that is being connected to.

Copy Code
#include <wincrypt.h>
 
DWORD VerifyServerCertificate(
	PCCERT_CONTEXT  pCertContextServer,
	PWSTR		 pwszServerName)
{
	PCCERT_CHAIN_CONTEXT	pChainContext   = NULL;
	CERT_CHAIN_PARA		 ChainPara;
	PCERT_SIMPLE_CHAIN	pSimpleChain;
	PCCERT_CONTEXT		pRootCert;
	WCHAR*				pwszName		= NULL;
	DWORD				 dwErr		 = NO_ERROR;
	DWORD				cchName;
	DWORD				dwTrustErrorMask =
~(CERT_TRUST_IS_NOT_TIME_NESTED|CERT_TRUST_REVOCATION_STATUS_UNKNOWN);
 
	ZeroMemory(&ChainPara, sizeof(ChainPara));
	ChainPara.cbSize = sizeof(ChainPara);
 
	if(!CertGetCertificateChain(
							NULL,
							pCertContextServer,
							NULL,
							pCertContextServer->hCertStore,
							&ChainPara,
							0,
							NULL,
							&pChainContext))
	{
		dwErr = GetLastError();
 
		EapTlsTrace(TEXT("CertGetCertificateChain failed and
returned 0x%x"), dwErr);
		pChainContext = NULL;
		goto LDone;
}
 
	pSimpleChain = pChainContext->rgpChain[0];
 
	dwTrustErrorMask &=
pSimpleChain->TrustStatus.dwErrorStatus;
	if (dwTrustErrorMask)
	{
		if (dwTrustErrorMask & (CERT_TRUST_IS_PARTIAL_CHAIN |
CERT_TRUST_IS_UNTRUSTED_ROOT))
			dwErr = SEC_E_UNTRUSTED_ROOT;
		else if (dwTrustErrorMask &
(CERT_TRUST_IS_NOT_TIME_VALID))
			dwErr = SEC_E_CERT_EXPIRED;
		else
			dwErr = SEC_E_CERT_UNKNOWN;
		goto LDone;
}
	// Compare the DNS name in the certificate with the server.
	dwErr = SEC_E_CERT_UNKNOWN;  // Could be a better error.
	// Get the DNS name from the certificate.

	pwszName = NULL;
	cchName = CertGetNameStringW(pCertContextServer,
						CERT_NAME_DNS_TYPE,
						0,
						NULL,
						NULL,
						0);
	if (cchName > 1)
	{
		pwszName = LocalAlloc(0, sizeof(WCHAR)*cchName);
		if (pwszName)
		{
			cchName = CertGetNameStringW(pCertContextServer,
						CERT_NAME_DNS_TYPE,
						0,
						NULL,
						pwszName,
						cchName);
			if (cchName > 1 && wcsicmp(pwszServerName,
pwszName) == 0)
				dwErr = ERROR_SUCCESS;
	}
}
					
LDone:
 
	if (pChainContext)
	{
		CertFreeCertificateChain(pChainContext);
}
 
	LocalFree(pwszName);
 
	return(dwErr);
}

Requirements

Header wincrypt.h
Library crypt32.lib
Windows Embedded CE Windows CE 3.0 and later
Windows Mobile Windows Mobile Version 5.0 and later

See Also