{"id":155,"date":"2012-07-02T07:17:35","date_gmt":"2012-07-02T15:17:35","guid":{"rendered":"http:\/\/unmitigatedrisk.com\/?p=155"},"modified":"2012-07-02T08:49:18","modified_gmt":"2012-07-02T16:49:18","slug":"cryptoapi-revocation-checking-ocsp-and-the-unknown-certstatus","status":"publish","type":"post","link":"https:\/\/unmitigatedrisk.com\/?p=155","title":{"rendered":"CryptoAPI, Revocation checking, OCSP and the Unknown certStatus"},"content":{"rendered":"<p>In CryptoAPI one can use the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/aa376078(v=vs.85).aspx\">CertGetCertificateChain<\/a> API to do the path building and basic chain validation, this validation may include revocation checking depending on which flags you pass via dwFlags; for example these flags control if revocation checking occurs, and if so, on which certificates:<\/p>\n<ul>\n<li>CERT_CHAIN_REVOCATION_CHECK_END_CERT<\/li>\n<li>CERT_CHAIN_REVOCATION_CHECK_CHAIN<\/li>\n<li>CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT<\/li>\n<\/ul>\n<p>Typically you would specify CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT which ensures the whole chain is checked (where possible \u2013 e.g. one shouldn\u2019t bother asking the root if he considers himself revoked).<\/p>\n<p>But in the context of OCSP what are the potential revocation related returns we might see?<\/p>\n<ol>\n<li><strong>Revoked<\/strong> \u2013 I have received a signed response from the CA or have had policy pushed to me that tells me that this certificate is not to be trusted.<\/li>\n<li><strong>Not Revoked<\/strong> \u2013 I have received a signed response from the CA that says this certificate was not revoked.<\/li>\n<li><strong>Unknown<\/strong> \u2013 I have received signed response from the CA that says it doesn\u2019t know anything about this certificate.<\/li>\n<li><strong>Offline<\/strong> \u2013 I was unable to reach the responder to verify the status of the certificate.<\/li>\n<\/ol>\n<p>Each of these cases are clearly represented in the API that is used by <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/aa376078(v=vs.85).aspx\">CertGetCertificateChain<\/a> to perform the revocation check, this API is <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/aa377167(v=vs.85).aspx\">CertVerifyRevocation<\/a>. The higher level <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/aa376078(v=vs.85).aspx\">CertGetCertificateChain<\/a> however only <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/aa377519(v=vs.85).aspx\">has two possible returns: Revoked and Unknown<\/a>\u00a0outside the &#8220;not revoked&#8221; case.<\/p>\n<p>One might assume the OCSP Unknown would get mapped into the Revoked state, this unfortunately is not the case, it is returned as unknown, as does the Offline error.<\/p>\n<p>This means that if OCSP was used you cannot tell what the actual status was, this is especially problematic since IE and Chrome both default to modes where they ignore \u201cUnknown\u201d revocations due to concerns over Revocation responder performance and reliability.<\/p>\n<p>It is possible to work around this platform behavior though &#8212; the problem is that it\u2019s not documented anywhere, let\u2019s take a quick stab at doing that here.<\/p>\n<p>First since <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/aa376078(v=vs.85).aspx\">CertGetCertificateChain<\/a> doesn\u2019t tell us what method was used to do revocation checking we have to use heuristics to figure it out. Thankfully to enable OCSP stapling in higher level protocols like TLS the OCSP response is passed back to the caller if OCSP was used; to get that we need to know:<\/p>\n<p>1. The <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/aa377183(v=vs.85).aspx\">CERT_CHAIN_ELEMENT<\/a> in the returned <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/aa377182(v=vs.85).aspx\">CHAIN_CONTEXT<\/a>\u00a0points to the following revocation information:<\/p>\n<ul>\n<li>PCERT_REVOCATION_INFO pRevocationInfo;<\/li>\n<li>PCERT_REVOCATION_CRL_INFO\u00a0\u00a0 pCrlInfo;<\/li>\n<li>PCCRL_CONTEXT\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 pBaseCrlContext;<\/li>\n<\/ul>\n<p>2.\u00a0For an OCSP response, the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/aa379873(v=vs.85).aspx\">CRL_CONTEXT<\/a>\u00a0is specially created to contain the full OCSP response in the following critical extension szOID_PKIX_OCSP_BASIC_SIGNED_RESPONSE.<\/p>\n<ul>\n<li>The presence of this extension indicates an OCSP response was used.<\/li>\n<li>The Issuer name in the CRL is the name of the OCSP signer.<\/li>\n<li>The signature algorithm is sha1NoSign.<\/li>\n<li>ThisUpdate and NextUpdate contain the response validity period.<\/li>\n<\/ul>\n<p>With this we can take the OCSP response from the CRL_CONTEXT and then look at the \u201c<a href=\"file:\/\/\/C:\/Users\/rmh\/Desktop\/ResponseData\">ResponseData<\/a>\u201d within it, you will need to look within the \u201cresponses\u201d here,\u00a0 you will need to find the right \u201cSingleResponse\u201d based on its \u201cCertID\u201d.<\/p>\n<p style=\"padding-left: 30px;\"><strong><em>NOTE<\/em><\/strong><em>: Some responders will return the status of multiple certificates in a response even if the status of only one was requested.<\/em><\/p>\n<p>You now can determine what the responder said the status of the certificate was by inspecting \u201ccertStatus\u201d element.<\/p>\n<p>This is a fair amount of work unfortunately but it does enable you to do the right thing with authoritative \u201cUnknown\u201d responses.<\/p>\n<p>Ryan<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In CryptoAPI one can use the CertGetCertificateChain API to do the path building and basic chain validation, this validation may include revocation checking depending on which flags you pass via dwFlags; for example these flags control if revocation checking occurs, and if so, on which certificates: CERT_CHAIN_REVOCATION_CHECK_END_CERT CERT_CHAIN_REVOCATION_CHECK_CHAIN CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT Typically you would specify CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT which [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"footnotes":""},"categories":[12,3,4],"tags":[36,17,25,24],"class_list":["post-155","post","type-post","status-publish","format-standard","hentry","category-programming","category-security","category-thoughts","tag-cryptoapi","tag-microsoft","tag-ocsp","tag-revocation"],"_links":{"self":[{"href":"https:\/\/unmitigatedrisk.com\/index.php?rest_route=\/wp\/v2\/posts\/155","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/unmitigatedrisk.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/unmitigatedrisk.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/unmitigatedrisk.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/unmitigatedrisk.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=155"}],"version-history":[{"count":0,"href":"https:\/\/unmitigatedrisk.com\/index.php?rest_route=\/wp\/v2\/posts\/155\/revisions"}],"wp:attachment":[{"href":"https:\/\/unmitigatedrisk.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=155"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/unmitigatedrisk.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=155"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/unmitigatedrisk.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=155"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}