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 <limits.h>
23 #include <ctype.h>
24 
25 #include "tpm_nvcommon.h"
26 #include "tpm_tspi.h"
27 #include "tpm_utils.h"
28 
29 const struct strings_with_values permvalues[] = {
30 	{
31 		.name = "AUTHREAD",
32 		.value = TPM_NV_PER_AUTHREAD,
33 		.desc = _("reading requires NVRAM area authorization"),
34 	},
35 	{
36 		.name = "AUTHWRITE",
37 		.value = TPM_NV_PER_AUTHWRITE,
38 		.desc = _("writing requires NVRAM area authorization"),
39 	},
40 	{
41 		.name = "OWNERREAD",
42 		.value = TPM_NV_PER_OWNERREAD,
43 		.desc = _("writing requires owner authorization"),
44 	},
45 	{
46 		.name = "OWNERWRITE",
47 		.value = TPM_NV_PER_OWNERWRITE,
48 		.desc = _("reading requires owner authorization"),
49 	},
50 	{
51 		.name = "PPREAD",
52 		.value = TPM_NV_PER_PPREAD,
53 		.desc = _("writing requires physical presence"),
54 	},
55 	{
56 		.name = "PPWRITE",
57 		.value = TPM_NV_PER_PPWRITE,
58 		.desc = _("reading requires physical presence"),
59 	},
60 	{
61 		.name = "GLOBALLOCK",
62 		.value = TPM_NV_PER_GLOBALLOCK,
63 		.desc = _("write to index 0 locks the NVRAM area until "
64 		          "TPM_STARTUP(ST_CLEAR)"),
65 	},
66 	{
67 		.name = "READ_STCLEAR",
68 		.value = TPM_NV_PER_READ_STCLEAR,
69 		.desc = _("a read with size 0 to the same index prevents further "
70 		          "reading until ST_STARTUP(ST_CLEAR)"),
71 	},
72 	{
73 		.name = "WRITE_STCLEAR",
74 		.value = TPM_NV_PER_WRITE_STCLEAR,
75 		.desc = _("a write with size 0 to the same index prevents further "
76                           "writing until ST_STARTUP(ST_CLEAR)"),
77 	},
78 	{
79 		.name = "WRITEDEFINE",
80 		.value = TPM_NV_PER_WRITEDEFINE,
81 		.desc = _("a write with size 0 to the same index locks the "
82 		          "NVRAM area permanently"),
83 	},
84 	{
85 		.name = "WRITEALL",
86 		.value = TPM_NV_PER_WRITEALL,
87 		.desc = _("the value must be written in a single operation"),
88 	},
89 	{
90 		.name = NULL,
91 	},
92 };
93 
94 
displayStringsAndValues(const struct strings_with_values * svals,const char * indent)95 void displayStringsAndValues(const struct strings_with_values *svals,
96                              const char *indent)
97 {
98 	unsigned int i;
99 
100 	logMsg("%sThe following strings are available:\n", indent);
101 	for (i = 0; svals[i].name; i++)
102 		logMsg("%s%15s : %s\n", indent, svals[i].name, svals[i].desc);
103 }
104 
105 
parseStringWithValues(const char * aArg,const struct strings_with_values * svals,unsigned int * x,unsigned int maximum,const char * name)106 int parseStringWithValues(const char *aArg,
107 			  const struct strings_with_values *svals,
108 			  unsigned int *x, unsigned int maximum,
109 			  const char *name)
110 {
111 	unsigned int offset = 0;
112 	int i, num, numbytes;
113 	size_t totlen = strlen(aArg);
114 	*x = 0;
115 
116 	while (offset < totlen) {
117 		int found = 0;
118 
119 		while (isspace(*(aArg + offset)))
120 			offset++;
121 
122 		for (i = 0; svals[i].name; i++) {
123 			size_t len = strlen(svals[i].name);
124 			if (strncmp(aArg + offset, svals[i].name, len) == 0 &&
125 				    (aArg[offset+len] == '|' ||
126 				     aArg[offset+len] == 0)) {
127 				*x |= svals[i].value;
128 				offset += len + 1;
129 				found = 1;
130 				break;
131 			}
132 		}
133 
134 		if (!found) {
135 			if (strncmp(aArg + offset, "0x", 2) == 0) {
136 				if (sscanf(aArg + offset, "%x%n", &num, &numbytes)
137 				    != 1) {
138 					logError(_("Could not parse hexadecimal "
139 					           "number in %s.\n"),
140 						 aArg);
141 					return -1;
142 				}
143 				if (aArg[offset+numbytes] != '|' ||
144 				    aArg[offset+numbytes] != 0) {
145 					logError(_("Illegal character following "
146                                                    "hexadecimal number in %s\n"),
147 						 aArg + offset);
148 					return -1;
149 				}
150 				*x |= num;
151 
152 				offset += numbytes + 1;
153 				found = 1;
154 			}
155 		}
156 
157 		while (!found) {
158 			if (!isdigit(*(aArg+offset)))
159 				break;
160 
161 			if (sscanf(aArg + offset, "%u%n", &num, &numbytes) != 1) {
162 				logError(_("Could not parse data in %s.\n"),
163 					 aArg + offset);
164 				return -1;
165 			}
166 
167 			if (aArg[offset+numbytes] != '|' &&
168 			    aArg[offset+numbytes] != 0) {
169 				logError(_("Illegal character following decimal "
170 				           "number in %s\n"),
171 					 aArg + offset);
172 				return -1;
173 			}
174 			*x |= num;
175 
176 			offset += numbytes + 1;
177 			found = 1;
178 			break;
179 		}
180 
181 		if (!found) {
182 			logError(_("Unknown element in %s: %s.\n"),
183 			         name, aArg + offset);
184 			return -1;
185 		}
186 	}
187 
188 	return 0;
189 }
190 
191 
printValueAsStrings(unsigned int value,const struct strings_with_values * svals)192 char *printValueAsStrings(unsigned int value,
193 			  const struct strings_with_values *svals)
194 {
195 	unsigned int mask = (1 << 31), i,c;
196 	unsigned int buffer_size = 1024;
197 	char *buffer = calloc(1, buffer_size);
198 	char printbuf[30];
199 	size_t len;
200 
201 	c = 0;
202 
203 	while (mask && value) {
204 		if (value & mask) {
205 			for (i = 0; svals[i].name; i++) {
206 				if (svals[i].value == mask) {
207 					len = strlen(svals[i].name);
208 					if (len + strlen(buffer) + 1 >
209 					    buffer_size) {
210 						buffer_size += 1024;
211 						buffer = realloc(buffer,
212 								 buffer_size);
213 						if (!buffer)
214 							return NULL;
215 					}
216 					if (c)
217 						strcat(buffer, "|");
218 					strcat(buffer, svals[i].name);
219 					c ++;
220 					value ^= mask;
221 					break;
222 				}
223 			}
224 		}
225 		mask >>= 1;
226 	}
227 	if (value) {
228 		snprintf(printbuf, sizeof(printbuf), "%s0x%x",
229 		         c ? "|" : "",
230 		         value);
231                 len = strlen(printbuf);
232 		if (len + strlen(buffer) + 1 > buffer_size) {
233 			buffer_size += 1024;
234 			buffer = realloc(buffer,
235 					 buffer_size);
236 			if (!buffer)
237 				return NULL;
238 		}
239 		if (c)
240 			strcat(buffer, printbuf);
241 	}
242 	return buffer;
243 }
244 
245 
parseHexOrDecimal(const char * aArg,unsigned int * x,unsigned int minimum,unsigned int maximum,const char * name)246 int parseHexOrDecimal(const char *aArg, unsigned int *x,
247                       unsigned int minimum, unsigned int maximum,
248 		      const char *name)
249 {
250 	while (isspace(*aArg))
251 		aArg++;
252 
253 	if (strncmp(aArg, "0x", 2) == 0) {
254 		if (sscanf(aArg, "%x", x) != 1) {
255 			return -1;
256 		}
257 	} else {
258 		if (!isdigit(*aArg)) {
259 		        fprintf(stderr,
260 		                "%s must be a positive integer.\n", name);
261 			return -1;
262                 }
263 
264 		if (sscanf(aArg, "%u", x) != 1) {
265 			return -1;
266 		}
267 	}
268 
269 	if ((*x > maximum) || (*x < minimum)) {
270 		fprintf(stderr, "%s is out of valid range [%u, %u]\n",
271 			name, minimum, maximum);
272 		return -1;
273 	}
274 
275 	return 0;
276 }
277 
278 
getNVDataPublic(TSS_HTPM hTpm,TPM_NV_INDEX nvindex,TPM_NV_DATA_PUBLIC ** pub)279 TSS_RESULT getNVDataPublic(TSS_HTPM hTpm, TPM_NV_INDEX nvindex,
280                            TPM_NV_DATA_PUBLIC **pub)
281 {
282 	TSS_RESULT res;
283 	UINT32 ulResultLen;
284 	BYTE *pResult;
285 	UINT64 off = 0;
286 
287 	res = getCapability(hTpm, TSS_TPMCAP_NV_INDEX, sizeof(UINT32),
288 			    (BYTE *)&nvindex, &ulResultLen, &pResult);
289 
290 	if (res != TSS_SUCCESS)
291 		return res;
292 
293 	*pub = calloc(1, sizeof(TPM_NV_DATA_PUBLIC));
294 	if (*pub == NULL) {
295 		res = TSS_E_OUTOFMEMORY;
296 		goto err_exit;
297 	}
298 
299 	res = unloadNVDataPublic(&off, pResult, ulResultLen, *pub);
300 
301 	if (res != TSS_SUCCESS) {
302 		freeNVDataPublic(*pub);
303 		*pub = NULL;
304 	}
305 err_exit:
306 	return res;
307 }
308 
freeNVDataPublic(TPM_NV_DATA_PUBLIC * pub)309 void freeNVDataPublic(TPM_NV_DATA_PUBLIC *pub)
310 {
311 	if (!pub)
312 		return;
313 
314 	free(pub->pcrInfoRead.pcrSelection.pcrSelect);
315 	free(pub->pcrInfoWrite.pcrSelection.pcrSelect);
316 	free(pub);
317 }
318