OpenSolaris_b135/cmd/cmd-crypto/tpmadm/admin_cmds.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <fcntl.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <inttypes.h>
#include <sha1.h>
#include <uuid/uuid.h>
#include <sys/stat.h>
#include <libintl.h>

#include <tss/tss_defines.h>
#include <tss/tspi.h>

#include "tpmadm.h"

int cmd_status(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]);
int cmd_init(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]);
int cmd_clear(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]);
int cmd_auth(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]);
int cmd_keyinfo(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]);
int cmd_deletekey(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[]);

cmdtable_t commands[] = {
	{"status", "", cmd_status},
	{"init", "", cmd_init},
	{"clear", "[owner | lock]", cmd_clear},
	{"auth", "", cmd_auth},
	{"keyinfo", "[uuid]", cmd_keyinfo},
	{"deletekey", "uuid", cmd_deletekey},
	{NULL, NULL, NULL},
};

BYTE well_known[] = TSS_WELL_KNOWN_SECRET;
TSS_UUID srk_uuid = TSS_UUID_SRK;


/*
 * TPM status
 */

static int
print_tpm_version(TSS_HCONTEXT hContext, TSS_HOBJECT hTPM)
{
	struct {
		TPM_CAP_VERSION_INFO vers_info;
		char extra[20]; /* vendor extensions */
	} info;

	if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_VERSION_VAL,
	    0, &info, sizeof (info)))
		return (ERR_FAIL);

	(void) printf(gettext("TPM Version: %d.%d (%c%c%c%c Rev: %d.%d, "
	    "SpecLevel: %d, ErrataRev: %d)\n"),
	    info.vers_info.version.major,
	    info.vers_info.version.minor,
	    info.vers_info.tpmVendorID[0],
	    info.vers_info.tpmVendorID[1],
	    info.vers_info.tpmVendorID[2],
	    info.vers_info.tpmVendorID[3],
	    info.vers_info.version.revMajor,
	    info.vers_info.version.revMinor,
	    (int)ntohs(info.vers_info.specLevel),
	    info.vers_info.errataRev);

	return (0);
}

static int
tpm_is_owned(TSS_HCONTEXT hContext, TSS_HOBJECT hTPM)
{
	BYTE owned;

	if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY,
	    TSS_TPMCAP_PROP_OWNER, &owned, sizeof (owned)))
		return (0);

	return (owned);
}

static int
print_tpm_resources(TSS_HCONTEXT hContext, TSS_HOBJECT hTPM)
{
	UINT32 avail, max;

	(void) printf(gettext("TPM resources\n"));

	if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY,
	    TSS_TPMCAP_PROP_MAXCONTEXTS, &max, sizeof (max)))
		return (ERR_FAIL);
	if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY,
	    TSS_TPMCAP_PROP_CONTEXTS, &avail, sizeof (avail)))
		return (ERR_FAIL);
	(void) printf(gettext("\tContexts: %d/%d available\n"), avail, max);

	if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY,
	    TSS_TPMCAP_PROP_MAXSESSIONS, &max, sizeof (max)))
		return (ERR_FAIL);
	if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY,
	    TSS_TPMCAP_PROP_SESSIONS, &avail, sizeof (avail)))
		return (ERR_FAIL);
	(void) printf(gettext("\tSessions: %d/%d available\n"), avail, max);

	if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY,
	    TSS_TPMCAP_PROP_MAXAUTHSESSIONS, &max, sizeof (max)))
		return (ERR_FAIL);
	if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY,
	    TSS_TPMCAP_PROP_AUTHSESSIONS, &avail, sizeof (avail)))
		return (ERR_FAIL);
	(void) printf(gettext("\tAuth Sessions: %d/%d available\n"),
	    avail, max);

	if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY,
	    TSS_TPMCAP_PROP_MAXKEYS, &max, sizeof (max)))
		return (ERR_FAIL);
	if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY,
	    TSS_TPMCAP_PROP_KEYS, &avail, sizeof (avail)))
		return (ERR_FAIL);
	(void) printf(gettext("\tLoaded Keys: %d/%d available\n"), avail, max);

	return (0);
}

