• 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 //** 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