diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 8dda9827..cbcc18ec 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -4615,11 +4615,12 @@ int wolfTPM2_RsaKey_TpmToWolf(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* tpmKey, exponent = tpmKey->pub.publicArea.parameters.rsaDetail.exponent; if (exponent == 0) exponent = RSA_DEFAULT_PUBLIC_EXPONENT; - e[3] = (exponent >> 24) & 0xFF; - e[2] = (exponent >> 16) & 0xFF; - e[1] = (exponent >> 8) & 0xFF; - e[0] = exponent & 0xFF; - eSz = e[3] ? 4 : e[2] ? 3 : e[1] ? 2 : e[0] ? 1 : 0; /* calc size */ + /* big-endian, matching wc_RsaPublicKeyDecodeRaw and RsaKey_Exponent */ + e[0] = (exponent >> 24) & 0xFF; + e[1] = (exponent >> 16) & 0xFF; + e[2] = (exponent >> 8) & 0xFF; + e[3] = exponent & 0xFF; + eSz = e[0] ? 4 : e[1] ? 3 : e[2] ? 2 : e[3] ? 1 : 0; /* significant bytes */ /* load public key */ nSz = tpmKey->pub.publicArea.unique.rsa.size; @@ -4628,8 +4629,8 @@ int wolfTPM2_RsaKey_TpmToWolf(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* tpmKey, } XMEMCPY(n, tpmKey->pub.publicArea.unique.rsa.buffer, nSz); - /* load public key portion into wolf RsaKey */ - rc = wc_RsaPublicKeyDecodeRaw(n, nSz, e, eSz, wolfKey); + /* load public key portion into wolf RsaKey (pass trailing significant e) */ + rc = wc_RsaPublicKeyDecodeRaw(n, nSz, e + (sizeof(e) - eSz), eSz, wolfKey); return rc; } diff --git a/tests/unit_tests.c b/tests/unit_tests.c index f5f83c65..59bfa37f 100644 --- a/tests/unit_tests.c +++ b/tests/unit_tests.c @@ -2695,6 +2695,48 @@ static void test_wolfTPM2_SetIdentityAuth_RequiresPassword(void) } #endif /* WOLFTPM_MFG_IDENTITY && !SLB9672 && !SLB9673 */ +/* wolfTPM2_RsaKey_TpmToWolf must preserve the exponent for multi-byte + * non-palindromic values. The exponent bytes are big-endian on the wolfCrypt + * side, so a little-endian build would corrupt e.g. 0x010003. */ +static void test_wolfTPM2_RsaKey_TpmToWolf_Exponent(void) +{ +#if !defined(WOLFTPM2_NO_WOLFCRYPT) && !defined(NO_RSA) && \ + !defined(WOLFTPM2_NO_WRAPPER) + int rc; + WOLFTPM2_DEV dev; + WOLFTPM2_KEY tpmKey; + RsaKey wolfKey; + byte eOut[8]; + byte nOut[256]; + word32 eOutSz = (word32)sizeof(eOut); + word32 nOutSz = (word32)sizeof(nOut); + word32 exponent = 0x010003; /* non-palindromic multi-byte exponent */ + + XMEMSET(&dev, 0, sizeof(dev)); + XMEMSET(&tpmKey, 0, sizeof(tpmKey)); + + tpmKey.pub.publicArea.type = TPM_ALG_RSA; + tpmKey.pub.publicArea.parameters.rsaDetail.exponent = exponent; + tpmKey.pub.publicArea.unique.rsa.size = 128; + XMEMSET(tpmKey.pub.publicArea.unique.rsa.buffer, 0xC7, 128); + + rc = wc_InitRsaKey(&wolfKey, NULL); + AssertIntEQ(0, rc); + + rc = wolfTPM2_RsaKey_TpmToWolf(&dev, &tpmKey, &wolfKey); + AssertIntEQ(0, rc); + + rc = wc_RsaFlattenPublicKey(&wolfKey, eOut, &eOutSz, nOut, &nOutSz); + AssertIntEQ(0, rc); + + /* Round-trip: decoded exponent must equal the original TPM exponent */ + AssertIntEQ((int)exponent, (int)wolfTPM2_RsaKey_Exponent(eOut, eOutSz)); + + wc_FreeRsaKey(&wolfKey); + printf("Test TPM Wrapper: %-40s Passed\n", "RsaKey_TpmToWolf exponent:"); +#endif +} + /* The ECDH shared-secret copy must reject a TPM response x-coordinate larger * than the caller's output buffer. TPM2_Packet_ParseEccPoint clamps only to * MAX_ECC_KEY_BYTES, so a MITM/crafted response can report a point.x.size @@ -6255,6 +6297,7 @@ int unit_tests(int argc, char *argv[]) !defined(WOLFTPM_SLB9672) && !defined(WOLFTPM_SLB9673) test_wolfTPM2_SetIdentityAuth_RequiresPassword(); #endif + test_wolfTPM2_RsaKey_TpmToWolf_Exponent(); test_wolfTPM2_EccZToBuffer(); test_wolfTPM2_LoadEccPublicKey_Ex(); test_TPM2_KeyedHashScheme_XorSerialize();