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 #include "Tpm.h"
37 #include "Policy_spt_fp.h"
38 #include "PolicySigned_fp.h"
39 #include "PolicySecret_fp.h"
40 #include "PolicyTicket_fp.h"
41
42 //** Functions
43 //*** PolicyParameterChecks()
44 // This function validates the common parameters of TPM2_PolicySiged()
45 // and TPM2_PolicySecret(). The common parameters are 'nonceTPM',
46 // 'expiration', and 'cpHashA'.
47 TPM_RC
PolicyParameterChecks(SESSION * session,UINT64 authTimeout,TPM2B_DIGEST * cpHashA,TPM2B_NONCE * nonce,TPM_RC blameNonce,TPM_RC blameCpHash,TPM_RC blameExpiration)48 PolicyParameterChecks(
49 SESSION *session,
50 UINT64 authTimeout,
51 TPM2B_DIGEST *cpHashA,
52 TPM2B_NONCE *nonce,
53 TPM_RC blameNonce,
54 TPM_RC blameCpHash,
55 TPM_RC blameExpiration
56 )
57 {
58 // Validate that input nonceTPM is correct if present
59 if(nonce != NULL && nonce->t.size != 0)
60 {
61 if(!MemoryEqual2B(&nonce->b, &session->nonceTPM.b))
62 return TPM_RCS_NONCE + blameNonce;
63 }
64 // If authTimeout is set (expiration != 0...
65 if(authTimeout != 0)
66 {
67 // Validate input expiration.
68 // Cannot compare time if clock stop advancing. A TPM_RC_NV_UNAVAILABLE
69 // or TPM_RC_NV_RATE error may be returned here.
70 RETURN_IF_NV_IS_NOT_AVAILABLE;
71
72 // if the time has already passed or the time epoch has changed then the
73 // time value is no longer good.
74 if((authTimeout < g_time)
75 || (session->epoch != g_timeEpoch))
76 return TPM_RCS_EXPIRED + blameExpiration;
77 }
78 // If the cpHash is present, then check it
79 if(cpHashA != NULL && cpHashA->t.size != 0)
80 {
81 // The cpHash input has to have the correct size
82 if(cpHashA->t.size != session->u2.policyDigest.t.size)
83 return TPM_RCS_SIZE + blameCpHash;
84
85 // If the cpHash has already been set, then this input value
86 // must match the current value.
87 if(session->u1.cpHash.b.size != 0
88 && !MemoryEqual2B(&cpHashA->b, &session->u1.cpHash.b))
89 return TPM_RC_CPHASH;
90 }
91 return TPM_RC_SUCCESS;
92 }
93
94 //*** PolicyContextUpdate()
95 // Update policy hash
96 // Update the policyDigest in policy session by extending policyRef and
97 // objectName to it. This will also update the cpHash if it is present.
98 //
99 // Return Type: void
100 void
PolicyContextUpdate(TPM_CC commandCode,TPM2B_NAME * name,TPM2B_NONCE * ref,TPM2B_DIGEST * cpHash,UINT64 policyTimeout,SESSION * session)101 PolicyContextUpdate(
102 TPM_CC commandCode, // IN: command code
103 TPM2B_NAME *name, // IN: name of entity
104 TPM2B_NONCE *ref, // IN: the reference data
105 TPM2B_DIGEST *cpHash, // IN: the cpHash (optional)
106 UINT64 policyTimeout, // IN: the timeout value for the policy
107 SESSION *session // IN/OUT: policy session to be updated
108 )
109 {
110 HASH_STATE hashState;
111
112 // Start hash
113 CryptHashStart(&hashState, session->authHashAlg);
114
115
116 // policyDigest size should always be the digest size of session hash algorithm.
117 pAssert(session->u2.policyDigest.t.size
118 == CryptHashGetDigestSize(session->authHashAlg));
119
120 // add old digest
121 CryptDigestUpdate2B(&hashState, &session->u2.policyDigest.b);
122
123 // add commandCode
124 CryptDigestUpdateInt(&hashState, sizeof(commandCode), commandCode);
125
126 // add name if applicable
127 if(name != NULL)
128 CryptDigestUpdate2B(&hashState, &name->b);
129
130 // Complete the digest and get the results
131 CryptHashEnd2B(&hashState, &session->u2.policyDigest.b);
132
133 // If the policy reference is not null, do a second update to the digest.
134 if(ref != NULL)
135 {
136
137 // Start second hash computation
138 CryptHashStart(&hashState, session->authHashAlg);
139
140 // add policyDigest
141 CryptDigestUpdate2B(&hashState, &session->u2.policyDigest.b);
142
143 // add policyRef
144 CryptDigestUpdate2B(&hashState, &ref->b);
145
146 // Complete second digest
147 CryptHashEnd2B(&hashState, &session->u2.policyDigest.b);
148 }
149 // Deal with the cpHash. If the cpHash value is present
150 // then it would have already been checked to make sure that
151 // it is compatible with the current value so all we need
152 // to do here is copy it and set the isCpHashDefined attribute
153 if(cpHash != NULL && cpHash->t.size != 0)
154 {
155 session->u1.cpHash = *cpHash;
156 session->attributes.isCpHashDefined = SET;
157 }
158
159 // update the timeout if it is specified
160 if(policyTimeout != 0)
161 {
162 // If the timeout has not been set, then set it to the new value
163 // than the current timeout then set it to the new value
164 if(session->timeout == 0 || session->timeout > policyTimeout)
165 session->timeout = policyTimeout;
166 }
167 return;
168 }
169 //*** ComputeAuthTimeout()
170 // This function is used to determine what the authorization timeout value for
171 // the session should be.
172 UINT64
ComputeAuthTimeout(SESSION * session,INT32 expiration,TPM2B_NONCE * nonce)173 ComputeAuthTimeout(
174 SESSION *session, // IN: the session containing the time
175 // values
176 INT32 expiration, // IN: either the number of seconds from
177 // the start of the session or the
178 // time in g_timer;
179 TPM2B_NONCE *nonce // IN: indicator of the time base
180 )
181 {
182 UINT64 policyTime;
183 // If no expiration, policy time is 0
184 if(expiration == 0)
185 policyTime = 0;
186 else
187 {
188 if(expiration < 0)
189 expiration = -expiration;
190 if(nonce->t.size == 0)
191 // The input time is absolute Time (not Clock), but it is expressed
192 // in seconds. To make sure that we don't time out too early, take the
193 // current value of milliseconds in g_time and add that to the input
194 // seconds value.
195 policyTime = (((UINT64)expiration) * 1000) + g_time % 1000;
196 else
197 // The policy timeout is the absolute value of the expiration in seconds
198 // added to the start time of the policy.
199 policyTime = session->startTime + (((UINT64)expiration) * 1000);
200
201 }
202 return policyTime;
203 }
204
205 //*** PolicyDigestClear()
206 // Function to reset the policyDigest of a session
207 void
PolicyDigestClear(SESSION * session)208 PolicyDigestClear(
209 SESSION *session
210 )
211 {
212 session->u2.policyDigest.t.size = CryptHashGetDigestSize(session->authHashAlg);
213 MemorySet(session->u2.policyDigest.t.buffer, 0,
214 session->u2.policyDigest.t.size);
215 }
216
217 //*** PolicySptCheckCondition()
218 // Checks to see if the condition in the policy is satisfied.
219 BOOL
PolicySptCheckCondition(TPM_EO operation,BYTE * opA,BYTE * opB,UINT16 size)220 PolicySptCheckCondition(
221 TPM_EO operation,
222 BYTE *opA,
223 BYTE *opB,
224 UINT16 size
225 )
226 {
227 // Arithmetic Comparison
228 switch(operation)
229 {
230 case TPM_EO_EQ:
231 // compare A = B
232 return (UnsignedCompareB(size, opA, size, opB) == 0);
233 break;
234 case TPM_EO_NEQ:
235 // compare A != B
236 return (UnsignedCompareB(size, opA, size, opB) != 0);
237 break;
238 case TPM_EO_SIGNED_GT:
239 // compare A > B signed
240 return (SignedCompareB(size, opA, size, opB) > 0);
241 break;
242 case TPM_EO_UNSIGNED_GT:
243 // compare A > B unsigned
244 return (UnsignedCompareB(size, opA, size, opB) > 0);
245 break;
246 case TPM_EO_SIGNED_LT:
247 // compare A < B signed
248 return (SignedCompareB(size, opA, size, opB) < 0);
249 break;
250 case TPM_EO_UNSIGNED_LT:
251 // compare A < B unsigned
252 return (UnsignedCompareB(size, opA, size, opB) < 0);
253 break;
254 case TPM_EO_SIGNED_GE:
255 // compare A >= B signed
256 return (SignedCompareB(size, opA, size, opB) >= 0);
257 break;
258 case TPM_EO_UNSIGNED_GE:
259 // compare A >= B unsigned
260 return (UnsignedCompareB(size, opA, size, opB) >= 0);
261 break;
262 case TPM_EO_SIGNED_LE:
263 // compare A <= B signed
264 return (SignedCompareB(size, opA, size, opB) <= 0);
265 break;
266 case TPM_EO_UNSIGNED_LE:
267 // compare A <= B unsigned
268 return (UnsignedCompareB(size, opA, size, opB) <= 0);
269 break;
270 case TPM_EO_BITSET:
271 // All bits SET in B are SET in A. ((A&B)=B)
272 {
273 UINT32 i;
274 for(i = 0; i < size; i++)
275 if((opA[i] & opB[i]) != opB[i])
276 return FALSE;
277 }
278 break;
279 case TPM_EO_BITCLEAR:
280 // All bits SET in B are CLEAR in A. ((A&B)=0)
281 {
282 UINT32 i;
283 for(i = 0; i < size; i++)
284 if((opA[i] & opB[i]) != 0)
285 return FALSE;
286 }
287 break;
288 default:
289 FAIL(FATAL_ERROR_INTERNAL);
290 break;
291 }
292 return TRUE;
293 }
294