xref: /netbsd-src/crypto/external/cpl/tpm-tools/dist/src/tpm_mgmt/tpm_nvwrite.c (revision 8cc77b481a5f7140fcf2d44453fb92dcd15fbbc6)
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 <sys/types.h>
23 #include <sys/stat.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <limits.h>
27 
28 #include "tpm_nvcommon.h"
29 #include "tpm_tspi.h"
30 #include "tpm_utils.h"
31 
32 static BOOL nvindex_set;
33 static unsigned int nvindex;
34 static unsigned int offset;
35 static unsigned int length;
36 static int fillvalue = -1;
37 static const char *filename;
38 static BOOL passWellKnown;
39 static BOOL askPassword;
40 static const char *password;
41 static char *data;
42 
43 TSS_HCONTEXT hContext = 0;
44 
45 
parse(const int aOpt,const char * aArg)46 static int parse(const int aOpt, const char *aArg)
47 {
48 
49 	switch (aOpt) {
50 	case 'i':
51 		if (parseHexOrDecimal(aArg, &nvindex, 0, UINT_MAX,
52 				      "NVRAM index") != 0)
53 			return -1;
54 
55 		nvindex_set = 1;
56 
57 		break;
58 
59 	case 's':
60 		if (parseHexOrDecimal(aArg, &length, 0, UINT_MAX,
61 				      "length of data") != 0)
62 			return -1;
63 		break;
64 
65 	case 'n':
66 		if (parseHexOrDecimal(aArg, &offset, 0, UINT_MAX,
67 				      "write offset") != 0)
68 			return -1;
69 		break;
70 
71 	case 'd':
72 		data = strdup(aArg);
73 		if (data == NULL) {
74 			logError(_("Out of memory\n"));
75 			return -1;
76 		}
77 		break;
78 
79 	case 'f':
80 		filename = aArg;
81 		break;
82 
83 	case 'm':
84 		if (parseHexOrDecimal(aArg, (unsigned int *)&fillvalue,
85 		                      0, UCHAR_MAX,
86 				      "fill value") != 0)
87 			return -1;
88 		break;
89 
90 	case 'p':
91 		password = aArg;
92 		if (!password)
93 			askPassword = TRUE;
94 		else
95 			askPassword = FALSE;
96 		passWellKnown =  FALSE;
97 		break;
98 
99 	case 'z':
100 		password = NULL;
101 		passWellKnown =  TRUE;
102 		askPassword = FALSE;
103 		break;
104 
105 	case 'u':
106 		useUnicode = TRUE;
107 		break;
108 
109 	default:
110 		return -1;
111 	}
112 	return 0;
113 }
114 
help(const char * aCmd)115 static void help(const char* aCmd)
116 {
117 	logCmdHelp(aCmd);
118 	logUnicodeCmdOption();
119 	logCmdOption("-z, --well-known",
120 		     _("Use 20 bytes of zeros (TSS_WELL_KNOWN_SECRET) as the TPM secret authorization data"));
121 	logCmdOption("-p, --password",
122 		     _("Owner or NVRAM area password depending on permissions"));
123 	logNVIndexCmdOption();
124 	logCmdOption("-s, --size",
125 		     _("Number of bytes to write to the NVRAM area"));
126 	logCmdOption("-n, --offset",
127 		     _("Offset at which to start writing into the NVRAM area"));
128 	logCmdOption("-f, --filename",
129 		     _("File whose contents to write into the NVRAM area"));
130 	logCmdOption("-d, --data",
131 		     _("Data to write into the NVRAM area"));
132 	logCmdOption("-m, --fill-value",
133 		     _("The byte to fill the NVRAM area with"));
134 }
135 
main(int argc,char ** argv)136 int main(int argc, char **argv)
137 {
138 
139 	TSS_HTPM hTpm;
140 	TSS_HNVSTORE nvObject;
141 	TSS_FLAG fNvAttrs;
142 	UINT32 ulDataLength, bytesToWrite, off;
143 	BYTE *rgbDataToWrite = NULL;
144 	TSS_HPOLICY hTpmPolicy, hDataPolicy;
145 	TPM_NV_DATA_PUBLIC *nvpub = NULL;
146 	int iRc = -1;
147 	BYTE well_known_secret[] = TSS_WELL_KNOWN_SECRET;
148 	int pswd_len = -1;
149 	struct option hOpts[] = {
150 		{"index"      , required_argument, NULL, 'i'},
151 		{"size"       , required_argument, NULL, 's'},
152 		{"offset"     , required_argument, NULL, 'n'},
153 		{"data"       , required_argument, NULL, 'd'},
154 		{"filename"   , required_argument, NULL, 'f'},
155 		{"fillvalue"  , required_argument, NULL, 'm'},
156 		{"password"   , optional_argument, NULL, 'p'},
157 		{"use-unicode",       no_argument, NULL, 'u'},
158 		{"well-known" ,       no_argument, NULL, 'z'},
159 		{NULL	 ,       no_argument, NULL, 0},
160 	};
161 	struct stat statbuf;
162 	int fd = -1;
163 	ssize_t read_bytes;
164 
165 	initIntlSys();
166 
167 	if (genericOptHandler
168 		    (argc, argv, "i:s:n:d:f:m:p::zu", hOpts,
169 		     sizeof(hOpts) / sizeof(struct option), parse, help) != 0)
170 		goto out;
171 
172 	if (nvindex_set == 0) {
173 		logError(_("You must provide an index for the NVRAM area.\n"));
174 		goto out;
175 	}
176 
177 	if (length > 0 && data == NULL &&
178 	    filename == NULL &&
179 	    fillvalue == -1) {
180 		logError(_("Either data, name of file or fill value must be "
181 			   "provided.\n"));
182 		goto out;
183 	}
184 
185 	if (data) {
186 		ulDataLength = strlen(data);
187 
188 		if (length > 0 && (UINT32)length < ulDataLength)
189 			ulDataLength = length;
190 
191 		rgbDataToWrite = (BYTE *)data;
192 		data = NULL;
193 	} else if (filename) {
194 		if (stat(filename, &statbuf) != 0) {
195 			logError(_("Could not access file '%s'\n"),
196 				 filename);
197 			goto out;
198 		}
199 		ulDataLength = statbuf.st_size;
200 
201 		if (length > 0 && (UINT32)length < ulDataLength)
202 			ulDataLength = length;
203 
204 		rgbDataToWrite = malloc(ulDataLength);
205 		if (rgbDataToWrite == NULL) {
206 			logError(_("Out of memory.\n"));
207 			return -1;
208 		}
209 		fd = open(filename, O_RDONLY);
210 		if (fd < 0) {
211 			logError(_("Could not open file %s for reading.\n"));
212 			return -1;
213 		}
214 		read_bytes = read(fd, rgbDataToWrite, ulDataLength);
215 
216 		if (read_bytes < 0 || ulDataLength != (UINT32)read_bytes) {
217 			logError(_("Error while reading data.\n"));
218 			return -1;
219 		}
220 		close(fd);
221 		fd = -1;
222 	} else if (fillvalue >= 0) {
223 		if (length < 0) {
224 			logError(_("Requiring size parameter.\n"));
225 			return -1;
226 		}
227 		ulDataLength = length;
228 		rgbDataToWrite = malloc(ulDataLength);
229 		if (rgbDataToWrite == NULL) {
230 			logError(_("Out of memory.\n"));
231 			return -1;
232 		}
233 		__memset(rgbDataToWrite, fillvalue, ulDataLength);
234 	} else {
235 		ulDataLength = 0;
236 	}
237 
238 	if (contextCreate(&hContext) != TSS_SUCCESS)
239 		goto out;
240 
241 	if (contextConnect(hContext) != TSS_SUCCESS)
242 		goto out_close;
243 
244 	if (contextGetTpm(hContext, &hTpm) != TSS_SUCCESS)
245 		goto out_close;
246 
247 	fNvAttrs = 0;
248 
249 	if (contextCreateObject(hContext,
250 				TSS_OBJECT_TYPE_NV,
251 				fNvAttrs,
252 				&nvObject) != TSS_SUCCESS)
253 		goto out_close;
254 
255 
256 	if (askPassword) {
257 		password = _GETPASSWD(_("Enter NVRAM access password: "), &pswd_len,
258 			FALSE, useUnicode );
259 		if (!password) {
260 			logError(_("Failed to get NVRAM access password\n"));
261 			goto out_close;
262 		}
263 	}
264 	if (password || passWellKnown) {
265 		if (policyGet(hTpm, &hTpmPolicy) != TSS_SUCCESS)
266 			goto out_close;
267 
268 		if (password) {
269 			if (pswd_len < 0)
270 				pswd_len = strlen(password);
271 			if (policySetSecret(hTpmPolicy, strlen(password),
272 					    (BYTE *)password) != TSS_SUCCESS)
273 				goto out_close;
274 		} else {
275 			if (policySetSecret(hTpmPolicy, TCPA_SHA1_160_HASH_LEN,
276 					    (BYTE *)well_known_secret) != TSS_SUCCESS)
277 				goto out_close;
278 		}
279 
280 		if (contextCreateObject
281 		    (hContext, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE,
282 		     &hDataPolicy) != TSS_SUCCESS)
283 			goto out_close;
284 
285 		if (password) {
286 			if (policySetSecret(hDataPolicy, strlen(password),
287 					    (BYTE *)password) != TSS_SUCCESS)
288 				goto out_close;
289 		} else {
290 			if (policySetSecret(hDataPolicy, TCPA_SHA1_160_HASH_LEN,
291 					    (BYTE *)well_known_secret) != TSS_SUCCESS)
292 				goto out_close;
293 		}
294 
295 		if (Tspi_Policy_AssignToObject(hDataPolicy, nvObject) !=
296 		    TSS_SUCCESS)
297 			goto out_close;
298 	}
299 
300 	if (nvindex != TPM_NV_INDEX0) {
301 		if (getNVDataPublic(hTpm, nvindex, &nvpub)  != TSS_SUCCESS) {
302 			logError(_("Could not get NVRAM area public information.\n"));
303 			goto out_close_obj;
304 		}
305 
306 		if ((UINT32)offset > nvpub->dataSize) {
307 			logError(_("The offset is outside the NVRAM area's size of "
308 			           "%u bytes.\n"),
309 				 nvpub->dataSize);
310 			goto out_close_obj;
311 		}
312 
313 		if ((UINT32)offset + ulDataLength > nvpub->dataSize) {
314 			logError(_("Writing of data would go beyond the NVRAM area's size "
315 			           "of %u bytes.\n"),
316 				 nvpub->dataSize);
317 			goto out_close_obj;
318 		}
319 	}
320 
321 	if (Tspi_SetAttribUint32(nvObject,
322 				 TSS_TSPATTRIB_NV_INDEX,
323 				 0,
324 				 nvindex) != TSS_SUCCESS)
325 		goto out_close_obj;
326 
327 
328 	bytesToWrite = ulDataLength;
329 	off = offset;
330 
331 	if (bytesToWrite == 0 &&
332 	    NVWriteValue(nvObject, 0, 0, NULL) != TSS_SUCCESS)
333 		goto out_close_obj;
334 
335 #define WRITE_CHUNK_SIZE   1024
336 	while (bytesToWrite > 0) {
337 		UINT32 chunk = (bytesToWrite > WRITE_CHUNK_SIZE)
338 			       ? WRITE_CHUNK_SIZE
339 			       : bytesToWrite;
340 		if (NVWriteValue(nvObject, off, chunk, &rgbDataToWrite[off-offset])
341 		    != TSS_SUCCESS)
342 			goto out_close_obj;
343 
344 		bytesToWrite -= chunk;
345 		off += chunk;
346 	}
347 
348 	logMsg(_("Successfully wrote %d bytes at offset %d to NVRAM index "
349 	         "0x%x (%u).\n"),
350 	       ulDataLength, offset, nvindex, nvindex);
351 
352 	iRc = 0;
353 
354 	goto out_close;
355 
356       out_close_obj:
357 	contextCloseObject(hContext, nvObject);
358 
359       out_close:
360 	contextClose(hContext);
361 
362       out:
363 	free(rgbDataToWrite);
364 	freeNVDataPublic(nvpub);
365 
366 	return iRc;
367 }
368