Conversation
📋 License Check Report
Note: This project is MIT-licensed. LGPL and most permissive licenses are compatible. GPL and proprietary licenses require review. |
|
❌ 1 Tests Failed:
View the top 1 failed test(s) by shortest run time
To view more test analytics, go to the Test Analytics Dashboard |
| 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 |
There was a problem hiding this comment.
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_displayhelpers 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.
| @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 | ||
| ) |
| return self._crypto_backend.sign( | ||
| key=self._key_ref, | ||
| data=data, | ||
| request=SignRequest( | ||
| signature_algorithm=SignatureAlgorithm.MLDSA, | ||
| hash_algorithm=None, | ||
| prehashed=False, | ||
| ), | ||
| ) |
| 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 |
| 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' |
| "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", |
| 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 |
| @@ -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() | |||
Legal