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 */
30typedef 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 */
45typedef 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 */
56static 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 */
71static 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 */
85Command* 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 */
103Command* 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 */
154Command* 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
164Command* 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
173Command* 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
181Command* 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
191Command* 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
201Command* 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
213Command* 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
223Command* 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
233Command* 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
240Command* 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
250Command* 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
257Command* 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
264Command* 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
271Command* 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
278Command* 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
285Command* 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
292Command* 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
300Command* 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
309Command* 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
328Command* 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
347Command* 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
365Command* 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
384Command* 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 */
394void 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 */
408int 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 */
455void OutputBytes(Command* cmd) {
456  (void) OutputBytes_(cmd, cmd->fields);
457}
458
459void 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 */
472void 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
488Command* (*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
515static void FreeFields(Field* fld) {
516  if (fld != NULL) {
517    Field* next_field = fld->next;
518    free(fld);
519    FreeFields(next_field);
520  }
521}
522
523static 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
532int 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