static int
print_tpm_pcrs(TSS_HCONTEXT hContext, TSS_HOBJECT hTPM)
{
	UINT32 num_pcrs;
	int i;

	if (get_tpm_capability(hContext, hTPM, TSS_TPMCAP_PROPERTY,
	    TSS_TPMCAP_PROP_PCR, &num_pcrs, sizeof (num_pcrs)))
		return (ERR_FAIL);
	(void) printf(gettext("Platform Configuration Registers (%u)\n"),
	    num_pcrs);

	/* Print each PCR */
	for (i = 0; i < num_pcrs; i++) {
		TSS_RESULT ret;
		UINT32 datalen;
		BYTE *data;

		ret = Tspi_TPM_PcrRead(hTPM, i, &datalen, &data);
		if (ret) {
			print_error(ret, gettext("Read PCR"));
			return (ret);
		}

		(void) printf("\tPCR %u:\t", i);
		print_bytes(data, datalen, FALSE);

		ret = Tspi_Context_FreeMemory(hContext, data);
		if (ret) {
			print_error(ret, gettext("Free PCR memory"));
			return (ret);
		}
	}
	return (0);
}

/*ARGSUSED*/
int
cmd_status(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[])
{
	if (set_object_policy(hTPM, TSS_SECRET_MODE_POPUP, NULL, 0, NULL))
		return (ERR_FAIL);

	(void) print_tpm_version(hContext, hTPM);
	if (tpm_is_owned(hContext, hTPM)) {
		(void) print_tpm_resources(hContext, hTPM);
		(void) print_tpm_pcrs(hContext, hTPM);
	} else {
		(void) printf(gettext("No TPM owner installed.\n"));
	}

	return (0);
}


/*
 * Key Information
 */

typedef struct {
	UINT32 code;
	char *str;
} decode_map_t;

decode_map_t key_usage[] = {
	{ TSS_KEYUSAGE_SIGN, "Signing" },
	{ TSS_KEYUSAGE_STORAGE, "Storage" },
	{ TSS_KEYUSAGE_IDENTITY, "Identity" },
	{ TSS_KEYUSAGE_AUTHCHANGE, "Authchange" },
	{ TSS_KEYUSAGE_BIND, "Bind" },
	{ TSS_KEYUSAGE_LEGACY, "Legacy" },
	{ TSS_KEYUSAGE_MIGRATE, "Migrate" },
	{ 0, NULL },
};

decode_map_t key_algorithm[] = {
	{ TSS_ALG_RSA, "RSA" },
	{ TSS_ALG_DES, "DES" },
	{ TSS_ALG_3DES, "3-DES" },
	{ TSS_ALG_SHA, "SHA" },
	{ TSS_ALG_HMAC, "HMAC" },
	{ TSS_ALG_AES, "AES" },
	{ TSS_ALG_MGF1, "MGF1" },
	{ TSS_ALG_AES192, "AES192" },
	{ TSS_ALG_AES256, "AES256" },
	{ TSS_ALG_XOR, "XOR" },
	{ 0, NULL },
};

decode_map_t key_sigscheme[] = {
	{ TSS_SS_NONE, "None" },
	{ TSS_SS_RSASSAPKCS1V15_SHA1, "RSASSAPKCS1v15_SHA1" },
	{ TSS_SS_RSASSAPKCS1V15_DER, "RSASSAPKCS1v15_DER" },
	{ 0, NULL },
};

decode_map_t key_encscheme[] = {
	{ TSS_ES_NONE, "None" },
	{ TSS_ES_RSAESPKCSV15, "RSAESPKCSv15" },
	{ TSS_ES_RSAESOAEP_SHA1_MGF1, "RSAESOAEP_SHA1_MGF1" },
	{ TSS_ES_SYM_CNT, "SYM_CNT" },
	{ TSS_ES_SYM_OFB, "SYM_OFB" },
	{ 0, NULL },
};

static char *
decode(decode_map_t *table, UINT32 code)
{
	static char buf[20];
	int i;

	for (i = 0; table[i].str != NULL; i++) {
		if (table[i].code == code)
			return (table[i].str);
	}

	(void) snprintf(buf, sizeof (buf), gettext("Unknown (%u)"), code);
	return (buf);
}

