Skip to content

Evaluate cache-only URL retrieval by default during Windows TLS credential acquisition #134525

Description

@rzikm

Description

Backlog design decision: should Windows TLS credential acquisition use SCH_CRED_CACHE_ONLY_URL_RETRIEVAL_ON_CREATE by default, preventing synchronous issuer downloads while constructing local credentials?

Consider both SslStream's direct Schannel integration and System.Net.Quic's MsQuic integration. This issue requests an evaluation, not an unconditional behavior change or a claim that the flag has already been validated as a fix.

Schannel documents this flag (0x00020000) as passing CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL to CertGetCertificateChain when validating supplied credentials during AcquireCredentialsHandle.

Reproduction Steps

An artifact-only diagnostic harness used the existing QUIC test PKI generator and responder:

  1. Generate a server leaf, one intermediate, and a root, with AIA URLs served by the local test responder. Keep the generated root untrusted.
  2. Supply only the leaf through QuicServerConnectionOptions.ServerAuthenticationOptions.ServerCertificate.
  3. Configure the responder's existing AIA-only delay hook to wait six seconds per response.
  4. Invoke internal MsQuicConfiguration.Create(serverOptions, "localhost") in isolation, without a QUIC listener or client. This reaches ConfigurationLoadCredential and Schannel credential acquisition.
  5. Compare with a fresh-process/fresh-PKI run that first constructs SslStreamCertificateContext.Create(leaf, issuers, offline: true) and supplies that context.

This is an internal diagnostic recipe, not a public API sample. The committed experiment/runbook in #134418 provides related PKI/provisioning comparisons; the isolated credential-acquisition and fault-injection harness is not part of that PR.

Expected behavior

Decide whether credential acquisition should be cache-only by default, or whether synchronous issuer discovery at this stage is intentional for compatibility.

Evaluation should cover:

  • Whether the creation-specific flag removes AIA requests during acquisition, and whether downloads are merely deferred to the handshake.
  • Behavior with incomplete local chains, what chain is actually presented to the peer, and compatibility for applications currently relying on discovery.
  • Server and client credentials, modern and legacy SslStream Schannel paths, and the MsQuic integration.
  • Preserving peer certificate validation, name checks, trust decisions, revocation policy, and intended OCSP behavior. Cache-only issuer discovery must not be conflated with disabling revocation checks.
  • Whether an opt-out is needed and whether the QUIC change belongs in MsQuic itself or can be correctly expressed through an existing credential flag.

Actual behavior

In the tested leaf-only configuration, isolated server credential acquisition fetched the intermediate and then the root via AIA and took 12,127 ms with the two injected six-second delays. No QUIC client or peer validation was involved.

With a prebuilt offline context and supplied issuers, acquisition made no AIA requests and took 43 ms, after 79 ms of context preconstruction. These are individual diagnostic observations, not benchmark results.

With an actual QUIC connection, the injected delays reproduced the managed ten-second handshake timeout. Supplying only client ExtraStore did not prevent it; prebuilding the server context did. This proves the injected dependency, not the cause of the historical CI failures.

SslStream's equivalent isolated acquisition behavior has not been tested. Source inspection shows that neither its legacy SCHANNEL_CRED nor modern SCH_CREDENTIALS acquisition path sets the creation-specific flag.

Regression?

Unknown. No regression window established.

Known Workarounds

Providing the generated issuer chain through a prebuilt server certificate context eliminated AIA requests in the controlled QUIC experiment. On Windows, context construction can populate the Intermediate Certification Authorities store, so this is not a purely in-memory intervention. Adding the root to that intermediate store does not make it trusted.

This is not evidence that all applications should perform store population as a workaround.

Configuration

Windows 11 build 26100, x64, Schannel; local dotnet/runtime Debug libraries / Release CoreCLR based on commit d4b2951c1fa53ed95aa5bea8ad8e8a0e0a5a2fe7, with the test-only experiment in #134418.

MsQuic 2.5.10.154561281, native commit 9ff06b71fd4b4d5258361598ada5b24cbc1beb20.

Other information

Implementation details to account for:

  • SslStreamPal.Windows.cs does not apply SCH_CRED_CACHE_ONLY_URL_RETRIEVAL_ON_CREATE in either credential-acquisition path.
  • The currently unused declaration in Common/src/Interop/Windows/SspiCli/Interop.SSPI.cs is 0x2000, whereas the documented flag is 0x20000. Correct it before using it; the unused incorrect declaration does not explain the observed requests.
  • In the tested MsQuic revision, the creation-specific flag is defined but not applied. QUIC_CREDENTIAL_FLAG_CACHE_ONLY_URL_RETRIEVAL maps to the distinct SCH_CRED_CACHE_ONLY_URL_RETRIEVAL; its effect on this creation-time repro remains to be measured.
  • MsQuic's DISABLE_AIA handling in that revision configures client-certificate validation policy on the server, rather than restricting acquisition of the server's own credentials.
  • SslStream's System.Net.Security.EnableServerAiaDownloads switch controls managed validation of a remote client certificate, not local credential acquisition.

Related investigation: #133645 and draft experiment #134418. Neither the natural IPv4/name-mismatch selectivity nor a common cause for the managed and native timeout signatures has been established. This issue is not a Known Build Error and should not close that investigation.

Note

This issue was prepared with GitHub Copilot.

Activity

  1. added this to the Future milestone on Sep 23, 2026
  2. dotnet-policy-service commented on Sep 23, 2026

    @dotnet-policy-service
    Contributor

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

  3. self-assigned this
    on Sep 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions