1 /* Microsoft Reference Implementation for TPM 2.0
2 *
3 * The copyright in this software is being made available under the BSD License,
4 * included below. This software may be subject to other third party and
5 * contributor rights, including patent rights, and no such rights are granted
6 * under this license.
7 *
8 * Copyright (c) Microsoft Corporation
9 *
10 * All rights reserved.
11 *
12 * BSD License
13 *
14 * Redistribution and use in source and binary forms, with or without modification,
15 * are permitted provided that the following conditions are met:
16 *
17 * Redistributions of source code must retain the above copyright notice, this list
18 * of conditions and the following disclaimer.
19 *
20 * Redistributions in binary form must reproduce the above copyright notice, this
21 * list of conditions and the following disclaimer in the documentation and/or
22 * other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35 #include "Tpm.h"
36 #include "ContextSave_fp.h"
37
38 #if CC_ContextSave // Conditional expansion of this file
39
40 #include "Context_spt_fp.h"
41
42 /*(See part 3 specification)
43 Save context
44 */
45 // Return Type: TPM_RC
46 // TPM_RC_CONTEXT_GAP a contextID could not be assigned for a session
47 // context save
48 // TPM_RC_TOO_MANY_CONTEXTS no more contexts can be saved as the counter has
49 // maxed out
50 TPM_RC
TPM2_ContextSave(ContextSave_In * in,ContextSave_Out * out)51 TPM2_ContextSave(
52 ContextSave_In *in, // IN: input parameter list
53 ContextSave_Out *out // OUT: output parameter list
54 )
55 {
56 TPM_RC result = TPM_RC_SUCCESS;
57 UINT16 fingerprintSize; // The size of fingerprint in context
58 // blob.
59 UINT64 contextID = 0; // session context ID
60 TPM2B_SYM_KEY symKey;
61 TPM2B_IV iv;
62
63 TPM2B_DIGEST integrity;
64 UINT16 integritySize;
65 BYTE *buffer;
66
67 // This command may cause the orderlyState to be cleared due to
68 // the update of state reset data. If the state is orderly and
69 // cannot be changed, exit early.
70 RETURN_IF_ORDERLY;
71
72 // Internal Data Update
73
74 // This implementation does not do things in quite the same way as described in
75 // Part 2 of the specification. In Part 2, it indicates that the
76 // TPMS_CONTEXT_DATA contains two TPM2B values. That is not how this is
77 // implemented. Rather, the size field of the TPM2B_CONTEXT_DATA is used to
78 // determine the amount of data in the encrypted data. That part is not
79 // independently sized. This makes the actual size 2 bytes smaller than
80 // calculated using Part 2. Since this is opaque to the caller, it is not
81 // necessary to fix. The actual size is returned by TPM2_GetCapabilties().
82
83 // Initialize output handle. At the end of command action, the output
84 // handle of an object will be replaced, while the output handle
85 // for a session will be the same as input
86 out->context.savedHandle = in->saveHandle;
87
88 // Get the size of fingerprint in context blob. The sequence value in
89 // TPMS_CONTEXT structure is used as the fingerprint
90 fingerprintSize = sizeof(out->context.sequence);
91
92 // Compute the integrity size at the beginning of context blob
93 integritySize = sizeof(integrity.t.size)
94 + CryptHashGetDigestSize(CONTEXT_INTEGRITY_HASH_ALG);
95
96 // Perform object or session specific context save
97 switch(HandleGetType(in->saveHandle))
98 {
99 case TPM_HT_TRANSIENT:
100 {
101 OBJECT *object = HandleToObject(in->saveHandle);
102 ANY_OBJECT_BUFFER *outObject;
103 UINT16 objectSize = ObjectIsSequence(object)
104 ? sizeof(HASH_OBJECT) : sizeof(OBJECT);
105
106 outObject = (ANY_OBJECT_BUFFER *)(out->context.contextBlob.t.buffer
107 + integritySize + fingerprintSize);
108
109 // Set size of the context data. The contents of context blob is vendor
110 // defined. In this implementation, the size is size of integrity
111 // plus fingerprint plus the whole internal OBJECT structure
112 out->context.contextBlob.t.size = integritySize +
113 fingerprintSize + objectSize;
114 #if ALG_RSA
115 // For an RSA key, make sure that the key has had the private exponent
116 // computed before saving.
117 if(object->publicArea.type == TPM_ALG_RSA &&
118 !(object->attributes.publicOnly))
119 CryptRsaLoadPrivateExponent(&object->publicArea, &object->sensitive);
120 #endif
121 // Make sure things fit
122 pAssert(out->context.contextBlob.t.size
123 <= sizeof(out->context.contextBlob.t.buffer));
124 // Copy the whole internal OBJECT structure to context blob
125 MemoryCopy(outObject, object, objectSize);
126
127 // Increment object context ID
128 gr.objectContextID++;
129 // If object context ID overflows, TPM should be put in failure mode
130 if(gr.objectContextID == 0)
131 FAIL(FATAL_ERROR_INTERNAL);
132
133 // Fill in other return values for an object.
134 out->context.sequence = gr.objectContextID;
135 // For regular object, savedHandle is 0x80000000. For sequence object,
136 // savedHandle is 0x80000001. For object with stClear, savedHandle
137 // is 0x80000002
138 if(ObjectIsSequence(object))
139 {
140 out->context.savedHandle = 0x80000001;
141 SequenceDataExport((HASH_OBJECT *)object,
142 (HASH_OBJECT_BUFFER *)outObject);
143 }
144 else
145 out->context.savedHandle = (object->attributes.stClear == SET)
146 ? 0x80000002 : 0x80000000;
147 // Get object hierarchy
148 out->context.hierarchy = ObjectGetHierarchy(object);
149
150 break;
151 }
152 case TPM_HT_HMAC_SESSION:
153 case TPM_HT_POLICY_SESSION:
154 {
155 SESSION *session = SessionGet(in->saveHandle);
156
157 // Set size of the context data. The contents of context blob is vendor
158 // defined. In this implementation, the size of context blob is the
159 // size of a internal session structure plus the size of
160 // fingerprint plus the size of integrity
161 out->context.contextBlob.t.size = integritySize +
162 fingerprintSize + sizeof(*session);
163
164 // Make sure things fit
165 pAssert(out->context.contextBlob.t.size
166 < sizeof(out->context.contextBlob.t.buffer));
167
168 // Copy the whole internal SESSION structure to context blob.
169 // Save space for fingerprint at the beginning of the buffer
170 // This is done before anything else so that the actual context
171 // can be reclaimed after this call
172 pAssert(sizeof(*session) <= sizeof(out->context.contextBlob.t.buffer)
173 - integritySize - fingerprintSize);
174 MemoryCopy(out->context.contextBlob.t.buffer + integritySize
175 + fingerprintSize, session, sizeof(*session));
176 // Fill in the other return parameters for a session
177 // Get a context ID and set the session tracking values appropriately
178 // TPM_RC_CONTEXT_GAP is a possible error.
179 // SessionContextSave() will flush the in-memory context
180 // so no additional errors may occur after this call.
181 result = SessionContextSave(out->context.savedHandle, &contextID);
182 if(result != TPM_RC_SUCCESS)
183 return result;
184 // sequence number is the current session contextID
185 out->context.sequence = contextID;
186
187 // use TPM_RH_NULL as hierarchy for session context
188 out->context.hierarchy = TPM_RH_NULL;
189
190 break;
191 }
192 default:
193 // SaveContext may only take an object handle or a session handle.
194 // All the other handle type should be filtered out at unmarshal
195 FAIL(FATAL_ERROR_INTERNAL);
196 break;
197 }
198
199 // Save fingerprint at the beginning of encrypted area of context blob.
200 // Reserve the integrity space
201 pAssert(sizeof(out->context.sequence) <=
202 sizeof(out->context.contextBlob.t.buffer) - integritySize);
203 MemoryCopy(out->context.contextBlob.t.buffer + integritySize,
204 &out->context.sequence, sizeof(out->context.sequence));
205
206 // Compute context encryption key
207 ComputeContextProtectionKey(&out->context, &symKey, &iv);
208
209 // Encrypt context blob
210 CryptSymmetricEncrypt(out->context.contextBlob.t.buffer + integritySize,
211 CONTEXT_ENCRYPT_ALG, CONTEXT_ENCRYPT_KEY_BITS,
212 symKey.t.buffer, &iv, TPM_ALG_CFB,
213 out->context.contextBlob.t.size - integritySize,
214 out->context.contextBlob.t.buffer + integritySize);
215
216 // Compute integrity hash for the object
217 // In this implementation, the same routine is used for both sessions
218 // and objects.
219 ComputeContextIntegrity(&out->context, &integrity);
220
221 // add integrity at the beginning of context blob
222 buffer = out->context.contextBlob.t.buffer;
223 TPM2B_DIGEST_Marshal(&integrity, &buffer, NULL);
224
225 // orderly state should be cleared because of the update of state reset and
226 // state clear data
227 g_clearOrderly = TRUE;
228
229 return result;
230 }
231
232 #endif // CC_ContextSave