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 <inttypes.h>
11 #include <stdbool.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15
16 #include "tss2_sys.h"
17
18 #include "context-util.h"
19 #include "sys-util.h"
20 #include "session-util.h"
21 #define LOGMODULE test
22 #include "util/log.h"
23
24 #define TPM20_INDEX_PASSWORD_TEST 0x01500020
25
26 #define NV_DATA_SIZE 4
27 #define NV_DATA { 0x00, 0xff, 0x55, 0xaa }
28 #define SECRET_SIZE 13
29 #define SECRET_DATA { 's', 'h', 'a', 'r', 'e', 'd', ' ', \
30 's', 'e', 'c', 'r', 'e', 't', }
31
32 TSS2_RC
create_policy(TSS2_SYS_CONTEXT * sys_ctx,TPM2B_DIGEST * authPolicy)33 create_policy (TSS2_SYS_CONTEXT *sys_ctx,
34 TPM2B_DIGEST *authPolicy)
35 {
36 TSS2_RC rc;
37 SESSION *trialPolicySession = NULL;
38 TPM2B_NONCE nonceCaller = { 0, };
39 TPM2B_ENCRYPTED_SECRET encryptedSalt = { 0, };
40 TPMT_SYM_DEF symmetric = {
41 .algorithm = TPM2_ALG_NULL,
42 };
43 TSS2_TCTI_CONTEXT *tcti_ctx;
44
45 rc = Tss2_Sys_GetTctiContext (sys_ctx, &tcti_ctx);
46 if (rc != TSS2_RC_SUCCESS || tcti_ctx == NULL) {
47 LOG_ERROR("InitSysContext failed, exiting...");
48 return rc;
49 }
50
51 rc = create_auth_session (&trialPolicySession,
52 TPM2_RH_NULL,
53 0,
54 TPM2_RH_NULL,
55 0,
56 &nonceCaller,
57 &encryptedSalt,
58 TPM2_SE_TRIAL,
59 &symmetric,
60 TPM2_ALG_SHA256,
61 tcti_ctx);
62 if (rc != TSS2_RC_SUCCESS) {
63 LOG_ERROR ("create_auth_session failed with rc: 0x%x", rc);
64 return rc;
65 }
66 rc = Tss2_Sys_PolicyAuthValue (sys_ctx,
67 trialPolicySession->sessionHandle,
68 0,
69 0);
70 if (rc != TSS2_RC_SUCCESS) {
71 LOG_ERROR ("Tss2_Sys_PolicyAuthValue failed with rc: 0x%x", rc);
72 return rc;
73 }
74 rc = Tss2_Sys_PolicyGetDigest (sys_ctx,
75 trialPolicySession->sessionHandle,
76 0,
77 authPolicy,
78 0);
79 if (rc != TSS2_RC_SUCCESS) {
80 LOG_ERROR ("Tss2_Sys_PolicyGetDigest failed with rc: 0x%x", rc);
81 return rc;
82 }
83
84 rc = Tss2_Sys_FlushContext (sys_ctx,
85 trialPolicySession->sessionHandle);
86 if (rc != TSS2_RC_SUCCESS) {
87 LOG_ERROR ("Tss2_Sys_FlushContext failed with rc: 0x%x", rc);
88 return rc;
89 }
90
91 end_auth_session (trialPolicySession);
92 return rc;
93 }
94
95 TSS2_RC
nv_rw_with_session(TSS2_SYS_CONTEXT * sys_ctx,const TPM2B_DIGEST * authPolicy,TPMA_NV nvAttributes,TPM2_SE session_type)96 nv_rw_with_session (
97 TSS2_SYS_CONTEXT *sys_ctx,
98 const TPM2B_DIGEST *authPolicy,
99 TPMA_NV nvAttributes,
100 TPM2_SE session_type)
101 {
102 TSS2_RC rc;
103 TPM2B_AUTH nvAuth = {
104 .size = SECRET_SIZE,
105 .buffer = SECRET_DATA,
106 };
107 SESSION *nvSession = NULL;
108 TPM2B_NAME nvName;
109 TPM2B_NONCE nonceCaller = { 0, };
110 TPM2B_MAX_NV_BUFFER nvWriteData = {
111 .size = NV_DATA_SIZE,
112 .buffer = NV_DATA,
113 };
114 TPM2B_MAX_NV_BUFFER nvReadData = { .size = TPM2B_SIZE (nvReadData), };
115 TPM2B_ENCRYPTED_SECRET encryptedSalt = { 0, };
116 TPMT_SYM_DEF symmetric = {
117 .algorithm = TPM2_ALG_NULL,
118 };
119 TSS2_TCTI_CONTEXT *tcti_ctx;
120 TSS2L_SYS_AUTH_RESPONSE nvRspAuths;
121 TSS2L_SYS_AUTH_COMMAND nvCmdAuths = {
122 .count = 1,
123 .auths= {
124 {
125 .nonce = {
126 .size = 1,
127 .buffer = { 0xa5, },
128 },
129 .sessionHandle = TPM2_RS_PW,
130 .sessionAttributes = TPMA_SESSION_CONTINUESESSION,
131 }
132 }
133 };
134 const TSS2L_SYS_AUTH_COMMAND auth_cmd_null_pwd = {
135 .count = 1,
136 .auths = {
137 {
138 .sessionHandle = TPM2_RS_PW,
139 },
140 },
141 };
142
143
144 rc = Tss2_Sys_GetTctiContext (sys_ctx, &tcti_ctx);
145 if (rc != TSS2_RC_SUCCESS || tcti_ctx == NULL) {
146 LOG_ERROR ("Failed to get TCTI from Sys context, got RC: 0x%x", rc);
147 return TSS2_SYS_RC_GENERAL_FAILURE;
148 }
149
150 rc = DefineNvIndex (sys_ctx,
151 TPM2_RH_PLATFORM,
152 &nvAuth,
153 authPolicy,
154 TPM20_INDEX_PASSWORD_TEST,
155 TPM2_ALG_SHA256,
156 nvAttributes,
157 32);
158 if (rc != TSS2_RC_SUCCESS) {
159 LOG_ERROR ("DefineNvIndex failed with RC: 0x%x", rc);
160 return rc;
161 }
162
163 /*
164 * Add index and associated authorization value to
165 * entity table. This helps when we need
166 * to calculate HMACs.
167 */
168 rc = AddEntity(TPM20_INDEX_PASSWORD_TEST, &nvAuth);
169 if (rc != TSS2_RC_SUCCESS) {
170 LOG_ERROR ("AddEntity failed with RC: 0x%x", rc);
171 return rc;
172 }
173
174 /* Get the name of the NV index. */
175 rc = tpm_handle_to_name (tcti_ctx,
176 TPM20_INDEX_PASSWORD_TEST,
177 &nvName);
178 if (rc != TSS2_RC_SUCCESS) {
179 LOG_ERROR ("tpm_handle_to_name failed with RC: 0x%x", rc);
180 return rc;
181 }
182
183 /*
184 * Start HMAC or real (non-trial) policy authorization session:
185 * it's an unbound and unsalted session, no symmetric
186 * encryption algorithm, and SHA256 is the session's
187 * hash algorithm.
188 */
189 rc = create_auth_session (&nvSession,
190 TPM2_RH_NULL,
191 0,
192 TPM2_RH_NULL,
193 0,
194 &nonceCaller,
195 &encryptedSalt,
196 session_type,
197 &symmetric,
198 TPM2_ALG_SHA256,
199 tcti_ctx);
200 if (rc != TSS2_RC_SUCCESS) {
201 LOG_ERROR ("create_auth_session failed with RC: 0x%x", rc);
202 return rc;
203 }
204
205 /* set handle in command auth */
206 nvCmdAuths.auths[0].sessionHandle = nvSession->sessionHandle;
207
208 /*
209 * Get the name of the session and save it in
210 * the nvSession structure.
211 */
212 rc = tpm_handle_to_name (tcti_ctx,
213 nvSession->sessionHandle,
214 &nvSession->name);
215 if (rc != TSS2_RC_SUCCESS) {
216 LOG_ERROR ("tpm_handle_to_name failed with RC: 0x%x", rc);
217 return rc;
218 }
219
220 /*
221 * Now setup for writing the NV index.
222 */
223 if (session_type == TPM2_SE_POLICY) {
224 rc = Tss2_Sys_PolicyAuthValue (sys_ctx,
225 nvSession->sessionHandle,
226 0,
227 0);
228 if (rc != TSS2_RC_SUCCESS) {
229 LOG_ERROR ("Tss2_Sys_PolicyAuthValue failed with RC: 0x%x", rc);
230 return rc;
231 }
232 }
233 /* First call prepare in order to create cpBuffer. */
234 rc = Tss2_Sys_NV_Write_Prepare (sys_ctx,
235 TPM20_INDEX_PASSWORD_TEST,
236 TPM20_INDEX_PASSWORD_TEST,
237 &nvWriteData,
238 0);
239 if (rc != TSS2_RC_SUCCESS) {
240 LOG_ERROR ("Tss2_Sys_NV_Write_Prepare failed with RC: 0x%x", rc);
241 return rc;
242 }
243
244 /* Roll nonces for command */
245 roll_nonces (nvSession, &nvCmdAuths.auths[0].nonce);
246
247 /*
248 * Complete command authorization area, by computing
249 * HMAC and setting it in nvCmdAuths.
250 */
251 rc = compute_command_hmac(sys_ctx,
252 TPM20_INDEX_PASSWORD_TEST,
253 TPM20_INDEX_PASSWORD_TEST,
254 TPM2_RH_NULL,
255 &nvCmdAuths);
256 if (rc != TSS2_RC_SUCCESS) {
257 LOG_ERROR ("compute_command_hmac failed with RC: 0x%x", rc);
258 return rc;
259 }
260
261 /*
262 * Finally!! Write the data to the NV index.
263 * If the command is successful, the command
264 * HMAC was correct.
265 */
266 rc = TSS2_RETRY_EXP (Tss2_Sys_NV_Write (sys_ctx,
267 TPM20_INDEX_PASSWORD_TEST,
268 TPM20_INDEX_PASSWORD_TEST,
269 &nvCmdAuths,
270 &nvWriteData,
271 0,
272 &nvRspAuths));
273 if (rc != TSS2_RC_SUCCESS) {
274 LOG_ERROR ("Tss2_Sys_NV_Write failed with RC: 0x%x", rc);
275 return rc;
276 }
277
278
279 /* Roll nonces for response */
280 roll_nonces (nvSession, &nvRspAuths.auths[0].nonce);
281
282 /*
283 * If the command was successful, check the
284 * response HMAC to make sure that the
285 * response was received correctly.
286 */
287 rc = check_response_hmac (sys_ctx,
288 &nvCmdAuths,
289 TPM20_INDEX_PASSWORD_TEST,
290 TPM20_INDEX_PASSWORD_TEST,
291 TPM2_RH_NULL,
292 &nvRspAuths);
293 if (rc != TSS2_RC_SUCCESS) {
294 LOG_ERROR ("check_response_hmac failed with RC: 0x%x", rc);
295 return rc;
296 }
297
298 if (session_type == TPM2_SE_POLICY) {
299 rc = Tss2_Sys_PolicyAuthValue (sys_ctx,
300 nvSession->sessionHandle,
301 0,
302 0);
303 if (rc != TSS2_RC_SUCCESS) {
304 LOG_ERROR ("Tss2_Sys_PolicyAuthValue failed with RC: 0x%x", rc);
305 return rc;
306 }
307 }
308 /* First call prepare in order to create cpBuffer. */
309 rc = Tss2_Sys_NV_Read_Prepare (sys_ctx,
310 TPM20_INDEX_PASSWORD_TEST,
311 TPM20_INDEX_PASSWORD_TEST,
312 NV_DATA_SIZE,
313 0);
314 if (rc != TSS2_RC_SUCCESS) {
315 LOG_ERROR ("Tss2_Sys_NV_Read_Prepare failed with RC: 0x%x", rc);
316 return rc;
317 }
318
319 roll_nonces (nvSession, &nvCmdAuths.auths[0].nonce);
320 /* End the session after next command. */
321 nvCmdAuths.auths[0].sessionAttributes &= ~TPMA_SESSION_CONTINUESESSION;
322
323 /*
324 * Complete command authorization area, by computing
325 * HMAC and setting it in nvCmdAuths.
326 */
327 rc = compute_command_hmac (sys_ctx,
328 TPM20_INDEX_PASSWORD_TEST,
329 TPM20_INDEX_PASSWORD_TEST,
330 TPM2_RH_NULL,
331 &nvCmdAuths);
332 if (rc != TSS2_RC_SUCCESS) {
333 LOG_ERROR ("compute_command_hmac failed with RC: 0x%x", rc);
334 return rc;
335 }
336
337 /*
338 * And now read the data back.
339 * If the command is successful, the command
340 * HMAC was correct.
341 */
342 rc = Tss2_Sys_NV_Read (sys_ctx,
343 TPM20_INDEX_PASSWORD_TEST,
344 TPM20_INDEX_PASSWORD_TEST,
345 &nvCmdAuths,
346 NV_DATA_SIZE,
347 0,
348 &nvReadData,
349 &nvRspAuths);
350 if (rc != TSS2_RC_SUCCESS) {
351 LOG_ERROR ("Tss2_Sys_NV_Read failed with RC: 0x%x", rc);
352 return rc;
353 }
354
355 /* Roll nonces for response */
356 roll_nonces (nvSession, &nvRspAuths.auths[0].nonce);
357
358 /*
359 * If the command was successful, check the
360 * response HMAC to make sure that the
361 * response was received correctly.
362 */
363 rc = check_response_hmac (sys_ctx,
364 &nvCmdAuths,
365 TPM20_INDEX_PASSWORD_TEST,
366 TPM20_INDEX_PASSWORD_TEST,
367 TPM2_RH_NULL,
368 &nvRspAuths);
369 if (rc != TSS2_RC_SUCCESS) {
370 LOG_ERROR ("check_response_hmac failed with RC: 0x%x", rc);
371 return rc;
372 }
373
374 /* Check that write and read data are equal. */
375 if (memcmp ((void *)&nvReadData.buffer[0],
376 (void *)&nvWriteData.buffer[0],
377 nvReadData.size))
378 {
379 LOG_ERROR ("Data read not equal to data written.");
380 return 1;
381 }
382
383 /*
384 * Now cleanup: undefine the NV index and delete
385 * the NV index's entity table entry.
386 */
387
388 /* Undefine the NV index. */
389 rc = Tss2_Sys_NV_UndefineSpace (sys_ctx,
390 TPM2_RH_PLATFORM,
391 TPM20_INDEX_PASSWORD_TEST,
392 &auth_cmd_null_pwd,
393 0);
394 if (rc != TSS2_RC_SUCCESS) {
395 LOG_ERROR ("Tss2_Sys_NV_UndefineSpace failed with RC: 0x%x", rc);
396 return rc;
397 }
398
399 /* Delete the NV index's entry in the entity table. */
400 DeleteEntity (TPM20_INDEX_PASSWORD_TEST);
401
402 /* Remove the real session from sessions table. */
403 end_auth_session (nvSession);
404 return rc;
405 }
406
407 int
test_invoke(TSS2_SYS_CONTEXT * sys_ctx)408 test_invoke (TSS2_SYS_CONTEXT *sys_ctx)
409 {
410 TSS2_RC rc;
411 TPM2B_DIGEST authPolicy = { 0, };
412 TPMA_NV nvAttributes;
413
414 LOG_INFO ("HMAC session test");
415 nvAttributes = TPMA_NV_AUTHREAD | TPMA_NV_AUTHWRITE | TPMA_NV_PLATFORMCREATE;
416 rc = nv_rw_with_session (sys_ctx, &authPolicy, nvAttributes, TPM2_SE_HMAC);
417 if (rc != TSS2_RC_SUCCESS)
418 return rc;
419
420 LOG_INFO ("Policy session test");
421 authPolicy.size = TPM2B_SIZE (authPolicy);
422 rc = create_policy (sys_ctx, &authPolicy);
423 if (rc != TSS2_RC_SUCCESS)
424 return rc;
425 nvAttributes = TPMA_NV_POLICYREAD | TPMA_NV_POLICYWRITE | TPMA_NV_PLATFORMCREATE;
426 rc = nv_rw_with_session (sys_ctx, &authPolicy, nvAttributes, TPM2_SE_POLICY);
427 if (rc != TSS2_RC_SUCCESS)
428 return rc;
429
430 return TSS2_RC_SUCCESS;
431 }
432