Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/workflows/fwtpm-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,24 @@ jobs:
wolfssl_config: --enable-wolftpm --enable-pkcallbacks --enable-keygen --disable-rsa
build_only: true

# RSA 4096 at runtime. The chip macros raise MAX_RSA_KEY_BITS to
# 4096, which is where a public area outgrows the buffers sized
# for RSA 2048; every other entry here leaves it at 2048.
- name: fwtpm-rsa4096
os: ubuntu-latest
wolftpm_config: --enable-fwtpm --enable-swtpm --enable-infineon=slb9672
wolfssl_config: --enable-wolftpm --enable-pkcallbacks --enable-keygen
build_only: false

# Build-only: the same chip macros with RSA disabled, so the RSA
# sizing branches must not fire and the buffers stay at their
# classical sizes.
- name: fwtpm-no-rsa-chip4096
os: ubuntu-latest
wolftpm_config: --enable-fwtpm --enable-swtpm --enable-infineon=slb9672
wolfssl_config: --enable-wolftpm --enable-pkcallbacks --enable-keygen --disable-rsa
build_only: true

# Build-only: fwTPM with ECC disabled
- name: fwtpm-no-ecc
os: ubuntu-latest
Expand Down
20 changes: 12 additions & 8 deletions examples/bench/bench.c
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,7 @@ int TPM2_Wrapper_BenchArgs(void* userCtx, int argc, char *argv[])
double start;
int count;
int sha1Supported;
int rsaBits = WOLFTPM2_WRAP_RSA_KEY_BITS;
int skipDec = 0; /* skip a decrypt op whose paired encrypt was unsupported */
TPM_ALG_ID paramEncAlg = TPM_ALG_NULL;
WOLFTPM2_SESSION tpmSession;
Expand Down Expand Up @@ -621,10 +622,12 @@ int TPM2_Wrapper_BenchArgs(void* userCtx, int argc, char *argv[])
&publicTemplate, (byte*)gKeyAuth, sizeof(gKeyAuth)-1);
if (rc != 0) goto exit;
} while (bench_stats_check(start, &count, maxKeyGenDurSec));
bench_stats_asym_finish("RSA", 2048, "key gen", count, start);
bench_stats_asym_finish("RSA", rsaBits, "key gen", count, start);

/* Perform RSA encrypt / decrypt (no pad) */
message.size = 256; /* test message 0x11,0x11,etc */
/* No padding means the message is exactly the modulus width, which the
* chip defaults take to 512 bytes on an RSA 4096 part. */
message.size = rsaBits / 8;
XMEMSET(message.buffer, 0x11, message.size);

bench_stats_start(&count, &start);
Expand All @@ -635,11 +638,12 @@ int TPM2_Wrapper_BenchArgs(void* userCtx, int argc, char *argv[])
if (rc != 0) break;
} while (bench_stats_check(start, &count, maxDuration));
skipDec = (rc != 0 && bench_unsupported(rc));
rc = bench_asym_done("RSA", 2048, "Public", count, start, rc);
rc = bench_asym_done("RSA", rsaBits, "Public", count, start, rc);
if (rc != 0) goto exit;

if (skipDec) {
printf("%-6s %5d %-9s Skipped (not supported)\n", "RSA", 2048, "Private");
printf("%-6s %5d %-9s Skipped (not supported)\n", "RSA", rsaBits,
"Private");
}
else {
bench_stats_start(&count, &start);
Expand All @@ -649,7 +653,7 @@ int TPM2_Wrapper_BenchArgs(void* userCtx, int argc, char *argv[])
cipher.buffer, cipher.size, plain.buffer, &plain.size);
if (rc != 0) break;
} while (bench_stats_check(start, &count, maxDuration));
rc = bench_asym_done("RSA", 2048, "Private", count, start, rc);
rc = bench_asym_done("RSA", rsaBits, "Private", count, start, rc);
if (rc != 0) goto exit;
}

Expand All @@ -666,11 +670,11 @@ int TPM2_Wrapper_BenchArgs(void* userCtx, int argc, char *argv[])
if (rc != 0) break;
} while (bench_stats_check(start, &count, maxDuration));
skipDec = (rc != 0 && bench_unsupported(rc));
rc = bench_asym_done("RSA", 2048, "Pub OAEP", count, start, rc);
rc = bench_asym_done("RSA", rsaBits, "Pub OAEP", count, start, rc);
if (rc != 0) goto exit;

