summaryrefslogtreecommitdiffstats
path: root/src/tpm2/AttestationCommands.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tpm2/AttestationCommands.c')
-rw-r--r--src/tpm2/AttestationCommands.c544
1 files changed, 544 insertions, 0 deletions
diff --git a/src/tpm2/AttestationCommands.c b/src/tpm2/AttestationCommands.c
new file mode 100644
index 0000000..9df4315
--- /dev/null
+++ b/src/tpm2/AttestationCommands.c
@@ -0,0 +1,544 @@
+/********************************************************************************/
+/* */
+/* Attestation Commands */
+/* Written by Ken Goldman */
+/* IBM Thomas J. Watson Research Center */
+/* $Id: AttestationCommands.c 1658 2021-01-22 23:14:01Z 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 - 2021 */
+/* */
+/********************************************************************************/
+
+#include "Tpm.h"
+#include "Attest_spt_fp.h"
+#include "Certify_fp.h"
+#if CC_Certify // Conditional expansion of this file
+TPM_RC
+TPM2_Certify(
+ Certify_In *in, // IN: input parameter list
+ Certify_Out *out // OUT: output parameter list
+ )
+{
+ TPMS_ATTEST certifyInfo;
+ OBJECT *signObject = HandleToObject(in->signHandle);
+ OBJECT *certifiedObject = HandleToObject(in->objectHandle);
+ // Input validation
+ if(!IsSigningObject(signObject))
+ return TPM_RCS_KEY + RC_Certify_signHandle;
+ if(!CryptSelectSignScheme(signObject, &in->inScheme))
+ return TPM_RCS_SCHEME + RC_Certify_inScheme;
+ // Command Output
+ // Filling in attest information
+ // Common fields
+ FillInAttestInfo(in->signHandle, &in->inScheme, &in->qualifyingData,
+ &certifyInfo);
+ // Certify specific fields
+ certifyInfo.type = TPM_ST_ATTEST_CERTIFY;
+ // NOTE: the certified object is not allowed to be TPM_ALG_NULL so
+ // 'certifiedObject' will never be NULL
+ certifyInfo.attested.certify.name = certifiedObject->name;
+
+ // When using an anonymous signing scheme, need to set the qualified Name to the
+ // empty buffer to avoid correlation between keys
+ if(CryptIsSchemeAnonymous(in->inScheme.scheme))
+ certifyInfo.attested.certify.qualifiedName.t.size = 0;
+ else
+ certifyInfo.attested.certify.qualifiedName = certifiedObject->qualifiedName;
+
+ // Sign attestation structure. A NULL signature will be returned if
+ // signHandle is TPM_RH_NULL. A TPM_RC_NV_UNAVAILABLE, TPM_RC_NV_RATE,
+ // TPM_RC_VALUE, TPM_RC_SCHEME or TPM_RC_ATTRIBUTES error may be returned
+ // by SignAttestInfo()
+ return SignAttestInfo(signObject, &in->inScheme, &certifyInfo,
+ &in->qualifyingData, &out->certifyInfo, &out->signature);
+}
+#endif // CC_Certify
+#include "Tpm.h"
+#include "Attest_spt_fp.h"
+#include "CertifyCreation_fp.h"
+#if CC_CertifyCreation // Conditional expansion of this file
+TPM_RC
+TPM2_CertifyCreation(
+ CertifyCreation_In *in, // IN: input parameter list
+ CertifyCreation_Out *out // OUT: output parameter list
+ )
+{
+ TPMT_TK_CREATION ticket;
+ TPMS_ATTEST certifyInfo;
+ OBJECT *certified = HandleToObject(in->objectHandle);
+ OBJECT *signObject = HandleToObject(in->signHandle);
+ // Input Validation
+ if(!IsSigningObject(signObject))
+ return TPM_RCS_KEY + RC_CertifyCreation_signHandle;
+ if(!CryptSelectSignScheme(signObject, &in->inScheme))
+ return TPM_RCS_SCHEME + RC_CertifyCreation_inScheme;
+ // CertifyCreation specific input validation
+ // Re-compute ticket
+ TicketComputeCreation(in->creationTicket.hierarchy, &certified->name,
+ &in->creationHash, &ticket);
+ // Compare ticket
+ if(!MemoryEqual2B(&ticket.digest.b, &in->creationTicket.digest.b))
+ return TPM_RCS_TICKET + RC_CertifyCreation_creationTicket;
+ // Command Output
+ // Common fields
+ FillInAttestInfo(in->signHandle, &in->inScheme, &in->qualifyingData,
+ &certifyInfo);
+ // CertifyCreation specific fields
+ // Attestation type
+ certifyInfo.type = TPM_ST_ATTEST_CREATION;
+ certifyInfo.attested.creation.objectName = certified->name;
+ // Copy the creationHash
+ certifyInfo.attested.creation.creationHash = in->creationHash;
+ // Sign attestation structure. A NULL signature will be returned if
+ // signObject is TPM_RH_NULL. A TPM_RC_NV_UNAVAILABLE, TPM_RC_NV_RATE,
+ // TPM_RC_VALUE, TPM_RC_SCHEME or TPM_RC_ATTRIBUTES error may be returned at
+ // this point
+ return SignAttestInfo(signObject, &in->inScheme, &certifyInfo,
+ &in->qualifyingData, &out->certifyInfo,
+ &out->signature);
+}
+#endif // CC_CertifyCreation
+#include "Tpm.h"
+#include "Attest_spt_fp.h"
+#include "Quote_fp.h"
+#if CC_Quote // Conditional expansion of this file
+TPM_RC
+TPM2_Quote(
+ Quote_In *in, // IN: input parameter list
+ Quote_Out *out // OUT: output parameter list
+ )
+{
+ TPMI_ALG_HASH hashAlg;
+ TPMS_ATTEST quoted;
+ OBJECT *signObject = HandleToObject(in->signHandle);
+ // Input Validation
+ if(!IsSigningObject(signObject))
+ return TPM_RCS_KEY + RC_Quote_signHandle;
+ if(!CryptSelectSignScheme(signObject, &in->inScheme))
+ return TPM_RCS_SCHEME + RC_Quote_inScheme;
+ // Command Output
+ // Filling in attest information
+ // Common fields
+ // FillInAttestInfo may return TPM_RC_SCHEME or TPM_RC_KEY
+ FillInAttestInfo(in->signHandle, &in->inScheme, &in->qualifyingData, &quoted);
+ // Quote specific fields
+ // Attestation type
+ quoted.type = TPM_ST_ATTEST_QUOTE;
+ // Get hash algorithm in sign scheme. This hash algorithm is used to
+ // compute PCR digest. If there is no algorithm, then the PCR cannot
+ // be digested and this command returns TPM_RC_SCHEME
+ hashAlg = in->inScheme.details.any.hashAlg;
+ if(hashAlg == TPM_ALG_NULL)
+ return TPM_RCS_SCHEME + RC_Quote_inScheme;
+ // Compute PCR digest
+ PCRComputeCurrentDigest(hashAlg, &in->PCRselect,
+ &quoted.attested.quote.pcrDigest);
+ // Copy PCR select. "PCRselect" is modified in PCRComputeCurrentDigest
+ // function
+ quoted.attested.quote.pcrSelect = in->PCRselect;
+ // Sign attestation structure. A NULL signature will be returned if
+ // signObject is NULL.
+ return SignAttestInfo(signObject, &in->inScheme, &quoted, &in->qualifyingData,
+ &out->quoted, &out->signature);
+}
+#endif // CC_Quote
+#include "Tpm.h"
+#include "Attest_spt_fp.h"
+#include "GetSessionAuditDigest_fp.h"
+#if CC_GetSessionAuditDigest // Conditional expansion of this file
+TPM_RC
+TPM2_GetSessionAuditDigest(
+ GetSessionAuditDigest_In *in, // IN: input parameter list
+ GetSessionAuditDigest_Out *out // OUT: output parameter list
+ )
+{
+ SESSION *session = SessionGet(in->sessionHandle);
+ TPMS_ATTEST auditInfo;
+ OBJECT *signObject = HandleToObject(in->signHandle);
+ // Input Validation
+ if(!IsSigningObject(signObject))
+ return TPM_RCS_KEY + RC_GetSessionAuditDigest_signHandle;
+ if(!CryptSelectSignScheme(signObject, &in->inScheme))
+ return TPM_RCS_SCHEME + RC_GetSessionAuditDigest_inScheme;
+ // session must be an audit session
+ if(session->attributes.isAudit == CLEAR)
+ return TPM_RCS_TYPE + RC_GetSessionAuditDigest_sessionHandle;
+ // Command Output
+ // Fill in attest information common fields
+ FillInAttestInfo(in->signHandle, &in->inScheme, &in->qualifyingData,
+ &auditInfo);
+ // SessionAuditDigest specific fields
+ auditInfo.type = TPM_ST_ATTEST_SESSION_AUDIT;
+ auditInfo.attested.sessionAudit.sessionDigest = session->u2.auditDigest;
+ // Exclusive audit session
+ auditInfo.attested.sessionAudit.exclusiveSession
+ = (g_exclusiveAuditSession == in->sessionHandle);
+ // Sign attestation structure. A NULL signature will be returned if
+ // signObject is NULL.
+ return SignAttestInfo(signObject, &in->inScheme, &auditInfo,
+ &in->qualifyingData, &out->auditInfo,
+ &out->signature);
+}
+#endif // CC_GetSessionAuditDigest
+#include "Tpm.h"
+#include "Attest_spt_fp.h"
+#include "GetCommandAuditDigest_fp.h"
+#if CC_GetCommandAuditDigest // Conditional expansion of this file
+TPM_RC
+TPM2_GetCommandAuditDigest(
+ GetCommandAuditDigest_In *in, // IN: input parameter list
+ GetCommandAuditDigest_Out *out // OUT: output parameter list
+ )
+{
+ TPM_RC result;
+ TPMS_ATTEST auditInfo;
+ OBJECT *signObject = HandleToObject(in->signHandle);
+ // Input validation
+ if(!IsSigningObject(signObject))
+ return TPM_RCS_KEY + RC_GetCommandAuditDigest_signHandle;
+ if(!CryptSelectSignScheme(signObject, &in->inScheme))
+ return TPM_RCS_SCHEME + RC_GetCommandAuditDigest_inScheme;
+ // Command Output
+ // Fill in attest information common fields
+ FillInAttestInfo(in->signHandle, &in->inScheme, &in->qualifyingData,
+ &auditInfo);
+ // CommandAuditDigest specific fields
+ auditInfo.type = TPM_ST_ATTEST_COMMAND_AUDIT;
+ auditInfo.attested.commandAudit.digestAlg = gp.auditHashAlg;
+ auditInfo.attested.commandAudit.auditCounter = gp.auditCounter;
+ // Copy command audit log
+ auditInfo.attested.commandAudit.auditDigest = gr.commandAuditDigest;
+ CommandAuditGetDigest(&auditInfo.attested.commandAudit.commandDigest);
+ // Sign attestation structure. A NULL signature will be returned if
+ // signHandle is TPM_RH_NULL. A TPM_RC_NV_UNAVAILABLE, TPM_RC_NV_RATE,
+ // TPM_RC_VALUE, TPM_RC_SCHEME or TPM_RC_ATTRIBUTES error may be returned at
+ // this point
+ result = SignAttestInfo(signObject, &in->inScheme, &auditInfo,
+ &in->qualifyingData, &out->auditInfo,
+ &out->signature);
+ // Internal Data Update
+ if(result == TPM_RC_SUCCESS && in->signHandle != TPM_RH_NULL)
+ // Reset log
+ gr.commandAuditDigest.t.size = 0;
+ return result;
+}
+#endif // CC_GetCommandAuditDigest
+#include "Tpm.h"
+#include "Attest_spt_fp.h"
+#include "GetTime_fp.h"
+#if CC_GetTime // Conditional expansion of this file
+TPM_RC
+TPM2_GetTime(
+ GetTime_In *in, // IN: input parameter list
+ GetTime_Out *out // OUT: output parameter list
+ )
+{
+ TPMS_ATTEST timeInfo;
+ OBJECT *signObject = HandleToObject(in->signHandle);
+ // Input Validation
+ if(!IsSigningObject(signObject))
+ return TPM_RCS_KEY + RC_GetTime_signHandle;
+ if(!CryptSelectSignScheme(signObject, &in->inScheme))
+ return TPM_RCS_SCHEME + RC_GetTime_inScheme;
+ // Command Output
+ // Fill in attest common fields
+ FillInAttestInfo(in->signHandle, &in->inScheme, &in->qualifyingData, &timeInfo);
+ // GetClock specific fields
+ timeInfo.type = TPM_ST_ATTEST_TIME;
+ timeInfo.attested.time.time.time = g_time;
+ TimeFillInfo(&timeInfo.attested.time.time.clockInfo);
+ // Firmware version in plain text
+ timeInfo.attested.time.firmwareVersion
+ = (((UINT64)gp.firmwareV1) << 32) + gp.firmwareV2;
+ // Sign attestation structure. A NULL signature will be returned if
+ // signObject is NULL.
+ return SignAttestInfo(signObject, &in->inScheme, &timeInfo, &in->qualifyingData,
+ &out->timeInfo, &out->signature);
+}
+#endif // CC_GetTime
+#include "Tpm.h"
+#include "CertifyX509_fp.h"
+#include "X509.h"
+#include "TpmAsn1_fp.h"
+#include "X509_spt_fp.h"
+#include "Attest_spt_fp.h"
+#include "Platform_fp.h"
+#if CC_CertifyX509 // Conditional expansion of this file
+#if CERTIFYX509_DEBUG
+#include "DebugHelpers_fp.h"
+#endif
+
+/* Error Returns Meaning*/
+/* TPM_RC_ATTRIBUTES the attributes of objectHandle are not compatible with the KeyUsage() or TPMA_OBJECT values in the extensions fields */
+/* TPM_RC_BINDING the public and private portions of the key are not properly bound. */
+/* TPM_RC_HASH the hash algorithm in the scheme is not supported */
+/* TPM_RC_KEY signHandle does not reference a signing key; */
+/* TPM_RC_SCHEME the scheme is not compatible with sign key type, or input scheme is not compatible with default scheme, or the chosen scheme is not a valid sign scheme */
+ /* TPM_RC_VALUE most likely a problem with the format of partialCertificate */
+TPM_RC
+TPM2_CertifyX509(
+ CertifyX509_In *in, // IN: input parameter list
+ CertifyX509_Out *out // OUT: output parameter list
+ )
+{
+ TPM_RC result;
+ OBJECT *signKey = HandleToObject(in->signHandle);
+ OBJECT *object = HandleToObject(in->objectHandle);
+ HASH_STATE hash;
+ INT16 length; // length for a tagged element
+ ASN1UnmarshalContext ctx;
+ ASN1MarshalContext ctxOut;
+ // certTBS holds an array of pointers and lengths. Each entry references the
+ // corresponding value in a TBSCertificate structure. For example, the 1th
+ // element references the version number
+ stringRef certTBS[REF_COUNT] = {{0}};
+#define ALLOWED_SEQUENCES (SUBJECT_PUBLIC_KEY_REF - SIGNATURE_REF)
+ stringRef partial[ALLOWED_SEQUENCES] = {{0}};
+ INT16 countOfSequences = 0;
+ INT16 i;
+ //
+#if CERTIFYX509_DEBUG
+ DebugFileInit();
+ DebugDumpBuffer(in->partialCertificate.t.size, in->partialCertificate.t.buffer,
+ "partialCertificate");
+#endif
+
+ // Input Validation
+ if(in->reserved.b.size != 0)
+ return TPM_RC_SIZE + RC_CertifyX509_reserved;
+ // signing key must be able to sign
+ if(!IsSigningObject(signKey))
+ return TPM_RCS_KEY + RC_CertifyX509_signHandle;
+ // Pick a scheme for sign. If the input sign scheme is not compatible with
+ // the default scheme, return an error.
+ if(!CryptSelectSignScheme(signKey, &in->inScheme))
+ return TPM_RCS_SCHEME + RC_CertifyX509_inScheme;
+ // Make sure that the public Key encoding is known
+ if(X509AddPublicKey(NULL, object) == 0)
+ return TPM_RCS_ASYMMETRIC + RC_CertifyX509_objectHandle;
+ // Unbundle 'partialCertificate'.
+ // Initialize the unmarshaling context
+ if(!ASN1UnmarshalContextInitialize(&ctx, in->partialCertificate.t.size,
+ in->partialCertificate.t.buffer))
+ return TPM_RCS_VALUE + RC_CertifyX509_partialCertificate;
+ // Make sure that this is a constructed SEQUENCE
+ length = ASN1NextTag(&ctx);
+ // Must be a constructed SEQUENCE that uses all of the input parameter
+ if((ctx.tag != (ASN1_CONSTRUCTED_SEQUENCE))
+ || ((ctx.offset + length) != in->partialCertificate.t.size))
+ return TPM_RCS_SIZE + RC_CertifyX509_partialCertificate;
+
+ // This scans through the contents of the outermost SEQUENCE. This would be the
+ // 'issuer', 'validity', 'subject', 'issuerUniqueID' (optional),
+ // 'subjectUniqueID' (optional), and 'extensions.'
+ while(ctx.offset < ctx.size)
+ {
+ INT16 startOfElement = ctx.offset;
+ //
+ // Read the next tag and length field.
+ length = ASN1NextTag(&ctx);
+ if(length < 0)
+ break;
+ if(ctx.tag == ASN1_CONSTRUCTED_SEQUENCE)
+ {
+ partial[countOfSequences].buf = &ctx.buffer[startOfElement];
+ ctx.offset += length;
+ partial[countOfSequences].len = (INT16)ctx.offset - startOfElement;
+ if(++countOfSequences > ALLOWED_SEQUENCES)
+ break;
+ }
+ else if(ctx.tag == X509_EXTENSIONS)
+ {
+ if(certTBS[EXTENSIONS_REF].len != 0)
+ return TPM_RCS_VALUE + RC_CertifyX509_partialCertificate;
+ certTBS[EXTENSIONS_REF].buf = &ctx.buffer[startOfElement];
+ ctx.offset += length;
+ certTBS[EXTENSIONS_REF].len =
+ (INT16)ctx.offset - startOfElement;
+ }
+ else
+ return TPM_RCS_VALUE + RC_CertifyX509_partialCertificate;
+ }
+ // Make sure that we used all of the data and found at least the required
+ // number of elements.
+ if((ctx.offset != ctx.size) || (countOfSequences < 3)
+ || (countOfSequences > 4)
+ || (certTBS[EXTENSIONS_REF].buf == NULL))
+ return TPM_RCS_VALUE + RC_CertifyX509_partialCertificate;
+ // Now that we know how many sequences there were, we can put them where they
+ // belong
+ for(i = 0; i < countOfSequences; i++)
+ certTBS[SUBJECT_KEY_REF - i] = partial[countOfSequences - 1 - i];
+
+ // If only three SEQUENCES, then the TPM needs to produce the signature algorithm.
+ // See if it can
+ if((countOfSequences == 3) &&
+ (X509AddSigningAlgorithm(NULL, signKey, &in->inScheme) == 0))
+ return TPM_RCS_SCHEME + RC_CertifyX509_signHandle;
+
+ // Process the extensions
+ result = X509ProcessExtensions(object, &certTBS[EXTENSIONS_REF]);
+ if(result != TPM_RC_SUCCESS)
+ // If the extension has the TPMA_OBJECT extension and the attributes don't
+ // match, then the error code will be TPM_RCS_ATTRIBUTES. Otherwise, the error
+ // indicates a malformed partialCertificate.
+ return result + ((result == TPM_RCS_ATTRIBUTES)
+ ? RC_CertifyX509_objectHandle
+ : RC_CertifyX509_partialCertificate);
+ // Command Output
+ // Create the addedToCertificate values
+
+ // Build the addedToCertificate from the bottom up.
+ // Initialize the context structure
+ ASN1InitialializeMarshalContext(&ctxOut, sizeof(out->addedToCertificate.t.buffer),
+ out->addedToCertificate.t.buffer);
+ // Place a marker for the overall context
+ ASN1StartMarshalContext(&ctxOut); // SEQUENCE for addedToCertificate
+
+ // Add the subject public key descriptor
+ certTBS[SUBJECT_PUBLIC_KEY_REF].len = X509AddPublicKey(&ctxOut, object);
+ certTBS[SUBJECT_PUBLIC_KEY_REF].buf = ctxOut.buffer + ctxOut.offset;
+ // If the caller didn't provide the algorithm identifier, create it
+ if(certTBS[SIGNATURE_REF].len == 0)
+ {
+ certTBS[SIGNATURE_REF].len = X509AddSigningAlgorithm(&ctxOut, signKey,
+ &in->inScheme);
+ certTBS[SIGNATURE_REF].buf = ctxOut.buffer + ctxOut.offset;
+ }
+ // Create the serial number value. Use the out->tbsDigest as scratch.
+ {
+ TPM2B *digest = &out->tbsDigest.b;
+ //
+ digest->size = (INT16)CryptHashStart(&hash, signKey->publicArea.nameAlg);
+ pAssert(digest->size != 0);
+
+ // The serial number size is the smaller of the digest and the vendor-defined
+ // value
+ digest->size = MIN(digest->size, SIZE_OF_X509_SERIAL_NUMBER);
+ // Add all the parts of the certificate other than the serial number
+ // and version number
+ for(i = SIGNATURE_REF; i < REF_COUNT; i++)
+ CryptDigestUpdate(&hash, certTBS[i].len, certTBS[i].buf);
+ // throw in the Name of the signing key...
+ CryptDigestUpdate2B(&hash, &signKey->name.b);
+ // ...and the Name of the signed key.
+ CryptDigestUpdate2B(&hash, &object->name.b);
+ // Done
+ CryptHashEnd2B(&hash, digest);
+ }
+
+ // Add the serial number
+ certTBS[SERIAL_NUMBER_REF].len =
+ ASN1PushInteger(&ctxOut, out->tbsDigest.t.size, out->tbsDigest.t.buffer);
+ certTBS[SERIAL_NUMBER_REF].buf = ctxOut.buffer + ctxOut.offset;
+
+ // Add the static version number
+ ASN1StartMarshalContext(&ctxOut);
+ ASN1PushUINT(&ctxOut, 2);
+ certTBS[VERSION_REF].len =
+ ASN1EndEncapsulation(&ctxOut, ASN1_APPLICAIION_SPECIFIC);
+ certTBS[VERSION_REF].buf = ctxOut.buffer + ctxOut.offset;
+
+ // Create a fake tag and length for the TBS in the space used for
+ // 'addedToCertificate'
+ {
+ for(length = 0, i = 0; i < REF_COUNT; i++)
+ length += certTBS[i].len;
+ // Put a fake tag and length into the buffer for use in the tbsDigest
+ certTBS[ENCODED_SIZE_REF].len =
+ ASN1PushTagAndLength(&ctxOut, ASN1_CONSTRUCTED_SEQUENCE, length);
+ certTBS[ENCODED_SIZE_REF].buf = ctxOut.buffer + ctxOut.offset;
+ // Restore the buffer pointer to add back the number of octets used for the
+ // tag and length
+ ctxOut.offset += certTBS[ENCODED_SIZE_REF].len;
+ }
+ // sanity check
+ if(ctxOut.offset < 0)
+ return TPM_RC_FAILURE;
+ // Create the tbsDigest to sign
+ out->tbsDigest.t.size = CryptHashStart(&hash, in->inScheme.details.any.hashAlg);
+ for(i = 0; i < REF_COUNT; i++)
+ CryptDigestUpdate(&hash, certTBS[i].len, certTBS[i].buf);
+ CryptHashEnd2B(&hash, &out->tbsDigest.b);
+
+#if CERTIFYX509_DEBUG
+ {
+ BYTE fullTBS[4096];
+ BYTE *fill = fullTBS;
+ int j;
+ for (j = 0; j < REF_COUNT; j++)
+ {
+ MemoryCopy(fill, certTBS[j].buf, certTBS[j].len);
+ fill += certTBS[j].len;
+ }
+ DebugDumpBuffer((int)(fill - &fullTBS[0]), fullTBS, "\nfull TBS");
+ }
+#endif
+
+ // Finish up the processing of addedToCertificate
+ // Create the actual tag and length for the addedToCertificate structure
+ out->addedToCertificate.t.size =
+ ASN1EndEncapsulation(&ctxOut, ASN1_CONSTRUCTED_SEQUENCE);
+ // Now move all the addedToContext to the start of the buffer
+ MemoryCopy(out->addedToCertificate.t.buffer, ctxOut.buffer + ctxOut.offset,
+ out->addedToCertificate.t.size);
+#if CERTIFYX509_DEBUG
+ DebugDumpBuffer(out->addedToCertificate.t.size, out->addedToCertificate.t.buffer,
+ "\naddedToCertificate");
+#endif
+ // only thing missing is the signature
+ result = CryptSign(signKey, &in->inScheme, &out->tbsDigest, &out->signature);
+
+ return result;
+}
+#endif // CC_CertifyX509