rev180: Add VendorInfo.c and use its functions

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
This commit is contained in:
Stefan Berger 2023-12-12 21:14:45 -05:00 committed by Stefan Berger
parent 26bb7d87d2
commit 6dcb416ddf
9 changed files with 243 additions and 177 deletions

View File

@ -274,6 +274,7 @@ libtpms_tpm2_la_SOURCES = \
tpm2/TpmFail.c \ tpm2/TpmFail.c \
tpm2/Unique.c \ tpm2/Unique.c \
tpm2/Unmarshal.c \ tpm2/Unmarshal.c \
tpm2/VendorInfo.c \
tpm2/Vendor_TCG_Test.c \ tpm2/Vendor_TCG_Test.c \
tpm2/X509_ECC.c \ tpm2/X509_ECC.c \
tpm2/X509_RSA.c \ tpm2/X509_RSA.c \
@ -522,7 +523,6 @@ noinst_HEADERS += \
tpm2/Unmarshal_fp.h \ tpm2/Unmarshal_fp.h \
tpm2/Unseal_fp.h \ tpm2/Unseal_fp.h \
tpm2/VendorInfo.h \ tpm2/VendorInfo.h \
tpm2/VendorString.h \
tpm2/Vendor_TCG_Test_fp.h \ tpm2/Vendor_TCG_Test_fp.h \
tpm2/VerifySignature_fp.h \ tpm2/VerifySignature_fp.h \
tpm2/X509.h \ tpm2/X509.h \

View File

@ -70,7 +70,6 @@
#include "endian_swap.h" #include "endian_swap.h"
#include "VendorInfo.h" #include "VendorInfo.h"
#include "VendorString.h" // libtpms: temporary
//** For Self-test //** For Self-test
// These macros are used in CryptUtil to invoke the incremental self test. // These macros are used in CryptUtil to invoke the incremental self test.

View File

