1Index: git/include/tpm_tspi.h
2===================================================================
3--- git.orig/include/tpm_tspi.h
4+++ git/include/tpm_tspi.h
5@@ -117,6 +117,10 @@ TSS_RESULT tpmPcrRead(TSS_HTPM a_hTpm, U
6 			UINT32 *a_PcrSize, BYTE **a_PcrValue);
7 TSS_RESULT pcrcompositeSetPcrValue(TSS_HPCRS a_hPcrs, UINT32 a_Idx,
8 					UINT32 a_PcrSize, BYTE *a_PcrValue);
9+TSS_RESULT tpmPcrExtend(TSS_HTPM a_hTpm, UINT32 a_Idx,
10+			UINT32 a_DataSize, BYTE *a_Data,
11+			TSS_PCR_EVENT *a_Event,
12+			UINT32 *a_PcrSize, BYTE **a_PcrValue);
13 #ifdef TSS_LIB_IS_12
14 TSS_RESULT unloadVersionInfo(UINT64 *offset, BYTE *blob, TPM_CAP_VERSION_INFO *v);
15 TSS_RESULT pcrcompositeSetPcrLocality(TSS_HPCRS a_hPcrs, UINT32 localityValue);
16Index: git/lib/tpm_tspi.c
17===================================================================
18--- git.orig/lib/tpm_tspi.c
19+++ git/lib/tpm_tspi.c
20@@ -594,6 +594,20 @@ pcrcompositeSetPcrValue(TSS_HPCRS a_hPcr
21 	return result;
22 }
23
24+TSS_RESULT
25+tpmPcrExtend(TSS_HTPM a_hTpm, UINT32 a_Idx,
26+		UINT32 a_DataSize, BYTE *a_Data,
27+		TSS_PCR_EVENT *a_Event,
28+		UINT32 *a_PcrSize, BYTE **a_PcrValue)
29+{
30+	TSS_RESULT result =
31+		Tspi_TPM_PcrExtend(a_hTpm, a_Idx, a_DataSize, a_Data, a_Event,
32+				   a_PcrSize, a_PcrValue);
33+	tspiResult("Tspi_TPM_PcrExtend", result);
34+
35+	return result;
36+}
37+
38 #ifdef TSS_LIB_IS_12
39 /*
40  * These getPasswd functions will wrap calls to the other functions and check to see if the TSS
41Index: git/src/cmds/Makefile.am
42===================================================================
43--- git.orig/src/cmds/Makefile.am
44+++ git/src/cmds/Makefile.am
45@@ -22,6 +22,7 @@
46 #
47
48 bin_PROGRAMS 	=	tpm_sealdata \
49+			tpm_extendpcr \
50 			tpm_unsealdata
51
52 if TSS_LIB_IS_12
53@@ -33,4 +34,5 @@ endif
54 LDADD		=	$(top_builddir)/lib/libtpm_tspi.la -ltspi $(top_builddir)/lib/libtpm_unseal.la -ltpm_unseal -lcrypto @INTLLIBS@
55
56 tpm_sealdata_SOURCES = tpm_sealdata.c
57+tpm_extendpcr_SOURCES = tpm_extendpcr.c
58 tpm_unsealdata_SOURCES = tpm_unsealdata.c
59Index: git/src/cmds/tpm_extendpcr.c
60===================================================================
61--- /dev/null
62+++ git/src/cmds/tpm_extendpcr.c
63@@ -0,0 +1,181 @@
64+/*
65+ * The Initial Developer of the Original Code is International
66+ * Business Machines Corporation. Portions created by IBM
67+ * Corporation are Copyright (C) 2005, 2006 International Business
68+ * Machines Corporation. All Rights Reserved.
69+ *
70+ * This program is free software; you can redistribute it and/or modify
71+ * it under the terms of the Common Public License as published by
72+ * IBM Corporation; either version 1 of the License, or (at your option)
73+ * any later version.
74+ *
75+ * This program is distributed in the hope that it will be useful,
76+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
77+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
78+ * Common Public License for more details.
79+ *
80+ * You should have received a copy of the Common Public License
81+ * along with this program; if not, a copy can be viewed at
82+ * http://www.opensource.org/licenses/cpl1.0.php.
83+ */
84+#include <openssl/evp.h>
85+#include <openssl/sha.h>
86+#include <limits.h>
87+#include "tpm_tspi.h"
88+#include "tpm_utils.h"
89+#include "tpm_seal.h"
90+
91+// #define TPM_EXTENDPCR_DEBUG
92+
93+static void help(const char *aCmd)
94+{
95+	logCmdHelp(aCmd);
96+	logCmdOption("-i, --infile FILE",
97+		     _
98+		     ("Filename containing data to extend PCRs with. Default is STDIN."));
99+	logCmdOption("-p, --pcr NUMBER",
100+		     _("PCR to extend."));
101+
102+}
103+
104+static char in_filename[PATH_MAX] = "";
105+static TSS_HPCRS hPcrs = NULL_HPCRS;
106+static TSS_HTPM hTpm;
107+static UINT32 selectedPcrs[24];
108+static UINT32 selectedPcrsLen = 0;
109+TSS_HCONTEXT hContext = 0;
110+
111+static int parse(const int aOpt, const char *aArg)
112+{
113+	int rc = -1;
114+
115+	switch (aOpt) {
116+	case 'i':
117+		if (aArg) {
118+			strncpy(in_filename, aArg, PATH_MAX);
119+			rc = 0;
120+		}
121+		break;
122+	case 'p':
123+		if (aArg) {
124+			selectedPcrs[selectedPcrsLen++] = atoi(aArg);
125+			rc = 0;
126+		}
127+		break;
128+	default:
129+		break;
130+	}
131+	return rc;
132+
133+}
134+
135+int main(int argc, char **argv)
136+{
137+
138+	int iRc = -1;
139+	struct option opts[] = {
140+		{"infile", required_argument, NULL, 'i'},
141+		{"pcr", required_argument, NULL, 'p'},
142+	};
143+	unsigned char line[EVP_MD_block_size(EVP_sha1()) * 16];
144+	int lineLen;
145+	UINT32 i;
146+
147+	BIO *bin = NULL;
148+
149+	initIntlSys();
150+
151+	if (genericOptHandler(argc, argv, "i:p:", opts,
152+			      sizeof(opts) / sizeof(struct option), parse,
153+			      help) != 0)
154+		goto out;
155+
156+	if (contextCreate(&hContext) != TSS_SUCCESS)
157+		goto out;
158+
159+	if (contextConnect(hContext) != TSS_SUCCESS)
160+		goto out_close;
161+
162+	if (contextGetTpm(hContext, &hTpm) != TSS_SUCCESS)
163+		goto out_close;
164+
165+	/* Create a BIO for the input file */
166+	if ((bin = BIO_new(BIO_s_file())) == NULL) {
167+		logError(_("Unable to open input BIO\n"));
168+		goto out_close;
169+	}
170+
171+	/* Assign the input file to the BIO */
172+	if (strlen(in_filename) == 0)
173+		BIO_set_fp(bin, stdin, BIO_NOCLOSE);
174+	else if (!BIO_read_filename(bin, in_filename)) {
175+		logError(_("Unable to open input file: %s\n"),
176+			 in_filename);
177+		goto out_close;
178+	}
179+
180+	/* Create the PCRs object. If any PCRs above 15 are selected, this will need to be
181+	 * a 1.2 TSS/TPM */
182+	if (selectedPcrsLen) {
183+		TSS_FLAG initFlag = 0;
184+		UINT32 pcrSize;
185+		BYTE *pcrValue;
186+
187+		for (i = 0; i < selectedPcrsLen; i++) {
188+			if (selectedPcrs[i] > 15) {
189+#ifdef TSS_LIB_IS_12
190+				initFlag |= TSS_PCRS_STRUCT_INFO_LONG;
191+#else
192+				logError(_("This version of %s was compiled for a v1.1 TSS, which "
193+					 "can only seal\n data to PCRs 0-15. PCR %u is out of range"
194+					 "\n"), argv[0], selectedPcrs[i]);
195+				goto out_close;
196+#endif
197+			}
198+		}
199+
200+		unsigned char msg[EVP_MAX_MD_SIZE];
201+		unsigned int msglen;
202+		EVP_MD_CTX ctx;
203+		EVP_DigestInit(&ctx, EVP_sha1());
204+		while ((lineLen = BIO_read(bin, line, sizeof(line))) > 0)
205+			EVP_DigestUpdate(&ctx, line, lineLen);
206+		EVP_DigestFinal(&ctx, msg, &msglen);
207+
208+		if (contextCreateObject(hContext, TSS_OBJECT_TYPE_PCRS, initFlag,
209+					&hPcrs) != TSS_SUCCESS)
210+			goto out_close;
211+
212+		for (i = 0; i < selectedPcrsLen; i++) {
213+#ifdef TPM_EXTENDPCR_DEBUG
214+			if (tpmPcrRead(hTpm, selectedPcrs[i], &pcrSize, &pcrValue) != TSS_SUCCESS)
215+				goto out_close;
216+
217+			unsigned int j;
218+			for (j = 0; j < pcrSize; j++)
219+			  printf("%02X ", pcrValue[j]);
220+			printf("\n");
221+#endif
222+
223+			if (tpmPcrExtend(hTpm, selectedPcrs[i], msglen, msg, NULL, &pcrSize, &pcrValue) != TSS_SUCCESS)
224+			  goto out_close;
225+
226+#ifdef TPM_EXTENDPCR_DEBUG
227+			for (j = 0; j < pcrSize; j++)
228+			  printf("%02X ", pcrValue[j]);
229+			printf("\n");
230+#endif
231+		}
232+	}
233+
234+	iRc = 0;
235+	logSuccess(argv[0]);
236+
237+out_close:
238+	contextClose(hContext);
239+
240+out:
241+	if (bin)
242+		BIO_free(bin);
243+	return iRc;
244+}
245