mirror of https://github.com/wolfSSL/wolfTPM.git
Phase 8a: add PQC end-to-end tests; fix FIPS 204 hedged-sign RNG
tests/fwtpm_unit_tests.c:
- Extend BuildCreatePrimaryCmd to emit MLKEM-768, MLDSA-65, and
Hash-MLDSA-65/SHA-256 TPMT_PUBLIC templates per Part 2 Table 232.
- test_fwtpm_create_primary_mlkem: sanity-check MLKEM keygen path.
- test_fwtpm_create_primary_mldsa: sanity-check MLDSA keygen path.
- test_fwtpm_mlkem_roundtrip: CreatePrimary MLKEM-768 → Encapsulate →
Decapsulate, asserts both shared secrets are 32 bytes and identical.
Proves Phase 3 KDFa derivation + Phase 4 encap/decap crypto + wire
format for TPM2B_SHARED_SECRET and TPM2B_KEM_CIPHERTEXT.
- test_fwtpm_mldsa_digest_roundtrip: CreatePrimary Hash-MLDSA-65 →
SignDigest → VerifyDigestSignature, asserts TPM_ST_DIGEST_VERIFIED
ticket. Proves Phase 5 digest handlers and Bug M-4 metadata format.
- test_fwtpm_mldsa_sequence_roundtrip: CreatePrimary Pure MLDSA-65 →
SignSequenceStart → SignSequenceComplete → VerifySequenceStart →
SequenceUpdate → VerifySequenceComplete, asserts TPM_ST_MESSAGE_
VERIFIED. Proves Phase 5 sign path, Phase 5b one-shot semantics and
message accumulator, and Bug M-1 Pure-MLDSA wire format.
Wired into main(); all five tests pass on --enable-v185.
src/fwtpm/fwtpm_crypto.c, wolftpm/fwtpm/fwtpm_crypto.h:
- Fix: FwSignMldsaMessage and FwSignMldsaHash now take a WC_RNG*.
wolfCrypt wc_dilithium_sign_ctx_msg / sign_ctx_hash require a
non-NULL RNG to source the 32-byte value for hedged signing
(FIPS 204 Algorithm 2 step 7). The Phase 5 code passed NULL and
returned BAD_FUNC_ARG at runtime. Both hedged and deterministic
signing are FIPS 204 compliant; wolfCrypt's non-_with_seed API
chose hedged, matching normal TPM side-channel practice.
src/fwtpm/fwtpm_command.c:
- Pass &ctx->rng to the two updated sign helpers from FwCmd_SignDigest
and FwCmd_SignSequenceComplete.
pull/445/head
parent
bef99113c5
commit
ef31aa8f79
|
|
@ -13207,7 +13207,7 @@ static TPM_RC FwCmd_SignSequenceComplete(FWTPM_CTX* ctx, TPM2_Packet* cmd,
|
|||
TPM2_Packet_ParseBytes(cmd, msgBuf, bufSize);
|
||||
|
||||
if (keyObj->pub.type == TPM_ALG_MLDSA) {
|
||||
rc = FwSignMldsaMessage(
|
||||
rc = FwSignMldsaMessage(&ctx->rng,
|
||||
keyObj->pub.parameters.mldsaDetail.parameterSet,
|
||||
keyObj->privKey,
|
||||
seq->context.buffer, seq->context.size,
|
||||
|
|
@ -13240,7 +13240,7 @@ static TPM_RC FwCmd_SignSequenceComplete(FWTPM_CTX* ctx, TPM2_Packet* cmd,
|
|||
}
|
||||
if (rc == 0) {
|
||||
digestSz = TPM2_GetHashDigestSize(seq->hashAlg);
|
||||
rc = FwSignMldsaHash(
|
||||
rc = FwSignMldsaHash(&ctx->rng,
|
||||
keyObj->pub.parameters.hash_mldsaDetail.parameterSet,
|
||||
keyObj->privKey,
|
||||
seq->context.buffer, seq->context.size,
|
||||
|
|
@ -13524,7 +13524,7 @@ static TPM_RC FwCmd_SignDigest(FWTPM_CTX* ctx, TPM2_Packet* cmd, int cmdSize,
|
|||
}
|
||||
}
|
||||
else if (obj->pub.type == TPM_ALG_HASH_MLDSA) {
|
||||
rc = FwSignMldsaHash(
|
||||
rc = FwSignMldsaHash(&ctx->rng,
|
||||
obj->pub.parameters.hash_mldsaDetail.parameterSet,
|
||||
obj->privKey,
|
||||
sigCtx->buffer, sigCtx->size,
|
||||
|
|
|
|||
|
|
@ -1013,7 +1013,8 @@ static TPM_RC FwLoadMldsaFromSeed(TPMI_MLDSA_PARAMETER_SET parameterSet,
|
|||
/** \brief Pure ML-DSA sign: full-message signing per FIPS 204 ML-DSA.Sign.
|
||||
* Takes the stored 32-byte xi seed and the raw message. The TPM computes
|
||||
* mu internally. */
|
||||
TPM_RC FwSignMldsaMessage(TPMI_MLDSA_PARAMETER_SET parameterSet,
|
||||
TPM_RC FwSignMldsaMessage(WC_RNG* rng,
|
||||
TPMI_MLDSA_PARAMETER_SET parameterSet,
|
||||
const byte* seedXi,
|
||||
const byte* context, int contextSz,
|
||||
const byte* msg, int msgSz,
|
||||
|
|
@ -1031,11 +1032,14 @@ TPM_RC FwSignMldsaMessage(TPMI_MLDSA_PARAMETER_SET parameterSet,
|
|||
|
||||
if (rc == 0) {
|
||||
sigSz = (word32)sizeof(sigOut->buffer);
|
||||
/* FIPS 204 Algorithm 2 hedged sign: wolfCrypt requires a non-NULL
|
||||
* RNG to source the 32-byte `rnd` value. Passing the TPM's internal
|
||||
* RNG matches normal TPM signing practice (side-channel hedging). */
|
||||
wcRet = wc_dilithium_sign_ctx_msg(
|
||||
context, (byte)contextSz,
|
||||
msg, (word32)msgSz,
|
||||
sigOut->buffer, &sigSz,
|
||||
keyVar, NULL /* deterministic when available */);
|
||||
keyVar, rng);
|
||||
if (wcRet != 0) {
|
||||
rc = TPM_RC_FAILURE;
|
||||
}
|
||||
|
|
@ -1109,7 +1113,8 @@ TPM_RC FwVerifyMldsaMessage(TPMI_MLDSA_PARAMETER_SET parameterSet,
|
|||
}
|
||||
|
||||
/** \brief Hash-ML-DSA sign: pre-hashed variant per FIPS 204 Algorithm 4. */
|
||||
TPM_RC FwSignMldsaHash(TPMI_MLDSA_PARAMETER_SET parameterSet,
|
||||
TPM_RC FwSignMldsaHash(WC_RNG* rng,
|
||||
TPMI_MLDSA_PARAMETER_SET parameterSet,
|
||||
const byte* seedXi,
|
||||
const byte* context, int contextSz,
|
||||
TPMI_ALG_HASH hashAlg,
|
||||
|
|
@ -1135,11 +1140,12 @@ TPM_RC FwSignMldsaHash(TPMI_MLDSA_PARAMETER_SET parameterSet,
|
|||
|
||||
if (rc == 0) {
|
||||
sigSz = (word32)sizeof(sigOut->buffer);
|
||||
/* Hedged sign (FIPS 204 Alg 2 step 7) — wolfCrypt requires RNG. */
|
||||
wcRet = wc_dilithium_sign_ctx_hash(
|
||||
context, (byte)contextSz,
|
||||
wcHash, digest, (word32)digestSz,
|
||||
sigOut->buffer, &sigSz,
|
||||
keyVar, NULL);
|
||||
keyVar, rng);
|
||||
if (wcRet != 0) {
|
||||
rc = TPM_RC_FAILURE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -865,7 +865,7 @@ static int BuildCreatePrimaryCmd(byte* buf, TPM_ALG_ID algType)
|
|||
/* unique (TPM2B): size=0 (TPM generates) */
|
||||
PutU16BE(buf + pos, 0); pos += 2;
|
||||
}
|
||||
else { /* ECC */
|
||||
else if (algType == TPM_ALG_ECC) {
|
||||
PutU16BE(buf + pos, TPM_ALG_ECC); pos += 2; /* type */
|
||||
PutU16BE(buf + pos, TPM_ALG_SHA256); pos += 2; /* nameAlg */
|
||||
PutU32BE(buf + pos, 0x00030472); pos += 4; /* objectAttributes */
|
||||
|
|
@ -882,6 +882,49 @@ static int BuildCreatePrimaryCmd(byte* buf, TPM_ALG_ID algType)
|
|||
PutU16BE(buf + pos, 0); pos += 2;
|
||||
PutU16BE(buf + pos, 0); pos += 2;
|
||||
}
|
||||
#ifdef WOLFTPM_V185
|
||||
else if (algType == TPM_ALG_MLKEM) {
|
||||
/* MLKEM-768 decrypt-only primary. Attributes:
|
||||
* fixedTPM|fixedParent|sensitiveDataOrigin|userWithAuth|decrypt */
|
||||
PutU16BE(buf + pos, TPM_ALG_MLKEM); pos += 2;
|
||||
PutU16BE(buf + pos, TPM_ALG_SHA256); pos += 2;
|
||||
PutU32BE(buf + pos, 0x00020072); pos += 4;
|
||||
PutU16BE(buf + pos, 0); pos += 2; /* authPolicy */
|
||||
/* TPMS_MLKEM_PARMS: symmetric(TPM_ALG_NULL) + parameterSet */
|
||||
PutU16BE(buf + pos, TPM_ALG_NULL); pos += 2;
|
||||
PutU16BE(buf + pos, TPM_MLKEM_768); pos += 2;
|
||||
/* unique.mlkem (TPM2B): size=0 — TPM derives */
|
||||
PutU16BE(buf + pos, 0); pos += 2;
|
||||
}
|
||||
else if (algType == TPM_ALG_MLDSA) {
|
||||
/* MLDSA-65 sign-only primary. Attributes:
|
||||
* fixedTPM|fixedParent|sensitiveDataOrigin|userWithAuth|sign */
|
||||
PutU16BE(buf + pos, TPM_ALG_MLDSA); pos += 2;
|
||||
PutU16BE(buf + pos, TPM_ALG_SHA256); pos += 2;
|
||||
PutU32BE(buf + pos, 0x00040072); pos += 4;
|
||||
PutU16BE(buf + pos, 0); pos += 2; /* authPolicy */
|
||||
/* TPMS_MLDSA_PARMS: parameterSet + allowExternalMu */
|
||||
PutU16BE(buf + pos, TPM_MLDSA_65); pos += 2;
|
||||
buf[pos++] = NO; /* allowExternalMu */
|
||||
/* unique.mldsa: size=0 */
|
||||
PutU16BE(buf + pos, 0); pos += 2;
|
||||
}
|
||||
else if (algType == TPM_ALG_HASH_MLDSA) {
|
||||
/* HashML-DSA-65 with SHA-256 pre-hash. sign-only attributes. */
|
||||
PutU16BE(buf + pos, TPM_ALG_HASH_MLDSA); pos += 2;
|
||||
PutU16BE(buf + pos, TPM_ALG_SHA256); pos += 2;
|
||||
PutU32BE(buf + pos, 0x00040072); pos += 4;
|
||||
PutU16BE(buf + pos, 0); pos += 2; /* authPolicy */
|
||||
/* TPMS_HASH_MLDSA_PARMS: parameterSet + hashAlg */
|
||||
PutU16BE(buf + pos, TPM_MLDSA_65); pos += 2;
|
||||
PutU16BE(buf + pos, TPM_ALG_SHA256); pos += 2;
|
||||
/* unique.mldsa: size=0 */
|
||||
PutU16BE(buf + pos, 0); pos += 2;
|
||||
}
|
||||
#endif /* WOLFTPM_V185 */
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pubAreaLen = pos - pubAreaStart - 2;
|
||||
PutU16BE(buf + pubAreaStart, (UINT16)pubAreaLen);
|
||||
|
|
@ -966,6 +1009,420 @@ static void test_fwtpm_create_primary_ecc(void)
|
|||
}
|
||||
#endif /* HAVE_ECC */
|
||||
|
||||
#ifdef WOLFTPM_V185
|
||||
static void test_fwtpm_create_primary_mlkem(void)
|
||||
{
|
||||
FWTPM_CTX ctx;
|
||||
int rc, rspSize, cmdSz;
|
||||
UINT32 handle;
|
||||
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
rc = fwtpm_test_startup(&ctx);
|
||||
AssertIntEQ(rc, 0);
|
||||
|
||||
cmdSz = BuildCreatePrimaryCmd(gCmd, TPM_ALG_MLKEM);
|
||||
rspSize = 0;
|
||||
rc = FWTPM_ProcessCommand(&ctx, gCmd, cmdSz, gRsp, &rspSize, 0);
|
||||
AssertIntEQ(rc, TPM_RC_SUCCESS);
|
||||
AssertIntEQ(GetRspRC(gRsp), TPM_RC_SUCCESS);
|
||||
AssertIntGT(rspSize, TPM2_HEADER_SIZE + 4);
|
||||
|
||||
handle = GetU32BE(gRsp + TPM2_HEADER_SIZE);
|
||||
AssertIntNE(handle, 0);
|
||||
|
||||
/* Flush */
|
||||
cmdSz = BuildCmdHeader(gCmd, TPM_ST_NO_SESSIONS, 14, TPM_CC_FlushContext);
|
||||
PutU32BE(gCmd + 10, handle);
|
||||
rspSize = 0;
|
||||
FWTPM_ProcessCommand(&ctx, gCmd, 14, gRsp, &rspSize, 0);
|
||||
|
||||
FWTPM_Cleanup(&ctx);
|
||||
printf("Test fwTPM:\tCreatePrimary(MLKEM-768):\t\tPassed\n");
|
||||
}
|
||||
|
||||
static void test_fwtpm_create_primary_mldsa(void)
|
||||
{
|
||||
FWTPM_CTX ctx;
|
||||
int rc, rspSize, cmdSz;
|
||||
UINT32 handle;
|
||||
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
rc = fwtpm_test_startup(&ctx);
|
||||
AssertIntEQ(rc, 0);
|
||||
|
||||
cmdSz = BuildCreatePrimaryCmd(gCmd, TPM_ALG_MLDSA);
|
||||
rspSize = 0;
|
||||
rc = FWTPM_ProcessCommand(&ctx, gCmd, cmdSz, gRsp, &rspSize, 0);
|
||||
AssertIntEQ(rc, TPM_RC_SUCCESS);
|
||||
AssertIntEQ(GetRspRC(gRsp), TPM_RC_SUCCESS);
|
||||
AssertIntGT(rspSize, TPM2_HEADER_SIZE + 4);
|
||||
|
||||
handle = GetU32BE(gRsp + TPM2_HEADER_SIZE);
|
||||
AssertIntNE(handle, 0);
|
||||
|
||||
/* Flush */
|
||||
cmdSz = BuildCmdHeader(gCmd, TPM_ST_NO_SESSIONS, 14, TPM_CC_FlushContext);
|
||||
PutU32BE(gCmd + 10, handle);
|
||||
rspSize = 0;
|
||||
FWTPM_ProcessCommand(&ctx, gCmd, 14, gRsp, &rspSize, 0);
|
||||
|
||||
FWTPM_Cleanup(&ctx);
|
||||
printf("Test fwTPM:\tCreatePrimary(MLDSA-65):\t\tPassed\n");
|
||||
}
|
||||
|
||||
/* End-to-end Layer D: CreatePrimary MLKEM → Encapsulate → Decapsulate.
|
||||
* Asserts that the two shared secrets match, proving FIPS 203 is wired
|
||||
* correctly from keygen through encaps and decaps. */
|
||||
static void test_fwtpm_mlkem_roundtrip(void)
|
||||
{
|
||||
FWTPM_CTX ctx;
|
||||
int rc, rspSize, cmdSz;
|
||||
UINT32 handle;
|
||||
int pos;
|
||||
int paramSzPos;
|
||||
UINT16 ss1Sz, ct1Sz, ss2Sz;
|
||||
byte ss1[64];
|
||||
FWTPM_DECLARE_BUF(ct1, 2048);
|
||||
byte ss2[64];
|
||||
|
||||
FWTPM_ALLOC_BUF(ct1, 2048);
|
||||
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
rc = fwtpm_test_startup(&ctx);
|
||||
AssertIntEQ(rc, 0);
|
||||
|
||||
/* CreatePrimary(MLKEM-768) */
|
||||
cmdSz = BuildCreatePrimaryCmd(gCmd, TPM_ALG_MLKEM);
|
||||
rspSize = 0;
|
||||
rc = FWTPM_ProcessCommand(&ctx, gCmd, cmdSz, gRsp, &rspSize, 0);
|
||||
AssertIntEQ(rc, TPM_RC_SUCCESS);
|
||||
AssertIntEQ(GetRspRC(gRsp), TPM_RC_SUCCESS);
|
||||
handle = GetU32BE(gRsp + TPM2_HEADER_SIZE);
|
||||
AssertIntNE(handle, 0);
|
||||
|
||||
/* Encapsulate — no auth required (Auth Index: None).
|
||||
* Command: tag | size | cc | keyHandle */
|
||||
cmdSz = BuildCmdHeader(gCmd, TPM_ST_NO_SESSIONS, 14, TPM_CC_Encapsulate);
|
||||
PutU32BE(gCmd + 10, handle);
|
||||
rspSize = 0;
|
||||
rc = FWTPM_ProcessCommand(&ctx, gCmd, 14, gRsp, &rspSize, 0);
|
||||
AssertIntEQ(rc, TPM_RC_SUCCESS);
|
||||
AssertIntEQ(GetRspRC(gRsp), TPM_RC_SUCCESS);
|
||||
|
||||
/* Response: header | sharedSecret TPM2B | ciphertext TPM2B */
|
||||
pos = TPM2_HEADER_SIZE;
|
||||
ss1Sz = GetU16BE(gRsp + pos); pos += 2;
|
||||
AssertIntEQ(ss1Sz, 32);
|
||||
memcpy(ss1, gRsp + pos, ss1Sz); pos += ss1Sz;
|
||||
ct1Sz = GetU16BE(gRsp + pos); pos += 2;
|
||||
AssertIntEQ(ct1Sz, 1088); /* MLKEM-768 ct size per Table 204 */
|
||||
memcpy(ct1, gRsp + pos, ct1Sz);
|
||||
|
||||
/* Decapsulate — USER auth required.
|
||||
* Command: tag(SESSIONS) | size | cc | keyHandle | authArea | ct */
|
||||
pos = 0;
|
||||
PutU16BE(gCmd + pos, TPM_ST_SESSIONS); pos += 2;
|
||||
PutU32BE(gCmd + pos, 0); pos += 4; /* size placeholder */
|
||||
PutU32BE(gCmd + pos, TPM_CC_Decapsulate); pos += 4;
|
||||
PutU32BE(gCmd + pos, handle); pos += 4;
|
||||
/* Auth area: password session, empty password */
|
||||
PutU32BE(gCmd + pos, 9); pos += 4;
|
||||
PutU32BE(gCmd + pos, TPM_RS_PW); pos += 4;
|
||||
PutU16BE(gCmd + pos, 0); pos += 2; /* nonce */
|
||||
gCmd[pos++] = 0; /* attributes */
|
||||
PutU16BE(gCmd + pos, 0); pos += 2; /* hmac */
|
||||
/* Parameters: ciphertext (TPM2B_KEM_CIPHERTEXT) */
|
||||
PutU16BE(gCmd + pos, ct1Sz); pos += 2;
|
||||
memcpy(gCmd + pos, ct1, ct1Sz); pos += ct1Sz;
|
||||
PutU32BE(gCmd + 2, (UINT32)pos);
|
||||
|
||||
rspSize = 0;
|
||||
rc = FWTPM_ProcessCommand(&ctx, gCmd, pos, gRsp, &rspSize, 0);
|
||||
AssertIntEQ(rc, TPM_RC_SUCCESS);
|
||||
AssertIntEQ(GetRspRC(gRsp), TPM_RC_SUCCESS);
|
||||
|
||||
/* Response: header | paramSize (U32 because ST_SESSIONS) | sharedSecret */
|
||||
paramSzPos = TPM2_HEADER_SIZE;
|
||||
(void)GetU32BE(gRsp + paramSzPos); /* skip paramSize */
|
||||
pos = paramSzPos + 4;
|
||||
ss2Sz = GetU16BE(gRsp + pos); pos += 2;
|
||||
AssertIntEQ(ss2Sz, 32);
|
||||
memcpy(ss2, gRsp + pos, ss2Sz);
|
||||
|
||||
/* The whole point: shared secrets must be equal. */
|
||||
AssertIntEQ(memcmp(ss1, ss2, 32), 0);
|
||||
|
||||
/* Flush */
|
||||
cmdSz = BuildCmdHeader(gCmd, TPM_ST_NO_SESSIONS, 14, TPM_CC_FlushContext);
|
||||
PutU32BE(gCmd + 10, handle);
|
||||
rspSize = 0;
|
||||
FWTPM_ProcessCommand(&ctx, gCmd, 14, gRsp, &rspSize, 0);
|
||||
|
||||
FWTPM_Cleanup(&ctx);
|
||||
FWTPM_FREE_BUF(ct1);
|
||||
printf("Test fwTPM:\tMLKEM Encap/Decap Roundtrip:\t\tPassed\n");
|
||||
}
|
||||
|
||||
/* Layer D: Hash-MLDSA-65 SignDigest → VerifyDigestSignature round-trip.
|
||||
* Verifies the signature-ticket validation path (Bug M-4 metadata field). */
|
||||
static void test_fwtpm_mldsa_digest_roundtrip(void)
|
||||
{
|
||||
FWTPM_CTX ctx;
|
||||
int rc, rspSize, cmdSz, pos;
|
||||
UINT32 handle;
|
||||
UINT16 sigAlg, sigHash, sigSz, valTag;
|
||||
FWTPM_DECLARE_BUF(sig, MAX_MLDSA_SIG_SIZE);
|
||||
byte digest[32];
|
||||
|
||||
FWTPM_ALLOC_BUF(sig, MAX_MLDSA_SIG_SIZE);
|
||||
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
rc = fwtpm_test_startup(&ctx);
|
||||
AssertIntEQ(rc, 0);
|
||||
|
||||
/* CreatePrimary(Hash-MLDSA-65 / SHA-256) */
|
||||
cmdSz = BuildCreatePrimaryCmd(gCmd, TPM_ALG_HASH_MLDSA);
|
||||
rspSize = 0;
|
||||
rc = FWTPM_ProcessCommand(&ctx, gCmd, cmdSz, gRsp, &rspSize, 0);
|
||||
AssertIntEQ(rc, TPM_RC_SUCCESS);
|
||||
AssertIntEQ(GetRspRC(gRsp), TPM_RC_SUCCESS);
|
||||
handle = GetU32BE(gRsp + TPM2_HEADER_SIZE);
|
||||
AssertIntNE(handle, 0);
|
||||
|
||||
/* Canonical test digest (32 bytes of 0xAA). */
|
||||
memset(digest, 0xAA, sizeof(digest));
|
||||
|
||||
/* SignDigest command:
|
||||
* tag=SESSIONS | size | cc | @keyHandle(USER auth) |
|
||||
* context(TPM2B empty) | digest(TPM2B) | validation(TPMT_TK_HASHCHECK NULL) */
|
||||
pos = 0;
|
||||
PutU16BE(gCmd + pos, TPM_ST_SESSIONS); pos += 2;
|
||||
PutU32BE(gCmd + pos, 0); pos += 4;
|
||||
PutU32BE(gCmd + pos, TPM_CC_SignDigest); pos += 4;
|
||||
PutU32BE(gCmd + pos, handle); pos += 4;
|
||||
/* Auth: password session empty */
|
||||
PutU32BE(gCmd + pos, 9); pos += 4;
|
||||
PutU32BE(gCmd + pos, TPM_RS_PW); pos += 4;
|
||||
PutU16BE(gCmd + pos, 0); pos += 2;
|
||||
gCmd[pos++] = 0;
|
||||
PutU16BE(gCmd + pos, 0); pos += 2;
|
||||
/* context empty */
|
||||
PutU16BE(gCmd + pos, 0); pos += 2;
|
||||
/* digest */
|
||||
PutU16BE(gCmd + pos, 32); pos += 2;
|
||||
memcpy(gCmd + pos, digest, 32); pos += 32;
|
||||
/* validation NULL ticket: tag TPM_ST_HASHCHECK + hierarchy NULL + empty digest */
|
||||
PutU16BE(gCmd + pos, TPM_ST_HASHCHECK); pos += 2;
|
||||
PutU32BE(gCmd + pos, TPM_RH_NULL); pos += 4;
|
||||
PutU16BE(gCmd + pos, 0); pos += 2;
|
||||
PutU32BE(gCmd + 2, (UINT32)pos);
|
||||
|
||||
rspSize = 0;
|
||||
rc = FWTPM_ProcessCommand(&ctx, gCmd, pos, gRsp, &rspSize, 0);
|
||||
AssertIntEQ(rc, TPM_RC_SUCCESS);
|
||||
AssertIntEQ(GetRspRC(gRsp), TPM_RC_SUCCESS);
|
||||
|
||||
/* Response: header | paramSize | sigAlg(2) | hash(2) | sigSz(2) | sig */
|
||||
pos = TPM2_HEADER_SIZE + 4;
|
||||
sigAlg = GetU16BE(gRsp + pos); pos += 2;
|
||||
AssertIntEQ(sigAlg, TPM_ALG_HASH_MLDSA);
|
||||
sigHash = GetU16BE(gRsp + pos); pos += 2;
|
||||
AssertIntEQ(sigHash, TPM_ALG_SHA256);
|
||||
sigSz = GetU16BE(gRsp + pos); pos += 2;
|
||||
AssertIntEQ(sigSz, 3309); /* MLDSA-65 signature size per Table 207 */
|
||||
memcpy(sig, gRsp + pos, sigSz);
|
||||
|
||||
/* VerifyDigestSignature command:
|
||||
* tag | size | cc | keyHandle(no auth) |
|
||||
* context(empty) | digest | signature */
|
||||
pos = 0;
|
||||
PutU16BE(gCmd + pos, TPM_ST_NO_SESSIONS); pos += 2;
|
||||
PutU32BE(gCmd + pos, 0); pos += 4;
|
||||
PutU32BE(gCmd + pos, TPM_CC_VerifyDigestSignature); pos += 4;
|
||||
PutU32BE(gCmd + pos, handle); pos += 4;
|
||||
/* context empty */
|
||||
PutU16BE(gCmd + pos, 0); pos += 2;
|
||||
/* digest */
|
||||
PutU16BE(gCmd + pos, 32); pos += 2;
|
||||
memcpy(gCmd + pos, digest, 32); pos += 32;
|
||||
/* signature: sigAlg + hash + TPM2B */
|
||||
PutU16BE(gCmd + pos, TPM_ALG_HASH_MLDSA); pos += 2;
|
||||
PutU16BE(gCmd + pos, TPM_ALG_SHA256); pos += 2;
|
||||
PutU16BE(gCmd + pos, sigSz); pos += 2;
|
||||
memcpy(gCmd + pos, sig, sigSz); pos += sigSz;
|
||||
PutU32BE(gCmd + 2, (UINT32)pos);
|
||||
|
||||
rspSize = 0;
|
||||
rc = FWTPM_ProcessCommand(&ctx, gCmd, pos, gRsp, &rspSize, 0);
|
||||
AssertIntEQ(rc, TPM_RC_SUCCESS);
|
||||
AssertIntEQ(GetRspRC(gRsp), TPM_RC_SUCCESS);
|
||||
|
||||
/* Response: header | validation.tag | hierarchy | metadata(TPM_ALG_ID) | hmac */
|
||||
pos = TPM2_HEADER_SIZE;
|
||||
valTag = GetU16BE(gRsp + pos); pos += 2;
|
||||
AssertIntEQ(valTag, TPM_ST_DIGEST_VERIFIED);
|
||||
|
||||
/* Flush */
|
||||
cmdSz = BuildCmdHeader(gCmd, TPM_ST_NO_SESSIONS, 14, TPM_CC_FlushContext);
|
||||
PutU32BE(gCmd + 10, handle);
|
||||
rspSize = 0;
|
||||
FWTPM_ProcessCommand(&ctx, gCmd, 14, gRsp, &rspSize, 0);
|
||||
|
||||
FWTPM_Cleanup(&ctx);
|
||||
FWTPM_FREE_BUF(sig);
|
||||
printf("Test fwTPM:\tMLDSA SignDigest/Verify Roundtrip:\tPassed\n");
|
||||
}
|
||||
|
||||
/* Layer D: Pure MLDSA-65 sign/verify sequence round-trip.
|
||||
* SignSequenceComplete is one-shot via buffer; VerifySequenceComplete
|
||||
* consumes a message accumulated via SequenceUpdate. */
|
||||
static void test_fwtpm_mldsa_sequence_roundtrip(void)
|
||||
{
|
||||
FWTPM_CTX ctx;
|
||||
int rc, rspSize, pos;
|
||||
UINT32 handle;
|
||||
UINT32 signSeqHandle, verifySeqHandle;
|
||||
UINT16 sigAlg, sigSz, valTag;
|
||||
FWTPM_DECLARE_BUF(sig, MAX_MLDSA_SIG_SIZE);
|
||||
const char* msg = "Test message for MLDSA sequence";
|
||||
UINT16 msgLen = (UINT16)strlen(msg);
|
||||
|
||||
FWTPM_ALLOC_BUF(sig, MAX_MLDSA_SIG_SIZE);
|
||||
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
rc = fwtpm_test_startup(&ctx);
|
||||
AssertIntEQ(rc, 0);
|
||||
|
||||
/* CreatePrimary Pure MLDSA-65 */
|
||||
rspSize = 0;
|
||||
rc = FWTPM_ProcessCommand(&ctx, gCmd,
|
||||
BuildCreatePrimaryCmd(gCmd, TPM_ALG_MLDSA),
|
||||
gRsp, &rspSize, 0);
|
||||
AssertIntEQ(rc, TPM_RC_SUCCESS);
|
||||
AssertIntEQ(GetRspRC(gRsp), TPM_RC_SUCCESS);
|
||||
handle = GetU32BE(gRsp + TPM2_HEADER_SIZE);
|
||||
|
||||
/* SignSequenceStart: keyHandle | auth(empty) | context(empty).
|
||||
* Note: no mandatory auth on this command per Table 89 Auth Index: None. */
|
||||
pos = 0;
|
||||
PutU16BE(gCmd + pos, TPM_ST_NO_SESSIONS); pos += 2;
|
||||
PutU32BE(gCmd + pos, 0); pos += 4;
|
||||
PutU32BE(gCmd + pos, TPM_CC_SignSequenceStart); pos += 4;
|
||||
PutU32BE(gCmd + pos, handle); pos += 4;
|
||||
PutU16BE(gCmd + pos, 0); pos += 2; /* auth */
|
||||
PutU16BE(gCmd + pos, 0); pos += 2; /* context */
|
||||
PutU32BE(gCmd + 2, (UINT32)pos);
|
||||
rspSize = 0;
|
||||
rc = FWTPM_ProcessCommand(&ctx, gCmd, pos, gRsp, &rspSize, 0);
|
||||
AssertIntEQ(rc, TPM_RC_SUCCESS);
|
||||
AssertIntEQ(GetRspRC(gRsp), TPM_RC_SUCCESS);
|
||||
signSeqHandle = GetU32BE(gRsp + TPM2_HEADER_SIZE);
|
||||
|
||||
/* SignSequenceComplete: @seqHandle(USER) + @keyHandle(USER) + buffer(msg).
|
||||
* Two auth sessions required (both USER). */
|
||||
pos = 0;
|
||||
PutU16BE(gCmd + pos, TPM_ST_SESSIONS); pos += 2;
|
||||
PutU32BE(gCmd + pos, 0); pos += 4;
|
||||
PutU32BE(gCmd + pos, TPM_CC_SignSequenceComplete); pos += 4;
|
||||
PutU32BE(gCmd + pos, signSeqHandle); pos += 4;
|
||||
PutU32BE(gCmd + pos, handle); pos += 4;
|
||||
/* Auth area: 2 PW sessions, both empty. authAreaSize = 9+9 = 18 */
|
||||
PutU32BE(gCmd + pos, 18); pos += 4;
|
||||
PutU32BE(gCmd + pos, TPM_RS_PW); pos += 4;
|
||||
PutU16BE(gCmd + pos, 0); pos += 2; gCmd[pos++] = 0; PutU16BE(gCmd + pos, 0); pos += 2;
|
||||
PutU32BE(gCmd + pos, TPM_RS_PW); pos += 4;
|
||||
PutU16BE(gCmd + pos, 0); pos += 2; gCmd[pos++] = 0; PutU16BE(gCmd + pos, 0); pos += 2;
|
||||
/* Parameters: buffer (TPM2B_MAX_BUFFER) */
|
||||
PutU16BE(gCmd + pos, msgLen); pos += 2;
|
||||
memcpy(gCmd + pos, msg, msgLen); pos += msgLen;
|
||||
PutU32BE(gCmd + 2, (UINT32)pos);
|
||||
|
||||
rspSize = 0;
|
||||
rc = FWTPM_ProcessCommand(&ctx, gCmd, pos, gRsp, &rspSize, 0);
|
||||
AssertIntEQ(rc, TPM_RC_SUCCESS);
|
||||
AssertIntEQ(GetRspRC(gRsp), TPM_RC_SUCCESS);
|
||||
|
||||
/* Response: hdr | paramSize | sigAlg | sigSz | sig */
|
||||
pos = TPM2_HEADER_SIZE + 4;
|
||||
sigAlg = GetU16BE(gRsp + pos); pos += 2;
|
||||
AssertIntEQ(sigAlg, TPM_ALG_MLDSA);
|
||||
sigSz = GetU16BE(gRsp + pos); pos += 2;
|
||||
AssertIntEQ(sigSz, 3309);
|
||||
memcpy(sig, gRsp + pos, sigSz);
|
||||
|
||||
/* VerifySequenceStart: keyHandle | auth(empty) | hint(empty) | context(empty). */
|
||||
pos = 0;
|
||||
PutU16BE(gCmd + pos, TPM_ST_NO_SESSIONS); pos += 2;
|
||||
PutU32BE(gCmd + pos, 0); pos += 4;
|
||||
PutU32BE(gCmd + pos, TPM_CC_VerifySequenceStart); pos += 4;
|
||||
PutU32BE(gCmd + pos, handle); pos += 4;
|
||||
PutU16BE(gCmd + pos, 0); pos += 2; /* auth */
|
||||
PutU16BE(gCmd + pos, 0); pos += 2; /* hint */
|
||||
PutU16BE(gCmd + pos, 0); pos += 2; /* context */
|
||||
PutU32BE(gCmd + 2, (UINT32)pos);
|
||||
rspSize = 0;
|
||||
rc = FWTPM_ProcessCommand(&ctx, gCmd, pos, gRsp, &rspSize, 0);
|
||||
AssertIntEQ(rc, TPM_RC_SUCCESS);
|
||||
AssertIntEQ(GetRspRC(gRsp), TPM_RC_SUCCESS);
|
||||
verifySeqHandle = GetU32BE(gRsp + TPM2_HEADER_SIZE);
|
||||
|
||||
/* SequenceUpdate: feed the message into the verify sequence. */
|
||||
pos = 0;
|
||||
PutU16BE(gCmd + pos, TPM_ST_SESSIONS); pos += 2;
|
||||
PutU32BE(gCmd + pos, 0); pos += 4;
|
||||
PutU32BE(gCmd + pos, TPM_CC_SequenceUpdate); pos += 4;
|
||||
PutU32BE(gCmd + pos, verifySeqHandle); pos += 4;
|
||||
PutU32BE(gCmd + pos, 9); pos += 4;
|
||||
PutU32BE(gCmd + pos, TPM_RS_PW); pos += 4;
|
||||
PutU16BE(gCmd + pos, 0); pos += 2; gCmd[pos++] = 0; PutU16BE(gCmd + pos, 0); pos += 2;
|
||||
PutU16BE(gCmd + pos, msgLen); pos += 2;
|
||||
memcpy(gCmd + pos, msg, msgLen); pos += msgLen;
|
||||
PutU32BE(gCmd + 2, (UINT32)pos);
|
||||
rspSize = 0;
|
||||
rc = FWTPM_ProcessCommand(&ctx, gCmd, pos, gRsp, &rspSize, 0);
|
||||
AssertIntEQ(rc, TPM_RC_SUCCESS);
|
||||
AssertIntEQ(GetRspRC(gRsp), TPM_RC_SUCCESS);
|
||||
|
||||
/* VerifySequenceComplete: @seqHandle(USER) + keyHandle(no auth) + signature. */
|
||||
pos = 0;
|
||||
PutU16BE(gCmd + pos, TPM_ST_SESSIONS); pos += 2;
|
||||
PutU32BE(gCmd + pos, 0); pos += 4;
|
||||
PutU32BE(gCmd + pos, TPM_CC_VerifySequenceComplete); pos += 4;
|
||||
PutU32BE(gCmd + pos, verifySeqHandle); pos += 4;
|
||||
PutU32BE(gCmd + pos, handle); pos += 4;
|
||||
/* Auth: one PW for seqHandle. */
|
||||
PutU32BE(gCmd + pos, 9); pos += 4;
|
||||
PutU32BE(gCmd + pos, TPM_RS_PW); pos += 4;
|
||||
PutU16BE(gCmd + pos, 0); pos += 2; gCmd[pos++] = 0; PutU16BE(gCmd + pos, 0); pos += 2;
|
||||
/* Parameters: signature (TPMT_SIGNATURE) = sigAlg + TPM2B */
|
||||
PutU16BE(gCmd + pos, TPM_ALG_MLDSA); pos += 2;
|
||||
PutU16BE(gCmd + pos, sigSz); pos += 2;
|
||||
memcpy(gCmd + pos, sig, sigSz); pos += sigSz;
|
||||
PutU32BE(gCmd + 2, (UINT32)pos);
|
||||
|
||||
rspSize = 0;
|
||||
rc = FWTPM_ProcessCommand(&ctx, gCmd, pos, gRsp, &rspSize, 0);
|
||||
AssertIntEQ(rc, TPM_RC_SUCCESS);
|
||||
AssertIntEQ(GetRspRC(gRsp), TPM_RC_SUCCESS);
|
||||
|
||||
/* Response: hdr | paramSize | validation.tag ... */
|
||||
pos = TPM2_HEADER_SIZE + 4;
|
||||
valTag = GetU16BE(gRsp + pos);
|
||||
AssertIntEQ(valTag, TPM_ST_MESSAGE_VERIFIED);
|
||||
|
||||
/* Flush key */
|
||||
PutU32BE(gCmd + 10, handle);
|
||||
rspSize = 0;
|
||||
FWTPM_ProcessCommand(&ctx, gCmd,
|
||||
BuildCmdHeader(gCmd, TPM_ST_NO_SESSIONS, 14, TPM_CC_FlushContext),
|
||||
gRsp, &rspSize, 0);
|
||||
|
||||
FWTPM_Cleanup(&ctx);
|
||||
FWTPM_FREE_BUF(sig);
|
||||
printf("Test fwTPM:\tMLDSA Sign/Verify Sequence:\t\tPassed\n");
|
||||
}
|
||||
#endif /* WOLFTPM_V185 */
|
||||
|
||||
/* ================================================================== */
|
||||
/* 9. Hash Sequence */
|
||||
/* ================================================================== */
|
||||
|
|
@ -2502,6 +2959,13 @@ int fwtpm_unit_tests(int argc, char *argv[])
|
|||
#endif
|
||||
#ifdef HAVE_ECC
|
||||
test_fwtpm_create_primary_ecc();
|
||||
#endif
|
||||
#ifdef WOLFTPM_V185
|
||||
test_fwtpm_create_primary_mlkem();
|
||||
test_fwtpm_create_primary_mldsa();
|
||||
test_fwtpm_mlkem_roundtrip();
|
||||
test_fwtpm_mldsa_digest_roundtrip();
|
||||
test_fwtpm_mldsa_sequence_roundtrip();
|
||||
#endif
|
||||
test_fwtpm_read_public();
|
||||
test_fwtpm_evict_control();
|
||||
|
|
|
|||
|
|
@ -177,7 +177,8 @@ TPM_RC FwDecapsulateMlkem(TPMI_MLKEM_PARAMETER_SET parameterSet,
|
|||
/* v1.85 ML-DSA sign/verify helpers. Sign helpers rebuild the keypair
|
||||
* deterministically from the stored 32-byte xi seed (no expanded private
|
||||
* key persisted). Verify helpers import the public-key bytes. */
|
||||
TPM_RC FwSignMldsaMessage(TPMI_MLDSA_PARAMETER_SET parameterSet,
|
||||
TPM_RC FwSignMldsaMessage(WC_RNG* rng,
|
||||
TPMI_MLDSA_PARAMETER_SET parameterSet,
|
||||
const byte* seedXi,
|
||||
const byte* context, int contextSz,
|
||||
const byte* msg, int msgSz,
|
||||
|
|
@ -189,7 +190,8 @@ TPM_RC FwVerifyMldsaMessage(TPMI_MLDSA_PARAMETER_SET parameterSet,
|
|||
const byte* msg, int msgSz,
|
||||
const byte* sig, int sigSz);
|
||||
|
||||
TPM_RC FwSignMldsaHash(TPMI_MLDSA_PARAMETER_SET parameterSet,
|
||||
TPM_RC FwSignMldsaHash(WC_RNG* rng,
|
||||
TPMI_MLDSA_PARAMETER_SET parameterSet,
|
||||
const byte* seedXi,
|
||||
const byte* context, int contextSz,
|
||||
TPMI_ALG_HASH hashAlg,
|
||||
|
|
|
|||
Loading…
Reference in New Issue