|
| 1 | +/* extend.c |
| 2 | + * |
| 3 | + * Copyright (C) 2006-2024 wolfSSL Inc. |
| 4 | + * |
| 5 | + * This file is part of wolfTPM. |
| 6 | + * |
| 7 | + * wolfTPM is free software; you can redistribute it and/or modify |
| 8 | + * it under the terms of the GNU General Public License as published by |
| 9 | + * the Free Software Foundation; either version 2 of the License, or |
| 10 | + * (at your option) any later version. |
| 11 | + * |
| 12 | + * wolfTPM is distributed in the hope that it will be useful, |
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 | + * GNU General Public License for more details. |
| 16 | + * |
| 17 | + * You should have received a copy of the GNU General Public License |
| 18 | + * along with this program; if not, write to the Free Software |
| 19 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA |
| 20 | + */ |
| 21 | + |
| 22 | +/* Example for showing NV extend usage for bus protection: |
| 23 | +* See "TCG_-CPU_-TPM_Bus_Protection_Guidance_Active_Attack_Mitigations-V1-R30_PUB-1.pdf" */ |
| 24 | + |
| 25 | +#ifdef HAVE_CONFIG_H |
| 26 | + #include <config.h> |
| 27 | +#endif |
| 28 | + |
| 29 | +#include <wolftpm/tpm2_wrap.h> |
| 30 | +#include <wolftpm/tpm2_packet.h> |
| 31 | +#include <stdio.h> |
| 32 | + |
| 33 | +#if !defined(WOLFTPM2_NO_WRAPPER) && !defined(WOLFTPM2_NO_WOLFCRYPT) |
| 34 | + |
| 35 | +#include <examples/nvram/nvram.h> |
| 36 | +#include <hal/tpm_io.h> |
| 37 | +#include <examples/tpm_test.h> |
| 38 | +#include <examples/tpm_test_keys.h> |
| 39 | + |
| 40 | + |
| 41 | +/******************************************************************************/ |
| 42 | +/* --- BEGIN TPM NVRAM Extend Example -- */ |
| 43 | +/******************************************************************************/ |
| 44 | +static void usage(void) |
| 45 | +{ |
| 46 | + printf("Expected usage:\n"); |
| 47 | + printf("./examples/nvram/extend [-nvindex=handle] [-aes/-xor]\n"); |
| 48 | + printf("* -nvindex=[handle] (default 0x%x)\n", |
| 49 | + TPM2_DEMO_NVRAM_EXTEND_INDEX); |
| 50 | + printf("* -aes/xor: Use Parameter Encryption\n");; |
| 51 | +} |
| 52 | + |
| 53 | +static int BuildPolicyCommandCode(TPMI_ALG_HASH hashAlg, |
| 54 | + byte* digest, word32* digestSz, TPM_CC cc) |
| 55 | +{ |
| 56 | + word32 val = cpu_to_be32(cc); |
| 57 | + return wolfTPM2_PolicyHash(hashAlg, digest, digestSz, |
| 58 | + TPM_CC_PolicyCommandCode, (byte*)&val, sizeof(val)); |
| 59 | +} |
| 60 | + |
| 61 | +static int PolicyOrApply(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* policySession, |
| 62 | + byte** hashList, word32 hashListSz, word32 digestSz) |
| 63 | +{ |
| 64 | + word32 i; |
| 65 | + PolicyOR_In policyOR; |
| 66 | + XMEMSET(&policyOR, 0, sizeof(policyOR)); |
| 67 | + policyOR.policySession = policySession->handle.hndl; |
| 68 | + policyOR.pHashList.count = hashListSz; |
| 69 | + for (i=0; i<hashListSz; i++) { |
| 70 | + policyOR.pHashList.digests[i].size = digestSz; |
| 71 | + XMEMCPY(policyOR.pHashList.digests[i].buffer, hashList[i], digestSz); |
| 72 | + } |
| 73 | + (void)dev; |
| 74 | + return TPM2_PolicyOR(&policyOR); |
| 75 | +} |
| 76 | + |
| 77 | +int TPM2_NVRAM_Extend_Example(void* userCtx, int argc, char *argv[]) |
| 78 | +{ |
| 79 | + int rc; |
| 80 | + WOLFTPM2_DEV dev; |
| 81 | + WOLFTPM2_KEY endorse; |
| 82 | + WOLFTPM2_SESSION tpmSession; |
| 83 | + WOLFTPM2_HANDLE nvAuth; |
| 84 | + WOLFTPM2_HANDLE bind; |
| 85 | + WOLFTPM2_NV nv; |
| 86 | + word32 nvAttributes; |
| 87 | + int paramEncAlg = TPM_ALG_CFB; |
| 88 | + TPMI_RH_NV_AUTH authHandle = TPM_RH_PLATFORM; |
| 89 | + word32 nvIndex = TPM2_DEMO_NVRAM_EXTEND_INDEX; |
| 90 | + byte* auth = (byte*)"cpusecret"; |
| 91 | + word32 authSz = (word32)XSTRLEN((const char*)auth); |
| 92 | + TPMI_ALG_HASH hashAlg = WOLFTPM2_WRAP_DIGEST; |
| 93 | + word32 nvSize = TPM2_GetHashDigestSize(hashAlg); |
| 94 | + byte nvDigest[TPM_MAX_DIGEST_SIZE]; /* buffer for nv read */ |
| 95 | + byte policyDigest[3*TPM_MAX_DIGEST_SIZE]; /* Policy A/B/C */ |
| 96 | + word32 policyDigestSz = 0; |
| 97 | + byte* policy[3]; /* pointers to policy A/B/C */ |
| 98 | + byte policyOr[TPM_MAX_DIGEST_SIZE]; |
| 99 | + |
| 100 | + if (argc >= 2) { |
| 101 | + if (XSTRCMP(argv[1], "-?") == 0 || |
| 102 | + XSTRCMP(argv[1], "-h") == 0 || |
| 103 | + XSTRCMP(argv[1], "--help") == 0) { |
| 104 | + usage(); |
| 105 | + return 0; |
| 106 | + } |
| 107 | + } |
| 108 | + while (argc > 1) { |
| 109 | + if (XSTRNCMP(argv[argc-1], "-nvindex=", XSTRLEN("-nvindex=")) == 0) { |
| 110 | + const char* nvIndexStr = argv[argc-1] + XSTRLEN("-nvindex="); |
| 111 | + nvIndex = (word32)XSTRTOUL(nvIndexStr, NULL, 0); |
| 112 | + if (nvIndex >= TPM_20_PLATFORM_MFG_NV_SPACE && |
| 113 | + nvIndex < TPM_20_OWNER_NV_SPACE) { |
| 114 | + authHandle = TPM_RH_PLATFORM; |
| 115 | + } |
| 116 | + else if (nvIndex >= TPM_20_OWNER_NV_SPACE && |
| 117 | + nvIndex < TPM_20_TCG_NV_SPACE) { |
| 118 | + authHandle = TPM_RH_OWNER; |
| 119 | + } |
| 120 | + else { |
| 121 | + fprintf(stderr, "Invalid NV Index %s\n", nvIndexStr); |
| 122 | + fprintf(stderr, "\tPlatform Range: 0x%x -> 0x%x\n", |
| 123 | + TPM_20_PLATFORM_MFG_NV_SPACE, TPM_20_OWNER_NV_SPACE); |
| 124 | + fprintf(stderr, "\tOwner Range: 0x%x -> 0x%x\n", |
| 125 | + TPM_20_OWNER_NV_SPACE, TPM_20_TCG_NV_SPACE); |
| 126 | + usage(); |
| 127 | + return -1; |
| 128 | + } |
| 129 | + } |
| 130 | + else if (XSTRCMP(argv[argc-1], "-aes") == 0) { |
| 131 | + paramEncAlg = TPM_ALG_CFB; |
| 132 | + } |
| 133 | + else if (XSTRCMP(argv[argc-1], "-xor") == 0) { |
| 134 | + paramEncAlg = TPM_ALG_XOR; |
| 135 | + } |
| 136 | + else { |
| 137 | + printf("Warning: Unrecognized option: %s\n", argv[argc-1]); |
| 138 | + } |
| 139 | + argc--; |
| 140 | + }; |
| 141 | + |
| 142 | + printf("NVRAM Extend (bus protection example)\n"); |
| 143 | + printf("Parameter Encryption: %s\n", |
| 144 | + (paramEncAlg == TPM_ALG_CFB) ? "AES CFB" : "XOR"); |
| 145 | + |
| 146 | + XMEMSET(&tpmSession, 0, sizeof(tpmSession)); |
| 147 | + XMEMSET(&endorse, 0, sizeof(endorse)); |
| 148 | + XMEMSET(&bind, 0, sizeof(bind)); |
| 149 | + XMEMSET(&nv, 0, sizeof(nv)); |
| 150 | + XMEMSET(&nvAuth, 0, sizeof(nvAuth)); |
| 151 | + XMEMSET(nvDigest, 0, sizeof(nvDigest)); |
| 152 | + XMEMSET(policyDigest, 0, sizeof(policyDigest)); |
| 153 | + |
| 154 | + rc = wolfTPM2_Init(&dev, TPM2_IoCb, userCtx); |
| 155 | + if (rc != TPM_RC_SUCCESS) { |
| 156 | + printf("wolfTPM2_Init failed\n"); |
| 157 | + goto exit; |
| 158 | + } |
| 159 | + |
| 160 | + /* Build Policies A/B/C */ |
| 161 | + /* Policy A: TPM2_PolicyCommandCode -> TPM_CC_NV_Read */ |
| 162 | + /* 47ce3032d8bad1f3089cb0c09088de43501491d460402b90cd1b7fc0b68ca92f */ |
| 163 | + policy[0] = &policyDigest[policyDigestSz]; |
| 164 | + BuildPolicyCommandCode(hashAlg, policy[0], &nvSize, TPM_CC_NV_Read); |
| 165 | + printf("PolicyA: %d\n", nvSize); |
| 166 | + TPM2_PrintBin(policy[0], nvSize); |
| 167 | + policyDigestSz += nvSize; |
| 168 | + |
| 169 | + /* Policy B: TPM2_PolicyCommandCode -> TPM_CC_NV_Extend */ |
| 170 | + /* b6a2e7142ee56fd978047488483daa5b42b8dc4cc7ddcceddfb91793cf1ff1b7 */ |
| 171 | + policy[1] = &policyDigest[policyDigestSz]; |
| 172 | + BuildPolicyCommandCode(hashAlg, policy[1], &nvSize, TPM_CC_NV_Extend); |
| 173 | + printf("PolicyB: %d\n", nvSize); |
| 174 | + TPM2_PrintBin(policy[1], nvSize); |
| 175 | + policyDigestSz += nvSize; |
| 176 | + |
| 177 | + /* Policy C: TPM2_PolicyCommandCode -> TPM_CC_PolicyNV */ |
| 178 | + /* 203e4bd5d0448c9615cc13fa18e8d39222441cc40204d99a77262068dbd55a43 */ |
| 179 | + policy[2] = &policyDigest[policyDigestSz]; |
| 180 | + BuildPolicyCommandCode(hashAlg, policy[2], &nvSize, TPM_CC_PolicyNV); |
| 181 | + printf("PolicyC: %d\n", nvSize); |
| 182 | + TPM2_PrintBin(policy[2], nvSize); |
| 183 | + policyDigestSz += nvSize; |
| 184 | + |
| 185 | + /* Policy OR A/B/C */ |
| 186 | + /* 7f17937e206279a3f755fb60f40cf126b70e5b1d9bf202866d527613874a64ac */ |
| 187 | + XMEMSET(policyOr, 0, sizeof(policyOr)); |
| 188 | + rc = wolfTPM2_PolicyHash(hashAlg, policyOr, &nvSize, |
| 189 | + TPM_CC_PolicyOR, policyDigest, policyDigestSz); |
| 190 | + printf("PolicyOR A/B/C: %d\n", nvSize); |
| 191 | + TPM2_PrintBin(policyOr, nvSize); |
| 192 | + |
| 193 | + /* 1: Create EK (RSA or ECC) */ |
| 194 | + rc = wolfTPM2_CreateEK(&dev, &endorse, |
| 195 | + #ifndef NO_RSA |
| 196 | + TPM_ALG_RSA |
| 197 | + #else |
| 198 | + TPM_ALG_ECC |
| 199 | + #endif |
| 200 | + ); |
| 201 | + if (rc != 0) { |
| 202 | + printf("Create EK RSA failed!\n"); |
| 203 | + goto exit; |
| 204 | + } |
| 205 | + endorse.handle.policyAuth = 1; /* EK requires policy auth */ |
| 206 | + printf("EK Handle: 0x%x\n", (word32)endorse.handle.hndl); |
| 207 | + |
| 208 | + /* 2: Create a salted session with the TPM using the EK */ |
| 209 | + rc = wolfTPM2_StartSession(&dev, &tpmSession, &endorse, NULL, |
| 210 | + TPM_SE_HMAC, paramEncAlg); |
| 211 | + if (rc == 0) { |
| 212 | + rc = wolfTPM2_SetAuthSession(&dev, 0, &tpmSession, |
| 213 | + (TPMA_SESSION_decrypt | TPMA_SESSION_encrypt | |
| 214 | + TPMA_SESSION_continueSession)); |
| 215 | + } |
| 216 | + if (rc != 0) { |
| 217 | + printf("Start HMAC session failed!\n"); |
| 218 | + goto exit; |
| 219 | + } |
| 220 | + printf("Encrypted HMAC Session Handle 0x%x\n", |
| 221 | + (word32)tpmSession.handle.hndl); |
| 222 | + |
| 223 | + /* 3. Create the NV Index with extend attribute. |
| 224 | + * Use "host secret" as password so it is used with the bind session later */ |
| 225 | + |
| 226 | + /* See TPM_Bus_Protection_Guidance_Active_Attack_Mitigations: |
| 227 | + * Section 3.4 Provisioning the NV Index */ |
| 228 | + nvAttributes = ( |
| 229 | + (TPMA_NV_TPM_NT & (TPM_NT_EXTEND << 4)) | |
| 230 | + TPMA_NV_ORDERLY | |
| 231 | + TPMA_NV_CLEAR_STCLEAR | |
| 232 | + TPMA_NV_PLATFORMCREATE | |
| 233 | + TPMA_NV_POLICYWRITE | |
| 234 | + TPMA_NV_POLICYREAD | |
| 235 | + TPMA_NV_NO_DA); |
| 236 | + nvSize = TPM2_GetHashDigestSize(WOLFTPM2_WRAP_DIGEST); |
| 237 | + |
| 238 | + /* Try and open existing NV */ |
| 239 | + rc = wolfTPM2_NVOpen(&dev, &nv, nvIndex, auth, authSz); |
| 240 | + if (rc != 0) { |
| 241 | + nvAuth.hndl = authHandle; |
| 242 | + |
| 243 | + rc = wolfTPM2_NVCreateAuthPolicy(&dev, &nvAuth, &nv, nvIndex, |
| 244 | + nvAttributes, /* needs TPM_NT_EXTEND set */ |
| 245 | + nvSize, /* must match nameAlg digest size */ |
| 246 | + auth, authSz, /* the password to bind session with */ |
| 247 | + policyOr, nvSize |
| 248 | + ); |
| 249 | + } |
| 250 | + |
| 251 | + /* Close session and unload endorsement */ |
| 252 | + wolfTPM2_UnsetAuth(&dev, 0); |
| 253 | + wolfTPM2_UnloadHandle(&dev, &tpmSession.handle); |
| 254 | + wolfTPM2_UnloadHandle(&dev, &endorse.handle); |
| 255 | + |
| 256 | + |
| 257 | + /* 4. Start a policy session and bind to NV handle */ |
| 258 | + rc = wolfTPM2_StartSession(&dev, &tpmSession, NULL, &nv.handle, |
| 259 | + TPM_SE_POLICY, TPM_ALG_CFB); |
| 260 | + if (rc == 0) { |
| 261 | + rc = wolfTPM2_SetAuthSession(&dev, 0, &tpmSession, |
| 262 | + (TPMA_SESSION_decrypt | TPMA_SESSION_encrypt | |
| 263 | + TPMA_SESSION_continueSession)); |
| 264 | + } |
| 265 | + if (rc != 0) { |
| 266 | + printf("Start Policy session failed!\n"); |
| 267 | + goto exit; |
| 268 | + } |
| 269 | + printf("Encrypted Policy Session Handle 0x%x\n", |
| 270 | + (word32)tpmSession.handle.hndl); |
| 271 | + |
| 272 | + /* 5. Satisfy policy for NV Extend (policy B) */ |
| 273 | + rc = wolfTPM2_PolicyCommandCode(&dev, &tpmSession, TPM_CC_NV_Extend); |
| 274 | + if (rc == 0) { |
| 275 | + rc = PolicyOrApply(&dev, &tpmSession, policy, 3, nvSize); |
| 276 | + } |
| 277 | + if (rc != 0) { |
| 278 | + printf("Failed to apply policy B\n"); |
| 279 | + goto exit; |
| 280 | + } |
| 281 | + |
| 282 | + /* 6. Perform NV extend */ |
| 283 | + rc = wolfTPM2_NVExtend(&dev, &nv, nvIndex, auth, (word32)authSz); |
| 284 | + if (rc != 0) { |
| 285 | + printf("NV Extend failed!\n"); |
| 286 | + goto exit; |
| 287 | + } |
| 288 | + printf("NV 0x%08x extended\n", (word32)nvIndex); |
| 289 | + |
| 290 | + /* 7. Restart session policy */ |
| 291 | + rc = wolfTPM2_PolicyRestart(&dev, tpmSession.handle.hndl); |
| 292 | + if (rc != 0) { |
| 293 | + printf("Policy restart failed!\n"); |
| 294 | + goto exit; |
| 295 | + } |
| 296 | + |
| 297 | + /* 8. Satisfy policy for NV Read (policy A) */ |
| 298 | + rc = wolfTPM2_PolicyCommandCode(&dev, &tpmSession, TPM_CC_NV_Read); |
| 299 | + if (rc == 0) { |
| 300 | + rc = PolicyOrApply(&dev, &tpmSession, policy, 3, nvSize); |
| 301 | + } |
| 302 | + if (rc != 0) { |
| 303 | + printf("Failed to apply policy A\n"); |
| 304 | + goto exit; |
| 305 | + } |
| 306 | + |
| 307 | + /* 9. Read NV extend digest */ |
| 308 | + rc = wolfTPM2_NVRead(&dev, authHandle, nv.handle.hndl, |
| 309 | + nvDigest, &nvSize, 0); |
| 310 | + if (rc == 0) { |
| 311 | + printf("NV Digest: %d\n", nvSize); |
| 312 | + TPM2_PrintBin(nvDigest, nvSize); |
| 313 | + |
| 314 | + /* Should be: |
| 315 | + * 0ad80f8e4450587760d9137df41c9374f657bafa621fe37d4d5c8cecf0bcce5e */ |
| 316 | + } |
| 317 | + |
| 318 | +exit: |
| 319 | + |
| 320 | + if (rc != 0) { |
| 321 | + printf("\nFailure 0x%x: %s\n\n", rc, wolfTPM2_GetRCString(rc)); |
| 322 | + } |
| 323 | + |
| 324 | + wolfTPM2_UnloadHandle(&dev, &tpmSession.handle); |
| 325 | + wolfTPM2_Cleanup(&dev); |
| 326 | + |
| 327 | + return rc; |
| 328 | +} |
| 329 | + |
| 330 | +/******************************************************************************/ |
| 331 | +/* --- END TPM NVRAM Extend Example -- */ |
| 332 | +/******************************************************************************/ |
| 333 | +#endif /* !WOLFTPM2_NO_WRAPPER && !WOLFTPM2_NO_WOLFCRYPT */ |
| 334 | + |
| 335 | +#ifndef NO_MAIN_DRIVER |
| 336 | +int main(int argc, char *argv[]) |
| 337 | +{ |
| 338 | + int rc = NOT_COMPILED_IN; |
| 339 | + |
| 340 | +#if !defined(WOLFTPM2_NO_WRAPPER) && !defined(WOLFTPM2_NO_WOLFCRYPT) |
| 341 | + rc = TPM2_NVRAM_Extend_Example(NULL, argc, argv); |
| 342 | +#else |
| 343 | + printf("NVRAM extend code not compiled in\n"); |
| 344 | + (void)argc; |
| 345 | + (void)argv; |
| 346 | +#endif |
| 347 | + |
| 348 | + return rc; |
| 349 | +} |
| 350 | +#endif |
0 commit comments