Enabling Secure Business Operations

CertGetCertificateChain: how CERT_CHAIN_TIMESTAMP_TIME actually works

The MSDN documentation for CertGetCertificateChain is pretty unclear when describing how the CERT_CHAIN_TIMESTAMP_TIME flag relates to the pTime parameter. The documentation for the function can be found here.

The pTime parameter is described like this:

A pointer to a FILETIME variable that indicates the time for which the chain is to be validated. Note that the time does not affect trust list, revocation, or 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. For revocation, a certificate revocation list (CRL), itself, must be valid at the current time. The value of this parameter is used to determine whether a certificate listed in a CRL has been revoked.

The value of CERT_CHAIN_TIMESTAMP_TIME is explained like this:

When this flag is set, pTime is used as the time stamp time to determine whether the end certificate was time valid. Current time can also be used to determine whether the end certificate remains time valid. All other certification authority (CA) and root certificates in the chain are checked by using current time and not pTime.

So, it would appear that when you pass in a timestamp in the pTime parameter with the CERT_CHAIN_TIMESTAMP_TIME, the chain would check the time-validity of the end certificate using the time that was passed into the function. But, this isn’t the case; in fact, that is the behavior that is exhibited when you don’t specify CERT_CHAIN_TIMESTAMP_TIME. What this flag actually does is set a requirement that the end user certificate is time-valid at both the pTime parameter as well as the current time. (This behavior was started by the MS04-011 patch. The function used to work the way you would think that it would, based on the documentation and the name of the constant). Think of it this way: the flag would make more sense were it named CERT_CHAIN_TIMESTAMP_AND_CURRENT_TIME.

Another thing to note is that the pTime parameter will only affect checking the time-validity of the end certificate in the chain; it is completely ignored when validating intermediate and root certificates, as well as during revocation checking. CAPI doesn’t have much support for verification of old signatures, mainly due to a lack of support for RFC3161 timestamps. Without secure timestamps, there is no standards-compliant way to validate older signatures, and therefore the current trust and revocation information is the only information that is useful for certificate validation.

If you want to do things in a non-standard way, you have to code around the limitations of the API – just realize that what you’re doing probably isn’t going to be all that secure. Certificates and revocation information expire for a reason.

For more information about validating aging digital signatures, see my white paper titled “Long Term Digital Signatures”, available on the Gemini Security Solutions web site.

Leave a Reply