if (skipDec) {
printf("%-6s %5d %-9s Skipped (not supported)\n", "RSA", 2048,
printf("%-6s %5d %-9s Skipped (not supported)\n", "RSA", rsaBits,
"Priv OAEP");
}
else {
Expand All @@ -681,7 +685,7 @@ int TPM2_Wrapper_BenchArgs(void* userCtx, int argc, char *argv[])
cipher.buffer, cipher.size, plain.buffer, &plain.size);
if (rc != 0) break;
} while (bench_stats_check(start, &count, maxDuration));
rc = bench_asym_done("RSA", 2048, "Priv OAEP", count, start, rc);
rc = bench_asym_done("RSA", rsaBits, "Priv OAEP", count, start, rc);
if (rc != 0) goto exit;
}

Expand Down
17 changes: 12 additions & 5 deletions src/fwtpm/fwtpm_command.c
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,10 @@ static TPM_RC FwSpdmTpmKeyName(const byte* rawPub, word32 rawPubSz,
pkt.buf = buf;
pkt.size = (int)FWTPM_MAX_PUB_BUF;
TPM2_Packet_AppendPublicArea(&pkt, pub);
rc = FwNameFromPublicArea(buf, (word32)pkt.pos, name);
if (pkt.overflow)
rc = TPM_RC_FAILURE;
else
rc = FwNameFromPublicArea(buf, (word32)pkt.pos, name);
}
FWTPM_FREE_BUF(buf);
FWTPM_FREE_VAR(pub);
Expand Down Expand Up @@ -7288,12 +7291,13 @@ static TPM_RC FwCmd_Create(FWTPM_CTX* ctx, TPM2_Packet* cmd,
nameDigSz = TPM2_GetHashDigestSize(inPublic->publicArea.nameAlg);
FWTPM_ALLOC_BUF(pubBuf2, FWTPM_MAX_PUB_BUF);
if (rc == 0) {
XMEMSET(&tmpPkt2, 0, sizeof(tmpPkt2));
tmpPkt2.buf = pubBuf2;
tmpPkt2.pos = 0;
tmpPkt2.size = (int)FWTPM_MAX_PUB_BUF;
TPM2_Packet_AppendPublicArea(&tmpPkt2, &inPublic->publicArea);
FwStoreU16BE(objName, inPublic->publicArea.nameAlg);
if (nameDigSz > 0) {
if (nameDigSz > 0 && !tmpPkt2.overflow) {
int hashRc = wc_Hash(
FwGetWcHashType(inPublic->publicArea.nameAlg),
pubBuf2, tmpPkt2.pos, objName + 2, nameDigSz);
Expand Down Expand Up @@ -8147,15 +8151,18 @@ static TPM_RC FwCmd_Import(FWTPM_CTX* ctx, TPM2_Packet* cmd,
}
}
if (rc == 0) {
XMEMSET(&tmpPkt, 0, sizeof(tmpPkt));
tmpPkt.buf = pubAreaBuf;
tmpPkt.pos = 0;
tmpPkt.size = (int)FWTPM_MAX_PUB_BUF;
TPM2_Packet_AppendPublicArea(&tmpPkt, &objectPublic->publicArea);
pubAreaSz = tmpPkt.pos;
FwStoreU16BE(nameBuf, objNameAlg);
rc = wc_Hash(objWcHash, pubAreaBuf, pubAreaSz,
nameBuf + 2, objDigestSz);
if (rc != 0) {
if (tmpPkt.overflow) {
rc = TPM_RC_FAILURE;
}
else if (wc_Hash(objWcHash, pubAreaBuf, pubAreaSz,
nameBuf + 2, objDigestSz) != 0) {
rc = TPM_RC_FAILURE;
}
else {
Expand Down
8 changes: 7 additions & 1 deletion src/fwtpm/fwtpm_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ int FwComputePublicName(TPMT_PUBLIC* pub, TPM2B_NAME* name)

if (rc == 0) {
/* Marshal public area into temp buffer */
XMEMSET(&tmpPkt, 0, sizeof(tmpPkt));
tmpPkt.buf = pubBuf;
tmpPkt.pos = 0;
tmpPkt.size = (int)FWTPM_MAX_PUB_BUF;
Expand All @@ -210,7 +211,12 @@ int FwComputePublicName(TPMT_PUBLIC* pub, TPM2B_NAME* name)

wcHash = FwGetWcHashType(pub->nameAlg);
digestSz = TPM2_GetHashDigestSize(pub->nameAlg);
if (wcHash == WC_HASH_TYPE_NONE || digestSz == 0) {
if (tmpPkt.overflow) {
/* An append that does not fit is skipped, so a short buffer
* names a partial area: two keys could share one Name. */
rc = TPM_RC_FAILURE;
}
else if (wcHash == WC_HASH_TYPE_NONE || digestSz == 0) {
rc = TPM_RC_HASH;
}
}
Expand Down
113 changes: 113 additions & 0 deletions tests/fwtpm_unit_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -18852,6 +18852,115 @@ static void test_fwtpm_custom_io_hal(void)
}
#endif

#ifndef NO_RSA
/* The largest valid RSA public area this build can produce, with the
* modulus filled so two keys can be told apart by their bytes. */
static void fwtpm_rsa_max_pub(TPMT_PUBLIC* pub, byte fill)
{
UINT16 modSz = (UINT16)(MAX_RSA_KEY_BITS / 8);

XMEMSET(pub, 0, sizeof(*pub));
pub->type = TPM_ALG_RSA;
pub->nameAlg = TPM_ALG_SHA256;
pub->objectAttributes = TPMA_OBJECT_fixedTPM |
TPMA_OBJECT_fixedParent | TPMA_OBJECT_sensitiveDataOrigin |
TPMA_OBJECT_userWithAuth | TPMA_OBJECT_restricted |
TPMA_OBJECT_decrypt;
pub->parameters.rsaDetail.symmetric.algorithm = TPM_ALG_AES;
pub->parameters.rsaDetail.symmetric.keyBits.aes = 128;
pub->parameters.rsaDetail.symmetric.mode.aes = TPM_ALG_CFB;
pub->parameters.rsaDetail.scheme.scheme = TPM_ALG_NULL;
pub->parameters.rsaDetail.keyBits = MAX_RSA_KEY_BITS;
pub->parameters.rsaDetail.exponent = 0x10001;
pub->unique.rsa.size = modSz;
XMEMSET(pub->unique.rsa.buffer, fill, modSz);
}

/* A public area too large for the buffer, which stays in bounds because
* MAX_RSA_KEY_BYTES is twice the modulus width. */
static void fwtpm_rsa_oversize_pub(TPMT_PUBLIC* pub, byte fill)
{
fwtpm_rsa_max_pub(pub, fill);
pub->unique.rsa.size = (UINT16)MAX_RSA_KEY_BYTES;
XMEMSET(pub->unique.rsa.buffer, fill, MAX_RSA_KEY_BYTES);
}

/* An oversized area must be refused, not named from the part that fit. */
static void test_fwtpm_public_name_rsa_overflow(void)
{
TPMT_PUBLIC pub;
TPM2B_NAME name;
TPM2_Packet pkt;
byte bufA[FWTPM_MAX_PUB_BUF];
byte bufB[FWTPM_MAX_PUB_BUF];
int posA;

fwtpm_rsa_oversize_pub(&pub, 0xAA);
XMEMSET(&pkt, 0, sizeof(pkt));
pkt.buf = bufA;
pkt.size = (int)sizeof(bufA);
TPM2_Packet_AppendPublicArea(&pkt, &pub);
if (!pkt.overflow) {
/* A PQC build sizes this buffer for ML-DSA, so no RSA public area
* the build can represent is large enough to overflow it. */
printf("Test fwTPM: %-6s %-42s Skipped\n", "",
"Public name refuses an oversized area:");
return;
}
posA = pkt.pos;

/* The modulus does not fit, and an append that does not fit is skipped
* whole, so a second key differing only there marshals identically. */
fwtpm_rsa_oversize_pub(&pub, 0xBB);
XMEMSET(&pkt, 0, sizeof(pkt));
pkt.buf = bufB;
pkt.size = (int)sizeof(bufB);
TPM2_Packet_AppendPublicArea(&pkt, &pub);
AssertIntEQ(pkt.pos, posA);
AssertIntEQ(XMEMCMP(bufA, bufB, (size_t)posA), 0);

/* Which is why naming it has to fail: those two keys would otherwise
* share one Name, and a Name is what binds authorization. */
XMEMSET(&name, 0, sizeof(name));
AssertIntEQ(FwComputePublicName(&pub, &name), TPM_RC_FAILURE);
AssertIntEQ(name.size, 0);

fwtpm_pass("Public name refuses an oversized area:", 0);
}

static void test_fwtpm_public_name_rsa_max(void)
Comment thread
dgarske marked this conversation as resolved.
{
TPMT_PUBLIC pub;
TPM2B_NAME nameA;
TPM2B_NAME nameB;
TPM2_Packet pkt;
byte buf[FWTPM_MAX_PUB_BUF];
UINT16 modSz = (UINT16)(MAX_RSA_KEY_BITS / 8);

XMEMSET(&nameA, 0, sizeof(nameA));
XMEMSET(&nameB, 0, sizeof(nameB));
fwtpm_rsa_max_pub(&pub, 0xAA);

/* A field that does not fit is skipped rather than truncated, so the
* buffer has to hold the largest public area whole. */
XMEMSET(&pkt, 0, sizeof(pkt));
pkt.buf = buf;
pkt.size = (int)sizeof(buf);
TPM2_Packet_AppendPublicArea(&pkt, &pub);
AssertIntEQ(pkt.overflow, 0);

/* The modulus is all that tells these two apart: a skipped one gives
* them the same Name, and Names bind authorization. */
AssertIntEQ(FwComputePublicName(&pub, &nameA), TPM_RC_SUCCESS);
XMEMSET(pub.unique.rsa.buffer, 0xBB, modSz);
AssertIntEQ(FwComputePublicName(&pub, &nameB), TPM_RC_SUCCESS);
AssertIntEQ(nameA.size, nameB.size);
AssertIntNE(XMEMCMP(nameA.name, nameB.name, nameA.size), 0);

fwtpm_pass("Public name at max RSA size:", 0);
}
#endif /* !NO_RSA */

/* ================================================================== */
/* main */
/* ================================================================== */
Expand Down Expand Up @@ -19377,6 +19486,10 @@ int fwtpm_unit_tests(int argc, char *argv[])
#endif

/* Hierarchy & misc */
#ifndef NO_RSA
test_fwtpm_public_name_rsa_max();
test_fwtpm_public_name_rsa_overflow();
#endif
test_fwtpm_test_parms();
test_fwtpm_incremental_selftest();
test_fwtpm_incremental_selftest_truncated_returns_cmd_size();
Expand Down
4 changes: 4 additions & 0 deletions wolftpm/fwtpm/fwtpm.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,10 @@
#endif
#if FWTPM_MAX_PUB_BUF_RAW > 384
#define FWTPM_MAX_PUB_BUF (FWTPM_MAX_PUB_BUF_RAW + 128)
/* An RSA public area reaches 604 bytes at RSA 4096. The chip macros
* raise MAX_RSA_KEY_BITS whether or not RSA is built. */
#elif !defined(NO_RSA) && ((MAX_RSA_KEY_BITS / 8) + 128) > 512
#define FWTPM_MAX_PUB_BUF ((MAX_RSA_KEY_BITS / 8) + 128)
#else
#define FWTPM_MAX_PUB_BUF 512 /* classical RSA/ECC default */
#endif
Expand Down
7 changes: 6 additions & 1 deletion wolftpm/fwtpm/fwtpm_nv.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@
#endif

/* PUBAREA_EST: largest enabled PQC pub key + 128 B TPMT_PUBLIC header
* slack, or 600 classical floor — whichever is bigger. */
* slack, or the 600 classical floor, or RSA's own 604 at 4096 bits. The
* chip macros raise MAX_RSA_KEY_BITS whether or not RSA is built. */
#ifdef WOLFTPM_V185
#if FWTPM_MAX_MLDSA_PUB_SIZE >= FWTPM_MAX_MLKEM_PUB_SIZE
#define FWTPM_NV_PUBAREA_UNIQUE FWTPM_MAX_MLDSA_PUB_SIZE
Expand All @@ -59,9 +60,13 @@
#endif
#if FWTPM_NV_PUBAREA_UNIQUE > 472 /* 600 - 128 = classical floor */
#define FWTPM_NV_PUBAREA_EST (FWTPM_NV_PUBAREA_UNIQUE + 128)
#elif !defined(NO_RSA) && ((MAX_RSA_KEY_BITS / 8) + 128) > 600
#define FWTPM_NV_PUBAREA_EST ((MAX_RSA_KEY_BITS / 8) + 128)
#else
#define FWTPM_NV_PUBAREA_EST 600
#endif
#elif !defined(NO_RSA) && ((MAX_RSA_KEY_BITS / 8) + 128) > 600
#define FWTPM_NV_PUBAREA_EST ((MAX_RSA_KEY_BITS / 8) + 128)
#else
#define FWTPM_NV_PUBAREA_EST 600
#endif
Expand Down
4 changes: 3 additions & 1 deletion wolftpm/tpm2_param_enc.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
* exceed MAX_DIGEST_BUFFER (1024), and an fwTPM outPrivate carries a 32-byte
* integrity value plus a 16-byte IV on top of the sensitive area. */
#ifndef TPM2_XOR_MASK_MAX
#define TPM2_XOR_MASK_MAX 1536
/* The sensitive area, and so that blob, scales with the RSA key size. */
#define TPM2_XOR_MASK_MAX \
((UINT32)(sizeof(TPM2B_PRIVATE) > 1536 ? sizeof(TPM2B_PRIVATE) : 1536))
#endif

/* XOR parameter encryption/decryption (raw pointer interface).
Expand Down
Loading