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 
40 extern cmdtable_t commands[];
41 
42 static void
43 print_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 
56 int
57 main(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 
106 void
107 print_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 
125 void
126 print_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 
149 int
150 get_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 
181 int
182 set_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 
208 int
209 set_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 
224 int
225 tpm_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 
251 int
252 tpm_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