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 //** Includes
36
37 #include "Tpm.h"
38 #include "Context_spt_fp.h"
39
40 //** Functions
41
42 //*** ComputeContextProtectionKey()
43 // This function retrieves the symmetric protection key for context encryption
44 // It is used by TPM2_ConextSave and TPM2_ContextLoad to create the symmetric
45 // encryption key and iv
46 /*(See part 1 specification)
47 KDFa is used to generate the symmetric encryption key and IV. The parameters
48 of the call are:
49 Symkey = KDFa(hashAlg, hProof, vendorString, sequence, handle, bits)
50 where
51 hashAlg a vendor-defined hash algorithm
52 hProof the hierarchy proof as selected by the hierarchy parameter
53 of the TPMS_CONTEXT
54 vendorString a value used to differentiate the uses of the KDF
55 sequence the sequence parameter of the TPMS_CONTEXT
56 handle the handle parameter of the TPMS_CONTEXT
57 bits the number of bits needed for a symmetric key and IV for
58 the context encryption
59 */
60 // Return Type: void
61 void
ComputeContextProtectionKey(TPMS_CONTEXT * contextBlob,TPM2B_SYM_KEY * symKey,TPM2B_IV * iv)62 ComputeContextProtectionKey(
63 TPMS_CONTEXT *contextBlob, // IN: context blob
64 TPM2B_SYM_KEY *symKey, // OUT: the symmetric key
65 TPM2B_IV *iv // OUT: the IV.
66 )
67 {
68 UINT16 symKeyBits; // number of bits in the parent's
69 // symmetric key
70 TPM2B_PROOF *proof = NULL; // the proof value to use. Is null for
71 // everything but a primary object in
72 // the Endorsement Hierarchy
73
74 BYTE kdfResult[sizeof(TPMU_HA) * 2];// Value produced by the KDF
75
76 TPM2B_DATA sequence2B, handle2B;
77
78 // Get proof value
79 proof = HierarchyGetProof(contextBlob->hierarchy);
80
81 // Get sequence value in 2B format
82 sequence2B.t.size = sizeof(contextBlob->sequence);
83 cAssert(sequence2B.t.size <= sizeof(sequence2B.t.buffer));
84 MemoryCopy(sequence2B.t.buffer, &contextBlob->sequence, sequence2B.t.size);
85
86 // Get handle value in 2B format
87 handle2B.t.size = sizeof(contextBlob->savedHandle);
88 cAssert(handle2B.t.size <= sizeof(handle2B.t.buffer));
89 MemoryCopy(handle2B.t.buffer, &contextBlob->savedHandle, handle2B.t.size);
90
91 // Get the symmetric encryption key size
92 symKey->t.size = CONTEXT_ENCRYPT_KEY_BYTES;
93 symKeyBits = CONTEXT_ENCRYPT_KEY_BITS;
94 // Get the size of the IV for the algorithm
95 iv->t.size = CryptGetSymmetricBlockSize(CONTEXT_ENCRYPT_ALG, symKeyBits);
96
97 // KDFa to generate symmetric key and IV value
98 CryptKDFa(CONTEXT_INTEGRITY_HASH_ALG, &proof->b, CONTEXT_KEY, &sequence2B.b,
99 &handle2B.b, (symKey->t.size + iv->t.size) * 8, kdfResult, NULL,
100 FALSE);
101
102 // Copy part of the returned value as the key
103 pAssert(symKey->t.size <= sizeof(symKey->t.buffer));
104 MemoryCopy(symKey->t.buffer, kdfResult, symKey->t.size);
105
106 // Copy the rest as the IV
107 pAssert(iv->t.size <= sizeof(iv->t.buffer));
108 MemoryCopy(iv->t.buffer, &kdfResult[symKey->t.size], iv->t.size);
109
110 return;
111 }
112
113 //*** ComputeContextIntegrity()
114 // Generate the integrity hash for a context
115 // It is used by TPM2_ContextSave to create an integrity hash
116 // and by TPM2_ContextLoad to compare an integrity hash
117 /*(See part 1 specification)
118 The HMAC integrity computation for a saved context is:
119 HMACvendorAlg(hProof, resetValue {|| clearCount} || sequence || handle ||
120 encContext)
121 where
122 HMACvendorAlg HMAC using a vendor-defined hash algorithm
123 hProof the hierarchy proof as selected by the hierarchy
124 parameter of the TPMS_CONTEXT
125 resetValue either a counter value that increments on each TPM Reset
126 and is not reset over the lifetime of the TPM or a random
127 value that changes on each TPM Reset and has the size of
128 the digest produced by vendorAlg
129 clearCount a counter value that is incremented on each TPM Reset
130 or TPM Restart. This value is only included if the handle
131 value is 0x80000002.
132 sequence the sequence parameter of the TPMS_CONTEXT
133 handle the handle parameter of the TPMS_CONTEXT
134 encContext the encrypted context blob
135 */
136 // Return Type: void
137 void
ComputeContextIntegrity(TPMS_CONTEXT * contextBlob,TPM2B_DIGEST * integrity)138 ComputeContextIntegrity(
139 TPMS_CONTEXT *contextBlob, // IN: context blob
140 TPM2B_DIGEST *integrity // OUT: integrity
141 )
142 {
143 HMAC_STATE hmacState;
144 TPM2B_PROOF *proof;
145 UINT16 integritySize;
146
147 // Get proof value
148 proof = HierarchyGetProof(contextBlob->hierarchy);
149
150 // Start HMAC
151 integrity->t.size = CryptHmacStart2B(&hmacState, CONTEXT_INTEGRITY_HASH_ALG,
152 &proof->b);
153
154 // Compute integrity size at the beginning of context blob
155 integritySize = sizeof(integrity->t.size) + integrity->t.size;
156
157 // Adding total reset counter so that the context cannot be
158 // used after a TPM Reset
159 CryptDigestUpdateInt(&hmacState.hashState, sizeof(gp.totalResetCount),
160 gp.totalResetCount);
161
162 // If this is a ST_CLEAR object, add the clear count
163 // so that this contest cannot be loaded after a TPM Restart
164 if(contextBlob->savedHandle == 0x80000002)
165 CryptDigestUpdateInt(&hmacState.hashState, sizeof(gr.clearCount),
166 gr.clearCount);
167
168 // Adding sequence number to the HMAC to make sure that it doesn't
169 // get changed
170 CryptDigestUpdateInt(&hmacState.hashState, sizeof(contextBlob->sequence),
171 contextBlob->sequence);
172
173 // Protect the handle
174 CryptDigestUpdateInt(&hmacState.hashState, sizeof(contextBlob->savedHandle),
175 contextBlob->savedHandle);
176
177 // Adding sensitive contextData, skip the leading integrity area
178 CryptDigestUpdate(&hmacState.hashState,
179 contextBlob->contextBlob.t.size - integritySize,
180 contextBlob->contextBlob.t.buffer + integritySize);
181
182 // Complete HMAC
183 CryptHmacEnd2B(&hmacState, &integrity->b);
184
185 return;
186 }
187
188 //*** SequenceDataExport();
189 // This function is used scan through the sequence object and
190 // either modify the hash state data for export (contextSave) or to
191 // import it into the internal format (contextLoad).
192 // This function should only be called after the sequence object has been copied
193 // to the context buffer (contextSave) or from the context buffer into the sequence
194 // object. The presumption is that the context buffer version of the data is the
195 // same size as the internal representation so nothing outsize of the hash context
196 // area gets modified.
197 void
SequenceDataExport(HASH_OBJECT * object,HASH_OBJECT_BUFFER * exportObject)198 SequenceDataExport(
199 HASH_OBJECT *object, // IN: an internal hash object
200 HASH_OBJECT_BUFFER *exportObject // OUT: a sequence context in a buffer
201 )
202 {
203 // If the hash object is not an event, then only one hash context is needed
204 int count = (object->attributes.eventSeq) ? HASH_COUNT : 1;
205
206 for(count--; count >= 0; count--)
207 {
208 HASH_STATE *hash = &object->state.hashState[count];
209 size_t offset = (BYTE *)hash - (BYTE *)object;
210 BYTE *exportHash = &((BYTE *)exportObject)[offset];
211
212 CryptHashExportState(hash, (EXPORT_HASH_STATE *)exportHash);
213 }
214 }
215
216 //*** SequenceDataImport();
217 // This function is used scan through the sequence object and
218 // either modify the hash state data for export (contextSave) or to
219 // import it into the internal format (contextLoad).
220 // This function should only be called after the sequence object has been copied
221 // to the context buffer (contextSave) or from the context buffer into the sequence
222 // object. The presumption is that the context buffer version of the data is the
223 // same size as the internal representation so nothing outsize of the hash context
224 // area gets modified.
225 void
SequenceDataImport(HASH_OBJECT * object,HASH_OBJECT_BUFFER * exportObject)226 SequenceDataImport(
227 HASH_OBJECT *object, // IN/OUT: an internal hash object
228 HASH_OBJECT_BUFFER *exportObject // IN/OUT: a sequence context in a buffer
229 )
230 {
231 // If the hash object is not an event, then only one hash context is needed
232 int count = (object->attributes.eventSeq) ? HASH_COUNT : 1;
233
234 for(count--; count >= 0; count--)
235 {
236 HASH_STATE *hash = &object->state.hashState[count];
237 size_t offset = (BYTE *)hash - (BYTE *)object;
238 BYTE *importHash = &((BYTE *)exportObject)[offset];
239 //
240 CryptHashImportState(hash, (EXPORT_HASH_STATE *)importHash);
241 }
242 }