Skip to content

Commit ff65c9e

Browse files
committed
F-10826 - Validate v1.85 ML templates in TPM2_CreateLoaded
1 parent fa57c83 commit ff65c9e

2 files changed

Lines changed: 114 additions & 0 deletions

File tree

src/fwtpm/fwtpm_command.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6859,6 +6859,13 @@ static TPM_RC FwCmd_CreateLoaded(FWTPM_CTX* ctx, TPM2_Packet* cmd,
68596859
}
68606860
#endif
68616861

6862+
/* Validate ML template parameters before key generation (Part 2
6863+
* Tables 204/207/208/229-231). The unique public key is produced by
6864+
* key generation, so no size check applies here. */
6865+
if (rc == 0) {
6866+
rc = FwValidateMlTemplate(&inPublic->publicArea, 0);
6867+
}
6868+
68626869
/* Generate key -- same logic as Create */
68636870
if (rc == 0) {
68646871
switch (inPublic->publicArea.type) {

tests/fwtpm_unit_tests.c

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8172,6 +8172,112 @@ static void test_fwtpm_nv_define_write_read(void)
81728172
fwtpm_pass("NV Define/Write/Read/Undef:", 0);
81738173
}
81748174

8175+
/* TPM2_CreateLoaded must validate ML templates (parameter set, allowExternalMu,
8176+
* Hash-ML-DSA hashAlg, ML-KEM symmetric) before key generation
8177+
* (TCG v1.85 Part 2 Tables 204/207/208/229-231). */
8178+
static TPM_RC tmp_cl_ml(FWTPM_CTX* ctx, UINT32 parent, UINT16 algType,
8179+
UINT16 ps, byte mu, UINT16 hashAlg, UINT16 symAlg, UINT16 symBits)
8180+
{
8181+
int pos = 0, rspSize = 0, sensStart, sensLen, pubStart, pubLen;
8182+
UINT32 h;
8183+
PutU16BE(gCmd + pos, TPM_ST_SESSIONS); pos += 2;
8184+
PutU32BE(gCmd + pos, 0); pos += 4;
8185+
PutU32BE(gCmd + pos, TPM_CC_CreateLoaded); pos += 4;
8186+
PutU32BE(gCmd + pos, parent); pos += 4;
8187+
pos = AppendPwAuth(gCmd, pos, NULL, 0);
8188+
/* inSensitive */
8189+
sensStart = pos;
8190+
PutU16BE(gCmd + pos, 0); pos += 2;
8191+
PutU16BE(gCmd + pos, 0); pos += 2;
8192+
PutU16BE(gCmd + pos, 0); pos += 2;
8193+
sensLen = pos - sensStart - 2;
8194+
PutU16BE(gCmd + sensStart, (UINT16)sensLen);
8195+
/* inPublic template */
8196+
pubStart = pos;
8197+
PutU16BE(gCmd + pos, 0); pos += 2;
8198+
PutU16BE(gCmd + pos, algType); pos += 2;
8199+
PutU16BE(gCmd + pos, TPM_ALG_SHA256); pos += 2;
8200+
if (algType == TPM_ALG_MLKEM) {
8201+
PutU32BE(gCmd + pos, 0x00020072); pos += 4; /* decrypt */
8202+
}
8203+
else {
8204+
PutU32BE(gCmd + pos, 0x00040072); pos += 4; /* sign */
8205+
}
8206+
PutU16BE(gCmd + pos, 0); pos += 2; /* authPolicy */
8207+
PutU16BE(gCmd + pos, ps); pos += 2; /* parameterSet (before sym? no) */
8208+
if (algType == TPM_ALG_MLKEM) {
8209+
/* TPMS_MLKEM_PARMS: symmetric FIRST, then parameterSet. Rebuild. */
8210+
pos -= 2; /* undo ps */
8211+
PutU16BE(gCmd + pos, symAlg); pos += 2;
8212+
if (symAlg != TPM_ALG_NULL) {
8213+
PutU16BE(gCmd + pos, symBits); pos += 2;
8214+
PutU16BE(gCmd + pos, TPM_ALG_CFB); pos += 2;
8215+
}
8216+
PutU16BE(gCmd + pos, ps); pos += 2;
8217+
}
8218+
else if (algType == TPM_ALG_HASH_MLDSA) {
8219+
PutU16BE(gCmd + pos, hashAlg); pos += 2;
8220+
}
8221+
else {
8222+
gCmd[pos++] = mu;
8223+
}
8224+
PutU16BE(gCmd + pos, 0); pos += 2; /* unique size 0 */
8225+
pubLen = pos - pubStart - 2;
8226+
PutU16BE(gCmd + pubStart, (UINT16)pubLen);
8227+
PutU32BE(gCmd + 2, (UINT32)pos);
8228+
rspSize = 0;
8229+
FWTPM_ProcessCommand(ctx, gCmd, pos, gRsp, &rspSize, 0);
8230+
if (GetRspRC(gRsp) == TPM_RC_SUCCESS) {
8231+
h = GetU32BE(gRsp + TPM2_HEADER_SIZE);
8232+
FlushHandle(ctx, h);
8233+
}
8234+
return GetRspRC(gRsp);
8235+
}
8236+
8237+
static void test_fwtpm_createloaded_ml_validation(void)
8238+
{
8239+
FWTPM_CTX ctx;
8240+
UINT32 srk;
8241+
TPM_RC rc;
8242+
memset(&ctx, 0, sizeof(ctx));
8243+
AssertIntEQ(fwtpm_test_startup(&ctx), 0);
8244+
srk = make_srk_parent(&ctx);
8245+
AssertIntNE(srk, 0);
8246+
8247+
/* Baseline: valid MLDSA-65 template creates. */
8248+
rc = tmp_cl_ml(&ctx, srk, TPM_ALG_MLDSA, TPM_MLDSA_65, NO, 0,
8249+
TPM_ALG_NULL, 0);
8250+
printf(" valid MLDSA-65 CL rc=0x%x\n", rc);
8251+
AssertIntEQ(rc, TPM_RC_SUCCESS);
8252+
8253+
/* Unsupported parameter set. */
8254+
rc = tmp_cl_ml(&ctx, srk, TPM_ALG_MLDSA, 0x0099, NO, 0, TPM_ALG_NULL, 0);
8255+
printf(" MLDSA bad ps CL rc=0x%x\n", rc);
8256+
AssertIntEQ(rc, TPM_RC_PARMS);
8257+
8258+
/* allowExternalMu out of range (TPMI_YES_NO). */
8259+
rc = tmp_cl_ml(&ctx, srk, TPM_ALG_MLDSA, TPM_MLDSA_65, 0x02, 0,
8260+
TPM_ALG_NULL, 0);
8261+
printf(" MLDSA bad ext-mu CL rc=0x%x\n", rc);
8262+
AssertIntEQ(rc, TPM_RC_VALUE);
8263+
8264+
/* Hash-ML-DSA with an invalid pre-hash algorithm. */
8265+
rc = tmp_cl_ml(&ctx, srk, TPM_ALG_HASH_MLDSA, TPM_MLDSA_65, 0,
8266+
TPM_ALG_NULL, TPM_ALG_NULL, 0);
8267+
printf(" HASH_MLDSA bad hash CL rc=0x%x\n", rc);
8268+
AssertIntEQ(rc, TPM_RC_HASH);
8269+
8270+
/* ML-KEM invalid symmetric (AES bogus keyBits). */
8271+
rc = tmp_cl_ml(&ctx, srk, TPM_ALG_MLKEM, TPM_MLKEM_512, 0, 0,
8272+
TPM_ALG_AES, 7);
8273+
printf(" MLKEM bad symmetric CL rc=0x%x\n", rc);
8274+
AssertIntNE(rc, TPM_RC_SUCCESS);
8275+
8276+
FlushHandle(&ctx, srk);
8277+
FWTPM_Cleanup(&ctx);
8278+
fwtpm_pass("CreateLoaded ML validation:", 1);
8279+
}
8280+
81758281
static void test_fwtpm_nv_read_public(void)
81768282
{
81778283
FWTPM_CTX ctx;
@@ -11992,6 +12098,7 @@ int fwtpm_unit_tests(int argc, char *argv[])
1199212098
test_fwtpm_mlkem_wolfssl_keygen_kat();
1199312099
test_fwtpm_mldsa_loadexternal_verify();
1199412100
test_fwtpm_loadexternal_ml_validation();
12101+
test_fwtpm_createloaded_ml_validation();
1199512102
test_fwtpm_mldsa_primary_determinism();
1199612103
test_fwtpm_mlkem_primary_determinism();
1199712104
test_fwtpm_getcap_pqc();

0 commit comments

Comments
 (0)