static void
print_key_info(TSS_HCONTEXT hContext, TSS_HOBJECT hKey)
{
	TSS_RESULT ret;
	UINT32 attrib;
	UINT32 keyInfoSize;
	BYTE *keyInfo;

	/* Key size */
	ret = Tspi_GetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO,
	    TSS_TSPATTRIB_KEYINFO_SIZE, &attrib);
	if (ret) {
		print_error(ret, gettext("Get key size"));
	}
	(void) printf(gettext("Key Size: %d bits\n"), attrib);

	/* Key usage */
	ret = Tspi_GetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO,
	    TSS_TSPATTRIB_KEYINFO_USAGE, &attrib);
	if (ret) {
		print_error(ret, gettext("Get key usage"));
	}
	(void) printf(gettext("Key Usage: %s\n"), decode(key_usage, attrib));

	/* Algorithm */
	ret = Tspi_GetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO,
	    TSS_TSPATTRIB_KEYINFO_ALGORITHM, &attrib);
	if (ret) {
		print_error(ret, gettext("Get key algorithm"));
	}
	(void) printf(gettext("Algorithm: %s\n"),
	    decode(key_algorithm, attrib));

	/* Authorization required */
	ret = Tspi_GetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO,
	    TSS_TSPATTRIB_KEYINFO_AUTHUSAGE, &attrib);
	if (ret) {
		print_error(ret, gettext("Get key authusage"));
	}
	(void) printf(gettext("Authorization required: %s\n"),
	    attrib ? gettext("Yes") : gettext("No"));

	/* Signature scheme */
	ret = Tspi_GetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO,
	    TSS_TSPATTRIB_KEYINFO_SIGSCHEME, &attrib);
	if (ret) {
		print_error(ret, gettext("Get key signature scheme"));
	}
	(void) printf(gettext("Signature scheme: %s\n"),
	    decode(key_sigscheme, attrib));

	/* Encoding scheme */
	ret = Tspi_GetAttribUint32(hKey, TSS_TSPATTRIB_KEY_INFO,
	    TSS_TSPATTRIB_KEYINFO_ENCSCHEME, &attrib);
	if (ret) {
		print_error(ret, gettext("Get key encoding scheme"));
	}
	(void) printf(gettext("Encoding scheme: %s\n"),
	    decode(key_encscheme, attrib));

	/* Key blob */
	ret = Tspi_GetAttribData(hKey, TSS_TSPATTRIB_KEY_BLOB,
	    TSS_TSPATTRIB_KEYBLOB_BLOB, &keyInfoSize, &keyInfo);
	if (ret) {
		print_error(ret, gettext("Get key blob"));
	}
	(void) printf(gettext("TPM Key Blob:\n"));
	print_bytes(keyInfo, keyInfoSize, TRUE);
	ret = Tspi_Context_FreeMemory(hContext, keyInfo);
	if (ret) {
		print_error(ret, gettext("Free key info buffer"));
	}
}

typedef struct hash_node {
	struct hash_node *next, *sibling, *child;
	TSS_UUID uuid;
	TSS_KM_KEYINFO2 *key_data;
} hash_node_t;

#define	HASHSIZE 17
hash_node_t *hash_table[HASHSIZE];

static hash_node_t *
hash_insert(TSS_UUID uuid, TSS_KM_KEYINFO2 *key_data)
{
	UINT32 i, index = 0;
	hash_node_t *node;
	char *cp;

	cp = (char *)&uuid;
	for (i = 0; i < sizeof (TSS_UUID); i++)
		index += cp[i];
	index = index % HASHSIZE;

	for (node = hash_table[index]; node != NULL; node = node->next) {
		if (memcmp(&(node->uuid), &uuid, sizeof (TSS_UUID)) == 0)
			break;
	}

	if (node == NULL) {
		node = calloc(1, sizeof (hash_node_t));
		node->uuid = uuid;
		node->next = hash_table[index];
		hash_table[index] = node;
	}
	if (node->key_data == NULL)
		node->key_data = key_data;

	return (node);
}

static void
add_child(hash_node_t *parent, hash_node_t *child)
{
	hash_node_t *node;

	for (node = parent->child; node != NULL; node = node->next) {
		if (node == child)
			return;
	}

	child->sibling = parent->child;
	parent->child = child;
}

static void
print_all(hash_node_t *parent, int indent)
{
	char uuidstr[UUID_PRINTABLE_STRING_LENGTH];
	hash_node_t *node;
	char *type, *loaded;

	uuid_unparse(*(uuid_t *)&parent->uuid, uuidstr);
	type = (parent->key_data->persistentStorageType == TSS_PS_TYPE_USER) ?
	    "USER" : "SYSTEM";
	loaded = parent->key_data->fIsLoaded ? "(loaded)" : "";
	(void) printf("%*s[%s] %s %s\n", indent, "",
	    type, uuidstr, loaded);

	for (node = parent->child; node != NULL; node = node->sibling)
		print_all(node, indent + 4);
}

