Fallback to RS256 when certificate PSS signing fails#6126
Conversation
There was a problem hiding this comment.
Pull request overview
This PR addresses token acquisition failures on .NET Framework when using certificates whose private keys are backed by legacy Windows CSP providers (exposed as RSACryptoServiceProvider), by falling back from PS256/PSS to RS256/PKCS#1 for client assertions while keeping x5c emission governed solely by the request option.
Changes:
- Add legacy CSP-backed certificate detection and reuse of resolved RSA providers in
CommonCryptographyManager. - Downgrade assertion signing from PS256 to RS256 when a legacy CSP-backed key is detected to avoid PSS padding failures.
- Add a .NET Framework unit test that creates a CertEnroll CSP certificate and validates the outgoing
client_assertionheader and PKCS#1 signature through the mocked HTTP pipeline.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| tests/Microsoft.Identity.Test.Unit/PublicApiTests/ClientCredentialWithCertTest.cs | Adds a net48-only test creating a legacy CSP-backed cert via CertEnroll and validating an RS256/PKCS#1 client assertion. |
| src/client/Microsoft.Identity.Client/PlatformsCommon/Shared/CommonCryptographyManager.cs | Introduces legacy CSP detection and refactors RSA provider caching into helpers reused by signing and detection. |
| src/client/Microsoft.Identity.Client/PlatformsCommon/Interfaces/ICryptographyManager.cs | Extends the internal crypto interface with legacy CSP certificate detection. |
| src/client/Microsoft.Identity.Client/Internal/JsonWebToken.cs | Switches to RS256 when legacy CSP is detected while preserving request-level sendX5C behavior. |
gladjohn
left a comment
There was a problem hiding this comment.
are SHA‑256-incapable CSPs (PROV_RSA_FULL, PROV_RSA_SCHANNEL) are in or out of scope?
861ca12 to
44cfa8e
Compare
Wrap only the invalid PSS operation performed by RSACryptoServiceProvider and rebuild the client assertion as RS256. Preserve unrelated cryptographic failures and cover both paths. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0ed0719e-5c4e-43db-8301-6fa74cec98e1
Keep the fallback localized to JsonWebToken: retry the assertion as RS256 after a PSS CryptographicException, without provider-specific product-code changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0ed0719e-5c4e-43db-8301-6fa74cec98e1
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0ed0719e-5c4e-43db-8301-6fa74cec98e1
a866d1a to
7d21759
Compare
I don't know. There doesn't seem to be a clear repro of this bug. So I pivoted to a try PSS / fallback to PKCS1. |
Summary
CryptographicExceptionRS256withx5twhile reusing the original encoded payloadx5cbehavior independent from signing fallbackTest coverage
AcquireTokenForClientflow through the mocked HTTP pipelineclient_assertionRS256,x5t,x5c, and the PKCS#1 SHA-256 signatureCloses #6125