tpm_nvwrite.c revision 1.1
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
32static BOOL nvindex_set;
33static unsigned int nvindex;
34static unsigned int offset;
35static unsigned int length;
36static int fillvalue = -1;
37static const char *filename;
38static BOOL passWellKnown;
39static BOOL askPassword;
40static const char *password;
41static char *data;
42
43TSS_HCONTEXT hContext = 0;
44
45
46static 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
115static 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
136int 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