1 /********************************************************************************/
2 /* */
3 /* Extend an EVENT measurement file into PCRs */
4 /* Written by Ken Goldman */
5 /* IBM Thomas J. Watson Research Center */
6 /* */
7 /* (c) Copyright IBM Corporation 2016 - 2019. */
8 /* */
9 /* All rights reserved. */
10 /* */
11 /* Redistribution and use in source and binary forms, with or without */
12 /* modification, are permitted provided that the following conditions are */
13 /* met: */
14 /* */
15 /* Redistributions of source code must retain the above copyright notice, */
16 /* this list of conditions and the following disclaimer. */
17 /* */
18 /* Redistributions in binary form must reproduce the above copyright */
19 /* notice, this list of conditions and the following disclaimer in the */
20 /* documentation and/or other materials provided with the distribution. */
21 /* */
22 /* Neither the names of the IBM Corporation nor the names of its */
23 /* contributors may be used to endorse or promote products derived from */
24 /* this software without specific prior written permission. */
25 /* */
26 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
27 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
28 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */
29 /* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
30 /* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
31 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
32 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */
33 /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */
34 /* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
35 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */
36 /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
37 /********************************************************************************/
38
39 /* eventextend is test/demo code. It parses a TPM2 event log file and extends the measurements into
40 TPM PCRs or simulated PCRs. This simulates the actions that would be performed by BIOS /
41 firmware in a hardware platform. */
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46
47 #include <ibmtss/tss.h>
48 #include <ibmtss/tssresponsecode.h>
49 #include <ibmtss/tsscryptoh.h>
50
51 #include "eventlib.h"
52
53 /* local prototypes */
54
55 static void printUsage(void);
56
57 extern int tssUtilsVerbose;
58
main(int argc,char * argv[])59 int main(int argc, char * argv[])
60 {
61 TPM_RC rc = 0;
62 int i = 0;
63 TSS_CONTEXT *tssContext = NULL;
64 const char *infilename = NULL;
65 FILE *infile = NULL;
66 int tpm = FALSE; /* extend into TPM */
67 int sim = FALSE; /* extend into simulated PCRs */
68 int nospec = FALSE; /* event log does not start with spec file */
69 int noSpace = FALSE;
70 uint32_t bankNum = 0; /* PCR hash bank */
71 unsigned int pcrNum = 0; /* PCR number iterator */
72 TPMI_DH_PCR pcrMax = 7;
73 TPMT_HA simPcrs[HASH_COUNT][IMPLEMENTATION_PCR];
74 TPMT_HA bootAggregates[HASH_COUNT];
75 TCG_PCR_EVENT2 event2; /* TPM 2.0 event log entry */
76 TCG_PCR_EVENT event; /* TPM 1.2 event log entry */
77 TCG_EfiSpecIDEvent specIdEvent;
78 unsigned int lineNum;
79 int endOfFile = FALSE;
80
81 setvbuf(stdout, 0, _IONBF, 0); /* output may be going through pipe to log file */
82 TSS_SetProperty(NULL, TPM_TRACE_LEVEL, "1");
83 tssUtilsVerbose = FALSE;
84
85 for (i=1 ; i<argc ; i++) {
86 if (strcmp(argv[i],"-if") == 0) {
87 i++;
88 if (i < argc) {
89 infilename = argv[i];
90 }
91 else {
92 printf("-if option needs a value\n");
93 printUsage();
94 exit(2);
95 }
96 }
97 else if (strcmp(argv[i],"-tpm") == 0) {
98 tpm = TRUE;
99 }
100 else if (strcmp(argv[i],"-nospec") == 0) {
101 nospec = TRUE;
102 }
103 else if (strcmp(argv[i],"-sim") == 0) {
104 sim = TRUE;
105 }
106 else if (strcmp(argv[i],"-ns") == 0) {
107 noSpace = TRUE;
108 }
109 else if (strcmp(argv[i],"-pcrmax") == 0) {
110 i++;
111 if (i < argc) {
112 sscanf(argv[i],"%u", &pcrMax);
113 }
114 else {
115 printf("Missing parameter for -pcrmax");
116 printUsage();
117 }
118 }
119 else if (!strcmp(argv[i], "-h")) {
120 printUsage();
121 }
122 else if (!strcmp(argv[i], "-v")) {
123 tssUtilsVerbose = TRUE;
124 TSS_SetProperty(NULL, TPM_TRACE_LEVEL, "2");
125 }
126 else {
127 printf("\n%s is not a valid option\n", argv[i]);
128 printUsage();
129 }
130 }
131 if (infilename == NULL) {
132 printf("Missing -if argument\n");
133 printUsage();
134 }
135 if (!tpm && !sim) {
136 printf("-tpm or -sim must be specified\n");
137 printUsage();
138 }
139 if (sim && nospec) {
140 printf("-sim incompatible with -nospec\n");
141 printUsage();
142 }
143 /*
144 ** read the event log file
145 */
146 infile = fopen(infilename,"rb");
147 if (infile == NULL) {
148 printf("Unable to open input file '%s'\n", infilename);
149 exit(-4);
150 }
151 /* the first event is a TPM 1.2 format event */
152 /* read an event line */
153 if ((rc == 0) && !nospec) {
154 rc = TSS_EVENT_Line_Read(&event, &endOfFile, infile);
155 }
156 /* debug tracing */
157 if ((rc == 0) && !nospec && !endOfFile && tssUtilsVerbose) {
158 printf("\neventextend: line 0\n");
159 TSS_EVENT_Line_Trace(&event);
160 }
161 /* parse the event, populates the TCG_EfiSpecIDEvent structure */
162 if ((rc == 0) && !nospec && !endOfFile) {
163 rc = TSS_SpecIdEvent_Unmarshal(&specIdEvent,
164 event.eventDataSize, event.event);
165 }
166 /* range check numberOfAlgorithms before the trace */
167 if ((rc == 0) && !nospec && !endOfFile) {
168 if (specIdEvent.numberOfAlgorithms > HASH_COUNT) {
169 printf("specIdEvent.numberOfAlgorithms %u greater than %u\n",
170 specIdEvent.numberOfAlgorithms, HASH_COUNT);
171 rc = TSS_RC_BAD_PROPERTY_VALUE;
172 }
173 }
174 /* trace the specIdEvent event */
175 if ((rc == 0) && !nospec && !endOfFile && tssUtilsVerbose) {
176 TSS_SpecIdEvent_Trace(&specIdEvent);
177 }
178 /* Start a TSS context */
179 if ((rc == 0) && tpm) {
180 rc = TSS_Create(&tssContext);
181 }
182 /* initialize simulated PCRs */
183 if ((rc == 0) && sim) {
184 if (specIdEvent.numberOfAlgorithms > HASH_COUNT) {
185 printf("specIdEvent.numberOfAlgorithms %u greater than %u\n",
186 specIdEvent.numberOfAlgorithms, HASH_COUNT);
187 rc = TSS_RC_BAD_PROPERTY_VALUE;
188 }
189 }
190 /* simulated BIOS PCRs start at zero at boot */
191 if ((rc == 0) && sim) {
192 for (bankNum = 0 ; bankNum < specIdEvent.numberOfAlgorithms ; bankNum++) {
193 bootAggregates[bankNum].hashAlg = specIdEvent.digestSizes[bankNum].algorithmId;
194 for (pcrNum = 0 ; pcrNum < IMPLEMENTATION_PCR ; pcrNum++) {
195 /* initialize each algorithm ID based on the specIdEvent */
196 simPcrs[bankNum][pcrNum].hashAlg = specIdEvent.digestSizes[bankNum].algorithmId;
197 memset(&simPcrs[bankNum][pcrNum].digest.tssmax, 0, sizeof(TPMU_HA));
198 }
199 }
200 }
201 /* scan each measurement 'line' in the binary */
202 for (lineNum = 1 ; (rc == 0) && !endOfFile ; lineNum++) {
203
204 /* read a TPM 2.0 hash agile event line */
205 if (rc == 0) {
206 rc = TSS_EVENT2_Line_Read(&event2, &endOfFile, infile);
207 }
208 /* debug tracing */
209 if ((rc == 0) && !endOfFile && tssUtilsVerbose) {
210 printf("\neventextend: line %u\n", lineNum);
211 TSS_EVENT2_Line_Trace(&event2);
212 }
213 /* don't extend no action events */
214 if ((rc == 0) && !endOfFile) {
215 if (event2.eventType == EV_NO_ACTION) {
216 continue;
217 }
218 }
219 if ((rc == 0) && !endOfFile && tpm) { /* extend TPM */
220 PCR_Extend_In in;
221 PCR_Read_In pcrReadIn;
222 PCR_Read_Out pcrReadOut;
223
224 if (rc == 0) {
225 in.pcrHandle = event2.pcrIndex;
226 in.digests = event2.digests;
227 rc = TSS_Execute(tssContext,
228 NULL,
229 (COMMAND_PARAMETERS *)&in,
230 NULL,
231 TPM_CC_PCR_Extend,
232 TPM_RS_PW, NULL, 0,
233 TPM_RH_NULL, NULL, 0);
234 }
235 /* for debug, read back and trace the PCR value after the extend */
236 if ((rc == 0) && tssUtilsVerbose) {
237 pcrReadIn.pcrSelectionIn.count = 1;
238 pcrReadIn.pcrSelectionIn.pcrSelections[0].hash =
239 event2.digests.digests[0].hashAlg;
240 pcrReadIn.pcrSelectionIn.pcrSelections[0].sizeofSelect = 3;
241 pcrReadIn.pcrSelectionIn.pcrSelections[0].pcrSelect[0] = 0;
242 pcrReadIn.pcrSelectionIn.pcrSelections[0].pcrSelect[1] = 0;
243 pcrReadIn.pcrSelectionIn.pcrSelections[0].pcrSelect[2] = 0;
244 pcrReadIn.pcrSelectionIn.pcrSelections[0].pcrSelect[event2.pcrIndex / 8] =
245 1 << (event2.pcrIndex % 8);
246
247 rc = TSS_Execute(tssContext,
248 (RESPONSE_PARAMETERS *)&pcrReadOut,
249 (COMMAND_PARAMETERS *)&pcrReadIn,
250 NULL,
251 TPM_CC_PCR_Read,
252 TPM_RH_NULL, NULL, 0);
253 }
254 if ((rc == 0) && tssUtilsVerbose) {
255 TSS_PrintAll("PCR digest",
256 pcrReadOut.pcrValues.digests[0].t.buffer,
257 pcrReadOut.pcrValues.digests[0].t.size);
258 }
259 }
260 if ((rc == 0) && !endOfFile && sim) { /* extend simulated PCRs */
261 rc = TSS_EVENT2_PCR_Extend(simPcrs, &event2);
262 }
263 }
264 {
265 if (tpm) {
266 TPM_RC rc1 = TSS_Delete(tssContext);
267 if (rc == 0) {
268 rc = rc1;
269 }
270 }
271 }
272 if ((rc == 0) && sim) {
273 for (bankNum = 0 ; (rc == 0) && (bankNum < specIdEvent.numberOfAlgorithms) ; bankNum++) {
274 /* trace the virtual PCRs */
275 if (rc == 0) {
276 char pcrString[9]; /* PCR number */
277
278 printf("\n");
279 TSS_TPM_ALG_ID_Print("algorithmId", specIdEvent.digestSizes[bankNum].algorithmId, 0);
280 for (pcrNum = 0 ; pcrNum < IMPLEMENTATION_PCR ; pcrNum++) {
281 sprintf(pcrString, "PCR %02u:", pcrNum);
282 if (!noSpace) {
283 /* TSS_PrintAllLogLevel() with a log level of LOGLEVEL_INFO to print the byte
284 array on one line with no length */
285 TSS_PrintAllLogLevel(LOGLEVEL_INFO, pcrString, 1,
286 simPcrs[bankNum][pcrNum].digest.tssmax,
287 specIdEvent.digestSizes[bankNum].digestSize);
288 }
289 else { /* print with no spaces */
290 uint32_t bp;
291 printf("PCR %02u: ", pcrNum);
292 for (bp = 0 ; bp < specIdEvent.digestSizes[bankNum].digestSize ; bp++) {
293 printf("%02x", simPcrs[bankNum][pcrNum].digest.tssmax[bp]);
294 }
295 printf("\n");
296 }
297 }
298 }
299 /* calculate the boot aggregate, hash of PCR 0-7 */
300 if (rc == 0) {
301 int length[IMPLEMENTATION_PCR];
302 size_t j;
303 for (j = 0 ; j < IMPLEMENTATION_PCR ; j++) {
304 if (j <= pcrMax) { /* include PCRs up to here */
305 length[j] = specIdEvent.digestSizes[bankNum].digestSize;
306 }
307 else {
308 length[j] = 0; /* exclude PCRs after to here */
309 }
310 }
311 rc = TSS_Hash_Generate(&bootAggregates[bankNum],
312 length[0], &simPcrs[bankNum][0].digest.tssmax,
313 length[1], &simPcrs[bankNum][1].digest.tssmax,
314 length[2], &simPcrs[bankNum][2].digest.tssmax,
315 length[3], &simPcrs[bankNum][3].digest.tssmax,
316 length[4], &simPcrs[bankNum][4].digest.tssmax,
317 length[5], &simPcrs[bankNum][5].digest.tssmax,
318 length[6], &simPcrs[bankNum][6].digest.tssmax,
319 length[7], &simPcrs[bankNum][7].digest.tssmax,
320 length[8], &simPcrs[bankNum][8].digest.tssmax,
321 length[9], &simPcrs[bankNum][9].digest.tssmax,
322 length[10], &simPcrs[bankNum][10].digest.tssmax,
323 length[11], &simPcrs[bankNum][11].digest.tssmax,
324 length[12], &simPcrs[bankNum][12].digest.tssmax,
325 length[13], &simPcrs[bankNum][13].digest.tssmax,
326 length[14], &simPcrs[bankNum][14].digest.tssmax,
327 length[15], &simPcrs[bankNum][15].digest.tssmax,
328 length[16], &simPcrs[bankNum][16].digest.tssmax,
329 length[17], &simPcrs[bankNum][17].digest.tssmax,
330 length[18], &simPcrs[bankNum][18].digest.tssmax,
331 length[19], &simPcrs[bankNum][19].digest.tssmax,
332 length[20], &simPcrs[bankNum][20].digest.tssmax,
333 length[21], &simPcrs[bankNum][21].digest.tssmax,
334 length[22], &simPcrs[bankNum][22].digest.tssmax,
335 length[23], &simPcrs[bankNum][23].digest.tssmax,
336 0, NULL);
337 }
338 /* trace the boot aggregate */
339 if (rc == 0) {
340 if (!noSpace) {
341 TSS_PrintAllLogLevel(LOGLEVEL_INFO, "\nboot aggregate:", 1,
342 bootAggregates[bankNum].digest.tssmax,
343 specIdEvent.digestSizes[bankNum].digestSize);
344 }
345 else { /* print with no spaces */
346 uint32_t bp;
347 printf("\nboot aggregate: ");
348 for (bp = 0 ; bp < specIdEvent.digestSizes[bankNum].digestSize ; bp++) {
349 printf("%02x", bootAggregates[bankNum].digest.tssmax[bp]);
350 }
351 printf("\n");
352 }
353 }
354 }
355 }
356 if (rc == 0) {
357 if (tssUtilsVerbose) printf("eventextend: success\n");
358 }
359 else {
360 const char *msg;
361 const char *submsg;
362 const char *num;
363 printf("eventextend: failed, rc %08x\n", rc);
364 TSS_ResponseCode_toString(&msg, &submsg, &num, rc);
365 printf("%s%s%s\n", msg, submsg, num);
366 rc = EXIT_FAILURE;
367 }
368 if (infile != NULL) {
369 fclose(infile);
370 }
371 return rc;
372 }
373
printUsage(void)374 static void printUsage(void)
375 {
376 printf("Usage: eventextend -if <measurement file> [-v]\n");
377 printf("\n");
378 printf("Extends a measurement file (binary) into a TPM or simulated PCRs\n");
379 printf("\n");
380 printf("\t-if\tfile containing the data to be extended\n");
381 printf("\t[-nospec\tfile does not contain spec ID header (useful for incremental test)]\n");
382 printf("\t[-tpm\textend TPM PCRs]\n");
383 printf("\t[-sim\tcalculate simulated PCRs and boot aggregate]\n");
384 printf("\t[-pcrmax\twith -sim, sets the highest PCR number to be used to calculate the\n"
385 "\t\tboot aggregate (default 7)]\n");
386 printf("\t[-ns\tno space, no text, no newlines]\n");
387 printf("\n");
388 exit(-1);
389 }
390
391