/********************************************************************************/ /* */ /* */ /* Written by Ken Goldman */ /* IBM Thomas J. Watson Research Center */ /* $Id: Attest_spt.c 1490 2019-07-26 21:13:22Z 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 - 2018 */ /* */ /********************************************************************************/ #include "Tpm.h" #include "Attest_spt_fp.h" /* 7.2.2 Functions */ /* 7.2.2.1 FillInAttestInfo() */ /* Fill in common fields of TPMS_ATTEST structure. */ void 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 ) { OBJECT *signObject = HandleToObject(signHandle); // Magic number attest->magic = TPM_GENERATED_VALUE; if(signObject == NULL) { // The name for a null handle is TPM_RH_NULL // This is defined because UINT32_TO_BYTE_ARRAY does a cast. If the // size of the cast is smaller than a constant, the compiler warns // about the truncation of a constant value. TPM_HANDLE nullHandle = TPM_RH_NULL; attest->qualifiedSigner.t.size = sizeof(TPM_HANDLE); UINT32_TO_BYTE_ARRAY(nullHandle, attest->qualifiedSigner.t.name); } 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 attest->qualifiedSigner = signObject->qualifiedName; } // 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; // Check the hierarchy of sign object. For NULL sign handle, the hierarchy // will be TPM_RH_NULL if((signObject == NULL) || (!signObject->attributes.epsHierarchy && !signObject->attributes.ppsHierarchy)) { // For signing key that is not in platform or endorsement hierarchy, // obfuscate the reset, restart and firmware version information UINT64 obfuscation[2]; CryptKDFa(CONTEXT_INTEGRITY_HASH_ALG, &gp.shProof.b, OBFUSCATE_STRING, &attest->qualifiedSigner.b, NULL, 128, (BYTE *)&obfuscation[0], NULL, FALSE); // 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 it is not // used in the signing operation except as part of the signed data attest->extraData = *data; data->t.size = 0; } } /* 7.2.2.2 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( OBJECT *signKey, // IN: 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 // process TPM2B_ATTEST *attest, // OUT: marshaled attest blob to be // signed TPMT_SIGNATURE *signature // OUT: signature ) { BYTE *buffer; HASH_STATE hashState; TPM2B_DIGEST digest; TPM_RC result; // Marshal TPMS_ATTEST structure for hash buffer = attest->t.attestationData; attest->t.size = TPMS_ATTEST_Marshal(certifyInfo, &buffer, NULL); if(signKey == NULL) { signature->sigAlg = TPM_ALG_NULL; result = TPM_RC_SUCCESS; } else { TPMI_ALG_HASH hashAlg; // Compute hash hashAlg = scheme->details.any.hashAlg; // need to set the receive buffer to get something put in it digest.t.size = sizeof(digest.t.buffer); digest.t.size = CryptHashBlock(hashAlg, attest->t.size, attest->t.attestationData, digest.t.size, digest.t.buffer); // If there is qualifying data, need to rehash the data // hash(qualifyingData || hash(attestationData)) if(qualifyingData->t.size != 0) { CryptHashStart(&hashState, hashAlg); CryptDigestUpdate2B(&hashState, &qualifyingData->b); CryptDigestUpdate2B(&hashState, &digest.b); CryptHashEnd2B(&hashState, &digest.b); } // Sign the hash. A TPM_RC_VALUE, TPM_RC_SCHEME, or // TPM_RC_ATTRIBUTES error may be returned at this point result = CryptSign(signKey, scheme, &digest, signature); // Since the clock is used in an attestation, the state in NV is no longer // "orderly" with respect to the data in RAM if the signature is valid if(result == TPM_RC_SUCCESS) { // Command uses the clock so need to clear the orderly state if it is // set. result = NvClearOrderly(); } } return result; } /* 7.2.2.3 IsSigningObject() */ /* Checks to see if the object is OK for signing. This is here rather than in Object_spt.c because all the attestation commands use this file but not Object_spt.c. */ /* Return Values Meaning */ /* TRUE object may sign */ /* FALSE object may not sign */ BOOL IsSigningObject( OBJECT *object // IN: ) { return ((object == NULL) || ((IS_ATTRIBUTE(object->publicArea.objectAttributes, TPMA_OBJECT, sign) && object->publicArea.type != TPM_ALG_SYMCIPHER))); }