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 
30 static unsigned int nvindex;
31 static BOOL nvindex_set;
32 static unsigned int nvperm;
33 static unsigned int nvsize;
34 static const char *ownerpass;
35 static BOOL ownerWellKnown;
36 static BOOL askOwnerPass;
37 static const char *datapass;
38 static BOOL dataWellKnown;
39 static BOOL askDataPass;
40 static int end;
41 static UINT32 selectedPcrsRead[24];
42 static UINT32 selectedPcrsWrite[24];
43 static UINT32 selectedPcrsReadLen = 0;
44 static UINT32 selectedPcrsWriteLen = 0;
45 static const char *filename;
46 
47 TSS_HCONTEXT hContext = 0;
48 
49 
parse(const int aOpt,const char * aArg)50 static 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 
help(const char * aCmd)135 static 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 
logInvalidPcrInfoFile()163 void 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 
170 int
parseNVPermsFile(FILE * f,TSS_HCONTEXT * hContext,TSS_HNVSTORE * nvObject,TSS_HPCRS * hPcrsRead,TSS_HPCRS * hPcrsWrite)171 parseNVPermsFile(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;
233 out:
234 	return rc;
235 }
236 
main(int argc,char ** argv)237 int 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