/*ARGSUSED*/
int
cmd_keyinfo(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[])
{
	TSS_RESULT ret;
	UINT32 i, num_keys;
	TSS_KM_KEYINFO2 *keys;
	hash_node_t *parent, *child, *srk = NULL;
	TSS_HKEY hKey;
	union {
		uuid_t arr_uuid;
		TSS_UUID tss_uuid;
	} uuid;

	switch (argc) {
	case 1:
		/* Print key hierarchy */
		ret = Tspi_Context_GetRegisteredKeysByUUID2(hContext,
		    TSS_PS_TYPE_USER, NULL, &num_keys, &keys);
		if (ret) {
			print_error(ret, gettext("Get key hierarchy"));
			return (ERR_FAIL);
		}

		for (i = 0; i < num_keys; i++) {
			parent = hash_insert(keys[i].parentKeyUUID, NULL);
			child = hash_insert(keys[i].keyUUID, &keys[i]);
			add_child(parent, child);
			if (memcmp(&(keys[i].keyUUID), &srk_uuid,
			    sizeof (TSS_UUID)) == 0)
				srk = child;
		}

		if (srk != NULL)
			print_all(srk, 0);
		ret = Tspi_Context_FreeMemory(hContext, (BYTE *) keys);
		if (ret) {
			print_error(ret, gettext("Free key list"));
			return (ERR_FAIL);
		}
		return (0);

	case 2:
		/* Print detailed info about a single key */
		if (uuid_parse(argv[1], uuid.arr_uuid))
			return (ERR_FAIL);
		ret = Tspi_Context_GetKeyByUUID(hContext, TSS_PS_TYPE_USER,
		    uuid.tss_uuid, &hKey);
		if (ret == TSP_ERROR(TSS_E_PS_KEY_NOTFOUND)) {
			ret = Tspi_Context_GetKeyByUUID(hContext,
			    TSS_PS_TYPE_SYSTEM, uuid.tss_uuid, &hKey);
		}
		if (ret) {
			print_error(ret, gettext("Get key by UUID"));
			return (ERR_FAIL);
		}
		print_key_info(hContext, hKey);
		return (0);

	default:
		(void) fprintf(stderr, gettext("Usage:\n"));
		(void) fprintf(stderr, "\tkeyinfo [uuid]\n");
		return (ERR_USAGE);
	}
}

/*ARGSUSED*/
int
cmd_deletekey(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[])
{
	TSS_RESULT ret;
	TSS_HOBJECT hKey;
	union {
		uuid_t arr_uuid;
		TSS_UUID tss_uuid;
	} uuid;

	if (argc < 2) {
		(void) fprintf(stderr, gettext("Usage:\n"));
		(void) fprintf(stderr, "\tdeletekey [uuid]\n");
		return (ERR_USAGE);
	}
	if (uuid_parse(argv[1], uuid.arr_uuid))
		return (ERR_FAIL);
	ret = Tspi_Context_UnregisterKey(hContext, TSS_PS_TYPE_USER,
	    uuid.tss_uuid, &hKey);
	if (ret == TSP_ERROR(TSS_E_PS_KEY_NOTFOUND)) {
		ret = Tspi_Context_UnregisterKey(hContext, TSS_PS_TYPE_SYSTEM,
		    uuid.tss_uuid, &hKey);
	}
	if (ret) {
		print_error(ret, gettext("Unregister key"));
		return (ERR_FAIL);
	}
	return (0);
}

/*
 * Clear
 */

static int
clearowner(TSS_HTPM hTPM)
{
	TSS_RESULT ret;

	if (set_object_policy(hTPM, TSS_SECRET_MODE_POPUP,
	    gettext("= TPM owner passphrase ="), 0, NULL))
		return (ERR_FAIL);

	ret = Tspi_TPM_ClearOwner(hTPM, FALSE);
	if (ret) {
		print_error(ret, gettext("Clear TPM owner"));
		return (ERR_FAIL);
	}
	return (0);
}

static int
resetlock(TSS_HTPM hTPM)
{
	TSS_RESULT ret;

	if (set_object_policy(hTPM, TSS_SECRET_MODE_POPUP,
	    gettext("= TPM owner passphrase ="), 0, NULL))
		return (ERR_FAIL);

	ret = Tspi_TPM_SetStatus(hTPM, TSS_TPMSTATUS_RESETLOCK, TRUE);
	if (ret) {
		print_error(ret, gettext("Reset Lock"));
		return (ERR_FAIL);
	}
	return (0);
}

/*ARGSUSED*/
int
cmd_clear(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[])
{
	char *subcmd = argv[1];

	if (subcmd && strcmp(subcmd, "lock") == 0) {
		return (resetlock(hTPM));
	} else if (subcmd && strcmp(subcmd, "owner") == 0) {
		return (clearowner(hTPM));
	} else {
		(void) fprintf(stderr, gettext("Usage:\n"));
		(void) fprintf(stderr, "\tclear owner\n");
		(void) fprintf(stderr, "\tclear lock\n");
		return (ERR_USAGE);
	}
}


/*
 * TPM initialization
 */