@ -145,12 +145,9 @@ TPM_Manufacture(
orderlyShutdown = TPM_SU_CLEAR; orderlyShutdown = TPM_SU_CLEAR;
NV_WRITE_PERSISTENT(orderlyState, orderlyShutdown); NV_WRITE_PERSISTENT(orderlyState, orderlyShutdown);
// initialize the firmware version // initialize the firmware version
gp.firmwareV1 = FIRMWARE_V1; gp.firmwareV1 = _plat__GetTpmFirmwareVersionHigh();
#ifdef FIRMWARE_V2 gp.firmwareV2 = _plat__GetTpmFirmwareVersionLow();
gp.firmwareV2 = FIRMWARE_V2;
#else
gp.firmwareV2 = 0;
#endif
NV_SYNC_PERSISTENT(firmwareV1); NV_SYNC_PERSISTENT(firmwareV1);
NV_SYNC_PERSISTENT(firmwareV2); NV_SYNC_PERSISTENT(firmwareV2);

View File

@ -105,40 +105,26 @@ TPMPropertyIsDefined(
*value = TPM_SPEC_YEAR; *value = TPM_SPEC_YEAR;
break; break;
case TPM_PT_MANUFACTURER: case TPM_PT_MANUFACTURER:
*value = _plat__GetManufacturerCapabilityCode();
// vendor ID unique to each TPM manufacturer // vendor ID unique to each TPM manufacturer
*value = BYTE_ARRAY_TO_UINT32(MANUFACTURER);
break; break;
case TPM_PT_VENDOR_STRING_1: case TPM_PT_VENDOR_STRING_1:
// first four characters of the vendor ID string // first four characters of the vendor ID string
*value = BYTE_ARRAY_TO_UINT32(VENDOR_STRING_1); *value = _plat__GetVendorCapabilityCode(1);
break; break;
case TPM_PT_VENDOR_STRING_2: case TPM_PT_VENDOR_STRING_2:
// second four characters of the vendor ID string *value = _plat__GetVendorCapabilityCode(2);
#ifdef VENDOR_STRING_2
*value = BYTE_ARRAY_TO_UINT32(VENDOR_STRING_2);
#else
*value = 0;
#endif
break; break;
case TPM_PT_VENDOR_STRING_3: case TPM_PT_VENDOR_STRING_3:
// third four characters of the vendor ID string // third four characters of the vendor ID string
#ifdef VENDOR_STRING_3 *value = _plat__GetVendorCapabilityCode(3);
*value = BYTE_ARRAY_TO_UINT32(VENDOR_STRING_3);
#else
*value = 0;
#endif
break; break;
case TPM_PT_VENDOR_STRING_4: case TPM_PT_VENDOR_STRING_4:
// fourth four characters of the vendor ID string // fourth four characters of the vendor ID string
#ifdef VENDOR_STRING_4 *value = _plat__GetVendorCapabilityCode(4);
*value = BYTE_ARRAY_TO_UINT32(VENDOR_STRING_4);
#else
*value = 0;
#endif
break; break;
case TPM_PT_VENDOR_TPM_TYPE: case TPM_PT_VENDOR_TPM_TYPE:
// vendor-defined value indicating the TPM model *value = _plat__GetTpmType();
*value = 1;
break; break;
case TPM_PT_FIRMWARE_VERSION_1: case TPM_PT_FIRMWARE_VERSION_1:
// more significant 32-bits of a vendor-specific value // more significant 32-bits of a vendor-specific value

View File

@ -421,73 +421,45 @@ void TpmFailureMode(uint32_t inRequestSize, // IN: command buffer size
{ {
case TPM_PT_MANUFACTURER: case TPM_PT_MANUFACTURER:
// the vendor ID unique to each TPM manufacturer // the vendor ID unique to each TPM manufacturer
#ifdef MANUFACTURER pt = _plat__GetManufacturerCapabilityCode();
pt = *(UINT32*)MANUFACTURER;
#else
pt = 0;
#endif
break; break;
case TPM_PT_VENDOR_STRING_1: case TPM_PT_VENDOR_STRING_1:
// the first four characters of the vendor ID string // the first four characters of the vendor ID string
#ifdef VENDOR_STRING_1 pt = _plat__GetVendorCapabilityCode(1);
pt = *(UINT32*)VENDOR_STRING_1;
#else
pt = 0;
#endif
break; break;
case TPM_PT_VENDOR_STRING_2: case TPM_PT_VENDOR_STRING_2:
// the second four characters of the vendor ID string // the second four characters of the vendor ID string
#ifdef VENDOR_STRING_2 pt = _plat__GetVendorCapabilityCode(2);
pt = *(UINT32*)VENDOR_STRING_2;
#else
pt = 0;
#endif
break; break;
case TPM_PT_VENDOR_STRING_3: case TPM_PT_VENDOR_STRING_3:
// the third four characters of the vendor ID string // the third four characters of the vendor ID string
#ifdef VENDOR_STRING_3 pt = _plat__GetVendorCapabilityCode(3);
pt = *(UINT32*)VENDOR_STRING_3;
#else
pt = 0;
#endif
break; break;
case TPM_PT_VENDOR_STRING_4: case TPM_PT_VENDOR_STRING_4:
// the fourth four characters of the vendor ID string // the fourth four characters of the vendor ID string
#ifdef VENDOR_STRING_4 pt = _plat__GetVendorCapabilityCode(4);
pt = *(UINT32*)VENDOR_STRING_4;
#else
pt = 0;
#endif
break; break;
case TPM_PT_VENDOR_TPM_TYPE: case TPM_PT_VENDOR_TPM_TYPE:
// vendor-defined value indicating the TPM model // vendor-defined value indicating the TPM model
// We just make up a number here // We just make up a number here
pt = 1; pt = _plat__GetTpmType();
break; break;
case TPM_PT_FIRMWARE_VERSION_1: case TPM_PT_FIRMWARE_VERSION_1:
// the more significant 32-bits of a vendor-specific value // the more significant 32-bits of a vendor-specific value
// indicating the version of the firmware // indicating the version of the firmware
#ifdef FIRMWARE_V1 pt = _plat__GetTpmFirmwareVersionHigh();
pt = FIRMWARE_V1;
#else
pt = 0;
#endif
break; break;
default: // TPM_PT_FIRMWARE_VERSION_2: default: // TPM_PT_FIRMWARE_VERSION_2:
// the less significant 32-bits of a vendor-specific value // the less significant 32-bits of a vendor-specific value
// indicating the version of the firmware // indicating the version of the firmware
#ifdef FIRMWARE_V2 pt = _plat__GetTpmFirmwareVersionLow();
pt = FIRMWARE_V2;
#else
pt = 0;
#endif
break; break;
} }
marshalSize += MarshalUint32(pt, &buffer); marshalSize += MarshalUint32(pt, &buffer);

214
src/tpm2/VendorInfo.c Normal file
View File

@ -0,0 +1,214 @@
/********************************************************************************/
/* */
/* */
/* Written by Ken Goldman */
/* IBM Thomas J. Watson Research Center */
/* */
/* Licenses and Notices */
/* */
/* 1. Copyright Licenses: */
/* */
/* - Trusted Computing Group (TCG) grants to the user of the source code in */
/* this specification (the "Source Code") a worldwide, irrevocable, */
/* nonexclusive, royalty free, copyright license to reproduce, create */
/* derivative works, distribute, display and perform the Source Code and */
/* derivative works thereof, and to grant others the rights granted herein. */
/* */
/* - The TCG grants to the user of the other parts of the specification */
/* (other than the Source Code) the rights to reproduce, distribute, */
/* display, and perform the specification solely for the purpose of */
/* developing products based on such documents. */
/* */
/* 2. Source Code Distribution Conditions: */
/* */
/* - Redistributions of Source Code must retain the above copyright licenses, */
/* this list of conditions and the following disclaimers. */
/* */
/* - Redistributions in binary form must reproduce the above copyright */
/* licenses, this list of conditions and the following disclaimers in the */
/* documentation and/or other materials provided with the distribution. */
/* */
/* 3. Disclaimers: */
/* */
/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */
/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */
/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */
/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */
/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */
/* information on specification licensing rights available through TCG */
/* membership agreements. */
/* */
/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */
/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */
/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */
/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */
/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */
/* */
/* - Without limitation, TCG and its members and licensors disclaim all */
/* liability, including liability for infringement of any proprietary */
/* rights, relating to use of information in this specification and to the */
/* implementation of this specification, and TCG disclaims all liability for */
/* cost of procurement of substitute goods or services, lost profits, loss */
/* of use, loss of data or any incidental, consequential, direct, indirect, */
/* or special damages, whether under contract, tort, warranty or otherwise, */
/* arising in any way out of use or reliance upon this specification or any */
/* information herein. */
/* */
/* (c) Copyright IBM Corp. and others, 2023 */
/* */
/********************************************************************************/
//** Introduction
// Provide vendor-specific version and identifiers to core TPM library for
// return in capabilities. These may not be compile time constants and therefore
// are provided by platform callbacks. These platform functions are expected to
// always be available, even in failure mode.
//
//** Includes
#include "Platform.h"
// In this sample platform, these are compile time constants, but are not required to be.
#define MANUFACTURER "IBM "
#define VENDOR_STRING_1 "SW "
#define VENDOR_STRING_2 " TPM"
#define VENDOR_STRING_3 "\0\0\0\0"
#define VENDOR_STRING_4 "\0\0\0\0"
#define FIRMWARE_V1 (0x20191023)
#define FIRMWARE_V2 (0x00163636)
#define MAX_SVN 255
#if 0 // libtpms: added
static uint32_t currentHash = FIRMWARE_V2;
static uint16_t currentSvn = 10;
#endif // libtpms: added
// Similar to the Core Library's ByteArrayToUint32, but usable in Platform code.
static uint32_t StringToUint32(char s[4])
{
uint8_t* b = (uint8_t*)s; // Avoid promotion to a signed integer type
return (((uint32_t)b[0] << 8 | b[1]) << 8 | b[2]) << 8 | b[3];
}
// return the 4 character Manufacturer Capability code. This
// should come from the platform library since that is provided by the manufacturer
LIB_EXPORT uint32_t _plat__GetManufacturerCapabilityCode()
{
return StringToUint32(MANUFACTURER);
}
// return the 4 character VendorStrings for Capabilities.
// Index is ONE-BASED, and may be in the range [1,4] inclusive.
// Any other index returns all zeros. The return value will be interpreted
// as an array of 4 ASCII characters (with no null terminator)
LIB_EXPORT uint32_t _plat__GetVendorCapabilityCode(int index)
{
switch(index)
{
case 1:
return StringToUint32(VENDOR_STRING_1);
case 2:
return StringToUint32(VENDOR_STRING_2);
case 3:
return StringToUint32(VENDOR_STRING_3);
case 4:
return StringToUint32(VENDOR_STRING_4);
}
return 0;
}
// return the most-significant 32-bits of the TPM Firmware Version reported by
// getCapability.
LIB_EXPORT uint32_t _plat__GetTpmFirmwareVersionHigh()
{
return FIRMWARE_V1;
}
// return the least-significant 32-bits of the TPM Firmware Version reported by
// getCapability.
LIB_EXPORT uint32_t _plat__GetTpmFirmwareVersionLow()
{
return FIRMWARE_V2;
}
#if 0 // libtpms: added
// return the TPM Firmware SVN reported by getCapability.
LIB_EXPORT uint16_t _plat__GetTpmFirmwareSvn(void)
{
return currentSvn;
}
// return the TPM Firmware maximum SVN reported by getCapability.
LIB_EXPORT uint16_t _plat__GetTpmFirmwareMaxSvn(void)
{
return MAX_SVN;
}
// Called by the simulator to set the TPM Firmware SVN reported by
// getCapability.
LIB_EXPORT void _plat__SetTpmFirmwareHash(uint32_t hash)
{
currentHash = hash;
}
// Called by the simulator to set the TPM Firmware SVN reported by
// getCapability.
LIB_EXPORT void _plat__SetTpmFirmwareSvn(uint16_t svn)
{
currentSvn = MIN(svn, MAX_SVN);
}
#endif // libtpms: added
#if SVN_LIMITED_SUPPORT
// Dummy implmenentation for obtaining a Firmware SVN Secret bound
// to the given SVN.
LIB_EXPORT int _plat__GetTpmFirmwareSvnSecret(uint16_t svn,
uint16_t secret_buf_size,
uint8_t* secret_buf,
uint16_t* secret_size)
{
int i;
if(svn > currentSvn)
{
return -1;
}
// INSECURE dummy implementation: repeat the SVN into the secret buffer.
for(i = 0; i < secret_buf_size; ++i)
{
secret_buf[i] = ((uint8_t*)&svn)[i % sizeof(svn)];
}
*secret_size = secret_buf_size;
return 0;
}
#endif // SVN_LIMITED_SUPPORT
#if FW_LIMITED_SUPPORT
// Dummy implmenentation for obtaining a Firmware Secret bound
// to the current firmware image.
LIB_EXPORT int _plat__GetTpmFirmwareSecret
(uint16_t secret_buf_size, uint8_t* secret_buf, uint16_t* secret_size)
{
int i;
// INSECURE dummy implementation: repeat the firmware hash into the
// secret buffer.
for(i = 0; i < secret_buf_size; ++i)
{
secret_buf[i] = ((uint8_t*)&currentHash)[i % sizeof(currentHash)];
}
*secret_size = secret_buf_size;
return 0;
}
#endif // FW_LIMITED_SUPPORT
// return the TPM Type returned by TPM_PT_VENDOR_TPM_TYPE
LIB_EXPORT uint32_t _plat__GetTpmType()
{
return 1; // just the value the reference code has returned in the past.
}

View File

@ -1,108 +0,0 @@
/********************************************************************************/
/* */
/* Vendor String */
/* Written by Ken Goldman */
/* IBM Thomas J. Watson Research Center */
/* $Id: VendorString.h 1519 2019-11-15 20:43:51Z kgoldman $ */
/* */
/* Licenses and Notices */
/* */
/* 1. Copyright Licenses: */
/* */
/* - Trusted Computing Group (TCG) grants to the user of the source code in */
/* this specification (the "Source Code") a worldwide, irrevocable, */
/* nonexclusive, royalty free, copyright license to reproduce, create */
/* derivative works, distribute, display and perform the Source Code and */
/* derivative works thereof, and to grant others the rights granted herein. */
/* */
/* - The TCG grants to the user of the other parts of the specification */
/* (other than the Source Code) the rights to reproduce, distribute, */
/* display, and perform the specification solely for the purpose of */
/* developing products based on such documents. */
/* */
/* 2. Source Code Distribution Conditions: */
/* */
/* - Redistributions of Source Code must retain the above copyright licenses, */
/* this list of conditions and the following disclaimers. */
/* */
/* - Redistributions in binary form must reproduce the above copyright */
/* licenses, this list of conditions and the following disclaimers in the */
/* documentation and/or other materials provided with the distribution. */
/* */
/* 3. Disclaimers: */
/* */
/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */
/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */
/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */
/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */
/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */
/* information on specification licensing rights available through TCG */
/* membership agreements. */
/* */
/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */
/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */
/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */
/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */
/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */
/* */
/* - Without limitation, TCG and its members and licensors disclaim all */
/* liability, including liability for infringement of any proprietary */
/* rights, relating to use of information in this specification and to the */
/* implementation of this specification, and TCG disclaims all liability for */
/* cost of procurement of substitute goods or services, lost profits, loss */
/* of use, loss of data or any incidental, consequential, direct, indirect, */
/* or special damages, whether under contract, tort, warranty or otherwise, */
/* arising in any way out of use or reliance upon this specification or any */
/* information herein. */
/* */
/* (c) Copyright IBM Corp. and others, 2016 - 2019 */
/* */
/********************************************************************************/
#ifndef VENDORSTRING_H
#define VENDORSTRING_H
/* Define up to 4-byte values for MANUFACTURER. This value defines the response for
TPM_PT_MANUFACTURER in TPM2_GetCapability(). The following line should be un-commented and a
vendor specific string should be provided here. */
#define MANUFACTURER "IBM"
/* The following #if macro may be deleted after a proper MANUFACTURER is provided. */
#ifndef MANUFACTURER
#error MANUFACTURER is not provided. \
Please modify VendorString.h to provide a specific \
manufacturer name.
#endif
/* Define up to 4, 4-byte, vendor-specific values. The values must each be 4 bytes long and the
last value used may contain trailing zeros. These values define the response for
TPM_PT_VENDOR_STRING_(1-4) in TPM2_GetCapability(). The following line should be un-commented
and a vendor specific string. The vendor strings 2-4 may also be defined as appropriate. */
#define VENDOR_STRING_1 "SW "
#define VENDOR_STRING_2 " TPM"
//#define VENDOR_STRING_3
//#define VENDOR_STRING_4
/* The following #if macro may be deleted after a proper VENDOR_STRING_1 is provided. */
#ifndef VENDOR_STRING_1
#error VENDOR_STRING_1 is not provided. \
Please modify VendorString.h to provide a vendor specific string.
#endif
/* the more significant 32-bits of a vendor-specific value indicating the version of the firmware
The following line should be un-commented and a vendor specific firmware V1 should be provided
here. The FIRMWARE_V2 may also be defined as appropriate. */
#define FIRMWARE_V1 (0x20191023)
// the less significant 32-bits of a vendor-specific value indicating the version of the firmware
#define FIRMWARE_V2 (0x00163636)
// The following #if macro may be deleted after a proper FIRMWARE_V1 is provided.
#ifndef FIRMWARE_V1
#error FIRMWARE_V1 is not provided. \
Please modify VendorString.h to provide a vendor specific firmware \
version
#endif
#endif

View File

@ -399,10 +399,11 @@ LIB_EXPORT uint32_t _plat__GetUnique(uint32_t which,
// to the Core library. // to the Core library.
LIB_EXPORT void _plat__GetPlatformManufactureData(uint8_t* pPlatformPersistentData, LIB_EXPORT void _plat__GetPlatformManufactureData(uint8_t* pPlatformPersistentData,
uint32_t bufferSize); uint32_t bufferSize);
#endif // libtpms: added
// return the 4 character Manufacturer Capability code. This // return the 4 character Manufacturer Capability code. This
// should come from the platform library since that is provided by the manufacturer // should come from the platform library since that is provided by the manufacturer
LIB_EXPORT uint32_t _plat__GetManufacturerCapabilityCode(); LIB_EXPORT uint32_t _plat__GetManufacturerCapabilityCode(void);
// return the 4 character VendorStrings for Capabilities. // return the 4 character VendorStrings for Capabilities.
// Index is ONE-BASED, and may be in the range [1,4] inclusive. // Index is ONE-BASED, and may be in the range [1,4] inclusive.
@ -412,12 +413,13 @@ LIB_EXPORT uint32_t _plat__GetVendorCapabilityCode(int index);
// return the most-significant 32-bits of the TPM Firmware Version reported by // return the most-significant 32-bits of the TPM Firmware Version reported by
// getCapability. // getCapability.
LIB_EXPORT uint32_t _plat__GetTpmFirmwareVersionHigh(); LIB_EXPORT uint32_t _plat__GetTpmFirmwareVersionHigh(void);
// return the least-significant 32-bits of the TPM Firmware Version reported by // return the least-significant 32-bits of the TPM Firmware Version reported by
// getCapability. // getCapability.
LIB_EXPORT uint32_t _plat__GetTpmFirmwareVersionLow(); LIB_EXPORT uint32_t _plat__GetTpmFirmwareVersionLow(void);
#if 0 // libtpms: added
// return the TPM Firmware's current SVN. // return the TPM Firmware's current SVN.
LIB_EXPORT uint16_t _plat__GetTpmFirmwareSvn(void); LIB_EXPORT uint16_t _plat__GetTpmFirmwareSvn(void);
@ -452,11 +454,13 @@ LIB_EXPORT int _plat__GetTpmFirmwareSecret(
uint16_t* secret_size // OUT: secret buffer uint16_t* secret_size // OUT: secret buffer
); );
#endif // FW_LIMITED_SUPPORT #endif // FW_LIMITED_SUPPORT
#endif // libtpms: added
// return the TPM Type returned by TPM_PT_VENDOR_TPM_TYPE // return the TPM Type returned by TPM_PT_VENDOR_TPM_TYPE
LIB_EXPORT uint32_t _plat__GetTpmType(); LIB_EXPORT uint32_t _plat__GetTpmType(void);
// platform PCR initialization functions // platform PCR initialization functions
#if 0 // libtpms: added
#include "platform_pcr_fp.h" #include "platform_pcr_fp.h"
#endif // libtpms: added #endif // libtpms: added

View File

@ -396,9 +396,11 @@ static char *TPM2_GetInfo(enum TPMLIB_InfoFlags flags)
} }
if ((flags & TPMLIB_INFO_TPMATTRIBUTES)) { if ((flags & TPMLIB_INFO_TPMATTRIBUTES)) {
uint32_t firmware_v1 = _plat__GetTpmFirmwareVersionHigh();
fmt = buffer; fmt = buffer;
buffer = NULL; buffer = NULL;
if (asprintf(&tpmattrs, tpmattrs_temp, FIRMWARE_V1) < 0) if (asprintf(&tpmattrs, tpmattrs_temp, firmware_v1) < 0)
goto error; goto error;
if (asprintf(&buffer, fmt, printed ? "," : "", if (asprintf(&buffer, fmt, printed ? "," : "",
tpmattrs, "%s%s%s") < 0) tpmattrs, "%s%s%s") < 0)