Skip to content

Experimental: ML-DSA support in Trustpoint - #843

Open
FHatCSW wants to merge 1 commit into
mainfrom
ml_dsa
Open

Experimental: ML-DSA support in Trustpoint#843
FHatCSW wants to merge 1 commit into
mainfrom
ml_dsa

Conversation

@FHatCSW

@FHatCSW FHatCSW commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Legal

  • I certify that I have all necessary rights to publish this contribution under the MIT license. I agree to the Trustpoint CLA and have added my name to the AUTHORS.md file.

@github-actions

Copy link
Copy Markdown

📋 License Check Report

Name Version License

Note: This project is MIT-licensed. LGPL and most permissive licenses are compatible. GPL and proprietary licenses require review.

@github-actions

Copy link
Copy Markdown
filepath error SUBTOTAL
trustpoint/crypto/tests/test_pkcs11_integration_signing_contract.py 1 1
TOTAL 1 1

@codecov

codecov Bot commented Jul 27, 2026

Copy link
Copy Markdown

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
1 1 0 0
View the top 1 failed test(s) by shortest run time
trustpoint/crypto/tests/test_pkcs11_integration_signing_contract.py::trustpoint.crypto.tests.test_pkcs11_integration_signing_contract
Stack Traces | 0s run time
.../crypto/tests/test_pkcs11_integration_signing_contract.py:55: in <module>
    sign_request=SignRequest.ecdsa_sha256(),
                 ^^^^^^^^^^^^^^^^^^^^^^^^
E   AttributeError: type object 'SignRequest' has no attribute 'ecdsa_sha256'

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

from cryptography.hazmat.primitives.asymmetric import ec, rsa # noqa: TC002

