/* * SPDX-License-Identifier: BSD-2-Clause * Copyright (c) 2019, Intel Corporation */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "tss2_sys.h" #include "context-util.h" #include "sapi-util.h" #include "session-util.h" #define LOGMODULE test #include "util/log.h" #define TPM20_INDEX_PASSWORD_TEST 0x01500020 #define NV_DATA_SIZE 4 #define NV_DATA { 0x00, 0xff, 0x55, 0xaa } #define SECRET_SIZE 13 #define SECRET_DATA { 's', 'h', 'a', 'r', 'e', 'd', ' ', \ 's', 'e', 'c', 'r', 'e', 't', } TSS2_RC create_policy (TSS2_SYS_CONTEXT *sys_ctx, TPM2B_DIGEST *authPolicy) { TSS2_RC rc; SESSION *trialPolicySession = NULL; TPM2B_NONCE nonceCaller = { 0, }; TPM2B_ENCRYPTED_SECRET encryptedSalt = { 0, }; TPMT_SYM_DEF symmetric = { .algorithm = TPM2_ALG_NULL, }; TSS2_TCTI_CONTEXT *tcti_ctx; rc = Tss2_Sys_GetTctiContext (sys_ctx, &tcti_ctx); if (rc != TSS2_RC_SUCCESS || tcti_ctx == NULL) { LOG_ERROR("InitSysContext failed, exiting..."); return rc; } rc = create_auth_session (&trialPolicySession, TPM2_RH_NULL, 0, TPM2_RH_NULL, 0, &nonceCaller, &encryptedSalt, TPM2_SE_TRIAL, &symmetric, TPM2_ALG_SHA256, tcti_ctx); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR ("create_auth_session failed with rc: 0x%x", rc); return rc; } rc = Tss2_Sys_PolicyAuthValue (sys_ctx, trialPolicySession->sessionHandle, 0, 0); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR ("Tss2_Sys_PolicyAuthValue failed with rc: 0x%x", rc); return rc; } rc = Tss2_Sys_PolicyGetDigest (sys_ctx, trialPolicySession->sessionHandle, 0, authPolicy, 0); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR ("Tss2_Sys_PolicyGetDigest failed with rc: 0x%x", rc); return rc; } rc = Tss2_Sys_FlushContext (sys_ctx, trialPolicySession->sessionHandle); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR ("Tss2_Sys_FlushContext failed with rc: 0x%x", rc); return rc; } end_auth_session (trialPolicySession); return rc; } TSS2_RC nv_rw_with_session ( TSS2_SYS_CONTEXT *sys_ctx, const TPM2B_DIGEST *authPolicy, TPMA_NV nvAttributes, TPM2_SE session_type) { TSS2_RC rc; TPM2B_AUTH nvAuth = { .size = SECRET_SIZE, .buffer = SECRET_DATA, }; SESSION *nvSession = NULL; TPM2B_NAME nvName; TPM2B_NONCE nonceCaller = { 0, }; TPM2B_MAX_NV_BUFFER nvWriteData = { .size = NV_DATA_SIZE, .buffer = NV_DATA, }; TPM2B_MAX_NV_BUFFER nvReadData = { .size = TPM2B_SIZE (nvReadData), }; TPM2B_ENCRYPTED_SECRET encryptedSalt = { 0, }; TPMT_SYM_DEF symmetric = { .algorithm = TPM2_ALG_NULL, }; TSS2_TCTI_CONTEXT *tcti_ctx; TSS2L_SYS_AUTH_RESPONSE nvRspAuths; TSS2L_SYS_AUTH_COMMAND nvCmdAuths = { .count = 1, .auths= { { .nonce = { .size = 1, .buffer = { 0xa5, }, }, .sessionHandle = TPM2_RS_PW, .sessionAttributes = TPMA_SESSION_CONTINUESESSION, } } }; const TSS2L_SYS_AUTH_COMMAND auth_cmd_null_pwd = { .count = 1, .auths = { { .sessionHandle = TPM2_RS_PW, }, }, }; rc = Tss2_Sys_GetTctiContext (sys_ctx, &tcti_ctx); if (rc != TSS2_RC_SUCCESS || tcti_ctx == NULL) { LOG_ERROR ("Failed to get TCTI from Sys context, got RC: 0x%x", rc); return TSS2_SYS_RC_GENERAL_FAILURE; } rc = DefineNvIndex (sys_ctx, TPM2_RH_PLATFORM, &nvAuth, authPolicy, TPM20_INDEX_PASSWORD_TEST, TPM2_ALG_SHA256, nvAttributes, 32); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR ("DefineNvIndex failed with RC: 0x%x", rc); return rc; } /* * Add index and associated authorization value to * entity table. This helps when we need * to calculate HMACs. */ rc = AddEntity(TPM20_INDEX_PASSWORD_TEST, &nvAuth); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR ("AddEntity failed with RC: 0x%x", rc); return rc; } /* Get the name of the NV index. */ rc = tpm_handle_to_name (tcti_ctx, TPM20_INDEX_PASSWORD_TEST, &nvName); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR ("tpm_handle_to_name failed with RC: 0x%x", rc); return rc; } /* * Start HMAC or real (non-trial) policy authorization session: * it's an unbound and unsalted session, no symmetric * encryption algorithm, and SHA256 is the session's * hash algorithm. */ rc = create_auth_session (&nvSession, TPM2_RH_NULL, 0, TPM2_RH_NULL, 0, &nonceCaller, &encryptedSalt, session_type, &symmetric, TPM2_ALG_SHA256, tcti_ctx); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR ("create_auth_session failed with RC: 0x%x", rc); return rc; } /* set handle in command auth */ nvCmdAuths.auths[0].sessionHandle = nvSession->sessionHandle; /* * Get the name of the session and save it in * the nvSession structure. */ rc = tpm_handle_to_name (tcti_ctx, nvSession->sessionHandle, &nvSession->name); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR ("tpm_handle_to_name failed with RC: 0x%x", rc); return rc; } /* * Now setup for writing the NV index. */ if (session_type == TPM2_SE_POLICY) { rc = Tss2_Sys_PolicyAuthValue (sys_ctx, nvSession->sessionHandle, 0, 0); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR ("Tss2_Sys_PolicyAuthValue failed with RC: 0x%x", rc); return rc; } } /* First call prepare in order to create cpBuffer. */ rc = Tss2_Sys_NV_Write_Prepare (sys_ctx, TPM20_INDEX_PASSWORD_TEST, TPM20_INDEX_PASSWORD_TEST, &nvWriteData, 0); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR ("Tss2_Sys_NV_Write_Prepare failed with RC: 0x%x", rc); return rc; } /* Roll nonces for command */ roll_nonces (nvSession, &nvCmdAuths.auths[0].nonce); /* * Complete command authorization area, by computing * HMAC and setting it in nvCmdAuths. */ rc = compute_command_hmac(sys_ctx, TPM20_INDEX_PASSWORD_TEST, TPM20_INDEX_PASSWORD_TEST, TPM2_RH_NULL, &nvCmdAuths); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR ("compute_command_hmac failed with RC: 0x%x", rc); return rc; } /* * Finally!! Write the data to the NV index. * If the command is successful, the command * HMAC was correct. */ rc = TSS2_RETRY_EXP (Tss2_Sys_NV_Write (sys_ctx, TPM20_INDEX_PASSWORD_TEST, TPM20_INDEX_PASSWORD_TEST, &nvCmdAuths, &nvWriteData, 0, &nvRspAuths)); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR ("Tss2_Sys_NV_Write failed with RC: 0x%x", rc); return rc; } /* Roll nonces for response */ roll_nonces (nvSession, &nvRspAuths.auths[0].nonce); /* * If the command was successful, check the * response HMAC to make sure that the * response was received correctly. */ rc = check_response_hmac (sys_ctx, &nvCmdAuths, TPM20_INDEX_PASSWORD_TEST, TPM20_INDEX_PASSWORD_TEST, TPM2_RH_NULL, &nvRspAuths); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR ("check_response_hmac failed with RC: 0x%x", rc); return rc; } if (session_type == TPM2_SE_POLICY) { rc = Tss2_Sys_PolicyAuthValue (sys_ctx, nvSession->sessionHandle, 0, 0); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR ("Tss2_Sys_PolicyAuthValue failed with RC: 0x%x", rc); return rc; } } /* First call prepare in order to create cpBuffer. */ rc = Tss2_Sys_NV_Read_Prepare (sys_ctx, TPM20_INDEX_PASSWORD_TEST, TPM20_INDEX_PASSWORD_TEST, NV_DATA_SIZE, 0); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR ("Tss2_Sys_NV_Read_Prepare failed with RC: 0x%x", rc); return rc; } roll_nonces (nvSession, &nvCmdAuths.auths[0].nonce); /* End the session after next command. */ nvCmdAuths.auths[0].sessionAttributes &= ~TPMA_SESSION_CONTINUESESSION; /* * Complete command authorization area, by computing * HMAC and setting it in nvCmdAuths. */ rc = compute_command_hmac (sys_ctx, TPM20_INDEX_PASSWORD_TEST, TPM20_INDEX_PASSWORD_TEST, TPM2_RH_NULL, &nvCmdAuths); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR ("compute_command_hmac failed with RC: 0x%x", rc); return rc; } /* * And now read the data back. * If the command is successful, the command * HMAC was correct. */ rc = Tss2_Sys_NV_Read (sys_ctx, TPM20_INDEX_PASSWORD_TEST, TPM20_INDEX_PASSWORD_TEST, &nvCmdAuths, NV_DATA_SIZE, 0, &nvReadData, &nvRspAuths); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR ("Tss2_Sys_NV_Read failed with RC: 0x%x", rc); return rc; } /* Roll nonces for response */ roll_nonces (nvSession, &nvRspAuths.auths[0].nonce); /* * If the command was successful, check the * response HMAC to make sure that the * response was received correctly. */ rc = check_response_hmac (sys_ctx, &nvCmdAuths, TPM20_INDEX_PASSWORD_TEST, TPM20_INDEX_PASSWORD_TEST, TPM2_RH_NULL, &nvRspAuths); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR ("check_response_hmac failed with RC: 0x%x", rc); return rc; } /* Check that write and read data are equal. */ if (memcmp ((void *)&nvReadData.buffer[0], (void *)&nvWriteData.buffer[0], nvReadData.size)) { LOG_ERROR ("Data read not equal to data written."); return 1; } /* * Now cleanup: undefine the NV index and delete * the NV index's entity table entry. */ /* Undefine the NV index. */ rc = Tss2_Sys_NV_UndefineSpace (sys_ctx, TPM2_RH_PLATFORM, TPM20_INDEX_PASSWORD_TEST, &auth_cmd_null_pwd, 0); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR ("Tss2_Sys_NV_UndefineSpace failed with RC: 0x%x", rc); return rc; } /* Delete the NV index's entry in the entity table. */ DeleteEntity (TPM20_INDEX_PASSWORD_TEST); /* Remove the real session from sessions table. */ end_auth_session (nvSession); return rc; } int test_invoke (TSS2_SYS_CONTEXT *sys_ctx) { TSS2_RC rc; TPM2B_DIGEST authPolicy = { 0, }; TPMA_NV nvAttributes; LOG_INFO ("HMAC session test"); nvAttributes = TPMA_NV_AUTHREAD | TPMA_NV_AUTHWRITE | TPMA_NV_PLATFORMCREATE; rc = nv_rw_with_session (sys_ctx, &authPolicy, nvAttributes, TPM2_SE_HMAC); if (rc != TSS2_RC_SUCCESS) return rc; LOG_INFO ("Policy session test"); authPolicy.size = TPM2B_SIZE (authPolicy); rc = create_policy (sys_ctx, &authPolicy); if (rc != TSS2_RC_SUCCESS) return rc; nvAttributes = TPMA_NV_POLICYREAD | TPMA_NV_POLICYWRITE | TPMA_NV_PLATFORMCREATE; rc = nv_rw_with_session (sys_ctx, &authPolicy, nvAttributes, TPM2_SE_POLICY); if (rc != TSS2_RC_SUCCESS) return rc; return TSS2_RC_SUCCESS; }