Skip to content

Detect ephemeral client cert key via SEC_E_UNKNOWN_CREDENTIALS in QUIC - #132832

Merged
wfurt merged 1 commit into
mainfrom
rzikm/fix-client-certificate-ephemeral-key-tes
Aug 28, 2026
Merged

Detect ephemeral client cert key via SEC_E_UNKNOWN_CREDENTIALS in QUIC#132832
wfurt merged 1 commit into
mainfrom
rzikm/fix-client-certificate-ephemeral-key-tes

Conversation

@rzikm

@rzikm rzikm commented Aug 27, 2026

Copy link
Copy Markdown
Member

Why

System.Net.Quic.Tests.MsQuicTests.Client_CertificateWithEphemeralKey_Throws started failing in CI with a raw:

System.Net.Quic.QuicException : An internal error has occurred. ConfigurationLoadCredential failed: Unknown (0x8009030d)

instead of the expected AuthenticationException whose message contains "ephemeral".

Root cause

The Windows ephemeral-key diagnostic in MsQuicConfiguration only triggers when the native status equals QUIC_STATUS_CERT_NO_CERT, which on Windows maps to SEC_E_NO_CREDENTIALS (0x8009030E). Schannel returns that status for server certificates, but for client certificates with an ephemeral private key it now returns SEC_E_UNKNOWN_CREDENTIALS (0x8009030D). Because the guard did not match 0x8009030D, the ephemeral check was skipped and ThrowHelper.ThrowIfMsQuicError surfaced the raw QuicException (GetErrorMessageForStatus has no name for 0x8009030D, hence the Unknown (0x8009030d) text). The server-side test still returns 0x8009030E, which is why only the client test regressed.

Fix

Broaden the status check to also handle SEC_E_UNKNOWN_CREDENTIALS, reusing the existing Interop.SECURITY_STATUS cast pattern already used a few lines above for AlgorithmMismatch. The block remains gated by certificate.HasPrivateKey() and safeCertContextHandle.HasEphemeralPrivateKey, so any non-ephemeral UnknownCredentials failure falls through to ThrowIfMsQuicError unchanged. No false positives.

The existing Client_CertificateWithEphemeralKey_Throws test is the regression coverage, so no new test is added.

Notes

  • Scope is QUIC only. SslStream (SslStreamPal.Windows.AcquireCredentialsHandle) has an analogous handler that catches only NoCredentials; it is a separate, non-failing code path and intentionally left out of this change.
  • No public API change.
  • The 0x8009030D vs 0x8009030E behavior is dependent on the Windows/Schannel version, so this is validated by CI rather than local runs.

Fixes: #132831

Note

This pull request was authored by GitHub Copilot.

Schannel reports SEC_E_NO_CREDENTIALS (QUIC_STATUS_CERT_NO_CERT, 0x8009030E)
for server certificates but SEC_E_UNKNOWN_CREDENTIALS (0x8009030D) for client
certificates when the private key is ephemeral. The ephemeral-key diagnostic in
MsQuicConfiguration only matched QUIC_STATUS_CERT_NO_CERT, so the client-cert
case surfaced a raw QuicException ("ConfigurationLoadCredential failed:
Unknown (0x8009030d)") instead of the expected AuthenticationException with the
"ephemeral" message, breaking Client_CertificateWithEphemeralKey_Throws.

Broaden the status check to also handle SEC_E_UNKNOWN_CREDENTIALS. The block
remains gated by HasPrivateKey()/HasEphemeralPrivateKey, so non-ephemeral
failures are unaffected.

Fixes #132831

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings August 27, 2026 12:50
@rzikm
rzikm requested a review from a team August 27, 2026 12:50
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Updates the Windows Schannel-specific error handling in System.Net.Quic configuration creation so that client certificates with ephemeral private keys are detected consistently and reported via the existing AuthenticationException path instead of surfacing a raw QuicException status.

Changes:

  • Extends the ephemeral-private-key diagnostic guard to also trigger when ConfigurationLoadCredential fails with SEC_E_UNKNOWN_CREDENTIALS (in addition to the existing QUIC_STATUS_CERT_NO_CERT / SEC_E_NO_CREDENTIALS case).
  • Adds clarifying comments documenting the server-vs-client Schannel status difference for ephemeral keys.
@wfurt

wfurt commented Aug 28, 2026

Copy link
Copy Markdown
Member

/ba-g test failures unrelated

@wfurt
wfurt merged commit 0e38b32 into main Aug 28, 2026
77 of 81 checks passed
@wfurt
wfurt deleted the rzikm/fix-client-certificate-ephemeral-key-tes branch August 28, 2026 17:17
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 12.0-preview1 milestone Aug 29, 2026
@rzikm

rzikm commented Aug 31, 2026

Copy link
Copy Markdown
Member Author

/backport to release/10.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/10.0 (link to workflow run)

@rzikm

rzikm commented Aug 31, 2026

Copy link
Copy Markdown
Member Author

/backport to release/11.0

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0 (link to workflow run)

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

3 participants