Add ML-DSA (FIPS 204) post-quantum signature support#3475
Closed
Add ML-DSA (FIPS 204) post-quantum signature support#3475
Conversation
Implement ML-DSA-44, ML-DSA-65, and ML-DSA-87 digital signature algorithm support in Microsoft.IdentityModel.Tokens. New types: - MlDsaSecurityKey: AsymmetricSecurityKey wrapping System.Security.Cryptography.MLDsa - MlDsaAdapter: Static helper for creating MLDsa from JWK parameters Key changes: - SecurityAlgorithms: Add MlDsa44/MlDsa65/MlDsa87 constants - JsonWebAlgorithmsKeyTypes: Add Akp (AKP) key type per draft-ietf-cose-dilithium - JsonWebKeyParameterNames: Add Pub/Priv for AKP key material - JsonWebKey: Add Pub/Priv properties, AKP thumbprint, KeySize, HasPrivateKey - JsonWebKeySerializer: Read/write pub/priv parameters - SupportedAlgorithms: Add TryGetHashAlgorithmName guard pattern, ML-DSA collections - AsymmetricAdapter: Add MLDsa sign/verify delegates (pure signing, no hash) - AsymmetricSignatureProvider: TryGetHashAlgorithmName guard, key size maps - JsonWebKeyConverter: ConvertFromMlDsaSecurityKey, TryConvertToMlDsaSecurityKey - CryptoTelemetry: ML-DSA key algorithm IDs - PublicAPI/InternalAPI tracking for all target frameworks Dependencies: - Microsoft.Bcl.Cryptography 10.0.2 (provides MLDsa on net462+) - System.Memory bumped from 4.5.5 to 4.6.3 Standards: FIPS 204 (Final), RFC 9881 (Final), draft-ietf-cose-dilithium v11 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tests for MlDsaSecurityKey: - Constructor validation (null, valid MLDsa, all 3 variants) - KeySize matches expected bits for ML-DSA-44/65/87 - HasPrivateKey/PrivateKeyStatus for private and public-only keys - JWK thumbprint: deterministic, public/private match, different keys differ - JWK round-trip: SecurityKey → JWK → SecurityKey preserves key material Sign/verify integration tests: - MlDsaSecurityKey sign/verify round-trip for all 3 variants (ML-DSA-44/65/87) - JsonWebKey (AKP) sign/verify round-trip for all 3 variants - Both direct provider and factory-created provider paths - Cross-verification (direct-signed verified by factory, and vice versa) Algorithm registry tests: - ML-DSA algorithms registered in DefaultMinimumAsymmetricKeySizeInBitsForSigningMap - ML-DSA algorithms registered in DefaultMinimumAsymmetricKeySizeInBitsForVerifyingMap - VerifyDefaultMinimumAsymmetricKeySizeAreSupported includes ML-DSA Test infrastructure: - KeyingMaterial: MlDsa44/65/87Key, MlDsa44/65/87Key_Public, JsonWebKeyMlDsa44/65/87 - AsymmetricSignatureTestData: MlDsaSecurityKeys, JsonMlDsaSecurityKeys, AddMlDsaAlgorithmVariations All 2318 tests pass (14 new ML-DSA + 6 sign/verify + 3 key size + existing). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
X509SecurityKey now handles ML-DSA certificates (OIDs from RFC 9881): - ML-DSA-44: 2.16.840.1.101.3.4.3.17 - ML-DSA-65: 2.16.840.1.101.3.4.3.18 - ML-DSA-87: 2.16.840.1.101.3.4.3.19 Changes: - X509SecurityKey: Add MlDsaPrivateKey/MlDsaPublicKey internal accessors using X509CertificateKeyAccessors.GetMLDsaPublicKey/GetMLDsaPrivateKey from Microsoft.Bcl.Cryptography - X509SecurityKey: KeySize, HasPrivateKey, PrivateKeyStatus, JWK thumbprint all handle ML-DSA certificates - AsymmetricAdapter: InitializeUsingX509SecurityKey routes ML-DSA certs through InitializeUsingMlDsaSecurityKey - SupportedAlgorithms: IsSupportedAlgorithm handles X509SecurityKey with ML-DSA via IsSupportedMlDsaAlgorithm All 2318 tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add [Experimental] attribute to MlDsaSecurityKey class (NET8_0_OR_GREATER) - Add [Experimental] attribute to ConvertFromMlDsaSecurityKey method - Add [Experimental] attribute to MlDsaAdapter class (internal) - Add file-level #pragma warning disable SYSLIB5006 for internal consumers: AsymmetricAdapter, SupportedAlgorithms, JsonWebKeyConverter, CryptoTelemetry, X509SecurityKey - Update PublicAPI.Unshipped.txt for net8.0/net9.0/net10.0 with [SYSLIB5006] prefix - Remove unnecessary [Experimental] from internal X509SecurityKey properties - Fix CryptographicOperations.ZeroMemory → Array.Clear for net462/net472 compat Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add ML-DSA self-signed certificate generation (NET10_0_OR_GREATER only) using CertificateRequest(string, MLDsa) constructor - Add X509SecurityKey property tests for ML-DSA-44/65/87 (KeySize, HasPrivateKey, PrivateKeyStatus) - Add X509 ML-DSA sign/verify round-trip tests via AsymmetricSignatureProvider - Add X509 ML-DSA JWK thumbprint tests (CanCompute, deterministic) - All 2330 tests pass on net10.0, 2313 on net9.0 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Verified via reflection that in Microsoft.Bcl.Cryptography 10.0.3: - MLDsa class itself is NOT marked [Experimental] - Core MLDsa methods (GenerateKey, SignData, VerifyData, ExportMLDsaPublicKey, ImportMLDsaPublicKey, ImportMLDsaPrivateSeed) are NOT experimental - Only PKCS#8/PEM import/export and X509 extension methods (GetMLDsaPublicKey, GetMLDsaPrivateKey) are [Experimental(SYSLIB5006)] - CertificateRequest(string, MLDsa) constructor is experimental Changes: - Remove [Experimental] from MlDsaSecurityKey class (MLDsa isn't experimental) - Remove [Experimental] from MlDsaAdapter class - Remove [Experimental] from ConvertFromMlDsaSecurityKey method - Remove file-level #pragma SYSLIB5006 from AsymmetricAdapter, JsonWebKeyConverter, SupportedAlgorithms, CryptoTelemetry (none call experimental APIs) - Remove #pragma SYSLIB5006 from all test files - Keep #pragma SYSLIB5006 only where experimental APIs are actually called: - X509SecurityKey.cs (GetMLDsaPublicKey/GetMLDsaPrivateKey) - KeyingMaterial.cs (CertificateRequest(string, MLDsa) constructor) - Revert PublicAPI.Unshipped.txt entries to non-prefixed format Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace #if NET10_0_OR_GREATER cert generation with pre-generated PFX base64 constants for ML-DSA-44, ML-DSA-65, and ML-DSA-87 - X509 ML-DSA tests now run on all TFMs (net462-net10.0) - Add CanExtractMlDsaPrivateKeyFromX509() runtime check to skip X509 sign tests on .NET 6 (GetMLDsaPrivateKey PlatformNotSupportedException) - Use X509CertificateLoader.LoadPkcs12 on net9.0+ to avoid SYSLIB0057 - Refactor MlDsaSecurityKeyTests X509 tests to theory-based pattern Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The decoded private key seed byte array was not being zeroed after being passed to MLDsa.ImportMLDsaPrivateSeed(). This left sensitive 32-byte seed material in memory longer than necessary. The export path in JsonWebKeyConverter.ConvertFromMlDsaSecurityKey already correctly zeroed the seed via CryptographicOperations.ZeroMemory. This fix applies the same pattern to the import path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tests added: - JWK negative tests (missing alg, missing pub, invalid alg) - Algorithm mismatch key size validation test - Public-key-only signing/verification tests - JWK JSON serialization round-trip (all 3 variants + public-only) - End-to-end JWT create/validate (MlDsaSecurityKey and JsonWebKey) Bug fixed: - SignUsingSpanMlDsa: MLDsa.SignData requires destination to be exactly SignatureSizeInBytes, but ArrayPool.Rent returns larger buffers. Fixed by slicing destination to exact size. Performance improvements: - VerifyUsingOffsetMlDsa: use span-based VerifyData on NET6+ to avoid byte[] copy on the JWT validation hot path (ArrayPool buffers are larger than payload, so offset path always triggered). - SignUsingOffsetMlDsa: use span-based SignData on NET6+ to avoid byte[] copy of input data. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rectness tests Bug fix (AsymmetricAdapter): - SignUsingSpanMlDsa: slice destination to exact SignatureSizeInBytes before calling MLDsa.SignData (ArrayPool.Rent returns oversized buffers) Performance optimizations (AsymmetricAdapter, NET6+): - VerifyUsingOffsetMlDsa: use span-based MLDsa.VerifyData to avoid byte[] copy on JWT validation hot path - SignUsingOffsetMlDsa: use span-based MLDsa.SignData to avoid byte[] copy of input data New tests: - TamperedSignature_FailsVerification (all 3 variants) - CrossKeyVerification_Fails Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add two new test methods covering the X509SecurityKey JWT workflow: - JwtCreateAndValidate_WithX509SecurityKey: signs and validates JWT using X509SecurityKey with ML-DSA certificate for all three variants - JwtCreateWithX509_ValidateWithMlDsaKey: signs with X509SecurityKey and validates with MlDsaSecurityKey extracted from the certificate's public key, testing cross-key-type interoperability Both tests gracefully skip on platforms where ML-DSA private key extraction from X509 certificates is not supported (e.g., .NET 6). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Cover all three JWT processing entry points with ML-DSA: - JwtSecurityTokenHandler (legacy): CreateToken + WriteToken + ValidateToken - JsonWebTokenHandler with TokenValidationParameters (current) - JsonWebTokenHandler via IResultBasedValidation with experimental ValidationParameters (result-based validation path) Each handler is tested with all three ML-DSA variants (44/65/87). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…eview fixes - Enforce ML-DSA key parameter set matches requested JOSE algorithm in IsSupportedAlgorithm for MlDsaSecurityKey, X509SecurityKey, and JsonWebKey - Validate AKP JWK 'pub' matches key derived from 'priv' seed to prevent key identity confusion - Restore GetHashAlgorithmName virtual extensibility point in CreateAsymmetricAdapter (backwards compatibility) - Narrow SYSLIB5006 pragma to specific experimental API call sites - Fix SkipValidationDelegates -> SkipValidationValidators rename from rebase - Add negative tests for algorithm mismatch and pub/priv mismatch Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ConvertFromX509SecurityKey now handles ML-DSA certificates in both x5c mode (kty=AKP + alg + x5c) and extractKeyMaterial mode (exports pub/priv directly from the X509SecurityKey's cached MLDsa instance). Key material extraction duplicates export logic from ConvertFromMlDsaSecurityKey rather than creating a wrapper MlDsaSecurityKey, to avoid ambiguous ownership of the MLDsa instance that X509SecurityKey caches internally. Also fixes MlDsaPrivateKey property to catch PlatformNotSupportedException on .NET 6 where GetMLDsaPrivateKey() is not supported, matching the documented behavior of returning null. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Microsoft.Bcl.Cryptography 10.0.2 and System.Formats.Asn1 10.0.2 emit TFM support warnings on net6.0 via InitialTargets in their buildTransitive .targets files. These fire across all projects that transitively reference Microsoft.IdentityModel.Tokens and would fail CI with TreatWarningsAsErrors. ML-DSA functionality is validated on net6.0 via the compatibility package and covered by the cross-TFM test suite (79/79 tests pass on net6.0). This uses targeted target-name overrides in Directory.Build.targets rather than the blanket SuppressTfmSupportBuildWarnings property, so TFM warnings from any other package will still surface normally. Remove when net6.0 is dropped from SrcTargets. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…sive catches - Fix AKP x5c JWK round-trip: TryConvertToSecurityKey now routes AKP JWKs with x5c to TryConvertToX509SecurityKey before trying raw ML-DSA - Wrap private seed zeroing in try/finally in ConvertFromMlDsaSecurityKey and ConvertFromX509SecurityKey extractKeyMaterial to ensure cleanup on exceptions - Track MLDsa ownership with success flag in MlDsaAdapter.CreateMlDsa to prevent native resource leak on malformed pub - Add defensive PlatformNotSupportedException catch in MlDsaPublicKey property (symmetric with MlDsaPrivateKey) - Add x5c round-trip assertion to ConvertFromX509SecurityKey_X5cMode test Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
MlDsaSecurityKey does not own or dispose the MLDsa instance — same pattern as RsaSecurityKey and ECDsaSecurityKey. Updated param doc to reflect this. Added comment in AsymmetricAdapter explaining the borrowed-instance pattern for X509 ML-DSA certificates. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces ML-DSA (FIPS 204) post-quantum signature support to Microsoft.IdentityModel.Tokens, integrating it across signing/verification, JWK representation/serialization, X.509 key extraction, and telemetry.
Changes:
- Added
MlDsaSecurityKey+MlDsaAdapterand wired ML-DSA into asymmetric signing/verification (including X.509 routing). - Extended JWK support for
kty=AKPwithpub/priv, thumbprints, and conversions (SecurityKey ↔ JWK ↔ JSON, including X.509). - Added ML-DSA telemetry identifiers, tests, and build/dependency updates for cross-TFM compatibility.
Reviewed changes
Copilot reviewed 30 out of 30 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| test/Microsoft.IdentityModel.Tokens.Tests/MlDsaSecurityKeyTests.cs | New end-to-end/unit test coverage for ML-DSA keys, JWK, X.509, and JWT flows. |
| test/Microsoft.IdentityModel.Tokens.Tests/AsymmetricSignatureTests.cs | Adds ML-DSA to existing asymmetric signature theory coverage and runtime platform gating for X.509 private key extraction. |
| test/Microsoft.IdentityModel.Tokens.Tests/AsymmetricSignatureTestData.cs | Adds ML-DSA key test vectors to shared asymmetric signature test data. |
| test/Microsoft.IdentityModel.TestUtils/KeyingMaterial.cs | Adds generated ML-DSA keys and embedded ML-DSA PFX test certificates. |
| src/Microsoft.IdentityModel.Tokens/X509SecurityKey.cs | Adds ML-DSA OID detection, key extraction caching, thumbprints, and key size handling for ML-DSA X.509 certs. |
| src/Microsoft.IdentityModel.Tokens/Telemetry/CryptoTelemetry.cs | Adds ML-DSA key algorithm identifiers for telemetry. |
| src/Microsoft.IdentityModel.Tokens/SupportedAlgorithms.cs | Adds ML-DSA signing algorithm list, hash algorithm guard (TryGetHashAlgorithmName), and max-byte-count entries. |
| src/Microsoft.IdentityModel.Tokens/SecurityAlgorithms.cs | Adds ML-DSA algorithm constants (ML-DSA-44/65/87). |
| src/Microsoft.IdentityModel.Tokens/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt | Public API baseline updates for ML-DSA/JWK additions. |
| src/Microsoft.IdentityModel.Tokens/PublicAPI/net6.0/PublicAPI.Unshipped.txt | Public API baseline updates for ML-DSA/JWK additions. |
| src/Microsoft.IdentityModel.Tokens/PublicAPI/net8.0/PublicAPI.Unshipped.txt | Public API baseline updates for ML-DSA/JWK additions. |
| src/Microsoft.IdentityModel.Tokens/PublicAPI/net9.0/PublicAPI.Unshipped.txt | Public API baseline updates for ML-DSA/JWK additions. |
| src/Microsoft.IdentityModel.Tokens/PublicAPI/net10.0/PublicAPI.Unshipped.txt | Public API baseline updates for ML-DSA/JWK additions. |
| src/Microsoft.IdentityModel.Tokens/PublicAPI/net462/PublicAPI.Unshipped.txt | Public API baseline updates for ML-DSA/JWK additions. |
| src/Microsoft.IdentityModel.Tokens/PublicAPI/net472/PublicAPI.Unshipped.txt | Public API baseline updates for ML-DSA/JWK additions. |
| src/Microsoft.IdentityModel.Tokens/MlDsaSecurityKey.cs | New AsymmetricSecurityKey implementation for ML-DSA with thumbprints and key-size/private-key detection. |
| src/Microsoft.IdentityModel.Tokens/MlDsaAdapter.cs | New internal adapter to build MLDsa from JWK (pub/priv) with pub/priv consistency checks. |
| src/Microsoft.IdentityModel.Tokens/Microsoft.IdentityModel.Tokens.csproj | Adds Microsoft.Bcl.Cryptography dependency required for MLDsa across TFMs. |
| src/Microsoft.IdentityModel.Tokens/JsonWebKeyParameterNames.cs | Adds pub/priv parameter names (string + UTF8). |
| src/Microsoft.IdentityModel.Tokens/JsonWebKeyConverter.cs | Adds ML-DSA conversions (SecurityKey ↔ JWK) and ML-DSA-aware X.509→JWK conversion. |
| src/Microsoft.IdentityModel.Tokens/JsonWebKey.cs | Adds Pub/Priv, AKP key sizing, private-key detection, thumbprint and public-JWK support. |
| src/Microsoft.IdentityModel.Tokens/JsonWebAlgorithmsKeyTypes.cs | Adds AKP key type constant. |
| src/Microsoft.IdentityModel.Tokens/Json/JsonWebKeySerializer.cs | Adds read/write support for pub/priv. |
| src/Microsoft.IdentityModel.Tokens/InternalAPI.Unshipped.txt | Internal API baseline updates for new ML-DSA internals. |
| src/Microsoft.IdentityModel.Tokens/GlobalSuppressions.cs | Adds targeted suppressions for new ML-DSA try-pattern and platform-test exception catching. |
| src/Microsoft.IdentityModel.Tokens/AsymmetricSignatureProvider.cs | Skips external-hash plumbing for ML-DSA and updates key-size maps with ML-DSA sizes. |
| src/Microsoft.IdentityModel.Tokens/AsymmetricAdapter.cs | Adds ML-DSA sign/verify support and ML-DSA routing for X509SecurityKey. |
| docs/Telemetry-Cardinality-Analysis.md | Adds documentation analyzing telemetry counter cardinality characteristics. |
| Directory.Build.targets | Adds build target overrides to suppress specific package TFM warnings. |
| build/dependencies.props | Adds MicrosoftBclCryptographyVersion and updates SystemMemoryVersion. |
- Guard KeySize and ComputeJwkThumbprint against null MlDsaPublicKey on platforms where GetMLDsaPublicKey() is not supported - Cache ML-DSA key initialization state to avoid repeated exception-driven control flow on unsupported platforms (_mlDsaPrivateKeyInitialized, _mlDsaPublicKeyInitialized flags) - Return PrivateKeyStatus.Unknown (not DoesNotExist) when ML-DSA private key extraction fails due to PlatformNotSupportedException - Remove unused using System.Text.Json from MlDsaSecurityKeyTests - Clarify Directory.Build.targets comment re Condition scope Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move all ML-DSA keying material from KeyingMaterial to a separate MlDsaKeyingMaterial class with lazy initialization, preventing TypeInitializationException on platforms where MLDsa.IsSupported is false (e.g., older OS versions without SymCrypt ML-DSA support). Add MlDsaFactAttribute and MlDsaTheoryAttribute that conditionally skip ML-DSA tests when the platform lacks ML-DSA support, reporting them as 'Skipped' rather than silently passing or crashing. - KeyingMaterial.cs: removed all ML-DSA fields (keys, JWKs, certs) - MlDsaKeyingMaterial.cs: self-contained lazy ML-DSA test material - MlDsaConditionalAttributes.cs: [MlDsaFact] and [MlDsaTheory] - MlDsaSecurityKeyTests.cs: [Fact]->[MlDsaFact], [Theory]->[MlDsaTheory] - AsymmetricSignatureTestData.cs: lazy ML-DSA test data lists Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…atforms SignVerifyTheoryData and VerifyAlgorithmsInDefaultMinimumAsymmetricKeySizeTests property getters accessed MlDsaKeyingMaterial during test discovery, which triggers MLDsa.GenerateKey() and throws PlatformNotSupportedException on OS versions without ML-DSA crypto support. Wrap ML-DSA test data population with MLDsa.IsSupported checks. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add AKP-generic log messages IDX10721 (missing required parameter) and IDX10722 (pub/priv key material mismatch) replacing RSA-specific IDX10700 in MlDsaAdapter - Guard null MlDsaPrivateKey in AsymmetricAdapter when X509 ML-DSA cert private key is unavailable (throws IDX10638) - Validate AKP x5c JWK alg matches certificate OID in TryConvertToSecurityKey to prevent key confusion - Use JsonWebKeyParameterNames constants in MlDsaSecurityKey thumbprint computation, consistent with RSA/ECDsa implementations - Document PrivateKeyStatus.Unknown behavior for ML-DSA on platforms where private key extraction is not supported Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add InitializeUsingMlDsa(MLDsa) overload in AsymmetricAdapter to avoid allocating a temporary MlDsaSecurityKey wrapper on the X509 signing path - Reject AKP JWKs without alg early in TryConvertToSecurityKey (alg is mandatory for all AKP keys per spec) - Update ownership comment in ConvertFromX509SecurityKey to reflect actual rationale (avoiding unnecessary allocation, not disposal concerns) - Fix MlDsaKeyingMaterial XML doc: callers must check IsSupported, members are not internally guarded - Move CanExtractMlDsaPrivateKeyFromX509 to MlDsaKeyingMaterial shared helper, removing duplication from AsymmetricSignatureTests and MlDsaSecurityKeyTests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add IDX10723 log message for X509 ML-DSA private key extraction failures, including algorithm and key ID for diagnostics - Validate AKP alg is a supported algorithm before attempting x5c certificate conversion - Register IDX10723 in InternalAPI.Unshipped.txt Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Require x5c certificate to contain an ML-DSA key matching the claimed alg when converting AKP JWKs (rejects RSA/ECDSA certs with kty=AKP) - Add IDX10724 for JWK thumbprint computation when public key extraction is not supported, replacing raw string exception message - Fix IDX10638 -> IDX10723 in PrivateKeyStatus comment - Fix indentation on MlDsaKeyingMaterial PFX constant Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The x5c-to-X509SecurityKey round-trip requires ML-DSA public key extraction from a public-only certificate, which may not be supported on all platforms. Guard with CanExtractMlDsaPublicKeyFromX509PublicOnlyCert so the shape assertions still run unconditionally while the round-trip is skipped on unsupported platforms. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Make _mlDsaPrivateKeyInitialized and _mlDsaPublicKeyInitialized volatile to ensure correct publication across threads in double-checked locking - Add IDX10725 for X509 certs where key extraction fails (unsupported platform or unrecognised key type) - Guard null PrivateKey before passing to InitializeUsingRsa to prevent deferred NRE when X509 cert has no private key - Register IDX10725 in InternalAPI.Unshipped.txt Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Access MlDsaPrivateKey before checking _mlDsaPrivateKeyUnsupported so the flag is set during initialization. Previously, first access would return DoesNotExist instead of Unknown on unsupported platforms. Make _mlDsaPrivateKeyUnsupported volatile for correct cross-thread visibility, consistent with the other initialization flags. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
Author
|
Re-issuing against dev8x from a separate branch to avoid changes from dev polluting the PR. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add ML-DSA (FIPS 204) post-quantum signature support
Summary
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 (79 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.