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
TPM2_ContextSave(ContextSave_In * in,ContextSave_Out * out)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