tpm2: Save key and hash contexts using ANY_OBJECT_Marshal

Save key and hash contexts using the ANY_OBJECT_Marshal function and try
to load it using ANY_OBJECT_Unmarshal(). Unfortunately older contexts were
written out as plain OBJECTs, so we have to accomodate this case as well
so that we can restore key contexts from libtpms-0.7.x. We do not support
resuming HASH contexts from libtpms-0.7.x.

Before this modification context files written out by the IBM TSS stack
were 2692 bytes independent of content. Now an RSA 2048 key is 1222 bytes
and a NIST p384 key is 982 bytes.

Several of the original TPM 2 function exporting Sequence state and
importing it can now be disabled.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
This commit is contained in:
Stefan Berger 2021-02-17 13:29:00 -05:00 committed by Stefan Berger
parent 81c507f528
commit 1e1648fec3
8 changed files with 344 additions and 7 deletions

View File

@ -276,6 +276,7 @@ libtpms_tpm2_la_SOURCES = \
tpm_tpm2_interface.c \
tpm_tpm2_tis.c \
\
tpm2/BackwardsCompatibilityObject.c \
tpm2/LibtpmsCallbacks.c \
tpm2/NVMarshal.c \
tpm2/StateMarshal.c \
@ -512,6 +513,7 @@ noinst_HEADERS += \
tpm2/ZGen_2Phase_fp.h \
\
tpm2/BackwardsCompatibility.h \
tpm2/BackwardsCompatibilityObject.h \
tpm2/LibtpmsCallbacks.h \
tpm2/NVMarshal.h \
tpm2/StateMarshal.h \

View File

