1 /*
2 * SPDX-License-Identifier: BSD-2-Clause
3 * Copyright (c) 2019, Intel Corporation
4 */
5
6 #ifdef HAVE_CONFIG_H
7 #include <config.h>
8 #endif
9
10 #include <assert.h>
11 #include <inttypes.h>
12 #include <stdbool.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16
17 #include "tss2_sys.h"
18
19 #include "context-util.h"
20 #include "sapi-util.h"
21 #include "util/aux_util.h"
22 #define LOGMODULE test
23 #include "util/log.h"
24
25 #define NV_INDEX 0x01800003
26 #define NV_SIZE 96
27
28 #define TPM2B_SIZE_MAX(type) (sizeof (type) - 2)
29
30 /*
31 * This test creates an NV index governed by a policy and then performs
32 * several operations on the NV region to exercise this policy. The NV
33 * region created is modeled after the TXT AUX region as defined by the
34 * Intel TXT software developers guide:
35 * https://www.intel.com/content/dam/www/public/us/en/documents/guides/intel-txt-software-development-guide.pdf
36 * Read is controlled by authValue and is unrestricted since authValue is
37 * set to emptyBuffer.
38 * Write is controlled by policy that allows writes from locality 3 and 4.
39 */
40 /*
41 * This function creates a policy session asserting that the locality is
42 * either 3 or 4. If this policy is used when executing a command and the
43 * policy is not satisfied (locality is not 3 or 4) then the command will
44 * fail.
45 */
46 static TSS2_RC
create_policy_session(TSS2_SYS_CONTEXT * sys_ctx,TPMI_SH_AUTH_SESSION * handle)47 create_policy_session (TSS2_SYS_CONTEXT *sys_ctx,
48 TPMI_SH_AUTH_SESSION *handle)
49 {
50 TPMA_LOCALITY locality = TPMA_LOCALITY_TPM2_LOC_THREE |
51 TPMA_LOCALITY_TPM2_LOC_FOUR;
52 TPM2B_NONCE nonce = { .size = GetDigestSize (TPM2_ALG_SHA1), };
53 TPM2B_NONCE nonce_tpm = { 0, };
54 TSS2_RC rc;
55 TPM2B_ENCRYPTED_SECRET salt = { 0, };
56 TPMT_SYM_DEF symmetric = { .algorithm = TPM2_ALG_NULL, };
57
58 rc = Tss2_Sys_StartAuthSession (sys_ctx,
59 TPM2_RH_NULL,
60 TPM2_RH_NULL,
61 0,
62 &nonce,
63 &salt,
64 TPM2_SE_POLICY,
65 &symmetric,
66 TPM2_ALG_SHA1,
67 handle,
68 &nonce_tpm,
69 0);
70 return_if_error (rc, "Tss2_Sys_StartAuthSession");
71
72 rc = Tss2_Sys_PolicyLocality (sys_ctx,
73 *handle,
74 0,
75 locality,
76 0);
77 return_if_error (rc, "Tss2_Sys_PolicyLocality");
78 return rc;
79 }
80 /*
81 * This function creates the NV region used in this test. The appropriate
82 * attributes are applied using the nvPublic member of the TPM2B_NV_PUBLIC
83 * structure.
84 */
85 static TSS2_RC
setup_nv(TSS2_SYS_CONTEXT * sys_ctx)86 setup_nv (TSS2_SYS_CONTEXT *sys_ctx)
87 {
88 TSS2_RC rc;
89 TPMI_SH_AUTH_SESSION auth_handle = 0;
90 TPM2B_DIGEST policy_hash = { 0, };
91 TPM2B_AUTH nv_auth = { 0, };
92 TSS2L_SYS_AUTH_RESPONSE auth_rsp = { 0, };
93 TPM2B_NV_PUBLIC public_info = {
94 .nvPublic = {
95 .attributes = TPMA_NV_AUTHREAD | TPMA_NV_POLICYWRITE |
96 TPMA_NV_PLATFORMCREATE, /* POLICYDELETE? */
97 .authPolicy = { .size = GetDigestSize (TPM2_ALG_SHA1), },
98 .dataSize = NV_SIZE,
99 .nameAlg = TPM2_ALG_SHA1,
100 .nvIndex = NV_INDEX,
101 },
102 };
103 const TSS2L_SYS_AUTH_COMMAND auth_cmd = {
104 .count = 1,
105 .auths= {
106 {
107 .sessionHandle = TPM2_RS_PW,
108 }
109 }
110 };
111
112 rc = create_policy_session (sys_ctx, &auth_handle);
113 return_if_error (rc, "create_policy_session");
114
115 rc = Tss2_Sys_PolicyGetDigest (sys_ctx,
116 auth_handle,
117 0,
118 &policy_hash,
119 0);
120 return_if_error (rc, "Tss2_Sys_PolicyGetDigest");
121
122 LOGBLOB_DEBUG (policy_hash.buffer, policy_hash.size, "policy_hash");
123 memcpy (public_info.nvPublic.authPolicy.buffer,
124 policy_hash.buffer,
125 policy_hash.size);
126
127 rc = Tss2_Sys_NV_DefineSpace (sys_ctx,
128 TPM2_RH_PLATFORM,
129 &auth_cmd,
130 &nv_auth,
131 &public_info,
132 &auth_rsp);
133 Tss2_Sys_FlushContext (sys_ctx, auth_handle);
134 return_if_error (rc, "Tss2_Sys_NV_DefineSpace");
135
136 return rc;
137 }
138
139 static TSS2_RC
teardown_nv(TSS2_SYS_CONTEXT * sys_ctx)140 teardown_nv (TSS2_SYS_CONTEXT *sys_ctx)
141 {
142 TSS2_RC rc;
143 const TSS2L_SYS_AUTH_COMMAND auth_cmd = {
144 .count = 1,
145 .auths = {
146 {
147 .sessionHandle = TPM2_RS_PW,
148 },
149 },
150 };
151 TSS2L_SYS_AUTH_RESPONSE auth_rsp = { 0, };
152
153 rc = Tss2_Sys_NV_UndefineSpace (sys_ctx,
154 TPM2_RH_PLATFORM,
155 NV_INDEX,
156 &auth_cmd,
157 &auth_rsp);
158 return_if_error (rc, "Tss2_Sys_NV_UndefineSpace");
159
160 return rc;
161 }
162
163 /*
164 * This function performs a single write operation to the NV region. This
165 * requires we first create a policy session that satisfies the policy
166 * governing the region. If the write fails we must manually flush the
167 * session since the continueSession flag only guarantees the policy is
168 * flushed after successful command execution.
169 */
170 static TSS2_RC
nv_write(TSS2_SYS_CONTEXT * sys_ctx)171 nv_write (TSS2_SYS_CONTEXT *sys_ctx)
172 {
173 TSS2_RC rc;
174 TSS2L_SYS_AUTH_COMMAND auth_cmd = {
175 .count = 1,
176 };
177 TSS2L_SYS_AUTH_RESPONSE auth_rsp = { 0, };
178 TPM2B_MAX_NV_BUFFER write_data = {
179 .size = 4,
180 .buffer = { 0xff, 0xfe, 0xfd, 0xfc, },
181 };
182
183 rc = create_policy_session (sys_ctx,
184 &auth_cmd.auths[0].sessionHandle);
185 return_if_error (rc, "create_policy_session");
186
187 rc = Tss2_Sys_NV_Write (sys_ctx,
188 NV_INDEX,
189 NV_INDEX,
190 &auth_cmd,
191 &write_data,
192 0,
193 &auth_rsp);
194 Tss2_Sys_FlushContext (sys_ctx, auth_cmd.auths [0].sessionHandle);
195 return_if_error (rc, "Tss2_Sys_NV_Write");
196
197 return rc;
198 }
199 /*
200 * This function executes a write operation on the NV region from each
201 * locality. Per the policy applied to the region @ provisioning, the
202 * write command will fail for all localities except 3 and 4.
203 */
204 static TSS2_RC
nv_write_test(TSS2_SYS_CONTEXT * sys_ctx)205 nv_write_test (TSS2_SYS_CONTEXT *sys_ctx)
206 {
207 TSS2_RC rc;
208 uint8_t locality;
209 TSS2_TCTI_CONTEXT *tcti_ctx;
210
211 LOG_INFO ("TPM NV write with locality policy test");
212
213 rc = Tss2_Sys_GetTctiContext (sys_ctx, &tcti_ctx);
214 return_if_error (rc, "Tss2_Sys_GetTctiContext");
215
216 for (locality = 0; locality < 5; ++locality)
217 {
218 LOG_INFO ("%s: writing NV from locality %" PRIu8, __func__, locality);
219 rc = Tss2_Tcti_SetLocality (tcti_ctx, locality);
220 return_if_error (rc, "Tss2_Tcti_SetLocality");
221
222 rc = nv_write (sys_ctx);
223 switch (locality) {
224 case 0:
225 case 1:
226 case 2:
227 if (rc != TPM2_RC_LOCALITY) {
228 LOG_ERROR ("nv_write: Expecting TPM2_RC_LOCALITY, got "
229 "0x%08" PRIu32, rc);
230 return 1;
231 }
232 break;
233 case 3:
234 case 4:
235 return_if_error (rc, "nv_write");
236 break;
237 default: /* locality can only be 0-4 */
238 assert (false);
239 break;
240 }
241 }
242 return TSS2_RC_SUCCESS;
243 }
244 /*
245 * This function executes a read command on the NV region from each
246 * locality providing the required auth value (empty). Per the policy
247 * defined a provisioning all should succeed.
248 */
249 static TSS2_RC
nv_read_test(TSS2_SYS_CONTEXT * sys_ctx)250 nv_read_test (TSS2_SYS_CONTEXT *sys_ctx)
251 {
252 TSS2_RC rc;
253 uint8_t locality;
254 TPM2B_MAX_NV_BUFFER nv_buf;
255 TSS2_TCTI_CONTEXT *tcti_ctx;
256 TSS2L_SYS_AUTH_RESPONSE auth_rsp = { 0, };
257 const TSS2L_SYS_AUTH_COMMAND auth_cmd = {
258 .count = 1,
259 .auths = {
260 {
261 .sessionHandle = TPM2_RS_PW,
262 },
263 },
264 };
265
266 rc = Tss2_Sys_GetTctiContext (sys_ctx, &tcti_ctx);
267 return_if_error (rc, "Tss2_Sys_GetTctiContext");
268
269 LOG_INFO ("TPM NV read with auth test");
270 for (locality = 0; locality < 5; ++locality)
271 {
272 rc = Tss2_Tcti_SetLocality (tcti_ctx, locality);
273 return_if_error (rc, "Tss2_Tcti_SetLocality");
274
275 nv_buf.size = TPM2B_SIZE_MAX (nv_buf);
276 rc = TSS2_RETRY_EXP (Tss2_Sys_NV_Read (sys_ctx,
277 NV_INDEX,
278 NV_INDEX,
279 &auth_cmd,
280 4,
281 0,
282 &nv_buf,
283 &auth_rsp));
284 return_if_error (rc, "Tss2_Sys_NV_Read");
285 }
286
287 rc = Tss2_Tcti_SetLocality (tcti_ctx, 3);
288 return_if_error (rc, "Tss2_Tcti_SetLocality");
289
290 return rc;
291 }
292
293 int
test_invoke(TSS2_SYS_CONTEXT * sys_ctx)294 test_invoke (TSS2_SYS_CONTEXT *sys_ctx)
295 {
296 TSS2_RC rc, rc_teardown;
297
298 rc = setup_nv (sys_ctx);
299 return_if_error (rc, "setup_nv");
300 rc = nv_write_test (sys_ctx);
301 goto_if_error (rc, "nv_write_test", teardown);
302 rc = nv_read_test (sys_ctx);
303 goto_if_error (rc, "nv_read_test", teardown);
304 teardown:
305 rc_teardown = teardown_nv (sys_ctx);
306 return_if_error (rc, "NV policy locality test failed");
307 return_if_error (rc_teardown, "teardown_nv");
308
309 return rc;
310 }
311