1/*
2 * The Initial Developer of the Original Code is International
3 * Business Machines Corporation. Portions created by IBM
4 * Corporation are Copyright (C) 2005 International Business
5 * Machines Corporation. All Rights Reserved.
6 *
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)
10 * any later version.
11 *
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.
16 *
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.
20 */
21
22#include <stdio.h>
23#include <errno.h>
24#include <limits.h>
25
26#include "tpm_tspi.h"
27#include "tpm_utils.h"
28#include "tpm_nvcommon.h"
29
30static unsigned int nvindex;
31static BOOL nvindex_set;
32static unsigned int nvperm;
33static unsigned int nvsize;
34static const char *ownerpass;
35static BOOL ownerWellKnown;
36static BOOL askOwnerPass;
37static const char *datapass;
38static BOOL dataWellKnown;
39static BOOL askDataPass;
40static int end;
41static UINT32 selectedPcrsRead[24];
42static UINT32 selectedPcrsWrite[24];
43static UINT32 selectedPcrsReadLen = 0;
44static UINT32 selectedPcrsWriteLen = 0;
45static const char *filename;
46
47TSS_HCONTEXT hContext = 0;
48
49
50static int parse(const int aOpt, const char *aArg)
51{
52	switch (aOpt) {
53	case 'i':
54		if (parseHexOrDecimal(aArg, &nvindex, 0, UINT_MAX,
55				      "NVRAM index") != 0)
56			return -1;
57		nvindex_set = TRUE;
58		break;
59
60	case 'p':
61		if (!strcmp(aArg, "?")) {
62			displayStringsAndValues(permvalues, "");
63			end = 1;
64			return 0;
65		}
66		if (parseStringWithValues(aArg, permvalues, &nvperm, UINT_MAX,
67				          "NVRAM permission") != 0)
68			return -1;
69		break;
70
71	case 's':
72		if (parseHexOrDecimal(aArg, &nvsize, 0, UINT_MAX,
73				      "NVRAM index size") != 0)
74			return -1;
75		break;
76
77	case 'o':
78		ownerpass = aArg;
79		if (!ownerpass)
80			askOwnerPass = TRUE;
81		else
82			askOwnerPass = FALSE;
83		ownerWellKnown = FALSE;
84		break;
85
86	case 'y':
87		ownerWellKnown = TRUE;
88		ownerpass = NULL;
89		askOwnerPass = FALSE;
90		break;
91
92	case 'a':
93		datapass = aArg;
94		if (!datapass)
95			askDataPass = TRUE;
96		else
97			askDataPass = FALSE;
98		dataWellKnown = FALSE;
99		break;
100
101	case 'z':
102		dataWellKnown = TRUE;
103		datapass = NULL;
104		askDataPass = FALSE;
105		break;
106
107	case 'u':
108		useUnicode = TRUE;
109		break;
110
111	case 'r':
112		if (aArg && atoi(aArg) >= 0 && atoi(aArg) < 24) {
113			selectedPcrsRead[selectedPcrsReadLen++] = atoi(aArg);
114		} else
115			return -1;
116		break;
117
118	case 'w':
119		if (aArg && atoi(aArg) >= 0 && atoi(aArg) < 24) {
120			selectedPcrsWrite[selectedPcrsWriteLen++] = atoi(aArg);
121		} else
122			return -1;
123		break;
124
125	case 'f':
126		filename = aArg;
127		break;
128
129	default:
130		return -1;
131	}
132	return 0;
133}
134
135static void help(const char* aCmd)
136{
137	logCmdHelp(aCmd);
138	logUnicodeCmdOption();
139	logCmdOption("-y, --owner-well-known",
140		     _("Use 20 bytes of zeros (TSS_WELL_KNOWN_SECRET) as the "
141		       "TPM owner secret"));
142	logCmdOption("-z, --data-well-known",
143		     _("Use 20 bytes of zeros (TSS_WELL_KNOWN_SECRET) as the "
144		       "NVRAM area's secret"));
145	logOwnerPassCmdOption();
146	logCmdOption("-a, --pwda",
147		     _("NVRAM area password"));
148	logNVIndexCmdOption();
149	logCmdOption("-s, --size",
150		     _("Size of the NVRAM area"));
151	logCmdOption("-r, --rpcrs",
152		     _("PCRs to seal the NVRAM area to for reading (use multiple times)"));
153	logCmdOption("-w, --wpcrs",
154		     _("PCRs to seal the NVRAM area to for writing (use multiple times)"));
155	logCmdOption("-f, --filename",
156		     _("File containing PCR info for the NVRAM area"));
157
158	logCmdOption("-p, --permissions",
159		     _("Permissions of the NVRAM area"));
160        displayStringsAndValues(permvalues, "                ");
161}
162
163void logInvalidPcrInfoFile()
164{
165	logError(_("Invalid PCR info file. Format is:\n"
166		 "[r/w] [PCR IDX] [SHA-1 ascii]\n\nExample:\n"
167		 "r 9 00112233445566778899AABBCCDDEEFF00112233"));
168}
169
170int
171parseNVPermsFile(FILE *f, TSS_HCONTEXT *hContext, TSS_HNVSTORE *nvObject,
172		 TSS_HPCRS *hPcrsRead, TSS_HPCRS *hPcrsWrite)
173{
174	UINT32 pcrSize;
175	char rw;
176	unsigned int pcr, n;
177	char hash_ascii[65], hash_bin[32], save;
178	int rc = -1;
179
180	while (!feof(f)) {
181		errno = 0;
182		n = fscanf(f, "%c %u %s\n", &rw, &pcr, hash_ascii);
183		if (n != 3) {
184			logInvalidPcrInfoFile();
185			goto out;
186		} else if (errno != 0) {
187			perror("fscanf");
188			goto out;
189		}
190
191		if (rw != 'r' && rw != 'w') {
192			logInvalidPcrInfoFile();
193			goto out;
194		}
195
196		if (pcr > 15) {
197			logError(_("Cannot seal NVRAM area to PCR > 15\n"));
198			goto out;
199		}
200
201		for (n = 0; n < strlen(hash_ascii); n += 2) {
202			save = hash_ascii[n + 2];
203			hash_ascii[n + 2] = '\0';
204			hash_bin[n/2] = strtoul(&hash_ascii[n], NULL, 16);
205			hash_ascii[n + 2] = save;
206		}
207		pcrSize = n/2;
208
209		if (rw == 'r') {
210			if (*hPcrsRead == NULL_HPCRS)
211				if (contextCreateObject(*hContext, TSS_OBJECT_TYPE_PCRS,
212							TSS_PCRS_STRUCT_INFO_SHORT,
213							hPcrsRead) != TSS_SUCCESS)
214					goto out;
215
216			if (pcrcompositeSetPcrValue(*hPcrsRead, pcr, pcrSize, (BYTE *)hash_bin)
217					!= TSS_SUCCESS)
218				goto out;
219		} else {
220			if (*hPcrsWrite == NULL_HPCRS)
221				if (contextCreateObject(*hContext, TSS_OBJECT_TYPE_PCRS,
222							TSS_PCRS_STRUCT_INFO_SHORT,
223							hPcrsWrite) != TSS_SUCCESS)
224					goto out;
225
226			if (pcrcompositeSetPcrValue(*hPcrsWrite, pcr, pcrSize, (BYTE *)hash_bin)
227					!= TSS_SUCCESS)
228				goto out;
229		}
230	}
231
232	rc = 0;
233out:
234	return rc;
235}
236
237int main(int argc, char **argv)
238{
239	TSS_HTPM hTpm;
240	TSS_HNVSTORE nvObject;
241	TSS_FLAG fNvAttrs;
242	TSS_HPOLICY hTpmPolicy, hDataPolicy;
243	int iRc = -1;
244	BYTE well_known_secret[] = TSS_WELL_KNOWN_SECRET;
245	int opswd_len = -1;
246	int dpswd_len = -1;
247	TSS_HPCRS hPcrsRead = 0, hPcrsWrite = 0;
248	struct option hOpts[] = {
249		{"index"           , required_argument, NULL, 'i'},
250		{"size"            , required_argument, NULL, 's'},
251		{"permissions"     , required_argument, NULL, 'p'},
252		{"rpcrs"           , required_argument, NULL, 'r'},
253		{"wpcrs"           , required_argument, NULL, 'w'},
254		{"filename"        , required_argument, NULL, 'f'},
255		{"pwdo"            , optional_argument, NULL, 'o'},
256		{"pwda"            , optional_argument, NULL, 'a'},
257		{"use-unicode"     ,       no_argument, NULL, 'u'},
258		{"data-well-known" ,       no_argument, NULL, 'z'},
259		{"owner-well-known",       no_argument, NULL, 'y'},
260		{NULL              ,       no_argument, NULL, 0},
261	};
262	TSS_FLAG initFlag = TSS_PCRS_STRUCT_INFO_SHORT;
263	UINT32 localityValue = TPM_LOC_ZERO | TPM_LOC_ONE | TPM_LOC_TWO |
264			       TPM_LOC_THREE | TPM_LOC_FOUR;
265
266	initIntlSys();
267
268	if (genericOptHandler
269		    (argc, argv, "i:s:p:o:a:r:w:f:yzu", hOpts,
270		     sizeof(hOpts) / sizeof(struct option), parse, help) != 0)
271		goto out;
272
273	if (end) {
274		iRc = 0;
275		goto out;
276	}
277
278	if (!nvindex_set) {
279		logError(_("You must provide an index for the NVRAM area.\n"));
280		goto out;
281	}
282
283	if (nvperm == 0 &&
284	    (UINT32)nvindex != TPM_NV_INDEX_LOCK &&
285	    (UINT32)nvindex != TPM_NV_INDEX0) {
286		logError(_("You must provide permission bits for the NVRAM area.\n"));
287		goto out;
288	}
289
290	logDebug("permissions = 0x%08x\n", nvperm);
291
292	if (contextCreate(&hContext) != TSS_SUCCESS)
293		goto out;
294
295	if (contextConnect(hContext) != TSS_SUCCESS)
296		goto out_close;
297
298	if (contextGetTpm(hContext, &hTpm) != TSS_SUCCESS)
299		goto out_close;
300
301	fNvAttrs = 0;
302
303	if (contextCreateObject(hContext,
304				TSS_OBJECT_TYPE_NV,
305				fNvAttrs,
306				&nvObject) != TSS_SUCCESS)
307		goto out_close;
308
309	if (askOwnerPass) {
310		ownerpass = _GETPASSWD(_("Enter owner password: "), &opswd_len,
311			FALSE, useUnicode );
312		if (!ownerpass) {
313			logError(_("Failed to get owner password\n"));
314			goto out_close;
315		}
316	}
317
318	if (ownerpass || ownerWellKnown) {
319		if (policyGet(hTpm, &hTpmPolicy) != TSS_SUCCESS)
320			goto out_close;
321		if (ownerpass) {
322			if (opswd_len < 0)
323				opswd_len = strlen(ownerpass);
324			if (policySetSecret(hTpmPolicy, opswd_len,
325					    (BYTE *)ownerpass) != TSS_SUCCESS)
326				goto out_close;
327		} else {
328			if (policySetSecret(hTpmPolicy, TCPA_SHA1_160_HASH_LEN,
329					    (BYTE *)well_known_secret) != TSS_SUCCESS)
330				goto out_close;
331		}
332	}
333
334	if (askDataPass) {
335		datapass = _GETPASSWD(_("Enter NVRAM data password: "), &dpswd_len,
336			TRUE, useUnicode );
337		if (!datapass) {
338			logError(_("Failed to get NVRAM data password\n"));
339			goto out_close;
340		}
341	}
342
343	if (datapass || dataWellKnown) {
344		if (contextCreateObject
345		    (hContext, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE,
346		     &hDataPolicy) != TSS_SUCCESS)
347			goto out_close;
348
349		if (datapass) {
350			if (dpswd_len < 0)
351				dpswd_len = strlen(datapass);
352			if (policySetSecret(hDataPolicy, dpswd_len,
353				    (BYTE *)datapass) != TSS_SUCCESS)
354				goto out_close;
355		} else {
356			if (policySetSecret(hDataPolicy, TCPA_SHA1_160_HASH_LEN,
357				    (BYTE *)well_known_secret) != TSS_SUCCESS)
358				goto out_close;
359		}
360
361		if (Tspi_Policy_AssignToObject(hDataPolicy, nvObject) !=
362		    TSS_SUCCESS)
363			goto out_close;
364	}
365
366	if (Tspi_SetAttribUint32(nvObject,
367				 TSS_TSPATTRIB_NV_INDEX,
368				 0,
369				 nvindex) != TSS_SUCCESS)
370		goto out_close_obj;
371
372	if (Tspi_SetAttribUint32(nvObject,
373				 TSS_TSPATTRIB_NV_PERMISSIONS,
374				 0,
375				 nvperm) != TSS_SUCCESS)
376		goto out_close_obj;
377
378	if (Tspi_SetAttribUint32(nvObject,
379				 TSS_TSPATTRIB_NV_DATASIZE,
380				 0,
381				 nvsize) != TSS_SUCCESS)
382		goto out_close_obj;
383
384	if (selectedPcrsReadLen) {
385		UINT32 pcrSize;
386		BYTE *pcrValue;
387		UINT32 i;
388
389		for (i = 0; i < selectedPcrsReadLen; i++) {
390			if (selectedPcrsRead[i] > 15) {
391				logError(_("Cannot seal NVRAM area to PCR > 15\n"));
392				goto out_close;
393			}
394		}
395
396		if (contextCreateObject(hContext, TSS_OBJECT_TYPE_PCRS, initFlag,
397					&hPcrsRead) != TSS_SUCCESS)
398			goto out_close;
399
400		for (i = 0; i < selectedPcrsReadLen; i++) {
401			if (tpmPcrRead(hTpm, selectedPcrsRead[i], &pcrSize, &pcrValue) !=
402			    TSS_SUCCESS)
403				goto out_close;
404
405			if (pcrcompositeSetPcrValue(hPcrsRead, selectedPcrsRead[i],
406						    pcrSize, pcrValue)
407					!= TSS_SUCCESS)
408				goto out_close;
409		}
410	}
411
412	if (selectedPcrsWriteLen) {
413		UINT32 pcrSize;
414		BYTE *pcrValue;
415		UINT32 i;
416
417		for (i = 0; i < selectedPcrsWriteLen; i++) {
418			if (selectedPcrsWrite[i] > 15) {
419				logError(_("Cannot seal NVRAM area to PCR > 15\n"));
420				goto out_close;
421			}
422		}
423
424		if (contextCreateObject(hContext, TSS_OBJECT_TYPE_PCRS, initFlag,
425					&hPcrsWrite) != TSS_SUCCESS)
426			goto out_close;
427
428		for (i = 0; i < selectedPcrsWriteLen; i++) {
429			if (tpmPcrRead(hTpm, selectedPcrsWrite[i], &pcrSize, &pcrValue) !=
430			    TSS_SUCCESS)
431				goto out_close;
432
433			if (pcrcompositeSetPcrValue(hPcrsWrite, selectedPcrsWrite[i],
434						    pcrSize, pcrValue)
435					!= TSS_SUCCESS)
436				goto out_close;
437		}
438	}
439
440	if (filename) {
441		FILE *f;
442
443		f = fopen(filename, "r");
444		if (!f) {
445			logError(_("Could not access file '%s'\n"), filename);
446			goto out_close_obj;
447		}
448
449		if (parseNVPermsFile(f, &hContext, &nvObject, &hPcrsRead, &hPcrsWrite)
450		    != TSS_SUCCESS)
451			goto out_close_obj;
452	}
453
454	if (hPcrsRead)
455		if (pcrcompositeSetPcrLocality(hPcrsRead, localityValue) != TSS_SUCCESS)
456			goto out_close;
457
458	if (hPcrsWrite)
459		if (pcrcompositeSetPcrLocality(hPcrsWrite, localityValue) != TSS_SUCCESS)
460			goto out_close;
461
462	if (NVDefineSpace(nvObject, hPcrsRead, hPcrsWrite) != TSS_SUCCESS)
463		goto out_close;
464
465	logMsg(_("Successfully created NVRAM area at index 0x%x (%u).\n"),
466	       nvindex, nvindex);
467
468	iRc = 0;
469
470	goto out_close;
471
472      out_close_obj:
473	contextCloseObject(hContext, nvObject);
474
475      out_close:
476	contextClose(hContext);
477
478      out:
479	return iRc;
480}
481