Skip to content

[release/11.0] Detect ephemeral client cert key via SEC_E_UNKNOWN_CREDENTIALS in QUIC - #132975

Merged
akoeplinger merged 1 commit into
release/11.0from
backport/pr-132832-to-release/11.0
Sep 2, 2026
Merged

[release/11.0] Detect ephemeral client cert key via SEC_E_UNKNOWN_CREDENTIALS in QUIC#132975
akoeplinger merged 1 commit into
release/11.0from
backport/pr-132832-to-release/11.0

Conversation

@github-actions

@github-actions github-actions Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Backport of #132832 to release/11.0

/cc @rzikm

Customer Impact

  • Customer reported
  • Found internally

A recent update in MsQuic changed an error code returned when applicaiton attempted to use certificates with ephemeral keys (Windows-only concept where keys are not persisted in a key store, Schannel, the TLS provider on Windows does not work with such certificates).

This causes to a hard-to-diagnose exception being surfaced to .NET application. This change:

  • fixes the error detection so that more helpful diagnostic exception is surfaced
  • fixes test failures to de-noise CI.

Regression

  • Yes
  • No

Regression was introduced by updating MsQuic to the latest version.

Testing

verified in CI.

Risk

Low, the fix is contained and well understood.

#132832)

## 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.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@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.

@akoeplinger

Copy link
Copy Markdown
Member

/ba-g unrelated test errors

@akoeplinger

akoeplinger commented Sep 2, 2026

Copy link
Copy Markdown
Member

Fix to address failing tests, Servicing-approved

@akoeplinger
akoeplinger merged commit f550d8f into release/11.0 Sep 2, 2026
84 of 86 checks passed
@akoeplinger
akoeplinger deleted the backport/pr-132832-to-release/11.0 branch September 2, 2026 09:39
@akoeplinger

Copy link
Copy Markdown
Member

Ah, I mistakenly assumed this is a test fix, I didn't see that this touches product code, sorry. Let me know if I should revert it but I assume you'll get tactics approval

@karelz

karelz commented Sep 2, 2026

Copy link
Copy Markdown
Member

Approved - Regression from msquic insertion - affecting product.

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

Labels

area-System.Net Servicing-approved Approved for servicing release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants