• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }