Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use the stapled OCSP response from TLS, when available. #67011

Merged
merged 5 commits into from
Apr 1, 2022

Conversation

bartonjs
Copy link
Member

@bartonjs bartonjs commented Mar 22, 2022

Based on (non-exhaustive) testing, chain builds from a Let's Encrypt issued certificate have
the following characteristics:

  • Live OCSP request required (uncached/unstapled): 577ms
  • OCSP response retrieved from cache (unstapled): 183ms
  • OCSP response utilized from TLS stapling (bypasses cache): 182ms

In both cached and stapled the revocation portion was about 39ms.
(The revocation mode was ExcludeRoot, the CRL pertaining to the intermediate was cached for all three measurements.)

The pattern of carrying the stapled response as extra (behind-the-scenes) data on the certificate is inspired by the Win32 behavior (CERT_OCSP_RESPONSE_PROP_ID).

Contributes to #33377.

Based on (non-exhaustive) testing, chain builds from a Let's Encrypt issued certificate have
the following characteristics:

* Live OCSP request required (uncached/unstapled): 577ms
* OCSP response retrieved from cache (unstapled): 183ms
* OCSP response utilized from TLS stapling (bypasses cache): 182ms

In both cached and stapled the revocation portion was about 39ms.
(The revocation mode was ExcludeRoot, the CRL pertaining to the intermediate was cached for all three measurements.)
@bartonjs bartonjs added this to the 7.0.0 milestone Mar 22, 2022
@bartonjs bartonjs self-assigned this Mar 22, 2022
@ghost
Copy link

ghost commented Mar 22, 2022

Tagging subscribers to this area: @dotnet/area-system-security, @vcsjones
See info in area-owners.md if you want to be subscribed.

Issue Details

Based on (non-exhaustive) testing, chain builds from a Let's Encrypt issued certificate have
the following characteristics:

  • Live OCSP request required (uncached/unstapled): 577ms
  • OCSP response retrieved from cache (unstapled): 183ms
  • OCSP response utilized from TLS stapling (bypasses cache): 182ms

In both cached and stapled the revocation portion was about 39ms.
(The revocation mode was ExcludeRoot, the CRL pertaining to the intermediate was cached for all three measurements.)

Contributes to #33377.

Author: bartonjs
Assignees: bartonjs
Labels:

area-System.Security

Milestone: 7.0.0

static X509VerifyStatusCode CheckOcsp(OCSP_REQUEST* req,
OCSP_RESPONSE* resp,
X509* subject,
X509* issuer,
X509_STORE_CTX* storeCtx,
ASN1_GENERALIZEDTIME** thisUpdate,
ASN1_GENERALIZEDTIME** nextUpdate)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cache policy was repeated across two callers, and almost got repeated to a third. Now it's inside this routine and just expressed via canCache... so no one needs these values any more.

return true;
}

Debug.Assert(resp == 0, $"Unexpected response from X509ChainHasStapledOcsp: {resp}");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the function CryptoNative_X509ChainHasStapledOcsp could return -2? I'd also be nervous about assuming hat the || operator in C++ result in exactly 0 or exactly 1. Per C++, any non-zero value should be interpreted as true.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The -2 is a "something has gone horribly wrong" code. For this particular case it would require that the X509_STORE_CTX value has no associated chain (had never tried chain building, or someone had just reset it), which is pretty unexpected by the time you're calling this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C99 said:

Semantics
3 The == (equal to) and != (not equal to) operators are analogous to the relational
operators except for their lower precedence. 93) Each of the operators yields 1 if the
specified relation is true and 0 if it is false.

and

Semantics
3 The || operator shall yield 1 if either of its operands compare unequal to 0; otherwise, it
yields 0. The result has type int.

So, in C, it seems to be well defined to be 1 or 0. And, if the compiler disagrees, the assert'll start firing 😄

}

// If the dup_func() returns 0 the whole CRYPTO_dup_ex_data() will fail.
// So, return 1 unless we returned 0 already.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what the "unless we returned 0 already" part refers to?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just theoretical future expansion. e.g. if we tried duplicating the g_x509_ocsp_index value it'd be something like *pptr = OCSP_RESPONSE_dup(*pptr); if (*pptr == NULL) { return 0; }

{
// time_t granularity is seconds, so subtract 4 days worth of seconds.
// The 4 day policy is based on the CA/Browser Forum Baseline Requirements
// (version 1.6.3) section 4.9.10 (On-Line Revocation Checking Requirements)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These requirements have changed effective 30 Sep 2020. See https://cabforum.org/wp-content/uploads/CA-Browser-Forum-BR-1.8.2.pdf, Sec. 4.9.10.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new rules are certainly more complicated 😄. In the 1.8.2 version the longest period they allow before informing an OCSP server of a change is still 4 days (Subscriber item 4), so I think it's still a reasonable maximum age cache boundary. We could certainly look at making our window match their current policy later, if you like. (FWIW, this code just moved up. It was originally written Feb 2019)

@bartonjs bartonjs merged commit 57da7d2 into dotnet:main Apr 1, 2022
@ghost ghost locked as resolved and limited conversation to collaborators May 2, 2022
@bartonjs bartonjs added os-linux Linux OS (any supported distro) cryptographic-docs-impact labels Jul 2, 2022
@bartonjs bartonjs deleted the linux_client_stapled_ocsp branch August 19, 2022 18:07
@bartonjs bartonjs added the needs-further-triage Issue has been initially triaged, but needs deeper consideration or reconsideration label Aug 19, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Security needs-further-triage Issue has been initially triaged, but needs deeper consideration or reconsideration os-linux Linux OS (any supported distro)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants