diff --git a/configure.ac b/configure.ac index 1391c2a0..f6120248 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 1e998278..0a1cdce5 100644 --- a/src/tpm2.c +++ b/src/tpm2.c @@ -3197,6 +3197,381 @@ 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); + 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); + 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); + } + + TPM2_Packet_ParseU16(&packet, &out->ciphertext.size); + TPM2_Packet_ParseBytes(&packet, out->ciphertext.buffer, + out->ciphertext.size); + + TPM2_Packet_ParseU16(&packet, &out->sharedSecret.size); + TPM2_Packet_ParseBytes(&packet, out->sharedSecret.buffer, + out->sharedSecret.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); + + TPM2_Packet_ParseU16(&packet, &out->sharedSecret.size); + TPM2_Packet_ParseBytes(&packet, out->sharedSecret.buffer, + out->sharedSecret.size); + } + + TPM2_ReleaseLock(ctx); + } + return rc; +} +#endif /* WOLFTPM_V185 */ + TPM_RC TPM2_SetCommandCodeAuditStatus(SetCommandCodeAuditStatus_In* in) { TPM_RC rc; @@ -6163,6 +6538,18 @@ const char* TPM2_GetAlgName(TPM_ALG_ID alg) return "AES-CFB"; case TPM_ALG_ECB: return "AES-ECB"; + case TPM_ALG_ML_DSA_44: + return "ML-DSA-44"; + case TPM_ALG_ML_DSA_65: + return "ML-DSA-65"; + case TPM_ALG_ML_DSA_87: + return "ML-DSA-87"; + case TPM_ALG_ML_KEM_512: + return "ML-KEM-512"; + case TPM_ALG_ML_KEM_768: + return "ML-KEM-768"; + case TPM_ALG_ML_KEM_1024: + return "ML-KEM-1024"; default: break; } diff --git a/src/tpm2_packet.c b/src/tpm2_packet.c index c24a1563..08d0f602 100644 --- a/src/tpm2_packet.c +++ b/src/tpm2_packet.c @@ -811,6 +811,16 @@ 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_ML_DSA_44: + case TPM_ALG_ML_DSA_65: + case TPM_ALG_ML_DSA_87: + 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; } @@ -847,6 +857,16 @@ 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_ML_DSA_44: + case TPM_ALG_ML_DSA_65: + case TPM_ALG_ML_DSA_87: + TPM2_Packet_ParseU16(packet, &sig->signature.mldsa.hash); + TPM2_Packet_ParseU16(packet, &sig->signature.mldsa.signature.size); + TPM2_Packet_ParseBytes(packet, sig->signature.mldsa.signature.buffer, + sig->signature.mldsa.signature.size); + break; +#endif /* WOLFTPM_V185 */ default: break; } diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index ed0d7b51..cddb3fce 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -4306,6 +4306,629 @@ 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 > (int)sizeof(signSeqStartIn.context.buffer)) { + return BUFFER_E; + } + + /* 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 > (int)sizeof(signSeqCompleteIn.buffer.buffer)) { + return BUFFER_E; + } + + /* 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_ML_DSA_44 || + signSeqCompleteOut.signature.sigAlg == TPM_ALG_ML_DSA_65 || + signSeqCompleteOut.signature.sigAlg == TPM_ALG_ML_DSA_87) { + /* 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 > (int)sizeof(verifySeqStartIn.context.buffer)) { + return BUFFER_E; + } + + 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 > (int)sizeof(verifySeqCompleteIn.buffer.buffer)) { + return BUFFER_E; + } + + 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 { + /* For ML-DSA try to detect from signature */ + TPMI_ALG_SIG_SCHEME scheme = TPM_ALG_NULL; + + /* Try to get scheme from key if available */ + if (key->pub.publicArea.type == TPM_ALG_KEYEDHASH) { + /* KEYEDHASH keys may have ML-DSA scheme */ + /* The scheme is in keyedHashDetail.scheme.scheme */ + scheme = key->pub.publicArea.parameters.keyedHashDetail.scheme.scheme; + } + + /* Check if it's an ML-DSA algorithm from key scheme */ + if (scheme == TPM_ALG_ML_DSA_44 || scheme == TPM_ALG_ML_DSA_65 || + scheme == TPM_ALG_ML_DSA_87) { + signature.sigAlg = scheme; + /* ML-DSA signatures use SHA3-256, SHA3-384, or SHA3-512 typically */ + /* Default to SHA3-256 if not specified */ + 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); + } + /* Fallback: detect ML-DSA from signature size if scheme not available */ + else if (sigSz >= 2000 && sigSz <= 5000) { + /* Likely ML-DSA signature - determine variant from size */ + /* ML-DSA-44: ~2420 bytes, ML-DSA-65: ~3309 bytes, ML-DSA-87: ~4627 bytes */ + if (sigSz <= 3000) { + scheme = TPM_ALG_ML_DSA_44; + } + else if (sigSz <= 4000) { + scheme = TPM_ALG_ML_DSA_65; + } + else { + scheme = TPM_ALG_ML_DSA_87; + } + signature.sigAlg = scheme; + 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); + } + else { + /* Unknown key type and signature doesn't match known formats */ + return BAD_FUNC_ARG; + } + } +#else + else { + /* For PQ algorithms or unknown types, return error */ + return BAD_FUNC_ARG; + } +#endif /* WOLFTPM_V185 */ + 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 > (int)sizeof(signDigestIn.digest.buffer)) { + return BUFFER_E; + } + + if (contextSz > (int)sizeof(signDigestIn.context.buffer)) { + return BUFFER_E; + } + + /* 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_ML_DSA_44 || + signDigestOut.signature.sigAlg == TPM_ALG_ML_DSA_65 || + signDigestOut.signature.sigAlg == TPM_ALG_ML_DSA_87) { + /* 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 > (int)sizeof(verifyDigestSigIn.digest.buffer)) { + return BUFFER_E; + } + + if (contextSz > (int)sizeof(verifyDigestSigIn.context.buffer)) { + return BUFFER_E; + } + + 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 { + /* For ML-DSA and other PQ algorithms, try to detect from signature */ + /* ML-DSA signatures are large: ML-DSA-44: ~2420 bytes, ML-DSA-65: ~3309 bytes, ML-DSA-87: ~4627 bytes */ + /* First, check if key has a scheme that indicates ML-DSA */ + TPMI_ALG_SIG_SCHEME scheme = TPM_ALG_NULL; + + /* Try to get scheme from key if available */ + if (key->pub.publicArea.type == TPM_ALG_KEYEDHASH) { + /* KEYEDHASH keys may have ML-DSA scheme */ + /* The scheme is in keyedHashDetail.scheme.scheme */ + scheme = key->pub.publicArea.parameters.keyedHashDetail.scheme.scheme; + } + + /* Check if it's an ML-DSA algorithm from key scheme */ + if (scheme == TPM_ALG_ML_DSA_44 || scheme == TPM_ALG_ML_DSA_65 || + scheme == TPM_ALG_ML_DSA_87) { + signature.sigAlg = scheme; + /* ML-DSA signatures use SHA3-256, SHA3-384, or SHA3-512 typically */ + /* Default to SHA3-256 if not specified */ + 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); + } + /* Fallback: detect ML-DSA from signature size if scheme not available */ + else if (sigSz >= 2000 && sigSz <= 5000) { + /* Likely ML-DSA signature - determine variant from size */ + /* ML-DSA-44: ~2420 bytes, ML-DSA-65: ~3309 bytes, ML-DSA-87: ~4627 bytes */ + if (sigSz <= 3000) { + scheme = TPM_ALG_ML_DSA_44; + } + else if (sigSz <= 4000) { + scheme = TPM_ALG_ML_DSA_65; + } + else { + scheme = TPM_ALG_ML_DSA_87; + } + signature.sigAlg = scheme; + 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); + } + else { + /* Unknown key type and signature doesn't match known formats */ + return BAD_FUNC_ARG; + } + } +#else + else { + /* For PQ algorithms or unknown types, return error */ + return BAD_FUNC_ARG; + } +#endif /* WOLFTPM_V185 */ + 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; + } + } + } + + 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; + } + } + + return rc; +} +#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 afbfceb2..a7264cc3 100644 --- a/tests/unit_tests.c +++ b/tests/unit_tests.c @@ -428,8 +428,8 @@ static void test_wolfTPM2_EccSignVerifyDig(WOLFTPM2_DEV* dev, word32 rLen, sLen; ecc_key wolfKey; int curveSize = TPM2_GetCurveSize(curve); + int tpmDevId = -2; /* INVALID_DEVID */ #ifdef WOLF_CRYPTO_CB - int tpmDevId = INVALID_DEVID; TpmCryptoDevCtx tpmCtx; XMEMSET(&tpmCtx, 0, sizeof(tpmCtx)); @@ -553,9 +553,11 @@ static void test_wolfTPM2_EccSignVerifyDig(WOLFTPM2_DEV* dev, (flags & FLAGS_USE_CRYPTO_CB) ? "Crypto CB" : "", rc == 0 ? "Passed" : "Failed"); +#ifdef WOLFTPM_CRYPTOCB if (flags & FLAGS_USE_CRYPTO_CB) { wolfTPM2_ClearCryptoDevCb(dev, tpmDevId); } +#endif } static void test_wolfTPM2_EccSignVerify_All(WOLFTPM2_DEV* dev, @@ -883,6 +885,314 @@ 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 */ + +/* 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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); +} +#endif /* WOLFTPM_V185 */ + #endif /* !WOLFTPM2_NO_WRAPPER */ #ifndef NO_MAIN_DRIVER @@ -915,6 +1225,9 @@ int unit_tests(int argc, char *argv[]) !defined(WOLFTPM2_NO_ASN) test_wolfTPM2_EccSignVerify(); #endif + #ifdef WOLFTPM_V185 + 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 74664821..dc3ad408 100644 --- a/wolftpm/tpm2.h +++ b/wolftpm/tpm2.h @@ -117,6 +117,14 @@ typedef enum { TPM_ALG_CBC = 0x0042, TPM_ALG_CFB = 0x0043, TPM_ALG_ECB = 0x0044, + TPM_ALG_ML_DSA_44 = 0x0045, + TPM_ALG_ML_DSA_65 = 0x0046, + TPM_ALG_ML_DSA_87 = 0x0047, + TPM_ALG_ML_KEM_512 = 0x0048, + TPM_ALG_ML_KEM_768 = 0x0049, + TPM_ALG_ML_KEM_1024 = 0x004A, + TPM_ALG_ML_DSA = TPM_ALG_ML_DSA_65, + TPM_ALG_ML_KEM = TPM_ALG_ML_KEM_768, } TPM_ALG_ID_T; typedef UINT16 TPM_ALG_ID; @@ -248,7 +256,15 @@ typedef enum { TPM_CC_CreateLoaded = 0x00000191, TPM_CC_PolicyAuthorizeNV = 0x00000192, TPM_CC_EncryptDecrypt2 = 0x00000193, - TPM_CC_LAST = TPM_CC_EncryptDecrypt2, + TPM_CC_SignSequenceStart = 0x00000194, + TPM_CC_VerifySequenceStart = 0x00000195, + TPM_CC_SignSequenceComplete = 0x00000196, + TPM_CC_VerifySequenceComplete = 0x00000197, + TPM_CC_SignDigest = 0x00000198, + TPM_CC_VerifyDigestSignature = 0x00000199, + TPM_CC_Encapsulate = 0x0000019A, + TPM_CC_Decapsulate = 0x0000019B, + TPM_CC_LAST = TPM_CC_Decapsulate, CC_VEND = 0x20000000, TPM_CC_Vendor_TCG_Test = CC_VEND + 0x0000, @@ -458,6 +474,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; @@ -879,6 +899,24 @@ 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; +#endif /* WOLFTPM_V185 */ + /* Names */ typedef union TPMU_NAME { @@ -1370,6 +1408,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_MAX_BUFFER signature; /* ML-DSA signature is variable length */ +} TPMS_SIGNATURE_ML_DSA; +#endif /* WOLFTPM_V185 */ + typedef union TPMU_SIGNATURE { TPMS_SIGNATURE_ECDSA ecdsa; TPMS_SIGNATURE_ECDAA ecdaa; @@ -1377,6 +1423,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 { @@ -2457,6 +2506,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_KEM_CIPHERTEXT ciphertext; + TPM2B_SHARED_SECRET sharedSecret; +} 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 7aeb187e..4572fa2e 100644 --- a/wolftpm/tpm2_types.h +++ b/wolftpm/tpm2_types.h @@ -689,6 +689,18 @@ 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 */ +#ifndef MAX_SIGNATURE_CTX_SIZE +#define MAX_SIGNATURE_CTX_SIZE 1024 +#endif +#ifndef MAX_KEM_CIPHERTEXT_SIZE +#define MAX_KEM_CIPHERTEXT_SIZE 2048 +#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 8d709baa..b1ab103d 100644 --- a/wolftpm/tpm2_wrap.h +++ b/wolftpm/tpm2_wrap.h @@ -1748,6 +1748,256 @@ 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); +#endif /* WOLFTPM_V185 */ + /*! \ingroup wolfTPM2_Wrappers \brief Generates and then loads a ECC key-pair with NULL hierarchy for Diffie-Hellman exchange