/*
* The Initial Developer of the Original Code is International
* Business Machines Corporation. Portions created by IBM
* Corporation are Copyright (C) 2005 International Business
* Machines Corporation. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the Common Public License as published by
* IBM Corporation; either version 1 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Common Public License for more details.
*
* You should have received a copy of the Common Public License
* along with this program; if not, a copy can be viewed at
* http://www.opensource.org/licenses/cpl1.0.php.
*/
#include <sys/stat.h>
#include <limits.h>
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include "tpm_nvcommon.h"
#include "tpm_tspi.h"
#include "tpm_utils.h"
static unsigned int nvindex;
static unsigned int offset;
static unsigned int length;
static BOOL length_set;
static const char *filename;
static BOOL passWellKnown;
static const char *password;
static BOOL askPassword;
TSS_HCONTEXT hContext = 0;
static int parse(const int aOpt, const char *aArg)
{
switch (aOpt) {
case 'i':
if (parseHexOrDecimal(aArg, &nvindex, 0, UINT_MAX,
"NVRAM index") != 0)
return -1;
break;
case 'n':
if (parseHexOrDecimal(aArg, &offset, 0, UINT_MAX,
"read offset") != 0)
return -1;
break;
case 's':
if (parseHexOrDecimal(aArg, &length, 0, UINT_MAX,
"length of data") != 0)
return -1;
length_set = TRUE;
break;
case 'f':
filename = aArg;
break;
case 'p':
password = aArg;
if (!password)
askPassword = TRUE;
else
askPassword = FALSE;
passWellKnown = FALSE;
break;
case 'z':
password = NULL;
passWellKnown = TRUE;
askPassword = FALSE;
break;
case 'u':
useUnicode = TRUE;
break;
default:
return -1;
}
return 0;
}
static void displayData(FILE *stream, UINT32 offset, BYTE *data, UINT32 length)
{
unsigned int len = (length + 0xf) & ~0xf;
unsigned int c;
unsigned char buf[17] = { 0, };
for (c = 0; c < len; c++) {
if ((c & 0xf) == 0)
printf("%08x ", c + offset);
if (c < length) {
printf("%02x ", data[c]);
if (isgraph(data[c]))
buf[c & 0xf] = data[c];
else
buf[c & 0xf] = ' ';
} else {
printf(" ");
buf[c & 0xf] = 0;
}
if ((c & 0xf) == 0xf) {
printf(" %s\n", buf);
}
}
}
static void help(const char* aCmd)
{
logCmdHelp(aCmd);
logUnicodeCmdOption();
logCmdOption("-z, --well-known",
_("Use 20 bytes of zeros (TSS_WELL_KNOWN_SECRET) as the TPM secret authorization data"));
logCmdOption("-p, --password",
_("Owner or NVRAM area password depending on permissions"));
logNVIndexCmdOption();
logCmdOption("-s, --size",
_("Number of bytes to read from the NVRAM area"));
logCmdOption("-n, --offset",
_("Offset at which to start reading from the NVRAM area"));
logCmdOption("-f, --filename",
_("File to write data to."));
}
int main(int argc, char **argv)
{
TSS_HTPM hTpm;
TSS_HNVSTORE nvObject;
TSS_FLAG fNvAttrs;
TSS_HPOLICY hTpmPolicy, hDataPolicy;
int iRc = -1;
int pswd_len = -1;
BYTE well_known_secret[] = TSS_WELL_KNOWN_SECRET;
UINT32 ulDataLength;
BYTE *rgbDataRead = NULL;
TPM_NV_DATA_PUBLIC *nvpub = NULL;
struct option hOpts[] = {
{"index" , required_argument, NULL, 'i'},
{"size" , required_argument, NULL, 's'},
{"offset" , required_argument, NULL, 'n'},
{"filename" , required_argument, NULL, 'f'},
{"password" , optional_argument, NULL, 'p'},
{"use-unicode", no_argument, NULL, 'u'},
{"well-known" , no_argument, NULL, 'z'},
{NULL , no_argument, NULL, 0},
};
int fd = -1;
ssize_t written;
initIntlSys();
if (genericOptHandler
(argc, argv, "i:s:n:f:p::zu", hOpts,
sizeof(hOpts) / sizeof(struct option), parse, help) != 0)
goto out;
if (nvindex == 0) {
logError(_("You must provide an index (!= 0) for the "
"NVRAM area.\n"));
goto out;
}
ulDataLength = length;
if (contextCreate(&hContext) != TSS_SUCCESS)
goto out;
if (contextConnect(hContext) != TSS_SUCCESS)
goto out_close;
if (contextGetTpm(hContext, &hTpm) != TSS_SUCCESS)
goto out_close;
fNvAttrs = 0;
if (contextCreateObject(hContext,
TSS_OBJECT_TYPE_NV,
fNvAttrs,
&nvObject) != TSS_SUCCESS)
goto out_close;
if (askPassword) {
password = _GETPASSWD(_("Enter NVRAM access password: "), &pswd_len,
FALSE, useUnicode );
if (!password) {
logError(_("Failed to get NVRAM access password\n"));
goto out_close;
}
}
if (password || passWellKnown) {
if (policyGet(hTpm, &hTpmPolicy) != TSS_SUCCESS)
goto out_close;
if (password) {
if (pswd_len < 0)
pswd_len = strlen(password);
if (policySetSecret(hTpmPolicy, pswd_len,
(BYTE *)password) != TSS_SUCCESS)
goto out_close;
} else {
if (policySetSecret(hTpmPolicy, TCPA_SHA1_160_HASH_LEN,
(BYTE *)well_known_secret) != TSS_SUCCESS)
goto out_close;
}
if (contextCreateObject
(hContext, TSS_OBJECT_TYPE_POLICY, TSS_POLICY_USAGE,
&hDataPolicy) != TSS_SUCCESS)
goto out_close;
if (password) {
if (policySetSecret(hDataPolicy, pswd_len,
(BYTE *)password) != TSS_SUCCESS)
goto out_close;
} else {
if (policySetSecret(hDataPolicy, TCPA_SHA1_160_HASH_LEN,
(BYTE *)well_known_secret) != TSS_SUCCESS)
goto out_close;
}
if (Tspi_Policy_AssignToObject(hDataPolicy, nvObject) !=
TSS_SUCCESS)
goto out_close;
}
if (getNVDataPublic(hTpm, nvindex, &nvpub) != TSS_SUCCESS) {
logError(_("Could not get the NVRAM area's public information.\n"));
goto out_close_obj;
}
if (!length_set)
ulDataLength = nvpub->dataSize;
if ((UINT32)offset > nvpub->dataSize) {
logError(_("The offset is outside the NVRAM area's size of "
"%u bytes.\n"),
nvpub->dataSize);
goto out_close_obj;
}
if ((UINT32)offset + ulDataLength > nvpub->dataSize) {
ulDataLength = nvpub->dataSize - (UINT32)offset;
}
if (Tspi_SetAttribUint32(nvObject,
TSS_TSPATTRIB_NV_INDEX,
0,
nvindex) != TSS_SUCCESS)
goto out_close_obj;
if (NVReadValue(nvObject, offset, &ulDataLength, &rgbDataRead) !=
TSS_SUCCESS)
goto out_close_obj;
if (filename) {
fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, S_IRUSR|S_IWUSR);
if (fd < 0) {
logError(_("Could not open file %s for writing."),
filename);
goto out_close_obj;
}
written = write(fd, rgbDataRead, ulDataLength);
if (written < 0 || ulDataLength != (UINT32)written) {
logError(_("Error while writing to file.\n"));
close(fd);
fd = -1;
goto out_close_obj;
}
close(fd);
fd = -1;
logMsg(_("Successfully wrote data from NVRAM area 0x%x (%u) "
"to file.\n"), nvindex, nvindex);
} else {
displayData(stdout, offset, rgbDataRead, ulDataLength);
}
iRc = 0;
goto out_close;
out_close_obj:
contextCloseObject(hContext, nvObject);
out_close:
contextClose(hContext);
out:
free(rgbDataRead);
freeNVDataPublic(nvpub);
return iRc;
}