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