OLD | NEW |
(Empty) | |
| 1 /* Copyright (c) 2010 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 <stddef.h> |
| 15 #include <stdio.h> |
| 16 #include <stdlib.h> |
| 17 #include <tss/tcs.h> |
| 18 |
| 19 #include "tlcl.h" |
| 20 #include "tlcl_internal.h" |
| 21 #include "tpmextras.h" |
| 22 #include "utility.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*) Malloc(sizeof(Field)); |
| 58 if (cmd->fields != NULL) { |
| 59 Field* fn = cmd->fields; |
| 60 assert(offset > fn->offset); |
| 61 } |
| 62 fld->next = cmd->fields; |
| 63 cmd->fields = fld; |
| 64 fld->name = name; |
| 65 fld->visible = 1; |
| 66 fld->offset = offset; |
| 67 } |
| 68 |
| 69 /* Adds a constant field with its value. The fields must be added at |
| 70 * increasing offsets. |
| 71 */ |
| 72 static void AddInitializedField(Command* cmd, int offset, |
| 73 int size, uint32_t value) { |
| 74 Field* fld = (Field*) Malloc(sizeof(Field)); |
| 75 fld->next = cmd->fields; |
| 76 cmd->fields = fld; |
| 77 fld->name = NULL; |
| 78 fld->visible = 0; |
| 79 fld->size = size; |
| 80 fld->offset = offset; |
| 81 fld->value = value; |
| 82 } |
| 83 |
| 84 /* Create a structure representing a TPM command datagram. |
| 85 */ |
| 86 Command* newCommand(TPM_COMMAND_CODE code, int size) { |
| 87 Command* cmd = (Command*) Malloc(sizeof(Command)); |
| 88 cmd->size = size; |
| 89 AddInitializedField(cmd, 0, sizeof(TPM_TAG), TPM_TAG_RQU_COMMAND); |
| 90 AddInitializedField(cmd, sizeof(TPM_TAG), sizeof(uint32_t), size); |
| 91 AddInitializedField(cmd, sizeof(TPM_TAG) + sizeof(uint32_t), |
| 92 sizeof(TPM_COMMAND_CODE), code); |
| 93 return cmd; |
| 94 } |
| 95 |
| 96 /* The TPM_PCR_SELECTION structure in /usr/include/tss/tpm.h contains a pointer |
| 97 * instead of an array[3] of bytes, so we need to adjust sizes and offsets |
| 98 * accordingly. |
| 99 */ |
| 100 #define PCR_SELECTION_FIX (3 - sizeof(char *)) |
| 101 |
| 102 /* BuildXXX builds TPM command XXX. |
| 103 */ |
| 104 Command* BuildDefineSpaceCommand(void) { |
| 105 int nv_data_public = kTpmRequestHeaderLength; |
| 106 int nv_index = nv_data_public + offsetof(TPM_NV_DATA_PUBLIC, nvIndex); |
| 107 int nv_pcr_info_read = nv_data_public + |
| 108 offsetof(TPM_NV_DATA_PUBLIC, pcrInfoRead); |
| 109 /* |
| 110 * Here we need to carefully add PCR_SELECTION_FIX (or twice that much) in |
| 111 * all the places where the offset calculation would be wrong without it. |
| 112 * The mismatch occurs in the TPM_PCR_SELECTION structure, and it must be |
| 113 * accounted for in all the structures that include it, directly or |
| 114 * indirectly. |
| 115 */ |
| 116 int read_locality = nv_pcr_info_read + |
| 117 offsetof(TPM_PCR_INFO_SHORT, localityAtRelease) + PCR_SELECTION_FIX; |
| 118 int nv_pcr_info_write = nv_data_public + |
| 119 offsetof(TPM_NV_DATA_PUBLIC, pcrInfoWrite) + PCR_SELECTION_FIX; |
| 120 int write_locality = nv_pcr_info_write + |
| 121 offsetof(TPM_PCR_INFO_SHORT, localityAtRelease) + PCR_SELECTION_FIX; |
| 122 int nv_permission = nv_data_public + |
| 123 offsetof(TPM_NV_DATA_PUBLIC, permission) + 2 * PCR_SELECTION_FIX; |
| 124 int nv_permission_tag = |
| 125 nv_permission + offsetof(TPM_NV_ATTRIBUTES, tag); |
| 126 int nv_permission_attributes = |
| 127 nv_permission + offsetof(TPM_NV_ATTRIBUTES, attributes); |
| 128 int nv_datasize = nv_data_public + |
| 129 offsetof(TPM_NV_DATA_PUBLIC, dataSize) + 2 * PCR_SELECTION_FIX; |
| 130 |
| 131 int size = kTpmRequestHeaderLength + sizeof(TPM_NV_DATA_PUBLIC) + |
| 132 2 * PCR_SELECTION_FIX + kEncAuthLength; |
| 133 Command* cmd = newCommand(TPM_ORD_NV_DefineSpace, size); |
| 134 cmd->name = "tpm_nv_definespace_cmd"; |
| 135 |
| 136 AddVisibleField(cmd, "index", nv_index); |
| 137 AddVisibleField(cmd, "perm", nv_permission_attributes); |
| 138 AddVisibleField(cmd, "size", nv_datasize); |
| 139 |
| 140 AddInitializedField(cmd, nv_data_public, sizeof(uint16_t), |
| 141 TPM_TAG_NV_DATA_PUBLIC); |
| 142 AddInitializedField(cmd, nv_pcr_info_read, sizeof(uint16_t), 3); |
| 143 AddInitializedField(cmd, read_locality, sizeof(TPM_LOCALITY_SELECTION), |
| 144 TPM_ALL_LOCALITIES); |
| 145 AddInitializedField(cmd, nv_pcr_info_write, sizeof(uint16_t), 3); |
| 146 AddInitializedField(cmd, write_locality, sizeof(TPM_LOCALITY_SELECTION), |
| 147 TPM_ALL_LOCALITIES); |
| 148 AddInitializedField(cmd, nv_permission_tag, sizeof(TPM_STRUCTURE_TAG), |
| 149 TPM_TAG_NV_ATTRIBUTES); |
| 150 return cmd; |
| 151 } |
| 152 |
| 153 /* BuildXXX builds TPM command XXX. |
| 154 */ |
| 155 Command* BuildWriteCommand(void) { |
| 156 Command* cmd = newCommand(TPM_ORD_NV_WriteValue, 0); |
| 157 cmd->name = "tpm_nv_write_cmd"; |
| 158 cmd->max_size = TPM_LARGE_ENOUGH_COMMAND_SIZE; |
| 159 AddVisibleField(cmd, "index", kTpmRequestHeaderLength); |
| 160 AddVisibleField(cmd, "length", kTpmRequestHeaderLength + 8); |
| 161 AddVisibleField(cmd, "data", kTpmRequestHeaderLength + 12); |
| 162 return cmd; |
| 163 } |
| 164 |
| 165 Command* BuildReadCommand(void) { |
| 166 int size = kTpmRequestHeaderLength + kTpmReadInfoLength; |
| 167 Command* cmd = newCommand(TPM_ORD_NV_ReadValue, size); |
| 168 cmd->name = "tpm_nv_read_cmd"; |
| 169 AddVisibleField(cmd, "index", kTpmRequestHeaderLength); |
| 170 AddVisibleField(cmd, "length", kTpmRequestHeaderLength + 8); |
| 171 return cmd; |
| 172 } |
| 173 |
| 174 Command* BuildPPAssertCommand(void) { |
| 175 int size = kTpmRequestHeaderLength + sizeof(TPM_PHYSICAL_PRESENCE); |
| 176 Command* cmd = newCommand(TSC_ORD_PhysicalPresence, size); |
| 177 cmd->name = "tpm_ppassert_cmd"; |
| 178 AddInitializedField(cmd, kTpmRequestHeaderLength, |
| 179 sizeof(TPM_PHYSICAL_PRESENCE), |
| 180 TPM_PHYSICAL_PRESENCE_PRESENT); |
| 181 return cmd; |
| 182 } |
| 183 |
| 184 Command* BuildPPLockCommand(void) { |
| 185 int size = kTpmRequestHeaderLength + sizeof(TPM_PHYSICAL_PRESENCE); |
| 186 Command* cmd = newCommand(TSC_ORD_PhysicalPresence, size); |
| 187 cmd->name = "tpm_pplock_cmd"; |
| 188 AddInitializedField(cmd, kTpmRequestHeaderLength, |
| 189 sizeof(TPM_PHYSICAL_PRESENCE), |
| 190 TPM_PHYSICAL_PRESENCE_LOCK); |
| 191 return cmd; |
| 192 } |
| 193 |
| 194 Command* BuildStartupCommand(void) { |
| 195 int size = kTpmRequestHeaderLength + sizeof(TPM_PHYSICAL_PRESENCE); |
| 196 Command* cmd = newCommand(TPM_ORD_Startup, size); |
| 197 cmd->name = "tpm_startup_cmd"; |
| 198 AddInitializedField(cmd, kTpmRequestHeaderLength, |
| 199 sizeof(TPM_STARTUP_TYPE), |
| 200 TPM_ST_CLEAR); |
| 201 return cmd; |
| 202 } |
| 203 |
| 204 Command* BuildSelftestfullCommand(void) { |
| 205 int size = kTpmRequestHeaderLength; |
| 206 Command* cmd = newCommand(TPM_ORD_SelfTestFull, size); |
| 207 cmd->name = "tpm_selftestfull_cmd"; |
| 208 return cmd; |
| 209 } |
| 210 |
| 211 Command* BuildContinueSelfTestCommand(void) { |
| 212 int size = kTpmRequestHeaderLength; |
| 213 Command* cmd = newCommand(TPM_ORD_ContinueSelfTest, size); |
| 214 cmd->name = "tpm_continueselftest_cmd"; |
| 215 return cmd; |
| 216 } |
| 217 |
| 218 Command* BuildReadPubekCommand(void) { |
| 219 int size = kTpmRequestHeaderLength + sizeof(TPM_NONCE); |
| 220 Command* cmd = newCommand(TPM_ORD_ReadPubek, size); |
| 221 cmd->name = "tpm_readpubek_cmd"; |
| 222 return cmd; |
| 223 } |
| 224 |
| 225 Command* BuildForceClearCommand(void) { |
| 226 int size = kTpmRequestHeaderLength; |
| 227 Command* cmd = newCommand(TPM_ORD_ForceClear, size); |
| 228 cmd->name = "tpm_forceclear_cmd"; |
| 229 return cmd; |
| 230 } |
| 231 |
| 232 Command* BuildPhysicalEnableCommand(void) { |
| 233 int size = kTpmRequestHeaderLength; |
| 234 Command* cmd = newCommand(TPM_ORD_PhysicalEnable, size); |
| 235 cmd->name = "tpm_physicalenable_cmd"; |
| 236 return cmd; |
| 237 } |
| 238 |
| 239 Command* BuildPhysicalDisableCommand(void) { |
| 240 int size = kTpmRequestHeaderLength; |
| 241 Command* cmd = newCommand(TPM_ORD_PhysicalDisable, size); |
| 242 cmd->name = "tpm_physicaldisable_cmd"; |
| 243 return cmd; |
| 244 } |
| 245 |
| 246 Command* BuildPhysicalSetDeactivatedCommand(void) { |
| 247 int size = kTpmRequestHeaderLength + sizeof(uint8_t); |
| 248 Command* cmd = newCommand(TPM_ORD_PhysicalSetDeactivated, size); |
| 249 cmd->name = "tpm_physicalsetdeactivated_cmd"; |
| 250 AddVisibleField(cmd, "deactivated", kTpmRequestHeaderLength); |
| 251 return cmd; |
| 252 } |
| 253 |
| 254 Command* BuildExtendCommand(void) { |
| 255 int size = kTpmRequestHeaderLength + sizeof(uint32_t) + kPcrDigestLength; |
| 256 Command* cmd = newCommand(TPM_ORD_Extend, size); |
| 257 cmd->name = "tpm_extend_cmd"; |
| 258 AddVisibleField(cmd, "pcrNum", kTpmRequestHeaderLength); |
| 259 AddVisibleField(cmd, "inDigest", kTpmRequestHeaderLength + sizeof(uint32_t)); |
| 260 return cmd; |
| 261 } |
| 262 |
| 263 Command* BuildGetFlagsCommand(void) { |
| 264 int size = (kTpmRequestHeaderLength + |
| 265 sizeof(TPM_CAPABILITY_AREA) + /* capArea */ |
| 266 sizeof(uint32_t) + /* subCapSize */ |
| 267 sizeof(uint32_t)); /* subCap */ |
| 268 |
| 269 Command* cmd = newCommand(TPM_ORD_GetCapability, size); |
| 270 cmd->name = "tpm_getflags_cmd"; |
| 271 AddInitializedField(cmd, kTpmRequestHeaderLength, |
| 272 sizeof(TPM_CAPABILITY_AREA), TPM_CAP_FLAG); |
| 273 AddInitializedField(cmd, kTpmRequestHeaderLength + |
| 274 sizeof(TPM_CAPABILITY_AREA), |
| 275 sizeof(uint32_t), sizeof(uint32_t)); |
| 276 AddInitializedField(cmd, kTpmRequestHeaderLength + |
| 277 sizeof(TPM_CAPABILITY_AREA) + sizeof(uint32_t), |
| 278 sizeof(uint32_t), TPM_CAP_FLAG_PERMANENT); |
| 279 return cmd; |
| 280 } |
| 281 |
| 282 Command* BuildGetPermissionsCommand(void) { |
| 283 int size = (kTpmRequestHeaderLength + |
| 284 sizeof(TPM_CAPABILITY_AREA) + /* capArea */ |
| 285 sizeof(uint32_t) + /* subCapSize */ |
| 286 sizeof(uint32_t)); /* subCap */ |
| 287 |
| 288 Command* cmd = newCommand(TPM_ORD_GetCapability, size); |
| 289 cmd->name = "tpm_getpermissions_cmd"; |
| 290 AddInitializedField(cmd, kTpmRequestHeaderLength, |
| 291 sizeof(TPM_CAPABILITY_AREA), TPM_CAP_NV_INDEX); |
| 292 AddInitializedField(cmd, kTpmRequestHeaderLength + |
| 293 sizeof(TPM_CAPABILITY_AREA), |
| 294 sizeof(uint32_t), sizeof(uint32_t)); |
| 295 AddVisibleField(cmd, "index", kTpmRequestHeaderLength + |
| 296 sizeof(TPM_CAPABILITY_AREA) + sizeof(uint32_t)); |
| 297 return cmd; |
| 298 } |
| 299 |
| 300 /* Output the fields of a structure. |
| 301 */ |
| 302 void OutputFields(Field* fld) { |
| 303 /* |
| 304 * Field order is reversed. |
| 305 */ |
| 306 if (fld != NULL) { |
| 307 OutputFields(fld->next); |
| 308 if (fld->visible) { |
| 309 printf(" uint8_t* %s;\n", fld->name); |
| 310 } |
| 311 } |
| 312 } |
| 313 |
| 314 /* Outputs a structure initializer. |
| 315 */ |
| 316 int OutputBytes_(Command* cmd, Field* fld) { |
| 317 int cursor = 0; |
| 318 int i; |
| 319 /* |
| 320 * Field order is reversed. |
| 321 */ |
| 322 if (fld != NULL) { |
| 323 cursor = OutputBytes_(cmd, fld->next); |
| 324 } else { |
| 325 return 0; |
| 326 } |
| 327 if (!fld->visible) { |
| 328 /* |
| 329 * Catch up missing fields. |
| 330 */ |
| 331 assert(fld->offset >= cursor); |
| 332 for (i = 0; i < fld->offset - cursor; i++) { |
| 333 printf("0, "); |
| 334 } |
| 335 cursor = fld->offset; |
| 336 switch (fld->size) { |
| 337 case 1: |
| 338 printf("0x%x, ", fld->value); |
| 339 cursor += 1; |
| 340 break; |
| 341 case 2: |
| 342 printf("0x%x, 0x%x, ", fld->value >> 8, fld->value & 0xff); |
| 343 cursor += 2; |
| 344 break; |
| 345 case 4: |
| 346 printf("0x%x, 0x%x, 0x%x, 0x%x, ", fld->value >> 24, |
| 347 (fld->value >> 16) & 0xff, |
| 348 (fld->value >> 8) & 0xff, |
| 349 fld->value & 0xff); |
| 350 cursor += 4; |
| 351 break; |
| 352 default: |
| 353 error("invalid field size %d\n", fld->size); |
| 354 break; |
| 355 } |
| 356 } |
| 357 return cursor; |
| 358 } |
| 359 |
| 360 /* Helper to output a structure initializer. |
| 361 */ |
| 362 void OutputBytes(Command* cmd) { |
| 363 (void) OutputBytes_(cmd, cmd->fields); |
| 364 } |
| 365 |
| 366 void OutputFieldPointers(Command* cmd, Field* fld) { |
| 367 if (fld == NULL) { |
| 368 return; |
| 369 } else { |
| 370 OutputFieldPointers(cmd, fld->next); |
| 371 if (fld->visible) { |
| 372 printf("%s.buffer + %d, ", cmd->name, fld->offset); |
| 373 } |
| 374 } |
| 375 } |
| 376 |
| 377 /* Outputs the structure initializers for all commands. |
| 378 */ |
| 379 void OutputCommands(Command* cmd) { |
| 380 if (cmd == NULL) { |
| 381 return; |
| 382 } else { |
| 383 printf("struct {\n uint8_t buffer[%d];\n", |
| 384 cmd->size == 0 ? cmd->max_size : cmd->size); |
| 385 OutputFields(cmd->fields); |
| 386 printf("} %s = {{", cmd->name); |
| 387 OutputBytes(cmd); |
| 388 printf("},\n"); |
| 389 OutputFieldPointers(cmd, cmd->fields); |
| 390 printf("};\n\n"); |
| 391 } |
| 392 OutputCommands(cmd->next); |
| 393 } |
| 394 |
| 395 Command* (*builders[])(void) = { |
| 396 BuildDefineSpaceCommand, |
| 397 BuildWriteCommand, |
| 398 BuildReadCommand, |
| 399 BuildPPAssertCommand, |
| 400 BuildPPLockCommand, |
| 401 BuildStartupCommand, |
| 402 BuildSelftestfullCommand, |
| 403 BuildContinueSelfTestCommand, |
| 404 BuildReadPubekCommand, |
| 405 BuildForceClearCommand, |
| 406 BuildPhysicalDisableCommand, |
| 407 BuildPhysicalEnableCommand, |
| 408 BuildPhysicalSetDeactivatedCommand, |
| 409 BuildGetFlagsCommand, |
| 410 BuildGetPermissionsCommand, |
| 411 BuildExtendCommand, |
| 412 }; |
| 413 |
| 414 static void FreeFields(Field* fld) { |
| 415 if (fld != NULL) { |
| 416 Field* next_field = fld->next; |
| 417 Free(fld); |
| 418 FreeFields(next_field); |
| 419 } |
| 420 } |
| 421 |
| 422 static void FreeCommands(Command* cmd) { |
| 423 if (cmd != NULL) { |
| 424 Command* next_command = cmd->next; |
| 425 Free(cmd); |
| 426 FreeFields(cmd->fields); |
| 427 FreeCommands(next_command); |
| 428 } |
| 429 } |
| 430 |
| 431 int main(void) { |
| 432 Command* commands = NULL; |
| 433 int i; |
| 434 for (i = 0; i < sizeof(builders) / sizeof(builders[0]); i++) { |
| 435 Command* cmd = builders[i](); |
| 436 cmd->next = commands; |
| 437 commands = cmd; |
| 438 } |
| 439 |
| 440 printf("/* This file is automatically generated */\n\n"); |
| 441 OutputCommands(commands); |
| 442 printf("const int kWriteInfoLength = %d;\n", (int) sizeof(TPM_WRITE_INFO)); |
| 443 printf("const int kNvDataPublicPermissionsOffset = %d;\n", |
| 444 (int) (offsetof(TPM_NV_DATA_PUBLIC, permission) + |
| 445 2 * PCR_SELECTION_FIX + |
| 446 offsetof(TPM_NV_ATTRIBUTES, attributes))); |
| 447 |
| 448 FreeCommands(commands); |
| 449 return 0; |
| 450 } |
OLD | NEW |