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