1// This file was extracted from the TCG Published
2// Trusted Platform Module Library
3// Part 3: Commands
4// Family "2.0"
5// Level 00 Revision 01.16
6// October 30, 2014
7
8#include "InternalRoutines.h"
9#include "HierarchyControl_fp.h"
10//
11//
12//     Error Returns               Meaning
13//
14//     TPM_RC_AUTH_TYPE            authHandle is not applicable to hierarchy in its current state
15//
16TPM_RC
17TPM2_HierarchyControl(
18   HierarchyControl_In    *in                 // IN: input parameter list
19   )
20{
21   TPM_RC      result;
22   BOOL        select = (in->state == YES);
23   BOOL        *selected = NULL;
24
25// Input Validation
26   switch(in->enable)
27   {
28       // Platform hierarchy has to be disabled by platform auth
29       // If the platform hierarchy has already been disabled, only a reboot
30       // can enable it again
31       case TPM_RH_PLATFORM:
32       case TPM_RH_PLATFORM_NV:
33           if(in->authHandle != TPM_RH_PLATFORM)
34               return TPM_RC_AUTH_TYPE;
35           break;
36
37       // ShEnable may be disabled if PlatformAuth/PlatformPolicy or
38       // OwnerAuth/OwnerPolicy is provided. If ShEnable is disabled, then it
39       // may only be enabled if PlatformAuth/PlatformPolicy is provided.
40       case TPM_RH_OWNER:
41           if(   in->authHandle != TPM_RH_PLATFORM
42              && in->authHandle != TPM_RH_OWNER)
43               return TPM_RC_AUTH_TYPE;
44           if(   gc.shEnable == FALSE && in->state == YES
45              && in->authHandle != TPM_RH_PLATFORM)
46               return TPM_RC_AUTH_TYPE;
47           break;
48
49       // EhEnable may be disabled if either PlatformAuth/PlatformPolicy or
50       // EndosementAuth/EndorsementPolicy is provided. If EhEnable is disabled,
51       // then it may only be enabled if PlatformAuth/PlatformPolicy is
52       // provided.
53       case TPM_RH_ENDORSEMENT:
54           if(   in->authHandle != TPM_RH_PLATFORM
55              && in->authHandle != TPM_RH_ENDORSEMENT)
56               return TPM_RC_AUTH_TYPE;
57           if(   gc.ehEnable == FALSE && in->state == YES
58              && in->authHandle != TPM_RH_PLATFORM)
59               return TPM_RC_AUTH_TYPE;
60           break;
61       default:
62           pAssert(FALSE);
63           break;
64   }
65
66// Internal Data Update
67
68   // Enable or disable the selected hierarchy
69   // Note: the authorization processing for this command may keep these
70   // command actions from being executed. For example, if phEnable is
71   // CLEAR, then platformAuth cannot be used for authorization. This
72   // means that would not be possible to use platformAuth to change the
73   // state of phEnable from CLEAR to SET.
74   // If it is decided that platformPolicy can still be used when phEnable
75   // is CLEAR, then this code could SET phEnable when proper platform
76   // policy is provided.
77   switch(in->enable)
78   {
79       case TPM_RH_OWNER:
80           selected = &gc.shEnable;
81           break;
82       case TPM_RH_ENDORSEMENT:
83           selected = &gc.ehEnable;
84           break;
85       case TPM_RH_PLATFORM:
86           selected = &g_phEnable;
87           break;
88       case TPM_RH_PLATFORM_NV:
89           selected = &gc.phEnableNV;
90           break;
91       default:
92           pAssert(FALSE);
93           break;
94   }
95   if(selected != NULL && *selected != select)
96   {
97       // Before changing the internal state, make sure that NV is available.
98       // Only need to update NV if changing the orderly state
99       if(gp.orderlyState != SHUTDOWN_NONE)
100       {
101           // The command needs NV update. Check if NV is available.
102           // A TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE error may be returned at
103           // this point
104           result = NvIsAvailable();
105           if(result != TPM_RC_SUCCESS)
106               return result;
107       }
108       // state is changing and NV is available so modify
109       *selected = select;
110       // If a hierarchy was just disabled, flush it
111       if(select == CLEAR && in->enable != TPM_RH_PLATFORM_NV)
112       // Flush hierarchy
113           ObjectFlushHierarchy(in->enable);
114
115       // orderly state should be cleared because of the update to state clear data
116       // This gets processed in ExecuteCommand() on the way out.
117       g_clearOrderly = TRUE;
118   }
119   return TPM_RC_SUCCESS;
120}
121