2 * The Initial Developer of the Original Code is International
3 * Business Machines Corporation. Portions created by IBM
4 * Corporation are Copyright (C) 2010 International Business
5 * Machines Corporation. All Rights Reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the Common Public License as published by
9 * IBM Corporation; either version 1 of the License, or (at your option)
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * Common Public License for more details.
17 * You should have received a copy of the Common Public License
18 * along with this program; if not, a copy can be viewed at
19 * http://www.opensource.org/licenses/cpl1.0.php.
24 * \brief Convert IR file to plaintext (or binary)
25 * @author Seiji Munetoh <munetoh@users.sourceforge.jp>
27 * cleanup 2011-01-22 SM
29 * IR(XML) -> SAX -> ctx->snapshot -> print
31 * this SAX code is based on ir.c. but remove the dependancy to other code.
40 #include <libxml/encoding.h>
41 #include <libxml/xmlwriter.h>
42 #include <libxml/parser.h>
44 #include <openssl/sha.h>
46 #include <tss/tss_structs.h>
50 /* Convert endian - 32bit */
51 #define econv(x) ((UINT32)( \
52 (((UINT32)(x) & (UINT32)0x000000ffUL) << 24) | \
53 (((UINT32)(x) & (UINT32)0x0000ff00UL) << 8) | \
54 (((UINT32)(x) & (UINT32)0x00ff0000UL) >> 8) | \
55 (((UINT32)(x) & (UINT32)0xff000000UL) >> 24)))
57 #define MAX_DIGEST_SIZE 64
58 #define EVENTDATA_BUF_SIZE 100000
61 #define SHA1_DIGEST_SIZE 20
62 BYTE pcr[MAX_PCRNUM][SHA1_DIGEST_SIZE];
66 #define IR_SAX_STATE_IDOL 0
67 #define IR_SAX_STATE_PCR_INDEX 1
68 #define IR_SAX_STATE_EVENT_TYPE 2
69 #define IR_SAX_STATE_DIGEST 3
70 #define IR_SAX_STATE_EVENT_DATA 4
71 #define IR_SAX_STATE_PCR 5
78 // char buf[EVENTDATA_BUF_SIZE]; // TODO(munetoh) fixed buffer
79 char *buf; /**< buffer for the text element */
83 BYTE pcr[MAX_DIGEST_SIZE];
86 FILE *fp; /* output */
88 int endian; // 0:normal 1:convert
90 int binary; // 0: plain text, 1: binary (BIOS format)
100 } PCR_EVENTTYPE_TABLE;
103 #define PCR_EVENTDATA_PRINT_NONE 0
104 #define PCR_EVENTDATA_PRINT_HEX 1
105 #define PCR_EVENTDATA_PRINT_STRING 2
107 /* event type (TCG) */
108 #define EV_PREBOOT_CERT 0x00
109 #define EV_POST_CODE 0x01
110 #define EV_SEPARATOR 0x04
111 #define EV_EVENT_TAG 0x06
113 #define EV_IPL_PARTITION_DATA 0x0e
115 /* event type (OpenPTS) */
116 #define EV_COLLECTOR_START 0x80
117 #define EV_UPDATE_START 0x81
118 #define EV_NEW_EVENT 0x82
119 #define EV_UPDATE_END 0x83
120 #define EV_FILE_SCAN 0x84
122 #define PCR_EVENTTYPE_TABLE_SIZE 11
124 PCR_EVENTTYPE_TABLE _event_table[] = {
125 {EV_PREBOOT_CERT, "EV_PREBOOT_CERT", PCR_EVENTDATA_PRINT_NONE},
126 {EV_POST_CODE, "EV_POST_CODE", PCR_EVENTDATA_PRINT_NONE},
127 {EV_SEPARATOR, "EV_SEPARATOR", PCR_EVENTDATA_PRINT_HEX},
128 {EV_EVENT_TAG, "EV_EVENT_TAG", PCR_EVENTDATA_PRINT_NONE},
129 {EV_IPL, "EV_IPL", PCR_EVENTDATA_PRINT_NONE},
130 {EV_IPL_PARTITION_DATA, "EV_IPL_PARTITION_DATA", PCR_EVENTDATA_PRINT_NONE},
132 {EV_COLLECTOR_START, "EV_COLLECTOR_START", PCR_EVENTDATA_PRINT_HEX},
133 {EV_UPDATE_START, "EV_UPDATE_START", PCR_EVENTDATA_PRINT_HEX},
134 {EV_NEW_EVENT, "EV_NEW_EVENT", PCR_EVENTDATA_PRINT_NONE},
135 {EV_UPDATE_END, "EV_UPDATE_END", PCR_EVENTDATA_PRINT_HEX},
136 {EV_FILE_SCAN, "EV_FILE_SCAN", PCR_EVENTDATA_PRINT_NONE}
150 for (i = 0; i < MAX_PCRNUM; i++) {
151 for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
156 for (i = 17; i < 23; i++) {
157 for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
168 int extend(int index, BYTE * digest) {
171 if (index >= MAX_PCRNUM)
174 // if (index == 10) { // Linux-IML, 0000... -> FFFF...
175 // if (isZero(digest) == 1) {
181 SHA1_Update(&ctx, &(pcr[index][0]), SHA1_DIGEST_SIZE);
182 SHA1_Update(&ctx, digest, SHA1_DIGEST_SIZE);
183 SHA1_Final(&(pcr[index][0]), &ctx);
185 return 0; // TODO(munetoh)
191 char *getEventName(UINT32 type) {
194 for (i = 0; i < PCR_EVENTTYPE_TABLE_SIZE; i++) {
195 if (type == _event_table[i].type) {
196 return _event_table[i].name;
202 void fprintEventData(FILE *fp, UINT32 type, UINT32 len, BYTE *eventdata) {
206 for (i = 0; i < PCR_EVENTTYPE_TABLE_SIZE; i++) {
207 if (type == _event_table[i].type) {
209 fprintf(fp, "%s", _event_table[i].name);
212 switch (_event_table[i].print_mode) {
213 case PCR_EVENTDATA_PRINT_NONE:
214 fprintf(fp, "[%d]", len);
216 case PCR_EVENTDATA_PRINT_HEX:
217 fprintf(fp, "[%d]=0x", len);
218 for (j = 0; j < (int) len; j++) fprintf(fp, "%02X", eventdata[j]);
220 case PCR_EVENTDATA_PRINT_STRING:
224 fprintf(fp, "[%d]", len);
240 <Report xmlns:core="http://www.trustedcomputinggroup.org/XML/SCHEMA/1_0_1/core_integrity#" xmlns:stuff="http://www.trustedcomputinggroup.org/XML/SCHEMA/1_0/simple_object#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.trustedcomputinggroup.org/XML/SCHEMA/1_0/integrity_report#" ID="IR_24868831-1b3c-4eb5-8e15-83b74f54d033" UUID="24868831-1b3c-4eb5-8e15-83b74f54d033">
241 <SnapshotCollection Id="IR_1bd0ac8f-d091-4a14-af05-651386f312a1" UUID="1bd0ac8f-d091-4a14-af05-651386f312a1" RevLevel="0">
242 <core:ComponentID Id="CID_0" ModelSystemClass="745749J" SimpleName="JJ" VersionBuild="1250694000000" VersionString="JJ">
243 <core:VendorID Name="JJ">
244 <core:SmiVendorId>0</core:SmiVendorId>
245 <core:TcgVendorId>DEMO</core:TcgVendorId>
248 <core:DigestMethod Algorithm="unknown" Id="sha1"/>
250 <stuff:SimpleSnapshotObject>
252 <stuff:Hash AlgRef="sha1" Id="PCR_0_LV0_8_0_EVENT">VnKCP/hHGXIdJtuXyR1gR7HnqXs=</stuff:Hash>
253 <pcrindex>0</pcrindex>
254 <eventtype>8</eventtype>
255 <eventdata>CAD+//////8FAAAA</eventdata>
259 <PcrHash AlgRef="sha1" Id="PCR_0_LV0_HASH" IsResetable="false" Number="0" StartHash="AAAAAAAAAAAAAAAAAAAAAAAAAAA=">j7/z7OqcVMjRxCz+qT1r8BvzQFs=</Pc
261 </SnapshotCollection>
266 #define IR_SAX_BUFFER_SIZE 2048
271 void irStartDocument(void * ctx) {
272 // OPENPTS_CONTEXT * pctx = (OPENPTS_CONTEXT *)ctx;
273 // OPENPTS_IR_CONTEXT * ctx = pctx->ctx;
274 // ctx->sax_error = 0;
275 // ctx->event_index = 0;
281 void irEndDocument(void * ctx) {
282 // printf("END DOC \n");
286 * SAX parser - Start of Element
288 void irStartElement(void* context, const xmlChar* name, const xmlChar** atts) {
289 IR_CONTEXT *ctx = (IR_CONTEXT *)context;
296 if (!strcmp((char *)name, "Report")) {
298 } else if (!strcmp((char *)name, "SnapshotCollection")) {
300 } else if (!strcmp((char *)name, "core:ComponentID")) {
302 } else if (!strcmp((char *)name, "core:VendorID")) {
304 } else if (!strcmp((char *)name, "core:TcgVendorId")) {
306 } else if (!strcmp((char *)name, "core:SmiVendorId")) {
308 } else if (!strcmp((char *)name, "core:DigestMethod")) {
310 } else if (!strcmp((char *)name, "core:Values")) {
312 } else if (!strcmp((char *)name, "stuff:SimpleSnapshotObject")) {
314 } else if (!strcmp((char *)name, "pcrindex")) {
315 /* stuff:Hash -> PCR value (base64) */
316 // printf("START ELEMENT [%s] <<<< HASH HASH \n",name);
317 // ctx->sax_state = IR_SAX_STATE_PCR_INDEX;
318 } else if (!strcmp((char *)name, "eventtype")) {
319 // printf("START ELEMENT [%s] <<<< HASH HASH \n",name);
320 // ctx->sax_state = IR_SAX_STATE_EVENT_TYPE;
321 } else if (!strcmp((char *)name, "stuff:Hash")) {
322 // printf("START ELEMENT [%s] <<<< DIGEST \n",name);
323 // ctx->sax_state = IR_SAX_STATE_DIGEST;
324 } else if (!strcmp((char *)name, "eventdata")) {
325 // printf("START ELEMENT [%s] <<<< EVENT_DATA\n",name);
326 // ctx->sax_state = IR_SAX_STATE_EVENT_DATA;
327 } else if (!strcmp((char *)name, "PcrHash")) {
328 // printf("START ELEMENT [%s] <<<< EVENT_DATA\n",name);
329 // ctx->sax_state = IR_SAX_STATE_PCR;
331 /* get Number =pcrindex) attribute ( */
333 for (i = 0;(atts[i] != NULL);i++) {
334 type = (char *)atts[i++];
335 // printf(", %s='", type);
336 if (atts[i] != NULL) {
337 value= (char *)atts[i];
338 // printf("%s'", value);
339 if (!strcmp(type, "Number")) {
340 ctx->pcr_index = atoi(value);
345 } else if (!strcmp((char *)name, "stuff:Objects")) {
348 ctx->event = (TSS_PCR_EVENT *) xmalloc(sizeof(TSS_PCR_EVENT));
349 if (ctx->event == NULL) {
352 memset(ctx->event, 0, sizeof(TSS_PCR_EVENT));
354 } else if (!strcmp((char *)name, "QuoteData")) {
356 } else if (!strcmp((char *)name, "Quote")) {
358 } else if (!strcmp((char *)name, "PcrComposit")) {
360 } else if (!strcmp((char *)name, "PcrSelection")) {
361 } else if (!strcmp((char *)name, "ValueSize")) {
362 } else if (!strcmp((char *)name, "PcrValue")) {
363 } else if (!strcmp((char *)name, "QuoteInfo")) {
364 } else if (!strcmp((char *)name, "TpmSignature")) {
365 } else if (!strcmp((char *)name, "SignatureMethod")) {
367 } else if (!strcmp((char *)name, "SignatureValue")) {
368 // DONE TODO("get value(base64)\n");
369 } else if (!strcmp((char *)name, "KeyInfo")) {
370 } else if (!strcmp((char *)name, "KeyValue")) {
371 // DONE TODO("get value(base64)\n");
374 ERROR("START ELEMENT [%s] \n", name);
375 ctx->sax_state = IR_SAX_STATE_IDOL;
380 * SAX parser - End of Element
382 void irEndElement(void * context, const xmlChar * name) {
383 IR_CONTEXT *ctx = (IR_CONTEXT *)context;
388 if (!strcmp((char *)name, "stuff:Objects")) {
389 /* Event finish, let's print out */
392 /* set the event structure */
393 if (ctx->event == NULL) {
394 ERROR("internal error\n");
397 if (ctx->binary == 0) {
399 fprintf(ctx->fp, "%5d %2d 0x%08x ",
401 ctx->event->ulPcrIndex,
402 ctx->event->eventType);
403 fprintHex(ctx->fp, ctx->event->rgbPcrValue, 20);
404 fprintf(ctx->fp, " [");
405 fprintEventData(ctx->fp, ctx->event->eventType, ctx->event->ulEventLength, ctx->event->rgbEvent);
406 fprintf(ctx->fp, "]\n");
409 if (ctx->endian == 0) {
411 rc = fwrite((BYTE *)&ctx->event->ulPcrIndex, 1, 4, ctx->fp); // PCR index
412 rc = fwrite((BYTE *)&ctx->event->eventType, 1, 4, ctx->fp); // Event type
413 rc = fwrite(ctx->event->rgbPcrValue, 1, 20, ctx->fp); // PCR
414 rc = fwrite((BYTE *)&ctx->event->ulEventLength, 1, 4, ctx->fp); // EventData length
415 rc = fwrite(ctx->event->rgbEvent, 1, ctx->event->ulEventLength, ctx->fp); // EventData
420 u = econv(ctx->event->ulPcrIndex);
421 rc = fwrite((BYTE *)&u, 1, 4, ctx->fp); // PCR index
422 u = econv(ctx->event->eventType);
423 rc = fwrite((BYTE *)&u, 1, 4, ctx->fp); // Event type
424 rc = fwrite(ctx->event->rgbPcrValue, 1, 20, ctx->fp); // PCR
425 u = econv(ctx->event->ulEventLength);
426 rc = fwrite((BYTE *)&u, 1, 4, ctx->fp); // EventData length
427 rc = fwrite(ctx->event->rgbEvent, 1, ctx->event->ulEventLength, ctx->fp); // EventData
430 if (ctx->aligned > 0) {
431 // TODO base64 IR already contains padding?
432 // DEBUG("padding\n");
433 pad_len = ctx->event->ulEventLength % ctx->aligned;
436 rc = fwrite((BYTE *)&padding, 1, pad_len, ctx->fp); // Padding
437 TODO("%d mod %d => %d\n", ctx->event->ulEventLength, ctx->aligned, pad_len);
444 ctx->event->ulPcrIndex,
445 ctx->event->rgbPcrValue);
449 } else if (!strcmp((char *)name, "SnapshotCollection")) {
450 /* snapshot finish */
451 } else if (!strcmp((char *)name, "pcrindex")) {
452 ctx->buf[ctx->char_size] = 0;
453 ctx->event->ulPcrIndex = atoi(ctx->buf);
454 } else if (!strcmp((char *)name, "stuff:Hash")) {
455 ctx->buf[ctx->char_size] = 0;
456 ctx->event->rgbPcrValue = decodeBase64(
459 (int *)&ctx->event->ulPcrValueLength);
460 if (ctx->event->rgbEvent == NULL) {
462 ctx->event->ulPcrValueLength = 0;
464 } else if (!strcmp((char *)name, "eventtype")) {
465 ctx->buf[ctx->char_size] = 0;
466 ctx->event->eventType = atoi(ctx->buf);
467 } else if (!strcmp((char *)name, "eventdata")) {
468 ctx->buf[ctx->char_size] = 0; // null terminate
469 ctx->event->rgbEvent = decodeBase64(
472 (int *)&ctx->event->ulEventLength);
473 if (ctx->event->rgbEvent == NULL) {
475 ctx->event->ulEventLength = 0;
477 } else if (!strcmp((char *)name, "PcrHash")) {
479 ctx->buf[ctx->char_size] = 0; // null terminate
480 // decodeBase64(ctx->pcr, (unsigned char *)ctx->buf, ctx->char_size);
482 /* Check with PCR in TPM */
483 // rc = checkTpmPcr2(&pctx->tpm, ctx->pcr_index, ctx->pcr);
486 ERROR("ERROR PCR[%d] != IML\n", ctx->pcr_index);
489 /* IML and PCR are consistent :-) */
490 // DEBUG_FSM("PCR[%d] == IML\n", ctx->pcr_index);
491 // TODO(munetoh) add property? tpm.pcr.N.snapshot.N.integrity=valid
494 /* update pcrs, used by validatePcrCompositeV11 */
495 if (pctx->conf->iml_mode == 0) {
497 /* malloc OPENPTS_PCRS */
498 // ERROR("PCR is not intialized - No QuoteData element\n");
499 pcrs = xmalloc(sizeof(OPENPTS_PCRS));
503 memset(pcrs, 0, sizeof(OPENPTS_PCRS));
506 pcrs->pcr_select[ctx->pcr_index] = 1;
507 memcpy(pcrs->pcr[ctx->pcr_index], ctx->pcr, 20); // TODO pcr size
509 // DEBUG("iml.mode!=tss, skip pcr copy to PCRS\n");
513 } else if (!strcmp((char *)name, "ValueSize")) {
514 DEBUG("ignore ValueSize\n");
515 } else if (!strcmp((char *)name, "PcrValue")) {
516 DEBUG("ignore PcrValue\n");
517 } else if (!strcmp((char *)name, "SignatureValue")) {
518 DEBUG("ignore SignatureValue\n");
519 } else if (!strcmp((char *)name, "KeyValue")) {
520 DEBUG("ignore KeyValue\n");
521 } else if (!strcmp((char *)name, "QuoteData")) {
522 DEBUG("ignore QuoteData\n");
525 // printf("END ELEMENT [%s] ",name);
528 ctx->sax_state = IR_SAX_STATE_IDOL;
532 * SAX parser - Text of Element
534 * This called multiple time:-(
537 void irCharacters(void* context, const xmlChar * ch, int len) {
538 IR_CONTEXT *ctx = (IR_CONTEXT *)context;
540 /* copy to buf at ctx */
541 if (ctx->char_size + len > EVENTDATA_BUF_SIZE) {
542 ERROR("Buffer for EVENTDATA is too small, %d + %d > %d\n", ctx->char_size, len, EVENTDATA_BUF_SIZE);
545 memcpy(&ctx->buf[ctx->char_size], ch, len);
546 ctx->char_size += len;
550 * read Integrity Report (IR) by using SAX parser
553 int readIr(IR_CONTEXT *context, const char *filename) {
554 xmlSAXHandler sax_handler;
557 memset(&sax_handler, 0, sizeof(xmlSAXHandler));
560 sax_handler.startDocument = irStartDocument;
561 sax_handler.endDocument = irEndDocument;
562 sax_handler.startElement = irStartElement;
563 sax_handler.endElement = irEndElement;
564 sax_handler.characters = irCharacters;
566 /* read IR, IR -> IML SAX */
567 if ((rc = xmlSAXUserParseFile(&sax_handler, (void *)context, filename)) != 0) {
583 fprintf(stderr, NLS(MS_OPENPTS, OPENPTS_IR2TEXT_USAGE, "OpenPTS command\n\n"
584 "Usage: ir2text [options]\n\n"
586 " -i filename Set IR file\n"
587 " -o filename Set output file, else stdout\n"
588 " -P filename Set PCR output file (option)\n"
589 " -b Binary, (Convert IR to IML)\n"
590 " -E Enable endian conversion (BE->LE or LE->BE)\n"
591 " -h Show this help message\n"
595 int main(int argc, char *argv[]) {
597 char *ir_filename = NULL;
598 char *out_filename = NULL;
599 char *pcrout_filename = NULL;
607 ctx = xmalloc(sizeof(IR_CONTEXT));
608 ctx = (IR_CONTEXT *) xmalloc(sizeof(IR_CONTEXT));
612 memset(ctx, 0, sizeof(IR_CONTEXT));
614 ctx->buf = xmalloc(EVENTDATA_BUF_SIZE);
615 if (ctx->buf == NULL) {
624 while ((c = getopt(argc, argv, "i:o:P:bEAdh")) != EOF) {
627 ir_filename = optarg;
630 out_filename = optarg;
633 pcrout_filename = optarg;
635 case 'b': /* Binary mode */
638 case 'E': /* Enable Endian Conversion */
639 // DEBUG("enable endian conversion\n");
642 case 'A': /* four byte aligned event data */
645 case 'd': /* DEBUG */
646 setDebugFlags(DEBUG_FLAG);
652 fprintf(stderr, NLS(MS_OPENPTS, OPENPTS_IR2TEXT_BAD_OPTION_C, "bad option %c\n"), c);
661 if (ctx->binary == 0) {
662 /* print IR in plain text */
663 DEBUG("ir2text - plain text mode\n");
665 if (out_filename != NULL) {
666 /* open output file */
667 ctx->fp = fopen(out_filename, "w");
668 if (ctx->fp == NULL) {
669 ERROR("output file %s - open failed\n", out_filename);
674 /* print IR in binary text, with -o option */
675 if (out_filename == NULL) {
676 fprintf(stderr, NLS(MS_OPENPTS, OPENPTS_IR2TEXT_OUTPUT_BINARY_MODE,
677 "set the output file for the binary mode\n"));
681 DEBUG("ir2text - binary mode (IR -> IML)\n");
683 /* open output file */
684 ctx->fp = fopen(out_filename, "wb");
685 if (ctx->fp == NULL) {
686 ERROR("output file %s - open failed\n", out_filename);
691 /* read IR and gen output */
692 rc = readIr(ctx, ir_filename);
694 /* close output file */
695 if (out_filename != NULL) {
696 /* close output file */
701 // PCR-00: 8F BF F3 EC EA 9C 54 C8 D1 C4 2C FE A9 3D 6B F0 1B F3 40 5B
702 if (pcrout_filename != NULL) {
705 TODO("pcrout_filename = %s\n", pcrout_filename);
707 /* open output file */
708 fp = fopen(pcrout_filename, "w");
710 ERROR("PCR output file %s - open failed\n", pcrout_filename);
714 for (i = 0; i < MAX_PCRNUM; i++) {
715 fprintf(fp, "PCR-%02d:", i);
716 for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
717 fprintf(fp, " %02X", pcr[i][j]);