@ -0,0 +1,234 @@
/********************************************************************************/
/* */
/* Backwards compatibility stuff related to OBJECT */
/* Written by Stefan Berger */
/* IBM Thomas J. Watson Research Center */
/* */
/* (c) Copyright IBM Corporation 2017,2018. */
/* */
/* All rights reserved. */
/* */
/* Redistribution and use in source and binary forms, with or without */
/* modification, are permitted provided that the following conditions are */
/* met: */
/* */
/* Redistributions of source code must retain the above copyright notice, */
/* this list of conditions and the following disclaimer. */
/* */
/* 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. */
/* */
/* Neither the names of the IBM Corporation nor the names of its */
/* contributors may be used to endorse or promote products derived from */
/* this software without specific prior written permission. */
/* */
/* 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 <assert.h>
#include "BackwardsCompatibilityObject.h"
/* The following are data structure from libtpms 0.7.x with RSA 2048 support
* that help to resume key and hash contexts (TPM2_ContextSave/Load) from this
* earlier version. All structures that have different sizes in 0.8 are found
* here.
*/
typedef union {
struct {
UINT16 size;
BYTE buffer[2048/8];
} t;
TPM2B b;
} OLD_TPM2B_PUBLIC_KEY_RSA;
typedef union {
TPM2B_DIGEST keyedHash;
TPM2B_DIGEST sym;
OLD_TPM2B_PUBLIC_KEY_RSA rsa;
TPMS_ECC_POINT ecc;
// TPMS_DERIVE derive;
} OLD_TPMU_PUBLIC_ID;
typedef struct {
TPMI_ALG_PUBLIC type;
TPMI_ALG_HASH nameAlg;
TPMA_OBJECT objectAttributes;
TPM2B_DIGEST authPolicy;
TPMU_PUBLIC_PARMS parameters;
OLD_TPMU_PUBLIC_ID unique;
} OLD_TPMT_PUBLIC;
static_assert(sizeof(OLD_TPMT_PUBLIC) == 356,
"OLD_TPMT_PUBLIC has wrong size");
typedef union {
struct {
UINT16 size;
BYTE buffer[((2048/8)/2)*5];
} t;
TPM2B b;
} OLD_TPM2B_PRIVATE_KEY_RSA;
static_assert(sizeof(OLD_TPM2B_PRIVATE_KEY_RSA) == 642,
"OLD_TPM2B_PRIVATE_KEY_RSA has wrong size");
typedef union {
struct {
UINT16 size;
BYTE buffer[((2048/8)/2)*5];
} t;
TPM2B b;
} OLD_TPM2B_PRIVATE_VENDOR_SPECIFIC;
typedef union {
OLD_TPM2B_PRIVATE_KEY_RSA rsa;
TPM2B_ECC_PARAMETER ecc;
TPM2B_SENSITIVE_DATA bits;
TPM2B_SYM_KEY sym;
OLD_TPM2B_PRIVATE_VENDOR_SPECIFIC any;
} OLD_TPMU_SENSITIVE_COMPOSITE;
typedef struct {
TPMI_ALG_PUBLIC sensitiveType;
TPM2B_AUTH authValue;
TPM2B_DIGEST seedValue;
OLD_TPMU_SENSITIVE_COMPOSITE sensitive;
} OLD_TPMT_SENSITIVE;
static_assert(sizeof(OLD_TPMT_SENSITIVE) == 776,
"OLD_TPMT_SENSITIVE has wrong size");
BN_TYPE(old_prime, (2048 / 2));
typedef struct OLD_privateExponent
{
bn_old_prime_t Q;
bn_old_prime_t dP;
bn_old_prime_t dQ;
bn_old_prime_t qInv;
} OLD_privateExponent_t;
static inline void CopyFromOldPrimeT(bn_prime_t *dst,
const bn_old_prime_t *src)
{
dst->allocated = src->allocated;
dst->size = src->size;
memcpy(dst->d, src->d, sizeof(src->d));
}
static_assert(sizeof(OLD_privateExponent_t) == 608,
"OLD_privateExponent_t has wrong size");
typedef struct OLD_OBJECT
{
// The attributes field is required to be first followed by the publicArea.
// This allows the overlay of the object structure and a sequence structure
OBJECT_ATTRIBUTES attributes; // object attributes
OLD_TPMT_PUBLIC publicArea; // public area of an object
OLD_TPMT_SENSITIVE sensitive; // sensitive area of an object
OLD_privateExponent_t privateExponent; // Additional field for the private
TPM2B_NAME qualifiedName; // object qualified name
TPMI_DH_OBJECT evictHandle; // if the object is an evict object,
// the original handle is kept here.
// The 'working' handle will be the
// handle of an object slot.
TPM2B_NAME name; // Name of the object name. Kept here
// to avoid repeatedly computing it.
// libtpms added: OBJECT lies in NVRAM; to avoid that it needs different number
// of bytes on 32 bit and 64 bit architectures, we need to make sure it's the
// same size; simple padding at the end works here
UINT32 _pad;
} OLD_OBJECT;
static_assert(sizeof(OLD_OBJECT) == 1896,
"OLD_OBJECT has wrong size");
// Convert an OLD_OBJECT that was copied into buffer using MemoryCopy
TPM_RC
OLD_OBJECTToOBJECT(OBJECT *newObject, BYTE *buffer, INT32 size)
{
OLD_OBJECT oldObject;
TPM_RC rc = 0;
// get the attributes
MemoryCopy(newObject, buffer, sizeof(newObject->attributes));
if (ObjectIsSequence(newObject))
{
/* resuming old hash contexts is not supported */
rc = TPM_RC_DISABLED;
}
else
{
if (size != sizeof(OLD_OBJECT))
return TPM_RC_SIZE;
MemoryCopy(&oldObject, buffer, sizeof(OLD_OBJECT));
/* fill the newObject with the contents of the oldObject */
newObject->attributes = oldObject.attributes;
newObject->publicArea.type = oldObject.publicArea.type;
newObject->publicArea.nameAlg = oldObject.publicArea.nameAlg;
newObject->publicArea.objectAttributes = oldObject.publicArea.objectAttributes;
newObject->publicArea.authPolicy = oldObject.publicArea.authPolicy;
newObject->publicArea.parameters = oldObject.publicArea.parameters;
/* the unique part can be one or two TPM2B's */
switch (newObject->publicArea.type) {
case TPM_ALG_KEYEDHASH:
MemoryCopy2B(&newObject->publicArea.unique.keyedHash.b,
&oldObject.publicArea.unique.keyedHash.b,
sizeof(oldObject.publicArea.unique.keyedHash.t.buffer));
break;
case TPM_ALG_SYMCIPHER:
MemoryCopy2B(&newObject->publicArea.unique.sym.b,
&oldObject.publicArea.unique.sym.b,
sizeof(oldObject.publicArea.unique.sym.t.buffer));
break;
case TPM_ALG_RSA:
MemoryCopy2B(&newObject->publicArea.unique.rsa.b,
&oldObject.publicArea.unique.rsa.b,
sizeof(oldObject.publicArea.unique.rsa.t.buffer));
break;
case TPM_ALG_ECC:
MemoryCopy2B(&newObject->publicArea.unique.ecc.x.b,
&oldObject.publicArea.unique.ecc.x.b,
sizeof(oldObject.publicArea.unique.ecc.x.t.buffer));
MemoryCopy2B(&newObject->publicArea.unique.ecc.y.b,
&oldObject.publicArea.unique.ecc.y.b,
sizeof(oldObject.publicArea.unique.ecc.y.t.buffer));
break;
}
newObject->sensitive.sensitiveType = oldObject.sensitive.sensitiveType;
newObject->sensitive.authValue = oldObject.sensitive.authValue;
newObject->sensitive.seedValue = oldObject.sensitive.seedValue;
/* The OLD_TPMU_SENSITIVE_COMPOSITE is always a TPM2B */
MemoryCopy2B(&newObject->sensitive.sensitive.any.b,
&oldObject.sensitive.sensitive.any.b,
sizeof(oldObject.sensitive.sensitive.any.t.buffer));
CopyFromOldPrimeT(&newObject->privateExponent.Q, &oldObject.privateExponent.Q);
CopyFromOldPrimeT(&newObject->privateExponent.dP, &oldObject.privateExponent.dP);
CopyFromOldPrimeT(&newObject->privateExponent.dQ, &oldObject.privateExponent.dQ);
CopyFromOldPrimeT(&newObject->privateExponent.qInv, &oldObject.privateExponent.qInv);
newObject->qualifiedName = oldObject.qualifiedName;
newObject->evictHandle = oldObject.evictHandle;
newObject->name = oldObject.name;
}
return rc;
}

