183 lines
7.2 KiB
C
183 lines
7.2 KiB
C
// This file was extracted from the TCG Published
|
|
// Trusted Platform Module Library
|
|
// Part 4: Supporting Routines
|
|
// Family "2.0"
|
|
// Level 00 Revision 01.16
|
|
// October 30, 2014
|
|
|
|
#include "InternalRoutines.h"
|
|
#include "Attest_spt_fp.h"
|
|
//
|
|
//
|
|
// Functions
|
|
//
|
|
// FillInAttestInfo()
|
|
//
|
|
// Fill in common fields of TPMS_ATTEST structure.
|
|
//
|
|
// Error Returns Meaning
|
|
//
|
|
// TPM_RC_KEY key referenced by signHandle is not a signing key
|
|
// TPM_RC_SCHEME both scheme and key's default scheme are empty; or scheme is
|
|
// empty while key's default scheme requires explicit input scheme (split
|
|
// signing); or non-empty default key scheme differs from scheme
|
|
//
|
|
TPM_RC
|
|
FillInAttestInfo(
|
|
TPMI_DH_OBJECT signHandle, // IN: handle of signing object
|
|
TPMT_SIG_SCHEME *scheme, // IN/OUT: scheme to be used for signing
|
|
TPM2B_DATA *data, // IN: qualifying data
|
|
TPMS_ATTEST *attest // OUT: attest structure
|
|
)
|
|
{
|
|
TPM_RC result;
|
|
TPMI_RH_HIERARCHY signHierarhcy;
|
|
result = CryptSelectSignScheme(signHandle, scheme);
|
|
if(result != TPM_RC_SUCCESS)
|
|
return result;
|
|
// Magic number
|
|
attest->magic = TPM_GENERATED_VALUE;
|
|
if(signHandle == TPM_RH_NULL)
|
|
{
|
|
BYTE *buffer;
|
|
INT32 bufferSize;
|
|
// For null sign handle, the QN is TPM_RH_NULL
|
|
buffer = attest->qualifiedSigner.t.name;
|
|
bufferSize = sizeof(TPM_HANDLE);
|
|
attest->qualifiedSigner.t.size =
|
|
TPM_HANDLE_Marshal(&signHandle, &buffer, &bufferSize);
|
|
}
|
|
else
|
|
{
|
|
// Certifying object qualified name
|
|
// if the scheme is anonymous, this is an empty buffer
|
|
if(CryptIsSchemeAnonymous(scheme->scheme))
|
|
attest->qualifiedSigner.t.size = 0;
|
|
else
|
|
ObjectGetQualifiedName(signHandle, &attest->qualifiedSigner);
|
|
}
|
|
// current clock in plain text
|
|
TimeFillInfo(&attest->clockInfo);
|
|
// Firmware version in plain text
|
|
attest->firmwareVersion = ((UINT64) gp.firmwareV1 << (sizeof(UINT32) * 8));
|
|
attest->firmwareVersion += gp.firmwareV2;
|
|
// Get the hierarchy of sign object. For NULL sign handle, the hierarchy
|
|
// will be TPM_RH_NULL
|
|
signHierarhcy = EntityGetHierarchy(signHandle);
|
|
if(signHierarhcy != TPM_RH_PLATFORM && signHierarhcy != TPM_RH_ENDORSEMENT)
|
|
{
|
|
// For sign object is not in platform or endorsement hierarchy,
|
|
// obfuscate the clock and firmwereVersion information
|
|
UINT64 obfuscation[2];
|
|
TPMI_ALG_HASH hashAlg;
|
|
// Get hash algorithm
|
|
if(signHandle == TPM_RH_NULL || signHandle == TPM_RH_OWNER)
|
|
{
|
|
hashAlg = CONTEXT_INTEGRITY_HASH_ALG;
|
|
}
|
|
else
|
|
{
|
|
OBJECT *signObject = NULL;
|
|
signObject = ObjectGet(signHandle);
|
|
hashAlg = signObject->publicArea.nameAlg;
|
|
}
|
|
KDFa(hashAlg, &gp.shProof.b, "OBFUSCATE",
|
|
&attest->qualifiedSigner.b, NULL, 128, (BYTE *)&obfuscation[0], NULL);
|
|
// Obfuscate data
|
|
attest->firmwareVersion += obfuscation[0];
|
|
attest->clockInfo.resetCount += (UINT32)(obfuscation[1] >> 32);
|
|
attest->clockInfo.restartCount += (UINT32)obfuscation[1];
|
|
}
|
|
// External data
|
|
if(CryptIsSchemeAnonymous(scheme->scheme))
|
|
attest->extraData.t.size = 0;
|
|
else
|
|
{
|
|
// If we move the data to the attestation structure, then we will not use
|
|
// it in the signing operation except as part of the signed data
|
|
attest->extraData = *data;
|
|
data->t.size = 0;
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|
|
//
|
|
//
|
|
// SignAttestInfo()
|
|
//
|
|
// Sign a TPMS_ATTEST structure. If signHandle is TPM_RH_NULL, a null signature is returned.
|
|
//
|
|
//
|
|
//
|
|
//
|
|
// Error Returns Meaning
|
|
//
|
|
// TPM_RC_ATTRIBUTES signHandle references not a signing key
|
|
// TPM_RC_SCHEME scheme is not compatible with signHandle type
|
|
// TPM_RC_VALUE digest generated for the given scheme is greater than the modulus of
|
|
// signHandle (for an RSA key); invalid commit status or failed to
|
|
// generate r value (for an ECC key)
|
|
//
|
|
TPM_RC
|
|
SignAttestInfo(
|
|
TPMI_DH_OBJECT signHandle, // IN: handle of sign object
|
|
TPMT_SIG_SCHEME *scheme, // IN: sign scheme
|
|
TPMS_ATTEST *certifyInfo, // IN: the data to be signed
|
|
TPM2B_DATA *qualifyingData, // IN: extra data for the signing proce
|
|
TPM2B_ATTEST *attest, // OUT: marshaled attest blob to be
|
|
// signed
|
|
TPMT_SIGNATURE *signature // OUT: signature
|
|
)
|
|
{
|
|
TPM_RC result;
|
|
TPMI_ALG_HASH hashAlg;
|
|
BYTE *buffer;
|
|
INT32 bufferSize;
|
|
HASH_STATE hashState;
|
|
TPM2B_DIGEST digest;
|
|
// Marshal TPMS_ATTEST structure for hash
|
|
buffer = attest->t.attestationData;
|
|
bufferSize = sizeof(TPMS_ATTEST);
|
|
attest->t.size = TPMS_ATTEST_Marshal(certifyInfo, &buffer, &bufferSize);
|
|
if(signHandle == TPM_RH_NULL)
|
|
{
|
|
signature->sigAlg = TPM_ALG_NULL;
|
|
}
|
|
else
|
|
{
|
|
// Attestation command may cause the orderlyState to be cleared due to
|
|
// the reporting of clock info. If this is the case, check if NV is
|
|
// available first
|
|
if(gp.orderlyState != SHUTDOWN_NONE)
|
|
{
|
|
// The command needs NV update. Check if NV is available.
|
|
// A TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE error may be returned at
|
|
// this point
|
|
result = NvIsAvailable();
|
|
if(result != TPM_RC_SUCCESS)
|
|
return result;
|
|
}
|
|
// Compute hash
|
|
hashAlg = scheme->details.any.hashAlg;
|
|
digest.t.size = CryptStartHash(hashAlg, &hashState);
|
|
CryptUpdateDigest(&hashState, attest->t.size, attest->t.attestationData);
|
|
CryptCompleteHash2B(&hashState, &digest.b);
|
|
// If there is qualifying data, need to rehash the the data
|
|
// hash(qualifyingData || hash(attestationData))
|
|
if(qualifyingData->t.size != 0)
|
|
{
|
|
CryptStartHash(hashAlg, &hashState);
|
|
CryptUpdateDigest(&hashState,
|
|
qualifyingData->t.size,
|
|
qualifyingData->t.buffer);
|
|
CryptUpdateDigest(&hashState, digest.t.size, digest.t.buffer);
|
|
CryptCompleteHash2B(&hashState, &digest.b);
|
|
}
|
|
// Sign the hash. A TPM_RC_VALUE, TPM_RC_SCHEME, or
|
|
// TPM_RC_ATTRIBUTES error may be returned at this point
|
|
return CryptSign(signHandle,
|
|
scheme,
|
|
&digest,
|
|
signature);
|
|
}
|
|
return TPM_RC_SUCCESS;
|
|
}
|