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 //** Introduction
36 // This file contains the functions for testing various command properties.
37
38 //** Includes and Defines
39
40 #include "Tpm.h"
41 #include "CommandCodeAttributes_fp.h"
42
43 // Set the default value for CC_VEND if not already set
44 #ifndef CC_VEND
45 #define CC_VEND (TPM_CC)(0x20000000)
46 #endif
47
48 typedef UINT16 ATTRIBUTE_TYPE;
49
50 // The following file is produced from the command tables in part 3 of the
51 // specification. It defines the attributes for each of the commands.
52 // NOTE: This file is currently produced by an automated process. Files
53 // produced from Part 2 or Part 3 tables through automated processes are not
54 // included in the specification so that their is no ambiguity about the
55 // table containing the information being the normative definition.
56 #define _COMMAND_CODE_ATTRIBUTES_
57 #include "CommandAttributeData.h"
58
59 //** Command Attribute Functions
60
61 //*** NextImplementedIndex()
62 // This function is used when the lists are not compressed. In a compressed list,
63 // only the implemented commands are present. So, a search might find a value
64 // but that value may not be implemented. This function checks to see if the input
65 // commandIndex points to an implemented command and, if not, it searches upwards
66 // until it finds one. When the list is compressed, this function gets defined
67 // as a no-op.
68 // Return Type: COMMAND_INDEX
69 // UNIMPLEMENTED_COMMAND_INDEX command is not implemented
70 // other index of the command
71 #if !COMPRESSED_LISTS
72 static COMMAND_INDEX
NextImplementedIndex(COMMAND_INDEX commandIndex)73 NextImplementedIndex(
74 COMMAND_INDEX commandIndex
75 )
76 {
77 for(;commandIndex < COMMAND_COUNT; commandIndex++)
78 {
79 if(s_commandAttributes[commandIndex] & IS_IMPLEMENTED)
80 return commandIndex;
81 }
82 return UNIMPLEMENTED_COMMAND_INDEX;
83 }
84 #else
85 #define NextImplementedIndex(x) (x)
86 #endif
87
88 //*** GetClosestCommandIndex()
89 // This function returns the command index for the command with a value that is
90 // equal to or greater than the input value
91 // Return Type: COMMAND_INDEX
92 // UNIMPLEMENTED_COMMAND_INDEX command is not implemented
93 // other index of a command
94 COMMAND_INDEX
GetClosestCommandIndex(TPM_CC commandCode)95 GetClosestCommandIndex(
96 TPM_CC commandCode // IN: the command code to start at
97 )
98 {
99 BOOL vendor = (commandCode & CC_VEND) != 0;
100 COMMAND_INDEX searchIndex = (COMMAND_INDEX)commandCode;
101
102 // The commandCode is a UINT32 and the search index is UINT16. We are going to
103 // search for a match but need to make sure that the commandCode value is not
104 // out of range. To do this, need to clear the vendor bit of the commandCode
105 // (if set) and compare the result to the 16-bit searchIndex value. If it is
106 // out of range, indicate that the command is not implemented
107 if((commandCode & ~CC_VEND) != searchIndex)
108 return UNIMPLEMENTED_COMMAND_INDEX;
109
110 // if there is at least one vendor command, the last entry in the array will
111 // have the v bit set. If the input commandCode is larger than the last
112 // vendor-command, then it is out of range.
113 if(vendor)
114 {
115 #if VENDOR_COMMAND_ARRAY_SIZE > 0
116 COMMAND_INDEX commandIndex;
117 COMMAND_INDEX min;
118 COMMAND_INDEX max;
119 int diff;
120 #if LIBRARY_COMMAND_ARRAY_SIZE == COMMAND_COUNT
121 #error "Constants are not consistent."
122 #endif
123 // Check to see if the value is equal to or below the minimum
124 // entry.
125 // Note: Put this check first so that the typical case of only one vendor-
126 // specific command doesn't waste any more time.
127 if(GET_ATTRIBUTE(s_ccAttr[LIBRARY_COMMAND_ARRAY_SIZE], TPMA_CC,
128 commandIndex) >= searchIndex)
129 {
130 // the vendor array is always assumed to be packed so there is
131 // no need to check to see if the command is implemented
132 return LIBRARY_COMMAND_ARRAY_SIZE;
133 }
134 // See if this is out of range on the top
135 if(GET_ATTRIBUTE(s_ccAttr[COMMAND_COUNT - 1], TPMA_CC, commandIndex)
136 < searchIndex)
137 {
138 return UNIMPLEMENTED_COMMAND_INDEX;
139 }
140 commandIndex = UNIMPLEMENTED_COMMAND_INDEX; // Needs initialization to keep
141 // compiler happy
142 min = LIBRARY_COMMAND_ARRAY_SIZE; // first vendor command
143 max = COMMAND_COUNT - 1; // last vendor command
144 diff = 1; // needs initialization to keep
145 // compiler happy
146 while(min <= max)
147 {
148 commandIndex = (min + max + 1) / 2;
149 diff = GET_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, commandIndex)
150 - searchIndex;
151 if(diff == 0)
152 return commandIndex;
153 if(diff > 0)
154 max = commandIndex - 1;
155 else
156 min = commandIndex + 1;
157 }
158 // didn't find and exact match. commandIndex will be pointing at the last
159 // item tested. If 'diff' is positive, then the last item tested was
160 // larger index of the command code so it is the smallest value
161 // larger than the requested value.
162 if(diff > 0)
163 return commandIndex;
164 // if 'diff' is negative, then the value tested was smaller than
165 // the commandCode index and the next higher value is the correct one.
166 // Note: this will necessarily be in range because of the earlier check
167 // that the index was within range.
168 return commandIndex + 1;
169 #else
170 // If there are no vendor commands so anything with the vendor bit set is out
171 // of range
172 return UNIMPLEMENTED_COMMAND_INDEX;
173 #endif
174 }
175 // Get here if the V-Bit was not set in 'commandCode'
176
177 if(GET_ATTRIBUTE(s_ccAttr[LIBRARY_COMMAND_ARRAY_SIZE - 1], TPMA_CC,
178 commandIndex) < searchIndex)
179 {
180 // requested index is out of the range to the top
181 #if VENDOR_COMMAND_ARRAY_SIZE > 0
182 // If there are vendor commands, then the first vendor command
183 // is the next value greater than the commandCode.
184 // NOTE: we got here if the starting index did not have the V bit but we
185 // reached the end of the array of library commands (non-vendor). Since
186 // there is at least one vendor command, and vendor commands are always
187 // in a compressed list that starts after the library list, the next
188 // index value contains a valid vendor command.
189 return LIBRARY_COMMAND_ARRAY_SIZE;
190 #else
191 // if there are no vendor commands, then this is out of range
192 return UNIMPLEMENTED_COMMAND_INDEX;
193 #endif
194 }
195 // If the request is lower than any value in the array, then return
196 // the lowest value (needs to be an index for an implemented command
197 if(GET_ATTRIBUTE(s_ccAttr[0], TPMA_CC, commandIndex) >= searchIndex)
198 {
199 return NextImplementedIndex(0);
200 }
201 else
202 {
203 #if COMPRESSED_LISTS
204 COMMAND_INDEX commandIndex = UNIMPLEMENTED_COMMAND_INDEX;
205 COMMAND_INDEX min = 0;
206 COMMAND_INDEX max = LIBRARY_COMMAND_ARRAY_SIZE - 1;
207 int diff = 1;
208 #if LIBRARY_COMMAND_ARRAY_SIZE == 0
209 #error "Something is terribly wrong"
210 #endif
211 // The s_ccAttr array contains an extra entry at the end (a zero value).
212 // Don't count this as an array entry. This means that max should start
213 // out pointing to the last valid entry in the array which is - 2
214 pAssert(max == (sizeof(s_ccAttr) / sizeof(TPMA_CC)
215 - VENDOR_COMMAND_ARRAY_SIZE - 2));
216 while(min <= max)
217 {
218 commandIndex = (min + max + 1) / 2;
219 diff = GET_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC,
220 commandIndex) - searchIndex;
221 if(diff == 0)
222 return commandIndex;
223 if(diff > 0)
224 max = commandIndex - 1;
225 else
226 min = commandIndex + 1;
227 }
228 // didn't find and exact match. commandIndex will be pointing at the
229 // last item tested. If diff is positive, then the last item tested was
230 // larger index of the command code so it is the smallest value
231 // larger than the requested value.
232 if(diff > 0)
233 return commandIndex;
234 // if diff is negative, then the value tested was smaller than
235 // the commandCode index and the next higher value is the correct one.
236 // Note: this will necessarily be in range because of the earlier check
237 // that the index was within range.
238 return commandIndex + 1;
239 #else
240 // The list is not compressed so offset into the array by the command
241 // code value of the first entry in the list. Then go find the first
242 // implemented command.
243 return NextImplementedIndex(searchIndex
244 - (COMMAND_INDEX)s_ccAttr[0].commandIndex);
245 #endif
246 }
247 }
248
249 //*** CommandCodeToComandIndex()
250 // This function returns the index in the various attributes arrays of the
251 // command.
252 // Return Type: COMMAND_INDEX
253 // UNIMPLEMENTED_COMMAND_INDEX command is not implemented
254 // other index of the command
255 COMMAND_INDEX
CommandCodeToCommandIndex(TPM_CC commandCode)256 CommandCodeToCommandIndex(
257 TPM_CC commandCode // IN: the command code to look up
258 )
259 {
260 // Extract the low 16-bits of the command code to get the starting search index
261 COMMAND_INDEX searchIndex = (COMMAND_INDEX)commandCode;
262 BOOL vendor = (commandCode & CC_VEND) != 0;
263 COMMAND_INDEX commandIndex;
264 #if !COMPRESSED_LISTS
265 if(!vendor)
266 {
267 commandIndex = searchIndex - (COMMAND_INDEX)s_ccAttr[0].commandIndex;
268 // Check for out of range or unimplemented.
269 // Note, since a COMMAND_INDEX is unsigned, if searchIndex is smaller than
270 // the lowest value of command, it will become a 'negative' number making
271 // it look like a large unsigned number, this will cause it to fail
272 // the unsigned check below.
273 if(commandIndex >= LIBRARY_COMMAND_ARRAY_SIZE
274 || (s_commandAttributes[commandIndex] & IS_IMPLEMENTED) == 0)
275 return UNIMPLEMENTED_COMMAND_INDEX;
276 return commandIndex;
277 }
278 #endif
279 // Need this code for any vendor code lookup or for compressed lists
280 commandIndex = GetClosestCommandIndex(commandCode);
281
282 // Look at the returned value from get closest. If it isn't the one that was
283 // requested, then the command is not implemented.
284 if(commandIndex != UNIMPLEMENTED_COMMAND_INDEX)
285 {
286 if((GET_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, commandIndex)
287 != searchIndex)
288 || (IS_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, V)) != vendor)
289 commandIndex = UNIMPLEMENTED_COMMAND_INDEX;
290 }
291 return commandIndex;
292 }
293
294 //*** GetNextCommandIndex()
295 // This function returns the index of the next implemented command.
296 // Return Type: COMMAND_INDEX
297 // UNIMPLEMENTED_COMMAND_INDEX no more implemented commands
298 // other the index of the next implemented command
299 COMMAND_INDEX
GetNextCommandIndex(COMMAND_INDEX commandIndex)300 GetNextCommandIndex(
301 COMMAND_INDEX commandIndex // IN: the starting index
302 )
303 {
304 while(++commandIndex < COMMAND_COUNT)
305 {
306 #if !COMPRESSED_LISTS
307 if(s_commandAttributes[commandIndex] & IS_IMPLEMENTED)
308 #endif
309 return commandIndex;
310 }
311 return UNIMPLEMENTED_COMMAND_INDEX;
312 }
313
314 //*** GetCommandCode()
315 // This function returns the commandCode associated with the command index
316 TPM_CC
GetCommandCode(COMMAND_INDEX commandIndex)317 GetCommandCode(
318 COMMAND_INDEX commandIndex // IN: the command index
319 )
320 {
321 TPM_CC commandCode = GET_ATTRIBUTE(s_ccAttr[commandIndex],
322 TPMA_CC, commandIndex);
323 if(IS_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, V))
324 commandCode += CC_VEND;
325 return commandCode;
326 }
327
328 //*** CommandAuthRole()
329 //
330 // This function returns the authorization role required of a handle.
331 //
332 // Return Type: AUTH_ROLE
333 // AUTH_NONE no authorization is required
334 // AUTH_USER user role authorization is required
335 // AUTH_ADMIN admin role authorization is required
336 // AUTH_DUP duplication role authorization is required
337 AUTH_ROLE
CommandAuthRole(COMMAND_INDEX commandIndex,UINT32 handleIndex)338 CommandAuthRole(
339 COMMAND_INDEX commandIndex, // IN: command index
340 UINT32 handleIndex // IN: handle index (zero based)
341 )
342 {
343 if(0 == handleIndex)
344 {
345 // Any authorization role set?
346 COMMAND_ATTRIBUTES properties = s_commandAttributes[commandIndex];
347
348 if(properties & HANDLE_1_USER)
349 return AUTH_USER;
350 if(properties & HANDLE_1_ADMIN)
351 return AUTH_ADMIN;
352 if(properties & HANDLE_1_DUP)
353 return AUTH_DUP;
354 }
355 else if(1 == handleIndex)
356 {
357 if(s_commandAttributes[commandIndex] & HANDLE_2_USER)
358 return AUTH_USER;
359 }
360 return AUTH_NONE;
361 }
362
363 //*** EncryptSize()
364 // This function returns the size of the decrypt size field. This function returns
365 // 0 if encryption is not allowed
366 // Return Type: int
367 // 0 encryption not allowed
368 // 2 size field is two bytes
369 // 4 size field is four bytes
370 int
EncryptSize(COMMAND_INDEX commandIndex)371 EncryptSize(
372 COMMAND_INDEX commandIndex // IN: command index
373 )
374 {
375 return ((s_commandAttributes[commandIndex] & ENCRYPT_2) ? 2 :
376 (s_commandAttributes[commandIndex] & ENCRYPT_4) ? 4 : 0);
377 }
378
379 //*** DecryptSize()
380 // This function returns the size of the decrypt size field. This function returns
381 // 0 if decryption is not allowed
382 // Return Type: int
383 // 0 encryption not allowed
384 // 2 size field is two bytes
385 // 4 size field is four bytes
386 int
DecryptSize(COMMAND_INDEX commandIndex)387 DecryptSize(
388 COMMAND_INDEX commandIndex // IN: command index
389 )
390 {
391 return ((s_commandAttributes[commandIndex] & DECRYPT_2) ? 2 :
392 (s_commandAttributes[commandIndex] & DECRYPT_4) ? 4 : 0);
393 }
394
395 //*** IsSessionAllowed()
396 //
397 // This function indicates if the command is allowed to have sessions.
398 //
399 // This function must not be called if the command is not known to be implemented.
400 //
401 // Return Type: BOOL
402 // TRUE(1) session is allowed with this command
403 // FALSE(0) session is not allowed with this command
404 BOOL
IsSessionAllowed(COMMAND_INDEX commandIndex)405 IsSessionAllowed(
406 COMMAND_INDEX commandIndex // IN: the command to be checked
407 )
408 {
409 return ((s_commandAttributes[commandIndex] & NO_SESSIONS) == 0);
410 }
411
412 //*** IsHandleInResponse()
413 // This function determines if a command has a handle in the response
414 BOOL
IsHandleInResponse(COMMAND_INDEX commandIndex)415 IsHandleInResponse(
416 COMMAND_INDEX commandIndex
417 )
418 {
419 return ((s_commandAttributes[commandIndex] & R_HANDLE) != 0);
420 }
421
422 //*** IsWriteOperation()
423 // Checks to see if an operation will write to an NV Index and is subject to being
424 // blocked by read-lock
425 BOOL
IsWriteOperation(COMMAND_INDEX commandIndex)426 IsWriteOperation(
427 COMMAND_INDEX commandIndex // IN: Command to check
428 )
429 {
430 #ifdef WRITE_LOCK
431 return ((s_commandAttributes[commandIndex] & WRITE_LOCK) != 0);
432 #else
433 if(!IS_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, V))
434 {
435 switch(GET_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, commandIndex))
436 {
437 case TPM_CC_NV_Write:
438 #if CC_NV_Increment
439 case TPM_CC_NV_Increment:
440 #endif
441 #if CC_NV_SetBits
442 case TPM_CC_NV_SetBits:
443 #endif
444 #if CC_NV_Extend
445 case TPM_CC_NV_Extend:
446 #endif
447 #if CC_AC_Send
448 case TPM_CC_AC_Send:
449 #endif
450 // NV write lock counts as a write operation for authorization purposes.
451 // We check to see if the NV is write locked before we do the
452 // authorization. If it is locked, we fail the command early.
453 case TPM_CC_NV_WriteLock:
454 return TRUE;
455 default:
456 break;
457 }
458 }
459 return FALSE;
460 #endif
461 }
462
463 //*** IsReadOperation()
464 // Checks to see if an operation will write to an NV Index and is
465 // subject to being blocked by write-lock.
466 BOOL
IsReadOperation(COMMAND_INDEX commandIndex)467 IsReadOperation(
468 COMMAND_INDEX commandIndex // IN: Command to check
469 )
470 {
471 #ifdef READ_LOCK
472 return ((s_commandAttributes[commandIndex] & READ_LOCK) != 0);
473 #else
474
475 if(!IS_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, V))
476 {
477 switch(GET_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, commandIndex))
478 {
479 case TPM_CC_NV_Read:
480 case TPM_CC_PolicyNV:
481 case TPM_CC_NV_Certify:
482 // NV read lock counts as a read operation for authorization purposes.
483 // We check to see if the NV is read locked before we do the
484 // authorization. If it is locked, we fail the command early.
485 case TPM_CC_NV_ReadLock:
486 return TRUE;
487 default:
488 break;
489 }
490 }
491 return FALSE;
492 #endif
493 }
494
495 //*** CommandCapGetCCList()
496 // This function returns a list of implemented commands and command attributes
497 // starting from the command in 'commandCode'.
498 // Return Type: TPMI_YES_NO
499 // YES more command attributes are available
500 // NO no more command attributes are available
501 TPMI_YES_NO
CommandCapGetCCList(TPM_CC commandCode,UINT32 count,TPML_CCA * commandList)502 CommandCapGetCCList(
503 TPM_CC commandCode, // IN: start command code
504 UINT32 count, // IN: maximum count for number of entries in
505 // 'commandList'
506 TPML_CCA *commandList // OUT: list of TPMA_CC
507 )
508 {
509 TPMI_YES_NO more = NO;
510 COMMAND_INDEX commandIndex;
511
512 // initialize output handle list count
513 commandList->count = 0;
514
515 for(commandIndex = GetClosestCommandIndex(commandCode);
516 commandIndex != UNIMPLEMENTED_COMMAND_INDEX;
517 commandIndex = GetNextCommandIndex(commandIndex))
518 {
519 #if !COMPRESSED_LISTS
520 // this check isn't needed for compressed lists.
521 if(!(s_commandAttributes[commandIndex] & IS_IMPLEMENTED))
522 continue;
523 #endif
524 if(commandList->count < count)
525 {
526 // If the list is not full, add the attributes for this command.
527 commandList->commandAttributes[commandList->count]
528 = s_ccAttr[commandIndex];
529 commandList->count++;
530 }
531 else
532 {
533 // If the list is full but there are more commands to report,
534 // indicate this and return.
535 more = YES;
536 break;
537 }
538 }
539 return more;
540 }
541
542 //*** IsVendorCommand()
543 // Function indicates if a command index references a vendor command.
544 // Return Type: BOOL
545 // TRUE(1) command is a vendor command
546 // FALSE(0) command is not a vendor command
547 BOOL
IsVendorCommand(COMMAND_INDEX commandIndex)548 IsVendorCommand(
549 COMMAND_INDEX commandIndex // IN: command index to check
550 )
551 {
552 return (IS_ATTRIBUTE(s_ccAttr[commandIndex], TPMA_CC, V));
553 }
554