View File

@ -0,0 +1,47 @@
/********************************************************************************/
/* */
/* Backwards compatibility stuff related to OBJECT */
/* Written by Stefan Berger */
/* IBM Thomas J. Watson Research Center */
/* */
/* (c) Copyright IBM Corporation 2017,2018. */
/* */
/* All rights reserved. */
/* */
/* Redistribution and use in source and binary forms, with or without */
/* modification, are permitted provided that the following conditions are */
/* met: */
/* */
/* Redistributions of source code must retain the above copyright notice, */
/* this list of conditions and the following disclaimer. */
/* */
/* 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. */
/* */
/* Neither the names of the IBM Corporation nor the names of its */
/* contributors may be used to endorse or promote products derived from */
/* this software without specific prior written permission. */
/* */
/* 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. */
/********************************************************************************/
#ifndef BACKWARDS_COMPATIBILITY_OBJECT_H
#define BACKWARDS_COMPATIBILITY_OBJECT_H
#include "Tpm.h"
TPM_RC OLD_OBJECTToOBJECT(OBJECT *object, BYTE *buffer, INT32 size);
#endif /* BACKWARDS_COMPATIBILITY_OBJECT_H */

View File

@ -61,6 +61,7 @@
#include "Tpm.h"
#include "ContextSave_fp.h"
#include "NVMarshal.h" // libtpms added
#if CC_ContextSave // Conditional expansion of this file
#include "Context_spt_fp.h"
/* Error Returns Meaning */
@ -114,8 +115,11 @@ TPM2_ContextSave(
{
OBJECT *object = HandleToObject(in->saveHandle);
ANY_OBJECT_BUFFER *outObject;
UINT16 objectSize = ObjectIsSequence(object)
? sizeof(HASH_OBJECT) : sizeof(OBJECT);
unsigned char buffer[sizeof(OBJECT) * 2]; // libtpms changed begin
BYTE *bufptr = &buffer[0];
INT32 size = sizeof(buffer);
UINT16 written = ANY_OBJECT_Marshal(object, &bufptr, &size);
UINT16 objectSize = written; // libtpms changed end
outObject = (ANY_OBJECT_BUFFER *)(out->context.contextBlob.t.buffer
+ integritySize + fingerprintSize);
// Set size of the context data. The contents of context blob is vendor
@ -127,7 +131,7 @@ TPM2_ContextSave(
pAssert(out->context.contextBlob.t.size
<= sizeof(out->context.contextBlob.t.buffer));
// Copy the whole internal OBJECT structure to context blob
MemoryCopy(outObject, object, objectSize);
MemoryCopy(outObject, buffer, written); // libtpms changed
// Increment object context ID
gr.objectContextID++;
// If object context ID overflows, TPM should be put in failure mode
@ -141,8 +145,10 @@ TPM2_ContextSave(
if(ObjectIsSequence(object))
{
out->context.savedHandle = 0x80000001;
/* ANY_OBJECT_Marshal already wrote it // libtpms changed begin
SequenceDataExport((HASH_OBJECT *)object,
(HASH_OBJECT_BUFFER *)outObject);
*/ // libtpms changed end
}
else
out->context.savedHandle = (object->attributes.stClear == SET)
@ -296,8 +302,8 @@ TPM2_ContextLoad(
if(!HierarchyIsEnabled(in->context.hierarchy))
return TPM_RCS_HIERARCHY + RC_ContextLoad_context;
// Restore object. If there is no empty space, indicate as much
outObject = ObjectContextLoad((ANY_OBJECT_BUFFER *)buffer,
&out->loadedHandle);
outObject = ObjectContextLoadLibtpms(buffer, size, // libtpms changed
&out->loadedHandle);
if(outObject == NULL)
return TPM_RC_OBJECT_MEMORY;
break;

View File

@ -153,6 +153,7 @@ ComputeContextIntegrity(
CryptHmacEnd2B(&hmacState, &integrity->b);
return;
}
#if 0
/* 7.3.2.3 SequenceDataExport() */
/* This function is used scan through the sequence object and either modify the hash state data for
export (contextSave) or to import it into the internal format (contextLoad). This function should
@ -200,3 +201,4 @@ SequenceDataImport(
CryptHashImportState(hash, (EXPORT_HASH_STATE *)importHash);
}
}
#endif

View File

@ -65,6 +65,8 @@
/* 8.6.2 Includes and Data Definitions */
#define OBJECT_C
#include "Tpm.h"
#include "NVMarshal.h" // libtpms added
#include "BackwardsCompatibilityObject.h" // libtpms added
/* 8.6.3 Functions */
/* 8.6.3.1 ObjectFlush() */
/* This function marks an object slot as available. Since there is no checking of the input
@ -619,6 +621,7 @@ ObjectTerminateEvent(
/* Return Values Meaning */
/* NULL if there is no free slot for an object */
/* NON_NULL points to the loaded object */
#if 0 // libtpms added
OBJECT *
ObjectContextLoad(
ANY_OBJECT_BUFFER *object, // IN: pointer to object structure in saved
@ -647,6 +650,39 @@ ObjectContextLoad(
}
return newObject;
}
#endif // libtpms added begin
OBJECT *
ObjectContextLoadLibtpms(BYTE *buffer,
INT32 size,
TPMI_DH_OBJECT *handle
)
{
OBJECT *newObject = ObjectAllocateSlot(handle);
TPM_RC rc;
BYTE *mybuf = buffer;
INT32 mysize = size;
pAssert(handle);
// Try to allocate a slot for new object
if(newObject != NULL)
{
rc = ANY_OBJECT_Unmarshal(newObject, &mybuf, &mysize, false);
if (rc) {
/* Attempt to load an old OBJECT that was copied out directly from
* an older version of OBJECT.
*/
rc = OLD_OBJECTToOBJECT(newObject, buffer, size);
if (rc) {
FlushObject(*handle);
newObject = NULL;
}
}
}
return newObject;
} // libtpms added end
/* 8.6.3.22 FlushObject() */
/* This function frees an object slot. */
/* This function requires that the object is loaded. */

View File

@ -158,12 +158,20 @@ void
ObjectTerminateEvent(
void
);
#if 0 // libtpms added
OBJECT *
ObjectContextLoad(
ANY_OBJECT_BUFFER *object, // IN: pointer to object structure in saved
// context
TPMI_DH_OBJECT *handle // OUT: object handle
);
#endif // libtpms added begin
OBJECT *
ObjectContextLoadLibtpms(BYTE *buffer, // IN: buffer holding the marshaled object
INT32 size, // IN: size of buffer
TPMI_DH_OBJECT *handle // OUT: object handle
);
// libtpms added end
void
FlushObject(
TPMI_DH_OBJECT handle // IN: handle to be freed

View File

@ -236,7 +236,7 @@ CryptHashGetContextAlg(
/* 10.2.13.5 State Import and Export */
/* 10.2.13.5.1 CryptHashCopyState */
/* This function is used to clone a HASH_STATE. */
#if 0 // libtpms added begin
#if 0 // libtpms added
LIB_EXPORT void
CryptHashCopyState(
HASH_STATE *out, // OUT: destination of the state
@ -258,7 +258,8 @@ CryptHashCopyState(
}
return;
}
#endif // libtpms added end
#endif // libtpms added
#if 0 // libtpms added
/* 10.2.13.5.2 CryptHashExportState() */
/* This function is used to export a hash or HMAC hash state. This function would be called when
preparing to context save a sequence object. */
@ -336,6 +337,7 @@ CryptHashImportState(
}
}
}
#endif // libtpms added
/* 10.2.13.6 State Modification Functions */
/* 10.2.13.6.1 HashEnd() */
/* Local function to complete a hash that uses the hashDef instead of an algorithm ID. This function