• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
AddVisibleField(Command * cmd,const char * name,int offset)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  */
AddInitializedField(Command * cmd,int offset,int size,uint32_t value)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  */
newCommand(TPM_COMMAND_CODE code,int size)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  */
BuildDefineSpaceCommand(void)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  */
BuildWriteCommand(void)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 
BuildReadCommand(void)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 
BuildPCRReadCommand(void)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 
BuildPPAssertCommand(void)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 
BuildPPEnableCommand(void)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 
BuildFinalizePPCommand(void)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 
BuildPPLockCommand(void)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 
BuildStartupCommand(void)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 
BuildSaveStateCommand(void)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 
BuildResumeCommand(void)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 
BuildSelftestfullCommand(void)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 
BuildContinueSelfTestCommand(void)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 
BuildReadPubekCommand(void)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 
BuildForceClearCommand(void)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 
BuildPhysicalEnableCommand(void)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 
BuildPhysicalDisableCommand(void)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 
BuildPhysicalSetDeactivatedCommand(void)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 
BuildExtendCommand(void)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 
BuildGetFlagsCommand(void)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 
BuildGetSTClearFlagsCommand(void)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 
BuildGetPermissionsCommand(void)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 
BuildGetOwnershipCommand(void)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 
BuildGetRandomCommand(void)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  */
OutputFields(Field * fld)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  */
OutputBytes_(Command * cmd,Field * fld)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  */
OutputBytes(Command * cmd)455 void OutputBytes(Command* cmd) {
456   (void) OutputBytes_(cmd, cmd->fields);
457 }
458 
OutputFieldPointers(Command * cmd,Field * fld)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  */
OutputCommands(Command * cmd)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 
FreeFields(Field * fld)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 
FreeCommands(Command * cmd)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 
main(void)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