From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- roms/skiboot/libstb/tss2/tssskiboot.c | 753 ++++++++++++++++++++++++++++++++++ 1 file changed, 753 insertions(+) create mode 100644 roms/skiboot/libstb/tss2/tssskiboot.c (limited to 'roms/skiboot/libstb/tss2/tssskiboot.c') diff --git a/roms/skiboot/libstb/tss2/tssskiboot.c b/roms/skiboot/libstb/tss2/tssskiboot.c new file mode 100644 index 000000000..b97159e73 --- /dev/null +++ b/roms/skiboot/libstb/tss2/tssskiboot.c @@ -0,0 +1,753 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* Copyright 2020 IBM Corp. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TSS_MAX_NV_BUFFER_SIZE 1024 + +/* + * Helper to string-fy TSS error response codes. + */ +static void tss_error_trace(const char *function, TPM_RC rc) +{ + const char *msg; + const char *submsg; + const char *num; + prlog(PR_ERR, "%s: failed, rc %08x\n", function, rc); + TSS_ResponseCode_toString(&msg, &submsg, &num, rc); + prlog(PR_ERR, "%s%s%s\n", msg, submsg, num); +} + +/* + * @brief Reads the public and name area of a NV Index. + * @param nv_index The target NV index to read public info from. + * @param nv_public buffer to save public are read from nv index + * @param nv_name buffer to save nv index name. + */ +int tss_nv_read_public(TPMI_RH_NV_INDEX nv_index, TPMS_NV_PUBLIC *nv_public, + TPM2B_NAME *nv_name) +{ + NV_ReadPublic_Out *out = NULL; + NV_ReadPublic_In *in = NULL; + TSS_CONTEXT *context = NULL; + TPM_RC rc = OPAL_SUCCESS; + + if (!nv_public || !nv_name) { + rc = OPAL_PARAMETER; + goto cleanup; + } + + in = zalloc(sizeof(NV_ReadPublic_In)); + if (!in) { + rc = OPAL_NO_MEM; + goto cleanup; + } + + out = zalloc(sizeof(NV_ReadPublic_Out)); + if (!out) { + rc = OPAL_NO_MEM; + goto cleanup; + } + + rc = TSS_Create(&context); + if (rc) { + tss_error_trace("tss_nv_read_public", rc); + rc = OPAL_NO_MEM; + goto cleanup; + } + + in->nvIndex = nv_index; + rc = TSS_Execute(context, + (RESPONSE_PARAMETERS *) out, + (COMMAND_PARAMETERS *) in, + NULL, + TPM_CC_NV_ReadPublic, + TPM_RH_NULL, NULL, 0); + if (!rc) { + memcpy(nv_public, &out->nvPublic, sizeof(TPMS_NV_PUBLIC)); + memcpy(nv_name, &out->nvName, sizeof(TPM2B_NAME)); + } + else + tss_error_trace("tss_nv_read_public", rc); +cleanup: + free(in); + free(out); + TSS_Delete(context); + return rc; +} + +/* @brief This command reads a value from an area previously defined using + * nv_define_space + * @param nv_index The target NV index to read from. + * @param buffer buffer to save the data read. + * @param buffer_size size of the buffer, to avoid overflow. + * @param offset position where to start the nv read operation. + */ +int tss_nv_read(TPMI_RH_NV_INDEX nv_index, void *buffer, + size_t buffer_size, uint16_t offset) +{ + TSS_CONTEXT *context = NULL; + NV_Read_Out *out = NULL; + NV_Read_In *in = NULL; + TPM_RC rc = OPAL_SUCCESS; + int64_t buffer_remaining; + + if (!buffer) { + rc = OPAL_PARAMETER; + goto cleanup; + } + + in = zalloc(sizeof(NV_Read_In)); + if (!in) { + rc = OPAL_NO_MEM; + goto cleanup; + } + + out = zalloc(sizeof(NV_Read_Out)); + if (!out) { + rc = OPAL_NO_MEM; + goto cleanup; + } + + rc = TSS_Create(&context); + if (rc) { + tss_error_trace("tss_nv_read", rc); + rc = OPAL_NO_MEM; + goto cleanup; + } + + in->nvIndex = nv_index; + in->authHandle = nv_index; + + buffer_remaining = buffer_size; + while (buffer_remaining > 0) { + in->offset = offset; + in->size = MIN(TSS_MAX_NV_BUFFER_SIZE, buffer_remaining); + + rc = TSS_Execute(context, + (RESPONSE_PARAMETERS *) out, + (COMMAND_PARAMETERS *) in, + NULL, + TPM_CC_NV_Read, + TPM_RS_PW, NULL, 0, + TPM_RH_NULL, NULL, 0); + + if (rc) { + tss_error_trace("tss_nv_read", rc); + goto cleanup; + } + + memcpy(buffer, out->data.b.buffer, in->size); + buffer += TSS_MAX_NV_BUFFER_SIZE; + buffer_remaining -= TSS_MAX_NV_BUFFER_SIZE; + offset += TSS_MAX_NV_BUFFER_SIZE; + } + +cleanup: + TSS_Delete(context); + free(in); + free(out); + return rc; +} + +/* @brief This command writes a value in an area previously defined using + * nv_define_space + * @param nv_index The target NV index to write to. + * @param buffer buffer containing the data write. + * @param buffer_size size of the buffer to write. + * @param offset position where to start the nv write operation. + */ +int tss_nv_write(TPMI_RH_NV_INDEX nv_index, void *buffer, + size_t buffer_size, uint16_t offset) +{ + TSS_CONTEXT *context = NULL; + NV_Write_In *in = NULL; + TPM_RC rc = OPAL_SUCCESS; + int64_t buffer_remaining; + + if (!buffer) { + rc = OPAL_PARAMETER; + goto cleanup; + } + + in = zalloc(sizeof(NV_Write_In)); + if (!in) { + rc = OPAL_NO_MEM; + goto cleanup; + } + + rc = TSS_Create(&context); + if (rc) { + tss_error_trace("tss_nv_write", rc); + rc = OPAL_NO_MEM; + goto cleanup; + } + + in->nvIndex = nv_index; + in->authHandle = TPM_RH_PLATFORM; + + buffer_remaining = buffer_size; + while (buffer_remaining > 0) { + in->offset = offset; + rc = TSS_TPM2B_Create(&in->data.b, buffer, + MIN(TSS_MAX_NV_BUFFER_SIZE, buffer_remaining), + sizeof(in->data.t.buffer)); + + if (rc) { + tss_error_trace("tss_nv_write", rc); + goto cleanup; + } + + rc = TSS_Execute(context, + NULL, + (COMMAND_PARAMETERS *) in, + NULL, + TPM_CC_NV_Write, + TPM_RS_PW, NULL, 0, + TPM_RH_NULL, NULL, 0); + if (rc) { + tss_error_trace("tss_nv_write", rc); + goto cleanup; + } + + buffer += TSS_MAX_NV_BUFFER_SIZE; + buffer_remaining -= TSS_MAX_NV_BUFFER_SIZE; + offset += TSS_MAX_NV_BUFFER_SIZE; + } + +cleanup: + TSS_Delete(context); + free(in); + return rc; +} + +/* + * @brief This command locks an area, pointed by the index and previously + * defined using nv_define_space, preventing further writing operations on it. + * @param nv_index The target NV index to lock. + */ +int tss_nv_write_lock(TPMI_RH_NV_INDEX nv_index) +{ + TSS_CONTEXT *context = NULL; + NV_WriteLock_In *in = NULL; + TPM_RC rc = OPAL_SUCCESS; + + in = zalloc(sizeof(NV_WriteLock_In)); + if (!in) { + rc = OPAL_NO_MEM; + goto cleanup; + } + + rc = TSS_Create(&context); + if (rc) { + rc = OPAL_NO_MEM; + goto cleanup; + } + + in->authHandle = TPM_RH_PLATFORM; + in->nvIndex = nv_index; + rc = TSS_Execute(context, + NULL, + (COMMAND_PARAMETERS *) in, + NULL, + TPM_CC_NV_WriteLock, + TPM_RS_PW, NULL, 0, + TPM_RH_NULL, NULL, 0); + if (rc) + tss_error_trace("tss_nv_write_lock", rc); +cleanup: + TSS_Delete(context); + free(in); + return rc; +} + + /* + * @brief This command defines the area pointed by nv index and its attributes. + * @param nv_index The target NV index to define. + * @param data_size size of the area to be defined. + */ +int tss_nv_define_space(TPMI_RH_NV_INDEX nv_index, uint16_t data_size) +{ + NV_DefineSpace_In *in = NULL; + TSS_CONTEXT *context = NULL; + TPM_RC rc = OPAL_SUCCESS; + + in = zalloc(sizeof(NV_DefineSpace_In)); + if (!in) { + rc = OPAL_NO_MEM; + goto cleanup; + } + + rc = TSS_Create(&context); + if (rc) { + rc = OPAL_NO_MEM; + goto cleanup; + } + + in->authHandle = TPM_RH_PLATFORM; + + in->publicInfo.nvPublic.nvIndex = nv_index; + in->publicInfo.nvPublic.dataSize = data_size; + /* password is NULL so b.size is 0 */ + in->auth.b.size = 0; + /* Empty policy, so size is 0 */ + in->publicInfo.nvPublic.authPolicy.t.size = 0; + /* Used algorithm is SHA256 */ + in->publicInfo.nvPublic.nameAlg = TPM_ALG_SHA256; + /* + * This carries the flags set according to default settings, excepting + * for what is set by this function parameters. Further customization + * will require a different setup for nvAttribute flags as is done in + * TSS's code. + */ + in->publicInfo.nvPublic.attributes.val = (TPMA_NVA_PPWRITE | + TPMA_NVA_ORDINARY | + TPMA_NVA_WRITE_STCLEAR | + TPMA_NVA_AUTHREAD | + TPMA_NVA_PLATFORMCREATE | + TPMA_NVA_NO_DA); + + rc = TSS_Execute(context, + NULL, + (COMMAND_PARAMETERS *)in, + NULL, + TPM_CC_NV_DefineSpace, + TPM_RS_PW, NULL, 0, + TPM_RH_NULL, NULL, 0); + if (rc) { + tss_error_trace("tss_nv_define_space", rc); + switch(rc) { + case TPM_RC_NV_DEFINED: + rc = OPAL_WRONG_STATE; + break; + default: + break; + } + } +cleanup: + TSS_Delete(context); + free(in); + return rc; +} + +/* + * @brief Extends a PCR using the given hashes and digest + * @param pcr_handle The PCR to be extended + * @param alg_hashes A pointer to an array of hash algorithms, each + * one used to extend its respective PCR bank. + * @param alg_hash_count The number of elements in alg_hashes array + * @param digests The digest data. + */ +int tss_pcr_extend(TPMI_DH_PCR pcr_handle, TPMI_ALG_HASH *alg_hashes, + uint8_t alg_hash_count, const uint8_t **digests) +{ + TSS_CONTEXT *context = NULL; + uint32_t rc = OPAL_SUCCESS; + PCR_Extend_In *in = NULL; + uint16_t digest_size; + + if (!alg_hashes || !digests || pcr_handle >= IMPLEMENTATION_PCR) { + rc = OPAL_PARAMETER; + goto cleanup; + } + + in = zalloc(sizeof(PCR_Extend_In)); + if (!in) { + rc = OPAL_NO_MEM; + goto cleanup; + } + + rc = TSS_Create(&context); + if (rc) { + tss_error_trace("tss_pcr_extend", rc); + rc = OPAL_NO_MEM; + goto cleanup; + } + + if (alg_hash_count >= HASH_COUNT) { + rc = OPAL_PARAMETER; + goto cleanup; + } + + in->digests.count = alg_hash_count; + in->pcrHandle = pcr_handle; + for (uint8_t i=0; i < alg_hash_count; i++) { + in->digests.digests[i].hashAlg = alg_hashes[i]; + /* memset zeroes first to assure the digest data is zero + * padded.*/ + memset((uint8_t*) &in->digests.digests[i].digest, 0, + sizeof(TPMU_HA)); + + digest_size = 0; + /* Marshal the digest in order to obtain its size. This is a + * commonly used pattern in TSS. + */ + rc = TSS_TPMU_HA_Marshalu((const TPMU_HA *)digests[i], + &digest_size, NULL, NULL , + alg_hashes[i]); + if (rc) + goto cleanup; + memcpy((uint8_t*) &in->digests.digests[i].digest, digests[i], + digest_size); + } + rc = TSS_Execute(context, + NULL, + (COMMAND_PARAMETERS *) in, + NULL, + TPM_CC_PCR_Extend, + TPM_RS_PW, NULL, 0, + TPM_RH_NULL, NULL, 0); + if (rc) + tss_error_trace("tss_pcr_extend", rc); +cleanup: + TSS_Delete(context); + free(in); + return rc; +} + +/* + * @brief reads pcr values of a given pcr handle. + * @param pcr_handle The PCR to be extended + * @param alg_hashes A pointer to an array of hash algorithms, each + * one used to extend its respective PCR bank. + * @param alg_hash_count The length of alg hashes array + */ +int tss_pcr_read(TPMI_DH_PCR pcr_handle, TPMI_ALG_HASH *alg_hashes, + uint8_t alg_hash_count) +{ + TSS_CONTEXT *context = NULL; + PCR_Read_Out *out = NULL; + PCR_Read_In *in = NULL; + uint32_t rc = OPAL_SUCCESS; + + if (!alg_hashes) { + rc = OPAL_PARAMETER; + goto cleanup; + } + + in = zalloc(sizeof(PCR_Read_In)); + if (!in) { + rc = OPAL_NO_MEM; + goto cleanup; + } + + out = zalloc(sizeof(PCR_Read_Out)); + if (!out) { + rc = OPAL_NO_MEM; + goto cleanup; + } + + rc = TSS_Create(&context); + if (!rc) { + tss_error_trace("tss_pcr_read", rc); + rc = OPAL_NO_MEM; + goto cleanup; + } + + in->pcrSelectionIn.count = alg_hash_count; + for (int i=0; i < alg_hash_count; i++) { + in->pcrSelectionIn.pcrSelections[i].hash = alg_hashes[i]; + in->pcrSelectionIn.pcrSelections[i].sizeofSelect = 3; + in->pcrSelectionIn.pcrSelections[i].pcrSelect[0] = 0; + in->pcrSelectionIn.pcrSelections[i].pcrSelect[1] = 0; + in->pcrSelectionIn.pcrSelections[i].pcrSelect[2] = 0; + in->pcrSelectionIn.pcrSelections[i].pcrSelect[pcr_handle/8] = 1 << (pcr_handle % 8); + } + + rc = TSS_Execute(context, + (RESPONSE_PARAMETERS *) out, + (COMMAND_PARAMETERS *) in, + NULL, + TPM_CC_PCR_Read, + TPM_RH_NULL, NULL, 0); + if (rc) + tss_error_trace("tss_pcr_read", rc); +cleanup: + TSS_Delete(context); + free(in); + free(out); + return rc; +} + +/* + * @brief returns next bytes_requested bytes from the TPM RNG + * @param buffer Buffer to save the generated numbers. + * @param bytes_requested How many random bytes are requested. + */ +int tss_get_random_number(void *buffer, uint16_t bytes_requested) +{ + TSS_CONTEXT *context = NULL; + GetRandom_Out *out = NULL; + TPM_RC rc = OPAL_SUCCESS; + GetRandom_In *in = NULL; + void *p_buffer = buffer; + + if (!buffer) { + rc = OPAL_PARAMETER; + goto cleanup; + } + + in = zalloc(sizeof(GetRandom_In)); + if (!in) { + rc = OPAL_NO_MEM; + goto cleanup; + } + + out = zalloc(sizeof(GetRandom_Out)); + if (!out) { + rc = OPAL_NO_MEM; + goto cleanup; + } + + rc = TSS_Create(&context); + if (rc) { + tss_error_trace("tss_get_random_number", rc); + rc = OPAL_NO_MEM; + goto cleanup; + } + + /* + * Even though we request a specific number of bytes, there is no + * guarantee that TPM will return that number of bytes, so we ask again + * until we reach the desired total of bytes or rng function fails + */ + for (uint16_t bytes_copied = 0; bytes_copied < bytes_requested; ) { + in->bytesRequested = bytes_requested - bytes_copied; + rc = TSS_Execute(context, + (RESPONSE_PARAMETERS *)out, + (COMMAND_PARAMETERS *)in, + NULL, TPM_CC_GetRandom, + TPM_RH_NULL, NULL, 0); + if (!rc){ + memcpy(p_buffer, out->randomBytes.t.buffer, + out->randomBytes.t.size); + bytes_copied += out->randomBytes.t.size; + p_buffer += bytes_copied; + /* explicitly clean up output's buffer from memory on + * every iteration, since the size will vary, to avoid + * some kind of exploitation. + */ + memset(out->randomBytes.t.buffer, 0, + out->randomBytes.t.size); + + } + else { + tss_error_trace("tss_get_random_number", rc); + break; + } + } + +cleanup: + TSS_Delete(context); + free(in); + free(out); + return rc; +} + +/* local helper to generate random password without zeroes */ +static int generate_random_passwd(char *passwd, uint16_t passwd_len) +{ + TPM_RC rc = OPAL_SUCCESS; + char *buffer = NULL; + int bytes_copied; + int i; + + buffer = zalloc(passwd_len); + if (!buffer) { + rc = OPAL_NO_MEM; + goto cleanup; + } + + bytes_copied = 0; + while ((rc == 0) && (bytes_copied < passwd_len)) { + rc = tss_get_random_number(buffer, passwd_len); + if (rc) + goto cleanup; + + /* Copy as many bytes as were received or until bytes requested */ + for (i = 0; (i < passwd_len) && + (bytes_copied < passwd_len); i++) { + + /* Skip zero bytes */ + if (buffer[i] == 0) + continue; + passwd[bytes_copied] = buffer[i]; + bytes_copied++; + } + } +cleanup: + free(buffer); + return rc; +} + +/* + * @brief This command allows the authorization secret for a hierarchy to be + * changed. + */ +int tss_set_platform_auth(void) +{ + HierarchyChangeAuth_In *in = NULL; + TSS_CONTEXT *context = NULL; + TPM_RC rc = OPAL_SUCCESS; + char *key_passwd = NULL; + + in = zalloc(sizeof(HierarchyChangeAuth_In)); + if (!in) { + rc = OPAL_NO_MEM; + goto cleanup; + } + + key_passwd = zalloc(TSS_AUTH_PASSWD_LEN + 1); + if (!key_passwd) { + rc = OPAL_NO_MEM; + goto cleanup; + } + + rc = TSS_Create(&context); + if (rc) { + tss_error_trace("tss_set_platform_auth", rc); + rc = OPAL_NO_MEM; + goto cleanup; + } + + rc = generate_random_passwd(key_passwd, TSS_AUTH_PASSWD_LEN); + if (rc) { + tss_error_trace("Failed to generate the auth password", rc); + goto cleanup; + } + key_passwd[TSS_AUTH_PASSWD_LEN] = 0; + + in->authHandle = TPM_RH_PLATFORM; + rc = TSS_TPM2B_StringCopy(&in->newAuth.b, key_passwd, + sizeof(in->newAuth.t.buffer)); + if (rc) { + tss_error_trace("tss_set_platform_auth", rc); + goto cleanup; + } + + rc = TSS_Execute(context, + NULL, + (COMMAND_PARAMETERS *)in, + NULL, + TPM_CC_HierarchyChangeAuth, + TPM_RS_PW, NULL, 0, + TPM_RH_NULL, NULL, 0); + if (rc) + tss_error_trace("tss_set_platform_auth", rc); + +cleanup: + TSS_Delete(context); + free(in); + /* explicitly clean up password from memory to avoid some kind of + * exploitation. + */ + memset(key_passwd, 0, TSS_AUTH_PASSWD_LEN + 1); + free(key_passwd); + return rc; +} + +/* + * @brief returns a list of defined NV indices + * @param pcr_handle The PCR to be extended + * @param alg_hashes A pointer to an array of hash algorithms, each + * one used to extend its respective PCR bank. + * @param alg_hash_count The length of alg hashes array + */ +int tss_get_defined_nv_indices(TPMI_RH_NV_INDEX **indices, size_t *count) +{ + TSS_CONTEXT *context = NULL; + GetCapability_In *in = NULL; + GetCapability_Out *out = NULL; + uint32_t rc = OPAL_SUCCESS; + TPML_HANDLE *handles; + + in = zalloc(sizeof(GetCapability_In)); + if (!in) { + rc = OPAL_NO_MEM; + goto cleanup; + } + + out = zalloc(sizeof(GetCapability_Out)); + if (!out) { + rc = OPAL_NO_MEM; + goto cleanup; + } + + rc = TSS_Create(&context); + if (rc) { + tss_error_trace("tss_check_nv_index", rc); + rc = OPAL_NO_MEM; + goto cleanup; + } + + in->capability = 1; + in->property = 0x01000000; + in->propertyCount = 64; + + rc = TSS_Execute(context, + (RESPONSE_PARAMETERS *) out, + (COMMAND_PARAMETERS *) in, + NULL, + TPM_CC_GetCapability, + TPM_RH_NULL, NULL, 0); + if (rc) { + tss_error_trace("tss_check_nv_index", rc); + goto cleanup; + } + + handles = (TPML_HANDLE *) &out->capabilityData.data; + *count = handles->count; + *indices = malloc(*count * sizeof(TPMI_RH_NV_INDEX)); + if (!indices) { + rc = OPAL_NO_MEM; + goto cleanup; + } + + memcpy(*indices, handles->handle, *count * sizeof(TPMI_RH_NV_INDEX)); + +cleanup: + TSS_Delete(context); + free(in); + free(out); + return rc; +} + + +int tss_nv_undefine_space(TPMI_RH_NV_INDEX nv_index) +{ + int rc; + TSS_CONTEXT *context = NULL; + NV_UndefineSpace_In in; + + rc = TSS_Create(&context); + if (rc) { + tss_error_trace("tss_check_nv_undefine_index", rc); + rc = OPAL_NO_MEM; + return rc; + } + + in.authHandle = TPM_RH_PLATFORM; + in.nvIndex = nv_index; + + rc = TSS_Execute(context, NULL, + (COMMAND_PARAMETERS *) &in, + NULL, + TPM_CC_NV_UndefineSpace, + TPM_RS_PW, NULL, 0, + TPM_RH_NULL, NULL, 0); + if (rc) + tss_error_trace("tss_check_nv_index", rc); + + TSS_Delete(context); + return rc; +} -- cgit 1.2.3-korg