| /******************************************************************************* |
| * Copyright 2017, Fraunhofer SIT sponsored by Infineon Technologies AG |
| * 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 "tss2_esys.h" |
| #include "esys_mu.h" |
| |
| #include "esys_iutil.h" |
| #define LOGMODULE esys |
| #include "util/log.h" |
| |
| /** Serialization of an ESYS_TR into a byte buffer. |
| * |
| * Serialize the metadata of an ESYS_TR object into a byte buffer such that it |
| * can be stored on disk for later use by a different program or context. |
| * The serialized object can be deserialized suing Esys_TR_Deserialize. |
| * @param esys_context [INOUT] The ESYS_CONTEXT. |
| * @param esys_handle [IN] The ESYS_TR object to serialize. |
| * @param buffer [OUT] The buffer containing the serialized metadata. (caller-callocated) Shall be free'd using free(). |
| * @param buffer_size [OUT] The size of the buffer parameter. |
| * @retval TSS2_RC_SUCCESS on Success. |
| * @retval TSS2_RC_ESYS_GENERAL_FAILURE On Failure. |
| */ |
| TSS2_RC |
| Esys_TR_Serialize(ESYS_CONTEXT * esys_context, |
| ESYS_TR esys_handle, uint8_t ** buffer, size_t * buffer_size) |
| { |
| TSS2_RC r = TSS2_RC_SUCCESS; |
| RSRC_NODE_T *esys_object; |
| size_t offset = 0; |
| *buffer_size = 0; |
| |
| r = esys_GetResourceObject(esys_context, esys_handle, &esys_object); |
| return_if_error(r, "Get resource object"); |
| |
| r = Tss2_MU_IESYS_RESOURCE_Marshal(&esys_object->rsrc, NULL, SIZE_MAX, |
| buffer_size); |
| return_if_error(r, "Marshal resource object"); |
| |
| *buffer = malloc(*buffer_size); |
| return_if_null(*buffer, "Buffer could not be allocated", |
| TSS2_ESYS_RC_MEMORY); |
| |
| r = Tss2_MU_IESYS_RESOURCE_Marshal(&esys_object->rsrc, *buffer, |
| *buffer_size, &offset); |
| return_if_error(r, "Marshal resource object"); |
| |
| return TSS2_RC_SUCCESS; |
| }; |
| |
| /** Deserialization of an ESYS_TR from a byte buffer. |
| * |
| * Deserialize the metadata of an ESYS_TR object from a byte buffer that was |
| * stored on disk for later use by a different program or context. |
| * An object can be serialized suing Esys_TR_Serialize. |
| * @param esys_context [INOUT] The ESYS_CONTEXT. |
| * @param esys_handle [IN] The ESYS_TR object to serialize. |
| * @param buffer [OUT] The buffer containing the serialized metadata. (caller-callocated) Shall be free'd using free(). |
| * @param buffer_size [OUT] The size of the buffer parameter. |
| * @retval TSS2_RC_SUCCESS on Success \todo Add error RCs. |
| * @retval TSS2_RC_ESYS_GENERAL_FAILURE On Failure. |
| */ |
| TSS2_RC |
| Esys_TR_Deserialize(ESYS_CONTEXT * esys_context, |
| uint8_t const *buffer, |
| size_t buffer_size, ESYS_TR * esys_handle) |
| { |
| TSS2_RC r = TSS2_RC_SUCCESS; |
| RSRC_NODE_T *esys_object; |
| size_t offset = 0; |
| |
| r = esys_CreateResourceObject(esys_context, *esys_handle, &esys_object); |
| return_if_error(r, "Get resource object"); |
| |
| r = Tss2_MU_IESYS_RESOURCE_Unmarshal(buffer, buffer_size, &offset, |
| &esys_object->rsrc); |
| return_if_error(r, "Unmarshal resource object"); |
| |
| return TSS2_RC_SUCCESS; |
| } |
| |
| /** Start syncrounous creation of an ESYS_TR object from TPM metadata. |
| * |
| * This function starts the asynchronous retrieval of metadata from the TPM in |
| * order to create a new ESYS_TR object. |
| * @see Esys_TR_FromTPMPublic for more infomration |
| */ |
| TSS2_RC |
| Esys_TR_FromTPMPublic_Async(ESYS_CONTEXT * esys_context, |
| TPM2_HANDLE tpm_handle, |
| ESYS_TR shandle1, |
| ESYS_TR shandle2, ESYS_TR shandle3) |
| { |
| TSS2_RC r; |
| ESYS_TR esys_handle = esys_context->esys_handle_cnt++; |
| RSRC_NODE_T *esysHandleNode = NULL; |
| r = esys_CreateResourceObject(esys_context, esys_handle, &esysHandleNode); |
| goto_if_error(r, "Error create resource", error_cleanup); |
| |
| esysHandleNode->rsrc.handle = tpm_handle; |
| esys_context->esys_handle = esys_handle; |
| |
| if (tpm_handle >= TPM2_NV_INDEX_FIRST && tpm_handle <= TPM2_NV_INDEX_LAST) { |
| esys_context->in.NV_ReadPublic.nvIndex = esys_handle; |
| r = Esys_NV_ReadPublic_async(esys_context, esys_handle, shandle1, |
| shandle2, shandle3); |
| goto_if_error(r, "Error NV_ReadPublic", error_cleanup); |
| |
| } else { |
| esys_context->in.ReadPublic.objectHandle = esys_handle; |
| r = Esys_ReadPublic_async(esys_context, esys_handle, shandle1, shandle2, |
| shandle3); |
| goto_if_error(r, "Error ReadPublic", error_cleanup); |
| } |
| return r; |
| error_cleanup: |
| Esys_TR_Close(esys_context, &esys_handle); |
| return r; |
| } |
| |
| /** Finish asyncrounous creation of an ESYS_TR object from TPM metadata. |
| * This function finishes the asynchronous retrieval of metadata from the TPM in |
| * order to create a new ESYS_TR object. |
| * @see Esys_TR_FromTPMPublic for more infomration |
| */ |
| TSS2_RC |
| Esys_TR_FromTPMPublic_Finish(ESYS_CONTEXT * esys_context, ESYS_TR * esys_handle) |
| { |
| TSS2_RC r = TSS2_RC_SUCCESS; |
| ESYS_TR objectHandle = esys_context->esys_handle; |
| RSRC_NODE_T *objectHandleNode; |
| |
| r = esys_GetResourceObject(esys_context, objectHandle, &objectHandleNode); |
| goto_if_error(r, "get resource", error_cleanup); |
| |
| if (objectHandleNode->rsrc.handle >= TPM2_NV_INDEX_FIRST |
| && objectHandleNode->rsrc.handle <= TPM2_NV_INDEX_LAST) { |
| TPM2B_NV_PUBLIC *nvPublic; |
| TPM2B_NAME *nvName; |
| r = Esys_NV_ReadPublic_finish(esys_context, &nvPublic, &nvName); |
| goto_if_error(r, "Error NV_ReadPublic", error_cleanup); |
| |
| objectHandleNode->rsrc.rsrcType = IESYSC_NV_RSRC; |
| objectHandleNode->rsrc.name = *nvName; |
| objectHandleNode->rsrc.misc.rsrc_nv_pub = *nvPublic; |
| SAFE_FREE(nvPublic); |
| SAFE_FREE(nvName); |
| } else { |
| TPM2B_PUBLIC *public; |
| TPM2B_NAME *name = NULL; |
| TPM2B_NAME *qualifiedName = NULL; |
| r = Esys_ReadPublic_finish(esys_context, &public, &name, |
| &qualifiedName); |
| goto_if_error(r, "Error ReadPublic", error_cleanup); |
| |
| objectHandleNode->rsrc.rsrcType = IESYSC_KEY_RSRC; |
| objectHandleNode->rsrc.name = *name; |
| objectHandleNode->rsrc.misc.rsrc_key_pub = *public; |
| SAFE_FREE(public); |
| SAFE_FREE(name); |
| SAFE_FREE(qualifiedName); |
| } |
| *esys_handle = objectHandle; |
| return TSS2_RC_SUCCESS; |
| |
| error_cleanup: |
| Esys_TR_Close(esys_context, &objectHandle); |
| return r; |
| } |
| |
| /** Creation of an ESYS_TR object from TPM metadata. |
| * |
| * This function can be used to create ESYS_TR object for Tpm Resouces that are |
| * not created or loaded (e.g. using ESys_CreatePrimary or ESys_Load) but |
| * pre-exist inside the TPM. Examples are NV-Indices or persistent object. |
| * |
| * Note: For PCRs and hierarchies, please use the global ESYS_TR identifiers. |
| * Note: If a session is provided the TPM is queried for the metadata twice. |
| * First without a session to retrieve some metadata then with the session where |
| * this metadata is used in the session HMAC calculation and thereby verified. |
| * |
| * Since man in the middle attacks should be prevented as much as possible it is |
| * recommended to pass a session. |
| * @param esys_context [INOUT] The ESYS_CONTEXT |
| * @param tpm_handle [IN] The handle of the TPM object to represent as ESYS_TR. |
| * @param shandle1 [INOUT] A session for securing the TPM command (optional). |
| * @param shandle2 [INOUT] A session for securing the TPM command (optional). |
| * @param shandle3 [INOUT] A session for securing the TPM command (optional). |
| * @param object [OUT] The newly created ESYS_TR metadata object. |
| * @retval TSS2_RC_SUCCESS on Success \todo Add error RCs. |
| */ |
| TSS2_RC |
| Esys_TR_FromTPMPublic(ESYS_CONTEXT * esys_context, |
| TPM2_HANDLE tpm_handle, |
| ESYS_TR shandle1, |
| ESYS_TR shandle2, ESYS_TR shandle3, ESYS_TR * object) |
| { |
| TSS2_RC r; |
| r = Esys_TR_FromTPMPublic_Async(esys_context, shandle1, shandle2, shandle3, |
| tpm_handle); |
| goto_if_error(r, "Error TR FromTPMPublic", error_cleanup); |
| |
| r = Esys_TR_FromTPMPublic_Finish(esys_context, object); |
| goto_if_error(r, "Error TR FromTPMPublic", error_cleanup); |
| |
| return r; |
| error_cleanup: |
| return r; |
| } |
| |
| /** Close an ESYS_TR without removing it from the TPM. |
| * |
| * This function deletes an ESYS_TR object from an ESYS_CONTEXT without deleting |
| * it from the TPM. This is useful for NV-Indices or persistent keys, after |
| * Esys_TR_Serialize has been called. Transient objects should be deleted using |
| * Esys_FlushContext. |
| * @param esys_context [INOUT] The ESYS_CONTEXT |
| * @param object [OUT] ESYS_TR metadata object to be deleted from ESYS_CONTEXT. |
| * @retval TSS2_RC_SUCCESS on Success \todo Add error RCs. |
| */ |
| TSS2_RC |
| Esys_TR_Close(ESYS_CONTEXT * esys_context, ESYS_TR * object) |
| { |
| RSRC_NODE_T *node; |
| RSRC_NODE_T **update_ptr; |
| for (node = esys_context->rsrc_list, |
| update_ptr = &esys_context->rsrc_list; |
| node != NULL; |
| update_ptr = &node->next, node = node->next) { |
| if (node->esys_handle == *object) { |
| *update_ptr = node->next; |
| SAFE_FREE(node); |
| *object = ESYS_TR_NONE; |
| return TSS2_RC_SUCCESS; |
| } |
| } |
| LOG_ERROR("Error: Esys handle does not exist (%x).", TSS2_ESYS_RC_BAD_TR); |
| return TSS2_ESYS_RC_BAD_TR; |
| } |
| |
| /** Set the authorization value of an ESYS_TR. |
| * |
| * Authorization values are associated with ESYS_TR Tpm Resource object. They |
| * are then picked up whenever an authorization is needed. |
| * |
| * Note: The authorization value is not stored in the metadata during |
| * Esys_TR_Serialize. Therefor Esys_TR_SetAuth needs to be called again after |
| * every Esys_TR_Deserialize. |
| * @param esys_context [INOUT] The ESYS_CONTEXT. |
| * @param esys_handle [INOUT] The ESYS_TR for which to set the auth value. |
| * @param authValue [IN] The auth value to set for the ESYS_TR. |
| * @retval TSS2_RC_SUCCESS on Success \todo Add error RCs. |
| */ |
| TSS2_RC |
| Esys_TR_SetAuth(ESYS_CONTEXT * esys_context, ESYS_TR esys_handle, |
| TPM2B_AUTH const *authValue) |
| { |
| RSRC_NODE_T *esys_object; |
| TSS2_RC r; |
| r = esys_GetResourceObject(esys_context, esys_handle, &esys_object); |
| if (r != TPM2_RC_SUCCESS) |
| return r; |
| esys_object->auth = *authValue; |
| return TSS2_RC_SUCCESS; |
| } |
| |
| /** Retrieve the TPM public name of an Esys_TR object. |
| * |
| * Some operations (i.e. Esys_PolicyNameHash) require the name of a TPM object |
| * to be passed. Esys_TR_GetName provides this name to the caller. |
| * @param esys_context [INOUT] The ESYS_CONTEXT. |
| * @param esys_handle [INOUT] The ESYS_TR for which to retrieve the name. |
| * @param name [OUT] The name of the object (caller-allocated; use free()). |
| * @retval TSS2_RC_SUCCESS on Success \todo Add error RCs. |
| */ |
| TSS2_RC |
| Esys_TR_GetName(ESYS_CONTEXT * esys_context, ESYS_TR esys_handle, |
| TPM2B_NAME ** name) |
| { |
| RSRC_NODE_T *esys_object; |
| TSS2_RC r = esys_GetResourceObject(esys_context, esys_handle, &esys_object); |
| return_if_error(r, "Object not found"); |
| |
| *name = malloc(sizeof(TPM2B_NAME)); |
| if (*name == NULL) { |
| LOG_ERROR("Error: out of memory"); |
| return TSS2_ESYS_RC_MEMORY; |
| } |
| if (esys_object->rsrc.rsrcType == IESYSC_KEY_RSRC) { |
| r = iesys_get_name(&esys_object->rsrc.misc.rsrc_key_pub, *name); |
| goto_if_error(r, "Error get name", error_cleanup); |
| |
| } else { |
| if (esys_object->rsrc.rsrcType == IESYSC_NV_RSRC) { |
| r = iesys_nv_get_name(&esys_object->rsrc.misc.rsrc_nv_pub, *name); |
| goto_if_error(r, "Error get name", error_cleanup); |
| |
| } else { |
| size_t offset = 0; |
| Tss2_MU_TPM2_HANDLE_Marshal(esys_object->rsrc.handle, |
| &(*name)->name[0], sizeof(TPM2_HANDLE), |
| &offset); |
| (*name)->size = offset; |
| } |
| } |
| return r; |
| error_cleanup: |
| SAFE_FREE(name); |
| return r; |
| } |
| |
| |
| /** Retrieve the Session Attributes of the ESYS_TR session. |
| * |
| * Sessions possess attributes, such as whether they shall continue of be |
| * flushed after the next command, or whether they are used to encrypt |
| * parameters. |
| * Note: this function only applies to ESYS_TR objects that represent sessions. |
| * @param esys_context [INOUT] The ESYS_CONTEXT. |
| * @param esys_handle [INOUT] The ESYS_TR of the session. |
| * @param flags [OUT] The attributes of the session. |
| * @retval TSS2_RC_SUCCESS on Success \todo Add error RCs. |
| */ |
| TSS2_RC |
| Esys_TRSess_GetAttributes(ESYS_CONTEXT * esys_context, ESYS_TR esys_handle, |
| TPMA_SESSION * flags) |
| { |
| RSRC_NODE_T *esys_object; |
| TSS2_RC r = esys_GetResourceObject(esys_context, esys_handle, &esys_object); |
| return_if_error(r, "Object not found"); |
| |
| if (esys_object->rsrc.rsrcType != IESYSC_SESSION_RSRC) |
| return_error(TSS2_ESYS_RC_BAD_TR, "Object is not a session object"); |
| *flags = esys_object->rsrc.misc.rsrc_session.sessionAttributes; |
| return TSS2_RC_SUCCESS; |
| } |
| |
| /** Set session attributes |
| * |
| * Set or unset a session's attributes according to the provieded flags and mask. |
| * @verbatim new_attributes = old_attributes & ~mask | flags & mask @endverbatim |
| * Note: this function only applies to ESYS_TR objects that represent sessions. |
| * @param esys_context [INOUT] The ESYS_CONTEXT. |
| * @param esys_handle [INOUT] The ESYS_TR of the session. |
| * @param flags [IN] The flags to be set or unset for the session. |
| * @param mask [IN] The mask for the flags to be set or unset. |
| * @retval TSS2_RC_SUCCESS on Success \todo Add error RCs. |
| */ |
| TSS2_RC |
| Esys_TRSess_SetAttributes(ESYS_CONTEXT * esys_context, ESYS_TR esys_handle, |
| TPMA_SESSION flags, TPMA_SESSION mask) |
| { |
| RSRC_NODE_T *esys_object; |
| TSS2_RC r = esys_GetResourceObject(esys_context, esys_handle, &esys_object); |
| return_if_error(r, "Object not found"); |
| |
| if (esys_object->rsrc.rsrcType != IESYSC_SESSION_RSRC) |
| return_error(TSS2_ESYS_RC_BAD_TR, "Object is not a session object"); |
| esys_object->rsrc.misc.rsrc_session.sessionAttributes = |
| (esys_object->rsrc.misc.rsrc_session. |
| sessionAttributes & ~mask) | (flags & mask); |
| return TSS2_RC_SUCCESS; |
| } |