Skip to content

Conversation

@bartonjs
Copy link
Member

Introduce an extra layer of caching for CRLs.

  • The cache has a fixed size of 30 elements. When full, it evicts the least-recently-used entry.
  • Using the same finalizable object sentinel approach as ArrayPool, the cache will purge entries every time the GC finalizes.
    • During a finalize, the current MRU node is marked as what to purge next time.
      • Using that node moves the purge target to the next-older entry before the node is promoted back to MRU.
    • On the subsequent finalize, the marked node (and everything after it) are purged.
  • To avoid finalizing the CRL SafeHandles, the cache does an AddReference on every item that is returned (so the caller must Release it), and it calls Dispose on anything it evicts.

This implementation ignores any finalizations that happen in the first minute of the sentinel object's life, to allow the object a chance to get into Gen2 before hyper-eagerly evicting things.

@bartonjs bartonjs added this to the 11.0.0 milestone Jan 23, 2026
@bartonjs bartonjs self-assigned this Jan 23, 2026
Copilot AI review requested due to automatic review settings January 23, 2026 20:14
@dotnet-policy-service
Copy link
Contributor

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

@bartonjs
Copy link
Member Author

Testing with a cert that has a large CRL, revocation-enabled chain building is significantly reduced. This is from building a chain 5 times in a row, the last build:

Before:

2026-01-23T19:52:47.746Z: ChainStart - Starting X.509 chain build.
2026-01-23T19:52:47.748Z: FindFirstChainFinished - First build finished with status 0.
2026-01-23T19:52:47.748Z: RevocationCheckStart - Starting revocation check in mode 'Online' with scope 'ExcludeRoot' on a 3-element chain.
2026-01-23T19:52:47.748Z: CrlIdentifiersDetermined - Certificate 'CN=*.redis.cache.windows.net, O=Microsoft Corporation, L=Redmond, S=WA, C=US' has a CRL Distribution Point of 'http://www.microsoft.com/pkiops/crl/Microsoft%20Azure%20RSA%20TLS%20Issuing%20CA%2004.crl', will use '093932f7.a38db5b0.crl' as the cache file.
2026-01-23T19:52:47.748Z: CrlCacheCheckStart - Checking for a cached CRL.
2026-01-23T19:52:48.123Z: CrlCacheAcceptedFile - The cached crl nextUpdate value (2026-01-28T14:33:08.0000000-08:00) is acceptable, using the cached file.
2026-01-23T19:52:48.123Z: CrlCacheCheckStop - Duration 374.733ms
2026-01-23T19:52:48.123Z: CrlIdentifiersDetermined - Certificate 'CN=Microsoft Azure RSA TLS Issuing CA 04, O=Microsoft Corporation, C=US' has a CRL Distribution Point of 'http://crl3.digicert.com/DigiCertGlobalRootG2.crl', will use '607986c7.8ab5229e.crl' as the cache file.
2026-01-23T19:52:48.123Z: CrlCacheCheckStart - Checking for a cached CRL.
2026-01-23T19:52:48.123Z: CrlCacheAcceptedFile - The cached crl nextUpdate value (2026-02-09T09:43:56.0000000-08:00) is acceptable, using the cached file.
2026-01-23T19:52:48.123Z: CrlCacheCheckStop - Duration 0.225ms
2026-01-23T19:52:48.224Z: CrlChainFinished - With CRLs applied, the chain build finished with status 0.
2026-01-23T19:52:48.224Z: RevocationCheckStop - Duration 476.439ms
2026-01-23T19:52:48.358Z: ChainStop - Duration 611.607ms

After:

2026-01-23T19:53:24.099Z: ChainStart - Starting X.509 chain build.
2026-01-23T19:53:24.101Z: FindFirstChainFinished - First build finished with status 0.
2026-01-23T19:53:24.101Z: RevocationCheckStart - Starting revocation check in mode 'Online' with scope 'ExcludeRoot' on a 3-element chain.
2026-01-23T19:53:24.101Z: CrlIdentifiersDetermined - Certificate 'CN=*.redis.cache.windows.net, O=Microsoft Corporation, L=Redmond, S=WA, C=US' has a CRL Distribution Point of 'http://www.microsoft.com/pkiops/crl/Microsoft%20Azure%20RSA%20TLS%20Issuing%20CA%2004.crl', will use '093932f7.a38db5b0.crl' as the cache file.
2026-01-23T19:53:24.101Z: CrlCacheInMemoryHit - The in-memory CRL cache has a valid entry for the requested CRL, expiration at 2026-01-28T14:33:08.0000000-08:00.
2026-01-23T19:53:24.101Z: CrlIdentifiersDetermined - Certificate 'CN=Microsoft Azure RSA TLS Issuing CA 04, O=Microsoft Corporation, C=US' has a CRL Distribution Point of 'http://crl3.digicert.com/DigiCertGlobalRootG2.crl', will use '607986c7.8ab5229e.crl' as the cache file.
2026-01-23T19:53:24.101Z: CrlCacheInMemoryHit - The in-memory CRL cache has a valid entry for the requested CRL, expiration at 2026-02-09T09:43:56.0000000-08:00.
2026-01-23T19:53:24.122Z: CrlChainFinished - With CRLs applied, the chain build finished with status 0.
2026-01-23T19:53:24.122Z: RevocationCheckStop - Duration 21.174ms
2026-01-23T19:53:24.122Z: ChainStop - Duration 22.639ms

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces an in-memory LRU cache layer for Certificate Revocation Lists (CRLs) on Linux to improve performance by reducing disk I/O. The cache sits between the caller and the existing disk cache, with a fixed capacity of 30 entries that evicts least-recently-used items when full. The implementation uses a GC-based pruning mechanism similar to ArrayPool, where a finalizable sentinel object triggers periodic cache cleanup to manage memory pressure.

Changes:

  • Added 5 new event source events for tracking in-memory cache hits, misses, expiration, pruning, and capacity events
  • Updated existing event messages to clarify they refer to disk cache operations
  • Implemented MruCrlCache class with thread-safe LRU eviction, reference counting via DangerousAddRef/DangerousRelease, and GC-triggered pruning
  • Refactored CRL loading to check in-memory cache first, then disk cache, then download
  • Added proper SafeHandle management to prevent premature finalization during cache operations

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 12 comments.

File Description
OpenSslX509ChainEventSource.cs Added 5 new event IDs and methods for in-memory cache telemetry; updated existing event messages to distinguish disk cache operations
OpenSslCrlCache.cs Added MruCrlCache class implementing thread-safe LRU cache with GC-based pruning; refactored CRL loading logic to check memory cache before disk; added proper SafeHandle reference management

@grbell-ms
Copy link
Member

This implementation ignores any finalizations that happen in the first minute of the sentinel object's life, to allow the object a chance to get into Gen2 before hyper-eagerly evicting things.

Might be simpler to check directly with GC.GetGeneration

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants