diff --git a/configure.ac b/configure.ac index 00533a2a..041c3585 100644 --- a/configure.ac +++ b/configure.ac @@ -462,6 +462,15 @@ then AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_PROVISIONING" fi +AC_ARG_ENABLE([v185], + [AS_HELP_STRING([--enable-v185],[Enable TPM 2.0 v185 Post-Quantum Cryptography (PQC) support (default: disabled)])], + [ ENABLED_V185=$enableval ], + [ ENABLED_V185=no ] + ) +if test "x$ENABLED_V185" = "xyes" +then + AM_CFLAGS="$AM_CFLAGS -DWOLFTPM_V185" +fi # HARDEN FLAGS AX_HARDEN_CC_COMPILER_FLAGS diff --git a/src/tpm2.c b/src/tpm2.c index 84258c31..74eed9a9 100644 --- a/src/tpm2.c +++ b/src/tpm2.c @@ -3233,6 +3233,436 @@ TPM_RC TPM2_Sign(Sign_In* in, Sign_Out* out) return rc; } +#ifdef WOLFTPM_V185 +/* Post-Quantum Cryptography (PQC) Commands - TPM 2.0 v185 */ + +TPM_RC TPM2_SignSequenceStart(SignSequenceStart_In* in, + SignSequenceStart_Out* out) +{ + TPM_RC rc; + TPM2_CTX* ctx = TPM2_GetActiveCtx(); + + if (ctx == NULL || in == NULL || out == NULL || ctx->session == NULL) + return BAD_FUNC_ARG; + + rc = TPM2_AcquireLock(ctx); + if (rc == TPM_RC_SUCCESS) { + TPM2_Packet packet; + CmdInfo_t info = {0,0,0,0}; + info.inHandleCnt = 1; + info.outHandleCnt = 1; + info.flags = (CMD_FLAG_ENC2 | CMD_FLAG_AUTH_USER1); + + TPM2_Packet_Init(ctx, &packet); + + TPM2_Packet_AppendU32(&packet, in->keyHandle); + + TPM2_Packet_AppendAuth(&packet, ctx, &info); + + TPM2_Packet_AppendU16(&packet, in->context.size); + TPM2_Packet_AppendBytes(&packet, in->context.buffer, in->context.size); + + TPM2_Packet_Finalize(&packet, TPM_ST_SESSIONS, TPM_CC_SignSequenceStart); + + /* send command */ + rc = TPM2_SendCommandAuth(ctx, &packet, &info); + if (rc == TPM_RC_SUCCESS) { + UINT32 paramSz = 0; + + TPM2_Packet_ParseU32(&packet, &out->sequenceHandle); + TPM2_Packet_ParseU32(&packet, ¶mSz); + } + + TPM2_ReleaseLock(ctx); + } + return rc; +} + +TPM_RC TPM2_VerifySequenceStart(VerifySequenceStart_In* in, + VerifySequenceStart_Out* out) +{ + TPM_RC rc; + TPM2_CTX* ctx = TPM2_GetActiveCtx(); + TPM_ST st; + + if (ctx == NULL || in == NULL || out == NULL) + return BAD_FUNC_ARG; + + rc = TPM2_AcquireLock(ctx); + if (rc == TPM_RC_SUCCESS) { + TPM2_Packet packet; + CmdInfo_t info = {0,0,0,0}; + info.inHandleCnt = 1; + info.outHandleCnt = 1; + info.flags = (CMD_FLAG_ENC2); + + TPM2_Packet_Init(ctx, &packet); + + TPM2_Packet_AppendU32(&packet, in->keyHandle); + + st = TPM2_Packet_AppendAuth(&packet, ctx, &info); + + TPM2_Packet_AppendU16(&packet, in->context.size); + TPM2_Packet_AppendBytes(&packet, in->context.buffer, in->context.size); + + TPM2_Packet_Finalize(&packet, st, TPM_CC_VerifySequenceStart); + + /* send command */ + rc = TPM2_SendCommandAuth(ctx, &packet, &info); + if (rc == TPM_RC_SUCCESS) { + UINT32 paramSz = 0; + + TPM2_Packet_ParseU32(&packet, &out->sequenceHandle); + if (st == TPM_ST_SESSIONS) { + TPM2_Packet_ParseU32(&packet, ¶mSz); + } + } + + TPM2_ReleaseLock(ctx); + } + return rc; +} + +TPM_RC TPM2_SignSequenceComplete(SignSequenceComplete_In* in, + SignSequenceComplete_Out* out) +{ + TPM_RC rc; + TPM2_CTX* ctx = TPM2_GetActiveCtx(); + + if (ctx == NULL || in == NULL || out == NULL || ctx->session == NULL) + return BAD_FUNC_ARG; + + rc = TPM2_AcquireLock(ctx); + if (rc == TPM_RC_SUCCESS) { + TPM2_Packet packet; + CmdInfo_t info = {0,0,0,0}; + info.inHandleCnt = 2; + info.flags = (CMD_FLAG_ENC2 | CMD_FLAG_AUTH_USER1); + + TPM2_Packet_Init(ctx, &packet); + + TPM2_Packet_AppendU32(&packet, in->sequenceHandle); + TPM2_Packet_AppendU32(&packet, in->keyHandle); + + TPM2_Packet_AppendAuth(&packet, ctx, &info); + + TPM2_Packet_AppendU16(&packet, in->buffer.size); + TPM2_Packet_AppendBytes(&packet, in->buffer.buffer, in->buffer.size); + + TPM2_Packet_Finalize(&packet, TPM_ST_SESSIONS, TPM_CC_SignSequenceComplete); + + /* send command */ + rc = TPM2_SendCommandAuth(ctx, &packet, &info); + if (rc == TPM_RC_SUCCESS) { + UINT32 paramSz = 0; + + TPM2_Packet_ParseU32(&packet, ¶mSz); + TPM2_Packet_ParseSignature(&packet, &out->signature); + } + + TPM2_ReleaseLock(ctx); + } + return rc; +} + +TPM_RC TPM2_VerifySequenceComplete(VerifySequenceComplete_In* in, + VerifySequenceComplete_Out* out) +{ + TPM_RC rc; + TPM2_CTX* ctx = TPM2_GetActiveCtx(); + TPM_ST st; + + if (ctx == NULL || in == NULL || out == NULL) + return BAD_FUNC_ARG; + + rc = TPM2_AcquireLock(ctx); + if (rc == TPM_RC_SUCCESS) { + TPM2_Packet packet; + CmdInfo_t info = {0,0,0,0}; + info.inHandleCnt = 2; + info.flags = (CMD_FLAG_ENC2); + + TPM2_Packet_Init(ctx, &packet); + + TPM2_Packet_AppendU32(&packet, in->sequenceHandle); + TPM2_Packet_AppendU32(&packet, in->keyHandle); + + st = TPM2_Packet_AppendAuth(&packet, ctx, &info); + + TPM2_Packet_AppendU16(&packet, in->buffer.size); + TPM2_Packet_AppendBytes(&packet, in->buffer.buffer, in->buffer.size); + + TPM2_Packet_AppendSignature(&packet, &in->signature); + + TPM2_Packet_Finalize(&packet, st, TPM_CC_VerifySequenceComplete); + + /* send command */ + rc = TPM2_SendCommandAuth(ctx, &packet, &info); + if (rc == TPM_RC_SUCCESS) { + UINT32 paramSz = 0; + + if (st == TPM_ST_SESSIONS) { + TPM2_Packet_ParseU32(&packet, ¶mSz); + } + + TPM2_Packet_ParseU16(&packet, &out->validation.tag); + TPM2_Packet_ParseU32(&packet, &out->validation.hierarchy); + TPM2_Packet_ParseU16(&packet, &out->validation.digest.size); + if (out->validation.digest.size > + sizeof(out->validation.digest.buffer)) { + out->validation.digest.size = + (UINT16)sizeof(out->validation.digest.buffer); + } + TPM2_Packet_ParseBytes(&packet, + out->validation.digest.buffer, + out->validation.digest.size); + } + + TPM2_ReleaseLock(ctx); + } + return rc; +} + +TPM_RC TPM2_SignDigest(SignDigest_In* in, SignDigest_Out* out) +{ + TPM_RC rc; + TPM2_CTX* ctx = TPM2_GetActiveCtx(); + + if (ctx == NULL || in == NULL || out == NULL || ctx->session == NULL) + return BAD_FUNC_ARG; + + rc = TPM2_AcquireLock(ctx); + if (rc == TPM_RC_SUCCESS) { + TPM2_Packet packet; + CmdInfo_t info = {0,0,0,0}; + info.inHandleCnt = 1; + info.flags = (CMD_FLAG_ENC2 | CMD_FLAG_AUTH_USER1); + + TPM2_Packet_Init(ctx, &packet); + + TPM2_Packet_AppendU32(&packet, in->keyHandle); + + TPM2_Packet_AppendAuth(&packet, ctx, &info); + + TPM2_Packet_AppendU16(&packet, in->digest.size); + TPM2_Packet_AppendBytes(&packet, in->digest.buffer, in->digest.size); + + TPM2_Packet_AppendU16(&packet, in->context.size); + TPM2_Packet_AppendBytes(&packet, in->context.buffer, in->context.size); + + TPM2_Packet_Finalize(&packet, TPM_ST_SESSIONS, TPM_CC_SignDigest); + + /* send command */ + rc = TPM2_SendCommandAuth(ctx, &packet, &info); + if (rc == TPM_RC_SUCCESS) { + UINT32 paramSz = 0; + + TPM2_Packet_ParseU32(&packet, ¶mSz); + TPM2_Packet_ParseSignature(&packet, &out->signature); + } + + TPM2_ReleaseLock(ctx); + } + return rc; +} + +TPM_RC TPM2_VerifyDigestSignature(VerifyDigestSignature_In* in, + VerifyDigestSignature_Out* out) +{ + TPM_RC rc; + TPM2_CTX* ctx = TPM2_GetActiveCtx(); + TPM_ST st; + + if (ctx == NULL || in == NULL || out == NULL) + return BAD_FUNC_ARG; + + rc = TPM2_AcquireLock(ctx); + if (rc == TPM_RC_SUCCESS) { + TPM2_Packet packet; + CmdInfo_t info = {0,0,0,0}; + info.inHandleCnt = 1; + info.flags = (CMD_FLAG_ENC2); + + TPM2_Packet_Init(ctx, &packet); + + TPM2_Packet_AppendU32(&packet, in->keyHandle); + + st = TPM2_Packet_AppendAuth(&packet, ctx, &info); + + TPM2_Packet_AppendU16(&packet, in->digest.size); + TPM2_Packet_AppendBytes(&packet, in->digest.buffer, in->digest.size); + + TPM2_Packet_AppendSignature(&packet, &in->signature); + + TPM2_Packet_AppendU16(&packet, in->context.size); + TPM2_Packet_AppendBytes(&packet, in->context.buffer, in->context.size); + + TPM2_Packet_Finalize(&packet, st, TPM_CC_VerifyDigestSignature); + + /* send command */ + rc = TPM2_SendCommandAuth(ctx, &packet, &info); + if (rc == TPM_RC_SUCCESS) { + UINT32 paramSz = 0; + + if (st == TPM_ST_SESSIONS) { + TPM2_Packet_ParseU32(&packet, ¶mSz); + } + + TPM2_Packet_ParseU16(&packet, &out->validation.tag); + TPM2_Packet_ParseU32(&packet, &out->validation.hierarchy); + TPM2_Packet_ParseU16(&packet, &out->validation.digest.size); + if (out->validation.digest.size > + sizeof(out->validation.digest.buffer)) { + out->validation.digest.size = + (UINT16)sizeof(out->validation.digest.buffer); + } + TPM2_Packet_ParseBytes(&packet, + out->validation.digest.buffer, + out->validation.digest.size); + } + + TPM2_ReleaseLock(ctx); + } + return rc; +} + +TPM_RC TPM2_Encapsulate(Encapsulate_In* in, Encapsulate_Out* out) +{ + TPM_RC rc; + TPM2_CTX* ctx = TPM2_GetActiveCtx(); + TPM_ST st; + + if (ctx == NULL || in == NULL || out == NULL) + return BAD_FUNC_ARG; + + rc = TPM2_AcquireLock(ctx); + if (rc == TPM_RC_SUCCESS) { + TPM2_Packet packet; + CmdInfo_t info = {0,0,0,0}; + info.inHandleCnt = 1; + info.flags = (CMD_FLAG_ENC2); + + TPM2_Packet_Init(ctx, &packet); + + TPM2_Packet_AppendU32(&packet, in->keyHandle); + + st = TPM2_Packet_AppendAuth(&packet, ctx, &info); + + TPM2_Packet_Finalize(&packet, st, TPM_CC_Encapsulate); + + /* send command */ + rc = TPM2_SendCommandAuth(ctx, &packet, &info); + if (rc == TPM_RC_SUCCESS) { + UINT32 paramSz = 0; + + if (st == TPM_ST_SESSIONS) { + TPM2_Packet_ParseU32(&packet, ¶mSz); + } + + /* Parse sharedSecret with bounds checking */ + { + UINT16 wireSize; + TPM2_Packet_ParseU16(&packet, &wireSize); + out->sharedSecret.size = wireSize; + if (out->sharedSecret.size > + (UINT16)sizeof(out->sharedSecret.buffer)) { + out->sharedSecret.size = + (UINT16)sizeof(out->sharedSecret.buffer); + } + TPM2_Packet_ParseBytes(&packet, out->sharedSecret.buffer, + out->sharedSecret.size); + /* Skip remaining bytes to keep packet aligned */ + if (wireSize > out->sharedSecret.size) { + TPM2_Packet_ParseBytes(&packet, NULL, + wireSize - out->sharedSecret.size); + } + } + + /* Parse ciphertext with bounds checking */ + { + UINT16 wireSize; + TPM2_Packet_ParseU16(&packet, &wireSize); + out->ciphertext.size = wireSize; + if (out->ciphertext.size > + (UINT16)sizeof(out->ciphertext.buffer)) { + out->ciphertext.size = + (UINT16)sizeof(out->ciphertext.buffer); + } + TPM2_Packet_ParseBytes(&packet, out->ciphertext.buffer, + out->ciphertext.size); + /* Skip remaining bytes to keep packet aligned */ + if (wireSize > out->ciphertext.size) { + TPM2_Packet_ParseBytes(&packet, NULL, + wireSize - out->ciphertext.size); + } + } + } + + TPM2_ReleaseLock(ctx); + } + return rc; +} + +TPM_RC TPM2_Decapsulate(Decapsulate_In* in, Decapsulate_Out* out) +{ + TPM_RC rc; + TPM2_CTX* ctx = TPM2_GetActiveCtx(); + + if (ctx == NULL || in == NULL || out == NULL || ctx->session == NULL) + return BAD_FUNC_ARG; + + rc = TPM2_AcquireLock(ctx); + if (rc == TPM_RC_SUCCESS) { + TPM2_Packet packet; + CmdInfo_t info = {0,0,0,0}; + info.inHandleCnt = 1; + info.flags = (CMD_FLAG_ENC2 | CMD_FLAG_DEC2 | CMD_FLAG_AUTH_USER1); + + TPM2_Packet_Init(ctx, &packet); + + TPM2_Packet_AppendU32(&packet, in->keyHandle); + + TPM2_Packet_AppendAuth(&packet, ctx, &info); + + TPM2_Packet_AppendU16(&packet, in->ciphertext.size); + TPM2_Packet_AppendBytes(&packet, in->ciphertext.buffer, + in->ciphertext.size); + + TPM2_Packet_Finalize(&packet, TPM_ST_SESSIONS, TPM_CC_Decapsulate); + + /* send command */ + rc = TPM2_SendCommandAuth(ctx, &packet, &info); + if (rc == TPM_RC_SUCCESS) { + UINT32 paramSz = 0; + + TPM2_Packet_ParseU32(&packet, ¶mSz); + + /* Parse sharedSecret with bounds checking */ + { + UINT16 wireSize; + TPM2_Packet_ParseU16(&packet, &wireSize); + out->sharedSecret.size = wireSize; + if (out->sharedSecret.size > + (UINT16)sizeof(out->sharedSecret.buffer)) { + out->sharedSecret.size = + (UINT16)sizeof(out->sharedSecret.buffer); + } + TPM2_Packet_ParseBytes(&packet, out->sharedSecret.buffer, + out->sharedSecret.size); + /* Skip remaining bytes to keep packet aligned */ + if (wireSize > out->sharedSecret.size) { + TPM2_Packet_ParseBytes(&packet, NULL, + wireSize - out->sharedSecret.size); + } + } + } + + TPM2_ReleaseLock(ctx); + } + return rc; +} +#endif /* WOLFTPM_V185 */ + TPM_RC TPM2_SetCommandCodeAuditStatus(SetCommandCodeAuditStatus_In* in) { TPM_RC rc; @@ -6261,6 +6691,14 @@ const char* TPM2_GetAlgName(TPM_ALG_ID alg) return "AES-CFB"; case TPM_ALG_ECB: return "AES-ECB"; +#ifdef WOLFTPM_V185 + case TPM_ALG_MLKEM: + return "ML-KEM"; + case TPM_ALG_MLDSA: + return "ML-DSA"; + case TPM_ALG_HASH_MLDSA: + return "HashML-DSA"; +#endif default: break; } diff --git a/src/tpm2_packet.c b/src/tpm2_packet.c index e603c005..793a0b47 100644 --- a/src/tpm2_packet.c +++ b/src/tpm2_packet.c @@ -652,6 +652,17 @@ void TPM2_Packet_AppendSensitive(TPM2_Packet* packet, TPM2B_SENSITIVE* sensitive TPM2_Packet_AppendU16(packet, sens->sym.size); TPM2_Packet_AppendBytes(packet, sens->sym.buffer, sens->sym.size); break; +#ifdef WOLFTPM_V185 + case TPM_ALG_MLDSA: + case TPM_ALG_HASH_MLDSA: + TPM2_Packet_AppendU16(packet, sens->mldsa.size); + TPM2_Packet_AppendBytes(packet, sens->mldsa.buffer, sens->mldsa.size); + break; + case TPM_ALG_MLKEM: + TPM2_Packet_AppendU16(packet, sens->mlkem.size); + TPM2_Packet_AppendBytes(packet, sens->mlkem.buffer, sens->mlkem.size); + break; +#endif /* WOLFTPM_V185 */ } TPM2_Packet_PlaceU16(packet, tmpSz); @@ -697,6 +708,20 @@ void TPM2_Packet_AppendPublicParms(TPM2_Packet* packet, TPMI_ALG_PUBLIC type, TPM2_Packet_AppendU16(packet, parameters->eccDetail.curveID); TPM2_Packet_AppendKdfScheme(packet, ¶meters->eccDetail.kdf); break; +#ifdef WOLFTPM_V185 + case TPM_ALG_MLDSA: + TPM2_Packet_AppendU16(packet, parameters->mldsaDetail.parameterSet); + TPM2_Packet_AppendU8(packet, parameters->mldsaDetail.allowExternalMu); + break; + case TPM_ALG_HASH_MLDSA: + TPM2_Packet_AppendU16(packet, parameters->hash_mldsaDetail.parameterSet); + TPM2_Packet_AppendU16(packet, parameters->hash_mldsaDetail.hashAlg); + break; + case TPM_ALG_MLKEM: + TPM2_Packet_AppendSymmetric(packet, ¶meters->mlkemDetail.symmetric); + TPM2_Packet_AppendU16(packet, parameters->mlkemDetail.parameterSet); + break; +#endif /* WOLFTPM_V185 */ default: TPM2_Packet_AppendSymmetric(packet, ¶meters->asymDetail.symmetric); TPM2_Packet_AppendAsymScheme(packet, ¶meters->asymDetail.scheme); @@ -727,6 +752,20 @@ void TPM2_Packet_ParsePublicParms(TPM2_Packet* packet, TPMI_ALG_PUBLIC type, TPM2_Packet_ParseU16(packet, ¶meters->eccDetail.curveID); TPM2_Packet_ParseKdfScheme(packet, ¶meters->eccDetail.kdf); break; +#ifdef WOLFTPM_V185 + case TPM_ALG_MLDSA: + TPM2_Packet_ParseU16(packet, ¶meters->mldsaDetail.parameterSet); + TPM2_Packet_ParseU8(packet, (BYTE*)¶meters->mldsaDetail.allowExternalMu); + break; + case TPM_ALG_HASH_MLDSA: + TPM2_Packet_ParseU16(packet, ¶meters->hash_mldsaDetail.parameterSet); + TPM2_Packet_ParseU16(packet, (UINT16*)¶meters->hash_mldsaDetail.hashAlg); + break; + case TPM_ALG_MLKEM: + TPM2_Packet_ParseSymmetric(packet, ¶meters->mlkemDetail.symmetric); + TPM2_Packet_ParseU16(packet, ¶meters->mlkemDetail.parameterSet); + break; +#endif /* WOLFTPM_V185 */ default: TPM2_Packet_ParseSymmetric(packet, ¶meters->asymDetail.symmetric); TPM2_Packet_ParseAsymScheme(packet, ¶meters->asymDetail.scheme); @@ -765,6 +804,19 @@ void TPM2_Packet_AppendPublicArea(TPM2_Packet* packet, TPMT_PUBLIC* publicArea) case TPM_ALG_ECC: TPM2_Packet_AppendEccPoint(packet, &publicArea->unique.ecc); break; +#ifdef WOLFTPM_V185 + case TPM_ALG_MLDSA: + case TPM_ALG_HASH_MLDSA: + TPM2_Packet_AppendU16(packet, publicArea->unique.mldsa.size); + TPM2_Packet_AppendBytes(packet, publicArea->unique.mldsa.buffer, + publicArea->unique.mldsa.size); + break; + case TPM_ALG_MLKEM: + TPM2_Packet_AppendU16(packet, publicArea->unique.mlkem.size); + TPM2_Packet_AppendBytes(packet, publicArea->unique.mlkem.buffer, + publicArea->unique.mlkem.size); + break; +#endif /* WOLFTPM_V185 */ default: /* TPMS_DERIVE derive; ? */ break; @@ -811,6 +863,43 @@ void TPM2_Packet_ParsePublic(TPM2_Packet* packet, TPM2B_PUBLIC* pub) case TPM_ALG_ECC: TPM2_Packet_ParseEccPoint(packet, &pub->publicArea.unique.ecc); break; +#ifdef WOLFTPM_V185 + case TPM_ALG_MLDSA: + case TPM_ALG_HASH_MLDSA: + { + UINT16 wireSize; + TPM2_Packet_ParseU16(packet, &wireSize); + pub->publicArea.unique.mldsa.size = wireSize; + if (pub->publicArea.unique.mldsa.size > MAX_MLDSA_PUB_SIZE) { + pub->publicArea.unique.mldsa.size = MAX_MLDSA_PUB_SIZE; + } + TPM2_Packet_ParseBytes(packet, pub->publicArea.unique.mldsa.buffer, + pub->publicArea.unique.mldsa.size); + /* Skip remaining bytes to keep packet position synchronized */ + if (wireSize > pub->publicArea.unique.mldsa.size) { + TPM2_Packet_ParseBytes(packet, NULL, + wireSize - pub->publicArea.unique.mldsa.size); + } + break; + } + case TPM_ALG_MLKEM: + { + UINT16 wireSize; + TPM2_Packet_ParseU16(packet, &wireSize); + pub->publicArea.unique.mlkem.size = wireSize; + if (pub->publicArea.unique.mlkem.size > MAX_MLKEM_PUB_SIZE) { + pub->publicArea.unique.mlkem.size = MAX_MLKEM_PUB_SIZE; + } + TPM2_Packet_ParseBytes(packet, pub->publicArea.unique.mlkem.buffer, + pub->publicArea.unique.mlkem.size); + /* Skip remaining bytes to keep packet position synchronized */ + if (wireSize > pub->publicArea.unique.mlkem.size) { + TPM2_Packet_ParseBytes(packet, NULL, + wireSize - pub->publicArea.unique.mlkem.size); + } + break; + } +#endif /* WOLFTPM_V185 */ default: /* TPMS_DERIVE derive; ? */ break; @@ -850,6 +939,15 @@ void TPM2_Packet_AppendSignature(TPM2_Packet* packet, TPMT_SIGNATURE* sig) digestSz = TPM2_GetHashDigestSize(sig->signature.hmac.hashAlg); TPM2_Packet_AppendBytes(packet, sig->signature.hmac.digest.H, digestSz); break; +#ifdef WOLFTPM_V185 + case TPM_ALG_MLDSA: + case TPM_ALG_HASH_MLDSA: + TPM2_Packet_AppendU16(packet, sig->signature.mldsa.hash); + TPM2_Packet_AppendU16(packet, sig->signature.mldsa.signature.size); + TPM2_Packet_AppendBytes(packet, sig->signature.mldsa.signature.buffer, + sig->signature.mldsa.signature.size); + break; +#endif /* WOLFTPM_V185 */ default: break; } @@ -920,6 +1018,26 @@ void TPM2_Packet_ParseSignature(TPM2_Packet* packet, TPMT_SIGNATURE* sig) digestSz = TPM2_GetHashDigestSize(sig->signature.hmac.hashAlg); TPM2_Packet_ParseBytes(packet, sig->signature.hmac.digest.H, digestSz); break; +#ifdef WOLFTPM_V185 + case TPM_ALG_MLDSA: + case TPM_ALG_HASH_MLDSA: + TPM2_Packet_ParseU16(packet, &sig->signature.mldsa.hash); + TPM2_Packet_ParseU16(packet, &wireSize); + sig->signature.mldsa.signature.size = wireSize; + if (sig->signature.mldsa.signature.size > + sizeof(sig->signature.mldsa.signature.buffer)) { + sig->signature.mldsa.signature.size = + sizeof(sig->signature.mldsa.signature.buffer); + } + TPM2_Packet_ParseBytes(packet, sig->signature.mldsa.signature.buffer, + sig->signature.mldsa.signature.size); + /* Skip remaining bytes to keep packet position synchronized */ + if (wireSize > sig->signature.mldsa.signature.size) { + TPM2_Packet_ParseBytes(packet, NULL, + wireSize - sig->signature.mldsa.signature.size); + } + break; +#endif /* WOLFTPM_V185 */ default: break; } diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 93e19e52..9db575d7 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -4430,6 +4430,633 @@ int wolfTPM2_VerifyHash(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, TPM_ALG_NULL, hashAlg, NULL); } +#ifdef WOLFTPM_V185 +/* Post-Quantum Cryptography (PQC) Wrapper Functions - TPM 2.0 v185 */ + +int wolfTPM2_SignSequenceStart(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, + const byte* context, int contextSz, TPM_HANDLE* sequenceHandle) +{ + int rc; + SignSequenceStart_In signSeqStartIn; + SignSequenceStart_Out signSeqStartOut; + + if (dev == NULL || key == NULL || sequenceHandle == NULL) { + return BAD_FUNC_ARG; + } + + if (contextSz < 0 || contextSz > (int)sizeof(signSeqStartIn.context.buffer)) { + return BUFFER_E; + } + if (contextSz > 0 && context == NULL) { + return BAD_FUNC_ARG; + } + + /* set session auth for key */ + wolfTPM2_SetAuthHandle(dev, 0, &key->handle); + + XMEMSET(&signSeqStartIn, 0, sizeof(signSeqStartIn)); + signSeqStartIn.keyHandle = key->handle.hndl; + signSeqStartIn.context.size = (UINT16)contextSz; + if (context != NULL && contextSz > 0) { + XMEMCPY(signSeqStartIn.context.buffer, context, contextSz); + } + + XMEMSET(&signSeqStartOut, 0, sizeof(signSeqStartOut)); + rc = TPM2_SignSequenceStart(&signSeqStartIn, &signSeqStartOut); + if (rc == TPM_RC_SUCCESS) { + *sequenceHandle = signSeqStartOut.sequenceHandle; + } + + return rc; +} + +int wolfTPM2_SignSequenceUpdate(WOLFTPM2_DEV* dev, + TPM_HANDLE sequenceHandle, const byte* data, int dataSz) +{ + int rc; + SequenceUpdate_In seqUpdateIn; + + if (dev == NULL || data == NULL || dataSz <= 0) { + return BAD_FUNC_ARG; + } + + if (dataSz > (int)sizeof(seqUpdateIn.buffer.buffer)) { + return BUFFER_E; + } + + XMEMSET(&seqUpdateIn, 0, sizeof(seqUpdateIn)); + seqUpdateIn.sequenceHandle = sequenceHandle; + seqUpdateIn.buffer.size = (UINT16)dataSz; + XMEMCPY(seqUpdateIn.buffer.buffer, data, dataSz); + + rc = TPM2_SequenceUpdate(&seqUpdateIn); + + return rc; +} + +int wolfTPM2_SignSequenceComplete(WOLFTPM2_DEV* dev, + TPM_HANDLE sequenceHandle, WOLFTPM2_KEY* key, const byte* data, int dataSz, + byte* sig, int* sigSz) +{ + int rc; + SignSequenceComplete_In signSeqCompleteIn; + SignSequenceComplete_Out signSeqCompleteOut; + + if (dev == NULL || key == NULL || sig == NULL || sigSz == NULL) { + return BAD_FUNC_ARG; + } + + if (dataSz < 0 || dataSz > (int)sizeof(signSeqCompleteIn.buffer.buffer)) { + return BUFFER_E; + } + if (dataSz > 0 && data == NULL) { + return BAD_FUNC_ARG; + } + + /* set session auth for key */ + wolfTPM2_SetAuthHandle(dev, 0, &key->handle); + + XMEMSET(&signSeqCompleteIn, 0, sizeof(signSeqCompleteIn)); + signSeqCompleteIn.sequenceHandle = sequenceHandle; + signSeqCompleteIn.keyHandle = key->handle.hndl; + signSeqCompleteIn.buffer.size = (UINT16)dataSz; + if (data != NULL && dataSz > 0) { + XMEMCPY(signSeqCompleteIn.buffer.buffer, data, dataSz); + } + + XMEMSET(&signSeqCompleteOut, 0, sizeof(signSeqCompleteOut)); + rc = TPM2_SignSequenceComplete(&signSeqCompleteIn, &signSeqCompleteOut); + if (rc == TPM_RC_SUCCESS) { + /* Extract signature based on algorithm */ + if (signSeqCompleteOut.signature.sigAlg == TPM_ALG_ECDSA || + signSeqCompleteOut.signature.sigAlg == TPM_ALG_ECDAA) { + int rSz = signSeqCompleteOut.signature.signature.ecdsa.signatureR.size; + int sSz = signSeqCompleteOut.signature.signature.ecdsa.signatureS.size; + if (*sigSz >= (rSz + sSz)) { + XMEMCPY(sig, signSeqCompleteOut.signature.signature.ecdsa.signatureR.buffer, rSz); + XMEMCPY(sig + rSz, signSeqCompleteOut.signature.signature.ecdsa.signatureS.buffer, sSz); + *sigSz = rSz + sSz; + } + else { + rc = BUFFER_E; + } + } + else if (signSeqCompleteOut.signature.sigAlg == TPM_ALG_RSASSA || + signSeqCompleteOut.signature.sigAlg == TPM_ALG_RSAPSS) { + int sigOutSz = signSeqCompleteOut.signature.signature.rsassa.sig.size; + if (*sigSz >= sigOutSz) { + XMEMCPY(sig, signSeqCompleteOut.signature.signature.rsassa.sig.buffer, sigOutSz); + *sigSz = sigOutSz; + } + else { + rc = BUFFER_E; + } + } +#ifdef WOLFTPM_V185 + else if (signSeqCompleteOut.signature.sigAlg == TPM_ALG_MLDSA || + signSeqCompleteOut.signature.sigAlg == TPM_ALG_HASH_MLDSA) { + /* ML-DSA signature is a variable-length buffer */ + int sigOutSz = signSeqCompleteOut.signature.signature.mldsa.signature.size; + if (*sigSz >= sigOutSz) { + XMEMCPY(sig, signSeqCompleteOut.signature.signature.mldsa.signature.buffer, sigOutSz); + *sigSz = sigOutSz; + } + else { + rc = BUFFER_E; + } + } +#endif /* WOLFTPM_V185 */ + else { + /* Unknown algorithm */ + rc = BUFFER_E; + } + } + + return rc; +} + +int wolfTPM2_VerifySequenceStart(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, + const byte* context, int contextSz, TPM_HANDLE* sequenceHandle) +{ + int rc; + VerifySequenceStart_In verifySeqStartIn; + VerifySequenceStart_Out verifySeqStartOut; + + if (dev == NULL || key == NULL || sequenceHandle == NULL) { + return BAD_FUNC_ARG; + } + + if (contextSz < 0 || contextSz > (int)sizeof(verifySeqStartIn.context.buffer)) { + return BUFFER_E; + } + if (contextSz > 0 && context == NULL) { + return BAD_FUNC_ARG; + } + + XMEMSET(&verifySeqStartIn, 0, sizeof(verifySeqStartIn)); + verifySeqStartIn.keyHandle = key->handle.hndl; + verifySeqStartIn.context.size = (UINT16)contextSz; + if (context != NULL && contextSz > 0) { + XMEMCPY(verifySeqStartIn.context.buffer, context, contextSz); + } + + XMEMSET(&verifySeqStartOut, 0, sizeof(verifySeqStartOut)); + rc = TPM2_VerifySequenceStart(&verifySeqStartIn, &verifySeqStartOut); + if (rc == TPM_RC_SUCCESS) { + *sequenceHandle = verifySeqStartOut.sequenceHandle; + } + + return rc; +} + +int wolfTPM2_VerifySequenceUpdate(WOLFTPM2_DEV* dev, + TPM_HANDLE sequenceHandle, const byte* data, int dataSz) +{ + int rc; + SequenceUpdate_In seqUpdateIn; + + if (dev == NULL || data == NULL || dataSz <= 0) { + return BAD_FUNC_ARG; + } + + if (dataSz > (int)sizeof(seqUpdateIn.buffer.buffer)) { + return BUFFER_E; + } + + XMEMSET(&seqUpdateIn, 0, sizeof(seqUpdateIn)); + seqUpdateIn.sequenceHandle = sequenceHandle; + seqUpdateIn.buffer.size = (UINT16)dataSz; + XMEMCPY(seqUpdateIn.buffer.buffer, data, dataSz); + + rc = TPM2_SequenceUpdate(&seqUpdateIn); + + return rc; +} + +int wolfTPM2_VerifySequenceComplete(WOLFTPM2_DEV* dev, + TPM_HANDLE sequenceHandle, WOLFTPM2_KEY* key, const byte* data, int dataSz, + const byte* sig, int sigSz, TPMT_TK_VERIFIED* validation) +{ + int rc; + VerifySequenceComplete_In verifySeqCompleteIn; + VerifySequenceComplete_Out verifySeqCompleteOut; + TPMT_SIGNATURE signature; + + if (dev == NULL || key == NULL || sig == NULL || sigSz <= 0) { + return BAD_FUNC_ARG; + } + + if (dataSz < 0 || dataSz > (int)sizeof(verifySeqCompleteIn.buffer.buffer)) { + return BUFFER_E; + } + if (dataSz > 0 && data == NULL) { + return BAD_FUNC_ARG; + } + + XMEMSET(&verifySeqCompleteIn, 0, sizeof(verifySeqCompleteIn)); + verifySeqCompleteIn.sequenceHandle = sequenceHandle; + verifySeqCompleteIn.keyHandle = key->handle.hndl; + verifySeqCompleteIn.buffer.size = (UINT16)dataSz; + if (data != NULL && dataSz > 0) { + XMEMCPY(verifySeqCompleteIn.buffer.buffer, data, dataSz); + } + + /* Build signature structure from raw signature */ + /* For PQ algorithms, we need to determine the signature format from the key */ + XMEMSET(&signature, 0, sizeof(signature)); + if (key->pub.publicArea.type == TPM_ALG_ECC) { + /* ECC signature: R then S */ + int curveSize = wolfTPM2_GetCurveSize( + key->pub.publicArea.parameters.eccDetail.curveID); + if (curveSize <= 0 || sigSz != (curveSize * 2)) { + return BAD_FUNC_ARG; + } + signature.sigAlg = key->pub.publicArea.parameters.eccDetail.scheme.scheme; + if (signature.sigAlg == TPM_ALG_NULL) { + signature.sigAlg = TPM_ALG_ECDSA; + } + signature.signature.ecdsa.hash = + key->pub.publicArea.parameters.eccDetail.scheme.details.any.hashAlg; + signature.signature.ecdsa.signatureR.size = curveSize; + XMEMCPY(signature.signature.ecdsa.signatureR.buffer, sig, curveSize); + signature.signature.ecdsa.signatureS.size = curveSize; + XMEMCPY(signature.signature.ecdsa.signatureS.buffer, sig + curveSize, curveSize); + } + else if (key->pub.publicArea.type == TPM_ALG_RSA) { + /* RSA signature */ + signature.sigAlg = key->pub.publicArea.parameters.rsaDetail.scheme.scheme; + if (signature.sigAlg == TPM_ALG_NULL) { + signature.sigAlg = TPM_ALG_RSASSA; + } + signature.signature.rsassa.hash = + key->pub.publicArea.parameters.rsaDetail.scheme.details.anySig.hashAlg; + if (sigSz > (int)sizeof(signature.signature.rsassa.sig.buffer)) { + return BUFFER_E; + } + signature.signature.rsassa.sig.size = (UINT16)sigSz; + XMEMCPY(signature.signature.rsassa.sig.buffer, sig, sigSz); + } +#ifdef WOLFTPM_V185 + else if (key->pub.publicArea.type == TPM_ALG_MLDSA || + key->pub.publicArea.type == TPM_ALG_HASH_MLDSA) { + /* ML-DSA signature - key type directly indicates algorithm */ + signature.sigAlg = key->pub.publicArea.type; + signature.signature.mldsa.hash = TPM_ALG_SHA3_256; + if (sigSz > (int)sizeof(signature.signature.mldsa.signature.buffer)) { + return BUFFER_E; + } + signature.signature.mldsa.signature.size = (UINT16)sigSz; + XMEMCPY(signature.signature.mldsa.signature.buffer, sig, sigSz); + } +#endif /* WOLFTPM_V185 */ + else { + /* Unknown key type */ + return BAD_FUNC_ARG; + } + verifySeqCompleteIn.signature = signature; + + XMEMSET(&verifySeqCompleteOut, 0, sizeof(verifySeqCompleteOut)); + rc = TPM2_VerifySequenceComplete(&verifySeqCompleteIn, &verifySeqCompleteOut); + if (rc == TPM_RC_SUCCESS && validation != NULL) { + XMEMCPY(validation, &verifySeqCompleteOut.validation, sizeof(TPMT_TK_VERIFIED)); + } + + return rc; +} + +int wolfTPM2_SignDigest(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, + const byte* digest, int digestSz, const byte* context, int contextSz, + byte* sig, int* sigSz) +{ + int rc; + SignDigest_In signDigestIn; + SignDigest_Out signDigestOut; + + if (dev == NULL || key == NULL || digest == NULL || sig == NULL || sigSz == NULL) { + return BAD_FUNC_ARG; + } + + if (digestSz <= 0 || digestSz > (int)sizeof(signDigestIn.digest.buffer)) { + return BUFFER_E; + } + + if (contextSz < 0 || contextSz > (int)sizeof(signDigestIn.context.buffer)) { + return BUFFER_E; + } + if (contextSz > 0 && context == NULL) { + return BAD_FUNC_ARG; + } + + /* set session auth for key */ + wolfTPM2_SetAuthHandle(dev, 0, &key->handle); + + XMEMSET(&signDigestIn, 0, sizeof(signDigestIn)); + signDigestIn.keyHandle = key->handle.hndl; + signDigestIn.digest.size = (UINT16)digestSz; + XMEMCPY(signDigestIn.digest.buffer, digest, digestSz); + signDigestIn.context.size = (UINT16)contextSz; + if (context != NULL && contextSz > 0) { + XMEMCPY(signDigestIn.context.buffer, context, contextSz); + } + + XMEMSET(&signDigestOut, 0, sizeof(signDigestOut)); + rc = TPM2_SignDigest(&signDigestIn, &signDigestOut); + if (rc == TPM_RC_SUCCESS) { + /* Extract signature based on algorithm */ + if (signDigestOut.signature.sigAlg == TPM_ALG_ECDSA || + signDigestOut.signature.sigAlg == TPM_ALG_ECDAA) { + int rSz = signDigestOut.signature.signature.ecdsa.signatureR.size; + int sSz = signDigestOut.signature.signature.ecdsa.signatureS.size; + if (*sigSz >= (rSz + sSz)) { + XMEMCPY(sig, signDigestOut.signature.signature.ecdsa.signatureR.buffer, rSz); + XMEMCPY(sig + rSz, signDigestOut.signature.signature.ecdsa.signatureS.buffer, sSz); + *sigSz = rSz + sSz; + } + else { + rc = BUFFER_E; + } + } + else if (signDigestOut.signature.sigAlg == TPM_ALG_RSASSA || + signDigestOut.signature.sigAlg == TPM_ALG_RSAPSS) { + int sigOutSz = signDigestOut.signature.signature.rsassa.sig.size; + if (*sigSz >= sigOutSz) { + XMEMCPY(sig, signDigestOut.signature.signature.rsassa.sig.buffer, sigOutSz); + *sigSz = sigOutSz; + } + else { + rc = BUFFER_E; + } + } +#ifdef WOLFTPM_V185 + else if (signDigestOut.signature.sigAlg == TPM_ALG_MLDSA || + signDigestOut.signature.sigAlg == TPM_ALG_HASH_MLDSA) { + /* ML-DSA signature is a variable-length buffer */ + int sigOutSz = signDigestOut.signature.signature.mldsa.signature.size; + if (*sigSz >= sigOutSz) { + XMEMCPY(sig, signDigestOut.signature.signature.mldsa.signature.buffer, sigOutSz); + *sigSz = sigOutSz; + } + else { + rc = BUFFER_E; + } + } +#endif /* WOLFTPM_V185 */ + else { + /* Unknown algorithm */ + rc = BUFFER_E; + } + } + + return rc; +} + +int wolfTPM2_VerifyDigestSignature(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, + const byte* digest, int digestSz, const byte* sig, int sigSz, + const byte* context, int contextSz, TPMT_TK_VERIFIED* validation) +{ + int rc; + VerifyDigestSignature_In verifyDigestSigIn; + VerifyDigestSignature_Out verifyDigestSigOut; + TPMT_SIGNATURE signature; + + if (dev == NULL || key == NULL || digest == NULL || sig == NULL || sigSz <= 0) { + return BAD_FUNC_ARG; + } + + if (digestSz <= 0 || digestSz > (int)sizeof(verifyDigestSigIn.digest.buffer)) { + return BUFFER_E; + } + + if (contextSz < 0 || contextSz > (int)sizeof(verifyDigestSigIn.context.buffer)) { + return BUFFER_E; + } + if (contextSz > 0 && context == NULL) { + return BAD_FUNC_ARG; + } + + XMEMSET(&verifyDigestSigIn, 0, sizeof(verifyDigestSigIn)); + verifyDigestSigIn.keyHandle = key->handle.hndl; + verifyDigestSigIn.digest.size = (UINT16)digestSz; + XMEMCPY(verifyDigestSigIn.digest.buffer, digest, digestSz); + + /* Build signature structure from raw signature */ + /* For PQ algorithms, we need to determine the signature format from the key */ + XMEMSET(&signature, 0, sizeof(signature)); + if (key->pub.publicArea.type == TPM_ALG_ECC) { + /* ECC signature: R then S */ + int curveSize = wolfTPM2_GetCurveSize( + key->pub.publicArea.parameters.eccDetail.curveID); + if (curveSize <= 0 || sigSz != (curveSize * 2)) { + return BAD_FUNC_ARG; + } + signature.sigAlg = key->pub.publicArea.parameters.eccDetail.scheme.scheme; + if (signature.sigAlg == TPM_ALG_NULL) { + signature.sigAlg = TPM_ALG_ECDSA; + } + signature.signature.ecdsa.hash = + key->pub.publicArea.parameters.eccDetail.scheme.details.any.hashAlg; + signature.signature.ecdsa.signatureR.size = curveSize; + XMEMCPY(signature.signature.ecdsa.signatureR.buffer, sig, curveSize); + signature.signature.ecdsa.signatureS.size = curveSize; + XMEMCPY(signature.signature.ecdsa.signatureS.buffer, sig + curveSize, curveSize); + } + else if (key->pub.publicArea.type == TPM_ALG_RSA) { + /* RSA signature */ + signature.sigAlg = key->pub.publicArea.parameters.rsaDetail.scheme.scheme; + if (signature.sigAlg == TPM_ALG_NULL) { + signature.sigAlg = TPM_ALG_RSASSA; + } + signature.signature.rsassa.hash = + key->pub.publicArea.parameters.rsaDetail.scheme.details.anySig.hashAlg; + if (sigSz > (int)sizeof(signature.signature.rsassa.sig.buffer)) { + return BUFFER_E; + } + signature.signature.rsassa.sig.size = (UINT16)sigSz; + XMEMCPY(signature.signature.rsassa.sig.buffer, sig, sigSz); + } +#ifdef WOLFTPM_V185 + else if (key->pub.publicArea.type == TPM_ALG_MLDSA || + key->pub.publicArea.type == TPM_ALG_HASH_MLDSA) { + /* ML-DSA signature - key type directly indicates algorithm */ + signature.sigAlg = key->pub.publicArea.type; + signature.signature.mldsa.hash = TPM_ALG_SHA3_256; + if (sigSz > (int)sizeof(signature.signature.mldsa.signature.buffer)) { + return BUFFER_E; + } + signature.signature.mldsa.signature.size = (UINT16)sigSz; + XMEMCPY(signature.signature.mldsa.signature.buffer, sig, sigSz); + } +#endif /* WOLFTPM_V185 */ + else { + /* Unknown key type */ + return BAD_FUNC_ARG; + } + verifyDigestSigIn.signature = signature; + + verifyDigestSigIn.context.size = (UINT16)contextSz; + if (context != NULL && contextSz > 0) { + XMEMCPY(verifyDigestSigIn.context.buffer, context, contextSz); + } + + XMEMSET(&verifyDigestSigOut, 0, sizeof(verifyDigestSigOut)); + rc = TPM2_VerifyDigestSignature(&verifyDigestSigIn, &verifyDigestSigOut); + if (rc == TPM_RC_SUCCESS && validation != NULL) { + XMEMCPY(validation, &verifyDigestSigOut.validation, sizeof(TPMT_TK_VERIFIED)); + } + + return rc; +} + +int wolfTPM2_Encapsulate(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, + byte* ciphertext, int* ciphertextSz, byte* sharedSecret, int* sharedSecretSz) +{ + int rc; + Encapsulate_In encapsulateIn; + Encapsulate_Out encapsulateOut; + + if (dev == NULL || key == NULL || ciphertext == NULL || ciphertextSz == NULL || + sharedSecret == NULL || sharedSecretSz == NULL) { + return BAD_FUNC_ARG; + } + + XMEMSET(&encapsulateIn, 0, sizeof(encapsulateIn)); + encapsulateIn.keyHandle = key->handle.hndl; + + XMEMSET(&encapsulateOut, 0, sizeof(encapsulateOut)); + rc = TPM2_Encapsulate(&encapsulateIn, &encapsulateOut); + if (rc == TPM_RC_SUCCESS) { + if (*ciphertextSz >= (int)encapsulateOut.ciphertext.size) { + XMEMCPY(ciphertext, encapsulateOut.ciphertext.buffer, encapsulateOut.ciphertext.size); + *ciphertextSz = encapsulateOut.ciphertext.size; + } + else { + rc = BUFFER_E; + } + + if (rc == TPM_RC_SUCCESS) { + if (*sharedSecretSz >= (int)encapsulateOut.sharedSecret.size) { + XMEMCPY(sharedSecret, encapsulateOut.sharedSecret.buffer, encapsulateOut.sharedSecret.size); + *sharedSecretSz = encapsulateOut.sharedSecret.size; + } + else { + rc = BUFFER_E; + } + } + } + + /* Clear sensitive shared secret from stack */ + TPM2_ForceZero(&encapsulateOut.sharedSecret, sizeof(encapsulateOut.sharedSecret)); + + return rc; +} + +int wolfTPM2_Decapsulate(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, + const byte* ciphertext, int ciphertextSz, byte* sharedSecret, int* sharedSecretSz) +{ + int rc; + Decapsulate_In decapsulateIn; + Decapsulate_Out decapsulateOut; + + if (dev == NULL || key == NULL || ciphertext == NULL || ciphertextSz <= 0 || + sharedSecret == NULL || sharedSecretSz == NULL) { + return BAD_FUNC_ARG; + } + + if (ciphertextSz > (int)sizeof(decapsulateIn.ciphertext.buffer)) { + return BUFFER_E; + } + + /* set session auth for key */ + wolfTPM2_SetAuthHandle(dev, 0, &key->handle); + + XMEMSET(&decapsulateIn, 0, sizeof(decapsulateIn)); + decapsulateIn.keyHandle = key->handle.hndl; + decapsulateIn.ciphertext.size = (UINT16)ciphertextSz; + XMEMCPY(decapsulateIn.ciphertext.buffer, ciphertext, ciphertextSz); + + XMEMSET(&decapsulateOut, 0, sizeof(decapsulateOut)); + rc = TPM2_Decapsulate(&decapsulateIn, &decapsulateOut); + if (rc == TPM_RC_SUCCESS) { + if (*sharedSecretSz >= (int)decapsulateOut.sharedSecret.size) { + XMEMCPY(sharedSecret, decapsulateOut.sharedSecret.buffer, decapsulateOut.sharedSecret.size); + *sharedSecretSz = decapsulateOut.sharedSecret.size; + } + else { + rc = BUFFER_E; + } + } + + /* Clear sensitive shared secret from stack */ + TPM2_ForceZero(&decapsulateOut.sharedSecret, sizeof(decapsulateOut.sharedSecret)); + + return rc; +} + +/* GetKeyTemplate_MLDSA - Create a key template for ML-DSA signing keys */ +int wolfTPM2_GetKeyTemplate_MLDSA(TPMT_PUBLIC* publicTemplate, + TPMA_OBJECT objectAttributes, TPMI_MLDSA_PARAMETER_SET parameterSet, + int allowExternalMu) +{ + if (publicTemplate == NULL) + return BAD_FUNC_ARG; + + /* TCG v185: MLDSA is sign-only. Enforce correct attributes. */ + objectAttributes &= ~TPMA_OBJECT_decrypt; + objectAttributes |= TPMA_OBJECT_sign; + + XMEMSET(publicTemplate, 0, sizeof(TPMT_PUBLIC)); + publicTemplate->type = TPM_ALG_MLDSA; + publicTemplate->nameAlg = TPM_ALG_SHA256; + publicTemplate->objectAttributes = objectAttributes; + publicTemplate->parameters.mldsaDetail.parameterSet = parameterSet; + publicTemplate->parameters.mldsaDetail.allowExternalMu = + (allowExternalMu ? YES : NO); + return TPM_RC_SUCCESS; +} + +/* GetKeyTemplate_HASH_MLDSA - Create a key template for Pre-Hash ML-DSA signing keys */ +int wolfTPM2_GetKeyTemplate_HASH_MLDSA(TPMT_PUBLIC* publicTemplate, + TPMA_OBJECT objectAttributes, TPMI_MLDSA_PARAMETER_SET parameterSet, + TPMI_ALG_HASH hashAlg) +{ + if (publicTemplate == NULL) + return BAD_FUNC_ARG; + + /* TCG v185: HASH_MLDSA is sign-only. Enforce correct attributes. */ + objectAttributes &= ~TPMA_OBJECT_decrypt; + objectAttributes |= TPMA_OBJECT_sign; + + XMEMSET(publicTemplate, 0, sizeof(TPMT_PUBLIC)); + publicTemplate->type = TPM_ALG_HASH_MLDSA; + publicTemplate->nameAlg = TPM_ALG_SHA256; + publicTemplate->objectAttributes = objectAttributes; + publicTemplate->parameters.hash_mldsaDetail.parameterSet = parameterSet; + publicTemplate->parameters.hash_mldsaDetail.hashAlg = hashAlg; + return TPM_RC_SUCCESS; +} + +/* GetKeyTemplate_MLKEM - Create a key template for ML-KEM decryption keys */ +int wolfTPM2_GetKeyTemplate_MLKEM(TPMT_PUBLIC* publicTemplate, + TPMA_OBJECT objectAttributes, TPMI_MLKEM_PARAMETER_SET parameterSet) +{ + if (publicTemplate == NULL) + return BAD_FUNC_ARG; + + /* TCG v185: MLKEM is decrypt-only. Enforce correct attributes. */ + objectAttributes &= ~TPMA_OBJECT_sign; + objectAttributes |= TPMA_OBJECT_decrypt; + + XMEMSET(publicTemplate, 0, sizeof(TPMT_PUBLIC)); + publicTemplate->type = TPM_ALG_MLKEM; + publicTemplate->nameAlg = TPM_ALG_SHA256; + publicTemplate->objectAttributes = objectAttributes; + publicTemplate->parameters.mlkemDetail.parameterSet = parameterSet; + /* symmetric field: TPM_ALG_NULL for unrestricted key */ + publicTemplate->parameters.mlkemDetail.symmetric.algorithm = TPM_ALG_NULL; + return TPM_RC_SUCCESS; +} +#endif /* WOLFTPM_V185 */ + /* Generate ECC key-pair with NULL hierarchy and load (populates handle) */ int wolfTPM2_ECDHGenKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* ecdhKey, int curve_id, const byte* auth, int authSz) diff --git a/tests/unit_tests.c b/tests/unit_tests.c index 07a86d12..df19bc3c 100644 --- a/tests/unit_tests.c +++ b/tests/unit_tests.c @@ -1057,6 +1057,402 @@ static void test_wolfTPM2_KeyBlob(TPM_ALG_ID alg) TPM2_GetAlgName(alg), rc == 0 ? "Passed" : "Failed"); } +#ifdef WOLFTPM_V185 +/* Post-Quantum Cryptography (PQC) Unit Tests - TPM 2.0 v185 */ + +/* TODO: Remove TPM_RC_COMMAND_CODE skip logic once we have a TPM simulator + * or hardware that supports TPM 2.0 v1.85 PQC commands. Currently the IBM SW + * TPM does not support ML-DSA/ML-KEM, so tests skip with TPM_RC_COMMAND_CODE. + * When real support is available, update tests to require success. */ + +/* Test ML-DSA Sign Sequence (Start, Update, Complete) */ +static void test_wolfTPM2_MLDSA_SignSequence(WOLFTPM2_DEV* dev, + WOLFTPM2_KEY* mldsaKey) +{ + int rc; + TPM_HANDLE sequenceHandle; + byte message[] = "Test message for ML-DSA signing"; + int messageSz = (int)sizeof(message) - 1; + byte sig[5000]; /* ML-DSA signatures are large */ + int sigSz = (int)sizeof(sig); + byte context[16] = {0}; /* Optional context */ + int contextSz = 0; + + /* Note: This test requires a TPM that supports ML-DSA */ + /* The key should already be created and loaded */ + + /* Test SignSequenceStart */ + rc = wolfTPM2_SignSequenceStart(dev, mldsaKey, context, contextSz, + &sequenceHandle); + if (rc == TPM_RC_VALUE || rc == TPM_RC_SCHEME || + rc == TPM_RC_COMMAND_CODE || rc == (int)(RC_VER1 + 0x043)) { + printf("Test TPM Wrapper:\tML-DSA Sign Sequence:\tSkipped (not supported)\n"); + return; + } + /* If we get here, TPM supports it, continue testing */ + AssertIntEQ(rc, 0); + + /* Test SignSequenceUpdate */ + rc = wolfTPM2_SignSequenceUpdate(dev, sequenceHandle, message, messageSz); + AssertIntEQ(rc, 0); + + /* Test SignSequenceComplete */ + rc = wolfTPM2_SignSequenceComplete(dev, sequenceHandle, mldsaKey, NULL, 0, + sig, &sigSz); + AssertIntEQ(rc, 0); + AssertIntGT(sigSz, 0); + + printf("Test TPM Wrapper:\tML-DSA Sign Sequence:\t%s\n", + rc == 0 ? "Passed" : "Failed"); +} + +/* Test ML-DSA Verify Sequence (Start, Update, Complete) */ +static void test_wolfTPM2_MLDSA_VerifySequence(WOLFTPM2_DEV* dev, + WOLFTPM2_KEY* mldsaKey, const byte* message, int messageSz, + const byte* sig, int sigSz) +{ + int rc; + TPM_HANDLE sequenceHandle; + + /* Test VerifySequenceStart */ + rc = wolfTPM2_VerifySequenceStart(dev, mldsaKey, NULL, 0, &sequenceHandle); + if (rc == TPM_RC_VALUE || rc == TPM_RC_SCHEME || + rc == TPM_RC_COMMAND_CODE || rc == (int)(RC_VER1 + 0x043)) { + printf("Test TPM Wrapper:\tML-DSA Verify Sequence:\tSkipped (not supported)\n"); + return; + } + AssertIntEQ(rc, 0); + + /* Test VerifySequenceUpdate */ + rc = wolfTPM2_VerifySequenceUpdate(dev, sequenceHandle, message, messageSz); + AssertIntEQ(rc, 0); + + /* Test VerifySequenceComplete */ + rc = wolfTPM2_VerifySequenceComplete(dev, sequenceHandle, mldsaKey, + NULL, 0, sig, sigSz, NULL); + AssertIntEQ(rc, 0); + + printf("Test TPM Wrapper:\tML-DSA Verify Sequence:\t%s\n", + rc == 0 ? "Passed" : "Failed"); +} + +/* Test ML-DSA Sign Digest */ +static void test_wolfTPM2_MLDSA_SignDigest(WOLFTPM2_DEV* dev, + WOLFTPM2_KEY* mldsaKey) +{ + int rc; + byte digest[32]; /* SHA3-256 digest */ + int digestSz = 32; + byte context[16]; + int contextSz = 16; + byte sig[5000]; + int sigSz = (int)sizeof(sig); + + /* Create test digest */ + XMEMSET(digest, 0xAA, digestSz); + XMEMSET(context, 0xBB, contextSz); + + /* Test SignDigest */ + rc = wolfTPM2_SignDigest(dev, mldsaKey, digest, digestSz, + context, contextSz, sig, &sigSz); + if (rc == TPM_RC_VALUE || rc == TPM_RC_SCHEME || + rc == TPM_RC_COMMAND_CODE || rc == (int)(RC_VER1 + 0x043)) { + printf("Test TPM Wrapper:\tML-DSA Sign Digest:\tSkipped (not supported)\n"); + return; + } + AssertIntEQ(rc, 0); + AssertIntGT(sigSz, 0); + + printf("Test TPM Wrapper:\tML-DSA Sign Digest:\t%s\n", + rc == 0 ? "Passed" : "Failed"); +} + +/* Test ML-DSA Verify Digest Signature */ +static void test_wolfTPM2_MLDSA_VerifyDigestSignature(WOLFTPM2_DEV* dev, + WOLFTPM2_KEY* mldsaKey, const byte* digest, int digestSz, + const byte* sig, int sigSz) +{ + int rc; + byte context[16]; + int contextSz = 16; + TPMT_TK_VERIFIED validation; + + XMEMSET(context, 0xBB, contextSz); + + /* Test VerifyDigestSignature */ + rc = wolfTPM2_VerifyDigestSignature(dev, mldsaKey, digest, digestSz, + sig, sigSz, context, contextSz, &validation); + if (rc == TPM_RC_VALUE || rc == TPM_RC_SCHEME || + rc == TPM_RC_COMMAND_CODE || rc == (int)(RC_VER1 + 0x043)) { + printf("Test TPM Wrapper:\tML-DSA Verify Digest:\tSkipped (not supported)\n"); + return; + } + AssertIntEQ(rc, 0); + + printf("Test TPM Wrapper:\tML-DSA Verify Digest:\t%s\n", + rc == 0 ? "Passed" : "Failed"); +} + +#if !defined(WOLFTPM2_NO_WOLFCRYPT) && \ + (defined(WOLFSSL_HAVE_MLKEM) || defined(WOLFSSL_KYBER512) || \ + defined(WOLFSSL_KYBER768) || defined(WOLFSSL_KYBER1024)) +/* Test ML-KEM Encapsulate */ +static void test_wolfTPM2_MLKEM_Encapsulate(WOLFTPM2_DEV* dev, + WOLFTPM2_KEY* mlkemKey) +{ + int rc; + byte ciphertext[2048]; /* ML-KEM ciphertext is variable length */ + int ciphertextSz = (int)sizeof(ciphertext); + byte sharedSecret[64]; /* Shared secret */ + int sharedSecretSz = (int)sizeof(sharedSecret); + + XMEMSET(ciphertext, 0, sizeof(ciphertext)); + XMEMSET(sharedSecret, 0, sizeof(sharedSecret)); + + /* Test Encapsulate */ + rc = wolfTPM2_Encapsulate(dev, mlkemKey, ciphertext, &ciphertextSz, + sharedSecret, &sharedSecretSz); + if (rc == TPM_RC_VALUE || rc == TPM_RC_SCHEME || + rc == TPM_RC_COMMAND_CODE || rc == (int)(RC_VER1 + 0x043)) { + printf("Test TPM Wrapper:\tML-KEM Encapsulate:\tSkipped (not supported)\n"); + return; + } + AssertIntEQ(rc, 0); + AssertIntGT(ciphertextSz, 0); + AssertIntGT(sharedSecretSz, 0); + + printf("Test TPM Wrapper:\tML-KEM Encapsulate:\t%s\n", + rc == 0 ? "Passed" : "Failed"); +} + +/* Test ML-KEM Decapsulate */ +static void test_wolfTPM2_MLKEM_Decapsulate(WOLFTPM2_DEV* dev, + WOLFTPM2_KEY* mlkemKey, const byte* ciphertext, int ciphertextSz) +{ + int rc; + byte sharedSecret[64]; /* Shared secret */ + int sharedSecretSz = (int)sizeof(sharedSecret); + + XMEMSET(sharedSecret, 0, sizeof(sharedSecret)); + + /* Test Decapsulate */ + rc = wolfTPM2_Decapsulate(dev, mlkemKey, ciphertext, ciphertextSz, + sharedSecret, &sharedSecretSz); + if (rc == TPM_RC_VALUE || rc == TPM_RC_SCHEME || + rc == TPM_RC_COMMAND_CODE || rc == (int)(RC_VER1 + 0x043)) { + printf("Test TPM Wrapper:\tML-KEM Decapsulate:\tSkipped (not supported)\n"); + return; + } + AssertIntEQ(rc, 0); + AssertIntGT(sharedSecretSz, 0); + + printf("Test TPM Wrapper:\tML-KEM Decapsulate:\t%s\n", + rc == 0 ? "Passed" : "Failed"); +} + +/* Test ML-KEM Encapsulate/Decapsulate round-trip */ +static void test_wolfTPM2_MLKEM_RoundTrip(WOLFTPM2_DEV* dev, + WOLFTPM2_KEY* mlkemKey) +{ + int rc; + byte ciphertext[2048]; + int ciphertextSz = (int)sizeof(ciphertext); + byte sharedSecret1[64], sharedSecret2[64]; + int sharedSecret1Sz = (int)sizeof(sharedSecret1); + int sharedSecret2Sz = (int)sizeof(sharedSecret2); + + XMEMSET(ciphertext, 0, sizeof(ciphertext)); + XMEMSET(sharedSecret1, 0, sizeof(sharedSecret1)); + XMEMSET(sharedSecret2, 0, sizeof(sharedSecret2)); + + /* Encapsulate */ + rc = wolfTPM2_Encapsulate(dev, mlkemKey, ciphertext, &ciphertextSz, + sharedSecret1, &sharedSecret1Sz); + if (rc == TPM_RC_VALUE || rc == TPM_RC_SCHEME || + rc == TPM_RC_COMMAND_CODE || rc == (int)(RC_VER1 + 0x043)) { + printf("Test TPM Wrapper:\tML-KEM Round Trip:\tSkipped (not supported)\n"); + return; + } + AssertIntEQ(rc, 0); + AssertIntGT(ciphertextSz, 0); + AssertIntGT(sharedSecret1Sz, 0); + + /* Decapsulate */ + rc = wolfTPM2_Decapsulate(dev, mlkemKey, ciphertext, ciphertextSz, + sharedSecret2, &sharedSecret2Sz); + AssertIntEQ(rc, 0); + AssertIntGT(sharedSecret2Sz, 0); + + /* Verify shared secrets match */ + AssertIntEQ(sharedSecret1Sz, sharedSecret2Sz); + AssertIntEQ(XMEMCMP(sharedSecret1, sharedSecret2, sharedSecret1Sz), 0); + + printf("Test TPM Wrapper:\tML-KEM Round Trip:\t%s\n", + rc == 0 ? "Passed" : "Failed"); +} +#endif /* ML-KEM support */ + +/* Main PQC test function */ +static void test_wolfTPM2_PQC(void) +{ + int rc; + WOLFTPM2_DEV dev; + WOLFTPM2_KEY storageKey; + WOLFTPM2_KEY mldsaKey; + byte sig[5000]; + int sigSz = (int)sizeof(sig); + byte digest[32]; + int digestSz = 32; +#if !defined(WOLFTPM2_NO_WOLFCRYPT) && \ + (defined(WOLFSSL_HAVE_MLKEM) || defined(WOLFSSL_KYBER512) || \ + defined(WOLFSSL_KYBER768) || defined(WOLFSSL_KYBER1024)) + WOLFTPM2_KEY mlkemKey; +#endif + + /* Initialize TPM */ + rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL); + AssertIntEQ(rc, 0); + + /* Create storage key */ + rc = wolfTPM2_CreateSRK(&dev, &storageKey, TPM_ALG_ECC, + (byte*)gStorageKeyAuth, sizeof(gStorageKeyAuth)-1); + AssertIntEQ(rc, 0); + + /* Note: ML-DSA key creation would need proper TPM 2.0 v185 support */ + /* For now, tests will gracefully skip if not supported */ + printf("Testing ML-DSA functions (will skip if not supported by TPM)...\n"); + + /* Initialize mldsaKey - in real usage, this would be created/loaded */ + XMEMSET(&mldsaKey, 0, sizeof(mldsaKey)); + + /* Test Sign Sequence */ + test_wolfTPM2_MLDSA_SignSequence(&dev, &mldsaKey); + + /* Test Sign Digest */ + test_wolfTPM2_MLDSA_SignDigest(&dev, &mldsaKey); + + /* Test Verify Sequence - will skip if not supported */ + /* Note: In a real test, we'd need actual message and signature */ + { + byte testMessage[] = "Test message"; + byte testSig[5000] = {0}; + test_wolfTPM2_MLDSA_VerifySequence(&dev, &mldsaKey, + testMessage, (int)sizeof(testMessage) - 1, + testSig, (int)sizeof(testSig)); + } + + /* If we have a signature, test verification */ + if (sigSz > 0 && sigSz < (int)sizeof(sig)) { + XMEMSET(digest, 0xAA, digestSz); + test_wolfTPM2_MLDSA_VerifyDigestSignature(&dev, &mldsaKey, + digest, digestSz, sig, sigSz); + } + +#if !defined(WOLFTPM2_NO_WOLFCRYPT) && \ + (defined(WOLFSSL_HAVE_MLKEM) || defined(WOLFSSL_KYBER512) || \ + defined(WOLFSSL_KYBER768) || defined(WOLFSSL_KYBER1024)) + /* Note: ML-KEM key creation would need proper TPM 2.0 v185 support */ + printf("Testing ML-KEM functions (will skip if not supported by TPM)...\n"); + + /* Initialize mlkemKey - in real usage, this would be created/loaded */ + XMEMSET(&mlkemKey, 0, sizeof(mlkemKey)); + + /* Test Encapsulate */ + test_wolfTPM2_MLKEM_Encapsulate(&dev, &mlkemKey); + + /* Test Decapsulate - will skip if not supported */ + /* Note: In a real test, we'd need actual ciphertext from Encapsulate */ + { + byte testCiphertext[2048] = {0}; + test_wolfTPM2_MLKEM_Decapsulate(&dev, &mlkemKey, + testCiphertext, (int)sizeof(testCiphertext)); + } + + /* Test Encapsulate/Decapsulate round-trip */ + test_wolfTPM2_MLKEM_RoundTrip(&dev, &mlkemKey); +#endif + + wolfTPM2_UnloadHandle(&dev, &storageKey.handle); + wolfTPM2_Cleanup(&dev); +} + +/* Test PQC key template creation */ +static void test_wolfTPM2_PQC_KeyTemplates(void) +{ + int rc; + TPMT_PUBLIC mldsaTemplate, hashMldsaTemplate, mlkemTemplate; + + printf("Testing PQC Key Templates...\n"); + + /* Test MLDSA template */ + rc = wolfTPM2_GetKeyTemplate_MLDSA(&mldsaTemplate, + TPMA_OBJECT_sign | TPMA_OBJECT_userWithAuth, + TPM_MLDSA_65, 1); + AssertIntEQ(rc, TPM_RC_SUCCESS); + AssertIntEQ(mldsaTemplate.type, TPM_ALG_MLDSA); + AssertIntEQ(mldsaTemplate.parameters.mldsaDetail.parameterSet, TPM_MLDSA_65); + AssertIntEQ(mldsaTemplate.parameters.mldsaDetail.allowExternalMu, YES); + /* Verify sign is set, decrypt is NOT set */ + AssertTrue(mldsaTemplate.objectAttributes & TPMA_OBJECT_sign); + AssertFalse(mldsaTemplate.objectAttributes & TPMA_OBJECT_decrypt); + + /* Test HASH_MLDSA template */ + rc = wolfTPM2_GetKeyTemplate_HASH_MLDSA(&hashMldsaTemplate, + TPMA_OBJECT_sign | TPMA_OBJECT_userWithAuth, + TPM_MLDSA_87, TPM_ALG_SHA256); + AssertIntEQ(rc, TPM_RC_SUCCESS); + AssertIntEQ(hashMldsaTemplate.type, TPM_ALG_HASH_MLDSA); + AssertIntEQ(hashMldsaTemplate.parameters.hash_mldsaDetail.parameterSet, TPM_MLDSA_87); + AssertIntEQ(hashMldsaTemplate.parameters.hash_mldsaDetail.hashAlg, TPM_ALG_SHA256); + + /* Test MLKEM template */ + rc = wolfTPM2_GetKeyTemplate_MLKEM(&mlkemTemplate, + TPMA_OBJECT_decrypt | TPMA_OBJECT_userWithAuth, + TPM_MLKEM_768); + AssertIntEQ(rc, TPM_RC_SUCCESS); + AssertIntEQ(mlkemTemplate.type, TPM_ALG_MLKEM); + AssertIntEQ(mlkemTemplate.parameters.mlkemDetail.parameterSet, TPM_MLKEM_768); + /* Verify decrypt is set, sign is NOT set */ + AssertTrue(mlkemTemplate.objectAttributes & TPMA_OBJECT_decrypt); + AssertFalse(mlkemTemplate.objectAttributes & TPMA_OBJECT_sign); + + /* Test NULL argument handling */ + rc = wolfTPM2_GetKeyTemplate_MLDSA(NULL, 0, TPM_MLDSA_44, 0); + AssertIntEQ(rc, BAD_FUNC_ARG); + + rc = wolfTPM2_GetKeyTemplate_HASH_MLDSA(NULL, 0, TPM_MLDSA_44, TPM_ALG_SHA256); + AssertIntEQ(rc, BAD_FUNC_ARG); + + rc = wolfTPM2_GetKeyTemplate_MLKEM(NULL, 0, TPM_MLKEM_512); + AssertIntEQ(rc, BAD_FUNC_ARG); + + printf("Test TPM Wrapper:\tPQC Key Templates:\tPassed\n"); +} + +/* Test PQC sizes sanity check */ +static void test_wolfTPM2_PQC_Sizes(void) +{ + printf("Testing PQC Sizes...\n"); + + /* Verify TPMT_PUBLIC size is reasonable for embedded targets */ + printf(" TPMT_PUBLIC size with PQC: %zu bytes\n", sizeof(TPMT_PUBLIC)); + /* Warn if > 5KB, which could be large for embedded stacks */ + if (sizeof(TPMT_PUBLIC) >= 5120) { + printf(" WARNING: TPMT_PUBLIC size (%zu bytes) may be large for " + "embedded stacks\n", sizeof(TPMT_PUBLIC)); + } + + /* Verify key buffer sizes are correct */ + AssertIntEQ(MAX_MLDSA_PUB_SIZE, 2592); /* ML-DSA-87 */ + AssertIntEQ(MAX_MLDSA_SIG_SIZE, 4627); /* ML-DSA-87 */ + AssertIntEQ(MAX_MLDSA_PRIV_SEED_SIZE, 32); + AssertIntEQ(MAX_MLKEM_PUB_SIZE, 1568); /* ML-KEM-1024 */ + AssertIntEQ(MAX_MLKEM_PRIV_SEED_SIZE, 64); + + printf("Test TPM Wrapper:\tPQC Sizes:\tPassed\n"); +} +#endif /* WOLFTPM_V185 */ + #endif /* !WOLFTPM2_NO_WRAPPER */ #ifndef NO_MAIN_DRIVER @@ -1096,6 +1492,13 @@ int unit_tests(int argc, char *argv[]) test_wolfTPM2_ST33_FirmwareUpgrade(); #endif #endif + #ifdef WOLFTPM_V185 + /* Run non-TPM-dependent tests first */ + test_wolfTPM2_PQC_KeyTemplates(); + test_wolfTPM2_PQC_Sizes(); + /* Then run TPM-dependent PQC tests */ + test_wolfTPM2_PQC(); + #endif test_wolfTPM2_Cleanup(); test_wolfTPM2_thread_local_storage(); #endif /* !WOLFTPM2_NO_WRAPPER */ diff --git a/wolftpm/tpm2.h b/wolftpm/tpm2.h index a01eacf2..1f562d07 100644 --- a/wolftpm/tpm2.h +++ b/wolftpm/tpm2.h @@ -117,6 +117,12 @@ typedef enum { TPM_ALG_CBC = 0x0042, TPM_ALG_CFB = 0x0043, TPM_ALG_ECB = 0x0044, +#ifdef WOLFTPM_V185 + /* Post-Quantum Algorithms - TPM 2.0 Library v185 */ + TPM_ALG_MLKEM = 0x00A0, + TPM_ALG_MLDSA = 0x00A1, + TPM_ALG_HASH_MLDSA = 0x00A2, +#endif } TPM_ALG_ID_T; typedef UINT16 TPM_ALG_ID; @@ -133,6 +139,22 @@ typedef enum { } TPM_ECC_CURVE_T; typedef UINT16 TPM_ECC_CURVE; +#ifdef WOLFTPM_V185 +/* ML-KEM Parameter Sets (TCG Algorithm Registry v2.0) */ +typedef UINT16 TPMI_MLKEM_PARAMETER_SET; +#define TPM_MLKEM_NONE 0x0000 +#define TPM_MLKEM_512 0x0001 +#define TPM_MLKEM_768 0x0002 +#define TPM_MLKEM_1024 0x0003 + +/* ML-DSA Parameter Sets (TCG Algorithm Registry v2.0) */ +typedef UINT16 TPMI_MLDSA_PARAMETER_SET; +#define TPM_MLDSA_NONE 0x0000 +#define TPM_MLDSA_44 0x0001 +#define TPM_MLDSA_65 0x0002 +#define TPM_MLDSA_87 0x0003 +#endif /* WOLFTPM_V185 */ + /* Command Codes */ typedef enum { TPM_CC_FIRST = 0x0000011F, @@ -248,7 +270,20 @@ typedef enum { TPM_CC_CreateLoaded = 0x00000191, TPM_CC_PolicyAuthorizeNV = 0x00000192, TPM_CC_EncryptDecrypt2 = 0x00000193, +#ifdef WOLFTPM_V185 + /* Post-Quantum Cryptography Commands - TPM 2.0 Library v185 */ + TPM_CC_VerifySequenceComplete = 0x000001A3, + TPM_CC_SignSequenceComplete = 0x000001A4, + TPM_CC_VerifyDigestSignature = 0x000001A5, + TPM_CC_SignDigest = 0x000001A6, + TPM_CC_Encapsulate = 0x000001A7, + TPM_CC_Decapsulate = 0x000001A8, + TPM_CC_VerifySequenceStart = 0x000001A9, + TPM_CC_SignSequenceStart = 0x000001AA, + TPM_CC_LAST = TPM_CC_SignSequenceStart, +#else TPM_CC_LAST = TPM_CC_EncryptDecrypt2, +#endif CC_VEND = 0x20000000, TPM_CC_Vendor_TCG_Test = CC_VEND + 0x0000, @@ -362,6 +397,10 @@ typedef enum { TPM_RC_BINDING = RC_FMT1 + 0x025, TPM_RC_CURVE = RC_FMT1 + 0x026, TPM_RC_ECC_POINT = RC_FMT1 + 0x027, +#ifdef WOLFTPM_V185 + /* TPM_RC_EXT_MU: external-Mu is not supported (TCG v185 RC4) */ + TPM_RC_EXT_MU = RC_FMT1 + 0x02B, +#endif RC_MAX_FMT1 = RC_FMT1 + 0x03F, RC_WARN = 0x900, @@ -468,6 +507,10 @@ typedef enum { TPM_ST_AUTH_SECRET = 0x8023, TPM_ST_HASHCHECK = 0x8024, TPM_ST_AUTH_SIGNED = 0x8025, +#ifdef WOLFTPM_V185 + TPM_ST_MESSAGE_VERIFIED = 0x8026, + TPM_ST_DIGEST_VERIFIED = 0x8027, +#endif TPM_ST_FU_MANIFEST = 0x8029, } TPM_ST_T; typedef UINT16 TPM_ST; @@ -889,6 +932,54 @@ typedef struct TPM2B_IV { BYTE buffer[MAX_SYM_BLOCK_SIZE]; } TPM2B_IV; +#ifdef WOLFTPM_V185 +/* Post-Quantum Cryptography (PQC) Types */ +typedef struct TPM2B_SIGNATURE_CTX { + UINT16 size; + BYTE buffer[MAX_SIGNATURE_CTX_SIZE]; +} TPM2B_SIGNATURE_CTX; + +typedef struct TPM2B_KEM_CIPHERTEXT { + UINT16 size; + BYTE buffer[MAX_KEM_CIPHERTEXT_SIZE]; +} TPM2B_KEM_CIPHERTEXT; + +typedef struct TPM2B_SHARED_SECRET { + UINT16 size; + BYTE buffer[MAX_SHARED_SECRET_SIZE]; +} TPM2B_SHARED_SECRET; + +/* TPM2B_PUBLIC_KEY_MLDSA - TCG v185 RC4 Table 209 */ +typedef struct TPM2B_PUBLIC_KEY_MLDSA { + UINT16 size; + BYTE buffer[MAX_MLDSA_PUB_SIZE]; +} TPM2B_PUBLIC_KEY_MLDSA; + +/* TPM2B_PRIVATE_KEY_MLDSA - TCG v185 RC4 Table 210 */ +typedef struct TPM2B_PRIVATE_KEY_MLDSA { + UINT16 size; /* shall be 32 */ + BYTE buffer[MAX_MLDSA_PRIV_SEED_SIZE]; /* 32-byte private seed Xi */ +} TPM2B_PRIVATE_KEY_MLDSA; + +/* TPM2B_PUBLIC_KEY_MLKEM - TCG v185 RC4 Table 205 */ +typedef struct TPM2B_PUBLIC_KEY_MLKEM { + UINT16 size; + BYTE buffer[MAX_MLKEM_PUB_SIZE]; +} TPM2B_PUBLIC_KEY_MLKEM; + +/* TPM2B_PRIVATE_KEY_MLKEM - TCG v185 RC4 Table 206 */ +typedef struct TPM2B_PRIVATE_KEY_MLKEM { + UINT16 size; /* shall be 64 */ + BYTE buffer[MAX_MLKEM_PRIV_SEED_SIZE]; /* 64-byte private seed (d||z) */ +} TPM2B_PRIVATE_KEY_MLKEM; + +/* TPM2B_MLDSA_SIGNATURE - ML-DSA signature (up to 4627 bytes for ML-DSA-87) */ +typedef struct TPM2B_MLDSA_SIGNATURE { + UINT16 size; + BYTE buffer[MAX_MLDSA_SIG_SIZE]; +} TPM2B_MLDSA_SIGNATURE; +#endif /* WOLFTPM_V185 */ + /* Names */ typedef union TPMU_NAME { @@ -1380,6 +1471,14 @@ typedef struct TPMS_SIGNATURE_ECC { typedef TPMS_SIGNATURE_ECC TPMS_SIGNATURE_ECDSA; typedef TPMS_SIGNATURE_ECC TPMS_SIGNATURE_ECDAA; +#ifdef WOLFTPM_V185 +/* ML-DSA (Dilithium) Signature Structure */ +typedef struct TPMS_SIGNATURE_ML_DSA { + TPMI_ALG_HASH hash; + TPM2B_MLDSA_SIGNATURE signature; /* ML-DSA signature up to 4627 bytes */ +} TPMS_SIGNATURE_ML_DSA; +#endif /* WOLFTPM_V185 */ + typedef union TPMU_SIGNATURE { TPMS_SIGNATURE_ECDSA ecdsa; TPMS_SIGNATURE_ECDAA ecdaa; @@ -1387,6 +1486,9 @@ typedef union TPMU_SIGNATURE { TPMS_SIGNATURE_RSAPSS rsapss; TPMT_HA hmac; TPMS_SCHEME_HASH any; +#ifdef WOLFTPM_V185 + TPMS_SIGNATURE_ML_DSA mldsa; +#endif /* WOLFTPM_V185 */ } TPMU_SIGNATURE; typedef struct TPMT_SIGNATURE { @@ -1420,6 +1522,10 @@ typedef union TPMU_PUBLIC_ID { TPM2B_PUBLIC_KEY_RSA rsa; /* TPM_ALG_RSA */ TPMS_ECC_POINT ecc; /* TPM_ALG_ECC */ TPMS_DERIVE derive; +#ifdef WOLFTPM_V185 + TPM2B_PUBLIC_KEY_MLDSA mldsa; /* TPM_ALG_MLDSA or TPM_ALG_HASH_MLDSA */ + TPM2B_PUBLIC_KEY_MLKEM mlkem; /* TPM_ALG_MLKEM */ +#endif } TPMU_PUBLIC_ID; typedef struct TPMS_KEYEDHASH_PARMS { @@ -1446,12 +1552,37 @@ typedef struct TPMS_ECC_PARMS { TPMT_KDF_SCHEME kdf; } TPMS_ECC_PARMS; +#ifdef WOLFTPM_V185 +/* TPMS_MLDSA_PARMS - TCG v185 RC4 Table 229 */ +typedef struct TPMS_MLDSA_PARMS { + TPMI_MLDSA_PARAMETER_SET parameterSet; /* ML-DSA parameter set ID */ + TPMI_YES_NO allowExternalMu; /* Allow TPM2_SignDigest/VerifyDigestSignature */ +} TPMS_MLDSA_PARMS; + +/* TPMS_HASH_MLDSA_PARMS - TCG v185 RC4 Table 230 (Pre-Hash ML-DSA) */ +typedef struct TPMS_HASH_MLDSA_PARMS { + TPMI_MLDSA_PARAMETER_SET parameterSet; /* ML-DSA parameter set ID */ + TPMI_ALG_HASH hashAlg; /* Pre-hash function PH */ +} TPMS_HASH_MLDSA_PARMS; + +/* TPMS_MLKEM_PARMS - TCG v185 RC4 Table 231 */ +typedef struct TPMS_MLKEM_PARMS { + TPMT_SYM_DEF_OBJECT symmetric; /* For restricted decryption key */ + TPMI_MLKEM_PARAMETER_SET parameterSet; /* ML-KEM parameter set */ +} TPMS_MLKEM_PARMS; +#endif /* WOLFTPM_V185 */ + typedef union TPMU_PUBLIC_PARMS { TPMS_KEYEDHASH_PARMS keyedHashDetail; TPMS_SYMCIPHER_PARMS symDetail; TPMS_RSA_PARMS rsaDetail; TPMS_ECC_PARMS eccDetail; TPMS_ASYM_PARMS asymDetail; +#ifdef WOLFTPM_V185 + TPMS_MLDSA_PARMS mldsaDetail; /* TPM_ALG_MLDSA - sign only */ + TPMS_HASH_MLDSA_PARMS hash_mldsaDetail; /* TPM_ALG_HASH_MLDSA - sign only */ + TPMS_MLKEM_PARMS mlkemDetail; /* TPM_ALG_MLKEM - decrypt only */ +#endif } TPMU_PUBLIC_PARMS; typedef struct TPMT_PUBLIC_PARMS { @@ -1493,6 +1624,10 @@ typedef union TPMU_SENSITIVE_COMPOSITE { TPM2B_SENSITIVE_DATA bits; /* TPM_ALG_KEYEDHASH */ TPM2B_SYM_KEY sym; /* TPM_ALG_SYMCIPHER */ TPM2B_PRIVATE_VENDOR_SPECIFIC any; +#ifdef WOLFTPM_V185 + TPM2B_PRIVATE_KEY_MLDSA mldsa; /* TPM_ALG_MLDSA/HASH_MLDSA - seed Xi */ + TPM2B_PRIVATE_KEY_MLKEM mlkem; /* TPM_ALG_MLKEM - seed (d||z) */ +#endif } TPMU_SENSITIVE_COMPOSITE; @@ -2473,6 +2608,92 @@ typedef struct { } Sign_Out; WOLFTPM_API TPM_RC TPM2_Sign(Sign_In* in, Sign_Out* out); +#ifdef WOLFTPM_V185 +/* Post-Quantum Cryptography (PQC) Commands - TPM 2.0 v185 */ + +typedef struct { + TPMI_DH_OBJECT keyHandle; + TPM2B_SIGNATURE_CTX context; +} SignSequenceStart_In; +typedef struct { + TPMI_DH_OBJECT sequenceHandle; +} SignSequenceStart_Out; +WOLFTPM_API TPM_RC TPM2_SignSequenceStart(SignSequenceStart_In* in, + SignSequenceStart_Out* out); + +typedef struct { + TPMI_DH_OBJECT keyHandle; + TPM2B_SIGNATURE_CTX context; +} VerifySequenceStart_In; +typedef struct { + TPMI_DH_OBJECT sequenceHandle; +} VerifySequenceStart_Out; +WOLFTPM_API TPM_RC TPM2_VerifySequenceStart(VerifySequenceStart_In* in, + VerifySequenceStart_Out* out); + +typedef struct { + TPMI_DH_OBJECT sequenceHandle; + TPMI_DH_OBJECT keyHandle; + TPM2B_MAX_BUFFER buffer; +} SignSequenceComplete_In; +typedef struct { + TPMT_SIGNATURE signature; +} SignSequenceComplete_Out; +WOLFTPM_API TPM_RC TPM2_SignSequenceComplete(SignSequenceComplete_In* in, + SignSequenceComplete_Out* out); + +typedef struct { + TPMI_DH_OBJECT sequenceHandle; + TPMI_DH_OBJECT keyHandle; + TPM2B_MAX_BUFFER buffer; + TPMT_SIGNATURE signature; +} VerifySequenceComplete_In; +typedef struct { + TPMT_TK_VERIFIED validation; +} VerifySequenceComplete_Out; +WOLFTPM_API TPM_RC TPM2_VerifySequenceComplete(VerifySequenceComplete_In* in, + VerifySequenceComplete_Out* out); + +typedef struct { + TPMI_DH_OBJECT keyHandle; + TPM2B_DIGEST digest; + TPM2B_SIGNATURE_CTX context; +} SignDigest_In; +typedef struct { + TPMT_SIGNATURE signature; +} SignDigest_Out; +WOLFTPM_API TPM_RC TPM2_SignDigest(SignDigest_In* in, SignDigest_Out* out); + +typedef struct { + TPMI_DH_OBJECT keyHandle; + TPM2B_DIGEST digest; + TPMT_SIGNATURE signature; + TPM2B_SIGNATURE_CTX context; +} VerifyDigestSignature_In; +typedef struct { + TPMT_TK_VERIFIED validation; +} VerifyDigestSignature_Out; +WOLFTPM_API TPM_RC TPM2_VerifyDigestSignature(VerifyDigestSignature_In* in, + VerifyDigestSignature_Out* out); + +typedef struct { + TPMI_DH_OBJECT keyHandle; +} Encapsulate_In; +typedef struct { + TPM2B_SHARED_SECRET sharedSecret; + TPM2B_KEM_CIPHERTEXT ciphertext; +} Encapsulate_Out; +WOLFTPM_API TPM_RC TPM2_Encapsulate(Encapsulate_In* in, Encapsulate_Out* out); + +typedef struct { + TPMI_DH_OBJECT keyHandle; + TPM2B_KEM_CIPHERTEXT ciphertext; +} Decapsulate_In; +typedef struct { + TPM2B_SHARED_SECRET sharedSecret; +} Decapsulate_Out; +WOLFTPM_API TPM_RC TPM2_Decapsulate(Decapsulate_In* in, Decapsulate_Out* out); +#endif /* WOLFTPM_V185 */ typedef struct { TPMI_RH_PROVISION auth; diff --git a/wolftpm/tpm2_types.h b/wolftpm/tpm2_types.h index ddd08d55..abdade15 100644 --- a/wolftpm/tpm2_types.h +++ b/wolftpm/tpm2_types.h @@ -696,6 +696,53 @@ typedef int64_t INT64; #ifndef MAX_CAP_HANDLES #define MAX_CAP_HANDLES (MAX_CAP_DATA / sizeof(TPM_HANDLE)) #endif +#ifdef WOLFTPM_V185 +/* Post-Quantum Cryptography (PQC) Size Definitions - TCG v185 RC4 */ + +/* ML-DSA sizes (TCG v185 RC4 Table 207) */ +#ifndef MAX_MLDSA_PUB_SIZE +#define MAX_MLDSA_PUB_SIZE 2592 /* ML-DSA-87 public key */ +#endif +#ifndef MAX_MLDSA_SIG_SIZE +#define MAX_MLDSA_SIG_SIZE 4627 /* ML-DSA-87 signature */ +#endif +#ifndef MAX_MLDSA_PRIV_SEED_SIZE +#define MAX_MLDSA_PRIV_SEED_SIZE 32 /* Private seed Xi (ΞΎ) */ +#endif + +/* ML-KEM sizes (TCG v185 RC4 Table 204) */ +#ifndef MAX_MLKEM_PUB_SIZE +#define MAX_MLKEM_PUB_SIZE 1568 /* ML-KEM-1024 public key */ +#endif +#ifndef MAX_MLKEM_PRIV_SEED_SIZE +#define MAX_MLKEM_PRIV_SEED_SIZE 64 /* Private seed (d||z) */ +#endif + +/* MAX_SIGNATURE_CTX_SIZE is for the domain separation context parameter + * passed to ML-DSA sign/verify operations. Set large enough for general use. + * Note: ML-DSA signatures themselves can be up to 4627 bytes (ML-DSA-87). */ +#ifndef MAX_SIGNATURE_CTX_SIZE +#define MAX_SIGNATURE_CTX_SIZE 255 /* Domain separation context max */ +#endif + +#ifndef MAX_KEM_CIPHERTEXT_SIZE +#define MAX_KEM_CIPHERTEXT_SIZE 2048 +#endif + +/* MAX_MLKEM_CT_SIZE aliased to avoid collision with existing MAX_KEM_CIPHERTEXT_SIZE */ +#ifndef MAX_MLKEM_CT_SIZE +#define MAX_MLKEM_CT_SIZE MAX_KEM_CIPHERTEXT_SIZE +#endif + +/* Compile-time sanity check */ +#if MAX_MLKEM_CT_SIZE < 1568 +#error "MAX_MLKEM_CT_SIZE too small for ML-KEM-1024 ciphertext (1568 bytes)" +#endif + +#ifndef MAX_SHARED_SECRET_SIZE +#define MAX_SHARED_SECRET_SIZE 64 +#endif +#endif /* WOLFTPM_V185 */ #ifndef HASH_COUNT #ifndef WOLFTPM2_NO_WOLFCRYPT /* Calculate hash count based on wolfCrypt enables */ diff --git a/wolftpm/tpm2_wrap.h b/wolftpm/tpm2_wrap.h index a7114037..c15cdc6a 100644 --- a/wolftpm/tpm2_wrap.h +++ b/wolftpm/tpm2_wrap.h @@ -1779,6 +1779,302 @@ WOLFTPM_API int wolfTPM2_VerifyHashTicket(WOLFTPM2_DEV* dev, int digestSz, TPMI_ALG_SIG_SCHEME sigAlg, TPMI_ALG_HASH hashAlg, TPMT_TK_VERIFIED* checkTicket); +#ifdef WOLFTPM_V185 +/*! + \ingroup wolfTPM2_Wrappers + \brief Post-Quantum Cryptography: Start a signing sequence with context support + \return 0 on success, negative on error + \param dev Device structure + \param key Signing key + \param context Signature context (for PQ algorithms like ML-DSA) + \param contextSz Size of context buffer + \param sequenceHandle Output sequence handle + + _Example_ + \code + WOLFTPM2_DEV dev; + WOLFTPM2_KEY key; + TPM_HANDLE sequenceHandle; + byte context[1024]; + int contextSz = sizeof(context); + + // Initialize and set up key... + rc = wolfTPM2_SignSequenceStart(&dev, &key, context, contextSz, &sequenceHandle); + \endcode + + \sa wolfTPM2_SignSequenceUpdate + \sa wolfTPM2_SignSequenceComplete + \sa wolfTPM2_VerifySequenceStart +*/ +WOLFTPM_API int wolfTPM2_SignSequenceStart(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, + const byte* context, int contextSz, TPM_HANDLE* sequenceHandle); + +/*! + \ingroup wolfTPM2_Wrappers + \brief Post-Quantum Cryptography: Update a signing sequence with data + \return 0 on success, negative on error + \param dev Device structure + \param sequenceHandle Sequence handle from SignSequenceStart + \param data Data to add to sequence + \param dataSz Size of data buffer + + _Example_ + \code + byte data[256]; + rc = wolfTPM2_SignSequenceUpdate(&dev, sequenceHandle, data, sizeof(data)); + \endcode + + \sa wolfTPM2_SignSequenceStart + \sa wolfTPM2_SignSequenceComplete +*/ +WOLFTPM_API int wolfTPM2_SignSequenceUpdate(WOLFTPM2_DEV* dev, + TPM_HANDLE sequenceHandle, const byte* data, int dataSz); + +/*! + \ingroup wolfTPM2_Wrappers + \brief Post-Quantum Cryptography: Complete a signing sequence + \return 0 on success, negative on error + \param dev Device structure + \param sequenceHandle Sequence handle from SignSequenceStart + \param key Signing key + \param data Final data to add to sequence + \param dataSz Size of data buffer + \param sig Output signature buffer + \param sigSz Input/output signature size + + _Example_ + \code + byte sig[2048]; + int sigSz = sizeof(sig); + rc = wolfTPM2_SignSequenceComplete(&dev, sequenceHandle, &key, data, dataSz, sig, &sigSz); + \endcode + + \sa wolfTPM2_SignSequenceStart + \sa wolfTPM2_SignSequenceUpdate +*/ +WOLFTPM_API int wolfTPM2_SignSequenceComplete(WOLFTPM2_DEV* dev, + TPM_HANDLE sequenceHandle, WOLFTPM2_KEY* key, const byte* data, int dataSz, + byte* sig, int* sigSz); + +/*! + \ingroup wolfTPM2_Wrappers + \brief Post-Quantum Cryptography: Start a verification sequence with context support + \return 0 on success, negative on error + \param dev Device structure + \param key Verification key + \param context Signature context (for PQ algorithms like ML-DSA) + \param contextSz Size of context buffer + \param sequenceHandle Output sequence handle + + _Example_ + \code + TPM_HANDLE sequenceHandle; + byte context[1024]; + rc = wolfTPM2_VerifySequenceStart(&dev, &key, context, sizeof(context), &sequenceHandle); + \endcode + + \sa wolfTPM2_VerifySequenceUpdate + \sa wolfTPM2_VerifySequenceComplete + \sa wolfTPM2_SignSequenceStart +*/ +WOLFTPM_API int wolfTPM2_VerifySequenceStart(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, + const byte* context, int contextSz, TPM_HANDLE* sequenceHandle); + +/*! + \ingroup wolfTPM2_Wrappers + \brief Post-Quantum Cryptography: Update a verification sequence with data + \return 0 on success, negative on error + \param dev Device structure + \param sequenceHandle Sequence handle from VerifySequenceStart + \param data Data to add to sequence + \param dataSz Size of data buffer + + _Example_ + \code + rc = wolfTPM2_VerifySequenceUpdate(&dev, sequenceHandle, data, sizeof(data)); + \endcode + + \sa wolfTPM2_VerifySequenceStart + \sa wolfTPM2_VerifySequenceComplete +*/ +WOLFTPM_API int wolfTPM2_VerifySequenceUpdate(WOLFTPM2_DEV* dev, + TPM_HANDLE sequenceHandle, const byte* data, int dataSz); + +/*! + \ingroup wolfTPM2_Wrappers + \brief Post-Quantum Cryptography: Complete a verification sequence + \return 0 on success, negative on error + \param dev Device structure + \param sequenceHandle Sequence handle from VerifySequenceStart + \param key Verification key + \param data Final data to add to sequence + \param dataSz Size of data buffer + \param sig Signature to verify + \param sigSz Size of signature buffer + \param validation Optional output validation ticket + + _Example_ + \code + TPMT_TK_VERIFIED validation; + rc = wolfTPM2_VerifySequenceComplete(&dev, sequenceHandle, &key, data, dataSz, sig, sigSz, &validation); + \endcode + + \sa wolfTPM2_VerifySequenceStart + \sa wolfTPM2_VerifySequenceUpdate +*/ +WOLFTPM_API int wolfTPM2_VerifySequenceComplete(WOLFTPM2_DEV* dev, + TPM_HANDLE sequenceHandle, WOLFTPM2_KEY* key, const byte* data, int dataSz, + const byte* sig, int sigSz, TPMT_TK_VERIFIED* validation); + +/*! + \ingroup wolfTPM2_Wrappers + \brief Post-Quantum Cryptography: Sign a digest with context support + \return 0 on success, negative on error + \param dev Device structure + \param key Signing key + \param digest Digest to sign + \param digestSz Size of digest buffer + \param context Signature context (for PQ algorithms like ML-DSA) + \param contextSz Size of context buffer + \param sig Output signature buffer + \param sigSz Input/output signature size + + _Example_ + \code + byte digest[64], sig[2048]; + int sigSz = sizeof(sig); + byte context[1024]; + rc = wolfTPM2_SignDigest(&dev, &key, digest, sizeof(digest), context, sizeof(context), sig, &sigSz); + \endcode + + \sa wolfTPM2_VerifyDigestSignature + \sa wolfTPM2_SignHash +*/ +WOLFTPM_API int wolfTPM2_SignDigest(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, + const byte* digest, int digestSz, const byte* context, int contextSz, + byte* sig, int* sigSz); + +/*! + \ingroup wolfTPM2_Wrappers + \brief Post-Quantum Cryptography: Verify a digest signature with context support + \return 0 on success, negative on error + \param dev Device structure + \param key Verification key + \param digest Digest that was signed + \param digestSz Size of digest buffer + \param sig Signature to verify + \param sigSz Size of signature buffer + \param context Signature context (for PQ algorithms like ML-DSA) + \param contextSz Size of context buffer + \param validation Optional output validation ticket + + _Example_ + \code + TPMT_TK_VERIFIED validation; + rc = wolfTPM2_VerifyDigestSignature(&dev, &key, digest, sizeof(digest), sig, sigSz, context, sizeof(context), &validation); + \endcode + + \sa wolfTPM2_SignDigest + \sa wolfTPM2_VerifyHash +*/ +WOLFTPM_API int wolfTPM2_VerifyDigestSignature(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, + const byte* digest, int digestSz, const byte* sig, int sigSz, + const byte* context, int contextSz, TPMT_TK_VERIFIED* validation); + +/*! + \ingroup wolfTPM2_Wrappers + \brief Post-Quantum Cryptography: KEM Encapsulate (public key operation) + \return 0 on success, negative on error + \param dev Device structure + \param key Public key for encapsulation + \param ciphertext Output ciphertext buffer + \param ciphertextSz Input/output ciphertext size + \param sharedSecret Output shared secret buffer + \param sharedSecretSz Input/output shared secret size + + _Example_ + \code + byte ciphertext[2048], sharedSecret[64]; + int ciphertextSz = sizeof(ciphertext); + int sharedSecretSz = sizeof(sharedSecret); + rc = wolfTPM2_Encapsulate(&dev, &key, ciphertext, &ciphertextSz, sharedSecret, &sharedSecretSz); + \endcode + + \sa wolfTPM2_Decapsulate +*/ +WOLFTPM_API int wolfTPM2_Encapsulate(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, + byte* ciphertext, int* ciphertextSz, byte* sharedSecret, int* sharedSecretSz); + +/*! + \ingroup wolfTPM2_Wrappers + \brief Post-Quantum Cryptography: KEM Decapsulate (private key operation) + \return 0 on success, negative on error + \param dev Device structure + \param key Private key for decapsulation + \param ciphertext Ciphertext to decapsulate + \param ciphertextSz Size of ciphertext buffer + \param sharedSecret Output shared secret buffer + \param sharedSecretSz Input/output shared secret size + + _Example_ + \code + byte sharedSecret[64]; + int sharedSecretSz = sizeof(sharedSecret); + rc = wolfTPM2_Decapsulate(&dev, &key, ciphertext, ciphertextSz, sharedSecret, &sharedSecretSz); + \endcode + + \sa wolfTPM2_Encapsulate +*/ +WOLFTPM_API int wolfTPM2_Decapsulate(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, + const byte* ciphertext, int ciphertextSz, byte* sharedSecret, int* sharedSecretSz); + +/*! + \ingroup wolfTPM2_Wrappers + \brief Create a key template for ML-DSA signing keys (TCG v185) + \return TPM_RC_SUCCESS on success, BAD_FUNC_ARG if publicTemplate is NULL + \param publicTemplate Pointer to TPMT_PUBLIC structure to populate + \param objectAttributes Key attributes (sign flag will be enforced, decrypt cleared) + \param parameterSet ML-DSA parameter set (TPM_MLDSA_44, TPM_MLDSA_65, or TPM_MLDSA_87) + \param allowExternalMu Non-zero to allow TPM2_SignDigest/VerifyDigestSignature + + \sa wolfTPM2_GetKeyTemplate_HASH_MLDSA + \sa wolfTPM2_GetKeyTemplate_MLKEM +*/ +WOLFTPM_API int wolfTPM2_GetKeyTemplate_MLDSA(TPMT_PUBLIC* publicTemplate, + TPMA_OBJECT objectAttributes, TPMI_MLDSA_PARAMETER_SET parameterSet, + int allowExternalMu); + +/*! + \ingroup wolfTPM2_Wrappers + \brief Create a key template for Pre-Hash ML-DSA signing keys (TCG v185) + \return TPM_RC_SUCCESS on success, BAD_FUNC_ARG if publicTemplate is NULL + \param publicTemplate Pointer to TPMT_PUBLIC structure to populate + \param objectAttributes Key attributes (sign flag will be enforced, decrypt cleared) + \param parameterSet ML-DSA parameter set (TPM_MLDSA_44, TPM_MLDSA_65, or TPM_MLDSA_87) + \param hashAlg Pre-hash algorithm (e.g., TPM_ALG_SHA256) + + \sa wolfTPM2_GetKeyTemplate_MLDSA + \sa wolfTPM2_GetKeyTemplate_MLKEM +*/ +WOLFTPM_API int wolfTPM2_GetKeyTemplate_HASH_MLDSA(TPMT_PUBLIC* publicTemplate, + TPMA_OBJECT objectAttributes, TPMI_MLDSA_PARAMETER_SET parameterSet, + TPMI_ALG_HASH hashAlg); + +/*! + \ingroup wolfTPM2_Wrappers + \brief Create a key template for ML-KEM decryption keys (TCG v185) + \return TPM_RC_SUCCESS on success, BAD_FUNC_ARG if publicTemplate is NULL + \param publicTemplate Pointer to TPMT_PUBLIC structure to populate + \param objectAttributes Key attributes (decrypt flag will be enforced, sign cleared) + \param parameterSet ML-KEM parameter set (TPM_MLKEM_512, TPM_MLKEM_768, or TPM_MLKEM_1024) + + \sa wolfTPM2_GetKeyTemplate_MLDSA + \sa wolfTPM2_GetKeyTemplate_HASH_MLDSA +*/ +WOLFTPM_API int wolfTPM2_GetKeyTemplate_MLKEM(TPMT_PUBLIC* publicTemplate, + TPMA_OBJECT objectAttributes, TPMI_MLKEM_PARAMETER_SET parameterSet); +#endif /* WOLFTPM_V185 */ + /*! \ingroup wolfTPM2_Wrappers \brief Generates and then loads a ECC key-pair with NULL hierarchy for Diffie-Hellman exchange