static int
get_random(UINT32 size,	BYTE *randomBytes)
{
	int fd, len;
	BYTE *buf;

	fd = open("/dev/random", O_RDONLY);
	if (fd == -1) {
		(void) fprintf(stderr, gettext("Unable to open /dev/random"));
		return (-1);
	}

	buf = randomBytes;
	while (size > 0) {
		len = read(fd, buf, size);
		if (len <= 0) {
			(void) close(fd);
			(void) fprintf(stderr,
			    gettext("Error reading /dev/random"));
			return (-1);
		}
		size -= len;
		buf += len;
	}

	(void) close(fd);
	return (0);
}

static int
createek(TSS_HCONTEXT hContext, TSS_HTPM hTPM)
{
	TSS_RESULT ret;
	TSS_HOBJECT hKeyEK;
	TSS_VALIDATION ValidationData;
	TPM_NONCE nonce;
	TPM_DIGEST digest;

	/* Create the empty key struct for EK */
	ret = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_RSAKEY,
	    (TSS_KEY_NO_AUTHORIZATION | TSS_KEY_NON_VOLATILE |
	    TSS_KEY_NOT_MIGRATABLE | TSS_KEY_TYPE_STORAGE |
	    TSS_KEY_SIZE_2048 | TSS_KEY_NOT_CERTIFIED_MIGRATABLE |
	    TSS_KEY_STRUCT_KEY12 | TSS_KEY_EMPTY_KEY),
	    &hKeyEK);
	if (ret) {
		print_error(ret, gettext("Create endorsement key object"));
		return (ERR_FAIL);
	}

	ValidationData.ulExternalDataLength = sizeof (nonce);
	ValidationData.rgbExternalData = (BYTE *) &nonce;
	ret = get_random(sizeof (nonce), (BYTE *) &nonce);
	if (ret)
		return (ERR_FAIL);
	ValidationData.ulValidationDataLength = sizeof (digest);
	ValidationData.rgbValidationData = (BYTE *) &digest;

	ret = Tspi_TPM_CreateEndorsementKey(hTPM, hKeyEK, &ValidationData);
	if (ret) {
		print_error(ret, gettext("Create endorsement key"));
		return (ERR_FAIL);
	}

	return (0);
}

/*ARGSUSED*/
int
cmd_init(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[])
{
	TSS_RESULT ret;
	TSS_HOBJECT hKeySRK;

	if (set_object_policy(hTPM, TSS_SECRET_MODE_POPUP,
	    gettext("= TPM owner passphrase ="), 0, NULL))
		return (ERR_FAIL);

	ret = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_RSAKEY,
	    TSS_KEY_TSP_SRK | TSS_KEY_AUTHORIZATION, &hKeySRK);
	if (ret) {
		print_error(ret, gettext("Create storage root key"));
		return (ERR_FAIL);
	}

	if (set_object_policy(hKeySRK, TSS_SECRET_MODE_SHA1, NULL,
	    sizeof (well_known), well_known))
		return (ERR_FAIL);

	ret = Tspi_TPM_TakeOwnership(hTPM, hKeySRK, NULL);
	if (ret == TPM_E_NO_ENDORSEMENT) {
		if (createek(hContext, hTPM))
			return (ERR_FAIL);
		ret = Tspi_TPM_TakeOwnership(hTPM, hKeySRK, NULL);
	}
	if (ret) {
		print_error(ret, gettext("Take ownership"));
		return (ERR_FAIL);
	}

	return (0);
}

/*
 * Auth
 */

/*ARGSUSED*/
int
cmd_auth(TSS_HCONTEXT hContext, TSS_HTPM hTPM, int argc, char *argv[])
{
	TSS_RESULT ret;
	TSS_HPOLICY hNewPolicy;

	if (set_object_policy(hTPM, TSS_SECRET_MODE_POPUP,
	    gettext("= TPM owner passphrase ="), 0, NULL))
		return (ERR_FAIL);

	/* policy object for new passphrase */
	ret = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_POLICY,
	    TSS_POLICY_USAGE, &hNewPolicy);
	if (ret) {
		print_error(ret, gettext("Create policy object"));
		return (ERR_FAIL);
	}
	if (set_policy_options(hNewPolicy, TSS_SECRET_MODE_POPUP,
	    gettext("= New TPM owner passphrase ="), 0, NULL))
		return (ERR_FAIL);

	ret = Tspi_ChangeAuth(hTPM, NULL, hNewPolicy);
	if (ret && ret != TSP_ERROR(TSS_E_POLICY_NO_SECRET)) {
		print_error(ret, gettext("Change authorization"));
		return (ERR_FAIL);
	}

	return (0);
}