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 #include "Tpm.h"
36 #include "Startup_fp.h"
37
38 #if CC_Startup // Conditional expansion of this file
39
40 /*(See part 3 specification)
41 // Initialize TPM because a system-wide reset
42 */
43 // Return Type: TPM_RC
44 // TPM_RC_LOCALITY a Startup(STATE) does not have the same H-CRTM
45 // state as the previous Startup() or the locality
46 // of the startup is not 0 or 3
47 // TPM_RC_NV_UNINITIALIZED the saved state cannot be recovered and a
48 // Startup(CLEAR) is required.
49 // TPM_RC_VALUE 'startup' type is not compatible with previous
50 // shutdown sequence
51
52 TPM_RC
TPM2_Startup(Startup_In * in)53 TPM2_Startup(
54 Startup_In *in // IN: input parameter list
55 )
56 {
57 STARTUP_TYPE startup;
58 BYTE locality = _plat__LocalityGet();
59 BOOL OK = TRUE;
60 //
61 // The command needs NV update.
62 RETURN_IF_NV_IS_NOT_AVAILABLE;
63
64 // Get the flags for the current startup locality and the H-CRTM.
65 // Rather than generalizing the locality setting, this code takes advantage
66 // of the fact that the PC Client specification only allows Startup()
67 // from locality 0 and 3. To generalize this probably would require a
68 // redo of the NV space and since this is a feature that is hardly ever used
69 // outside of the PC Client, this code just support the PC Client needs.
70
71 // Input Validation
72 // Check that the locality is a supported value
73 if(locality != 0 && locality != 3)
74 return TPM_RC_LOCALITY;
75 // If there was a H-CRTM, then treat the locality as being 3
76 // regardless of what the Startup() was. This is done to preserve the
77 // H-CRTM PCR so that they don't get overwritten with the normal
78 // PCR startup initialization. This basically means that g_StartupLocality3
79 // and g_DrtmPreStartup can't both be SET at the same time.
80 if(g_DrtmPreStartup)
81 locality = 0;
82 g_StartupLocality3 = (locality == 3);
83
84 #if USE_DA_USED
85 // If there was no orderly shutdown, then there might have been a write to
86 // failedTries that didn't get recorded but only if g_daUsed was SET in the
87 // shutdown state
88 g_daUsed = (gp.orderlyState == SU_DA_USED_VALUE);
89 if(g_daUsed)
90 gp.orderlyState = SU_NONE_VALUE;
91 #endif
92
93 g_prevOrderlyState = gp.orderlyState;
94
95 // If there was a proper shutdown, then the startup modifiers are in the
96 // orderlyState. Turn them off in the copy.
97 if(IS_ORDERLY(g_prevOrderlyState))
98 g_prevOrderlyState &= ~(PRE_STARTUP_FLAG | STARTUP_LOCALITY_3);
99 // If this is a Resume,
100 if(in->startupType == TPM_SU_STATE)
101 {
102 // then there must have been a prior TPM2_ShutdownState(STATE)
103 if(g_prevOrderlyState != TPM_SU_STATE)
104 return TPM_RCS_VALUE + RC_Startup_startupType;
105 // and the part of NV used for state save must have been recovered
106 // correctly.
107 // NOTE: if this fails, then the caller will need to do Startup(CLEAR). The
108 // code for Startup(Clear) cannot fail if the NV can't be read correctly
109 // because that would prevent the TPM from ever getting unstuck.
110 if(g_nvOk == FALSE)
111 return TPM_RC_NV_UNINITIALIZED;
112 // For Resume, the H-CRTM has to be the same as the previous boot
113 if(g_DrtmPreStartup != ((gp.orderlyState & PRE_STARTUP_FLAG) != 0))
114 return TPM_RCS_VALUE + RC_Startup_startupType;
115 if(g_StartupLocality3 != ((gp.orderlyState & STARTUP_LOCALITY_3) != 0))
116 return TPM_RC_LOCALITY;
117 }
118 // Clean up the gp state
119 gp.orderlyState = g_prevOrderlyState;
120
121 // Internal Date Update
122 if((gp.orderlyState == TPM_SU_STATE) && (g_nvOk == TRUE))
123 {
124 // Always read the data that is only cleared on a Reset because this is not
125 // a reset
126 NvRead(&gr, NV_STATE_RESET_DATA, sizeof(gr));
127 if(in->startupType == TPM_SU_STATE)
128 {
129 // If this is a startup STATE (a Resume) need to read the data
130 // that is cleared on a startup CLEAR because this is not a Reset
131 // or Restart.
132 NvRead(&gc, NV_STATE_CLEAR_DATA, sizeof(gc));
133 startup = SU_RESUME;
134 }
135 else
136 startup = SU_RESTART;
137 }
138 else
139 // Will do a TPM reset if Shutdown(CLEAR) and Startup(CLEAR) or no shutdown
140 // or there was a failure reading the NV data.
141 startup = SU_RESET;
142 // Startup for cryptographic library. Don't do this until after the orderly
143 // state has been read in from NV.
144 OK = OK && CryptStartup(startup);
145
146 // When the cryptographic library has been started, indicate that a TPM2_Startup
147 // command has been received.
148 OK = OK && TPMRegisterStartup();
149
150 // Read the platform unique value that is used as VENDOR_PERMANENT
151 // authorization value
152 g_platformUniqueDetails.t.size
153 = (UINT16)_plat__GetUnique(1, sizeof(g_platformUniqueDetails.t.buffer),
154 g_platformUniqueDetails.t.buffer);
155
156 // Start up subsystems
157 // Start set the safe flag
158 OK = OK && TimeStartup(startup);
159
160 // Start dictionary attack subsystem
161 OK = OK && DAStartup(startup);
162
163 // Enable hierarchies
164 OK = OK && HierarchyStartup(startup);
165
166 // Restore/Initialize PCR
167 OK = OK && PCRStartup(startup, locality);
168
169 // Restore/Initialize command audit information
170 OK = OK && CommandAuditStartup(startup);
171
172 // Restore the ACT
173 OK = OK && ActStartup(startup);
174
175 //// The following code was moved from Time.c where it made no sense
176 if(OK)
177 {
178 switch(startup)
179 {
180 case SU_RESUME:
181 // Resume sequence
182 gr.restartCount++;
183 break;
184 case SU_RESTART:
185 // Hibernate sequence
186 gr.clearCount++;
187 gr.restartCount++;
188 break;
189 default:
190 // Reset object context ID to 0
191 gr.objectContextID = 0;
192 // Reset clearCount to 0
193 gr.clearCount = 0;
194
195 // Reset sequence
196 // Increase resetCount
197 gp.resetCount++;
198
199 // Write resetCount to NV
200 NV_SYNC_PERSISTENT(resetCount);
201
202 gp.totalResetCount++;
203 // We do not expect the total reset counter overflow during the life
204 // time of TPM. if it ever happens, TPM will be put to failure mode
205 // and there is no way to recover it.
206 // The reason that there is no recovery is that we don't increment
207 // the NV totalResetCount when incrementing would make it 0. When the
208 // TPM starts up again, the old value of totalResetCount will be read
209 // and we will get right back to here with the increment failing.
210 if(gp.totalResetCount == 0)
211 FAIL(FATAL_ERROR_INTERNAL);
212
213 // Write total reset counter to NV
214 NV_SYNC_PERSISTENT(totalResetCount);
215
216 // Reset restartCount
217 gr.restartCount = 0;
218
219 break;
220 }
221 }
222 // Initialize session table
223 OK = OK && SessionStartup(startup);
224
225 // Initialize object table
226 OK = OK && ObjectStartup();
227
228 // Initialize index/evict data. This function clears read/write locks
229 // in NV index
230 OK = OK && NvEntityStartup(startup);
231
232 // Initialize the orderly shut down flag for this cycle to SU_NONE_VALUE.
233 gp.orderlyState = SU_NONE_VALUE;
234
235 OK = OK && NV_SYNC_PERSISTENT(orderlyState);
236
237 // This can be reset after the first completion of a TPM2_Startup() after
238 // a power loss. It can probably be reset earlier but this is an OK place.
239 if(OK)
240 g_powerWasLost = FALSE;
241
242 return (OK) ? TPM_RC_SUCCESS : TPM_RC_FAILURE;
243 }
244
245 #endif // CC_Startup