1 /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 2 * Use of this source code is governed by a BSD-style license that can be 3 * found in the LICENSE file. 4 */ 5 6 /* This program generates partially filled TPM datagrams and other compile-time 7 * constants (e.g. structure sizes and offsets). Compile this file---and ONLY 8 * this file---with -fpack-struct. We take advantage of the fact that the 9 * (packed) TPM structures layout (mostly) match the TPM request and response 10 * datagram layout. When they don't completely match, some fixing is necessary 11 * (see PCR_SELECTION_FIX below). 12 */ 13 14 #include <assert.h> 15 #include <stddef.h> 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <tss/tcs.h> 19 20 #include "sysincludes.h" 21 #include "tlcl_internal.h" 22 #include "tpmextras.h" 23 24 /* See struct Command below. This structure represent a field in a TPM 25 * command. [name] is the field name. [visible] is 1 if the field is 26 * modified by the run-time. Non-visible fields are initialized at build time 27 * and remain constant. [size] is the field size in bytes. [value] is the 28 * fixed value of non-visible fields. 29 */ 30 typedef struct Field { 31 const char* name; 32 int visible; 33 int offset; 34 int size; 35 uint32_t value; /* large enough for all initializers */ 36 struct Field* next; 37 } Field; 38 39 /* This structure is used to build (at build time) and manipulate (at firmware 40 * or emulation run time) buffers containing TPM datagrams. [name] is the name 41 * of a TPM command. [size] is the size of the command buffer in bytes, when 42 * known. [max_size] is the maximum size allowed for variable-length commands 43 * (such as Read and Write). [fields] is a link-list of command fields. 44 */ 45 typedef struct Command { 46 const char* name; 47 int size; 48 int max_size; 49 Field* fields; 50 struct Command* next; 51 } Command; 52 53 /* Adds a field to a command, and makes its offset visible. The fields must be 54 * added at increasing offsets. 55 */ 56 static void AddVisibleField(Command* cmd, const char* name, int offset) { 57 Field* fld = (Field*) calloc(1, sizeof(Field)); 58 if (cmd->fields != NULL) { 59 assert(offset > fn->offset); 60 } 61 fld->next = cmd->fields; 62 cmd->fields = fld; 63 fld->name = name; 64 fld->visible = 1; 65 fld->offset = offset; 66 } 67 68 /* Adds a constant field with its value. The fields must be added at 69 * increasing offsets. 70 */ 71 static void AddInitializedField(Command* cmd, int offset, 72 int size, uint32_t value) { 73 Field* fld = (Field*) calloc(1, sizeof(Field)); 74 fld->next = cmd->fields; 75 cmd->fields = fld; 76 fld->name = NULL; 77 fld->visible = 0; 78 fld->size = size; 79 fld->offset = offset; 80 fld->value = value; 81 } 82 83 /* Create a structure representing a TPM command datagram. 84 */ 85 Command* newCommand(TPM_COMMAND_CODE code, int size) { 86 Command* cmd = (Command*) calloc(1, sizeof(Command)); 87 cmd->size = size; 88 AddInitializedField(cmd, 0, sizeof(TPM_TAG), TPM_TAG_RQU_COMMAND); 89 AddInitializedField(cmd, sizeof(TPM_TAG), sizeof(uint32_t), size); 90 AddInitializedField(cmd, sizeof(TPM_TAG) + sizeof(uint32_t), 91 sizeof(TPM_COMMAND_CODE), code); 92 return cmd; 93 } 94 95 /* The TPM_PCR_SELECTION structure in /usr/include/tss/tpm.h contains a pointer 96 * instead of an array[3] of bytes, so we need to adjust sizes and offsets 97 * accordingly. 98 */ 99 #define PCR_SELECTION_FIX (3 - sizeof(char *)) 100 101 /* BuildXXX builds TPM command XXX. 102 */ 103 Command* BuildDefineSpaceCommand(void) { 104 int nv_data_public = kTpmRequestHeaderLength; 105 int nv_index = nv_data_public + offsetof(TPM_NV_DATA_PUBLIC, nvIndex); 106 int nv_pcr_info_read = nv_data_public + 107 offsetof(TPM_NV_DATA_PUBLIC, pcrInfoRead); 108 /* 109 * Here we need to carefully add PCR_SELECTION_FIX (or twice that much) in 110 * all the places where the offset calculation would be wrong without it. 111 * The mismatch occurs in the TPM_PCR_SELECTION structure, and it must be 112 * accounted for in all the structures that include it, directly or 113 * indirectly. 114 */ 115 int read_locality = nv_pcr_info_read + 116 offsetof(TPM_PCR_INFO_SHORT, localityAtRelease) + PCR_SELECTION_FIX; 117 int nv_pcr_info_write = nv_data_public + 118 offsetof(TPM_NV_DATA_PUBLIC, pcrInfoWrite) + PCR_SELECTION_FIX; 119 int write_locality = nv_pcr_info_write + 120 offsetof(TPM_PCR_INFO_SHORT, localityAtRelease) + PCR_SELECTION_FIX; 121 int nv_permission = nv_data_public + 122 offsetof(TPM_NV_DATA_PUBLIC, permission) + 2 * PCR_SELECTION_FIX; 123 int nv_permission_tag = 124 nv_permission + offsetof(TPM_NV_ATTRIBUTES, tag); 125 int nv_permission_attributes = 126 nv_permission + offsetof(TPM_NV_ATTRIBUTES, attributes); 127 int nv_datasize = nv_data_public + 128 offsetof(TPM_NV_DATA_PUBLIC, dataSize) + 2 * PCR_SELECTION_FIX; 129 130 int size = kTpmRequestHeaderLength + sizeof(TPM_NV_DATA_PUBLIC) + 131 2 * PCR_SELECTION_FIX + kEncAuthLength; 132 Command* cmd = newCommand(TPM_ORD_NV_DefineSpace, size); 133 cmd->name = "tpm_nv_definespace_cmd"; 134 135 AddVisibleField(cmd, "index", nv_index); 136 AddVisibleField(cmd, "perm", nv_permission_attributes); 137 AddVisibleField(cmd, "size", nv_datasize); 138 139 AddInitializedField(cmd, nv_data_public, sizeof(uint16_t), 140 TPM_TAG_NV_DATA_PUBLIC); 141 AddInitializedField(cmd, nv_pcr_info_read, sizeof(uint16_t), 3); 142 AddInitializedField(cmd, read_locality, sizeof(TPM_LOCALITY_SELECTION), 143 TPM_ALL_LOCALITIES); 144 AddInitializedField(cmd, nv_pcr_info_write, sizeof(uint16_t), 3); 145 AddInitializedField(cmd, write_locality, sizeof(TPM_LOCALITY_SELECTION), 146 TPM_ALL_LOCALITIES); 147 AddInitializedField(cmd, nv_permission_tag, sizeof(TPM_STRUCTURE_TAG), 148 TPM_TAG_NV_ATTRIBUTES); 149 return cmd; 150 } 151 152 /* BuildXXX builds TPM command XXX. 153 */ 154 Command* BuildWriteCommand(void) { 155 Command* cmd = newCommand(TPM_ORD_NV_WriteValue, 0); 156 cmd->name = "tpm_nv_write_cmd"; 157 cmd->max_size = TPM_LARGE_ENOUGH_COMMAND_SIZE; 158 AddVisibleField(cmd, "index", kTpmRequestHeaderLength); 159 AddVisibleField(cmd, "length", kTpmRequestHeaderLength + 8); 160 AddVisibleField(cmd, "data", kTpmRequestHeaderLength + 12); 161 return cmd; 162 } 163 164 Command* BuildReadCommand(void) { 165 int size = kTpmRequestHeaderLength + kTpmReadInfoLength; 166 Command* cmd = newCommand(TPM_ORD_NV_ReadValue, size); 167 cmd->name = "tpm_nv_read_cmd"; 168 AddVisibleField(cmd, "index", kTpmRequestHeaderLength); 169 AddVisibleField(cmd, "length", kTpmRequestHeaderLength + 8); 170 return cmd; 171 } 172 173 Command* BuildPCRReadCommand(void) { 174 int size = kTpmRequestHeaderLength + sizeof(uint32_t); 175 Command* cmd = newCommand(TPM_ORD_PcrRead, size); 176 cmd->name = "tpm_pcr_read_cmd"; 177 AddVisibleField(cmd, "pcrNum", kTpmRequestHeaderLength); 178 return cmd; 179 } 180 181 Command* BuildPPAssertCommand(void) { 182 int size = kTpmRequestHeaderLength + sizeof(TPM_PHYSICAL_PRESENCE); 183 Command* cmd = newCommand(TSC_ORD_PhysicalPresence, size); 184 cmd->name = "tpm_ppassert_cmd"; 185 AddInitializedField(cmd, kTpmRequestHeaderLength, 186 sizeof(TPM_PHYSICAL_PRESENCE), 187 TPM_PHYSICAL_PRESENCE_PRESENT); 188 return cmd; 189 } 190 191 Command* BuildPPEnableCommand(void) { 192 int size = kTpmRequestHeaderLength + sizeof(TPM_PHYSICAL_PRESENCE); 193 Command* cmd = newCommand(TSC_ORD_PhysicalPresence, size); 194 cmd->name = "tpm_ppenable_cmd"; 195 AddInitializedField(cmd, kTpmRequestHeaderLength, 196 sizeof(TPM_PHYSICAL_PRESENCE), 197 TPM_PHYSICAL_PRESENCE_CMD_ENABLE); 198 return cmd; 199 } 200 201 Command* BuildFinalizePPCommand(void) { 202 int size = kTpmRequestHeaderLength + sizeof(TPM_PHYSICAL_PRESENCE); 203 Command* cmd = newCommand(TSC_ORD_PhysicalPresence, size); 204 cmd->name = "tpm_finalizepp_cmd"; 205 AddInitializedField(cmd, kTpmRequestHeaderLength, 206 sizeof(TPM_PHYSICAL_PRESENCE), 207 TPM_PHYSICAL_PRESENCE_CMD_ENABLE | 208 TPM_PHYSICAL_PRESENCE_HW_DISABLE | 209 TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK); 210 return cmd; 211 } 212 213 Command* BuildPPLockCommand(void) { 214 int size = kTpmRequestHeaderLength + sizeof(TPM_PHYSICAL_PRESENCE); 215 Command* cmd = newCommand(TSC_ORD_PhysicalPresence, size); 216 cmd->name = "tpm_pplock_cmd"; 217 AddInitializedField(cmd, kTpmRequestHeaderLength, 218 sizeof(TPM_PHYSICAL_PRESENCE), 219 TPM_PHYSICAL_PRESENCE_LOCK); 220 return cmd; 221 } 222 223 Command* BuildStartupCommand(void) { 224 int size = kTpmRequestHeaderLength + sizeof(TPM_STARTUP_TYPE); 225 Command* cmd = newCommand(TPM_ORD_Startup, size); 226 cmd->name = "tpm_startup_cmd"; 227 AddInitializedField(cmd, kTpmRequestHeaderLength, 228 sizeof(TPM_STARTUP_TYPE), 229 TPM_ST_CLEAR); 230 return cmd; 231 } 232 233 Command* BuildSaveStateCommand(void) { 234 int size = kTpmRequestHeaderLength; 235 Command* cmd = newCommand(TPM_ORD_SaveState, size); 236 cmd->name = "tpm_savestate_cmd"; 237 return cmd; 238 } 239 240 Command* BuildResumeCommand(void) { 241 int size = kTpmRequestHeaderLength + sizeof(TPM_STARTUP_TYPE); 242 Command* cmd = newCommand(TPM_ORD_Startup, size); 243 cmd->name = "tpm_resume_cmd"; 244 AddInitializedField(cmd, kTpmRequestHeaderLength, 245 sizeof(TPM_STARTUP_TYPE), 246 TPM_ST_STATE); 247 return cmd; 248 } 249 250 Command* BuildSelftestfullCommand(void) { 251 int size = kTpmRequestHeaderLength; 252 Command* cmd = newCommand(TPM_ORD_SelfTestFull, size); 253 cmd->name = "tpm_selftestfull_cmd"; 254 return cmd; 255 } 256 257 Command* BuildContinueSelfTestCommand(void) { 258 int size = kTpmRequestHeaderLength; 259 Command* cmd = newCommand(TPM_ORD_ContinueSelfTest, size); 260 cmd->name = "tpm_continueselftest_cmd"; 261 return cmd; 262 } 263 264 Command* BuildReadPubekCommand(void) { 265 int size = kTpmRequestHeaderLength + sizeof(TPM_NONCE); 266 Command* cmd = newCommand(TPM_ORD_ReadPubek, size); 267 cmd->name = "tpm_readpubek_cmd"; 268 return cmd; 269 } 270 271 Command* BuildForceClearCommand(void) { 272 int size = kTpmRequestHeaderLength; 273 Command* cmd = newCommand(TPM_ORD_ForceClear, size); 274 cmd->name = "tpm_forceclear_cmd"; 275 return cmd; 276 } 277 278 Command* BuildPhysicalEnableCommand(void) { 279 int size = kTpmRequestHeaderLength; 280 Command* cmd = newCommand(TPM_ORD_PhysicalEnable, size); 281 cmd->name = "tpm_physicalenable_cmd"; 282 return cmd; 283 } 284 285 Command* BuildPhysicalDisableCommand(void) { 286 int size = kTpmRequestHeaderLength; 287 Command* cmd = newCommand(TPM_ORD_PhysicalDisable, size); 288 cmd->name = "tpm_physicaldisable_cmd"; 289 return cmd; 290 } 291 292 Command* BuildPhysicalSetDeactivatedCommand(void) { 293 int size = kTpmRequestHeaderLength + sizeof(uint8_t); 294 Command* cmd = newCommand(TPM_ORD_PhysicalSetDeactivated, size); 295 cmd->name = "tpm_physicalsetdeactivated_cmd"; 296 AddVisibleField(cmd, "deactivated", kTpmRequestHeaderLength); 297 return cmd; 298 } 299 300 Command* BuildExtendCommand(void) { 301 int size = kTpmRequestHeaderLength + sizeof(uint32_t) + kPcrDigestLength; 302 Command* cmd = newCommand(TPM_ORD_Extend, size); 303 cmd->name = "tpm_extend_cmd"; 304 AddVisibleField(cmd, "pcrNum", kTpmRequestHeaderLength); 305 AddVisibleField(cmd, "inDigest", kTpmRequestHeaderLength + sizeof(uint32_t)); 306 return cmd; 307 } 308 309 Command* BuildGetFlagsCommand(void) { 310 int size = (kTpmRequestHeaderLength + 311 sizeof(TPM_CAPABILITY_AREA) + /* capArea */ 312 sizeof(uint32_t) + /* subCapSize */ 313 sizeof(uint32_t)); /* subCap */ 314 315 Command* cmd = newCommand(TPM_ORD_GetCapability, size); 316 cmd->name = "tpm_getflags_cmd"; 317 AddInitializedField(cmd, kTpmRequestHeaderLength, 318 sizeof(TPM_CAPABILITY_AREA), TPM_CAP_FLAG); 319 AddInitializedField(cmd, kTpmRequestHeaderLength + 320 sizeof(TPM_CAPABILITY_AREA), 321 sizeof(uint32_t), sizeof(uint32_t)); 322 AddInitializedField(cmd, kTpmRequestHeaderLength + 323 sizeof(TPM_CAPABILITY_AREA) + sizeof(uint32_t), 324 sizeof(uint32_t), TPM_CAP_FLAG_PERMANENT); 325 return cmd; 326 } 327 328 Command* BuildGetSTClearFlagsCommand(void) { 329 int size = (kTpmRequestHeaderLength + 330 sizeof(TPM_CAPABILITY_AREA) + /* capArea */ 331 sizeof(uint32_t) + /* subCapSize */ 332 sizeof(uint32_t)); /* subCap */ 333 334 Command* cmd = newCommand(TPM_ORD_GetCapability, size); 335 cmd->name = "tpm_getstclearflags_cmd"; 336 AddInitializedField(cmd, kTpmRequestHeaderLength, 337 sizeof(TPM_CAPABILITY_AREA), TPM_CAP_FLAG); 338 AddInitializedField(cmd, kTpmRequestHeaderLength + 339 sizeof(TPM_CAPABILITY_AREA), 340 sizeof(uint32_t), sizeof(uint32_t)); 341 AddInitializedField(cmd, kTpmRequestHeaderLength + 342 sizeof(TPM_CAPABILITY_AREA) + sizeof(uint32_t), 343 sizeof(uint32_t), TPM_CAP_FLAG_VOLATILE); 344 return cmd; 345 } 346 347 Command* BuildGetPermissionsCommand(void) { 348 int size = (kTpmRequestHeaderLength + 349 sizeof(TPM_CAPABILITY_AREA) + /* capArea */ 350 sizeof(uint32_t) + /* subCapSize */ 351 sizeof(uint32_t)); /* subCap */ 352 353 Command* cmd = newCommand(TPM_ORD_GetCapability, size); 354 cmd->name = "tpm_getpermissions_cmd"; 355 AddInitializedField(cmd, kTpmRequestHeaderLength, 356 sizeof(TPM_CAPABILITY_AREA), TPM_CAP_NV_INDEX); 357 AddInitializedField(cmd, kTpmRequestHeaderLength + 358 sizeof(TPM_CAPABILITY_AREA), 359 sizeof(uint32_t), sizeof(uint32_t)); 360 AddVisibleField(cmd, "index", kTpmRequestHeaderLength + 361 sizeof(TPM_CAPABILITY_AREA) + sizeof(uint32_t)); 362 return cmd; 363 } 364 365 Command* BuildGetOwnershipCommand(void) { 366 int size = (kTpmRequestHeaderLength + 367 sizeof(TPM_CAPABILITY_AREA) + /* capArea */ 368 sizeof(uint32_t) + /* subCapSize */ 369 sizeof(uint32_t)); /* subCap */ 370 371 Command* cmd = newCommand(TPM_ORD_GetCapability, size); 372 cmd->name = "tpm_getownership_cmd"; 373 AddInitializedField(cmd, kTpmRequestHeaderLength, 374 sizeof(TPM_CAPABILITY_AREA), TPM_CAP_PROPERTY); 375 AddInitializedField(cmd, kTpmRequestHeaderLength + 376 sizeof(TPM_CAPABILITY_AREA), 377 sizeof(uint32_t), sizeof(uint32_t)); 378 AddInitializedField(cmd, kTpmRequestHeaderLength + 379 sizeof(TPM_CAPABILITY_AREA) + sizeof(uint32_t), 380 sizeof(uint32_t), TPM_CAP_PROP_OWNER); 381 return cmd; 382 } 383 384 Command* BuildGetRandomCommand(void) { 385 int size = kTpmRequestHeaderLength + sizeof(uint32_t); 386 Command* cmd = newCommand(TPM_ORD_GetRandom, size); 387 cmd->name = "tpm_get_random_cmd"; 388 AddVisibleField(cmd, "bytesRequested", kTpmRequestHeaderLength); 389 return cmd; 390 } 391 392 /* Output the fields of a structure. 393 */ 394 void OutputFields(Field* fld) { 395 /* 396 * Field order is reversed. 397 */ 398 if (fld != NULL) { 399 OutputFields(fld->next); 400 if (fld->visible) { 401 printf(" uint16_t %s;\n", fld->name); 402 } 403 } 404 } 405 406 /* Outputs a structure initializer. 407 */ 408 int OutputBytes_(Command* cmd, Field* fld) { 409 int cursor = 0; 410 int i; 411 /* 412 * Field order is reversed. 413 */ 414 if (fld != NULL) { 415 cursor = OutputBytes_(cmd, fld->next); 416 } else { 417 return 0; 418 } 419 if (!fld->visible) { 420 /* 421 * Catch up missing fields. 422 */ 423 assert(fld->offset >= cursor); 424 for (i = 0; i < fld->offset - cursor; i++) { 425 printf("0, "); 426 } 427 cursor = fld->offset; 428 switch (fld->size) { 429 case 1: 430 printf("0x%x, ", fld->value); 431 cursor += 1; 432 break; 433 case 2: 434 printf("0x%x, 0x%x, ", fld->value >> 8, fld->value & 0xff); 435 cursor += 2; 436 break; 437 case 4: 438 printf("0x%x, 0x%x, 0x%x, 0x%x, ", fld->value >> 24, 439 (fld->value >> 16) & 0xff, 440 (fld->value >> 8) & 0xff, 441 fld->value & 0xff); 442 cursor += 4; 443 break; 444 default: 445 fprintf(stderr, "invalid field size %d\n", fld->size); 446 exit(1); 447 break; 448 } 449 } 450 return cursor; 451 } 452 453 /* Helper to output a structure initializer. 454 */ 455 void OutputBytes(Command* cmd) { 456 (void) OutputBytes_(cmd, cmd->fields); 457 } 458 459 void OutputFieldPointers(Command* cmd, Field* fld) { 460 if (fld == NULL) { 461 return; 462 } else { 463 OutputFieldPointers(cmd, fld->next); 464 if (fld->visible) { 465 printf("%d, ", fld->offset); 466 } 467 } 468 } 469 470 /* Outputs the structure initializers for all commands. 471 */ 472 void OutputCommands(Command* cmd) { 473 if (cmd == NULL) { 474 return; 475 } else { 476 printf("const struct s_%s{\n uint8_t buffer[%d];\n", 477 cmd->name, cmd->size == 0 ? cmd->max_size : cmd->size); 478 OutputFields(cmd->fields); 479 printf("} %s = {{", cmd->name); 480 OutputBytes(cmd); 481 printf("},\n"); 482 OutputFieldPointers(cmd, cmd->fields); 483 printf("};\n\n"); 484 } 485 OutputCommands(cmd->next); 486 } 487 488 Command* (*builders[])(void) = { 489 BuildDefineSpaceCommand, 490 BuildWriteCommand, 491 BuildReadCommand, 492 BuildPCRReadCommand, 493 BuildPPAssertCommand, 494 BuildPPEnableCommand, 495 BuildPPLockCommand, 496 BuildFinalizePPCommand, 497 BuildStartupCommand, 498 BuildSaveStateCommand, 499 BuildResumeCommand, 500 BuildSelftestfullCommand, 501 BuildContinueSelfTestCommand, 502 BuildReadPubekCommand, 503 BuildForceClearCommand, 504 BuildPhysicalDisableCommand, 505 BuildPhysicalEnableCommand, 506 BuildPhysicalSetDeactivatedCommand, 507 BuildGetFlagsCommand, 508 BuildGetSTClearFlagsCommand, 509 BuildGetPermissionsCommand, 510 BuildGetOwnershipCommand, 511 BuildGetRandomCommand, 512 BuildExtendCommand, 513 }; 514 515 static void FreeFields(Field* fld) { 516 if (fld != NULL) { 517 Field* next_field = fld->next; 518 free(fld); 519 FreeFields(next_field); 520 } 521 } 522 523 static void FreeCommands(Command* cmd) { 524 if (cmd != NULL) { 525 Command* next_command = cmd->next; 526 FreeFields(cmd->fields); 527 free(cmd); 528 FreeCommands(next_command); 529 } 530 } 531 532 int main(void) { 533 Command* commands = NULL; 534 int i; 535 for (i = 0; i < sizeof(builders) / sizeof(builders[0]); i++) { 536 Command* cmd = builders[i](); 537 cmd->next = commands; 538 commands = cmd; 539 } 540 541 printf("/* This file is automatically generated */\n\n"); 542 OutputCommands(commands); 543 printf("const int kWriteInfoLength = %d;\n", (int) sizeof(TPM_WRITE_INFO)); 544 printf("const int kNvDataPublicPermissionsOffset = %d;\n", 545 (int) (offsetof(TPM_NV_DATA_PUBLIC, permission) + 546 2 * PCR_SELECTION_FIX + 547 offsetof(TPM_NV_ATTRIBUTES, attributes))); 548 549 FreeCommands(commands); 550 return 0; 551 } 552