• 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 #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