Add ML-DSA (FIPS 204) post-quantum signature support#3479
Conversation
Implement ML-DSA-44, ML-DSA-65, and ML-DSA-87 digital signature support in Microsoft.IdentityModel.Tokens, enabling post-quantum signatures across the JOSE pipeline: JWS signing/verification, JWK representation, X.509 certificate key extraction, and JWK conversion. Standards: FIPS 204 (Final), RFC 9881 (Final), draft-ietf-cose-dilithium v11 (RFC 9964 pending) Targeting dev8x (Wilson 8.x) with representAsRsaKey parameter naming. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| <NewtonsoftVersion>13.0.3</NewtonsoftVersion> | ||
| <SystemDiagnosticSourceVersion>6.0.2</SystemDiagnosticSourceVersion> | ||
| <SystemMemoryVersion>4.5.5</SystemMemoryVersion> | ||
| <SystemMemoryVersion>4.6.3</SystemMemoryVersion> |
There was a problem hiding this comment.
This is being bumped as a requirement from Microsoft.Bcl.Cryptography.
There was a problem hiding this comment.
I guess this drives the requirement upwards for entire dependency tree?
There was a problem hiding this comment.
Yes. Microsoft.Bcl.Cryptography 10.0.2 is a new dependency that provides the MLDsa API on downlevel TFMs (net462, net472, net6.0, net8.0, net9.0). Without it we can only support ML-DSA on .NET 10+. System.Memory 4.5.5 → 4.6.3 is a transitive requirement from Microsoft.Bcl.Cryptography. Both will flow to consumers of the NuGet packages.
There was a problem hiding this comment.
Pull request overview
This PR introduces ML-DSA (FIPS 204) post-quantum signature support across the IdentityModel JOSE pipeline, including new key types, JWK serialization/conversion, X.509 extraction, algorithm support/enforcement, telemetry, and extensive test coverage.
Changes:
- Added
MlDsaSecurityKeyandMlDsaAdapter, plus ML-DSA signing/verification support inAsymmetricAdapter/AsymmetricSignatureProvider. - Extended JWK and X.509 handling for ML-DSA (
kty=AKP,pub/priv, thumbprints, X509→JWK conversion). - Added test utilities and new test suites gated by platform support, plus dependency updates to enable
MLDsaacross TFMs.
Reviewed changes
Copilot reviewed 31 out of 31 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| test/Microsoft.IdentityModel.Tokens.Tests/MlDsaSecurityKeyTests.cs | Adds focused unit + E2E JWT coverage for ML-DSA keys, JWK, thumbprints, and X.509 scenarios. |
| test/Microsoft.IdentityModel.Tokens.Tests/AsymmetricSignatureTests.cs | Extends existing signing/verifying theory data to include ML-DSA keys/algorithms when supported. |
| test/Microsoft.IdentityModel.Tokens.Tests/AsymmetricSignatureTestData.cs | Adds ML-DSA key sets and algorithm-variation wiring for signature theory data. |
| test/Microsoft.IdentityModel.TestUtils/MlDsaKeyingMaterial.cs | Introduces lazily-initialized ML-DSA test keys and embedded X.509 PFX material. |
| test/Microsoft.IdentityModel.TestUtils/MlDsaConditionalAttributes.cs | Adds conditional xUnit attributes to skip ML-DSA tests on unsupported platforms. |
| src/Microsoft.IdentityModel.Tokens/X509SecurityKey.cs | Adds ML-DSA OID detection, cached public/private extraction, key size/thumbprint support. |
| src/Microsoft.IdentityModel.Tokens/Telemetry/CryptoTelemetry.cs | Adds ML-DSA key algorithm identifiers for telemetry reporting. |
| src/Microsoft.IdentityModel.Tokens/SupportedAlgorithms.cs | Adds ML-DSA signing algorithms and hash-selection guard (TryGetHashAlgorithmName). |
| src/Microsoft.IdentityModel.Tokens/SecurityAlgorithms.cs | Adds ML-DSA JOSE algorithm string constants. |
| src/Microsoft.IdentityModel.Tokens/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt | Public API additions for ML-DSA key type and JWK parameters. |
| src/Microsoft.IdentityModel.Tokens/PublicAPI/net6.0/PublicAPI.Unshipped.txt | Public API additions for ML-DSA key type and JWK parameters. |
| src/Microsoft.IdentityModel.Tokens/PublicAPI/net8.0/PublicAPI.Unshipped.txt | Public API additions for ML-DSA key type and JWK parameters. |
| src/Microsoft.IdentityModel.Tokens/PublicAPI/net9.0/PublicAPI.Unshipped.txt | Public API additions for ML-DSA key type and JWK parameters. |
| src/Microsoft.IdentityModel.Tokens/PublicAPI/net10.0/PublicAPI.Unshipped.txt | Public API additions for ML-DSA key type and JWK parameters. |
| src/Microsoft.IdentityModel.Tokens/PublicAPI/net462/PublicAPI.Unshipped.txt | Public API additions for ML-DSA key type and JWK parameters. |
| src/Microsoft.IdentityModel.Tokens/PublicAPI/net472/PublicAPI.Unshipped.txt | Public API additions for ML-DSA key type and JWK parameters. |
| src/Microsoft.IdentityModel.Tokens/MlDsaSecurityKey.cs | Adds new SecurityKey wrapper for MLDsa with key-size/private-key detection and thumbprints. |
| src/Microsoft.IdentityModel.Tokens/MlDsaAdapter.cs | Adds JWK→MLDsa import and pub/priv consistency validation. |
| src/Microsoft.IdentityModel.Tokens/Microsoft.IdentityModel.Tokens.csproj | Adds Microsoft.Bcl.Cryptography package reference to provide MLDsa across TFMs. |
| src/Microsoft.IdentityModel.Tokens/LogMessages.cs | Adds ML-DSA specific error messages for JWK import and X.509 extraction failure modes. |
| src/Microsoft.IdentityModel.Tokens/JsonWebKeyParameterNames.cs | Adds pub/priv constants and UTF-8 byte spans for high-performance JSON parsing/writing. |
| src/Microsoft.IdentityModel.Tokens/JsonWebKeyConverter.cs | Adds ML-DSA key conversion paths: SecurityKey↔JWK and X.509→JWK routing for AKP. |
| src/Microsoft.IdentityModel.Tokens/JsonWebKey.cs | Adds Pub/Priv properties, AKP key sizing, private-key detection, and thumbprint support. |
| src/Microsoft.IdentityModel.Tokens/JsonWebAlgorithmsKeyTypes.cs | Adds AKP key type constant for the JOSE draft key type. |
| src/Microsoft.IdentityModel.Tokens/Json/JsonWebKeySerializer.cs | Adds read/write support for pub/priv parameters. |
| src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt | Tracks new internal APIs added for ML-DSA support. |
| src/Microsoft.IdentityModel.Tokens/GlobalSuppressions.cs | Adds CA1031 suppressions for ML-DSA try-pattern conversion and platform probing. |
| src/Microsoft.IdentityModel.Tokens/AsymmetricSignatureProvider.cs | Adds ML-DSA key size minima and bypasses hash selection for “pure signing” algorithms. |
| src/Microsoft.IdentityModel.Tokens/AsymmetricAdapter.cs | Adds ML-DSA sign/verify delegates, X.509 ML-DSA routing, and span-based signing when available. |
| Directory.Build.targets | Adds targeted target overrides to suppress net6.0 compatibility warnings from new crypto dependencies. |
| build/dependencies.props | Introduces Microsoft.Bcl.Cryptography version and updates System.Memory version. |
- Refactor InitializeUsingX509SecurityKey into explicit routing: InitializeUsingX509MlDsa, InitializeUsingX509Rsa, with clear unsupported key type fallback (IDX10725). Extensible pattern for future PQC algorithms (Composite ML-DSA, SLH-DSA). - Fix X509 ML-DSA telemetry: extract GetX509KeyAlgorithmId helper to correctly identify ML-DSA certs instead of reporting UNKNOWN. - Use EphemeralKeySet for PFX loading on .NET 6+ to avoid persisting keys to disk; fall back to Exportable on .NET Framework. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…fix Task style - Add ECDsa routing in InitializeUsingX509SecurityKey so ECDSA X509 certificates are handled correctly instead of falling through to the unsupported key type error - Broaden exception handling in MlDsaSecurityKey.PrivateKeyStatus and HasPrivateKey to return Unknown/false for non-CryptographicException failures (e.g., platform limitations), matching the documented contract - Use consistent short-form Task in test method signatures - Add CA1031 suppression for MlDsaSecurityKey.HasPrivateKey Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ey check - Don't cache _hasPrivateKey on general Exception in HasPrivateKey so PrivateKeyStatus can independently return Unknown for indeterminate cases - Use !string.IsNullOrEmpty(Priv) for AKP HasPrivateKey in JsonWebKey, consistent with MlDsaAdapter which treats empty priv as missing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When AKP x5c validation rejects a certificate (non-ML-DSA cert or alg mismatch), clear webKey.ConvertedSecurityKey to prevent subsequent TryConvertToSecurityKey calls from returning the cached key and bypassing validation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add using declarations to public-only X509Certificate2 instances created from RawData to avoid leaking certificate handles. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| <NewtonsoftVersion>13.0.3</NewtonsoftVersion> | ||
| <SystemDiagnosticSourceVersion>6.0.2</SystemDiagnosticSourceVersion> | ||
| <SystemMemoryVersion>4.5.5</SystemMemoryVersion> | ||
| <SystemMemoryVersion>4.6.3</SystemMemoryVersion> |
There was a problem hiding this comment.
I guess this drives the requirement upwards for entire dependency tree?
# Conflicts: # src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt # src/Microsoft.IdentityModel.Tokens/PublicAPI/net10.0/PublicAPI.Unshipped.txt # src/Microsoft.IdentityModel.Tokens/PublicAPI/net462/PublicAPI.Unshipped.txt # src/Microsoft.IdentityModel.Tokens/PublicAPI/net472/PublicAPI.Unshipped.txt # src/Microsoft.IdentityModel.Tokens/PublicAPI/net6.0/PublicAPI.Unshipped.txt # src/Microsoft.IdentityModel.Tokens/PublicAPI/net8.0/PublicAPI.Unshipped.txt # src/Microsoft.IdentityModel.Tokens/PublicAPI/net9.0/PublicAPI.Unshipped.txt # src/Microsoft.IdentityModel.Tokens/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt
Remove non-ML-DSA entries that were incorrectly added during the dev8x merge conflict resolution. The file should only contain our new internal API entries, not entries already tracked in InternalAPI.Shipped.txt. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The ML-DSA entries are identical across all TFMs. Move them to the root PublicAPI.Unshipped.txt and empty the per-TFM files, matching the repo convention. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add ML-DSA (FIPS 204) post-quantum signature support
This PR adds ML-DSA (Module-Lattice-Based Digital Signature Algorithm, FIPS 204) support to Microsoft.IdentityModel.Tokens, enabling post-quantum digital signatures across the JOSE pipeline — JWS signing/verification, JWK key representation, X.509 certificate key extraction, and JWK conversion.
Standards
kty=AKP), parameter names (pub,priv), JWS algorithm identifiers, thumbprint computationWhat's included
New types
MlDsaSecurityKey—AsymmetricSecurityKeysubclass wrappingMLDsa; supports key size, private key detection, JWK thumbprint computationMlDsaAdapter(internal) — createsMLDsafrom JWK parameters with pub/priv consistency validationModified types
AsymmetricAdapter— ML-DSA sign/verify delegates (byte[], offset, span), X.509 ML-DSA routingAsymmetricSignatureProvider— ML-DSA key size maps, hash algorithm guard pattern (TryGetHashAlgorithmName)SupportedAlgorithms— ML-DSA algorithm collection, algorithm/key parameter set enforcementJsonWebKey—Pub/Privproperties, AKP key size,HasPrivateKey, thumbprint computationJsonWebKeySerializer— read/writepub/privparametersJsonWebKeyConverter—ConvertFromMlDsaSecurityKey,TryConvertToMlDsaSecurityKey, X.509→JWK conversion for ML-DSA certificates (x5c and extractKeyMaterial modes)X509SecurityKey— ML-DSA OID detection (RFC 9881),MlDsaPublicKey/MlDsaPrivateKeyproperties with .NET 6 platform compatibility handlingCryptoTelemetry— ML-DSA key algorithm identifiersSecurityAlgorithms—MlDsa44,MlDsa65,MlDsa87constantsJsonWebAlgorithmsKeyTypes—AkpconstantJsonWebKeyParameterNames—Pub,Privconstants with UTF8 equivalentsDependencies
Microsoft.Bcl.Cryptography≥ 10.0.2 — providesMLDsatype on all Wilson TFMsSystem.Memoryupgraded 4.5.5 → 4.6.3 (transitive requirement)Design decisions
MLDsais available on all TFMs via the BCL compatibility package[Experimental]on Wilson types — only internal call sites that invoke .NET experimental X.509 extension methods use#pragma SYSLIB5006suppressionIsSupportedAlgorithmvalidates that the ML-DSA key's parameter set matches the requested JOSE algorithm (prevents algorithm confusion)pubmatches the key derived fromprivseedkty=AKPwith mandatoryalg— per draft-ietf-cose-dilithium; routing checks bothktyandalg, neverktyalone{"alg","kty","pub"}in lexicographic orderfinallyblocksMlDsaPrivateKeycatchesPlatformNotSupportedExceptionon .NET 6 where private key extraction is not supportedTest coverage (93 tests)
Tests run on: net462, net472, net6.0, net8.0, net9.0, net10.0
Known limitations
GetMLDsaPrivateKey()throwsPlatformNotSupportedException. Verification works; signing requiresMlDsaSecurityKeywith a standalone key.CertificateRequest(string, MLDsa)is only available on .NET 10. Test certificates are pre-generated PFX embedded as base64 constants.Directory.Build.targetsoverrides. Remove when net6.0 is dropped fromSrcTargets.