Skip to content
13 changes: 13 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ The PKCS #7 and TLS examples require generating CSR's and signing them using a t

To enable parameter encryption use `-aes` for AES-CFB mode or `-xor` for XOR mode. Only some TPM commands / responses support parameter encryption. If the TPM2_ API has .flags `CMD_FLAG_ENC2` or `CMD_FLAG_DEC2` set then the command will use parameter encryption / decryption.

On a v1.85 PQC capable TPM the parameter encryption session can also be keyed with a post-quantum primary: pass `-mlkem` to salt the session with an ML-KEM key or `-mldsa` to bind it to an ML-DSA key (`keygen` uses `-paramkey=mlkem|mldsa` since `-mlkem`/`-mldsa` there select the child key). See "Parameter Encryption" below.

There are some vendor specific examples, like the TPM 2.0 extra GPIO examples for ST33 and NPCT75x.

## Native API Test
Expand Down Expand Up @@ -80,6 +82,17 @@ This behavior depends on the `sessionAttributes`:

Either one can be set separately or both can be set in one authorization session. This is up to the user (developer).

### Post-quantum session keys (v1.85)

The parameter encryption session can be keyed with a post-quantum primary instead of an RSA/ECC storage key. ML-KEM is decrypt capable and is used as the session salt key; ML-DSA is sign only and is used as the session bind key. The RSA/ECC storage key (where one is needed, such as the parent of a created child) is unchanged. `wrap_test`, `pcr/quote`, and `nvram/store` and `nvram/counter` accept `-mlkem[=512|768|1024]` and `-mldsa[=44|65|87]`; `keygen` uses `-paramkey=mlkem[=...]` / `-paramkey=mldsa[=...]` because `-mlkem`/`-mldsa` there select the child key. This requires a v1.85 PQC capable TPM.

```sh
./examples/wrap/wrap_test -aes -mlkem=768
./examples/pcr/quote 16 quote.blob -ecc -xor -mldsa=65
./examples/nvram/counter -aes -mldsa=65
./examples/keygen/keygen keyblob.bin -ecc -aes -paramkey=mlkem=768
```

## CSR

Generates a Certificate Signing Request for building a certificate based on a TPM key pair.
Expand Down
49 changes: 49 additions & 0 deletions examples/keygen/create_primary.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ static void usage(void)
printf("Primary Key Type:\n");
printf("\t-rsa: Use RSA for asymmetric key generation (DEFAULT)\n");
printf("\t-ecc: Use ECC for asymmetric key generation \n");
#ifdef WOLFTPM_PQC
printf("\t-mldsa[=44|65|87]: Use ML-DSA for primary key generation "
"(v1.85, default 65)\n");
#endif
printf("Hierarchy:\n");
printf("\t-oh: Create keys under the Owner Hierarchy (DEFAULT)\n");
printf("\t-eh: Create keys under the Endorsement Hierarchy\n");
Expand Down Expand Up @@ -77,7 +81,25 @@ static void usage(void)
printf("\t* Create SRK used by wolfTPM:\n");
printf("\t\tcreate_primary -rsa -oh -auth=ThisIsMyStorageKeyAuth "
"-store=0x81000200\n");
#ifdef WOLFTPM_PQC
printf("\t* Create an ML-DSA-65 primary key:\n");
printf("\t\tcreate_primary -mldsa -oh\n");
#endif
}

#ifdef WOLFTPM_PQC
static int mldsaParamSet(const char* optVal, TPMI_MLDSA_PARAMETER_SET* ps)
{
int n = XATOI(optVal);
switch (n) {
case 0: /* missing or empty suffix, use default */
case 65: *ps = TPM_MLDSA_65; return TPM_RC_SUCCESS;
case 44: *ps = TPM_MLDSA_44; return TPM_RC_SUCCESS;
case 87: *ps = TPM_MLDSA_87; return TPM_RC_SUCCESS;
default: return TPM_RC_FAILURE;
}
}
#endif /* WOLFTPM_PQC */

