CertGetCertificateChain (Compact 2013)

3/28/2014

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_CONTEXT structure 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_PARA structure 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 GetLastError function.

Remarks

When an application requests a certificate chain, the structure returned is in the form of a CERT_CHAIN_CONTEXT structure. This context contains an array of CERT_SIMPLE_CHAIN structures where each simple chain goes from an end certificate to a self-signed certificate. Because Windows Embedded Compact 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 dwFlags flags that Windows Embedded Compact 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 CertGetCertificateChain to 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.

#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

See Also

Reference

Certificates Functions
CertFreeCertificateChain
CertDuplicateCertificateChain
CERT_CHAIN_CONTEXT
CERT_CHAIN_PARA
CERT_CONTEXT
CERT_SIMPLE_CHAIN