diff --git a/examples/spdm/spdm_ctrl.c b/examples/spdm/spdm_ctrl.c index 1bcb924bf..a03fc5ac6 100644 --- a/examples/spdm/spdm_ctrl.c +++ b/examples/spdm/spdm_ctrl.c @@ -45,14 +45,90 @@ int TPM2_SPDM_Ctrl(void* userCtx, int argc, char *argv[]); -static const char* ctrl_init_rc_string(int rc) +static const char* ctrl_rc_string(int rc) { - if (rc >= WOLFSPDM_E_NOT_IMPL && rc <= WOLFSPDM_E_INVALID_ARG) { + /* -1 is also the HAL I/O failure code, so it keeps the TPM string */ + if (rc >= WOLFSPDM_E_CHUNK && rc < WOLFSPDM_E_INVALID_ARG) { return wolfSPDM_GetErrorString(rc); } return TPM2_GetRCString(rc); } +#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +#define CTRL_PUBK_MAX 256 + +/* GET_PUBK returns a TPMT_PUBLIC or a raw point; --responder-pubkey takes + * the raw P-384 X||Y */ +static int ctrl_pubkey_point(const byte* pubKey, word32 pubKeySz, + byte* point) +{ + int rc; + int sizeUsed = 0; + int encSz = 0; + TPM2B_PUBLIC pub; + byte wire[2 + CTRL_PUBK_MAX]; + byte enc[2 + CTRL_PUBK_MAX]; + + if (pubKey == NULL || point == NULL) + return BAD_FUNC_ARG; + if (pubKeySz == WOLFSPDM_ECC_POINT_SIZE) { + XMEMCPY(point, pubKey, WOLFSPDM_ECC_POINT_SIZE); + return TPM_RC_SUCCESS; + } + if (pubKeySz > CTRL_PUBK_MAX) + return BUFFER_E; + + XMEMSET(&pub, 0, sizeof(pub)); + wire[0] = (byte)(pubKeySz >> 8); + wire[1] = (byte)pubKeySz; + XMEMCPY(wire + 2, pubKey, pubKeySz); + rc = TPM2_ParsePublic(&pub, wire, pubKeySz + 2, &sizeUsed); + if (rc == TPM_RC_SUCCESS && ((word32)sizeUsed != pubKeySz + 2 || + pub.publicArea.type != TPM_ALG_ECC || + pub.publicArea.parameters.eccDetail.curveID != TPM_ECC_NIST_P384 || + pub.publicArea.unique.ecc.x.size != WOLFSPDM_ECC_KEY_SIZE || + pub.publicArea.unique.ecc.y.size != WOLFSPDM_ECC_KEY_SIZE)) { + rc = BAD_FUNC_ARG; + } + /* The parser clamps oversized fields, so require a lossless re-encode */ + if (rc == TPM_RC_SUCCESS) { + rc = TPM2_AppendPublic(enc, (word32)sizeof(enc), &encSz, &pub); + if (rc == TPM_RC_SUCCESS && (encSz != sizeUsed || + XMEMCMP(enc, wire, (size_t)encSz) != 0)) { + rc = BAD_FUNC_ARG; + } + } + if (rc == TPM_RC_SUCCESS) { + XMEMCPY(point, pub.publicArea.unique.ecc.x.buffer, + WOLFSPDM_ECC_KEY_SIZE); + XMEMCPY(point + WOLFSPDM_ECC_KEY_SIZE, + pub.publicArea.unique.ecc.y.buffer, WOLFSPDM_ECC_KEY_SIZE); + } + return rc; +} + +static int ctrl_print_pubkey(const byte* pubKey, word32 pubKeySz) +{ + int rc; + word32 i; + byte point[WOLFSPDM_ECC_POINT_SIZE]; + + printf(" Got %u bytes\n", (unsigned int)pubKeySz); + rc = ctrl_pubkey_point(pubKey, pubKeySz, point); + if (rc != TPM_RC_SUCCESS) { + printf(" Not a P-384 public key: 0x%x: %s\n", rc, + ctrl_rc_string(rc)); + return rc; + } + printf(" SPDM responder public key: "); + for (i = 0; i < (word32)sizeof(point); i++) { + printf("%02x", point[i]); + } + printf("\n"); + return TPM_RC_SUCCESS; +} +#endif /* WOLFSPDM_NUVOTON || WOLFSPDM_NATIONS */ + static void usage(void) { printf("SPDM Demo - TPM secure session\n\n" @@ -116,7 +192,7 @@ static int ctrl_caps(WOLFTPM2_DEV* dev) printf(" wolfTPM caps read successfully\n"); } else { - printf(" FAILED: 0x%x: %s\n", rc, ctrl_init_rc_string(rc)); + printf(" FAILED: 0x%x: %s\n", rc, ctrl_rc_string(rc)); } return rc; } @@ -145,12 +221,13 @@ static int ctrl_session_info(WOLFTPM2_DEV* dev) printf("\n=== SPDM Session Info (TPM_CAP_SPDM_SESSION_INFO) ===\n"); XMEMSET(&info, 0, sizeof(info)); rc = wolfTPM2_GetCapability_SPDMSessionInfo(dev, &info); - if (rc == TPM_RC_VALUE) { + /* Parameter bits ride on format-1 codes (Nuvoton answers 0x1c4) */ + if (rc > 0 && (rc & RC_MAX_FMT1) == TPM_RC_VALUE) { printf(" Not supported by this TPM (TPM_RC_VALUE)\n"); return rc; } if (rc != 0) { - printf(" FAILED: 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + printf(" FAILED: 0x%x: %s\n", rc, ctrl_rc_string(rc)); return rc; } printf(" Sessions: %u%s\n", info.count, @@ -422,7 +499,7 @@ static int ctrl_policy_nv(WOLFTPM2_DEV* dev) exit: if (rc != 0) { - printf(" FAILED: 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + printf(" FAILED: 0x%x: %s\n", rc, ctrl_rc_string(rc)); /* Format-one codes may carry an auth-session selector in upper bits. */ if ((rc & RC_MAX_FMT1) == TPM_RC_CHANNEL) { printf(" (the policy requires the command to arrive over SPDM)\n"); @@ -432,7 +509,7 @@ static int ctrl_policy_nv(WOLFTPM2_DEV* dev) int cleanupRc = wolfTPM2_NVDeleteAuth(dev, &parent, nvIndex); if (cleanupRc != 0) { printf(" NV cleanup failed: 0x%x: %s\n", cleanupRc, - wolfTPM2_GetRCString(cleanupRc)); + ctrl_rc_string(cleanupRc)); if (rc == 0) rc = cleanupRc; } } @@ -454,7 +531,7 @@ static int ctrl_enable(WOLFTPM2_DEV* dev) printf(" NTC2_PreConfig not supported (may already be enabled)\n"); rc = 0; } else { - printf(" FAILED: 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + printf(" FAILED: 0x%x: %s\n", rc, ctrl_rc_string(rc)); } return rc; } @@ -472,7 +549,7 @@ static int ctrl_disable(WOLFTPM2_DEV* dev) printf(" NTC2_PreConfig not supported\n"); rc = 0; } else { - printf(" FAILED: 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + printf(" FAILED: 0x%x: %s\n", rc, ctrl_rc_string(rc)); } return rc; } @@ -502,7 +579,7 @@ static int ctrl_status(WOLFTPM2_DEV* dev) if (status.spdmOnlyLocked) printf(" NOTE: SPDM-only mode, use --unlock to restore\n"); } else { - printf(" FAILED: 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + printf(" FAILED: 0x%x: %s\n", rc, ctrl_rc_string(rc)); } return rc; } @@ -510,19 +587,15 @@ static int ctrl_status(WOLFTPM2_DEV* dev) static int ctrl_get_pubkey(WOLFTPM2_DEV* dev) { int rc; - byte pubKey[128]; + byte pubKey[CTRL_PUBK_MAX]; word32 pubKeySz = sizeof(pubKey); - word32 i; printf("\n=== Get SPDM-Identity Public Key ===\n"); rc = wolfTPM2_SpdmGetPubKey(dev, pubKey, &pubKeySz); if (rc == 0) { - printf(" Got %d bytes: ", (int)pubKeySz); - for (i = 0; i < pubKeySz && i < 32; i++) printf("%02x", pubKey[i]); - if (pubKeySz > 32) printf("..."); - printf("\n"); + rc = ctrl_print_pubkey(pubKey, pubKeySz); } else { - printf(" FAILED: 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + printf(" FAILED: 0x%x: %s\n", rc, ctrl_rc_string(rc)); } return rc; } @@ -545,7 +618,7 @@ static int ctrl_connect(WOLFTPM2_DEV* dev) printf(" Session established (AES-256-GCM, SessionID: 0x%08x)\n", wolfTPM2_SpdmGetSessionId(dev)); } else { - printf(" FAILED: 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + printf(" FAILED: 0x%x: %s\n", rc, ctrl_rc_string(rc)); } return rc; } @@ -558,7 +631,7 @@ static int ctrl_lock(WOLFTPM2_DEV* dev, int lock) if (rc == 0) printf(" %s\n", lock ? "LOCKED (TPM requires SPDM)" : "UNLOCKED"); else - printf(" FAILED: 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + printf(" FAILED: 0x%x: %s\n", rc, ctrl_rc_string(rc)); return rc; } #endif /* WOLFSPDM_NUVOTON */ @@ -701,7 +774,7 @@ static int ctrl_nations_psk_set(WOLFTPM2_DEV* dev, /* PSK_SET is a vendor-defined SPDM command — needs GET_VERSION first */ rc = wolfSPDM_GetVersion(dev->spdmCtx->spdmCtx); if (rc != 0) { - printf(" GET_VERSION failed: %d\n", rc); + printf(" GET_VERSION failed: %d: %s\n", rc, ctrl_rc_string(rc)); wc_ForceZero(payload, sizeof(payload)); return rc; } @@ -711,7 +784,7 @@ static int ctrl_nations_psk_set(WOLFTPM2_DEV* dev, if (rc == 0) printf(" PSK provisioned (64-byte PSK + 48-byte digest)\n"); else - printf(" FAILED: 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + printf(" FAILED: 0x%x: %s\n", rc, ctrl_rc_string(rc)); return rc; } @@ -742,7 +815,7 @@ static int ctrl_nations_psk_clear(WOLFTPM2_DEV* dev, const char* authHex) if (rc == 0) printf(" PSK cleared\n"); else - printf(" FAILED: 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + printf(" FAILED: 0x%x: %s\n", rc, ctrl_rc_string(rc)); return rc; } @@ -754,7 +827,7 @@ static int ctrl_nations_identity_key_set(WOLFTPM2_DEV* dev, int set) if (rc == 0) { printf(" Identity key %s\n", set ? "provisioned" : "un-provisioned"); } else { - printf(" FAILED: 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + printf(" FAILED: 0x%x: %s\n", rc, ctrl_rc_string(rc)); } return rc; } @@ -762,27 +835,23 @@ static int ctrl_nations_identity_key_set(WOLFTPM2_DEV* dev, int set) static int ctrl_nations_get_pubkey(WOLFTPM2_DEV* dev) { int rc; - byte pubKey[128]; + byte pubKey[CTRL_PUBK_MAX]; word32 pubKeySz = sizeof(pubKey); - word32 i; printf("\n=== Get SPDM-Identity Public Key ===\n"); /* GET_PUBK is a vendor SPDM command — needs GET_VERSION first */ rc = wolfSPDM_GetVersion(dev->spdmCtx->spdmCtx); if (rc != 0) { - printf(" GET_VERSION failed: %d\n", rc); + printf(" GET_VERSION failed: %d: %s\n", rc, ctrl_rc_string(rc)); return rc; } rc = wolfTPM2_SpdmGetPubKey(dev, pubKey, &pubKeySz); if (rc == 0) { - printf(" Got %d bytes: ", (int)pubKeySz); - for (i = 0; i < pubKeySz && i < 32; i++) printf("%02x", pubKey[i]); - if (pubKeySz > 32) printf("..."); - printf("\n"); + rc = ctrl_print_pubkey(pubKey, pubKeySz); } else { - printf(" FAILED: 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + printf(" FAILED: 0x%x: %s\n", rc, ctrl_rc_string(rc)); } return rc; } @@ -814,7 +883,7 @@ static int ctrl_nations_caps184(WOLFTPM2_DEV* dev) printf("%02x", raw[i]); printf("\n"); } else { - printf(" Failed: 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + printf(" Failed: 0x%x: %s\n", rc, ctrl_rc_string(rc)); } /* 2. TPM_CAP_PUB_KEYS (TPM 184: SPDM identity keys) */ @@ -836,7 +905,7 @@ static int ctrl_nations_caps184(WOLFTPM2_DEV* dev) } else if (rc == TPM_RC_VALUE) { printf(" Not supported (TPM_RC_VALUE)\n"); } else { - printf(" Failed: 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + printf(" Failed: 0x%x: %s\n", rc, ctrl_rc_string(rc)); } /* 3. TPM_CAP_SPDM_SESSION_INFO (TPM 184: SPDM session state) */ @@ -863,7 +932,7 @@ static int ctrl_nations_connect(WOLFTPM2_DEV* dev) printf(" Session established (AES-256-GCM, SessionID: 0x%08x)\n", wolfTPM2_SpdmGetSessionId(dev)); } else { - printf(" FAILED: 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + printf(" FAILED: 0x%x: %s\n", rc, ctrl_rc_string(rc)); } return rc; } @@ -883,7 +952,7 @@ static int ctrl_infineon_enable(WOLFTPM2_DEV* dev, int enable) enable ? "enabled" : "disabled"); } else { - printf(" FAILED: 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + printf(" FAILED: 0x%x: %s\n", rc, ctrl_rc_string(rc)); } return rc; } @@ -954,7 +1023,7 @@ static int ctrl_infineon_connect(WOLFTPM2_DEV* dev) } rc = wolfTPM2_SpdmConnectInfineonTcg(dev, NULL, 0, NULL, 0); if (rc != TPM_RC_SUCCESS) { - printf(" FAILED: %d: %s\n", rc, ctrl_init_rc_string(rc)); + printf(" FAILED: %d: %s\n", rc, ctrl_rc_string(rc)); } return rc; } @@ -1281,14 +1350,14 @@ int TPM2_SPDM_Ctrl(void* userCtx, int argc, char *argv[]) } if (rc != 0) { printf("TPM initialization failed: 0x%x: %s\n", rc, - ctrl_init_rc_string(rc)); + ctrl_rc_string(rc)); return rc; } rc = wolfTPM2_SpdmInit(&dev); if (rc != 0) { printf("wolfTPM2_SpdmInit failed: %s\n", - ctrl_init_rc_string(rc)); + ctrl_rc_string(rc)); wolfTPM2_Cleanup(&dev); return rc; } diff --git a/src/spdm/unit_test.c b/src/spdm/unit_test.c index 6c4a11096..258e005f0 100644 --- a/src/spdm/unit_test.c +++ b/src/spdm/unit_test.c @@ -785,24 +785,33 @@ static int tcg_get_pub_key_io_cb(WOLFSPDM_CTX* ctx, const byte* txBuf, word32 txSz, byte* rxBuf, word32* rxSz, void* userCtx) { TCG_GET_PUB_KEY_IO_CTX* ioCtx = (TCG_GET_PUB_KEY_IO_CTX*)userCtx; + static const byte versionRsp[] = { + SPDM_VERSION_10, SPDM_VERSION, 0x00, 0x00, 0x00, 0x01, + 0x00, SPDM_VERSION_13 + }; byte spdmRsp[WOLFSPDM_VENDOR_BUF_SZ]; word32 totalSz; int spdmRspSz; - (void)txBuf; - (void)txSz; - - if (ctx == NULL || rxBuf == NULL || rxSz == NULL || ioCtx == NULL) { + if (ctx == NULL || txBuf == NULL || rxBuf == NULL || rxSz == NULL || + ioCtx == NULL || txSz < WOLFSPDM_TCG_HEADER_SIZE + 2) { return -1; } - spdmRspSz = wolfSPDM_BuildVendorDefined(SPDM_VERSION_13, - WOLFSPDM_VDCODE_GET_PUBK, ioCtx->pubKey, ioCtx->pubKeySz, - spdmRsp, sizeof(spdmRsp)); - if (spdmRspSz < 0) { - return -1; + /* wolfSPDM sends GET_VERSION first when no version is negotiated */ + if (txBuf[WOLFSPDM_TCG_HEADER_SIZE + 1] == SPDM_GET_VERSION) { + XMEMCPY(spdmRsp, versionRsp, sizeof(versionRsp)); + spdmRspSz = (int)sizeof(versionRsp); + } + else { + spdmRspSz = wolfSPDM_BuildVendorDefined(SPDM_VERSION_13, + WOLFSPDM_VDCODE_GET_PUBK, ioCtx->pubKey, ioCtx->pubKeySz, + spdmRsp, sizeof(spdmRsp)); + if (spdmRspSz < 0) { + return -1; + } + spdmRsp[1] = SPDM_TEST_VENDOR_DEFINED_RSP; } - spdmRsp[1] = SPDM_TEST_VENDOR_DEFINED_RSP; totalSz = WOLFSPDM_TCG_HEADER_SIZE + (word32)spdmRspSz; if (*rxSz < totalSz) { @@ -2260,7 +2269,7 @@ static int test_encrypt_internal_null_args(void) static int test_encrypt_decrypt_roundtrip(void) { - byte plain[16] = "Hello SPDM test!"; + byte plain[] = "Hello SPDM test!"; static byte enc[512]; static byte dec[256]; word32 encSz = sizeof(enc); @@ -2296,7 +2305,7 @@ static int test_encrypt_decrypt_roundtrip(void) #ifdef WOLFTPM_SPDM_TCG static int test_encrypt_decrypt_roundtrip_tcg(void) { - byte plain[16] = "TCG encrypt tst!"; + byte plain[] = "TCG encrypt tst!"; static byte enc[512]; static byte dec[256]; word32 encSz = sizeof(enc); diff --git a/tests/spdm_ctrl_tests.c b/tests/spdm_ctrl_tests.c index 964a35d4a..a36c85e10 100644 --- a/tests/spdm_ctrl_tests.c +++ b/tests/spdm_ctrl_tests.c @@ -216,10 +216,109 @@ static int test_vendor_dispatch(void) return 0; } +static int test_rc_string(void) +{ + if (XSTRCMP(ctrl_rc_string(WOLFSPDM_E_PEER_ERROR), + wolfSPDM_GetErrorString(WOLFSPDM_E_PEER_ERROR)) != 0) + return 1; + if (XSTRCMP(ctrl_rc_string(WOLFSPDM_E_CHUNK), + wolfSPDM_GetErrorString(WOLFSPDM_E_CHUNK)) != 0) + return 1; + if (XSTRCMP(ctrl_rc_string(TPM_RC_VALUE), + TPM2_GetRCString(TPM_RC_VALUE)) != 0) + return 1; + if (XSTRCMP(ctrl_rc_string(BAD_FUNC_ARG), + TPM2_GetRCString(BAD_FUNC_ARG)) != 0) + return 1; + if (XSTRCMP(ctrl_rc_string(-1), TPM2_GetRCString(-1)) != 0) + return 1; + puts("PASS: wolfSPDM and TPM error codes print their own names"); + return 0; +} + +#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) +static int test_pubkey_point(void) +{ + TPM2B_PUBLIC pubIn; + byte wire[2 + CTRL_PUBK_MAX]; + byte raw[WOLFSPDM_ECC_POINT_SIZE]; + byte point[WOLFSPDM_ECC_POINT_SIZE]; + byte big[CTRL_PUBK_MAX]; + word32 off; + int sz = 0; + + XMEMSET(&pubIn, 0, sizeof(pubIn)); + pubIn.publicArea.type = TPM_ALG_ECC; + pubIn.publicArea.nameAlg = TPM_ALG_SHA384; + pubIn.publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_NULL; + pubIn.publicArea.parameters.eccDetail.scheme.scheme = TPM_ALG_ECDSA; + pubIn.publicArea.parameters.eccDetail.scheme.details.ecdsa.hashAlg = + TPM_ALG_SHA384; + pubIn.publicArea.parameters.eccDetail.curveID = TPM_ECC_NIST_P384; + pubIn.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL; + pubIn.publicArea.unique.ecc.x.size = WOLFSPDM_ECC_KEY_SIZE; + XMEMSET(pubIn.publicArea.unique.ecc.x.buffer, 0x11, WOLFSPDM_ECC_KEY_SIZE); + pubIn.publicArea.unique.ecc.y.size = WOLFSPDM_ECC_KEY_SIZE; + XMEMSET(pubIn.publicArea.unique.ecc.y.buffer, 0x22, WOLFSPDM_ECC_KEY_SIZE); + if (TPM2_AppendPublic(wire, (word32)sizeof(wire), &sz, &pubIn) != 0 || + sz <= 2) + return 1; + + XMEMSET(point, 0, sizeof(point)); + if (ctrl_pubkey_point(wire + 2, (word32)sz - 2, point) != 0) + return 1; + XMEMSET(raw, 0x11, WOLFSPDM_ECC_KEY_SIZE); + XMEMSET(raw + WOLFSPDM_ECC_KEY_SIZE, 0x22, WOLFSPDM_ECC_KEY_SIZE); + if (XMEMCMP(point, raw, sizeof(raw)) != 0) + return 1; + if (ctrl_print_pubkey(wire + 2, (word32)sz - 2) != 0) + return 1; + + XMEMSET(point, 0, sizeof(point)); + if (ctrl_pubkey_point(raw, sizeof(raw), point) != 0 || + XMEMCMP(point, raw, sizeof(raw)) != 0) + return 1; + + /* 49-byte X must not be accepted as a clamped 48-byte coordinate */ + off = (word32)sz - 2 - (2 * (2 + WOLFSPDM_ECC_KEY_SIZE)); + XMEMCPY(big, wire + 2, off); + big[off++] = 0; + big[off++] = WOLFSPDM_ECC_KEY_SIZE + 1; + XMEMSET(big + off, 0x11, WOLFSPDM_ECC_KEY_SIZE + 1); + off += WOLFSPDM_ECC_KEY_SIZE + 1; + big[off++] = 0; + big[off++] = WOLFSPDM_ECC_KEY_SIZE; + XMEMSET(big + off, 0x22, WOLFSPDM_ECC_KEY_SIZE); + off += WOLFSPDM_ECC_KEY_SIZE; + if (ctrl_pubkey_point(big, off, point) == 0) + return 1; + + if (ctrl_pubkey_point(wire + 2, (word32)sz - 3, point) == 0) + return 1; + wire[3] = (byte)TPM_ALG_RSA; + if (ctrl_pubkey_point(wire + 2, (word32)sz - 2, point) == 0) + return 1; + + pubIn.publicArea.parameters.eccDetail.curveID = TPM_ECC_BP_P384_R1; + sz = 0; + if (TPM2_AppendPublic(wire, (word32)sizeof(wire), &sz, &pubIn) != 0 || + sz <= 2) + return 1; + if (ctrl_pubkey_point(wire + 2, (word32)sz - 2, point) == 0) + return 1; + puts("PASS: GET_PUBK TPMT_PUBLIC reduces to the P-384 X||Y point"); + return 0; +} +#endif + int main(void) { int rc; rc = test_nv_cleanup(); + if (rc == 0) rc = test_rc_string(); +#if defined(WOLFSPDM_NUVOTON) || defined(WOLFSPDM_NATIONS) + if (rc == 0) rc = test_pubkey_point(); +#endif if (rc == 0) rc = test_vendor_dispatch(); if (rc != 0) puts("FAIL: SPDM control regression"); return rc; diff --git a/tests/unit_tests.c b/tests/unit_tests.c index e2543426c..e15fa7ece 100644 --- a/tests/unit_tests.c +++ b/tests/unit_tests.c @@ -315,6 +315,13 @@ static void test_wolfTPM2_InitWithSpdmPsk_success(void) #endif #ifdef WOLFTPM_SPDM +/* Format-1 TPM_RC_VALUE carries parameter bits; Nuvoton answers 0x1c4 */ +static int spdm_cap_unsupported(int rc) +{ + return (rc > 0 && (rc & RC_MAX_FMT1) == TPM_RC_VALUE) || + WOLFTPM_IS_COMMAND_UNAVAILABLE(rc); +} + static void test_wolfTPM2_PolicyTransportSPDMMake(void) { /* SHA-256 of (zeros[32] || 0x000001A1 || scKeyNameHash), scKeyNameHash = @@ -407,6 +414,13 @@ static void test_wolfTPM2_PolicyTransportSPDMMake(void) rc = TPM2_PolicyTransportSPDM(NULL); AssertIntEQ(rc, BAD_FUNC_ARG); + AssertIntEQ(spdm_cap_unsupported(TPM_RC_VALUE), 1); + AssertIntEQ(spdm_cap_unsupported(TPM_RC_VALUE | TPM_RC_P | TPM_RC_1), 1); + AssertIntEQ(spdm_cap_unsupported(TPM_RC_COMMAND_CODE), 1); + AssertIntEQ(spdm_cap_unsupported(TPM_RC_SIZE | TPM_RC_P | TPM_RC_1), 0); + AssertIntEQ(spdm_cap_unsupported(TPM_RC_SUCCESS), 0); + AssertIntEQ(spdm_cap_unsupported(BAD_FUNC_ARG), 0); + printf("Test TPM Wrapper: %-40s Passed\n", "PolicyTransportSPDM make:"); } @@ -429,7 +443,7 @@ static void test_wolfTPM2_PolicyTransportSPDM_live(WOLFTPM2_DEV* dev) rc = wolfTPM2_GetCapability_SPDMSessionInfo(dev, &info); /* PolicyTransportSPDM and its capability are optional (TPM 2.0 v1.84). * A connected SPDM TPM that does not implement them is not a failure. */ - if (rc == TPM_RC_VALUE || rc == TPM_RC_COMMAND_CODE) { + if (spdm_cap_unsupported(rc)) { printf("Test TPM Wrapper: %-40s Skipped\n", "PolicyTransportSPDM live:"); return;