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