1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
26 */
27
28
29#include <stdlib.h>
30#include <stdio.h>
31#include <unistd.h>
32#include <strings.h>
33#include <libintl.h>
34#include <locale.h>
35
36#include <tss/tspi.h>
37#include <trousers/trousers.h>
38#include "tpmadm.h"
39
40extern cmdtable_t commands[];
41
42static void
43print_usage(char *progname, cmdtable_t cmds[])
44{
45	cmdtable_t *p;
46
47	(void) fprintf(stderr,
48	    gettext("usage: %s command args ...\n"), progname);
49	(void) fprintf(stderr,
50	    gettext("where 'command' is one of the following:\n"));
51	for (p = &cmds[0]; p->name != NULL; p++) {
52		(void) fprintf(stderr, "\t%s %s\n", p->name, p->args);
53	}
54}
55
56int
57main(int argc, char *argv[])
58{
59	char *progname;
60	cmdtable_t *p;
61	cmdfunc_t fptr = NULL;
62	int ret;
63	TSS_HCONTEXT hContext;
64	TSS_HOBJECT hTPM;
65
66	/* Set up for i18n/l10n. */
67#if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D. */
68#define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it isn't. */
69#endif
70	(void) setlocale(LC_ALL, "");
71	(void) textdomain(TEXT_DOMAIN);
72
73	progname = argv[0];
74	argc--;
75	argv++;
76
77	if (argc <= 0) {
78		print_usage(progname, commands);
79		return (ERR_USAGE);
80	}
81
82	for (p = &commands[0]; p->name != NULL; p++) {
83		if (0 == strcmp(p->name, argv[0])) {
84			fptr = p->func;
85			break;
86		}
87	}
88	if (fptr == NULL) {
89		print_usage(progname, commands);
90		return (ERR_USAGE);
91	}
92
93	if (tpm_preamble(&hContext, &hTPM))
94		return (ERR_FAIL);
95	ret = fptr(hContext, hTPM, argc, argv);
96	(void) tpm_postamble(hContext);
97
98	return (ret);
99}
100
101
102/*
103 * Utility functions
104 */
105
106void
107print_bytes(BYTE *bytes, size_t len, int formatted)
108{
109	int i;
110	for (i = 0; i < len; i++) {
111		(void) printf("%02X ", bytes[i]);
112		if (formatted && i % 16 == 7)
113			(void) printf("  ");
114		if (formatted && i % 16 == 15)
115			(void) printf("\n");
116	}
117	(void) printf("\n");
118}
119
120
121/*
122 * TSS convenience functions
123 */
124
125void
126print_error(TSS_RESULT ret, char *msg)
127{
128	char *err_string;
129
130	/* Print the standard error string and error code. */
131	err_string = Trspi_Error_String(ret);
132	(void) fprintf(stderr, "%s: %s (0x%0x)\n", msg, err_string, ret);
133
134	/* For a few special cases, add a more verbose error message. */
135	switch (ret) {
136	case TPM_E_DEACTIVATED:
137	case TPM_E_DISABLED:
138		(void) fprintf(stderr,
139		    gettext("Enable the TPM and reboot.\n"));
140		break;
141	case TSP_ERROR(TSS_E_COMM_FAILURE):
142		(void) fprintf(stderr,
143		    gettext("Make sure the tcsd service "
144		    "(svc:/application/security/tcsd) is running.\n"));
145		break;
146	}
147}
148
149int
150get_tpm_capability(TSS_HCONTEXT hContext, TSS_HOBJECT hTPM, UINT32 cap,
151    UINT32 subcap, void *buf, size_t bufsize)
152{
153	TSS_RESULT ret;
154	UINT32 datalen;
155	BYTE *data;
156
157	ret = Tspi_TPM_GetCapability(hTPM, cap, sizeof (subcap),
158	    (BYTE *)&subcap, &datalen, &data);
159	if (ret) {
160		print_error(ret, gettext("Get TPM capability"));
161		return (ERR_FAIL);
162	}
163
164	if (datalen > bufsize) {
165		(void) fprintf(stderr,
166		    gettext("Capability 0x%x returned %u bytes "
167		    "(expected %u)\n"), cap, datalen, bufsize);
168		return (ERR_FAIL);
169	}
170	bcopy(data, buf, datalen);
171
172	ret = Tspi_Context_FreeMemory(hContext, data);
173	if (ret) {
174		print_error(ret, gettext("Free capability buffer"));
175		return (ERR_FAIL);
176	}
177
178	return (0);
179}
180
181int
182set_policy_options(TSS_HPOLICY hPolicy, TSS_FLAG mode, char *prompt,
183    UINT32 secret_len, BYTE *secret)
184{
185	TSS_RESULT ret;
186	BYTE *unicode_prompt;
187	UINT32 len;
188
189	ret = Tspi_Policy_SetSecret(hPolicy, mode, secret_len, secret);
190	if (ret) {
191		print_error(ret, gettext("Set policy secret"));
192		return (ERR_FAIL);
193	}
194	if (prompt != NULL) {
195		unicode_prompt = Trspi_Native_To_UNICODE((BYTE *)prompt, &len);
196		ret = Tspi_SetAttribData(hPolicy,
197		    TSS_TSPATTRIB_POLICY_POPUPSTRING,
198		    0, len, unicode_prompt);
199		if (ret) {
200			print_error(ret, gettext("Set policy prompt"));
201			return (ERR_FAIL);
202		}
203	}
204
205	return (0);
206}
207
208int
209set_object_policy(TSS_HOBJECT handle, TSS_FLAG mode, char *prompt,
210    UINT32 secret_len, BYTE *secret)
211{
212	TSS_HPOLICY hPolicy;
213	TSS_RESULT ret;
214
215	ret = Tspi_GetPolicyObject(handle, TSS_POLICY_USAGE, &hPolicy);
216	if (ret) {
217		print_error(ret, gettext("Get object policy"));
218		return (ERR_FAIL);
219	}
220
221	return (set_policy_options(hPolicy, mode, prompt, secret_len, secret));
222}
223
224int
225tpm_preamble(TSS_HCONTEXT *hContext, TSS_HOBJECT *hTPM)
226{
227	TSS_RESULT ret;
228
229	ret = Tspi_Context_Create(hContext);
230	if (ret) {
231		print_error(ret, gettext("Create context"));
232		return (ERR_FAIL);
233	}
234
235	ret = Tspi_Context_Connect(*hContext, NULL);
236	if (ret) {
237		print_error(ret, gettext("Connect context"));
238		(void) Tspi_Context_Close(*hContext);
239		return (ERR_FAIL);
240	}
241
242	ret = Tspi_Context_GetTpmObject(*hContext, hTPM);
243	if (ret) {
244		print_error(ret, gettext("Get TPM object"));
245		(void) Tspi_Context_Close(*hContext);
246		return (ERR_FAIL);
247	}
248	return (0);
249}
250
251int
252tpm_postamble(TSS_HCONTEXT hContext)
253{
254	TSS_RESULT ret;
255
256	ret = Tspi_Context_Close(hContext);
257	if (ret) {
258		print_error(ret, gettext("Close context"));
259		return (ERR_FAIL);
260	}
261	return (0);
262}
263