blob: 6ec9d320c87c4a6900893e289e8814a169dea94f [file] [log] [blame]
// Copyright (c) 2009,2010 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "bitstring.h"
#include "commands.h"
#include "tpm_nv.h"
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#include <getopt.h>
#include <errno.h>
#include <limits.h>
#define PROGNAME "tpm-nvtool"
static struct option
long_options[] = {
{ "define", no_argument, 0, 'D' },
{ "file", required_argument, 0, 'f' },
{ "help", no_argument, 0, 'h' },
{ "hexdump", no_argument, 0, 'x' },
{ "index", required_argument, 0, 'I' },
{ "index_password", required_argument, 0, 'i' },
{ "list", no_argument, 0, 'l' },
{ "offset", required_argument, 0, 'O' },
{ "owner_password", required_argument, 0, 'o' },
{ "password", required_argument, 0, '0' },
{ "pcr", required_argument, 0, 'p' },
{ "permissions", required_argument, 0, 'P' },
{ "read", no_argument, 0, 'r' },
{ "release", no_argument, 0, 'R' },
{ "size", required_argument, 0, 's' },
{ "string", required_argument, 0, 'd' },
{ "write", no_argument, 0, 'w' },
{ "writezero", no_argument, 0, 'z' },
{ NULL, 0, 0, 0 },
};
static const char* options = "0:DI:O:P:Rd:f:hi:lo:p:rs:wxz";
static void
help_brief(void)
{
TNV_stderr("Try %s --help for more information.\n", PROGNAME);
}
static void
help_long(void)
{
const char* help_message =
#include "help/help.h"
;
TNV_stderr("%s", help_message);
}
int
main(int argc, char** argv)
{
tnv_args_t tnv_args;
tnv_context_t* t = NULL;
char* tss_server = NULL;
uint64_t cmdmap = 0ULL;
int c, option_index = 0, ret = 0;
int data_fd = -1;
if (argc <= 1) {
help_brief();
exit(1);
}
memset(&tnv_args, 0, sizeof(tnv_args));
tnv_args.data_fd = -1;
while ((c = getopt_long(argc, argv, options, long_options, &option_index))
!= -1) {
switch (c) {
case '0':
tnv_args.password = optarg;
tnv_args.flags |= TNV_FLAG_RWAUTH;
break;
case 'D':
cmdmap |= CMD_BITMAP(CMDBIT_TNV_DEFINE);
break;
case 'I': {
errno = 0;
char* end;
uint64_t tmp_index = strtoull(optarg, &end, 0);
if (errno || (end != optarg + strlen(optarg)) ||
(tmp_index > UINT_MAX) || (tmp_index == 0)) {
TNV_stderr("Invalid index %s.\n", optarg);
exit(1);
}
tnv_args.index = (uint32_t)tmp_index;
cmdmap |= CMD_BITMAP(CMDBIT_TNV_INDEX);
break;
}
case 'O':
errno = 0;
char* end;
uint64_t tmp_offset = strtoull(optarg, &end, 0);
if (errno || (end != optarg + strlen(optarg)) ||
(tmp_offset > UINT_MAX)) {
TNV_stderr("Invalid offset %s.\n", optarg);
exit(1);
}
tnv_args.offset = (uint32_t)tmp_offset;
break;
case 'P': {
int i;
char* aperm = strtok((char*)optarg, ",");
while (aperm) {
for (i = 0; TPM_NV_PER_table[i].permission_name; i++) {
if (strcasecmp(TPM_NV_PER_table[i].permission_name,
aperm) == 0) {
if (TPM_NV_PER_table[i].allowed == TRUE) {
tnv_args.permissions |=
TPM_NV_PER_table[i].permission_value;
}
}
}
aperm = strtok(NULL, ",");
}
break;
}
case 'R':
cmdmap |= CMD_BITMAP(CMDBIT_TNV_RELEASE);
break;
case 'd':
cmdmap |= CMD_BITMAP(CMDBIT_TNV_DATA);
if (*optarg == '\0') {
TNV_stderr("Attempt to write an empty string.\n");
exit(1);
}
tnv_args.data = optarg;
break;
case 'f':
tnv_args.data = optarg;
tnv_args.flags |= TNV_FLAG_FILEDATA;
cmdmap |= CMD_BITMAP(CMDBIT_TNV_FILE);
break;
case 'h':
help_long();
exit(0);
case 'i':
tnv_args.index_password = optarg;
break;
case 'l':
cmdmap |= CMD_BITMAP(CMDBIT_TNV_LIST);
break;
case 'o':
tnv_args.owner_password = optarg;
break;
case 'p': {
errno = 0;
char* end;
uint64_t tmp_pcr = strtoull(optarg, &end, 0);
if (errno || (end != optarg + strlen(optarg)) ||
(tmp_pcr >= TNV_MAX_PCRS)) {
TNV_stderr("Invalid PCR index %s.\n", optarg);
exit(1);
}
bit_set(tnv_args.pcrs_selected.bitmap, tmp_pcr);
if ((uint32_t)tmp_pcr > tnv_args.pcrs_selected.highest) {
tnv_args.pcrs_selected.highest = (uint32_t)tmp_pcr;
}
tnv_args.pcrs_selected.count++;
break;
}
case 'r':
cmdmap |= CMD_BITMAP(CMDBIT_TNV_READ);
break;
case 's': {
errno = 0;
char* end;
uint64_t tmp_size = strtoull(optarg, &end, 0);
if (errno || (end != optarg + strlen(optarg)) ||
(tmp_size > UINT_MAX)) {
TNV_stderr("Invalid size %s.\n", optarg);
exit(1);
}
tnv_args.size = (uint32_t)tmp_size;
break;
}
case 'w':
cmdmap |= CMD_BITMAP(CMDBIT_TNV_WRITE);
break;
case 'x':
tnv_args.flags |= TNV_FLAG_HEXDUMP;
break;
case 'z':
cmdmap |= CMD_BITMAP(CMDBIT_TNV_WRITEZERO);
break;
default:
help_brief();
exit(1);
}
}
if (optind != argc) {
help_brief();
exit(1);
}
switch (cmdmap) {
case CMD_TNV_DEFINE:
tnv_args.flags |= (TNV_FLAG_CREATE | TNV_FLAG_NEEDOWNER);
break;
case CMD_TNV_RELEASE:
tnv_args.flags |= (TNV_FLAG_DESTROY | TNV_FLAG_NEEDOWNER);
break;
case CMD_TNV_LIST:
tnv_args.flags |= TNV_FLAG_NONSPECIFIC;
break;
case CMD_TNV_LIST_INDEX:
case CMD_TNV_READ:
break;
case CMD_TNV_WRITE: {
size_t dataLength = strlen(tnv_args.data);
if ((tnv_args.size == 0) || (tnv_args.size > dataLength)) {
tnv_args.size = dataLength;
}
break;
}
case CMD_TNV_WRITE_FILE: {
struct stat stbuf;
char fileBuffer[TNV_MAX_NV_SIZE];
int fd = open(tnv_args.data, O_RDONLY);
ret = -1;
if (fd < 0) {
TNV_stderr("Failed to open %s for reading (%s).\n",
tnv_args.data, strerror(errno));
goto out;
}
if (fstat(fd, &stbuf) < 0) {
TNV_stderr("Failed to stat %s (%s).\n", tnv_args.data,
strerror(errno));
goto out;
}
if (stbuf.st_size > TNV_MAX_NV_SIZE) {
TNV_stderr("Will not read files larger than %u bytes.\n",
TNV_MAX_NV_SIZE);
goto out;
}
if (stbuf.st_size == 0) {
TNV_stderr("Zero length file %s.\n", tnv_args.data);
goto out;
}
if (!S_ISREG(stbuf.st_mode)) {
TNV_stderr("Will not read from a non-regular file.\n");
goto out;
}
if (read(fd, fileBuffer, stbuf.st_size) != stbuf.st_size) {
TNV_stderr("Failed to read file content (%s).\n",
strerror(errno));
goto out;
}
tnv_args.data = &fileBuffer[0];
if ((tnv_args.size == 0) || (tnv_args.size > stbuf.st_size)) {
tnv_args.size = stbuf.st_size;
}
break;
}
case CMD_TNV_WRITEZERO:
tnv_args.offset = 0;
tnv_args.size = 0;
break;
default:
help_brief();
exit(1);
}
tnv_args.tss_version = TSS_TSPATTRIB_CONTEXT_VERSION_V1_1;
t = tnv_open_context(tss_server, &tnv_args);
if (t == NULL) {
exit(1);
}
switch (cmdmap) {
case CMD_TNV_DEFINE:
ret = tnv_define(t, &tnv_args);
break;
case CMD_TNV_LIST:
ret = tnv_list(t, &tnv_args);
break;
case CMD_TNV_LIST_INDEX:
ret = tnv_list(t, &tnv_args);
break;
case CMD_TNV_READ:
ret = tnv_read(t, &tnv_args);
break;
case CMD_TNV_RELEASE:
ret = tnv_release(t, &tnv_args);
break;
case CMD_TNV_WRITE:
ret = tnv_write(t, &tnv_args);
break;
case CMD_TNV_WRITEZERO:
ret = tnv_write(t, &tnv_args);
break;
}
out:
if (data_fd >= 0) {
close(data_fd);
}
tnv_close_context(&t);
exit(ret);
}