|
| 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 <stdio.h> |
| 31 | + |
| 32 | +#ifndef WOLFTPM2_NO_WRAPPER |
| 33 | + |
| 34 | +#include <examples/nvram/nvram.h> |
| 35 | +#include <hal/tpm_io.h> |
| 36 | +#include <examples/tpm_test.h> |
| 37 | +#include <examples/tpm_test_keys.h> |
| 38 | + |
| 39 | +/******************************************************************************/ |
| 40 | +/* --- BEGIN TPM NVRAM Extend Example -- */ |
| 41 | +/******************************************************************************/ |
| 42 | +static void usage(void) |
| 43 | +{ |
| 44 | + printf("Expected usage:\n"); |
| 45 | + printf("./examples/nvram/extend [-nvindex=handle] [-aes/-xor]\n"); |
| 46 | + printf("* -nvindex=[handle] (default 0x%x)\n", |
| 47 | + TPM2_DEMO_NVRAM_EXTEND_INDEX); |
| 48 | + printf("* -aes/xor: Use Parameter Encryption\n");; |
| 49 | +} |
| 50 | + |
| 51 | +/* Policy A: TPM2_PolicyCommandCode -> TPM_CC_NV_Read */ |
| 52 | +static const byte policyA[] = { |
| 53 | + 0x47, 0xCE, 0x30, 0x32, 0xD8, 0xBA, 0xD1, 0xF3, |
| 54 | + 0x08, 0x9C, 0xB0, 0xC0, 0x90, 0x88, 0xDE, 0x43, |
| 55 | + 0x50, 0x14, 0x91, 0xD4, 0x60, 0x40, 0x2B, 0x90, |
| 56 | + 0xCD, 0x1B, 0x7F, 0xC0, 0xB6, 0x8C, 0xA9, 0x2F |
| 57 | +}; |
| 58 | +/* Policy B: TPM2_PolicyCommandCode -> TPM_CC_NV_Extend */ |
| 59 | +static const byte policyB[] = { |
| 60 | + 0xB6, 0xA2, 0xE7, 0x14, 0x2E, 0xE5, 0x6F, 0xD9, |
| 61 | + 0x78, 0x04, 0x74, 0x88, 0x48, 0x3D, 0xAA, 0x5B, |
| 62 | + 0x42, 0xB8, 0xDC, 0x4C, 0xC7, 0xDD, 0xCC, 0xED, |
| 63 | + 0xDF, 0xB9, 0x17, 0x93, 0xCF, 0x1F, 0xF1, 0xB7 |
| 64 | +}; |
| 65 | +/* Policy C: TPM2_PolicyCommandCode -> TPM_CC_PolicyNV */ |
| 66 | +static const byte policyC[] = { |
| 67 | + 0x20, 0x3E, 0x4B, 0xD5, 0xD0, 0x44, 0x8C, 0x96, |
| 68 | + 0x15, 0xCC, 0x13, 0xFA, 0x18, 0xE8, 0xD3, 0x92, |
| 69 | + 0x22, 0x44, 0x1C, 0xC4, 0x02, 0x04, 0xD9, 0x9A, |
| 70 | + 0x77, 0x26, 0x20, 0x68, 0xDB, 0xD5, 0x5A, 0x43 |
| 71 | +}; |
| 72 | + |
| 73 | +/* pre-computed policy: |
| 74 | + * NV Read (A), NV Extend (B), PolicyNV (C), then policy OR (A/B/C) */ |
| 75 | +static const byte policyNv[] = { |
| 76 | + 0x7F, 0x17, 0x93, 0x7E, 0x20, 0x62, 0x79, 0xA3, |
| 77 | + 0xF7, 0x55, 0xFB, 0x60, 0xF4, 0x0C, 0xF1, 0x26, |
| 78 | + 0xB7, 0x0E, 0x5B, 0x1D, 0x9B, 0xF2, 0x02, 0x86, |
| 79 | + 0x6D, 0x52, 0x76, 0x13, 0x87, 0x4A, 0x64, 0xAC |
| 80 | +}; |
| 81 | + |
| 82 | + |
| 83 | +static int PolicyOrApply(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* policySession) |
| 84 | +{ |
| 85 | + PolicyOR_In policyOR; |
| 86 | + XMEMSET(&policyOR, 0, sizeof(policyOR)); |
| 87 | + policyOR.policySession = policySession->handle.hndl; |
| 88 | + policyOR.pHashList.count = 3; |
| 89 | + policyOR.pHashList.digests[0].size = sizeof(policyA); |
| 90 | + XMEMCPY(policyOR.pHashList.digests[0].buffer, policyA, sizeof(policyA)); |
| 91 | + policyOR.pHashList.digests[1].size = sizeof(policyB); |
| 92 | + XMEMCPY(policyOR.pHashList.digests[1].buffer, policyB, sizeof(policyB)); |
| 93 | + policyOR.pHashList.digests[2].size = sizeof(policyC); |
| 94 | + XMEMCPY(policyOR.pHashList.digests[2].buffer, policyC, sizeof(policyC)); |
| 95 | + (void)dev; |
| 96 | + return TPM2_PolicyOR(&policyOR); |
| 97 | +} |
| 98 | + |
| 99 | +int TPM2_NVRAM_Extend_Example(void* userCtx, int argc, char *argv[]) |
| 100 | +{ |
| 101 | + int rc; |
| 102 | + WOLFTPM2_DEV dev; |
| 103 | + WOLFTPM2_KEY endorse; |
| 104 | + WOLFTPM2_SESSION tpmSession; |
| 105 | + WOLFTPM2_HANDLE nvAuth; |
| 106 | + WOLFTPM2_HANDLE bind; |
| 107 | + WOLFTPM2_NV nv; |
| 108 | + word32 nvAttributes; |
| 109 | + int paramEncAlg = TPM_ALG_CFB; |
| 110 | + TPMI_RH_NV_AUTH authHandle = TPM_RH_PLATFORM; |
| 111 | + word32 nvIndex = TPM2_DEMO_NVRAM_EXTEND_INDEX; |
| 112 | + word32 nvSize; /* 32 for SHA2-256 */ |
| 113 | + byte* auth = (byte*)"cpusecret"; |
| 114 | + word32 authSz = (word32)XSTRLEN((const char*)auth); |
| 115 | + byte nvDigest[32]; |
| 116 | + word32 nvDigestSz = (word32)sizeof(nvDigest); |
| 117 | + |
| 118 | + if (argc >= 2) { |
| 119 | + if (XSTRCMP(argv[1], "-?") == 0 || |
| 120 | + XSTRCMP(argv[1], "-h") == 0 || |
| 121 | + XSTRCMP(argv[1], "--help") == 0) { |
| 122 | + usage(); |
| 123 | + return 0; |
| 124 | + } |
| 125 | + } |
| 126 | + while (argc > 1) { |
| 127 | + if (XSTRNCMP(argv[argc-1], "-nvindex=", XSTRLEN("-nvindex=")) == 0) { |
| 128 | + const char* nvIndexStr = argv[argc-1] + XSTRLEN("-nvindex="); |
| 129 | + nvIndex = (word32)XSTRTOUL(nvIndexStr, NULL, 0); |
| 130 | + if (nvIndex >= TPM_20_PLATFORM_MFG_NV_SPACE && |
| 131 | + nvIndex < TPM_20_OWNER_NV_SPACE) { |
| 132 | + authHandle = TPM_RH_PLATFORM; |
| 133 | + } |
| 134 | + else if (nvIndex >= TPM_20_OWNER_NV_SPACE && |
| 135 | + nvIndex < TPM_20_TCG_NV_SPACE) { |
| 136 | + authHandle = TPM_RH_OWNER; |
| 137 | + } |
| 138 | + else { |
| 139 | + fprintf(stderr, "Invalid NV Index %s\n", nvIndexStr); |
| 140 | + fprintf(stderr, "\tPlatform Range: 0x%x -> 0x%x\n", |
| 141 | + TPM_20_PLATFORM_MFG_NV_SPACE, TPM_20_OWNER_NV_SPACE); |
| 142 | + fprintf(stderr, "\tOwner Range: 0x%x -> 0x%x\n", |
| 143 | + TPM_20_OWNER_NV_SPACE, TPM_20_TCG_NV_SPACE); |
| 144 | + usage(); |
| 145 | + return -1; |
| 146 | + } |
| 147 | + } |
| 148 | + else if (XSTRCMP(argv[argc-1], "-aes") == 0) { |
| 149 | + paramEncAlg = TPM_ALG_CFB; |
| 150 | + } |
| 151 | + else if (XSTRCMP(argv[argc-1], "-xor") == 0) { |
| 152 | + paramEncAlg = TPM_ALG_XOR; |
| 153 | + } |
| 154 | + else { |
| 155 | + printf("Warning: Unrecognized option: %s\n", argv[argc-1]); |
| 156 | + } |
| 157 | + argc--; |
| 158 | + }; |
| 159 | + |
| 160 | + printf("NVRAM Extend (bus protection example)\n"); |
| 161 | + printf("Parameter Encryption: %s\n", |
| 162 | + (paramEncAlg == TPM_ALG_CFB) ? "AES CFB" : "XOR"); |
| 163 | + |
| 164 | + XMEMSET(&tpmSession, 0, sizeof(tpmSession)); |
| 165 | + XMEMSET(&endorse, 0, sizeof(endorse)); |
| 166 | + XMEMSET(&bind, 0, sizeof(bind)); |
| 167 | + XMEMSET(&nv, 0, sizeof(nv)); |
| 168 | + XMEMSET(&nvAuth, 0, sizeof(nvAuth)); |
| 169 | + |
| 170 | + rc = wolfTPM2_Init(&dev, TPM2_IoCb, userCtx); |
| 171 | + if (rc != TPM_RC_SUCCESS) { |
| 172 | + printf("wolfTPM2_Init failed\n"); |
| 173 | + goto exit; |
| 174 | + } |
| 175 | + |
| 176 | + /* 1: Create EK RSA 2048-bit */ |
| 177 | + rc = wolfTPM2_CreateEK(&dev, &endorse, TPM_ALG_RSA); |
| 178 | + if (rc != 0) { |
| 179 | + printf("Create EK RSA failed!\n"); |
| 180 | + goto exit; |
| 181 | + } |
| 182 | + endorse.handle.policyAuth = 1; /* EK requires policy auth */ |
| 183 | + printf("EK Handle: 0x%x\n", (word32)endorse.handle.hndl); |
| 184 | + |
| 185 | + /* 2: Create a salted session with the TPM using the EK */ |
| 186 | + rc = wolfTPM2_StartSession(&dev, &tpmSession, &endorse, NULL, |
| 187 | + TPM_SE_HMAC, paramEncAlg); |
| 188 | + if (rc == 0) { |
| 189 | + rc = wolfTPM2_SetAuthSession(&dev, 0, &tpmSession, |
| 190 | + (TPMA_SESSION_decrypt | TPMA_SESSION_encrypt | |
| 191 | + TPMA_SESSION_continueSession)); |
| 192 | + } |
| 193 | + if (rc != 0) { |
| 194 | + printf("Start HMAC session failed!\n"); |
| 195 | + goto exit; |
| 196 | + } |
| 197 | + printf("Encrypted HMAC Session Handle 0x%x\n", |
| 198 | + (word32)tpmSession.handle.hndl); |
| 199 | + |
| 200 | + /* 3. Create the NV Index with extend attribute. |
| 201 | + * Use "host secret" as password so it is used with the bind session later */ |
| 202 | + |
| 203 | + /* See TPM_Bus_Protection_Guidance_Active_Attack_Mitigations: |
| 204 | + * Section 3.4 Provisioning the NV Index */ |
| 205 | + nvAttributes = ( |
| 206 | + (TPMA_NV_TPM_NT & (TPM_NT_EXTEND << 4)) | |
| 207 | + TPMA_NV_ORDERLY | |
| 208 | + TPMA_NV_CLEAR_STCLEAR | |
| 209 | + TPMA_NV_PLATFORMCREATE | |
| 210 | + TPMA_NV_POLICYWRITE | |
| 211 | + TPMA_NV_POLICYREAD | |
| 212 | + TPMA_NV_NO_DA); |
| 213 | + nvSize = TPM2_GetHashDigestSize(WOLFTPM2_WRAP_DIGEST); |
| 214 | + |
| 215 | + /* Try and open existing NV */ |
| 216 | + rc = wolfTPM2_NVOpen(&dev, &nv, nvIndex, auth, authSz); |
| 217 | + if (rc != 0) { |
| 218 | + nvAuth.hndl = authHandle; |
| 219 | + |
| 220 | + rc = wolfTPM2_NVCreateAuthPolicy(&dev, &nvAuth, &nv, nvIndex, |
| 221 | + nvAttributes, /* needs TPM_NT_EXTEND set */ |
| 222 | + nvSize, /* must match nameAlg digest size */ |
| 223 | + auth, authSz, /* the password to bind session with */ |
| 224 | + policyNv, (word32)sizeof(policyNv) |
| 225 | + ); |
| 226 | + } |
| 227 | + |
| 228 | + /* Close session and unload endorsement */ |
| 229 | + wolfTPM2_UnsetAuth(&dev, 0); |
| 230 | + wolfTPM2_UnloadHandle(&dev, &tpmSession.handle); |
| 231 | + wolfTPM2_UnloadHandle(&dev, &endorse.handle); |
| 232 | + |
| 233 | + |
| 234 | + /* 4. Start a policy session and bind to NV handle */ |
| 235 | + rc = wolfTPM2_StartSession(&dev, &tpmSession, NULL, &nv.handle, |
| 236 | + TPM_SE_POLICY, TPM_ALG_CFB); |
| 237 | + if (rc == 0) { |
| 238 | + rc = wolfTPM2_SetAuthSession(&dev, 0, &tpmSession, |
| 239 | + (TPMA_SESSION_decrypt | TPMA_SESSION_encrypt | |
| 240 | + TPMA_SESSION_continueSession)); |
| 241 | + } |
| 242 | + if (rc != 0) { |
| 243 | + printf("Start Policy session failed!\n"); |
| 244 | + goto exit; |
| 245 | + } |
| 246 | + printf("Encrypted Policy Session Handle 0x%x\n", |
| 247 | + (word32)tpmSession.handle.hndl); |
| 248 | + |
| 249 | + /* 5. Satisfy policy for NV Extend (policy B) */ |
| 250 | + rc = wolfTPM2_PolicyCommandCode(&dev, &tpmSession, TPM_CC_NV_Extend); |
| 251 | + if (rc == 0) { |
| 252 | + rc = PolicyOrApply(&dev, &tpmSession); |
| 253 | + } |
| 254 | + if (rc != 0) { |
| 255 | + printf("Failed to apply policy B\n"); |
| 256 | + goto exit; |
| 257 | + } |
| 258 | + |
| 259 | + /* 6. Perform NV extend */ |
| 260 | + rc = wolfTPM2_NVExtend(&dev, &nv, nvIndex, auth, (word32)authSz); |
| 261 | + if (rc != 0) { |
| 262 | + printf("NV Extend failed!\n"); |
| 263 | + goto exit; |
| 264 | + } |
| 265 | + printf("NV 0x%08x extended\n", (word32)nvIndex); |
| 266 | + |
| 267 | + /* 7. Restart session policy */ |
| 268 | + rc = wolfTPM2_PolicyRestart(&dev, tpmSession.handle.hndl); |
| 269 | + if (rc != 0) { |
| 270 | + printf("Policy restart failed!\n"); |
| 271 | + goto exit; |
| 272 | + } |
| 273 | + |
| 274 | + /* 8. Satisfy policy for NV Read (policy A) */ |
| 275 | + rc = wolfTPM2_PolicyCommandCode(&dev, &tpmSession, TPM_CC_NV_Read); |
| 276 | + if (rc == 0) { |
| 277 | + rc = PolicyOrApply(&dev, &tpmSession); |
| 278 | + } |
| 279 | + if (rc != 0) { |
| 280 | + printf("Failed to apply policy A\n"); |
| 281 | + goto exit; |
| 282 | + } |
| 283 | + |
| 284 | + /* 9. Read NV extend digest */ |
| 285 | + rc = wolfTPM2_NVRead(&dev, authHandle, nv.handle.hndl, |
| 286 | + nvDigest, &nvDigestSz, 0); |
| 287 | + if (rc == 0) { |
| 288 | + printf("NV Digest: %d\n", nvDigestSz); |
| 289 | + TPM2_PrintBin(nvDigest, nvDigestSz); |
| 290 | + |
| 291 | + /* Should be: |
| 292 | + * 0ad80f8e4450587760d9137df41c9374f657bafa621fe37d4d5c8cecf0bcce5e */ |
| 293 | + } |
| 294 | + |
| 295 | +exit: |
| 296 | + |
| 297 | + if (rc != 0) { |
| 298 | + printf("\nFailure 0x%x: %s\n\n", rc, wolfTPM2_GetRCString(rc)); |
| 299 | + } |
| 300 | + |
| 301 | + wolfTPM2_UnloadHandle(&dev, &tpmSession.handle); |
| 302 | + wolfTPM2_Cleanup(&dev); |
| 303 | + |
| 304 | + return rc; |
| 305 | +} |
| 306 | + |
| 307 | +/******************************************************************************/ |
| 308 | +/* --- END TPM NVRAM Extend Example -- */ |
| 309 | +/******************************************************************************/ |
| 310 | +#endif /* !WOLFTPM2_NO_WRAPPER */ |
| 311 | + |
| 312 | +#ifndef NO_MAIN_DRIVER |
| 313 | +int main(int argc, char *argv[]) |
| 314 | +{ |
| 315 | + int rc = NOT_COMPILED_IN; |
| 316 | + |
| 317 | +#ifndef WOLFTPM2_NO_WRAPPER |
| 318 | + rc = TPM2_NVRAM_Extend_Example(NULL, argc, argv); |
| 319 | +#else |
| 320 | + printf("NVRAM code not compiled in\n"); |
| 321 | + (void)argc; |
| 322 | + (void)argv; |
| 323 | +#endif |
| 324 | + |
| 325 | + return rc; |
| 326 | +} |
| 327 | +#endif |
0 commit comments