microsoft / microsoft/mu_crypto_release
Enforce digest strength pairing for ML-DSA pre-hash (ML-DSA-MU) to prevent downgrade attacks
- Dominant language
- Assembly
- Stars
- 21
- Forks
- 23
- Avg merge
- 8d 16h
- Merged PRs (30d)
- 3
Description
## Context
Follow-up from review of PR #252 (OpensslPkg: Update openssl submodule to 4.0.0), specifically the changes in `OpensslPkg/Library/OpensslLib/OpensslStub/uefiprov.c`:
https://github.com/microsoft/mu_crypto_release/pull/252/changes#diff-dc489f55d9f86f846dfaf6cfbf238cb6dc0b1211ed48611ba8841cf1fdeb75c2
That PR registers `ossl_ml_dsa_mu_functions` (the ML-DSA "external mu" / pre-hash signature path) along with SHAKE-128/256 digests in the default provider's algorithm tables:
```c
#ifndef OPENSSL_NO_SHAKE
{ PROV_NAMES_SHAKE_128, "provider=default", ossl_shake_128_functions },
{ PROV_NAMES_SHAKE_256, "provider=default", ossl_shake_256_functions },
#endif
#ifndef OPENSSL_NO_ML_DSA
{ PROV_NAMES_ML_DSA_MU, "provider=default", ossl_ml_dsa_mu_functions },
#endif
```
as well as ML-DSA-44/65/87 signature and keymgmt functions, and ML-KEM/composite KEM (`deflt_asym_kem`) support.
## Problem
With ML-DSA-MU (pre-hash) enabled, a signer/verifier could pair a high-security-level ML-DSA key (e.g., ML-DSA-87, nominally NIST Category 5 / ~256-bit strength) with a weak pre-hash digest (e.g., SHA-1, MD5, or even SHA-256) in a CMS/PKCS#7 `SignerInfo`. Because the overall signature's effective security is bounded by `min(security_strength(ML-DSA level), security_strength(digest))`, this allows a silent downgrade of the claimed security strength — the same class of "hash substitution" / weak-digest attack that has historically affected RSA-PSS/ECDSA/PKCS#1v1.5 constructions.
Today there does not appear to be any enforced pairing/allow-list between the ML-DSA parameter set in use and the digest algorithm used for pre-hashing, either at the OpenSSL provider layer or in the UEFI PKCS#7 verification wrapper.
For reference, a similar (but simpler, non-ML-DSA-aware) enforcement pattern already exists for classical algorithms in `mu_basecore`'s `SecurityPkg/Library/AuthVariableLib/AuthService.c`, which restricts `SignedData.digestAlgorithms` to SHA-256/384/512, with parsing handled in `WrapPkcs7Data()` in `CryptPkcs7VerifyCommon.c`. That pattern is a flat allow-list independent of the signing algorithm/key strength — it would need to become key-strength-aware to properly cover ML-DSA.
## Proposed Fix (two complementary layers)
1. **Provider-level allow-list/strength check** near `ossl_ml_dsa_mu_functions` (or a thin wrapping dispatch table in `uefiprov.c` that intercepts sign/verify init calls before delegating): reject digests weaker than what's appropriate for the ML-DSA parameter set in use (e.g., reject SHA-1, MD5, SHA-224, and arguably SHA-256 for ML-DSA-87), mirroring NIST SP 800-57 strength-pairing guidance. This is the most robust fix since it can't be bypassed by whatever constructs the CMS `SignerInfo`.
2. **UEFI crypto wrapper check** in `CryptPkcs7VerifyCommon.c` (present in `OpensslPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c` and the `MbedTlsPkg` equivalent) — parse both `SignerInfo.digestAlgorithm` and the signature algorithm/key type, and enforce a minimum digest strength conditional on the ML-DSA level (44/65/87) or composite OID in use, extending the existing flat SHA-256/384/512 allow-list pattern seen in `AuthService.c` to be ML-DSA-parameter-set-aware. Since this file is duplicated across BaseCryptLib instances, the fix likely needs to be applied in each instance (or consolidated).
## Additional considerations
- If IETF composite signature OIDs (draft-ietf-lamps-pq-composite-sigs) are used instead of raw ML-DSA-MU, the digest is already fixed per-OID (e.g., `id-MLDSA87-ECDSA-P384-SHA512` implies SHA-512) — validation there just needs to confirm the OID matches the actual digest used, rather than allowing arbitrary pairing.
- This should be tracked as a hardening/security follow-up before ML-DSA pre-hash paths are relied upon in production signing/verification flows.
## Acceptance Criteria
- [ ] Define and document a strength-pairing table between ML-DSA parameter sets (44/65/87) and minimum acceptable pre-hash digest algorithms.
- [ ] Add enforcement at the OpenSSL provider layer (or UEFI stub wrapper) for ML-DSA-MU sign/verify operations.
- [ ] Add/extend enforcement in `CryptPkcs7VerifyCommon.c` (all BaseCryptLib instances) to validate digest algorithm strength against the ML-DSA/composite signature algorithm in the SignerInfo.
- [ ] Add unit tests covering rejection of weak digest + strong ML-DSA key combinations.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by reviewing the ML-DSA-MU registration in OpensslPkg/Library/OpensslLib/OpensslStub/uefiprov.c, then compare the existing digest handling in CryptPkcs7VerifyCommon.c and AuthService.c. Define the 44/65/87 digest-strength table, enforce it in the provider or UEFI wrapper and all relevant BaseCryptLib instances, and add tests covering weak digests with strong ML-DSA keys.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- cryptography, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100