2 * This file is part of the OpenPTS project.
4 * The Initial Developer of the Original Code is International
5 * Business Machines Corporation. Portions created by IBM
6 * Corporation are Copyright (C) 2011 International Business
7 * Machines Corporation. All Rights Reserved.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the Common Public License as published by
11 * IBM Corporation; either version 1 of the License, or (at your option)
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * Common Public License for more details.
19 * You should have received a copy of the Common Public License
20 * along with this program; if not, a copy can be viewed at
21 * http://www.opensource.org/licenses/cpl1.0.php.
25 * \file src/tboot2iml.c
26 * \brief create pseudo IML of tboot, standalone tool
27 * @author Seiji Munetoh <munetoh@users.sourceforge.jp>
29 * cleanup 2011-07-06 SM
35 * cat tests/data/ThinkpadX200_Fedora15_tboot/txt-stat.20110328 | ./src/tboot2iml > tests/data/ThinkpadX200_Fedora15_tboot/eventlog2
36 * ./src/tboot2iml -i tests/data/ThinkpadX200_Fedora15_tboot/txt-stat.20110328 -o tests/data/ThinkpadX200_Fedora15_tboot/eventlog2
37 * ./src/iml2text -i tests/data/ThinkpadX200_Fedora15_tboot/eventlog2
39 * ./src/tboot2iml -v -i tests/data/ThinkpadX200_Fedora15_tboot/txt-stat.20110328 -g tests/data/ThinkpadX200_Fedora15_tboot/grub.conf -p ./tests/data/ThinkpadX200_Fedora15_tboot -o tests/data/ThinkpadX200_Fedora15_tboot/eventlog2
41 * ./src/iml2text -D -v -V -i tests/data/ThinkpadX200_Fedora15_tboot/eventlog2
48 #include <unistd.h> // getopt
50 #include <sys/types.h>
54 #include <arpa/inet.h>
58 #include <openssl/sha.h>
61 #include <openpts_tboot.h>
66 #define MAX_PCRNUM 24 // TPM v1.2
69 #define CHAR_SPACE 0x20
75 unsigned char pcr[MAX_PCRNUM][SHA1_DIGEST_SIZE];
78 void debugPrintHex(char *head, BYTE *data, int num, char *tail) {
82 for (i = 0; i < num; i++) {
83 printf("%02X", data[i]);
94 for (i = 0;i < MAX_PCRNUM; i ++) {
95 for (j = 0;j < SHA1_DIGEST_SIZE; j ++) {
101 void resetPcrWithSecret(int i, BYTE *digest) {
104 for (j = 0;j < SHA1_DIGEST_SIZE; j ++) {
105 pcr[i][j] = digest[j];
109 void extend(int index, unsigned char* digest) {
113 SHA1_Update(&ctx, &pcr[index][0], SHA1_DIGEST_SIZE);
114 SHA1_Update(&ctx, digest, SHA1_DIGEST_SIZE);
115 SHA1_Final(&pcr[index][0], &ctx);
122 TXTSTAT_SINIT_MLE_DATA,
127 TXTSTAT_LCP_POLICY_HASH,
129 TXTSTAT_VL_MEASUREMENT,
130 TXTSTAT_PCRS_BEFORE_EXTENTING,
131 TXTSTAT_PCRS_AFTER_EXTENTING,
136 BYTE hex2byte(char *buf, int offset) {
141 memcpy(buf2, &buf[offset], 2);
144 tmp = strtol(buf2, &e, 16);
146 return (BYTE) (0xFF & tmp);
151 * parse TXT-stat file
153 int parseTxtStatFile(OPENPTS_TBOOT_CONTEXT *ctx, char *filename) {
155 char line[1024]; // TODO(munetoh)
157 int state = TXTSTAT_START;
158 int next_state = TXTSTAT_START;
161 if (filename != NULL) {
163 if ((fp = fopen(filename, "r")) == NULL) {
164 ERROR("parseTxtStatFile - %s file is missing\n", filename);
165 return PTS_FATAL; // TODO
172 while (fgets(line, sizeof(line), fp) != NULL) { // read line
173 // TBOOT: v2 LCP policy data found
174 if (!strncmp(line, "TBOOT: v2 LCP policy data found", 31)) {
175 ctx->lcp_policy_version = 2;
176 DEBUG("lcp_policy_version : 2\n");
180 // TBOOT: sinit_mle_data (@0x799301b8, 0x260):
181 if (!strncmp(line, "TBOOT: sinit_mle_data", 21)) {
182 next_state = TXTSTAT_SINIT_MLE_DATA;
185 if ((state == TXTSTAT_SINIT_MLE_DATA) &&
186 (!strncmp(line, "TBOOT: version:", 17))) {
187 ctx->mle_version = atoi(&line[18]);
188 DEBUG("ctx->mle_version = %d\n", ctx->mle_version);
190 // TBOOT: bios_acm_id:
191 if (!strncmp(line, "TBOOT: bios_acm_id:", 21)) {
192 next_state = TXTSTAT_BIOS_ACM_ID;
194 // 80 00 00 00 20 08 05 15 00 00 2a 40 00 00 00 00 ff ff ff ff
195 if (state == TXTSTAT_BIOS_ACM_ID) {
196 for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
197 ctx->bios_acm_id[j] = 0;
198 ctx->bios_acm_id[j] = hex2byte(line, 1 + j * 3);
200 next_state = TXTSTAT_NA;
201 DEBUG("bios_acm_id\n");
202 // printHex("bios_acm_id ", ctx->bios_acm_id, 20, "\n");
204 // TBOOT: edx_senter_flags: 0x00000000
205 if (!strncmp(line, "TBOOT: edx_senter_flags:", 26)) {
206 for (j = 0; j < 4; j++) {
207 ctx->edx_senter_flags[j] = 0;
208 ctx->edx_senter_flags[j] = hex2byte(line, 29 + j * 2);
210 next_state = TXTSTAT_NA;
211 DEBUG("edx_senter_flags\n");
212 // printHex("edx_senter_flags ", ctx->edx_senter_flags, 4, "\n");
216 // TBOOT: mseg_valid: 0x0
217 // TBOOT: sinit_hash:
218 if (!strncmp(line, "TBOOT: sinit_hash:", 20)) {
219 next_state = TXTSTAT_SINIT_HASH;
221 // d0 29 d1 14 d6 d4 d2 f0 70 98 db 05 85 24 f9 5e a2 7c 72 a5
222 if (state == TXTSTAT_SINIT_HASH) {
223 for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
224 ctx->sinit_hash[j] = 0;
225 ctx->sinit_hash[j] = hex2byte(line, 1 + j * 3);
227 next_state = TXTSTAT_NA;
228 DEBUG("sinit_hash\n");
229 debugPrintHex(" sinit_hash : ", ctx->sinit_hash, 20, "\n");
232 if (!strncmp(line, "TBOOT: mle_hash:", 18)) {
233 next_state = TXTSTAT_MLE_HASH;
235 // 88 43 1c c6 0c 5f 11 5b 29 08 2f 04 43 8d de 94 93 47 62 46
236 if (state == TXTSTAT_MLE_HASH) {
237 for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
238 ctx->mle_hash[j] = 0;
239 ctx->mle_hash[j] = hex2byte(line, 1 + j * 3);
241 next_state = TXTSTAT_NA;
243 debugPrintHex(" mle_hash ", ctx->mle_hash, 20, "\n");
246 if (!strncmp(line, "TBOOT: stm_hash:", 18)) {
247 next_state = TXTSTAT_STM_HASH;
249 // 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
250 if (state == TXTSTAT_STM_HASH) {
251 for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
252 ctx->stm_hash[j] = 0;
253 ctx->stm_hash[j] = hex2byte(line, 1 + j * 3);
255 next_state = TXTSTAT_NA;
257 // printHex("stm_hash ", ctx->stm_hash, 20, "\n");
259 // TBOOT: lcp_policy_hash:
260 if (!strncmp(line, "TBOOT: lcp_policy_hash:", 25)) {
261 next_state = TXTSTAT_LCP_POLICY_HASH;
263 // 88 43 1c c6 0c 5f 11 5b 29 08 2f 04 43 8d de 94 93 47 62 46
264 if (state == TXTSTAT_LCP_POLICY_HASH) {
265 for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
266 ctx->lcp_policy_hash[j] = 0;
267 ctx->lcp_policy_hash[j] = hex2byte(line, 1 + j * 3);
269 next_state = TXTSTAT_NA;
270 DEBUG("lcp_policy_hash\n");
271 // printHex("lcp_policy_hash ", ctx->lcp_policy_hash, 20, "\n");
273 // TBOOT: lcp_policy_control: 0x00000000
276 // TBOOT: policy_control: 00000001 (EXTEND_PCR17)
278 if (!strncmp(line, "TBOOT: policy_control:", 24)) {
279 for (j = 0; j < 4; j++) {
280 ctx->pol_control[j] = hex2byte(line, 25 + (3 - j) * 2);
282 DEBUG("pol_control");
283 // printHex("pol_control ", ctx->pol_control, 4, "\n");
286 // TBOOT: pol_hash: 5a 14 3f 34 f5 03 41 ff a2 01 34 0f b8 8e f9 98 73 b7 e0 3d
287 if (!strncmp(line, "TBOOT: pol_hash:", 18)) {
288 for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
289 ctx->pol_hash[j] = 0;
290 ctx->pol_hash[j] = hex2byte(line, 19 + j * 3);
292 DEBUG("pol_hash PCR17");
293 // printHex("pol_hash ", ctx->pol_hash, 20, "\n");
296 // TBOOT: VL measurements:
297 if (!strncmp(line, "TBOOT: VL measurements", 24)) {
298 next_state = TXTSTAT_VL_MEASUREMENT;
300 // TBOOT: PCR 17: a8 21 ff be 39 69 21 f3 bd 8d 79 e7 70 ec 8f 75 41 ba 5c 5e
301 // TBOOT: PCR 18: d2 5c 5b 18 2a 9a 62 ce 15 e4 6d 08 91 9d 4e fc 1b 7c fc ad
302 // TBOOT: PCR 19: 0f 93 a8 2c 3b 3b 20 30 98 61 39 a2 03 2e 38 23 73 3f c6 42
303 if ((state == TXTSTAT_VL_MEASUREMENT) &&
304 (!strncmp(line, "TBOOT: PCR 17:", 18))) {
305 for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
306 ctx->vl_pcr17[j] = 0;
307 ctx->vl_pcr17[j] = hex2byte(line, 19 + j * 3);
310 debugPrintHex(" PCR17 ", ctx->vl_pcr17, 20, "\n");
312 if ((state == TXTSTAT_VL_MEASUREMENT) &&
313 (!strncmp(line, "TBOOT: PCR 18:", 18))) {
314 for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
315 ctx->vl_pcr18[j] = 0;
316 ctx->vl_pcr18[j] = hex2byte(line, 19 + j * 3);
319 debugPrintHex(" PCR18 ", ctx->vl_pcr18, 20, "\n");
321 if ((state == TXTSTAT_VL_MEASUREMENT) &&
322 (!strncmp(line, "TBOOT: PCR 19:", 18))) {
323 for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
324 ctx->vl_pcr19[j] = 0;
325 ctx->vl_pcr19[j] = hex2byte(line, 19 + j * 3);
328 debugPrintHex(" PCR19 ", ctx->vl_pcr19, 20, "\n");
332 // TBOOT: PCRs after extending:
333 if (!strncmp(line, "TBOOT: PCRs after extending:", 28)) {
334 next_state = TXTSTAT_PCRS_AFTER_EXTENTING;
336 // TBOOT: PCR 17: bb 0f 68 4f df 3a 42 b9 24 93 80 6d 5d a5 4e 36 62 c5 c5 52
337 // TBOOT: PCR 18: 5e 24 63 ef f8 ee 13 c3 28 1e 13 03 d2 0e d4 79 69 5f 15 d7
338 if ((state == TXTSTAT_PCRS_AFTER_EXTENTING) &&
339 (!strncmp(line, "TBOOT: PCR 17:", 16))) {
340 for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
341 ctx->final_pcr17[j] = 0;
342 ctx->final_pcr17[j] = hex2byte(line, 17 + j * 3);
344 DEBUG("final PCR17");
345 debugPrintHex(" PCR17 ", ctx->final_pcr17, 20, "\n");
347 if ((state == TXTSTAT_PCRS_AFTER_EXTENTING) &&
348 (!strncmp(line, "TBOOT: PCR 18:", 16))) {
349 for (j = 0; j < SHA1_DIGEST_SIZE; j++) {
350 ctx->final_pcr18[j] = 0;
351 ctx->final_pcr18[j] = hex2byte(line, 17 + j * 3);
353 DEBUG("final PCR18");
354 debugPrintHex(" PCR18 ", ctx->final_pcr18, 20, "\n");
361 if (filename != NULL) {
368 * skip space/tab at start
370 char * skipspace(char *str) {
371 while ((*str == CHAR_SPACE) || (*str == CHAR_TAB)) {
378 * skip to space or end
380 char * skip2space(char *str) {
387 if (*str == 0x0a) { // \n
393 for (i = 0; i < len; i++) {
394 if (str[i] == 0x20) {
406 * remove \n at the end
408 void removecr(char *str) {
412 if (str[len - 1] == 0x0a) {
419 // 000004c0 aa 3a c0 7f a7 46 db 18 2e ac 69 8f 8d 41 7f 5a
420 // 000004c0 aa 3a c0 7f a7 46 db 18 2e ac 69 8f 8d 41 7f 5a |.:...F....i..A.Z|
422 int checkSinitAcm(BYTE *buf) {
424 {0xaa, 0x3a, 0xc0, 0x7f, 0xa7, 0x46, 0xdb, 0x18,
425 0x2e, 0xac, 0x69, 0x8f, 0x8d, 0x41, 0x7f, 0x5a};
427 if (memcmp(&buf[0x4c0], UUID, 16) == 0) {
429 DEBUG("SINIT ACM\n");
438 UINT32 HeaderVersion;
446 UINT32 ErrorEntryPoint;
454 BYTE RSAPubKey[256]; // 128 not included
455 BYTE RSAPubExp[4]; // not included
456 BYTE RSASig[256]; // not included
457 BYTE Scratch[1]; // not included
458 // UserArea[] // 644+ScratchSize*4
461 int sinit_acm_hash(char *filename, int size, BYTE *sha1_digest, BYTE *sha256_digest) {
468 SHA256_CTX sha256_ctx;
471 int rc = PTS_SUCCESS;
473 DEBUG("sinit_acm_hash() file = %s, size = %d\n", filename, size);
475 acmbuf = malloc(size);
476 if (acmbuf == NULL) {
481 memset(acmbuf, 0, size);
484 fp = fopen(filename, "rb");
486 ERROR("File %s does not exist\n", filename);
494 len = fread(buf, 1, sizeof(buf), fp);
498 memcpy(ptr, buf, len);
506 acm = (SINIT_ACM *)acmbuf;
507 DEBUG(" MopduleType : 0x%08X\n", acm->MopduleType);
508 DEBUG(" Size : %d\n", acm->Size);
509 DEBUG(" EntryPoint : %d, 0x%08X\n", acm->EntryPoint, acm->EntryPoint);
510 DEBUG(" KeySize : %d, 0x%08X\n", acm->KeySize, acm->KeySize);
511 DEBUG(" ScratchSize : %d, 0x%08X\n", acm->ScratchSize, acm->ScratchSize);
512 user_area = 644 + (acm->ScratchSize * 4);
513 DEBUG(" User Area : %d, 0x%08X\n", user_area, user_area);
516 SHA1_Update(&sha_ctx, &acmbuf[0], 128);
517 SHA1_Update(&sha_ctx, &acmbuf[user_area], size - user_area);
518 SHA1_Final(sha1_digest, &sha_ctx);
520 debugPrintHex(" SHA1 Digest : ", sha1_digest, 20, "\n");
522 SHA256_Init(&sha256_ctx);
523 SHA256_Update(&sha256_ctx, &acmbuf[0], 128);
524 SHA256_Update(&sha256_ctx, &acmbuf[user_area], size - user_area);
525 SHA256_Final(sha256_digest, &sha256_ctx);
527 debugPrintHex(" SHA256 Digest : ", sha256_digest, 32, "\n");
535 int sha1sum_unzip(char *filename, int *filesize, BYTE *digest) {
541 int is_sinit_acm = 0;
545 fp = gzopen(filename, "rb");
547 ERROR("File %s does not exist\n", filename);
554 len = gzread(fp, buf, sizeof(buf));
555 if ((rdCnt == 0) && (len > 1216 + 16)) {
556 is_sinit_acm = checkSinitAcm((BYTE *)buf);
561 SHA1_Update(&sha_ctx, buf, len);
566 SHA1_Final(digest, &sha_ctx);
575 * parse grub.conf file
577 * just check the default setting
579 int parseGrubConfFile(OPENPTS_TBOOT_CONTEXT *ctx, char *filename, char *path) {
580 int rc = PTS_SUCCESS;
585 int module_count = 0;
587 char *module_filename;
590 TBOOT_MODULE *prev_module = NULL;
595 if ((fp = fopen(filename, "r")) == NULL) {
596 ERROR("parseTxtStatFile - %s file is missing\n", filename);
597 return PTS_FATAL; // TODO
602 while (fgets(line, sizeof(line), fp) != NULL) { // read line
604 if (!strncmp(line, "default=", 8)) {
605 default_num = atoi(&line[8]);
606 DEBUG("default_num = %d\n", default_num);
609 // title Fedora (2.6.38.1-6.fc15.x86_64) tboot
610 if (!strncmp(line, "title", 5)) {
613 DEBUG("title[%d] : %s", count, line);
614 } else if (default_num == count) {
615 ptr = skipspace(line);
618 // kernel /tboot.gz logging=serial,vga,memory vga_delay=5
620 // module /vmlinuz-2.6.38.1-6.fc15.x86_64 ro...
621 // module /initramfs-2.6.38.1-6.fc15.x86_64.img
622 // module /GM45_GS45_PM45_SINIT_21.BIN
623 if (!strncmp(ptr, "module", 6)) {
624 TBOOT_MODULE *module;
625 OPENPTS_EVENT_TBOOT_MODULE *eventdata;
626 /* module structure */
627 module = malloc(sizeof(TBOOT_MODULE));
628 eventdata = malloc(sizeof(OPENPTS_EVENT_TBOOT_MODULE));
629 module->eventdata = eventdata;
631 if (prev_module == NULL) {
633 ctx->module = module;
635 prev_module->next = module;
641 module_filename = &ptr[8];
643 module_filename = &ptr[7];
647 ptr = skip2space(&ptr[7]);
650 eventdata->filename = getFullpathName(path, module_filename);
651 eventdata->filename_size = strlen(eventdata->filename);
654 removecr(module_option);
655 eventdata->command = smalloc(module_option);
656 eventdata->command_size = strlen(eventdata->command);
657 DEBUG("module[%d] file : '%s'", module_count, eventdata->filename);
658 DEBUG("module[%d] option : '%s'", module_count, eventdata->command);
660 module_option = NULL;
661 removecr(module_filename);
662 eventdata->filename = getFullpathName(path, module_filename);
663 eventdata->filename_size = strlen(eventdata->filename);
664 eventdata->command = NULL;
665 eventdata->command_size = 0;
666 DEBUG("module[%d] file : '%s'", module_count, eventdata->filename);
671 is_sinit_acm = sha1sum_unzip(eventdata->filename, &size, eventdata->file_hash);
672 if (is_sinit_acm == 1) {
673 // calc hash of SINIT ACM
677 ctx->sinit_hash_from_file,
678 ctx->sinit_hash256_from_file);
681 debugPrintHex(" SHA1(file) : ", eventdata->file_hash, 20, "\n");
684 SHA1_Update(&sha_ctx, eventdata->command, eventdata->command_size);
685 SHA1_Final(eventdata->command_hash, &sha_ctx);
687 debugPrintHex(" SHA1(command) : ", eventdata->command_hash, 20, "\n");
690 SHA1_Update(&sha_ctx, eventdata->command_hash, 20);
691 SHA1_Update(&sha_ctx, eventdata->file_hash, 20);
692 SHA1_Final(module->digest, &sha_ctx);
694 debugPrintHex(" extend : ", module->digest, 20, "\n");
697 prev_module = module;
710 * Verify Tboot Measurement
712 * setup OPENPTS_TBOOT_CONTEXT before call this
714 int emulateTboot(OPENPTS_TBOOT_CONTEXT *ctx) {
715 int rc = PTS_SUCCESS;
717 unsigned char digest[20];
719 DEBUG("emulateTboot()\n");
724 // Ref: Dev Guide 1.9.1 PCR 17 - p.14
725 if (ctx->mle_version == 6) {
726 // Extend(SHA-1(SinitMleData.SinitHash |
727 // SinitMleData.EdxSenterFlags))
729 SHA1_Update(&sha_ctx, ctx->sinit_hash, 20);
730 SHA1_Update(&sha_ctx, ctx->edx_senter_flags, 4);
731 SHA1_Final(digest, &sha_ctx);
734 DEBUG("PCR17(mle v6)\n");
735 debugPrintHex(" sinit_hash : ", ctx->sinit_hash, 20, "\n");
736 debugPrintHex(" edx_senter_flags : ", ctx->edx_senter_flags, 4, "\n");
737 debugPrintHex(" extend : ", digest, 20, "\n");
738 debugPrintHex(" PCR[17] : ", &pcr[17][0], 20, "\n");
741 // Extend(SHA-1(SinitMleData.BiosAcm.ID |
742 // SinitMleData.MsegValid |
743 // SinitMleData.StmHash |
744 // SinitMleData.PolicyControl |
745 // SinitMleData.LcpPolicyHash |
746 // (OsSinitData.Capabilities, 0)))
748 SHA1_Update(&sha_ctx, ctx->bios_acm_id, 20);
749 SHA1_Update(&sha_ctx, ctx->mseg_valid, 8);
750 SHA1_Update(&sha_ctx, ctx->stm_hash, 20);
751 SHA1_Update(&sha_ctx, ctx->lcp_policy_control, 4);
752 SHA1_Update(&sha_ctx, ctx->lcp_policy_hash, 20);
753 SHA1_Update(&sha_ctx, ctx->capabilities, 4);
754 SHA1_Final(digest, &sha_ctx);
757 DEBUG("PCR17(mle v6)\n");
758 debugPrintHex(" bios_acm_id : ", ctx->bios_acm_id, 20, "\n");
759 debugPrintHex(" mseg_valid : ", ctx->mseg_valid, 8, "\n");
760 debugPrintHex(" stm_hash : ", ctx->stm_hash, 20, "\n");
761 debugPrintHex(" lcp_policy_control : ", ctx->lcp_policy_control, 4, "\n");
762 debugPrintHex(" lcp_policy_hash : ", ctx->lcp_policy_hash, 20, "\n");
763 debugPrintHex(" capabilities : ", ctx->capabilities, 4, "\n");
764 debugPrintHex(" extend : ", digest, 20, "\n");
765 debugPrintHex(" PCR[17] : ", &pcr[17][0], 20, "\n");
767 } else if (ctx->mle_version == 7) {
769 // Extend(Hidden Value)
770 // SinitMleData.SinitHash = PCR17
771 // Extend(SHA-1(SinitMleData.BiosAcm.ID |
772 // SinitMleData.MsegValid |
773 // SinitMleData.StmHash |
774 // SinitMleData.PolicyControl |
775 // SinitMleData.LcpPolicyHash |
776 // (OsSinitData.Capabilities, 0)))
778 // SHA-1(SinitMleData.SinitHash |
779 // SHA-1( SinitMleData.BiosAcm.ID |
780 // SinitMleData.MsegValid |
781 // SinitMleData.StmHash |
782 // SinitMleData.PolicyControl |
783 // SinitMleData.LcpPolicyHash |
784 // (OsSinitData.Capabilities, 0)))
788 SHA1_Update(&sha_ctx, ctx->sinit_hash256_from_file, 32);
789 SHA1_Update(&sha_ctx, ctx->edx_senter_flags, 4);
790 SHA1_Final(digest, &sha_ctx);
793 DEBUG("PCR17(mle v6)\n");
794 debugPrintHex(" sinit_hash : ", ctx->sinit_hash256_from_file, 32, "\n");
795 debugPrintHex(" edx_senter_flags : ", ctx->edx_senter_flags, 4, "\n");
796 debugPrintHex(" extend : ", digest, 20, "\n");
797 debugPrintHex(" PCR[17] : ", &pcr[17][0], 20, "\n");
800 // extend(17, ctx->sinit_hash256_from_file);
801 // extend(17, ctx->sinit_hash_from_file);
802 // debugPrintHex(" mle v7 PCR17 ", &pcr[17][0], 20, " (SINIT ACM)\n");
805 resetPcrWithSecret(17, ctx->sinit_hash);
806 debugPrintHex(" SINIT hash ", ctx->sinit_hash, 20, "\n");
807 debugPrintHex(" mle v7 PCR17 ", &pcr[17][0], 20, "\n");
810 SHA1_Update(&sha_ctx, ctx->bios_acm_id, 20);
811 SHA1_Update(&sha_ctx, ctx->mseg_valid, 8);
812 SHA1_Update(&sha_ctx, ctx->stm_hash, 20);
813 SHA1_Update(&sha_ctx, ctx->lcp_policy_control, 4);
814 SHA1_Update(&sha_ctx, ctx->lcp_policy_hash, 20);
815 SHA1_Update(&sha_ctx, ctx->capabilities, 4);
816 SHA1_Final(digest, &sha_ctx);
818 debugPrintHex(" mle v7 PCR17 ", &pcr[17][0], 20, "\n");
819 } else if (ctx->mle_version == 8) {
822 // SHA-1(SinitMleData.SinitHash |
823 // SHA-1(SinitMleData.BiosAcm.ID |
824 // SinitMleData.MsegValid |
825 // SinitMleData.StmHash |
826 // SinitMleData.PolicyControl |
827 // SinitMleData.LcpPolicyHash |
828 // (OsSinitData.Capabilities, 0) |
829 // SinitMleData.ProcessorSCRTMStatus)) << added
832 extend(17, ctx->sinit_hash256_from_file);
833 debugPrintHex(" mle v8 PCR17 ", &pcr[17][0], 20, "\n");
836 // resetPcrWithSecret(17, ctx->sinit_hash);
839 SHA1_Update(&sha_ctx, ctx->bios_acm_id, 20);
840 SHA1_Update(&sha_ctx, ctx->mseg_valid, 8);
841 SHA1_Update(&sha_ctx, ctx->stm_hash, 20);
842 SHA1_Update(&sha_ctx, ctx->lcp_policy_control, 4);
843 SHA1_Update(&sha_ctx, ctx->lcp_policy_hash, 20);
844 SHA1_Update(&sha_ctx, ctx->capabilities, 4);
845 SHA1_Update(&sha_ctx, ctx->ProcessorSCRTMStatus, 4);
846 SHA1_Final(digest, &sha_ctx);
848 debugPrintHex(" mle v8 PCR17 ", &pcr[17][0], 20, "\n");
850 ERROR("mle_version = %d \n", ctx->mle_version);
853 extend(18, ctx->mle_hash);
856 printHex("PCR-17", &pcr[17][0], 20, "\n");
857 printHex("PCR-18", &pcr[18][0], 20, "\n");
858 printHex("PCR-19", &pcr[19][0], 20, "\n");
861 extend(17, ctx->vl_pcr17);
862 debugPrintHex(" extend : ", ctx->vl_pcr17, 20, "\n");
863 debugPrintHex(" PCR[17] : ", &pcr[17][0], 20, "\n");
865 extend(18, ctx->vl_pcr18);
866 debugPrintHex(" extend : ", ctx->vl_pcr18, 20, "\n");
867 debugPrintHex(" PCR[18] : ", &pcr[18][0], 20, "\n");
869 extend(19, ctx->vl_pcr19);
870 debugPrintHex(" extend : ", ctx->vl_pcr19, 20, "\n");
871 debugPrintHex(" PCR[19] : ", &pcr[19][0], 20, "\n");
874 printHex("PCR-17", &pcr[17][0], 20, "\n");
875 printHex("PCR-18", &pcr[18][0], 20, "\n");
876 printHex("PCR-19", &pcr[19][0], 20, "\n");
879 /* check PCR values after DRTM */
881 /* check (within TXT-STAT) */
882 if (memcmp(&pcr[17][0], ctx->final_pcr17, 20) != 0) {
883 ERROR("bad PCR17\n");
884 printHex("PCR-17", &pcr[17][0], 20, "\n");
887 if (memcmp(&pcr[18][0], ctx->final_pcr18, 20) != 0) {
888 ERROR("bad PCR18\n");
889 printHex("PCR-18", &pcr[18][0], 20, "\n");
892 // TODO check PCR19 - with PCRs
901 int writeEvent(FILE *fp, TSS_PCR_EVENT *event) {
903 rc = fwrite((BYTE *)&event->ulPcrIndex, 1, 4, fp); // PCR index
904 rc = fwrite((BYTE *)&event->eventType, 1, 4, fp); // Event type
905 rc = fwrite(event->rgbPcrValue, 1, 20, fp); // PCR
906 rc = fwrite((BYTE *)&event->ulEventLength, 1, 4, fp); // EventData length
907 if ((event->rgbEvent != NULL) && (event->ulEventLength > 0)) {
908 rc = fwrite(event->rgbEvent, 1, event->ulEventLength, fp); // EventData
915 * filename IML(binary) file
917 int generateEventlog(OPENPTS_TBOOT_CONTEXT *ctx, char *filename) {
918 int rc = PTS_SUCCESS;
920 TSS_PCR_EVENT *event;
923 DEBUG("generateEventlog() - filename = %s\n", filename);
926 if (filename != NULL) {
928 if ((fp = fopen(filename, "wb")) == NULL) {
929 ERROR("generateEventlog - %s file can't open\n", filename);
930 return PTS_FATAL; // TODO
937 event = malloc(sizeof(TSS_PCR_EVENT));
942 memset(event, 0, sizeof(TSS_PCR_EVENT));
945 event->rgbPcrValue = malloc(20);
946 if (event->rgbPcrValue == NULL) {
952 if (ctx->mle_version == 6) {
953 OPENPTS_EVENT_TBOOT_SINIT_V6 data0;
954 OPENPTS_EVENT_TBOOT_STM_V6 data1;
956 event->ulPcrIndex = 17;
957 event->eventType = EV_TBOOT_SINIT_V6;
958 memcpy(data0.sinit_hash, ctx->sinit_hash, 20);
959 memcpy(data0.edx_senter_flags, ctx->edx_senter_flags, 4);
960 event->ulEventLength = 24;
961 event->rgbEvent = (BYTE *)&data0;
963 SHA1_Update(&sha_ctx, event->rgbEvent, event->ulEventLength);
964 SHA1_Final(event->rgbPcrValue, &sha_ctx);
965 writeEvent(fp, event);
968 event->ulPcrIndex = 17;
969 event->eventType = EV_TBOOT_STM_V6;
970 memcpy(data1.bios_acm_id, ctx->bios_acm_id, 20);
971 memcpy(data1.mseg_valid, ctx->mseg_valid, 8);
972 memcpy(data1.stm_hash, ctx->stm_hash, 20);
973 memcpy(data1.lcp_policy_control, ctx->lcp_policy_control, 4);
974 memcpy(data1.lcp_policy_hash, ctx->lcp_policy_hash, 20);
975 memcpy(data1.capabilities, ctx->capabilities, 4);
976 event->ulEventLength = 76;
977 event->rgbEvent = (BYTE *)&data1;
979 SHA1_Update(&sha_ctx, event->rgbEvent, event->ulEventLength);
980 SHA1_Final(event->rgbPcrValue, &sha_ctx);
981 writeEvent(fp, event);
982 } else if (ctx->mle_version == 7) {
983 DEBUG("TBD mle_version = %d \n", ctx->mle_version);
984 OPENPTS_EVENT_TBOOT_SINIT_V7 data0;
985 OPENPTS_EVENT_TBOOT_STM_V6 data1;
987 event->ulPcrIndex = 17;
988 event->eventType = EV_TBOOT_SINIT_V7;
989 memcpy(data0.sinit_hash, ctx->sinit_hash256_from_file, 32);
990 memcpy(data0.edx_senter_flags, ctx->edx_senter_flags, 4);
991 event->ulEventLength = 36;
992 event->rgbEvent = (BYTE *)&data0;
994 SHA1_Update(&sha_ctx, event->rgbEvent, event->ulEventLength);
995 SHA1_Final(event->rgbPcrValue, &sha_ctx);
996 writeEvent(fp, event);
999 event->ulPcrIndex = 17;
1000 event->eventType = EV_TBOOT_STM_V6;
1001 memcpy(data1.bios_acm_id, ctx->bios_acm_id, 20);
1002 memcpy(data1.mseg_valid, ctx->mseg_valid, 8);
1003 memcpy(data1.stm_hash, ctx->stm_hash, 20);
1004 memcpy(data1.lcp_policy_control, ctx->lcp_policy_control, 4);
1005 memcpy(data1.lcp_policy_hash, ctx->lcp_policy_hash, 20);
1006 memcpy(data1.capabilities, ctx->capabilities, 4);
1007 event->ulEventLength = 76;
1008 event->rgbEvent = (BYTE *)&data1;
1009 SHA1_Init(&sha_ctx);
1010 SHA1_Update(&sha_ctx, event->rgbEvent, event->ulEventLength);
1011 SHA1_Final(event->rgbPcrValue, &sha_ctx);
1012 writeEvent(fp, event);
1015 } else if (ctx->mle_version == 8) {
1016 TODO("TBD mle_version = %d \n", ctx->mle_version);
1018 TODO("TBD mle_version = %d \n", ctx->mle_version);
1022 event->ulPcrIndex = 18;
1023 event->eventType = EV_TBOOT_MLE_HASH;
1024 event->ulEventLength = 0;
1025 memcpy(event->rgbPcrValue, ctx->mle_hash, 20);
1026 writeEvent(fp, event);
1029 /* TBOOT Policy => PCR17 */
1031 OPENPTS_EVENT_TBOOT_POLCTL polctl;
1033 // ctx->pol_control[0] = 1; // TODO extend PCR17
1034 // ctx->pol_control[1] = 0;
1035 // ctx->pol_control[2] = 0;
1036 // ctx->pol_control[3] = 0;
1038 // SHA1_Init(&sha_ctx);
1039 // SHA1_Update(&sha_ctx, ctx->pol_control, 4);
1040 // SHA1_Update(&sha_ctx, ctx->pol_hash, 20);
1041 // SHA1_Final(digest, &sha_ctx);
1042 // extend(17, digest);
1044 // DEBUG("PCR17 \n");
1045 // printHex("PCR-17", digest, 20, "\n");
1046 // printHex("PCR-17", ctx->vl_pcr17, 20, "\n");
1048 event->ulPcrIndex = 17;
1049 event->eventType = EV_TBOOT_POLCTL;
1050 event->ulEventLength = 24;
1051 event->rgbEvent = (BYTE *)&polctl;
1052 memcpy(&polctl.pol_control, ctx->pol_control, 4);
1053 memcpy(&polctl.pol_hash, ctx->pol_hash, 20);
1054 memcpy(event->rgbPcrValue, ctx->vl_pcr17, 20);
1055 writeEvent(fp, event);
1060 DEBUG(" module[0]\n");
1061 event->ulPcrIndex = 18;
1062 event->eventType = EV_TBOOT_MODULE;
1063 if (ctx->module != NULL) {
1064 TBOOT_MODULE *module;
1065 OPENPTS_EVENT_TBOOT_MODULE *eventdata;
1068 module = ctx->module;
1069 if (memcmp(module->digest, ctx->vl_pcr18, 20) != 0) {
1070 ERROR("Module[0] digest did not match\n");
1071 debugPrintHex(" TXT-STAT : ", ctx->vl_pcr18, 20, "\n");
1072 debugPrintHex(" Calc : ", module->digest, 20, "\n");
1074 eventdata = module->eventdata;
1075 event->ulEventLength = 20 + 20 + 4 + 4 + eventdata->command_size + eventdata->filename_size;
1076 event->rgbEvent = malloc(event->ulEventLength);
1077 if (event->rgbEvent == NULL) {
1081 ptr = event->rgbEvent;
1082 memcpy(ptr, eventdata->command_hash, 20);
1084 memcpy(ptr, eventdata->file_hash, 20);
1086 memcpy(ptr, &eventdata->command_size, 4);
1088 memcpy(ptr, eventdata->command, eventdata->command_size);
1089 ptr += eventdata->command_size;
1090 memcpy(ptr, &eventdata->filename_size, 4);
1092 memcpy(ptr, eventdata->filename, eventdata->filename_size);
1093 // DEBUG("%s\n", eventdata->command);
1094 // DEBUG("%s\n", eventdata->filename);
1096 event->ulEventLength = 0;
1097 event->rgbEvent = NULL;
1098 DEBUG(" module[0] eventdata = null, check the default value in the grub.conf\n");
1100 memcpy(event->rgbPcrValue, ctx->vl_pcr18, 20);
1101 writeEvent(fp, event);
1104 DEBUG(" module[1]\n");
1105 event->ulPcrIndex = 19;
1106 event->eventType = EV_TBOOT_MODULE;
1107 if ((ctx->module != NULL) && (ctx->module->next != NULL)) {
1108 TBOOT_MODULE *module;
1109 OPENPTS_EVENT_TBOOT_MODULE *eventdata;
1112 module = ctx->module->next;
1113 if (memcmp(module->digest, ctx->vl_pcr19, 20) != 0) {
1114 ERROR("Module[1] digest did not match\n");
1115 debugPrintHex(" TXT-STAT : ", ctx->vl_pcr19, 20, "\n");
1116 debugPrintHex(" Calc : ", module->digest, 20, "\n");
1118 eventdata = module->eventdata;
1119 event->ulEventLength = 20 + 20 + 4 + 4 + eventdata->command_size + eventdata->filename_size;
1120 if (event->rgbEvent != NULL) free(event->rgbEvent);
1121 event->rgbEvent = malloc(event->ulEventLength);
1122 if (event->rgbEvent == NULL) {
1126 ptr = event->rgbEvent;
1127 memcpy(ptr, eventdata->command_hash, 20);
1129 memcpy(ptr, eventdata->file_hash, 20);
1131 memcpy(ptr, &eventdata->command_size, 4);
1133 memcpy(ptr, eventdata->command, eventdata->command_size);
1134 ptr += eventdata->command_size;
1135 memcpy(ptr, &eventdata->filename_size, 4);
1137 memcpy(ptr, eventdata->filename, eventdata->filename_size);
1138 // DEBUG("%s\n", eventdata->command);
1139 // DEBUG("%s\n", eventdata->filename);
1141 event->ulEventLength = 0;
1142 event->rgbEvent = NULL;
1143 DEBUG(" module[0] eventdata = null, check the default value in the grub.conf\n");
1145 memcpy(event->rgbPcrValue, ctx->vl_pcr19, 20);
1146 writeEvent(fp, event);
1150 if (event != NULL) {
1151 if (event->rgbPcrValue != NULL) free(event->rgbPcrValue);
1152 if (event->rgbEvent != NULL) free(event->rgbEvent);
1157 if (filename != NULL) {
1166 fprintf(stderr, "OpenPTS command\n\n");
1167 fprintf(stderr, "Usage: tboot2iml [options]\n\n");
1168 fprintf(stderr, "Options:\n");
1169 fprintf(stderr, " -i filename txt-stat file to read (default is STDIN)\n");
1170 fprintf(stderr, " -g filename grub.conf file to read (OPTION)\n");
1171 fprintf(stderr, " -p path grub path (OPTION)\n");
1172 fprintf(stderr, " -o filename Output to file (default is STDOUT)\n");
1173 fprintf(stderr, " -v Verbose message\n");
1174 fprintf(stderr, " -h Help\n");
1175 fprintf(stderr, "\n");
1178 int main(int argc, char *argv[]) {
1180 char *txt_stat_filename = NULL;
1181 char *grub_conf_filename = NULL;
1182 char *iml_filename = NULL;
1183 OPENPTS_TBOOT_CONTEXT *ctx = NULL;
1185 char *grub_path = NULL; // TODO
1188 while ((c = getopt(argc, argv, "i:g:p:o:vh")) != EOF) {
1190 case 'i': /* input file name */
1191 txt_stat_filename = optarg;
1193 case 'g': /* input file name */
1194 grub_conf_filename = optarg;
1196 case 'p': /* input file name */
1199 case 'o': /* output file name */
1200 iml_filename = optarg;
1203 verbose = DEBUG_FLAG;
1205 case 'h': /* help */
1214 // printf("tboot to IML (%s)\n", txt_stat_filename);
1217 if ((grub_conf_filename != NULL) && (grub_path == NULL)) {
1218 fprintf(stderr, "set the root path used by crub.conf\n");
1224 ctx = malloc(sizeof(OPENPTS_TBOOT_CONTEXT));
1225 memset(ctx, 0, sizeof(OPENPTS_TBOOT_CONTEXT));
1226 ctx->lcp_policy_version = 1;
1228 /* parse TXT stat */
1229 rc = parseTxtStatFile(ctx, txt_stat_filename);
1230 if (rc != PTS_SUCCESS) {
1231 ERROR("parse of %s file was failed\n", txt_stat_filename);
1234 /* parse grub.conf */
1235 if (grub_conf_filename != NULL) {
1236 rc = parseGrubConfFile(ctx, grub_conf_filename, grub_path);
1239 /* parse grub.conf */
1242 /* validate IML and PCRs */
1243 rc = emulateTboot(ctx);
1245 // ctx = malloc(sizeof(OPENPTS_TBOOT_CONTEXT));
1249 rc = generateEventlog(ctx, iml_filename);