1 // This file was extracted from the TCG Published 2 // Trusted Platform Module Library 3 // Part 3: Commands 4 // Family "2.0" 5 // Level 00 Revision 01.16 6 // October 30, 2014 7 8 #include "InternalRoutines.h" 9 #include "ContextSave_fp.h" 10 #include "Context_spt_fp.h" 11 // 12 // 13 // Error Returns Meaning 14 // 15 // TPM_RC_CONTEXT_GAP a contextID could not be assigned for a session context save 16 // TPM_RC_TOO_MANY_CONTEXTS no more contexts can be saved as the counter has maxed out 17 // 18 TPM_RC 19 TPM2_ContextSave( 20 ContextSave_In *in, // IN: input parameter list 21 ContextSave_Out *out // OUT: output parameter list 22 ) 23 { 24 TPM_RC result; 25 UINT16 fingerprintSize; // The size of fingerprint in context 26 // blob. 27 UINT64 contextID = 0; // session context ID 28 TPM2B_SYM_KEY symKey; 29 TPM2B_IV iv; 30 31 TPM2B_DIGEST integrity; 32 UINT16 integritySize; 33 BYTE *buffer; 34 INT32 bufferSize; 35 36 // This command may cause the orderlyState to be cleared due to 37 // the update of state reset data. If this is the case, check if NV is 38 // available first 39 if(gp.orderlyState != SHUTDOWN_NONE) 40 { 41 // The command needs NV update. Check if NV is available. 42 // A TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE error may be returned at 43 // this point 44 result = NvIsAvailable(); 45 if(result != TPM_RC_SUCCESS) return result; 46 } 47 48 // Internal Data Update 49 50 // Initialize output handle. At the end of command action, the output 51 // handle of an object will be replaced, while the output handle 52 // for a session will be the same as input 53 out->context.savedHandle = in->saveHandle; 54 55 // Get the size of fingerprint in context blob. The sequence value in 56 // TPMS_CONTEXT structure is used as the fingerprint 57 fingerprintSize = sizeof(out->context.sequence); 58 59 // Compute the integrity size at the beginning of context blob 60 integritySize = sizeof(integrity.t.size) 61 + CryptGetHashDigestSize(CONTEXT_INTEGRITY_HASH_ALG); 62 63 // Perform object or session specific context save 64 switch(HandleGetType(in->saveHandle)) 65 { 66 case TPM_HT_TRANSIENT: 67 { 68 OBJECT *object = ObjectGet(in->saveHandle); 69 OBJECT *outObject = 70 (OBJECT *)(out->context.contextBlob.t.buffer 71 + integritySize + fingerprintSize); 72 73 // Set size of the context data. The contents of context blob is vendor 74 // defined. In this implementation, the size is size of integrity 75 // plus fingerprint plus the whole internal OBJECT structure 76 out->context.contextBlob.t.size = integritySize + 77 fingerprintSize + sizeof(OBJECT); 78 // Make sure things fit 79 pAssert(out->context.contextBlob.t.size 80 < sizeof(out->context.contextBlob.t.buffer)); 81 82 // Copy the whole internal OBJECT structure to context blob, leave 83 // the size for fingerprint 84 *outObject = *object; 85 86 // Increment object context ID 87 gr.objectContextID++; 88 // If object context ID overflows, TPM should be put in failure mode 89 if(gr.objectContextID == 0) 90 FAIL(FATAL_ERROR_INTERNAL); 91 92 // Fill in other return values for an object. 93 out->context.sequence = gr.objectContextID; 94 // For regular object, savedHandle is 0x80000000. For sequence object, 95 // savedHandle is 0x80000001. For object with stClear, savedHandle 96 // is 0x80000002 97 if(ObjectIsSequence(object)) 98 { 99 out->context.savedHandle = 0x80000001; 100 SequenceDataImportExport(object, outObject, EXPORT_STATE); 101 } 102 else if(object->attributes.stClear == SET) 103 { 104 out->context.savedHandle = 0x80000002; 105 } 106 else 107 { 108 out->context.savedHandle = 0x80000000; 109 } 110 111 // Get object hierarchy 112 out->context.hierarchy = ObjectDataGetHierarchy(object); 113 114 break; 115 } 116 case TPM_HT_HMAC_SESSION: 117 case TPM_HT_POLICY_SESSION: 118 { 119 SESSION *session = SessionGet(in->saveHandle); 120 121 // Set size of the context data. The contents of context blob is vendor 122 // defined. In this implementation, the size of context blob is the 123 // size of a internal session structure plus the size of 124 // fingerprint plus the size of integrity 125 out->context.contextBlob.t.size = integritySize + 126 fingerprintSize + sizeof(*session); 127 128 // Make sure things fit 129 pAssert(out->context.contextBlob.t.size 130 < sizeof(out->context.contextBlob.t.buffer)); 131 132 // Copy the whole internal SESSION structure to context blob. 133 // Save space for fingerprint at the beginning of the buffer 134 // This is done before anything else so that the actual context 135 // can be reclaimed after this call 136 MemoryCopy(out->context.contextBlob.t.buffer 137 + integritySize + fingerprintSize, 138 session, sizeof(*session), 139 sizeof(out->context.contextBlob.t.buffer) 140 - integritySize - fingerprintSize); 141 142 // Fill in the other return parameters for a session 143 // Get a context ID and set the session tracking values appropriately 144 // TPM_RC_CONTEXT_GAP is a possible error. 145 // SessionContextSave() will flush the in-memory context 146 // so no additional errors may occur after this call. 147 result = SessionContextSave(out->context.savedHandle, &contextID); 148 if(result != TPM_RC_SUCCESS) return result; 149 150 // sequence number is the current session contextID 151 out->context.sequence = contextID; 152 153 // use TPM_RH_NULL as hierarchy for session context 154 out->context.hierarchy = TPM_RH_NULL; 155 156 break; 157 } 158 default: 159 // SaveContext may only take an object handle or a session handle. 160 // All the other handle type should be filtered out at unmarshal 161 pAssert(FALSE); 162 break; 163 } 164 165 // Save fingerprint at the beginning of encrypted area of context blob. 166 // Reserve the integrity space 167 MemoryCopy(out->context.contextBlob.t.buffer + integritySize, 168 &out->context.sequence, sizeof(out->context.sequence), 169 sizeof(out->context.contextBlob.t.buffer) - integritySize); 170 171 // Compute context encryption key 172 ComputeContextProtectionKey(&out->context, &symKey, &iv); 173 174 // Encrypt context blob 175 CryptSymmetricEncrypt(out->context.contextBlob.t.buffer + integritySize, 176 CONTEXT_ENCRYPT_ALG, CONTEXT_ENCRYPT_KEY_BITS, 177 TPM_ALG_CFB, symKey.t.buffer, &iv, 178 out->context.contextBlob.t.size - integritySize, 179 out->context.contextBlob.t.buffer + integritySize); 180 181 // Compute integrity hash for the object 182 // In this implementation, the same routine is used for both sessions 183 // and objects. 184 ComputeContextIntegrity(&out->context, &integrity); 185 186 // add integrity at the beginning of context blob 187 buffer = out->context.contextBlob.t.buffer; 188 bufferSize = sizeof(TPM2B_DIGEST); 189 TPM2B_DIGEST_Marshal(&integrity, &buffer, &bufferSize); 190 191 // orderly state should be cleared because of the update of state reset and 192 // state clear data 193 g_clearOrderly = TRUE; 194 195 return TPM_RC_SUCCESS; 196 } 197