In my program I use CertGetCertificateChain to investigate the validity of certificates. If in my test PKI I revoke a certificate and specify the reason "unspecified", the error code in the last parameter pChainContext->TrustStatus.dwErrorStatus is zero, meaning no error, the certificate is not considered revoked. However, in the Windows Event Log I can see the following entry:

ETW unspecified

So, the revocation and its reason got detected correctly, however CertGetCertificateChain doesn't let me know about it.

If I revoke the certificate with any other reason (e.g. "cessation of operation"), CertGetCertificateChain correctly returns pChainContext->TrustStatus.dwErrorStatus == 4 which means CERT_TRUST_IS_REVOKED and in the Windows Event Log I can see this:

ETW cessation of operation

So my question is: Is this behavior of CertGetCertificateChain correct?

I spent some time researching this and I found this document. In section 6.3.2 (a) it says:

reasons_mask: This variable contains the set of revocation reasons supported by the CRLs and delta CRLs processed so far. The legal members of the set are the possible revocation reason values minus unspecified: keyCompromise, cACompromise, affiliationChanged, superseded, cessationOfOperation, certificateHold, privilegeWithdrawn, and aACompromise. The special value all-reasons is used to denote the set of all legal members. This variable is initialized to the empty set.

(emphasis is mine)

On the other hand, right in the next paragraph 6.3.2 (b) it says:

cert_status: This variable contains the status of the certificate. This variable may be assigned one of the following values: unspecified, keyCompromise, cACompromise, affiliationChanged, superseded, cessationOfOperation, certificateHold, removeFromCRL, privilegeWithdrawn, aACompromise, the special value UNREVOKED, or the special value UNDETERMINED. This variable is initialized to the special value UNREVOKED.

I really have no idea how to interpret this. Does it mean that the described algorithm must not consider the "unspecified" reason as revoked because it's not set in the mask? If so, this would mean that CertGetCertificateChain behaves correctly. But then some followup questions arise: Shouldn't there be some big, all capital, blinking warning along the lines of

"If you revoke a certificate, NEVER EVER choose "unspecified" as reason because otherwise it won't be considered revoked."?

But maybe I'm not reading this correctly, so here are some other blind guesses of mine why CertGetCertificateChain doesn't work like expected:

  • Maybe I need to configure my CRL to support the "unspecified" reason. But I don't see where I can configure that.
  • Do I have to pass some extra flags to CertGetCertificateChain to make it consider the "unspecified" reason? I cannot see any flags that sound suitable...
  • Am I trying to solve a not existing problem? Maybe literally nobody uses the "unspecified" reason and that's why I find so little information about it?

Can anyone shed some light on this?

1 Answer 1


I have literally zero experience with certificate revocation lists, so I may be technically incorrect in some places. This answer is purely based on what I understand from reading the relevant parts of RFC5280.

So my question is: Is this behavior of CertGetCertificateChain correct?

Apparently, yes.

The main reason is simply that you are not supposed to set the reason in the CRL to unspecified. Section 5.3.1 of the RFC says:

however, the reason code CRL entry extension SHOULD be absent instead of using the unspecified (0) reasonCode value.

Concerning your confusion with two apparently contradictory paragraphs of section 6.3.2... these are actually referring to two separate variables used in the CRL processing algorithm:reasons_mask and cert_status.

The reasons_mask variable is meant to contain supported revocation reasons of the CRLs processed so far, and therefore is largely irrelevant to whether the algorithm considers a certificate as revoked or not. If I understood correctly, this variable is used to ensure that in case a CRL has the the onlySomeReasons flag set (which means the CRL only contains revocations for the reasons it specifies), the algorithm will check other CRLs from the certificate issuer to cover other revocation reasons.

The cert_status variable is the one relevant to your question. This variable is intialized to UNREVOKED. When a certificate is checked against a CRL, if an entry is found that matches the certificate issuer and serial number, then cert_status is set using the following rules (from the RFC):

(1) If the reason code CRL entry extension is present, set the cert_status variable to the value of the reason code CRL extension.

(2) If the reason code CRL entry extension is not present, set the cert_status variable to the value unspecified.

So if the reason code CRL entry extension is present, then cert_status is supposed to to be set to the reason which corresponds to the reason code given. However, the unspecified reason code is not valid, so, in your case, Microsoft's implementation probably just leaves cert_status to whatever it already is (in this case UNREVOKED). This results in CertGetCertificateChain considering the certificate valid.

  • I also stumbled over section 5.3.1. However, the choice of the word "should" (rather than "must") plus the wording of the sentences right before your quote ("The reasonCode is a non-critical CRL entry ... CRL issuers are strongly encouraged to include meaningful reason codes") made me believe that the "unspecified" is quite bad as a reason, yet technically OK. But your understanding of the algorithm makes quite some sense to me, so I have to question my interpretation of 5.3.1. I think this is the right answer, but I will wait a little so that others can verify or object your views.
    – sebrockm
    Nov 27, 2020 at 16:21
  • @sebrockm Yes the wording is somewhat confusing. Specifically, messing up a non-critical field shouldn't result in the whole thing failing, but I guess since CRLs are mainly meant to be issued by CAs who are familiar with how these things work, this probably hasn't been a big issue yet.
    – nobody
    Nov 27, 2020 at 19:04

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .