Skip to content

Add ML-DSA (FIPS 204) post-quantum signature support#3475

Closed
iNinja wants to merge 31 commits intodevfrom
iinglese/ml-dsa
Closed

Add ML-DSA (FIPS 204) post-quantum signature support#3475
iNinja wants to merge 31 commits intodevfrom
iinglese/ml-dsa

Conversation

@iNinja
Copy link
Copy Markdown
Contributor

@iNinja iNinja commented May 7, 2026

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

Standard Status Usage
FIPS 204 Final ML-DSA algorithm (key gen, sign, verify)
RFC 9881 Final (Oct 2025) X.509 algorithm OIDs for ML-DSA-44/65/87
draft-ietf-cose-dilithium-11 (RFC 9964 pending) AUTH48 — content frozen JWK key type (kty=AKP), parameter names (pub, priv), JWS algorithm identifiers, thumbprint computation

What's included

New types

  • MlDsaSecurityKeyAsymmetricSecurityKey subclass wrapping MLDsa; supports key size, private key detection, JWK thumbprint computation
  • MlDsaAdapter (internal) — creates MLDsa from JWK parameters with pub/priv consistency validation

Modified types

  • AsymmetricAdapter — ML-DSA sign/verify delegates (byte[], offset, span), X.509 ML-DSA routing
  • AsymmetricSignatureProvider — ML-DSA key size maps, hash algorithm guard pattern (TryGetHashAlgorithmName)
  • SupportedAlgorithms — ML-DSA algorithm collection, algorithm/key parameter set enforcement
  • JsonWebKeyPub/Priv properties, AKP key size, HasPrivateKey, thumbprint computation
  • JsonWebKeySerializer — read/write pub/priv parameters
  • JsonWebKeyConverterConvertFromMlDsaSecurityKey, TryConvertToMlDsaSecurityKey, X.509→JWK conversion for ML-DSA certificates (x5c and extractKeyMaterial modes)
  • X509SecurityKey — ML-DSA OID detection (RFC 9881), MlDsaPublicKey/MlDsaPrivateKey properties with .NET 6 platform compatibility handling
  • CryptoTelemetry — ML-DSA key algorithm identifiers
  • SecurityAlgorithmsMlDsa44, MlDsa65, MlDsa87 constants
  • JsonWebAlgorithmsKeyTypesAkp constant
  • JsonWebKeyParameterNamesPub, Priv constants with UTF8 equivalents

Dependencies

  • Microsoft.Bcl.Cryptography ≥ 10.0.2 — provides MLDsa type on all Wilson TFMs
  • System.Memory upgraded 4.5.5 → 4.6.3 (transitive requirement)

Design decisions

  • No conditional compilationMLDsa is available on all TFMs via the BCL compatibility package
  • No [Experimental] on Wilson types — only internal call sites that invoke .NET experimental X.509 extension methods use #pragma SYSLIB5006 suppression
  • Algorithm/key enforcementIsSupportedAlgorithm validates that the ML-DSA key's parameter set matches the requested JOSE algorithm (prevents algorithm confusion)
  • Pub/priv consistency validation — JWK import verifies the claimed pub matches the key derived from priv seed
  • kty=AKP with mandatory alg — per draft-ietf-cose-dilithium; routing checks both kty and alg, never kty alone
  • JWK thumbprint — canonical form {"alg","kty","pub"} in lexicographic order
  • Private key format — 32-byte seed only (not expanded key), zeroed after use in finally blocks
  • X.509 key extractionMlDsaPrivateKey catches PlatformNotSupportedException on .NET 6 where private key extraction is not supported

Test coverage (79 tests)

Category Tests
Key construction & properties 5
JWK thumbprint (deterministic, pub/priv match, cross-key) 4
JWK round-trip (SecurityKey ↔ JWK ↔ JSON) 6
X.509 key size, thumbprint, JWK conversion 12
JWK negative tests (missing alg, missing pub, invalid alg, pub/priv mismatch) 4
Algorithm/key mismatch enforcement 10
Public-key-only signing/verification 2
Signature correctness (tampering, cross-key) 4
E2E JWT create/validate (JsonWebTokenHandler, JwtSecurityTokenHandler, experimental ValidationParameters, JWK keys) 12
E2E JWT with X.509 (sign with X509SecurityKey, cross-key-type validation) 6
Existing asymmetric signature tests 523 (unchanged, no regressions)

Tests run on: net462, net472, net6.0, net8.0, net9.0, net10.0

Known limitations

  1. X.509 ML-DSA private key on .NET 6GetMLDsaPrivateKey() throws PlatformNotSupportedException. Verification works; signing requires MlDsaSecurityKey with a standalone key.
  2. X.509 certificate creationCertificateRequest(string, MLDsa) is only available on .NET 10. Test certificates are pre-generated PFX embedded as base64 constants.
  3. JOSE draft status — draft-ietf-cose-dilithium is in AUTH48 (RFC 9964 pending). Content is frozen; algorithm identifiers and wire formats are final.
  4. BCL package net6.0 warnings — suppressed via targeted Directory.Build.targets overrides. Remove when net6.0 is dropped from SrcTargets.

iNinja and others added 18 commits May 7, 2026 12:52
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>
@iNinja iNinja requested a review from a team as a code owner May 7, 2026 11:58
@iNinja iNinja requested a review from Copilot May 7, 2026 11:59
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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 + MlDsaAdapter and wired ML-DSA into asymmetric signing/verification (including X.509 routing).
  • Extended JWK support for kty=AKP with pub/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.

Comment thread test/Microsoft.IdentityModel.Tokens.Tests/MlDsaSecurityKeyTests.cs Outdated
Comment thread src/Microsoft.IdentityModel.Tokens/X509SecurityKey.cs Outdated
Comment thread src/Microsoft.IdentityModel.Tokens/X509SecurityKey.cs
Comment thread src/Microsoft.IdentityModel.Tokens/X509SecurityKey.cs Outdated
Comment thread Directory.Build.targets
Comment thread src/Microsoft.IdentityModel.Tokens/X509SecurityKey.cs Outdated
iNinja and others added 3 commits May 7, 2026 13:20
- 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>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated 7 comments.

Comment thread src/Microsoft.IdentityModel.Tokens/MlDsaAdapter.cs
Comment thread src/Microsoft.IdentityModel.Tokens/MlDsaAdapter.cs Outdated
Comment thread src/Microsoft.IdentityModel.Tokens/AsymmetricAdapter.cs Outdated
Comment thread src/Microsoft.IdentityModel.Tokens/X509SecurityKey.cs
Comment thread src/Microsoft.IdentityModel.Tokens/JsonWebKeyConverter.cs
Comment thread src/Microsoft.IdentityModel.Tokens/MlDsaSecurityKey.cs Outdated
Comment thread Directory.Build.targets
- 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>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated 5 comments.

Comment thread src/Microsoft.IdentityModel.Tokens/JsonWebKeyConverter.cs
Comment thread src/Microsoft.IdentityModel.Tokens/JsonWebKeyConverter.cs Outdated
Comment thread test/Microsoft.IdentityModel.TestUtils/MlDsaKeyingMaterial.cs Outdated
Comment thread test/Microsoft.IdentityModel.Tokens.Tests/AsymmetricSignatureTests.cs Outdated
Comment thread src/Microsoft.IdentityModel.Tokens/AsymmetricAdapter.cs
- 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>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated 2 comments.

Comment thread src/Microsoft.IdentityModel.Tokens/JsonWebKeyConverter.cs
Comment thread src/Microsoft.IdentityModel.Tokens/AsymmetricAdapter.cs Outdated
- 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>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated 4 comments.

Comment thread src/Microsoft.IdentityModel.Tokens/JsonWebKeyConverter.cs
Comment thread src/Microsoft.IdentityModel.Tokens/X509SecurityKey.cs
Comment thread src/Microsoft.IdentityModel.Tokens/X509SecurityKey.cs
Comment thread test/Microsoft.IdentityModel.TestUtils/MlDsaKeyingMaterial.cs
- 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>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated 2 comments.

Comment thread test/Microsoft.IdentityModel.Tokens.Tests/MlDsaSecurityKeyTests.cs
Comment thread src/Microsoft.IdentityModel.Tokens/JsonWebKey.cs
iNinja and others added 2 commits May 7, 2026 19:11
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>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated 2 comments.

Comment thread src/Microsoft.IdentityModel.Tokens/AsymmetricAdapter.cs
Comment thread src/Microsoft.IdentityModel.Tokens/X509SecurityKey.cs
- 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>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated 1 comment.

Comment thread src/Microsoft.IdentityModel.Tokens/X509SecurityKey.cs
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>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated no new comments.

@iNinja
Copy link
Copy Markdown
Contributor Author

iNinja commented May 8, 2026

Re-issuing against dev8x from a separate branch to avoid changes from dev polluting the PR.

@iNinja iNinja closed this May 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants