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 //
16 TPM_RC
TPM2_HierarchyControl(HierarchyControl_In * in)17 TPM2_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