| /*********************************************************************** |
| * Copyright (c) 2017-2018, Intel Corporation |
| * |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| ***********************************************************************/ |
| #include <inttypes.h> |
| |
| #include "session-util.h" |
| #include "sapi-util.h" |
| #include "context-util.h" |
| #include "util/tss2_endian.h" |
| #define LOGMODULE test |
| #include "util/log.h" |
| |
| static SESSION *sessions = NULL; |
| |
| SESSION * |
| get_session(TPMI_SH_AUTH_SESSION hndl) |
| { |
| SESSION *s; |
| |
| HASH_FIND_INT(sessions, &hndl, s); |
| return s; |
| } |
| |
| static TSS2_RC |
| start_auth_session( |
| SESSION *session, |
| TSS2_TCTI_CONTEXT *tctiContext) |
| { |
| TSS2_RC rval; |
| TPM2B_ENCRYPTED_SECRET key; |
| char label[] = "ATH"; |
| TSS2_SYS_CONTEXT *tmp_context; |
| UINT16 bytes; |
| |
| key.size = 0; |
| |
| tmp_context = sapi_init_from_tcti_ctx(tctiContext); |
| if (tmp_context == NULL) |
| return TSS2_SYS_RC_GENERAL_FAILURE; |
| |
| if (session->nonceOlder.size == 0) |
| session->nonceOlder.size = GetDigestSize(session->authHash); |
| |
| memset(session->nonceOlder.buffer, '\0', session->nonceOlder.size); |
| session->nonceNewer.size = session->nonceOlder.size; |
| session->nonceTpmDecrypt.size = 0; |
| session->nonceTpmEncrypt.size = 0; |
| |
| rval = Tss2_Sys_StartAuthSession( |
| tmp_context, session->tpmKey, session->bind, 0, |
| &session->nonceOlder, &session->encryptedSalt, |
| session->sessionType, &session->symmetric, |
| session->authHash, &session->sessionHandle, |
| &session->nonceNewer, 0); |
| if (rval != TPM2_RC_SUCCESS) |
| goto out; |
| |
| if (session->tpmKey == TPM2_RH_NULL) |
| session->salt.size = 0; |
| |
| if (session->bind == TPM2_RH_NULL) |
| session->authValueBind.size = 0; |
| |
| session->sessionKey.size = 0; |
| if (session->tpmKey == TPM2_RH_NULL && session->bind == TPM2_RH_NULL) |
| goto out; |
| |
| /* Generate the key used as input to the KDF. */ |
| rval = ConcatSizedByteBuffer((TPM2B_MAX_BUFFER *)&key, |
| (TPM2B *)&session->authValueBind); |
| if (rval != TPM2_RC_SUCCESS) { |
| Tss2_Sys_FlushContext(tmp_context, session->sessionHandle); |
| goto out; |
| } |
| |
| rval = ConcatSizedByteBuffer((TPM2B_MAX_BUFFER *)&key, |
| (TPM2B *)&session->salt); |
| if (rval != TPM2_RC_SUCCESS) { |
| Tss2_Sys_FlushContext(tmp_context, session->sessionHandle); |
| goto out; |
| } |
| |
| bytes = GetDigestSize(session->authHash) * 8; |
| |
| rval = KDFa(session->authHash, (TPM2B *)&key, label, |
| (TPM2B *)&session->nonceNewer, |
| (TPM2B *)&session->nonceOlder, |
| bytes, (TPM2B_MAX_BUFFER *)&session->sessionKey); |
| out: |
| sapi_teardown(tmp_context); |
| return rval; |
| } |
| |
| static TSS2_RC |
| compute_session_auth( |
| TSS2_SYS_CONTEXT *sysContext, |
| SESSION *session, |
| TPMS_AUTH_COMMAND *pSessionDataIn, |
| bool command, |
| TPM2_HANDLE handle1, |
| TPM2_HANDLE handle2, |
| TPM2_HANDLE handle3, |
| TPM2B_MAX_BUFFER *hmacKey) |
| { |
| TPM2B_DIGEST *buffer_list[7]; |
| TPM2B_DIGEST pHash = TPM2B_DIGEST_INIT; |
| TPM2B sessionAttributesByteBuffer = { |
| .size = 1, |
| .buffer = pSessionDataIn->sessionAttributes |
| }; |
| UINT16 i; |
| TSS2_RC rval; |
| TPM2_CC cmdCode; |
| |
| rval = tpm_calc_phash(sysContext, handle1, handle2, handle3, |
| session->authHash, command, &pHash); |
| if (rval != TPM2_RC_SUCCESS) |
| return rval; |
| |
| rval = Tss2_Sys_GetCommandCode(sysContext, (UINT8 *)&cmdCode); |
| if (rval != TPM2_RC_SUCCESS) |
| return rval; |
| |
| /* cmdCode comes back as BigEndian; not suited for comparisons below. */ |
| cmdCode = BE_TO_HOST_32(cmdCode); |
| LOGBLOB_DEBUG(hmacKey->buffer, hmacKey->size, "hmacKey="); |
| |
| i = 0; |
| buffer_list[i++] = (TPM2B_DIGEST *)&pHash; |
| buffer_list[i++] = (TPM2B_DIGEST *)&session->nonceNewer; |
| buffer_list[i++] = (TPM2B_DIGEST *)&session->nonceOlder; |
| buffer_list[i++] = (TPM2B_DIGEST *)&session->nonceTpmDecrypt; |
| buffer_list[i++] = (TPM2B_DIGEST *)&session->nonceTpmEncrypt; |
| buffer_list[i++] = (TPM2B_DIGEST *)&sessionAttributesByteBuffer; |
| buffer_list[i++] = 0; |
| |
| for (int j = 0; buffer_list[j] != 0; j++) { |
| LOGBLOB_DEBUG(&buffer_list[j]->buffer[0], |
| buffer_list[j]->size, "bufferlist[%d]:", j); |
| ; |
| } |
| |
| rval = hmac(session->authHash, hmacKey->buffer, |
| hmacKey->size, buffer_list, |
| (TPM2B_DIGEST *)&pSessionDataIn->hmac); |
| |
| if (rval != TPM2_RC_SUCCESS) { |
| LOGBLOB_ERROR(pSessionDataIn->hmac.buffer, |
| pSessionDataIn->hmac.size, |
| "HMAC Failed rval = %d !!!", rval); |
| return rval; |
| } |
| return rval; |
| } |
| |
| TSS2_RC |
| compute_command_hmac( |
| TSS2_SYS_CONTEXT *sysContext, |
| TPM2_HANDLE handle1, |
| TPM2_HANDLE handle2, |
| TPM2_HANDLE handle3, |
| TSS2L_SYS_AUTH_COMMAND *pSessionsDataIn) |
| { |
| TPM2_HANDLE handles[3] = {handle1, handle2, handle3}; |
| ENTITY *entity; |
| SESSION *session; |
| TPM2B_MAX_BUFFER hmac_key; |
| TSS2_RC rval = TPM2_RC_SUCCESS; |
| unsigned int i; |
| unsigned int count = pSessionsDataIn->count; |
| |
| if (count > 3) { |
| LOG_ERROR("Bad value for session count: %" PRIu16, count); |
| return TSS2_SYS_RC_GENERAL_FAILURE; |
| } |
| |
| for (i = 0; i < count; i++) { |
| if (handles[i] == TPM2_RH_NULL) |
| break; |
| |
| entity = GetEntity(handles[i]); |
| if (!entity) |
| return TSS2_SYS_RC_GENERAL_FAILURE; |
| |
| session = get_session(pSessionsDataIn->auths[i].sessionHandle); |
| if (!session) |
| return TPM2_RC_SUCCESS; |
| |
| CopySizedByteBuffer((TPM2B *)&hmac_key, (TPM2B *)&session->sessionKey); |
| |
| if (handles[i] != session->bind || handles[i] == TPM2_RH_NULL) |
| ConcatSizedByteBuffer(&hmac_key, (TPM2B *)&entity->entityAuth); |
| |
| rval = compute_session_auth(sysContext, |
| session, |
| &pSessionsDataIn->auths[i], |
| true, |
| handle1, |
| handle2, |
| handle3, |
| &hmac_key); |
| if (rval != TPM2_RC_SUCCESS) |
| break; |
| } |
| return rval; |
| } |
| |
| TSS2_RC check_response_hmac( |
| TSS2_SYS_CONTEXT *sysContext, |
| TSS2L_SYS_AUTH_COMMAND *pSessionsDataIn, |
| TPM2_HANDLE handle1, |
| TPM2_HANDLE handle2, |
| TPM2_HANDLE handle3, |
| TSS2L_SYS_AUTH_RESPONSE *pSessionsDataOut) |
| { |
| TPM2_HANDLE handles[3] = {handle1, handle2, handle3}; |
| ENTITY *entity; |
| SESSION *session; |
| TPM2B_MAX_BUFFER hmac_key; |
| TSS2_RC rval = TPM2_RC_SUCCESS; |
| unsigned int i; |
| unsigned int count = pSessionsDataIn->count; |
| |
| if (count > 3) { |
| LOG_ERROR("Bad value for session count: %" PRIu16, count); |
| return TSS2_SYS_RC_GENERAL_FAILURE; |
| } |
| |
| for (i = 0; i < count; i++) { |
| if (handles[i] == TPM2_RH_NULL) |
| break; |
| |
| entity = GetEntity(handles[i]); |
| if (!entity) |
| return TSS2_SYS_RC_GENERAL_FAILURE; |
| |
| session = get_session(pSessionsDataIn->auths[i].sessionHandle); |
| if (!session) |
| return TPM2_RC_SUCCESS; |
| |
| CopySizedByteBuffer((TPM2B *)&hmac_key, (TPM2B *)&session->sessionKey); |
| |
| if (handles[i] != session->bind) |
| ConcatSizedByteBuffer(&hmac_key, (TPM2B *)&entity->entityAuth); |
| |
| rval = compute_session_auth(sysContext, |
| session, |
| &pSessionsDataIn->auths[i], |
| false, |
| handle1, |
| handle2, |
| handle3, |
| &hmac_key); |
| |
| if (rval != TPM2_RC_SUCCESS) |
| return rval; |
| |
| rval = CompareSizedByteBuffer((TPM2B *)&pSessionsDataIn->auths[i].hmac, |
| (TPM2B *)&pSessionsDataOut->auths[i].hmac); |
| if (rval != TPM2_RC_SUCCESS) |
| return TSS2_SYS_RC_GENERAL_FAILURE; |
| } |
| return rval; |
| } |
| |
| TSS2_RC create_auth_session( |
| SESSION **psession, |
| TPMI_DH_OBJECT tpmKey, |
| TPM2B_MAX_BUFFER *salt, |
| TPMI_DH_ENTITY bind, |
| TPM2B_AUTH *bindAuth, |
| TPM2B_NONCE *nonceCaller, |
| TPM2B_ENCRYPTED_SECRET *encryptedSalt, |
| TPM2_SE sessionType, |
| TPMT_SYM_DEF *symmetric, |
| TPMI_ALG_HASH algId, |
| TSS2_TCTI_CONTEXT *tctiContext) |
| { |
| TSS2_RC rval; |
| SESSION *session, *tmp; |
| |
| if (psession == NULL) |
| return TSS2_SYS_RC_BAD_REFERENCE; |
| |
| session = calloc(1, sizeof(SESSION)); |
| |
| if (!session) |
| return TSS2_SYS_RC_GENERAL_FAILURE; |
| |
| session->bind = bind; |
| session->tpmKey = tpmKey; |
| CopySizedByteBuffer((TPM2B *)&session->nonceOlder, (TPM2B *)nonceCaller); |
| CopySizedByteBuffer((TPM2B *)&session->encryptedSalt, (TPM2B *)encryptedSalt); |
| session->sessionType = sessionType; |
| session->symmetric.algorithm = symmetric->algorithm; |
| session->symmetric.keyBits.sym = symmetric->keyBits.sym; |
| session->symmetric.mode.sym = symmetric->mode.sym; |
| session->authHash = algId; |
| if (bindAuth != NULL) |
| CopySizedByteBuffer((TPM2B *)&session->authValueBind, (TPM2B *)bindAuth); |
| |
| if (session->tpmKey != TPM2_RH_NULL) |
| CopySizedByteBuffer((TPM2B *)&session->salt, (TPM2B *)salt); |
| |
| rval = start_auth_session(session, tctiContext); |
| if (rval != TSS2_RC_SUCCESS) { |
| free(session); |
| return rval; |
| } |
| /* Make sure this session handle is not already in the table */ |
| HASH_FIND_INT(sessions, &session->sessionHandle, tmp); |
| if (tmp) |
| HASH_DEL(sessions, tmp); |
| |
| HASH_ADD_INT(sessions, sessionHandle, session); |
| *psession = session; |
| return TSS2_RC_SUCCESS; |
| } |
| |
| void end_auth_session(SESSION *session) |
| { |
| HASH_DEL(sessions, session); |
| free(session); |
| } |
| |
| void roll_nonces(SESSION *session, TPM2B_NONCE *new_nonce) |
| { |
| session->nonceOlder = session->nonceNewer; |
| session->nonceNewer = *new_nonce; |
| } |
| |
| TSS2_RC |
| tpm_calc_phash( |
| TSS2_SYS_CONTEXT *sysContext, |
| TPM2_HANDLE handle1, |
| TPM2_HANDLE handle2, |
| TPM2_HANDLE handle3, |
| TPMI_ALG_HASH authHash, |
| bool command, |
| TPM2B_DIGEST *pHash) |
| { |
| TSS2_RC rval = TPM2_RC_SUCCESS; |
| TSS2_TCTI_CONTEXT *tcti_context; |
| UINT32 i; |
| TPM2B_NAME name1, name2, name3; |
| TPM2B_MAX_BUFFER hashInput; |
| UINT8 *hashInputPtr; |
| size_t parametersSize; |
| const uint8_t *startParams; |
| TPM2_CC cmdCode; |
| |
| name1.size = 0; |
| name2.size = 0; |
| name3.size = 0; |
| hashInput.size = 0; |
| |
| rval = Tss2_Sys_GetTctiContext(sysContext, &tcti_context); |
| if (rval != TPM2_RC_SUCCESS) |
| return rval; |
| |
| if (command) { |
| rval = tpm_handle_to_name(tcti_context, handle1, &name1); |
| if (rval != TPM2_RC_SUCCESS) |
| return rval; |
| |
| rval = tpm_handle_to_name(tcti_context, handle2, &name2); |
| if (rval != TPM2_RC_SUCCESS) |
| return rval; |
| |
| rval = tpm_handle_to_name(tcti_context, handle3, &name3); |
| if (rval != TPM2_RC_SUCCESS) |
| return rval; |
| |
| rval = Tss2_Sys_GetCpBuffer(sysContext, ¶metersSize, &startParams); |
| if (rval != TPM2_RC_SUCCESS) |
| return rval; |
| } else { |
| rval = Tss2_Sys_GetRpBuffer(sysContext, ¶metersSize, &startParams); |
| if (rval != TPM2_RC_SUCCESS) |
| return rval; |
| |
| hashInputPtr = &(hashInput.buffer[hashInput.size]); |
| /* This is response code. Assuming 0 (success) */ |
| *(UINT32 *)hashInputPtr = 0; |
| hashInput.size += 4; |
| } |
| |
| rval = Tss2_Sys_GetCommandCode(sysContext, (UINT8 *)&cmdCode); |
| if (rval != TPM2_RC_SUCCESS) |
| return rval; |
| |
| hashInputPtr = &(hashInput.buffer[hashInput.size]); |
| *(UINT32 *)hashInputPtr = cmdCode; |
| hashInput.size += 4; |
| |
| rval = ConcatSizedByteBuffer(&hashInput, (TPM2B *)&name1); |
| if (rval != TPM2_RC_SUCCESS) |
| return rval; |
| |
| rval = ConcatSizedByteBuffer(&hashInput, (TPM2B *)&name2); |
| if (rval != TPM2_RC_SUCCESS) |
| return rval; |
| |
| rval = ConcatSizedByteBuffer(&hashInput, (TPM2B *)&name3); |
| if (rval != TPM2_RC_SUCCESS) |
| return rval; |
| |
| if (hashInput.size + parametersSize > sizeof(hashInput.buffer)) |
| return TSS2_SYS_RC_INSUFFICIENT_BUFFER; |
| |
| for(i = 0; i < parametersSize; i++) |
| hashInput.buffer[hashInput.size + i ] = startParams[i]; |
| |
| hashInput.size += (UINT16)parametersSize; |
| LOGBLOB_DEBUG(&hashInput.buffer[0], hashInput.size, "PHASH input bytes="); |
| |
| if (hashInput.size > sizeof(hashInput.buffer)) |
| return TSS2_SYS_RC_INSUFFICIENT_BUFFER; |
| |
| rval = hash(authHash, hashInput.buffer, hashInput.size, pHash); |
| if (rval != TPM2_RC_SUCCESS) |
| return rval; |
| |
| LOGBLOB_DEBUG(&pHash->buffer[0], pHash->size, "PHASH ="); |
| return rval; |
| } |
| |
| UINT32 tpm_handle_to_name( |
| TSS2_TCTI_CONTEXT *tcti_context, |
| TPM2_HANDLE handle, |
| TPM2B_NAME *name) |
| { |
| TSS2_RC rval; |
| TPM2B_NAME qualified_name = TPM2B_NAME_INIT; |
| TPM2B_PUBLIC public; |
| TPM2B_NV_PUBLIC nvPublic; |
| TSS2_SYS_CONTEXT *sysContext; |
| UINT8 *namePtr; |
| |
| if (!tcti_context || !name) |
| return TSS2_SYS_RC_BAD_VALUE; |
| |
| namePtr = name->name; |
| |
| if (handle == TPM2_RH_NULL) { |
| name->size = 0; |
| return TSS2_RC_SUCCESS; |
| } |
| |
| switch(handle >> TPM2_HR_SHIFT) |
| { |
| case TPM2_HT_NV_INDEX: |
| sysContext = sapi_init_from_tcti_ctx(tcti_context); |
| if (sysContext == NULL) |
| return TSS2_SYS_RC_GENERAL_FAILURE; |
| |
| nvPublic.size = 0; |
| rval = Tss2_Sys_NV_ReadPublic(sysContext, handle, 0, |
| &nvPublic, name, 0); |
| sapi_teardown(sysContext); |
| break; |
| |
| case TPM2_HT_TRANSIENT: |
| case TPM2_HT_PERSISTENT: |
| sysContext = sapi_init_from_tcti_ctx(tcti_context); |
| if (sysContext == NULL) |
| return TSS2_SYS_RC_GENERAL_FAILURE; |
| |
| public.size = 0; |
| rval = Tss2_Sys_ReadPublic(sysContext, handle, 0, |
| &public, name, &qualified_name, 0); |
| sapi_teardown(sysContext); |
| break; |
| |
| default: |
| rval = TPM2_RC_SUCCESS; |
| name->size = sizeof(TPM2_HANDLE); |
| *(TPM2_HANDLE *)namePtr = BE_TO_HOST_32(handle); |
| } |
| return rval; |
| } |
| |
| TSS2_RC |
| KDFa( |
| TPMI_ALG_HASH hash, |
| TPM2B *key, |
| const char *label, |
| TPM2B *contextU, |
| TPM2B *contextV, |
| UINT16 bits, |
| TPM2B_MAX_BUFFER *result_key) |
| { |
| TPM2B_DIGEST digest; |
| TPM2B_DIGEST tpm2blabel, tpm2bbits, tpm2bctr; |
| TPM2B_DIGEST *buffer_list[8]; |
| UINT32 counter; |
| TSS2_RC rval; |
| int i, j; |
| UINT16 bytes = bits / 8; |
| |
| result_key->size = 0; |
| tpm2bctr.size = 4; |
| tpm2bbits.size = 4; |
| counter = BE_TO_HOST_32(bits); |
| memcpy(tpm2bbits.buffer, &counter, 4); |
| tpm2blabel.size = strlen(label) + 1; |
| memcpy(tpm2blabel.buffer, label, tpm2blabel.size); |
| |
| LOG_DEBUG("KDFA, hash = %4.4x", hash); |
| LOGBLOB_DEBUG(&key->buffer[0], key->size, "KDFA, key ="); |
| LOGBLOB_DEBUG(&tpm2blabel.buffer[0], tpm2blabel.size, "KDFA, tpm2blabel ="); |
| LOGBLOB_DEBUG(&contextU->buffer[0], contextU->size, "KDFA, contextU ="); |
| LOGBLOB_DEBUG(&contextV->buffer[0], contextV->size, "KDFA, contextV ="); |
| |
| for (i = 1, j = 0; result_key->size < bytes; j = 0) { |
| counter = BE_TO_HOST_32(i++); |
| memcpy(tpm2bctr.buffer, &counter, 4); |
| buffer_list[j++] = (TPM2B_DIGEST *)&tpm2bctr; |
| buffer_list[j++] = (TPM2B_DIGEST *)&tpm2blabel; |
| buffer_list[j++] = (TPM2B_DIGEST *)contextU; |
| buffer_list[j++] = (TPM2B_DIGEST *)contextV; |
| buffer_list[j++] = (TPM2B_DIGEST *)&tpm2bbits; |
| buffer_list[j++] = NULL; |
| |
| for (j = 0; buffer_list[j] != NULL; j++) { |
| LOGBLOB_DEBUG(&buffer_list[j]->buffer[0], buffer_list[j]->size, "bufferlist[%d]:", j); |
| ; |
| } |
| |
| rval = hmac(hash, key->buffer, key->size, buffer_list, &digest); |
| if (rval != TPM2_RC_SUCCESS) { |
| LOGBLOB_ERROR(digest.buffer, digest.size, "HMAC Failed rval = %d", rval); |
| return rval; |
| } |
| |
| ConcatSizedByteBuffer(result_key, (TPM2B *)&digest); |
| } |
| |
| /* Truncate the result to the desired size. */ |
| result_key->size = bytes; |
| LOGBLOB_DEBUG(result_key->buffer, result_key->size, "KDFA, key = "); |
| return TPM2_RC_SUCCESS; |
| } |
| |
| static TSS2_RC |
| gen_session_key( |
| SESSION *session, |
| TPM2B_MAX_BUFFER *session_key, |
| TPM2B_IV *iv, |
| TPM2B_AUTH *auth_value) |
| { |
| TSS2_RC rval = TSS2_RC_SUCCESS; |
| UINT32 aes_block_size = 16; |
| TPM2B_MAX_BUFFER key, sessionValue; |
| |
| if (iv == NULL || session_key == NULL) |
| return TSS2_SYS_RC_BAD_VALUE; |
| |
| CopySizedByteBuffer((TPM2B *)&sessionValue, (TPM2B *)&session->sessionKey); |
| CatSizedByteBuffer((TPM2B *)&sessionValue, (TPM2B *)auth_value); |
| |
| rval = KDFa (session->authHash, |
| (TPM2B *)&sessionValue, |
| "CFB", |
| (TPM2B *)&session->nonceNewer, |
| (TPM2B *)&session->nonceOlder, |
| session->symmetric.keyBits.sym + aes_block_size * 8, |
| &key); |
| if (rval != TSS2_RC_SUCCESS) |
| return rval; |
| |
| if (key.size != (session->symmetric.keyBits.sym / 8) + aes_block_size) |
| return TSS2_SYS_RC_GENERAL_FAILURE; |
| |
| iv->size = aes_block_size; |
| session_key->size = (session->symmetric.keyBits.sym) / 8; |
| if (iv->size > sizeof (iv->buffer) || |
| (session_key->size + iv->size) > TPM2_MAX_DIGEST_BUFFER) |
| return TSS2_SYS_RC_GENERAL_FAILURE; |
| |
| memcpy (iv->buffer, &key.buffer[session_key->size], iv->size); |
| memcpy (session_key->buffer, key.buffer, session_key->size); |
| return rval; |
| } |
| |
| static TSS2_RC |
| encrypt_param_cfb( |
| SESSION *session, |
| TPM2B_MAX_BUFFER *encrypted_data, |
| TPM2B_MAX_BUFFER *clear_data, |
| TPM2B_AUTH *auth_value) |
| { |
| TSS2_RC rval = TSS2_RC_SUCCESS; |
| TPM2B_MAX_BUFFER encryptKey = TPM2B_MAX_BUFFER_INIT; |
| TPM2B_IV iv = TPM2B_IV_INIT; |
| |
| rval = gen_session_key(session, &encryptKey, &iv, auth_value); |
| if (rval) |
| return rval; |
| |
| return encrypt_cfb(encrypted_data, clear_data, &encryptKey, &iv); |
| } |
| |
| static TSS2_RC |
| decrypt_param_cfb( |
| SESSION *session, |
| TPM2B_MAX_BUFFER *clear_data, |
| TPM2B_MAX_BUFFER *encrypted_data, |
| TPM2B_AUTH *auth_value) |
| { |
| TSS2_RC rval = TSS2_RC_SUCCESS; |
| TPM2B_MAX_BUFFER encryptKey = TPM2B_MAX_BUFFER_INIT; |
| TPM2B_IV iv = TPM2B_IV_INIT; |
| |
| rval = gen_session_key(session, &encryptKey, &iv, auth_value); |
| if (rval) |
| return rval; |
| |
| return decrypt_cfb(clear_data, encrypted_data, &encryptKey, &iv); |
| } |
| |
| static TSS2_RC |
| encrypt_decrypt_xor( |
| SESSION *session, |
| TPM2B_MAX_BUFFER *output_data, |
| TPM2B_MAX_BUFFER *input_data, |
| TPM2B_AUTH *auth_value) |
| { |
| TSS2_RC rval = TSS2_RC_SUCCESS; |
| TPM2B_MAX_BUFFER key; |
| TPM2B_MAX_BUFFER mask = { .size = 0, .buffer = 0 }; |
| UINT16 i; |
| UINT16 size = input_data->size; |
| |
| if (size > TPM2_MAX_DIGEST_BUFFER) { |
| LOG_ERROR("Bad value for inputData size: %" PRIu16, size); |
| return TSS2_SYS_RC_GENERAL_FAILURE; |
| } |
| |
| CopySizedByteBuffer((TPM2B *)&key, (TPM2B *)&session->sessionKey); |
| CatSizedByteBuffer((TPM2B *)&key, (TPM2B *)auth_value); |
| |
| rval = KDFa(session->authHash, |
| (TPM2B *)&key, |
| "XOR", |
| (TPM2B *)&session->nonceNewer, |
| (TPM2B *)&session->nonceOlder, |
| input_data->size * 8, &mask); |
| |
| if (rval) |
| return rval; |
| |
| for (i = 0; i < size; i++) |
| output_data->buffer[i] = input_data->buffer[i] ^ mask.buffer[i]; |
| |
| output_data->size = size; |
| |
| return rval; |
| } |
| |
| TSS2_RC |
| encrypt_command_param( |
| SESSION *session, |
| TPM2B_MAX_BUFFER *encrypted_data, |
| TPM2B_MAX_BUFFER *clear_data, |
| TPM2B_AUTH *auth_value) |
| { |
| return session->symmetric.algorithm == TPM2_ALG_AES ? |
| encrypt_param_cfb(session, encrypted_data, clear_data, auth_value) : |
| encrypt_decrypt_xor(session, encrypted_data, clear_data, auth_value); |
| } |
| |
| TSS2_RC |
| decrypt_response_param( |
| SESSION *session, |
| TPM2B_MAX_BUFFER *clear_data, |
| TPM2B_MAX_BUFFER *encrypted_data, |
| TPM2B_AUTH *auth_value) |
| { |
| return session->symmetric.algorithm == TPM2_ALG_AES ? |
| decrypt_param_cfb(session, clear_data, encrypted_data, auth_value) : |
| encrypt_decrypt_xor(session, clear_data, encrypted_data, auth_value); |
| } |