int TPM2_CreatePrimaryKey_Example(void* userCtx, int argc, char *argv[])
{
Expand All @@ -98,6 +120,9 @@ int TPM2_CreatePrimaryKey_Example(void* userCtx, int argc, char *argv[])
#ifdef WOLFTPM_PROVISIONING
int useIAKTemplate = 0, useIDevIDTemplate = 0;
#endif
#ifdef WOLFTPM_PQC
TPMI_MLDSA_PARAMETER_SET mldsaPs = TPM_MLDSA_65; /* default param set */
#endif

if (argc >= 2) {
if (XSTRCMP(argv[1], "-?") == 0 ||
Expand All @@ -114,6 +139,19 @@ int TPM2_CreatePrimaryKey_Example(void* userCtx, int argc, char *argv[])
else if (XSTRCMP(argv[argc-1], "-ecc") == 0) {
alg = TPM_ALG_ECC;
}
#ifdef WOLFTPM_PQC
else if (XSTRCMP(argv[argc-1], "-mldsa") == 0 ||
XSTRNCMP(argv[argc-1], "-mldsa=",
XSTRLEN("-mldsa=")) == 0) {
const char* optVal = (argv[argc-1][6] == '=') ?
argv[argc-1] + 7 : "";
if (mldsaParamSet(optVal, &mldsaPs) != TPM_RC_SUCCESS) {
usage();
return 0;
}
alg = TPM_ALG_MLDSA;
}
#endif
else if (XSTRCMP(argv[argc-1], "-aes") == 0) {
paramEncAlg = TPM_ALG_CFB;
}
Expand Down Expand Up @@ -221,6 +259,17 @@ int TPM2_CreatePrimaryKey_Example(void* userCtx, int argc, char *argv[])
else
rc = wolfTPM2_GetKeyTemplate_ECC_SRK(&publicTemplate);
}
#ifdef WOLFTPM_PQC
else if (alg == TPM_ALG_MLDSA) {
/* ML-DSA is sign-only and has no AIK/IAK/IDevID variant; the
* wrapper enforces TPMA_OBJECT_sign and clears decrypt. */
rc = wolfTPM2_GetKeyTemplate_MLDSA(&publicTemplate,
TPMA_OBJECT_sign | TPMA_OBJECT_fixedTPM |
TPMA_OBJECT_fixedParent | TPMA_OBJECT_sensitiveDataOrigin |
TPMA_OBJECT_userWithAuth | TPMA_OBJECT_noDA,
mldsaPs, 0 /* allowExternalMu: 0 avoids TPM_RC_EXT_MU */);
}
#endif
else {
rc = BAD_FUNC_ARG;
}
Expand Down
53 changes: 48 additions & 5 deletions examples/keygen/keygen.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ static void usage(void)
#endif
printf("* -t: Use default template (otherwise AIK)\n");
printf("* -aes/xor: Use Parameter Encryption\n");
#if defined(WOLFTPM_MLKEM) || defined(WOLFTPM_MLDSA)
printf("* -paramkey=mlkem[=512|768|1024]: Use an ML-KEM key as the "
"param-enc session salt (v1.85, default 768)\n");
printf("* -paramkey=mldsa[=44|65|87]: Use an ML-DSA key as the "
"param-enc session bind (v1.85, default 65)\n");
#endif
printf("* -unique=[value]\n");
printf("\t* Used for the KDF of the create\n");
printf("* -auth=pass: Use custom password for key authentication\n");
Expand Down Expand Up @@ -176,6 +182,11 @@ int TPM2_Keygen_Example(void* userCtx, int argc, char *argv[])
TPMI_ALG_PUBLIC srkAlg = TPM_ALG_RSA; /* default matches seal.c / keyload.c */
TPM_ALG_ID algSym = TPM_ALG_CTR; /* default Symmetric Cipher, see usage */
TPM_ALG_ID paramEncAlg = TPM_ALG_NULL;
#if defined(WOLFTPM_MLKEM) || defined(WOLFTPM_MLDSA)
TPM_ALG_ID pqcParamEncAlg = TPM_ALG_NULL;
int pqcParamSet = 0;
WOLFTPM2_KEY pqcKey;
#endif
#ifdef WOLFTPM_PQC
TPMI_MLDSA_PARAMETER_SET mldsaPs = TPM_MLDSA_65; /* default */
TPMI_MLKEM_PARAMETER_SET mlkemPs = TPM_MLKEM_768; /* default */
Expand Down Expand Up @@ -281,6 +292,21 @@ int TPM2_Keygen_Example(void* userCtx, int argc, char *argv[])
else if (XSTRCMP(argv[argc-1], "-xor") == 0) {
paramEncAlg = TPM_ALG_XOR;
}
#if defined(WOLFTPM_MLKEM) || defined(WOLFTPM_MLDSA)
else if (XSTRNCMP(argv[argc-1], "-paramkey=",
XSTRLEN("-paramkey=")) == 0) {
/* Choose a PQC key for the param-enc session (separate from the
* child key -mlkem/-mldsa selection above). Value is e.g.
* "mlkem", "mlkem=768", "mldsa" or "mldsa=65". Reuses the shared
* value-form parser so validation stays consistent. */
const char* pkVal = argv[argc-1] + XSTRLEN("-paramkey=");
if (!parsePqcParamSet(pkVal, &pqcParamEncAlg, &pqcParamSet)) {
printf("Invalid -paramkey value: %s\n", pkVal);
usage();
return 0;
}
}
Comment on lines +296 to +308
#endif
else if (XSTRNCMP(argv[argc-1], "-unique=", XSTRLEN("-unique=")) == 0) {
uniqueStr = argv[argc-1] + XSTRLEN("-unique=");
}
Expand Down Expand Up @@ -310,6 +336,9 @@ int TPM2_Keygen_Example(void* userCtx, int argc, char *argv[])
XMEMSET(&primaryBlob, 0, sizeof(primaryBlob));
XMEMSET(&tpmSession, 0, sizeof(tpmSession));
XMEMSET(&auth, 0, sizeof(auth));
#if defined(WOLFTPM_MLKEM) || defined(WOLFTPM_MLDSA)
XMEMSET(&pqcKey, 0, sizeof(pqcKey));
#endif

/* Only use the ECC SRK for ECC child keys; RSA, SYMCIPHER, KEYEDHASH
* all stay on the RSA SRK so that keyload/seal can round-trip them. */
Expand Down Expand Up @@ -364,9 +393,20 @@ int TPM2_Keygen_Example(void* userCtx, int argc, char *argv[])
if (srkAlg == TPM_ALG_RSA)
bindKey = NULL; /* cannot bind to key without RSA enabled */
#endif
/* Start an authenticated session (salted / unbound) with parameter encryption */
rc = wolfTPM2_StartSession(&dev, &tpmSession, bindKey, NULL,
TPM_SE_HMAC, paramEncAlg);
#if defined(WOLFTPM_MLKEM) || defined(WOLFTPM_MLDSA)
if (pqcParamEncAlg != TPM_ALG_NULL) {
/* Use a PQC primary as the param-enc session key: ML-KEM salt
* or ML-DSA bind. This replaces the salted-to-SRK session. */
rc = getPrimaryParamEncKey(&dev, &tpmSession, &pqcKey,
pqcParamEncAlg, pqcParamSet, paramEncAlg);
}
else
#endif
{
/* Start an authenticated session (salted / unbound) with parameter encryption */
rc = wolfTPM2_StartSession(&dev, &tpmSession, bindKey, NULL,
TPM_SE_HMAC, paramEncAlg);
}
if (rc != 0) goto exit;
printf("HMAC Session: Handle 0x%x\n",
(word32)tpmSession.handle.hndl);
Expand Down Expand Up @@ -462,9 +502,9 @@ int TPM2_Keygen_Example(void* userCtx, int argc, char *argv[])
TPMA_OBJECT_sign | TPMA_OBJECT_fixedTPM |
TPMA_OBJECT_fixedParent | TPMA_OBJECT_sensitiveDataOrigin |
TPMA_OBJECT_userWithAuth | TPMA_OBJECT_noDA,
mldsaPs, 0 /* allowExternalMu TPM_RC_EXT_MU at create
mldsaPs, 0 /* allowExternalMu - TPM_RC_EXT_MU at create
* per Part 2 Sec.12.2.3.6 when SET on a TPM
* without μ-direct sign support */);
* without mu-direct sign support */);
}
else if (alg == TPM_ALG_HASH_MLDSA) {
printf("Hash-ML-DSA template (parameter set %u, pre-hash %s)\n",
Expand Down Expand Up @@ -613,6 +653,9 @@ int TPM2_Keygen_Example(void* userCtx, int argc, char *argv[])
wolfTPM2_UnloadHandle(&dev, &primary->handle);
wolfTPM2_UnloadHandle(&dev, &newKeyBlob.handle);
wolfTPM2_UnloadHandle(&dev, &tpmSession.handle);
#if defined(WOLFTPM_MLKEM) || defined(WOLFTPM_MLDSA)
wolfTPM2_UnloadHandle(&dev, &pqcKey.handle);
#endif

wolfTPM2_Cleanup(&dev);
return rc;
Expand Down
40 changes: 37 additions & 3 deletions examples/nvram/counter.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ static void usage(void)
printf("./examples/nvram/counter [-nvindex=] [-aes/-xor]\n");
printf("* -nvindex=[handle] (default 0x%x)\n", TPM2_DEMO_NV_COUNTER_INDEX);
printf("* -aes/xor: Use Parameter Encryption\n");
#if defined(WOLFTPM_MLKEM) || defined(WOLFTPM_MLDSA)
printf("* -mlkem[=512|768|1024]: Use an ML-KEM key as the param-enc "
"session salt (v1.85, default 768)\n");
printf("* -mldsa[=44|65|87]: Use an ML-DSA key as the param-enc "
"session bind (v1.85, default 65)\n");
#endif
}

int TPM2_NVRAM_Counter_Example(void* userCtx, int argc, char *argv[])
Expand All @@ -63,12 +69,20 @@ int TPM2_NVRAM_Counter_Example(void* userCtx, int argc, char *argv[])
TPMS_NV_PUBLIC nvPublic;
TPMI_RH_NV_AUTH authHandle = TPM_RH_OWNER; /* or TPM_RH_PLATFORM */
int paramEncAlg = TPM_ALG_NULL;
#if defined(WOLFTPM_MLKEM) || defined(WOLFTPM_MLDSA)
TPM_ALG_ID pqcParamEncAlg = TPM_ALG_NULL;
int pqcParamSet = 0;
WOLFTPM2_KEY pqcKey;
#endif
word32 nvIndex = TPM2_DEMO_NV_COUNTER_INDEX;

XMEMSET(&tpmSession, 0, sizeof(tpmSession));
XMEMSET(&parent, 0, sizeof(parent));
XMEMSET(&nv, 0, sizeof(nv));
XMEMSET(&storage, 0, sizeof(storage));
#if defined(WOLFTPM_MLKEM) || defined(WOLFTPM_MLDSA)
XMEMSET(&pqcKey, 0, sizeof(pqcKey));
#endif

if (argc >= 2) {
if (XSTRCMP(argv[1], "-?") == 0 ||
Expand Down Expand Up @@ -104,6 +118,12 @@ int TPM2_NVRAM_Counter_Example(void* userCtx, int argc, char *argv[])
else if (XSTRCMP(argv[argc-1], "-xor") == 0) {
paramEncAlg = TPM_ALG_XOR;
}
#if defined(WOLFTPM_MLKEM) || defined(WOLFTPM_MLDSA)
else if (parsePqcParamEncArg(argv[argc-1], &pqcParamEncAlg,
&pqcParamSet)) {
/* PQC parameter-encryption session key selected */
}
#endif
else {
printf("Warning: Unrecognized option: %s\n", argv[argc-1]);
}
Expand All @@ -130,9 +150,20 @@ int TPM2_NVRAM_Counter_Example(void* userCtx, int argc, char *argv[])
}

if (paramEncAlg != TPM_ALG_NULL) {
/* Start TPM session for parameter encryption */
rc = wolfTPM2_StartSession(&dev, &tpmSession, NULL, NULL,
TPM_SE_HMAC, paramEncAlg);
#if defined(WOLFTPM_MLKEM) || defined(WOLFTPM_MLDSA)
if (pqcParamEncAlg != TPM_ALG_NULL) {
/* Use a PQC primary as the param-enc session key: ML-KEM salt
* or ML-DSA bind. */
rc = getPrimaryParamEncKey(&dev, &tpmSession, &pqcKey,
pqcParamEncAlg, pqcParamSet, paramEncAlg);
}
else
#endif
{
/* Start TPM session for parameter encryption */
rc = wolfTPM2_StartSession(&dev, &tpmSession, NULL, NULL,
TPM_SE_HMAC, paramEncAlg);
}
if (rc != 0) goto exit;
printf("TPM2_StartAuthSession: sessionHandle 0x%x\n",
(word32)tpmSession.handle.hndl);
Expand Down Expand Up @@ -191,6 +222,9 @@ int TPM2_NVRAM_Counter_Example(void* userCtx, int argc, char *argv[])
}

wolfTPM2_UnloadHandle(&dev, &tpmSession.handle);
#if defined(WOLFTPM_MLKEM) || defined(WOLFTPM_MLDSA)
wolfTPM2_UnloadHandle(&dev, &pqcKey.handle);
#endif
wolfTPM2_Cleanup(&dev);

return rc;
Expand Down
40 changes: 37 additions & 3 deletions examples/nvram/store.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ static void usage(void)
printf("* -priv: Store only the private part of the key\n");
printf("* -pub: Store only the public part of the key\n");
printf("* -aes/xor: Use Parameter Encryption\n");
#if defined(WOLFTPM_MLKEM) || defined(WOLFTPM_MLDSA)
printf("* -mlkem[=512|768|1024]: Use an ML-KEM key as the param-enc "
"session salt (v1.85, default 768)\n");
printf("* -mldsa[=44|65|87]: Use an ML-DSA key as the param-enc "
"session bind (v1.85, default 65)\n");
#endif
}

int TPM2_NVRAM_Store_Example(void* userCtx, int argc, char *argv[])
Expand All @@ -71,6 +77,11 @@ int TPM2_NVRAM_Store_Example(void* userCtx, int argc, char *argv[])
TPMI_RH_NV_AUTH authHandle = TPM_RH_OWNER; /* or TPM_RH_PLATFORM */
const char* filename = "keyblob.bin";
int paramEncAlg = TPM_ALG_NULL;
#if defined(WOLFTPM_MLKEM) || defined(WOLFTPM_MLDSA)
TPM_ALG_ID pqcParamEncAlg = TPM_ALG_NULL;
int pqcParamSet = 0;
WOLFTPM2_KEY pqcKey;
#endif
int partialStore = 0;
int offset = 0;
/* Needed for TPM2_AppendPublic */
Expand Down Expand Up @@ -121,6 +132,12 @@ int TPM2_NVRAM_Store_Example(void* userCtx, int argc, char *argv[])
else if (XSTRCMP(argv[argc-1], "-pub") == 0) {
partialStore = PUBLIC_PART_ONLY;
}
#if defined(WOLFTPM_MLKEM) || defined(WOLFTPM_MLDSA)
else if (parsePqcParamEncArg(argv[argc-1], &pqcParamEncAlg,
&pqcParamSet)) {
/* PQC parameter-encryption session key selected */
}
#endif
else if (argv[argc-1][0] != '-') {
filename = argv[argc-1];
}
Expand All @@ -144,6 +161,9 @@ int TPM2_NVRAM_Store_Example(void* userCtx, int argc, char *argv[])
XMEMSET(&keyBlob, 0, sizeof(keyBlob));
XMEMSET(&tpmSession, 0, sizeof(tpmSession));
XMEMSET(&parent, 0, sizeof(parent));
#if defined(WOLFTPM_MLKEM) || defined(WOLFTPM_MLDSA)
XMEMSET(&pqcKey, 0, sizeof(pqcKey));
#endif

rc = wolfTPM2_Init(&dev, TPM2_IoCb, userCtx);
if (rc != TPM_RC_SUCCESS) {
Expand All @@ -152,9 +172,20 @@ int TPM2_NVRAM_Store_Example(void* userCtx, int argc, char *argv[])
}

if (paramEncAlg != TPM_ALG_NULL) {
/* Start TPM session for parameter encryption */
rc = wolfTPM2_StartSession(&dev, &tpmSession, NULL, NULL,
TPM_SE_HMAC, paramEncAlg);
#if defined(WOLFTPM_MLKEM) || defined(WOLFTPM_MLDSA)
if (pqcParamEncAlg != TPM_ALG_NULL) {
/* Use a PQC primary as the param-enc session key: ML-KEM salt
* or ML-DSA bind. */
rc = getPrimaryParamEncKey(&dev, &tpmSession, &pqcKey,
pqcParamEncAlg, pqcParamSet, paramEncAlg);
}
else
#endif
{
/* Start TPM session for parameter encryption */
rc = wolfTPM2_StartSession(&dev, &tpmSession, NULL, NULL,
TPM_SE_HMAC, paramEncAlg);
}
if (rc != 0) goto exit;
printf("TPM2_StartAuthSession: sessionHandle 0x%x\n",
(word32)tpmSession.handle.hndl);
Expand Down Expand Up @@ -246,6 +277,9 @@ int TPM2_NVRAM_Store_Example(void* userCtx, int argc, char *argv[])
}

wolfTPM2_UnloadHandle(&dev, &tpmSession.handle);
#if defined(WOLFTPM_MLKEM) || defined(WOLFTPM_MLDSA)
wolfTPM2_UnloadHandle(&dev, &pqcKey.handle);
#endif
wolfTPM2_Cleanup(&dev);

return rc;
Expand Down
Loading
Loading