try:
from cryptography.hazmat.primitives.asymmetric import mldsa
Returns:
The actual cryptography private key if it's a managed key, otherwise the input unchanged.
"""
import logging

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 adds experimental ML-DSA support across Trustpoint’s crypto/key-management pipeline (software backend, managed keys, certificate issuance/verification, CMP/EST handling) and updates UI/model display helpers to present ML-DSA signature suites cleanly. It also updates security policy configuration to allow restricting ML-DSA variants and switches trustpoint-core to a Git ref containing ML-DSA support.

Changes:

  • Add ML-DSA key specs/variants and software-backend support for ML-DSA key generation and signing.
  • Extend certificate issuance, signature operations, and request parsing/building (CMP/EST) to support ML-DSA.
  • Add signature_suite_display helpers and update templates to use them; extend security configuration/migrations for ML-DSA variant restrictions.

Reviewed changes

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

Show a summary per file
File Description
uv.lock Switches trustpoint-core to a Git-based source for ML-DSA work.
pyproject.toml Uses a direct Git reference for trustpoint-core and enables Hatch direct references.
trustpoint/templates/signer/signers.html Displays signature_suite_display instead of raw signature suite.
trustpoint/templates/pki/issuing_cas/issuing_cas.html Displays signature_suite_display for issuing CAs.
trustpoint/templates/pki/domains/domain.html Displays signature_suite_display for domains.
trustpoint/templates/pki/cas/cas.html Simplifies signature suite rendering using display property.
trustpoint/templates/home/simplified_overview.html Displays CA signature suite via signature_suite_display.
trustpoint/request/operation_processor/sign.py Adds ML-DSA support for signing/verifying when hash algorithm is absent.
trustpoint/request/operation_processor/issue_cert.py Allows hash algorithm to be None for pure schemes; unwraps ML-DSA managed keys for signing.
trustpoint/request/operation_processor/csr_sign.py Unwraps managed keys before CSR signing to support ML-DSA.
trustpoint/request/message_parser/est.py Allows ML-DSA CSR verification without a signature hash algorithm.
trustpoint/request/message_builder/cmp.py Adds ML-DSA POP signature generation for CMP requests.
trustpoint/request/authorization/base.py Adds ML-DSA public key handling and security-policy restrictions.
trustpoint/pki/views/issuing_cas.py Broadens CMP param typing to include ML-DSA keys and adjusts casts.
trustpoint/pki/views/domains.py Formats ML-DSA signature-suite labels without hash details.
trustpoint/pki/util/x509.py Adds managed-key unwrapping for software-backed RSA/EC/ML-DSA and uses it for issuing CA signing.
trustpoint/pki/util/keys.py Adds ML-DSA AutoGenPKI key algorithm options based on backend capabilities.
trustpoint/pki/util/crl.py Unwraps managed keys before CRL signing.
trustpoint/pki/models/domain.py Adds signature_suite_display property for domains.
trustpoint/pki/models/certificate.py Adds ML-DSA OID choices, display helper, and SPKI parsing for ML-DSA public keys.
trustpoint/pki/models/ca.py Adds signature_suite_display property for CAs.
trustpoint/pki/migrations/0003_tp_v0_6_0.py Updates certificate model choices to include ML-DSA OIDs.
trustpoint/pki/forms/issuing_cas.py Adds ML-DSA key-type options and maps them to backend key specs.
trustpoint/pki/auto_gen_pki.py Extends AutoGenPKI key generation/storage flows to ML-DSA managed keys.
trustpoint/management/models/security.py Adds ML-DSA variant restriction field, defaults, and transition checks.
trustpoint/management/migrations/0003_tp_v0_6_0.py Adds not_permitted_mldsa_variant_oids and extends AutoGenPKI choices for ML-DSA.
trustpoint/help_pages/commands.py Adds OpenSSL key generation commands for ML-DSA variants.
trustpoint/devices/issuer.py Extends certificate issuance to handle ML-DSA key usage and signing with managed-key unwrapping.
trustpoint/crypto/domain/specs.py Adds ML-DSA key specs/variants and (renames) signing request helpers.
trustpoint/crypto/domain/algorithms.py Extends domain algorithm enums and supported public-key typing to ML-DSA.
trustpoint/crypto/domain/init.py Re-exports ML-DSA domain specs/variant types.
trustpoint/crypto/application/private_keys.py Adds ManagedMLDSAPrivateKey facade and supports resolving ML-DSA managed keys.
trustpoint/crypto/application/capabilities.py Adds ML-DSA variants to capability reporting and key-spec support checks.
trustpoint/crypto/adapters/software/backend.py Adds ML-DSA keygen/sign/load support in the software backend.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 59 to 65
@classmethod
def ecdsa_sha256(cls) -> SignRequest:
"""Build a common ECDSA request."""
def mldsa_pure(cls) -> SignRequest:
"""Build a pure ML-DSA request (no hash algorithm needed)."""
return cls(
signature_algorithm=SignatureAlgorithm.ECDSA,
hash_algorithm=HashAlgorithmName.SHA256,
signature_algorithm=SignatureAlgorithm.MLDSA,
hash_algorithm=HashAlgorithmName.SHA256, # Placeholder, not used for ML-DSA
)
Comment on lines +240 to +248
return self._crypto_backend.sign(
key=self._key_ref,
data=data,
request=SignRequest(
signature_algorithm=SignatureAlgorithm.MLDSA,
hash_algorithm=None,
prehashed=False,
),
)
Comment on lines +250 to +255
if isinstance(private_key, mldsa.MLDSA44PrivateKey):
algorithm_oid = AlgorithmIdentifier.MLDSA44.dotted_string
elif isinstance(private_key, mldsa.MLDSA65PrivateKey):
algorithm_oid = AlgorithmIdentifier.MLDSA65.dotted_string
else: # MLDSA87PrivateKey
algorithm_oid = AlgorithmIdentifier.MLDSA87.dotted_string
Comment on lines +392 to +402
not_permitted_mldsa: list[str] = cfg.not_permitted_mldsa_variant_oids or []
if not_permitted_mldsa:
if isinstance(public_key, mldsa.MLDSA44PublicKey):
variant_oid = AlgorithmIdentifier.MLDSA44.dotted_string
variant_name = 'ML-DSA-44'
elif isinstance(public_key, mldsa.MLDSA65PublicKey):
variant_oid = AlgorithmIdentifier.MLDSA65.dotted_string
variant_name = 'ML-DSA-65'
else: # MLDSA87PublicKey
variant_oid = AlgorithmIdentifier.MLDSA87.dotted_string
variant_name = 'ML-DSA-87'
Comment thread pyproject.toml
"pydeps>=3.0.1",
"python-pkcs11>=0.8.1",
"trustpoint-core==0.3.1",
"trustpoint-core @ git+https://github.com/Trustpoint-Project/trustpoint-core.git@ml_dsa",
Comment on lines +46 to +52
import logging
logger = logging.getLogger(__name__)

logger.debug(f'_unwrap_mldsa_managed_key: input type = {type(private_key).__name__}')
if not isinstance(private_key, (ManagedRSAPrivateKey, ManagedECPrivateKey, ManagedMLDSAPrivateKey)):
logger.debug('_unwrap_mldsa_managed_key: not a managed key, returning unchanged')
return private_key
Comment on lines 178 to +210
@@ -170,6 +201,16 @@ def _generate_private_key(self, key_spec: KeySpec) -> SupportedPrivateKey:
curve = self._curve_for_name(key_spec.curve)
return ec.generate_private_key(curve)

if isinstance(key_spec, MlDsaKeySpec):
if key_spec.variant is MlDsaVariant.MLDSA44:
return mldsa.MLDSA44PrivateKey.generate()
if key_spec.variant is MlDsaVariant.MLDSA65:
return mldsa.MLDSA65PrivateKey.generate()
if key_spec.variant is MlDsaVariant.MLDSA87:
return mldsa.MLDSA87PrivateKey.generate()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants