Skip to content

TPMU_SIG_SCHEME missing mldsa + hash_mldsa arms (V1.85 RC4 §11.3.5 Table 216) #504

Description

@eramusa

Summary

TPMU_SIG_SCHEME in wolftpm/tpm2.h is missing the two V1.85 RC4 union arms that V1.85 §11.3.5 Table 216 added for ML-DSA. As a result, sending inScheme.scheme = TPM_ALG_MLDSA (or TPM_ALG_HASH_MLDSA) in any wolfTPM command — TPM2_Quote, TPM2_Certify, TPM2_Sign, etc. — causes the TPM to respond with TPM_RC_SELECTOR (0x2d8) because the union body cannot be marshalled.

This was discovered while implementing the first independent post-quantum TPM 2.0 remote-attestation cross-check at pqctoday-org/pqctoday-tpm v0.4.0. Workaround: send inScheme.scheme = TPM_ALG_NULL — spec-allowed for ML-DSA AKs whose TPMS_MLDSA_PARMS has no explicit scheme field, but it cannot carry a FIPS 204 context string.

Current state (master @ commit `0ae18dc` / PR #501 merge)

```c
typedef union TPMU_SIG_SCHEME {
TPMS_SIG_SCHEME_RSASSA rsassa;
TPMS_SIG_SCHEME_RSAPSS rsapss;
TPMS_SIG_SCHEME_ECDSA ecdsa;
TPMS_SIG_SCHEME_ECDAA ecdaa;
TPMS_SCHEME_HMAC hmac;
TPMS_SCHEME_HASH any;
} TPMU_SIG_SCHEME;
```

No `#ifdef WOLFTPM_V185` block adds `mldsa` or `hash_mldsa`. Compare to `TPMU_SIGNATURE` which does have them.

V1.85 RC4 spec

Table 216 (Part 2 §11.3.5 — Definition of TPMU_SIG_SCHEME Union) adds:

Parameter Type Selector
mldsa TPMS_SIG_SCHEME_MLDSA TPM_ALG_MLDSA
hash_mldsa TPMS_SIG_SCHEME_HASH_MLDSA TPM_ALG_HASH_MLDSA

Companion struct types `TPMS_SIG_SCHEME_MLDSA` and `TPMS_SIG_SCHEME_HASH_MLDSA` (§11.3.6 / §11.3.7) are also missing from `tpm2.h`. Their definitions carry the FIPS 204 signature context string.

Reproducer

```c
WOLFTPM2_DEV dev; WOLFTPM2_KEY ak;
wolfTPM2_Init(&dev, TPM2_IoCb, NULL);
/* create a restricted+sign ML-DSA-65 AK */
TPMT_PUBLIC tpl;
wolfTPM2_GetKeyTemplate_MLDSA(&tpl,
TPMA_OBJECT_sign | TPMA_OBJECT_restricted | TPMA_OBJECT_fixedTPM |
TPMA_OBJECT_fixedParent | TPMA_OBJECT_sensitiveDataOrigin |
TPMA_OBJECT_userWithAuth | TPMA_OBJECT_noDA,
TPM_MLDSA_65, 0);
wolfTPM2_CreatePrimaryKey(&dev, &ak, TPM_RH_OWNER, &tpl, NULL, 0);

Quote_In in; XMEMSET(&in, 0, sizeof(in));
in.signHandle = ak.handle.hndl;
in.inScheme.scheme = TPM_ALG_MLDSA; /* <-- triggers the bug /
in.inScheme.details.any.hashAlg = TPM_ALG_SHA256;
/
... PCRselect setup ... */

Quote_Out out;
TPM_RC rc = TPM2_Quote(&in, &out);
/* rc == 0x2d8 (TPM_RC_SELECTOR) — TPM rejects the malformed inScheme union */
```

Tested against `pqctoday-tpm` swtpm with libtpms (V1.85 RC4-conformant TPM 2.0). The same reproducer with `in.inScheme.scheme = TPM_ALG_NULL` succeeds — confirming this is wolfTPM's marshaling, not the TPM's parsing.

Suggested fix

```c
typedef union TPMU_SIG_SCHEME {
TPMS_SIG_SCHEME_RSASSA rsassa;
TPMS_SIG_SCHEME_RSAPSS rsapss;
TPMS_SIG_SCHEME_ECDSA ecdsa;
TPMS_SIG_SCHEME_ECDAA ecdaa;
TPMS_SCHEME_HMAC hmac;
TPMS_SCHEME_HASH any;
#ifdef WOLFTPM_V185
/* v185 rc4 Part 2 §11.3.5 Table 216 + §11.3.6 / §11.3.7 */
TPMS_SIG_SCHEME_MLDSA mldsa;
TPMS_SIG_SCHEME_HASH_MLDSA hash_mldsa;
#endif
} TPMU_SIG_SCHEME;
```

Plus the two new `TPMS_SIG_SCHEME_*MLDSA` struct definitions (each carries a `TPM2B_SIGNATURE_CTX context` per FIPS 204; `TPM2B_SIGNATURE_CTX` already exists in `tpm2.h`). Marshal/Unmarshal hooks for `TPMT_SIG_SCHEME` need a switch case for `TPM_ALG_MLDSA` / `TPM_ALG_HASH_MLDSA` to route to the new struct.

Impact

Blocks any wolfTPM client from driving ML-DSA attestation flows with an explicit scheme. Notable for FIPS 204 context-string use, which the `scheme = NULL` workaround cannot carry.

References

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions